Kaynağa Gözat

Merge branch 'yufei' of gitadmin/tuoheng_lc_web into develop

tags/v1.0.0^2
zhangtao 2 yıl önce
ebeveyn
işleme
56b4429b84
15 değiştirilmiş dosya ile 594 ekleme ve 10 silme
  1. +2
    -0
      package.json
  2. BIN
      src/assets/point/await.png
  3. BIN
      src/assets/point/checked.png
  4. BIN
      src/assets/point/close.png
  5. BIN
      src/assets/point/ignored.png
  6. BIN
      src/assets/point/selected.png
  7. +133
    -0
      src/components/PositionMsg/OverLay.vue
  8. +250
    -0
      src/components/PositionMsg/index.vue
  9. +65
    -0
      src/components/PositionMsg/util.js
  10. +1
    -1
      src/router/routes/modules/index.js
  11. +3
    -1
      src/views/task-manage/all-task/components/VerifyDrawer.vue
  12. +3
    -2
      src/views/task-manage/all-task/index.vue
  13. +101
    -0
      src/views/task-manage/question/components/PositionDrawer.vue
  14. +9
    -4
      src/views/task-manage/question/index.vue
  15. +27
    -2
      src/views/task-manage/question/tools/table.js

+ 2
- 0
package.json Dosyayı Görüntüle

@@ -16,9 +16,11 @@
"axios": "^0.26.1",
"dayjs": "^1.11.2",
"mockjs": "^1.1.0",
"ol": "^6.15.1",
"pinia": "^2.0.13",
"pinia-plugin-persist": "^1.0.0",
"tinymce": "^5.10.2",
"vite-plugin-svg-icons": "^2.0.1",
"vue": "^3.2.16",
"vue-router": "^4.0.14",
"vuedraggable": "^4.1.0"

BIN
src/assets/point/await.png Dosyayı Görüntüle

Önce Sonra
Genişlik: 24  |  Yükseklik: 24  |  Boyut: 676B

BIN
src/assets/point/checked.png Dosyayı Görüntüle

Önce Sonra
Genişlik: 24  |  Yükseklik: 24  |  Boyut: 799B

BIN
src/assets/point/close.png Dosyayı Görüntüle

Önce Sonra
Genişlik: 122  |  Yükseklik: 122  |  Boyut: 1.2KB

BIN
src/assets/point/ignored.png Dosyayı Görüntüle

Önce Sonra
Genişlik: 24  |  Yükseklik: 25  |  Boyut: 869B

BIN
src/assets/point/selected.png Dosyayı Görüntüle

Önce Sonra
Genişlik: 24  |  Yükseklik: 25  |  Boyut: 678B

+ 133
- 0
src/components/PositionMsg/OverLay.vue Dosyayı Görüntüle

@@ -0,0 +1,133 @@
<template>
<div class="overlay_container">
<div class="overlay_head">
<img class="close_img" src="@/assets/point/close.png" alt="" @click="updateVisible">
</div>
<div class="overlay_main">
<n-form
ref="formRef"
:model="form"
:label-width="80"
label-placement="left"
require-mark-placement="left"
>
<n-form-item label="问题类型:">
<n-select
v-model:value="form.type"
:options="typeList"
placeholder="请选择问题类型"
/>
</n-form-item>
<n-form-item label="问题描述:">
<span>{{ form.content }}</span>
</n-form-item>
<n-form-item label="经纬度:">
<span>{{ form.longitude }},{{ form.latitude }}</span>
</n-form-item>
<n-form-item label="问题图片:">
<img class="image_size" :src="form.fileImage" alt="" style="width: 108px; height: auto; margin: 0 5px 5px 0">
</n-form-item>
</n-form>
</div>
<div class="btn_list">
<n-button class="btn_item" type="primary" @click="makeSure">确定</n-button>
<n-button class="btn_item" @click="pass">忽略</n-button>
</div>
</div>
</template>
<script>
import { toRefs, reactive, watch, inject } from 'vue'
export default {
name: 'OverLay',
props: {
data: {
type: Object,
default: () => null
}
},
emits: {
'close': null
},
setup(props, { emit }) {
const data = reactive({
form: {},
typeList: [
{ value: 1, label: '林斑' },
{ value: 2, label: '病虫害' }
]
})
/* 引入祖先组件注册的方法 */
const confirm = inject('confirm', null)
const ignore = inject('ignore', null)

watch(() => props.data, () => {
data.form = Object.assign({}, props.data)
})
const updateVisible = function() {
emit('close')
}
function makeSure() {
confirm(data.form)
updateVisible()
}
function pass() {
ignore(data.form)
updateVisible()
}
return {
...toRefs(data),
updateVisible,
makeSure,
pass
}
}

}
</script>
<style lang="scss" scoped>
.overlay_container {
width: 100%;
height: 436px;
border-radius: 6px;
padding: 0;
overflow-y: scroll;
background-color: #fff;
position: relative;
}

