From 08ab4ebee26bb6c275b68c350bfa93ae770d6fee Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 30 Jan 2026 16:26:27 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'
---
applications/task-work-order/src/views/orderView/flyingHand/FlyingHandDialog.vue | 4
applications/task-work-order/src/views/orderView/flyingHand/index.vue | 2
applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue | 208 +++++++++++++++++++++++++++++++++++++++++
applications/drone-command/src/views/api.txt | 6
applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue | 16 +-
applications/task-work-order/src/styles/common/cockpit.scss | 22 ++++
applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue | 11 +-
7 files changed, 250 insertions(+), 19 deletions(-)
diff --git a/applications/drone-command/src/views/api.txt b/applications/drone-command/src/views/api.txt
index 4563847..5480053 100644
--- a/applications/drone-command/src/views/api.txt
+++ b/applications/drone-command/src/views/api.txt
@@ -3,7 +3,7 @@
## 列表-不带分页
-**接口地址**:`/drone-fw/area/fwAreaDivide/list`
+**接口地址**:`/area/fwAreaDivide/list`
**请求方式**:`GET`
@@ -15,7 +15,7 @@
**响应数据类型**:`*/*`
-**接口描述**:<p>传入filterSelected或sceneId或areaTypeKeys</p>
+**接口描述**:<p>传入filterSelected或sceneId或areaTypeKeys或isSetSceneManage或flyTime</p>
@@ -29,6 +29,8 @@
| -------- | -------- | ----- | -------- | -------- | ------ |
|areaTypeKeys|区域类型key集合(逗号分隔)|query|false|string||
|filterSelected|是否过滤已被选择的数据(1过滤 0不过滤)|query|false|integer(int32)||
+|flyTime|时间筛选(yyyy-MM-dd HH:mm:ss)|query|false|string(date-time)||
+|isSetSceneManage|是否按场景管理过滤(1是 0或空否)|query|false|integer(int32)||
|sceneId|场景id|query|false|integer(int64)||
diff --git a/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue b/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
index eba09ef..e3818e6 100644
--- a/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
+++ b/applications/drone-command/src/views/areaManage/sceneManage/FormDiaLog.vue
@@ -146,6 +146,9 @@
import commandPost from '@/assets/images/dataCockpit/legend/command-post.png'
import { saveOperationLog } from '@ztzf/apis'
import { useRoute } from 'vue-router'
+import { fwAreaDivideDetailApi, fwAreaDivideListApi } from '../partition/partitionApi'
+import { buildEllipsePositions } from '@/utils/cesium/shapeTools'
+import { AREA_TYPE_STYLE_MAP, BUFFER_LEVEL_STYLES, DEFAULT_AREA_STYLE } from '@ztzf/constants'
// 初始化表单数据
const initForm = () => ({
@@ -169,10 +172,12 @@
const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
const effectiveDateRange = ref([]) // 有效时间范围
const sceneConfigList = ref([]) // 场景配置列表
+const areaList = ref([]) // ????
const mapRef = ref(null)
const route = useRoute()
let viewer
let redPointEntity
+let areaDisplaySource
let leftClickBound = false
// 表单验证规则
@@ -229,6 +234,189 @@
}
// 获取场景配置列表
+// ?????
+function ensureAreaDisplaySource() {
+ if (!viewer) return null
+ if (!areaDisplaySource) {
+ areaDisplaySource = new Cesium.CustomDataSource('scene-manage-area-display')
+ viewer.dataSources.add(areaDisplaySource)
+ }
+ return areaDisplaySource
+}
+
+function clearAreaDisplay() {
+ if (!areaDisplaySource) return
+ areaDisplaySource.entities.removeAll()
+}
+
+function normalizeShapePoint(point) {
+ if (!point) return null
+ const lng = point?.lng ?? point?.longitude
+ const lat = point?.lat ?? point?.latitude
+ const height = Number.isFinite(Number(point?.height)) ? Number(point.height) : 0
+ if (!Number.isFinite(Number(lng)) || !Number.isFinite(Number(lat))) return null
+ return { lng: Number(lng), lat: Number(lat), height }
+}
+
+function buildShapePositions(points = []) {
+ const normalized = points.map(normalizeShapePoint).filter(Boolean)
+ return normalized.map(point => Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.height))
+}
+
+function getShapeDisplayPoints(shape) {
+ if (Array.isArray(shape?.displayPoints) && shape.displayPoints.length) {
+ return shape.displayPoints
+ }
+ return shape?.points || []
+}
+
+function getAreaTypeStyle(areaType) {
+ return AREA_TYPE_STYLE_MAP?.[String(areaType)] || DEFAULT_AREA_STYLE
+}
+
+function parseGeomJson(geomJson) {
+ if (!geomJson) return null
+ if (typeof geomJson === 'object') return geomJson
+ if (typeof geomJson !== 'string') return null
+ const trimmed = geomJson.trim()
+ if (!trimmed) return null
+ try {
+ return JSON.parse(trimmed)
+ } catch (error) {
+ return null
+ }
+}
+
+function resolveAreaShapes(area) {
+ const extList = Array.isArray(area?.fwAreaDivideExtList) ? area.fwAreaDivideExtList : []
+ if (!extList.length) return []
+ return extList
+ .map((item, index) => {
+ const isShapePayload = item?.drawType || item?.points
+ if (isShapePayload) {
+ return {
+ id: item?.id || `shape_${Date.now()}_${index}_${Math.random().toString(16).slice(2, 6)}`,
+ drawType: item?.drawType ?? 'polygon',
+ areaType: item?.areaType ?? item?.areaTypeKey ?? '',
+ points: Array.isArray(item?.points) ? item.points : [],
+ displayPoints: Array.isArray(item?.displayPoints) ? item.displayPoints : null,
+ meta: item?.meta ?? null,
+ }
+ }
+ const parsed = parseGeomJson(item?.geomJson)
+ if (!parsed) return null
+ return {
+ id: parsed?.id || `shape_${Date.now()}_${index}_${Math.random().toString(16).slice(2, 6)}`,
+ drawType: parsed?.drawType ?? 'polygon',
+ areaType: item?.areaTypeKey ?? parsed?.areaType ?? '',
+ points: Array.isArray(parsed?.points) ? parsed.points : [],
+ displayPoints: Array.isArray(parsed?.displayPoints) ? parsed.displayPoints : null,
+ meta: parsed?.meta ?? null,
+ }
+ })
+ .filter(Boolean)
+}
+
+function renderSceneAreas() {
+ if (!visible.value) {
+ clearAreaDisplay()
+ return
+ }
+ if (!viewer) initMap()
+ const dataSource = ensureAreaDisplaySource()
+ if (!dataSource) return
+ dataSource.entities.removeAll()
+ areaList.value.forEach(area => {
+ const shapes = resolveAreaShapes(area)
+ shapes.forEach(shape => {
+ if (shape.drawType === 'buffer' && shape.meta?.bufferRadii?.length && shape.meta?.center) {
+ const center = shape.meta.center
+ const centerCartesian = Cesium.Cartesian3.fromDegrees(center.lng, center.lat, center.height || 0)
+ const radii = shape.meta.bufferRadii
+ .map(radius => Number(radius))
+ .filter(radius => Number.isFinite(radius) && radius > 0)
+ radii.forEach((radius, index) => {
+ const style = BUFFER_LEVEL_STYLES[index] || BUFFER_LEVEL_STYLES[BUFFER_LEVEL_STYLES.length - 1]
+ dataSource.entities.add({
+ name: 'scene-manage-area-display',
+ customData: { drawType: shape.drawType, level: index + 1 },
+ position: centerCartesian,
+ ellipse: {
+ semiMajorAxis: radius,
+ semiMinorAxis: radius,
+ material: style.fill,
+ outline: false,
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+ },
+ })
+ const positions = buildEllipsePositions(centerCartesian, radius, radius)
+ dataSource.entities.add({
+ name: 'scene-manage-area-display',
+ customData: { drawType: shape.drawType, level: index + 1, outline: true },
+ polyline: {
+ positions: positions.length ? [...positions, positions[0]] : positions,
+ clampToGround: true,
+ width: 2,
+ material: style.outline,
+ },
+ })
+ })
+ return
+ }
+ const positions = buildShapePositions(getShapeDisplayPoints(shape))
+ if (positions.length < 3) return
+ const style = getAreaTypeStyle(shape.areaType)
+ dataSource.entities.add({
+ name: 'scene-manage-area-display',
+ customData: { drawType: shape.drawType },
+ polygon: {
+ hierarchy: new Cesium.PolygonHierarchy(positions),
+ material: style.fill,
+ outline: false,
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+ },
+ polyline: {
+ positions: positions.length ? [...positions, positions[0]] : positions,
+ clampToGround: true,
+ width: 2,
+ material: style.outline,
+ },
+ })
+ })
+ })
+}
+
+async function ensureAreaExtList(rows) {
+ const missingRows = rows.filter(row => row?.id && !Array.isArray(row?.fwAreaDivideExtList))
+ if (!missingRows.length) return rows
+ const detailList = await Promise.all(
+ missingRows.map(row =>
+ fwAreaDivideDetailApi({ id: row.id })
+ .then(res => res?.data?.data)
+ .catch(() => null)
+ )
+ )
+ const detailMap = new Map(detailList.filter(Boolean).map(item => [String(item.id), item]))
+ if (!detailMap.size) return rows
+ return rows.map(item => {
+ const detail = detailMap.get(String(item.id))
+ return detail ? { ...item, ...detail } : item
+ })
+}
+
+// ??????????
+async function loadAreaList(sceneId) {
+ if (!sceneId) {
+ areaList.value = []
+ clearAreaDisplay()
+ return
+ }
+ const res = await fwAreaDivideListApi({ sceneId })
+ const list = res?.data?.data ?? []
+ areaList.value = await ensureAreaExtList(list)
+ renderSceneAreas()
+}
+
async function getSceneConfigList() {
if (sceneConfigList.value.length) return
const res = await fwDefenseSceneListApi({unbound: 1})
@@ -267,7 +455,7 @@
}
// 地图左键点击事件
-function LeftClickEvent(click) {
+async function LeftClickEvent(click) {
const pos = click.position
// 优先使用 pickPosition 获取贴地坐标(包含地形高度)
let cartesian3 = viewer.scene.pickPosition(pos)
@@ -282,6 +470,7 @@
formData.value.longitude = _.round(longitude, 6)
formData.value.latitude = _.round(latitude, 6)
setMapPoint(formData.value.longitude, formData.value.latitude)
+ await loadAreaList(formData.value.defenseSceneId)
}
// 设置地图点位
@@ -333,12 +522,29 @@
}
await nextTick()
setMapPoint(formData.value.longitude, formData.value.latitude)
+ await loadAreaList(formData.value.defenseSceneId)
}
onMounted(() => {
getSceneConfigList()
})
+watch(
+ () => formData.value.defenseSceneId,
+ sceneId => {
+ if (!visible.value) return
+ loadAreaList(sceneId)
+ }
+)
+
+watch(
+ () => visible.value,
+ val => {
+ if (!val) clearAreaDisplay()
+ }
+)
+
+
defineExpose({
open,
})
diff --git a/applications/task-work-order/src/styles/common/cockpit.scss b/applications/task-work-order/src/styles/common/cockpit.scss
index f5673b5..39ab188 100644
--- a/applications/task-work-order/src/styles/common/cockpit.scss
+++ b/applications/task-work-order/src/styles/common/cockpit.scss
@@ -31,6 +31,7 @@
&::placeholder {
color: var(--tips);
}
+ color: #383874;
}
&.is-disabled {
@@ -122,6 +123,7 @@
&::placeholder {
color: var(--tips);
}
+ color: #383874;
}
.el-range-separator {
@@ -1188,4 +1190,24 @@
}
}
}
+}
+
+.gd-dialog-form {
+ // 最后一排不需要设置 margin-bottom
+ // border: 1px solid red;
+ // 倒数第二个也设置为0
+ // .el-col:nth-last-child(2) {
+ // margin-bottom: 0;
+ // }
+ // .el-col:nth-last-child(1) {
+ // margin-bottom: 0;
+ // }
+
+ // .el-form-item:nth-last-child(2) {
+ // margin-bottom: 0;
+ // }
+ // .el-form-item:nth-last-child(1) {
+ // margin-bottom: 0;
+ // }
+
}
\ No newline at end of file
diff --git a/applications/task-work-order/src/views/orderView/flyingHand/FlyingHandDialog.vue b/applications/task-work-order/src/views/orderView/flyingHand/FlyingHandDialog.vue
index f58c380..29fff53 100644
--- a/applications/task-work-order/src/views/orderView/flyingHand/FlyingHandDialog.vue
+++ b/applications/task-work-order/src/views/orderView/flyingHand/FlyingHandDialog.vue
@@ -191,7 +191,7 @@
color="#4C34FF"
@click="handleSubmit"
>
- 确定
+ 保存
</el-button>
</template>
</el-dialog>
@@ -234,7 +234,7 @@
const dialogTitle = computed(() => {
switch (props.dialogType) {
case 'add':
- return '新增'
+ return '飞手建档'
case 'edit':
return '编辑'
case 'view':
diff --git a/applications/task-work-order/src/views/orderView/flyingHand/index.vue b/applications/task-work-order/src/views/orderView/flyingHand/index.vue
index 8972b67..c499452 100644
--- a/applications/task-work-order/src/views/orderView/flyingHand/index.vue
+++ b/applications/task-work-order/src/views/orderView/flyingHand/index.vue
@@ -49,7 +49,7 @@
</el-form>
<div class="gd-table-toolbar">
- <el-button :icon="Plus" color="#4C34FF" type="primary" @click="addFlyingHand">新增</el-button>
+ <el-button :icon="Plus" color="#4C34FF" type="primary" @click="addFlyingHand">飞手建档</el-button>
</div>
<div class="gd-table-container" v-loading="loading">
diff --git a/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue b/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
index 4a13918..11c31a3 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
@@ -31,12 +31,10 @@
<el-table-column prop="distributeUserName" show-overflow-tooltip label="分发人员" />
<el-table-column label="操作" class-name="operation-btns" width="140">
<template v-slot="{ row }">
- <el-link type="primary"
- @click="openDistributeDialog(row)"
- :disabled="!requester || (row.distributeStatus === 1 || currentRow.taskStatus !== '8')"
- >
+ <el-link type="primary" @click="openDistributeDialog(row)" v-if="permission.clueEvents_distribute && (row.distributeStatus === 0 || row.distributeStatus === 2)">
转为事件并分发
</el-link>
+ <el-button disabled type="text" v-else>转为事件并分发</el-button>
</template>
</el-table-column>
</el-table>
@@ -64,6 +62,9 @@
const requester = computed(() => store.state.user.userInfo?.role_id === '2014158512610869250')
const activeName = ref('all')
+const permission = computed(() => store.state.user.permission)
+console.log(permission.value.clueEvents_distribute, 'permission')
+
const visible = defineModel()
const loading = ref(false)
const list = ref([])
@@ -75,7 +76,7 @@
const distributeStatusOptions = [
{ label: '未分发', value: 0 },
{ label: '已分发', value: 1 },
- { label: '已驳回', value: 2 },
+ { label: '已退回', value: 2 },
{ label: '已确认', value: 3 },
]
diff --git a/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue b/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
index 5e322fa..fd0cd13 100644
--- a/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
+++ b/applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
@@ -10,10 +10,10 @@
<el-table class="gd-table" :data="tableList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="46" />
<el-table-column label="序号" type="index" width="60"></el-table-column>
- <el-table-column prop="operatingIncome" label="营业收入" align="center"></el-table-column>
- <el-table-column prop="totalCost" label="综合总成本费用" align="center"></el-table-column>
- <el-table-column prop="netProfit" label="净利润" align="center"></el-table-column>
- <el-table-column prop="financialIrr" label="财务内部收益率" align="center"></el-table-column>
+ <el-table-column prop="operatingIncome" label="营业收入(元)" align="center"></el-table-column>
+ <el-table-column prop="totalCost" label="综合总成本费用(元)" align="center"></el-table-column>
+ <el-table-column prop="netProfit" label="净利润(元)" align="center"></el-table-column>
+ <el-table-column prop="financialIrr" label="财务内部收益率(%)" align="center"></el-table-column>
<el-table-column prop="marketSpace" label="市场空间" align="center" show-overflow-tooltip></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
<el-table-column prop="nickName" label="创建人" align="center"></el-table-column>
@@ -36,12 +36,12 @@
<el-form class="gd-dialog-form" ref="ruleFormRef" :model="editParams" :rules="rules" label-width="140px">
<el-row>
<el-col :span="12">
- <el-form-item label="营业收入" prop="operatingIncome">
+ <el-form-item label="营业收入(元)" prop="operatingIncome">
<el-input class="gd-input" v-model="editParams.operatingIncome" />
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="综合总成本费用" prop="totalCost">
+ <el-form-item label="综合总成本费用(元)" prop="totalCost">
<el-input class="gd-input" v-model="editParams.totalCost" />
</el-form-item>
</el-col>
@@ -49,12 +49,12 @@
<el-row>
<el-col :span="12">
- <el-form-item label="净利润" prop="netProfit">
+ <el-form-item label="净利润(元)" prop="netProfit">
<el-input class="gd-input" v-model="editParams.netProfit" />
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="财务内部收益率" prop="financialIrr">
+ <el-form-item label="财务内部收益率(%)" prop="financialIrr">
<el-input class="gd-input" v-model="editParams.financialIrr" />
</el-form-item>
</el-col>
--
Gitblit v1.9.3