.overlay_head {
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
position: fixed;
top: 0;
left: 0;
}
.close_img {
width: 40px;
height: 40px;
cursor: pointer;
}
.overlay_main {
width: 100%;
margin-top: 10px;
padding: 40px 30px 60px 40px;
}
.btn_list {
width: 100%;
padding-right: 32px;
position: fixed;
bottom: 20px;
right: 0;
display: flex;
justify-content: flex-end;
align-items: center;
}
.btn_item {
width: 64px;
height: 32px;
margin-left: 20px;
}

</style>

+ 250
- 0
src/components/PositionMsg/index.vue Dosyayı Görüntüle

@@ -0,0 +1,250 @@
<template>
<div class="main_container">
<div id="track" ref="map" />
<div id="pointOverlay" class="point_overlay">
<over-lay :data="problemData" @close="closeOverlay" />
</div>

<ul class="legend_list">
<li v-for="(item, index) in legendList" :key="index" class="legend_item">
<div class="legend_point" :style="{background: item.color}" />
<span class="legend_name">{{ item.name }}</span>
</li>
</ul>
</div>
</template>
<script>
import { reactive, toRefs, onMounted, watch, ref } from 'vue'
import { styleList, legendList } from './util.js'
import { Map, View, Feature, Overlay } from 'ol'
import 'ol/ol.css'
import { Tile, Vector as VectorLayer } from 'ol/layer'
import LineString from 'ol/geom/LineString'
import { XYZ, Vector as VectorSource } from 'ol/source'
import { transform, fromLonLat } from 'ol/proj'
import * as control from 'ol/control'
import { Select } from 'ol/interaction'
import Point from 'ol/geom/Point'

import OverLay from './OverLay.vue'

export default {
name: 'PositionMsg',
components: { OverLay },
props: {
data: {
type: Array,
default: () => {}
}
},
emits: {},
setup(props, { emit }) {
const data = reactive({
problemList: props.data, // 问题矢量点列表
problemData: {}, // 问题点数据
legendList: legendList
})

const mapdata = ref(null)
const select = ref(null)
const problemLayer = ref(null)
const overlay = ref(null)
const view = ref(null)

/**
* 初始化底图
*/
const initMap = function() {
const layers = [
new Tile({
visible: true,
source: new XYZ({
url: 'https://tianditu.t-aaron.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=f82bb2fd8115c7fb576a8b2fcf738523'
})
})
]

view.value = new View({
maxZoom: 18,
zoom: 4,
center: transform([108.94043, 31.008173], 'EPSG:4326', 'EPSG:3857')
})
mapdata.value = new Map({
layers: layers,
target: 'track',
view: view.value,
controls: control.defaults({
attribution: false,
rotate: false,
zoom: false
})
})
mapdata.value.render()
// 添加select并设置选中样式
select.value = new Select({
style: (feature) => {
if (feature.getGeometry() instanceof Point) {
return styleList[0]
}
}
})
mapdata.value.addInteraction(select.value)
// 新建overlay弹出框
overlay.value = new Overlay({
element: document.getElementById('pointOverlay'),
autoPan: true
})
}

onMounted(() => {
initMap()
getLayer(props.data, view.value, mapdata.value)
})

/**
* 加载矢量图层
*/
const getLayer = function(data) {
const pointFeatures = []
const points = []
if (data.length) {
data.forEach((item) => {
const pointItem = []
pointItem.push(parseFloat(item.longitude))
pointItem.push(parseFloat(item.latitude))
const featureItem = new Feature(new Point(fromLonLat(pointItem)))
points.push(fromLonLat(pointItem))
featureItem.setProperties({ item: item, type: 'problem' }, false)
featureItem.setStyle(styleList[item.status])
pointFeatures.push(featureItem)
})
const pointSource = new VectorSource({
wrapX: false,
features: pointFeatures
})
problemLayer.value = new VectorLayer({
source: pointSource,
zIndex: 12
})
let geom
if (points.length > 1) {
geom = new LineString(points)
} else if (points.length > 0) {
geom = new Point(points[0])
}
if (geom) {
view.value.fit(geom, { padding: [150, 200, 150, 200] })
}
mapdata.value.addLayer(problemLayer.value)
}
}

/**
* 删除矢量图层
*/
const removeVector = function(layer) {
layer.getSource().clear()
mapdata.value.removeLayer(layer)
problemLayer.value = null
}
/**
* 选择矢量点数据
*/
const setOverlay = function() {
select.value.on('select', (e) => {
if (e.selected.length > 0) {
const properties = e.selected[0].getProperties()
const geom = properties.geometry
if (geom instanceof Point) {
data.problemData = properties.item
const coordinate = e.mapBrowserEvent.coordinate
overlay.value.setPosition(coordinate)
overlay.value.setOffset([30, -400])
mapdata.value.addOverlay(overlay.value)
} else {
closeOverlay()
}
} else {
closeOverlay()
}
})
}

watch(
() => select.value,
(value) => {
setOverlay(mapdata.value, overlay.value)
}
)
watch(() => props.data, (value) => {
if (value) {
if (mapdata.value) {
removeVector(problemLayer.value)
getLayer(props.data)
}
}
})

/**
* 关闭overlay
*/
const closeOverlay = () => {
data.problemData = {}
select.value.getFeatures().clear()
mapdata.value.removeOverlay(overlay.value)
}

return {
...toRefs(data),
removeVector,
closeOverlay

}
}
}
</script>
<style scoped>
.main_container {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
#track {
width: 100%;
height: 100%;
}
.point_overlay {
width: 400px;
}
.legend_list {
width: 172px;
height: 173px;
padding: 10px 20px;
background: rgba(31, 31, 31, 0.5);
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
position: absolute;
bottom: 0;
right: 0;
}
.legend_item {
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
}
.legend_point {
width: 24px;
height: 24px;
margin-right: 24px;
border-radius: 50%;
border: 1px solid #fff;
}
.legend_name {
font-size: 16px;
color: #fff;
}
</style>

+ 65
- 0
src/components/PositionMsg/util.js Dosyayı Görüntüle

@@ -0,0 +1,65 @@
import 'ol/ol.css'
import { Style, Icon } from 'ol/style'
import imgAwait from '../../assets/point/await.png'
import imgChecked from '../../assets/point/checked.png'
import imgIgnored from '../../assets/point/ignored.png'
import imgSelected from '../../assets/point/selected.png'

// 矢量图标样式
export const styleList = [
new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: imgSelected,
crossOrigin: '',
scale: [1, 1],
rotateWithView: true
})
}),
new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: imgAwait,
crossOrigin: '',
scale: [1, 1],
rotateWithView: true
})
}),
new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: imgChecked,
crossOrigin: '',
scale: [1, 1],
rotateWithView: true
})
}),
new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: imgIgnored,
crossOrigin: '',
scale: [1, 1],
rotateWithView: true
})
})
]

export const legendList = [
{
name: '待确认问题',
color: '#F1EA0B'
},
{
name: '当前问题',
color: '#1AFA29'
},
{
name: '已忽略问题',
color: '#FF8A15'
},
{
name: '已确定问题',
color: '#FF3333'
}
]

+ 1
- 1
src/router/routes/modules/index.js Dosyayı Görüntüle

@@ -11,7 +11,7 @@ export default [
},
children: [
{
path: 'allTask',
path: 'all',
component: () => import('@/views/task-manage/all-task/index.vue'),
name: 'TaskAll',
title: '所有任务',

+ 3
- 1
src/views/task-manage/all-task/components/VerifyDrawer.vue Dosyayı Görüntüle

@@ -29,7 +29,9 @@ export default defineComponent({
'update:visible': null
},
setup(props, { emit }) {
const data = reactive({})
const data = reactive({

})

/* 获取抽屉的信息 */
const getDrawerOptions = computed(() => {

+ 3
- 2
src/views/task-manage/all-task/index.vue Dosyayı Görüntüle

@@ -5,7 +5,7 @@
<DataTable
ref="tableRef"
:columns="columns"
:request="loadDataTable"
:data="data"
:row-key="(row) => row.id"
size="large"
>
@@ -55,7 +55,8 @@ export default {
setup() {
const data = reactive({
search,
...toRefs(table)
...toRefs(table),
data: [{}]
})

/**

+ 101
- 0
src/views/task-manage/question/components/PositionDrawer.vue Dosyayı Görüntüle

@@ -0,0 +1,101 @@
<template>
<n-drawer v-bind="getDrawerOptions" @update:show="handleDrawerColse">
<n-drawer-content closable title="图片位置">
<position-msg :data="problemList" />
</n-drawer-content>
</n-drawer>
</template>

<script>
import { defineComponent, computed, reactive, toRefs, provide } from 'vue'
import PositionMsg from '@/components/PositionMsg/index.vue'

export default defineComponent({
name: 'PositionDrawer',
components: { PositionMsg },
props: {
/* 可见 */
visible: {
type: Boolean,
default: false
},
/* 选中的数据 */
data: {
type: Object,
default: () => {}
}
},
emits: {
'update:visible': null
},
setup(props, { emit }) {
const data = reactive({
problemList: [
{ content: '河道内存在水生植被',
fileImage: 'https://image.t-aaron.com/XJRW20220725103839/2022-07-25-10-41-46_frame-1500-1680_type-水生植被_VMgRwh05s4clHXCu_s-live-XJRW20220725103839-b73c470768f74422b287981fc75c31c3_AI.jpg',
handlerImage: 'https://image.t-aaron.com/imagedir/kw6vv4m1yw_1658717157035.png',
handlerResult: '',
handlerTime: '2022-07-25 10:45:56',
latitude: '31.829037194418085',
location: '江苏省南京市江宁区秣陵街道东吉大道',
longitude: '118.770222690945',
name: 1,
status: 1,
type: 1,
userName: '运管单位' },
{ content: '水生植被',
fileImage: 'https://image.t-aaron.com/XJRW20220725103839/2022-07-25-10-41-46_frame-1500-1680_type-水生植被_VMgRwh05s4clHXCu_s-live-XJRW20220725103839-b73c470768f74422b287981fc75c31c3_AI.jpg',
handlerImage: 'https://image.t-aaron.com/imagedir/kw6vv4m1yw_1658717157035.png',
handlerResult: '',
handlerTime: '2022-07-25 10:45:56',
latitude: '31.129037194418085',
location: '江苏省南京市江宁区秣陵街道东吉大道',
longitude: '118.880222690945',
name: 1,
status: 2,
type: 2,
userName: '运管单位' }
]
})

const confirm = function(params) {
console.log(params, '确认++++++++++++')
}

const ignore = function(params) {
console.log(params, '忽略------------')
}

/* 注册确认方法 */
provide('confirm', confirm)

/* 注册忽略方法 */
provide('ignore', ignore)
/* 获取抽屉的信息 */
const getDrawerOptions = computed(() => {
return {
show: props.visible,
width: '100%',
placement: 'right'
}
})

/* 关闭抽屉 */
function handleDrawerColse() {
emit('update:visible', false)
}

return {
...toRefs(data),
getDrawerOptions,
handleDrawerColse
}
}
})
</script>

<style scoped lang='scss'>
.n-button+.n-button{
margin-left: 30px;
}
</style>

+ 9
- 4
src/views/task-manage/question/index.vue Dosyayı Görüntüle

@@ -20,6 +20,9 @@

<ConfirmModal v-if="confirmModal" v-model:visible="confirmModal" :data="pageData" @update-data="tableReload" />

<!-- 图片位置 -->
<position-drawer v-model:visible="positionDrawer" :data="rowData" />

</template>

<script>
@@ -28,19 +31,21 @@ import search from './tools/search.js'
import HeadSearch from '@/components/Search/index.vue'
import DataTable from '@/components/DataTable/index.vue'
import ConfirmModal from './components/ConfirmModal.vue'
import { h, computed, ref, reactive, toRefs } from 'vue'
import PositionDrawer from './components/PositionDrawer.vue'
import { ref, reactive, toRefs } from 'vue'
export default {
name: 'QuestionPage',
components: { HeadSearch, DataTable, ConfirmModal },
components: { HeadSearch, DataTable, ConfirmModal, PositionDrawer },
setup() {
const data = reactive({
search,
...toRefs(table),
data: [
{ id: 1, image: 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel1.jpeg', type: 1 },
{ id: 2, image: 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel2.jpeg', type: 2 }
{ id: 1, image: 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel1.jpeg', position: '软件园', type: 1 },
{ id: 2, image: 'https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel2.jpeg', position: '东吉大道一号', type: 2 }
],
pageData: []

})

/**

+ 27
- 2
src/views/task-manage/question/tools/table.js Dosyayı Görüntüle

@@ -15,6 +15,12 @@ function handleRowConfirm(row) {
console.log('问题确认')
}

/* 位置 */
function handlePositionDrawer(row) {
data.rowData = row
data.positionDrawer = true
}

function handleImgPreview() {
data.confirmModal = true
}
@@ -22,6 +28,7 @@ function handleImgPreview() {
const data = reactive({
rowData: {},
confirmModal: false,
positionDrawer: false,
columns: [
{
type: 'selection'
@@ -59,8 +66,26 @@ const data = reactive({
},
{
title: '位置',
key: 'name',
align: 'center'
key: 'position',
align: 'center',
render(row) {
return h(TableAction, {
actions: [
{
label: '图片位置',
type: 'button',
props: {
type: 'primary',
text: true,
onClick: handlePositionDrawer.bind(null, row)
},
auth: 'basic_list',
show: row.status !== 1
}
],
align: 'center'
})
}
},
{
title: '备注',

Yükleniyor…
İptal
Kaydet