@@ -0,0 +1,14 @@ | |||
# 资源公共路径,需要以 /开头和结尾 | |||
VITE_PUBLIC_PATH = '/' | |||
# 是否启用MOCK | |||
VITE_APP_USE_MOCK = false | |||
# proxy | |||
VITE_PROXY = [["/api-local","http://127.0.0.1:8002"],["/api-mock","http://127.0.0.1:8003"]] | |||
# base api | |||
VITE_APP_GLOB_BASE_API = '/api-local' | |||
# mock base api | |||
VITE_APP_GLOB_BASE_API_MOCK = '/api-mock' |
@@ -9,18 +9,19 @@ | |||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||
<link rel="icon" href="/favicon.ico" /> | |||
<!-- IE需要es6-promise,目前支持到IE10 --> | |||
<script src="./public/aliyun-upload-sdk/lib/es6-promise.min.js"></script> | |||
<script src="./public/aliyun-upload-sdk/lib/aliyun-oss-sdk-6.13.0.min.js"></script> | |||
<script src="./public/aliyun-upload-sdk/aliyun-upload-sdk-1.5.2.min.js"></script> | |||
<title> | |||
<%= title %> | |||
</title> | |||
<script type="text/javascript"> | |||
window._AMapSecurityConfig = { | |||
// serviceHost:'http://127.0.0.1:8002/_AMapService', | |||
// 例如 :serviceHost:'http://1.1.1.1:80/_AMapService', | |||
securityJsCode: '935114b12a268130801d10a1d874418a', | |||
securityJsCode: 'eb839debb422cd65cc598664067ee7d8' | |||
} | |||
</script> | |||
<!-- <script type="text/javascript" | |||
src="https://webapi.amap.com/maps?v=1.4.15&key=20535a30fa0f3aae9c7bbe4407270792"></script> --> | |||
<style type="text/css"> | |||
.amap-logo { | |||
display: none; |
@@ -14,6 +14,7 @@ | |||
"@vicons/ionicons5": "^0.10.0", | |||
"ali-oss": "^6.17.1", | |||
"axios": "^0.26.1", | |||
"chart-all": "^1.0.2", | |||
"dayjs": "^1.11.2", | |||
"mockjs": "^1.1.0", | |||
"pinia": "^2.0.13", | |||
@@ -2849,6 +2850,17 @@ | |||
"url": "https://github.com/chalk/chalk?sponsor=1" | |||
} | |||
}, | |||
"node_modules/chart-all": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/chart-all/-/chart-all-1.0.2.tgz", | |||
"integrity": "sha512-gxkvz4rsnsr+nM5pnQt+4m6lKkie8JQYRhsyae+VlWMn3iR2iqhQo98AsYFUgKZAdm0Cvsh6ZvDlZnLx2VwLZg==", | |||
"dependencies": { | |||
"echarts": "^4.9.0", | |||
"echarts-gl": "^1.1.2", | |||
"echarts-liquidfill": "^2.0.6", | |||
"zrender": "^4.3.1" | |||
} | |||
}, | |||
"node_modules/chokidar": { | |||
"version": "3.5.3", | |||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", | |||
@@ -2903,6 +2915,11 @@ | |||
"integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", | |||
"dev": true | |||
}, | |||
"node_modules/claygl": { | |||
"version": "1.3.0", | |||
"resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz", | |||
"integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==" | |||
}, | |||
"node_modules/clean-css": { | |||
"version": "5.3.0", | |||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", | |||
@@ -4103,6 +4120,40 @@ | |||
"node": ">=6.0.0" | |||
} | |||
}, | |||
"node_modules/echarts": { | |||
"version": "4.9.0", | |||
"resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz", | |||
"integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==", | |||
"dependencies": { | |||
"zrender": "4.3.2" | |||
} | |||
}, | |||
"node_modules/echarts-gl": { | |||
"version": "1.1.2", | |||
"resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-1.1.2.tgz", | |||
"integrity": "sha512-EVGx9RS2eMzaCgAMJSDCeLId4g8oFCFn78Fdh+0xIXASiZw/gPnJqr1vQgnQhmXhiUKixkIhIzfdc//qrct/Hg==", | |||
"dependencies": { | |||
"claygl": "^1.2.1", | |||
"zrender": "^4.0.4" | |||
}, | |||
"peerDependencies": { | |||
"echarts": "^4.1.0" | |||
} | |||
}, | |||
"node_modules/echarts-liquidfill": { | |||
"version": "2.0.6", | |||
"resolved": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-2.0.6.tgz", | |||
"integrity": "sha512-p+AH0O9/BtwXMQQyhjJbMZo+GwRAgWG/DCyK5r27PQzpS0UWrgXu57MyEFc0A8Ub3sRuqEu08BuxwHICBkSWSQ==", | |||
"peerDependencies": { | |||
"echarts": "^4.8.0", | |||
"zrender": "^4.3.1" | |||
} | |||
}, | |||
"node_modules/echarts/node_modules/zrender": { | |||
"version": "4.3.2", | |||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.2.tgz", | |||
"integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g==" | |||
}, | |||
"node_modules/ee-first": { | |||
"version": "1.1.1", | |||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", | |||
@@ -12126,6 +12177,11 @@ | |||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", | |||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", | |||
"dev": true | |||
}, | |||
"node_modules/zrender": { | |||
"version": "4.3.1", | |||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.1.tgz", | |||
"integrity": "sha512-CeH2TpJeCdG0TAGYoPSAcFX2ogdug1K7LIn9UO/q9HWqQ54gWhrMAlDP9AwWYMUDhrPe4VeazQ4DW3msD96nUQ==" | |||
} | |||
}, | |||
"dependencies": { | |||
@@ -14376,6 +14432,17 @@ | |||
"integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", | |||
"dev": true | |||
}, | |||
"chart-all": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/chart-all/-/chart-all-1.0.2.tgz", | |||
"integrity": "sha512-gxkvz4rsnsr+nM5pnQt+4m6lKkie8JQYRhsyae+VlWMn3iR2iqhQo98AsYFUgKZAdm0Cvsh6ZvDlZnLx2VwLZg==", | |||
"requires": { | |||
"echarts": "^4.9.0", | |||
"echarts-gl": "^1.1.2", | |||
"echarts-liquidfill": "^2.0.6", | |||
"zrender": "^4.3.1" | |||
} | |||
}, | |||
"chokidar": { | |||
"version": "3.5.3", | |||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", | |||
@@ -14415,6 +14482,11 @@ | |||
"integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", | |||
"dev": true | |||
}, | |||
"claygl": { | |||
"version": "1.3.0", | |||
"resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz", | |||
"integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==" | |||
}, | |||
"clean-css": { | |||
"version": "5.3.0", | |||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.0.tgz", | |||
@@ -15325,6 +15397,36 @@ | |||
"integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", | |||
"dev": true | |||
}, | |||
"echarts": { | |||
"version": "4.9.0", | |||
"resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz", | |||
"integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==", | |||
"requires": { | |||
"zrender": "4.3.2" | |||
}, | |||
"dependencies": { | |||
"zrender": { | |||
"version": "4.3.2", | |||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.2.tgz", | |||
"integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g==" | |||
} | |||
} | |||
}, | |||
"echarts-gl": { | |||
"version": "1.1.2", | |||
"resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-1.1.2.tgz", | |||
"integrity": "sha512-EVGx9RS2eMzaCgAMJSDCeLId4g8oFCFn78Fdh+0xIXASiZw/gPnJqr1vQgnQhmXhiUKixkIhIzfdc//qrct/Hg==", | |||
"requires": { | |||
"claygl": "^1.2.1", | |||
"zrender": "^4.0.4" | |||
} | |||
}, | |||
"echarts-liquidfill": { | |||
"version": "2.0.6", | |||
"resolved": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-2.0.6.tgz", | |||
"integrity": "sha512-p+AH0O9/BtwXMQQyhjJbMZo+GwRAgWG/DCyK5r27PQzpS0UWrgXu57MyEFc0A8Ub3sRuqEu08BuxwHICBkSWSQ==", | |||
"requires": {} | |||
}, | |||
"ee-first": { | |||
"version": "1.1.1", | |||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", | |||
@@ -21255,6 +21357,11 @@ | |||
"dev": true | |||
} | |||
} | |||
}, | |||
"zrender": { | |||
"version": "4.3.1", | |||
"resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.1.tgz", | |||
"integrity": "sha512-CeH2TpJeCdG0TAGYoPSAcFX2ogdug1K7LIn9UO/q9HWqQ54gWhrMAlDP9AwWYMUDhrPe4VeazQ4DW3msD96nUQ==" | |||
} | |||
} | |||
} |
@@ -15,6 +15,7 @@ | |||
"@vicons/ionicons5": "^0.10.0", | |||
"ali-oss": "^6.17.1", | |||
"axios": "^0.26.1", | |||
"chart-all": "^1.0.2", | |||
"dayjs": "^1.11.2", | |||
"mockjs": "^1.1.0", | |||
"pinia": "^2.0.13", |
@@ -2,19 +2,27 @@ import { defAxios as request } from '@/utils/http' | |||
/** | |||
* 无人机列表 | |||
* @returns | |||
* @returns | |||
*/ | |||
export const getEquipment = () => request({ | |||
url: '/equipment/getList', | |||
method: 'GET' | |||
}) | |||
/** | |||
* 挂载设备列表 | |||
* @returns | |||
* @returns | |||
*/ | |||
export const getEquipmentMount = () => request({ | |||
url: '/equipmentMount/getList', | |||
method: 'GET' | |||
}) | |||
}) | |||
/** | |||
* 挂载盒子 | |||
* @returns | |||
*/ | |||
export const getCloud = () => request({ | |||
url: '/cloudBox/getList', | |||
method: 'GET' | |||
}) |
@@ -2,9 +2,9 @@ import { defAxios as request } from '@/utils/http' | |||
/** | |||
* 任务查询 | |||
* @returns | |||
* @returns | |||
*/ | |||
export const getTaskList = params => request({ | |||
export const getTaskList = params => request({ | |||
url: '/task/getTaskList', | |||
method: 'GET', | |||
params | |||
@@ -13,17 +13,16 @@ import { defAxios as request } from '@/utils/http' | |||
/** | |||
* 任务详情 | |||
* @param {*} params id | |||
* @returns | |||
* @returns | |||
*/ | |||
export const getTaskInfo = params => request({ | |||
export const getTaskInfo = params => request({ | |||
url: `/task/getInfo/${params}`, | |||
method: 'GET' | |||
}) | |||
/** | |||
* 获取飞手列表 | |||
* @returns | |||
* @returns | |||
*/ | |||
export const getTaskPilot = () => request({ | |||
url: '/task/getPilot', | |||
@@ -33,9 +32,9 @@ export const getTaskPilot = () => request({ | |||
/** | |||
* 添加任务 | |||
* @param {*} params | |||
* @returns | |||
* @returns | |||
*/ | |||
export const taskAdd = data => request({ | |||
export const taskAdd = data => request({ | |||
url: '/task/add', | |||
method: 'POST', | |||
data | |||
@@ -44,9 +43,9 @@ export const getTaskPilot = () => request({ | |||
/** | |||
* 编辑任务 | |||
* @param {*} params | |||
* @returns | |||
* @returns | |||
*/ | |||
export const taskEdit = data => request({ | |||
export const taskEdit = data => request({ | |||
url: '/task/edit', | |||
method: 'PUT', | |||
data | |||
@@ -55,9 +54,9 @@ export const getTaskPilot = () => request({ | |||
/** | |||
* 删除任务 | |||
* @param {*} params | |||
* @returns | |||
* @returns | |||
*/ | |||
export const taskDel = params => request({ | |||
export const taskDel = params => request({ | |||
url: `/task/delete/${params}`, | |||
method: 'DELETE' | |||
}) | |||
@@ -65,10 +64,43 @@ export const getTaskPilot = () => request({ | |||
/** | |||
* 分配飞手 | |||
* @param {*} params | |||
* @returns | |||
* @returns | |||
*/ | |||
export const distributionPilot = data => request({ | |||
export const distributionPilot = data => request({ | |||
url: '/task/distributionPilot', | |||
method: 'PUT', | |||
data | |||
}) | |||
}) | |||
/** | |||
* 飞手接单 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export const pilotOrder = data => request({ | |||
url: '/task/pilotOrder', | |||
method: 'PUT', | |||
data | |||
}) | |||
/** | |||
* 开始飞行 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export const pilotStart = data => request({ | |||
url: '/task/pilotStart', | |||
method: 'PUT', | |||
data | |||
}) | |||
/** | |||
* 结束飞行 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export const pilotEnd = data => request({ | |||
url: '/task/pilotEnd', | |||
method: 'PUT', | |||
data | |||
}) |
@@ -80,3 +80,19 @@ export const TASK_STATUS = [ | |||
value: 25 | |||
} | |||
] | |||
// 拍摄方式 | |||
export const PHOTOGRAPHY_WAY = [ | |||
{ | |||
label: '普通巡检', | |||
value: '1' | |||
}, | |||
{ | |||
label: '正射影像', | |||
value: '2' | |||
}, | |||
{ | |||
label: '倾斜摄影', | |||
value: '3' | |||
} | |||
] |
@@ -0,0 +1,24 @@ | |||
## use | |||
```js | |||
<template> | |||
<div id="testLine" style="width: 50%; height: 300px;"></div> | |||
</template> | |||
<script> | |||
import { onMounted } from "vue"; | |||
import myChart from "@/utils/echarts"; | |||
export default { | |||
name: "about", | |||
setup() { | |||
onMounted(() => { | |||
myChart.line1('testLine', (e) => { | |||
console.log('点我了', e) | |||
}); | |||
}) | |||
} | |||
} | |||
</script> | |||
``` |
@@ -0,0 +1,247 @@ | |||
import chartClass from 'chart-all' | |||
import * as echarts from 'echarts' | |||
export default { | |||
// 首页 - 任务数据 | |||
line1: (id, data) => { | |||
const { chart } = new chartClass(id) | |||
chart.setOption({ | |||
grid: { | |||
top: '20%', | |||
left: '5%', | |||
right: '7%', | |||
bottom: '5%', | |||
containLabel: true | |||
}, | |||
tooltip: { | |||
trigger: 'axis', | |||
axisPointer: { | |||
// 坐标轴指示器,坐标轴触发有效 | |||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' | |||
} | |||
}, | |||
xAxis: [{ | |||
type: 'category', | |||
// boundaryGap: true, //坐标轴两边留白 | |||
data: data.eventNameTrend, | |||
animation: true, | |||
boundaryGap: false, // 贴边 | |||
// offset: 5, | |||
axisLine: { | |||
// x轴 | |||
show: true, | |||
lineStyle: { | |||
color: 'rgba(137, 137, 137, 0.6)' | |||
} | |||
}, | |||
axisTick: { | |||
// x轴刻度线 | |||
show: false | |||
}, | |||
axisLabel: { | |||
// x轴刻度文案 | |||
show: true | |||
}, | |||
splitLine: { | |||
// 网格 | |||
show: false | |||
} | |||
}], | |||
yAxis: [{ | |||
type: 'value', | |||
animation: true, | |||
min: 0, | |||
minInterval: 1, | |||
axisLine: { | |||
// y轴 | |||
show: false | |||
}, | |||
axisTick: { | |||
// y轴刻度线 | |||
show: false | |||
}, | |||
axisLabel: { | |||
// y轴刻度文案 | |||
show: true | |||
}, | |||
splitLine: { | |||
// 网格 | |||
show: true, | |||
lineStyle: { | |||
color: 'rgba(137, 137, 137, 0.6)' | |||
} | |||
} | |||
}], | |||
series: [{ | |||
type: 'line', | |||
emphasis: { | |||
focus: 'series' | |||
}, | |||
name: '', | |||
smooth: true, // 平滑曲线 | |||
showSymbol: true, // 节点 | |||
symbolSize: 6, | |||
animationDuration: 2500, | |||
lineStyle: { | |||
width: 2 | |||
}, | |||
itemStyle: { | |||
color: 'rgba(255,235,123, 0.8)' | |||
}, | |||
areaStyle: { | |||
normal: { | |||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
{ | |||
offset: 0, | |||
color: 'rgba(255,235,123, 0.8)' | |||
}, | |||
{ | |||
offset: 1, | |||
color: 'rgba(60,212,191, 0.8)' | |||
} | |||
]) | |||
} | |||
}, | |||
data: data.valueNameTrend | |||
}] | |||
}) | |||
}, | |||
line2: (id, data) => { | |||
const { chart } = new chartClass(id) | |||
chart.setOption({ | |||
grid: { | |||
top: '4%', | |||
left: '5%', | |||
right: '8%', | |||
bottom: '4%', | |||
containLabel: true | |||
}, | |||
legend: { | |||
show: false, | |||
data: [], | |||
right: '7%', | |||
itemWidth: 6, | |||
itemHeight: 6, | |||
textStyle: { | |||
color: '#fff', | |||
fontSize: '12' | |||
} | |||
}, | |||
tooltip: { | |||
trigger: 'axis', | |||
axisPointer: { | |||
// 坐标轴指示器,坐标轴触发有效 | |||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' | |||
} | |||
}, | |||
yAxis: [{ | |||
type: 'category', | |||
data: data.tatil, | |||
animation: true, | |||
offset: 5, | |||
axisLine: { | |||
// x轴 | |||
show: false | |||
// lineStyle: { | |||
// color: 'rgba(255, 255, 255, 0.3)' | |||
// } | |||
}, | |||
axisTick: { | |||
// x轴刻度线 | |||
show: false | |||
}, | |||
axisLabel: { | |||
// x轴刻度文案 | |||
show: true, | |||
showMaxLabel: true, | |||
rotate: 0, // 倾斜 | |||
interval: 0, | |||
formatter: function(params) { | |||
var newParamsName = '' // 最终拼接成的字符串 | |||
var paramsNameNumber = params.length // 实际标签的个数 | |||
var provideNumber = 7 // 每行能显示的字的个数 | |||
var rowNumber = Math.ceil(paramsNameNumber / provideNumber) // 换行的话,需要显示几行,向上取整 | |||
/** | |||
* 判断标签的个数是否大于规定的个数, 如果大于,则进行换行处理 如果不大于,即等于或小于,就返回原标签 | |||
*/ | |||
// 条件等同于rowNumber>1 | |||
if (paramsNameNumber > provideNumber) { | |||
/** 循环每一行,p表示行 */ | |||
for (var p = 0; p < rowNumber; p++) { | |||
var tempStr = '' // 表示每一次截取的字符串 | |||
var start = p * provideNumber // 开始截取的位置 | |||
var end = start + provideNumber // 结束截取的位置 | |||
// 此处特殊处理最后一行的索引值 | |||
if (p == rowNumber - 1) { | |||
// 最后一次不换行 | |||
tempStr = params.substring(start, paramsNameNumber) | |||
} else { | |||
// 每一次拼接字符串并换行 | |||
tempStr = params.substring(start, end) + '\n' | |||
} | |||
newParamsName += tempStr // 最终拼成的字符串 | |||
} | |||
} else { | |||
// 将旧标签的值赋给新标签 | |||
newParamsName = params | |||
} | |||
// 将最终的字符串返回 | |||
return newParamsName | |||
} | |||
}, | |||
splitLine: { | |||
// 网格 | |||
show: false | |||
} | |||
}], | |||
xAxis: [{ | |||
type: 'value', | |||
name: '', | |||
animation: true, | |||
axisLine: { | |||
// y轴 | |||
show: false | |||
}, | |||
axisTick: { | |||
// y轴刻度线 | |||
show: false | |||
}, | |||
axisLabel: { | |||
// y轴刻度文案 | |||
show: false | |||
}, | |||
splitLine: { | |||
// 网格 | |||
show: false, | |||
lineStyle: { | |||
color: 'rgba(102, 102, 102, 0.6)' | |||
} | |||
} | |||
}], | |||
series: [{ | |||
barWidth: 22, | |||
type: 'bar', | |||
emphasis: { | |||
focus: 'series' | |||
}, | |||
itemStyle: { | |||
// color: "#9AC1FD" | |||
color: '#4CD964', | |||
opacity: 0.5 | |||
}, | |||
showBackground: true, | |||
backgroundStyle: { | |||
// color: 'rgba(180, 180, 180, 0.2)' | |||
color: 'rgba(225, 106, 53, 0.2)' | |||
}, | |||
data: data.data | |||
} | |||
] | |||
} | |||
) | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
import { router } from '@/router' | |||
import { getToken, removeToken } from '@/utils/token' | |||
import { isWithoutToken } from './help' | |||
export function setupInterceptor(service) { | |||
service.interceptors.request.use( | |||
async(config) => { | |||
// 防止缓存,给get请求加上时间戳 | |||
if (config.method === 'get') { | |||
config.params = { ...config.params, t: new Date().getTime() } | |||
} | |||
// 处理不需要token的请求 | |||
if (isWithoutToken(config)) { | |||
return config | |||
} | |||
// const token = getToken() | |||
const token = 'token' | |||
if (token) { | |||
config.headers.Authorization = token | |||
return config | |||
} | |||
/** | |||
* * 未登录或者token过期的情况下 | |||
* * 跳转登录页重新登录,携带当前路由及参数,登录成功会回到原来的页面 | |||
*/ | |||
const { currentRoute } = router | |||
router.replace({ | |||
path: '/login', | |||
query: { ...currentRoute.query, redirect: currentRoute.path } | |||
}) | |||
return Promise.reject({ code: '-1', message: '未登录' }) | |||
}, | |||
(error) => Promise.reject(error) | |||
) | |||
service.interceptors.response.use( | |||
(response) => { | |||
const { method } = response?.config | |||
const { code } = response?.data | |||
const { currentRoute } = router | |||
switch (code) { | |||
case 0: | |||
if (method !== 'get') { | |||
$message.success(response.data.msg) | |||
} | |||
break | |||
case -1: | |||
$message.error(response.data.msg) | |||
break | |||
case 401: | |||
// 未登录(可能是token过期或者无效了) | |||
removeToken() | |||
router.replace({ | |||
path: '/login', | |||
query: { ...currentRoute.query, redirect: currentRoute.path } | |||
}) | |||
break | |||
default: | |||
break | |||
} | |||
return response?.data | |||
}, | |||
(error) => { | |||
return Promise.reject(error) | |||
} | |||
) | |||
} |
@@ -1,11 +1,11 @@ | |||
import AMapLoader from '@amap/amap-jsapi-loader'; | |||
import AMapLoader from '@amap/amap-jsapi-loader' | |||
export default AMapLoader.load({ | |||
"key": "20535a30fa0f3aae9c7bbe4407270792", | |||
"version": "2.0", | |||
"plugins": ['AMap.ToolBar', 'AMap.AutoComplete', "AMap.PlaceSearch", 'AMap.Geocoder'], | |||
'key': '709c024e3faa4a92473b9d847ca87702', | |||
'version': '2.0', | |||
'plugins': ['AMap.ToolBar', 'AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.Geocoder'], | |||
AMapUI: { | |||
version: '1.1', | |||
plugins: ['overlay/SimpleMarker'], | |||
plugins: ['overlay/SimpleMarker'] | |||
} | |||
}) | |||
}) |
@@ -0,0 +1,52 @@ | |||
<template> | |||
<div class="ContComp"> | |||
<div class="title">任务数据</div> | |||
<div id="chart01" /> | |||
</div> | |||
</template> | |||
<script setup name="ContComp"> | |||
import { onMounted } from 'vue' | |||
import myChart from '@/utils/echarts' | |||
onMounted(() => { | |||
myChart.line1('chart01', { | |||
'eventNameTrend': [ | |||
'2022-09-20', | |||
'2022-09-21', | |||
'2022-09-22', | |||
'2022-09-23', | |||
'2022-09-26', | |||
'2022-09-27', | |||
'2022-09-28' | |||
], | |||
'valueNameTrend': [ | |||
'0.00', | |||
'0.00', | |||
'0.00', | |||
'4.00', | |||
'1.00', | |||
'0.00', | |||
'1.00' | |||
] | |||
} | |||
) | |||
}) | |||
</script> | |||
<style scoped lang='scss'> | |||
.ContComp { | |||
margin-top: 20px; | |||
.title { | |||
font-size: 16px; | |||
font-weight: 600; | |||
color: rgba(0, 0, 0, 1); | |||
} | |||
#chart01 { | |||
width: 100%; | |||
height: 300px; | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,121 @@ | |||
<template> | |||
<div class="FootComp"> | |||
<n-grid x-gap="12" :cols="3"> | |||
<n-gi> | |||
<div class="test"> | |||
<div class="comp"> | |||
<div class="title">飞手飞行时长</div> | |||
<div id="chart02" /> | |||
</div> | |||
<div class="comp" style="margin-top: 20px;"> | |||
<div class="title">飞手飞行时长</div> | |||
<div id="chart03" /> | |||
</div> | |||
</div> | |||
</n-gi> | |||
<n-gi> | |||
<div class="test"> | |||
<div class="comp"> | |||
<div class="title">飞手飞行时长</div> | |||
<div id="chart04" /> | |||
</div> | |||
<div class="comp" style="margin-top: 20px;"> | |||
<div class="title">飞手飞行时长</div> | |||
<div id="chart05" /> | |||
</div> | |||
</div> | |||
</n-gi> | |||
<n-gi> | |||
<tab-comp class="comp" /> | |||
</n-gi> | |||
</n-grid> | |||
</div> | |||
</template> | |||
<script setup name="FootComp"> | |||
import TabComp from './TabComp.vue' | |||
import { onMounted } from 'vue' | |||
import myChart from '@/utils/echarts' | |||
onMounted(() => { | |||
myChart.line2('chart02', { | |||
'data': [ | |||
'242.0', | |||
'285.5', | |||
'476.0' | |||
], | |||
'tatil': [ | |||
'长椅', | |||
'路灯', | |||
'消防栓' | |||
] | |||
} | |||
) | |||
myChart.line2('chart03', { | |||
'data': [ | |||
'242.0', | |||
'285.5', | |||
'476.0' | |||
], | |||
'tatil': [ | |||
'长椅', | |||
'路灯', | |||
'消防栓' | |||
] | |||
} | |||
) | |||
myChart.line2('chart04', { | |||
'data': [ | |||
'242.0', | |||
'285.5', | |||
'476.0' | |||
], | |||
'tatil': [ | |||
'长椅', | |||
'路灯', | |||
'消防栓' | |||
] | |||
} | |||
) | |||
myChart.line2('chart05', { | |||
'data': [ | |||
'242.0', | |||
'285.5', | |||
'476.0' | |||
], | |||
'tatil': [ | |||
'长椅', | |||
'路灯', | |||
'消防栓' | |||
] | |||
} | |||
) | |||
}) | |||
</script> | |||
<style scoped lang='scss'> | |||
.FootComp { | |||
margin-top: 20px; | |||
.comp { | |||
padding: 10px; | |||
background-color: #fff; | |||
border-radius: 4px; | |||
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.25); | |||
} | |||
.title { | |||
font-size: 16px; | |||
font-weight: bold; | |||
} | |||
#chart02, | |||
#chart03, | |||
#chart04, | |||
#chart05 { | |||
width: 100%; | |||
height: 195px; | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,101 @@ | |||
<template> | |||
<div class="HeadComp"> | |||
<div v-for="(it, i) in headList" :key="i + it.name" class="box" :class="{border: i % 2 != 0}"> | |||
<template v-if="i % 2 == 0"> | |||
<img :src="it.img" class="img"> | |||
<div class="item"> | |||
<div class="name">{{ it.name }}</div> | |||
<div class="num"><span class="span">{{ it.value }}</span> 个</div> | |||
</div> | |||
</template> | |||
</div> | |||
</div> | |||
</template> | |||
<script setup name="HeadComp"> | |||
import { reactive, ref } from 'vue' | |||
import total from '../assets/total.png' | |||
import task from '../assets/task.png' | |||
import platform from '../assets/platform.png' | |||
import clients from '../assets/clients.png' | |||
import fly from '../assets/fly.png' | |||
const headList = reactive([ | |||
{ | |||
name: '总条数', | |||
value: 373, | |||
img: total | |||
}, | |||
{}, | |||
{ | |||
name: '待执行任务', | |||
value: 23, | |||
img: task | |||
}, | |||
{}, | |||
{ | |||
name: '接入平台数量', | |||
value: 7, | |||
img: platform | |||
}, | |||
{}, | |||
{ | |||
name: '服务客户数量', | |||
value: 27, | |||
img: clients | |||
}, | |||
{}, | |||
{ | |||
name: '累计飞行时长', | |||
value: 884, | |||
img: fly | |||
} | |||
]) | |||
</script> | |||
<style scoped lang='scss'> | |||
.HeadComp { | |||
display: flex; | |||
justify-content: space-around; | |||
flex-wrap: wrap; | |||
font-size: 14px; | |||
height: 60px; | |||
.box { | |||
display: flex; | |||
align-items: center; | |||
.img { | |||
width: 24px; | |||
height: 24px; | |||
} | |||
.item { | |||
margin-left: 20px; | |||
.name { | |||
margin-bottom: 2px; | |||
color: rgba(0, 0, 0, 0.75); | |||
} | |||
.num { | |||
text-align: end; | |||
margin-top: 2px; | |||
.span { | |||
font-weight: bold; | |||
margin-right: 10px; | |||
color: rgba(0, 0, 0, 1); | |||
} | |||
} | |||
} | |||
} | |||
.border { | |||
border: 1px solid rgba(207, 207, 207, 0.65); | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,86 @@ | |||
<template> | |||
<div class="TabComp"> | |||
<div class="title"> | |||
<div class="title-left">最新任务</div> | |||
<div class="title-right">查看更多</div> | |||
</div> | |||
<n-space vertical> | |||
<n-table striped> | |||
<thead> | |||
<tr> | |||
<th>序号</th> | |||
<th>任务名称</th> | |||
<th>执行时间</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr v-for="(it, i) in tabList" :key="i + it.name"> | |||
<td>{{ i + 1 }}</td> | |||
<td>{{ it.name }}</td> | |||
<td>{{ it.time }}</td> | |||
</tr> | |||
</tbody> | |||
</n-table> | |||
</n-space> | |||
</div> | |||
</template> | |||
<script setup name="tabComp"> | |||
import { reactive } from 'vue' | |||
const tabList = reactive([ | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
}, | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
}, | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
}, | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
}, | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
}, | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
}, | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
}, | |||
{ | |||
name: '宁杭高速巡检', | |||
time: '202-08-19' | |||
} | |||
]) | |||
</script> | |||
<style lang="scss" scoped> | |||
.TabComp { | |||
height: 500px; | |||
.title{ | |||
display: flex; | |||
justify-content: space-between; | |||
margin-bottom: 10px; | |||
&-left { | |||
font-size: 16px; | |||
font-weight: bold; | |||
} | |||
&-right { | |||
font-size: 12px; | |||
color: rgba(36, 158, 255, 1); | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
</style> |
@@ -1,17 +1,23 @@ | |||
<template> | |||
<div> | |||
主页 | |||
</div> | |||
</template> | |||
<n-card class="wrapper"> | |||
<script> | |||
export default { | |||
name: 'HomePage', | |||
setup() { | |||
<head-comp /> | |||
} | |||
} | |||
<cont-comp /> | |||
<foot-comp /> | |||
</n-card> | |||
</template> | |||
<script setup name="dashboard"> | |||
import HeadComp from './components/HeadComp.vue' | |||
import ContComp from './components/ContComp.vue' | |||
import FootComp from './components/FootComp.vue' | |||
</script> | |||
<style scoped lang='scss'> | |||
.wrapper { | |||
background: rgba(240, 242, 245, 1); | |||
} | |||
</style> |
@@ -1,91 +1,226 @@ | |||
<template> | |||
<!-- 状态 --> | |||
<div class="head"> | |||
<n-steps size="small" :current="current" :status="'process'"> | |||
<n-step :title="it.label" v-for="(it, i) in TASK_STATUS" :key="i + it.label" /> | |||
<n-step v-for="(it, i) in TASK_STATUS" :key="i + it.label" :title="it.label" /> | |||
</n-steps> | |||
</div> | |||
<div class="basic"> | |||
<!-- 基本信息 --> | |||
<div class="cont"> | |||
<n-descriptions label-placement="left" label-align="right" :column="4" title="任务基本信息"> | |||
<n-descriptions-item :label="it.label" v-for="(it, i) in basicInfo" :key="i + it.label"> | |||
{{ it.value}} | |||
<n-descriptions-item v-for="(it, i) in basicInfo" :key="i + it.label" :label="it.label"> | |||
{{ it.value }} | |||
</n-descriptions-item> | |||
</n-descriptions> | |||
</div> | |||
<div class="basic"> | |||
<!-- 飞行信息 - 待分配飞手:状态为5 --> | |||
<div v-if="current === 1 && isAdmin" class="cont"> | |||
<div class="title">飞行信息</div> | |||
<n-form | |||
ref="formRef" | |||
:model="form.userForm" | |||
:rules="form.userRules" | |||
:label-width="85" | |||
label-placement="left" | |||
require-mark-placement="left" | |||
> | |||
<template v-for="it in form.formItem" :key="it.key"> | |||
<n-form-item v-if="it?.isLive !== data.isLive" :label="it.label" :path="it.key"> | |||
<n-select v-model:value="form.userForm[it.key]" v-bind="it.props" /> | |||
</n-form-item> | |||
</template> | |||
</n-form> | |||
<n-button type="info" class="btn" @click="submitClick">提交</n-button> | |||
</div> | |||
<!-- 飞行信息 - 状态不为5 --> | |||
<div v-if="current !== 1" class="cont"> | |||
<n-descriptions label-placement="left" label-align="right" :column="4" title="飞行信息"> | |||
<n-descriptions-item :label="it.label" v-for="(it, i) in basicInfo" :key="i + it.label"> | |||
{{ it.value}} | |||
</n-descriptions-item> | |||
<template v-for="(it, i) in flyInfo" :key="i + it.label"> | |||
<n-descriptions-item v-if="current !== it?.current" :label="it.label"> | |||
{{ it.value }} | |||
</n-descriptions-item> | |||
</template> | |||
</n-descriptions> | |||
</div> | |||
<div class="basic"> | |||
<!-- 设备/影响基本信息 - 飞手接单: 管理员 --> | |||
<div v-if="current == 2 && isAdmin" class="cont"> | |||
<n-descriptions label-placement="left" label-align="right" :column="4" title="设备/影响基本信息"> | |||
<n-descriptions-item :label="it.label" v-for="(it, i) in basicInfo" :key="i + it.label"> | |||
{{ it.value}} | |||
</n-descriptions-item> | |||
<template v-for="(it, i) in equipmentInfo" :key="i + it.label"> | |||
<n-descriptions-item v-if="it?.isLive !== data.isLive" :label="it.label"> | |||
{{ it.value }} | |||
</n-descriptions-item> | |||
</template> | |||
</n-descriptions> | |||
</div> | |||
<!-- 飞手接单: 飞手 --> | |||
<div v-if="current === 2 && !isAdmin" class="cont"> | |||
<div class="title">飞行信息{{ '-isAdmin:' + isAdmin + data.isLive }}</div> | |||
<n-form | |||
ref="formRefOrder" | |||
:model="form.userForm" | |||
:rules="form.userRulesOrder" | |||
:label-width="85" | |||
label-placement="left" | |||
require-mark-placement="left" | |||
> | |||
<template v-for="it in form.formItemOrder" :key="it.key"> | |||
<n-form-item v-if="it?.isLive !== data.isLive" :label="it.label" :path="it.key"> | |||
<n-select v-model:value="form.userForm[it.key]" v-bind="it.props" /> | |||
</n-form-item> | |||
</template> | |||
</n-form> | |||
<n-button type="info" class="btn" @click="flyClick">接单</n-button> | |||
</div> | |||
<!-- 设备/影响基本信息 - 已接单 --> | |||
<div v-if="current === 3" class="cont"> | |||
<n-descriptions label-placement="left" label-align="right" :column="4" title="设备/影响基本信息"> | |||
<template v-for="(it, i) in executionInfo" :key="i + it.label"> | |||
<n-descriptions-item :label="it.label"> | |||
{{ it.value }} | |||
</n-descriptions-item> | |||
</template> | |||
</n-descriptions> | |||
<n-button v-if="isAdmin" type="info" class="btn" @click="startFly">开始飞行</n-button> | |||
</div> | |||
<!-- 设备/影响基本信息 - 执行中: 管理员 --> | |||
<div v-if="current === 4" class="cont"> | |||
<n-descriptions label-placement="left" label-align="right" :column="4" title="设备/影响基本信息"> | |||
<template v-for="(it, i) in executionInfo" :key="i + it.label"> | |||
<n-descriptions-item :label="it.label"> | |||
{{ it.value }} | |||
</n-descriptions-item> | |||
</template> | |||
</n-descriptions> | |||
<n-button v-if="isAdmin" type="Error" class="btn" @click="endFly">结束飞行</n-button> | |||
</div> | |||
<div v-if="current === 5" class="cont"> | |||
<div class="title">飞行文件</div> | |||
<UploadOss :ref="uploadoss" :limit="2" :default-list="ossList" @upload-status="handleUploadStatus" /> | |||
<UploadVod @upload-status="vodStatus" /> | |||
<!-- <n-button v-if="data.photographyWay == 1" type="info" class="btn">上传文件</n-button> | |||
<n-button v-if="data.photographyWay == 2" type="info" class="btn">上传文件</n-button> | |||
<n-button v-if="data.photographyWay == 3" type="info" class="btn">上传文件</n-button> --> | |||
</div> | |||
</template> | |||
<script setup name="DrawComp"> | |||
import { ref, computed, reactive, onMounted } from 'vue' | |||
import { ref, defineProps, reactive, defineEmits } from 'vue' | |||
import { TASK_STATUS } from '@/utils/dictionary' | |||
import { distributionPilot, pilotOrder, pilotStart, pilotEnd } from '@/api/task/index.js' | |||
import { form, getPilotList, getEquipment, getEquipmentMount, getCloudMount } from '../tools/drawForm' | |||
import { basic, fly, equipment, execution } from '../hook/index' | |||
import UploadOss from '@/components/UploadOss/index.vue' | |||
import UploadVod from '@/components/UploadVod/index.vue' | |||
getPilotList() // 获取飞手列表 | |||
getEquipment() // 无人机列表 | |||
getEquipmentMount() // 挂载设备列表 | |||
getCloudMount() // 挂载盒子列表 | |||
const props = defineProps({ | |||
detail: Object | |||
detail: { | |||
type: Object, | |||
required: true | |||
} | |||
}) | |||
const { detail: {data}} = props; | |||
let basicInfo = reactive([ | |||
{ | |||
label: "平台", | |||
value: data.platformName | |||
}, | |||
{ | |||
label: "客户名称", | |||
value: data.tenantName | |||
}, | |||
{ | |||
label: "任务编号", | |||
value: data.taskCode | |||
}, | |||
{ | |||
label: "巡逻地点", | |||
value: data.patrolLocation | |||
}, | |||
{ | |||
label: "任务发起人", | |||
value: data.sponsorName | |||
}, | |||
{ | |||
label: "发起人联系方式", | |||
value: data.sponsorPhone | |||
}, | |||
{ | |||
label: "任务发起时间", | |||
value: data.createTime | |||
}, | |||
{ | |||
label: "期望执行时间", | |||
value: data.taskStartTime | |||
}, | |||
{ | |||
label: "备注", | |||
value: data.remark | |||
}, | |||
]) | |||
const current = ref(2) | |||
const { detail: { data }} = props // 传来的详情数据 | |||
const current = data.pilotStatus / 5 // 当前状态 | |||
const isAdmin = Math.random() > 0.5 // 模拟是否管理员 | |||
const formRef = ref() // 表格refs - 分配飞手 | |||
const formRefOrder = ref() // 表格refs - 飞手接单 | |||
const uploadoss = ref([]) // 上传refs | |||
const ossList = ref('https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg') | |||
const basicInfo = basic(data) // 基础信息 | |||
const flyInfo = fly(data) // 飞行信息 | |||
const equipmentInfo = equipment(data) // 设备/影响基本信息 | |||
const executionInfo = execution(data) // 执行中信息 | |||
const emit = defineEmits(['close']) | |||
// 分配飞手 | |||
const submitClick = () => { | |||
formRef.value?.validate().then(() => { | |||
const { userForm } = form | |||
distributionPilot({ | |||
...userForm, | |||
id: data.id | |||
}).then(({ code }) => { | |||
if (code === 0) { | |||
emit('close') | |||
} | |||
}) | |||
}).catch(e => { | |||
$message.error('请完善必填信息') | |||
}) | |||
} | |||
// 飞手接单 | |||
const flyClick = () => { | |||
formRefOrder.value?.validate().then(() => { | |||
const { userForm } = form | |||
pilotOrder({ | |||
...userForm, | |||
flightHandId: data.flightHandId, | |||
id: data.id | |||
}).then(({ code }) => { | |||
if (code === 0) { | |||
emit('close') | |||
} | |||
}) | |||
}).catch(e => { | |||
$message.error('请完善必填信息') | |||
}) | |||
} | |||
// 开始飞行 | |||
const startFly = () => { | |||
pilotStart({ id: data.id }).then(({ code, msg }) => { | |||
if (code === 0) { | |||
emit('close') | |||
} else { | |||
$message.error(msg) | |||
} | |||
}) | |||
} | |||
// 结束飞行 | |||
const endFly = () => { | |||
pilotEnd({ id: data.id }).then(({ code, msg }) => { | |||
if (code === 0) { | |||
emit('close') | |||
} else { | |||
$message.error(msg) | |||
} | |||
}) | |||
} | |||
// 图片上传状态 | |||
const handleUploadStatus = status => { | |||
console.log(status) | |||
} | |||
// 视频上传状态 | |||
const vodStatus = status => { | |||
console.log(status) | |||
} | |||
</script> | |||
@@ -96,9 +231,21 @@ const current = ref(2) | |||
background-color: #fff; | |||
} | |||
.basic { | |||
.cont { | |||
margin: 20px; | |||
background-color: #fff; | |||
.title { | |||
margin: 20px; | |||
padding: 20px; | |||
font-size: 18px; | |||
font-weight: bold; | |||
} | |||
.btn { | |||
width: 70px; | |||
margin-left: calc(50% - 30px); | |||
margin-top: 10px; | |||
margin-bottom: 30px; | |||
} | |||
} | |||
:deep(.n-descriptions-header) { | |||
@@ -116,4 +263,15 @@ const current = ref(2) | |||
:deep(.n-drawer-body-content-wrapper) { | |||
background-color: rgba(240, 242, 245, 1); | |||
} | |||
</style> | |||
:deep(.n-form) { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: flex-start; | |||
padding: 0 20px; | |||
} | |||
:deep(.n-form-item) { | |||
width: 230px; | |||
margin-right: 15px; | |||
} | |||
</style> |
@@ -1,20 +1,35 @@ | |||
<template> | |||
<Modal :options="getModalOptions" :on-positive-click="handleConfirm" :on-negative-click="handleClose" | |||
:on-close="handleClose"> | |||
<Modal | |||
:options="getModalOptions" | |||
:on-positive-click="handleConfirm" | |||
:on-negative-click="handleClose" | |||
:on-close="handleClose" | |||
> | |||
<template #Context> | |||
<n-form ref="formRef" :model="userForm" :rules="userRules" :label-width="80" label-placement="left" | |||
require-mark-placement="left" :disabled="disabled"> | |||
<n-form | |||
ref="formRef" | |||
:model="userForm" | |||
:rules="userRules" | |||
:label-width="80" | |||
label-placement="left" | |||
require-mark-placement="left" | |||
:disabled="disabled" | |||
> | |||
<template v-for="(item,index) in getFormOptions" :key="index"> | |||
<n-form-item :label="item.label" :path="item.key"> | |||
<UploadOss v-if="item.type === 'oss'" :ref="el=>{ossRefs[item.refIndex] = el}" | |||
:default-list="userForm[item.file]" @upload-status="handleUploadStatus" /> | |||
<UploadOss | |||
v-if="item.type === 'oss'" | |||
:ref="el=>{ossRefs[item.refIndex] = el}" | |||
:default-list="userForm[item.file]" | |||
@upload-status="handleUploadStatus" | |||
/> | |||
<n-input v-if="item.type === 'input'" v-model:value="userForm[item.key]" v-bind="item.props" /> | |||
<n-select v-if="item.type === 'select'" v-model:value="userForm[item.key]" v-bind="item.props" /> | |||
<div v-if="item.type === 'map'" id="mapContainer" class="map"></div> | |||
<div v-if="item.type === 'map'" id="mapContainer" class="map" /> | |||
<n-input v-if="item.type === 'inputStart'" disabled v-model:value="userForm[item.key]" v-bind="item.props"> | |||
<n-input v-if="item.type === 'inputStart'" v-model:value="userForm[item.key]" disabled v-bind="item.props"> | |||
<template #suffix> | |||
<n-button @click="showStart = true" quaternary type="info">去标记 | |||
<n-button quaternary type="info" @click="showStart = true">去标记 | |||
<n-icon size="20" color="rgba(42, 130, 228, 1)"> | |||
<LocationSharp /> | |||
</n-icon> | |||
@@ -22,9 +37,9 @@ | |||
</template> | |||
</n-input> | |||
<n-input v-if="item.type === 'inputEnd'" disabled v-model:value="userForm[item.key]" v-bind="item.props"> | |||
<n-input v-if="item.type === 'inputEnd'" v-model:value="userForm[item.key]" disabled v-bind="item.props"> | |||
<template #suffix> | |||
<n-button @click="showEnd = true" quaternary type="info">去标记 | |||
<n-button quaternary type="info" @click="showEnd = true">去标记 | |||
<n-icon size="20" color="rgba(42, 130, 228, 1)"> | |||
<LocationSharp /> | |||
</n-icon> | |||
@@ -32,12 +47,17 @@ | |||
</template> | |||
</n-input> | |||
<n-date-picker v-if="item.type === 'datetime'" v-model:formatted-value="userForm[item.key]" | |||
v-bind="item.props" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" /> | |||
<n-date-picker | |||
v-if="item.type === 'datetime'" | |||
v-model:formatted-value="userForm[item.key]" | |||
v-bind="item.props" | |||
type="datetime" | |||
value-format="yyyy-MM-dd HH:mm:ss" | |||
/> | |||
<n-radio-group v-if="item.type === 'radio'" v-model:value="userForm[item.key]" :name="item.key"> | |||
<n-space> | |||
<n-radio v-for="(cItem,cIndex) in item.options" :key="`${item.key}_${cIndex}`" :value="cItem.value"> {{ | |||
cItem.label }}</n-radio> | |||
cItem.label }}</n-radio> | |||
</n-space> | |||
</n-radio-group> | |||
</n-form-item> | |||
@@ -46,22 +66,35 @@ | |||
</template> | |||
</Modal> | |||
<n-modal v-model:show="showStart" :mask-closable="false" preset="dialog" title="" positive-text="确定" | |||
@positive-click="userForm.patrolLocation = startVal" @negative-click="showStart = false"> | |||
<map-comp @mapEmit="startHandle"></map-comp> | |||
<n-modal | |||
v-model:show="showStart" | |||
:mask-closable="false" | |||
preset="dialog" | |||
title="" | |||
positive-text="确定" | |||
@positive-click="userForm.patrolLocation = startVal" | |||
@negative-click="showStart = false" | |||
> | |||
<map-comp @mapEmit="startHandle" /> | |||
</n-modal> | |||
<n-modal v-model:show="showEnd" :mask-closable="false" preset="dialog" title="" positive-text="确定" | |||
@positive-click="userForm.endValue = endVal" @negative-click="showEnd = false"> | |||
<map-comp @mapEmit="endHandle"></map-comp> | |||
<n-modal | |||
v-model:show="showEnd" | |||
:mask-closable="false" | |||
preset="dialog" | |||
title="" | |||
positive-text="确定" | |||
@positive-click="userForm.endValue = endVal" | |||
@negative-click="showEnd = false" | |||
> | |||
<map-comp @mapEmit="endHandle" /> | |||
</n-modal> | |||
</template> | |||
<script> | |||
import { form, getPilotList, getEquipment, getEquipmentMount } from '../tools/form.js' | |||
import { defineComponent, ref, reactive, computed, toRefs, unref } from 'vue' | |||
import { defineComponent, ref, reactive, computed, toRefs } from 'vue' | |||
import Modal from '@/components/Modal/index.vue' | |||
import UploadOss from '@/components/UploadOss/index.vue' | |||
import { taskAdd, taskEdit } from '@/api/task' | |||
@@ -97,9 +130,9 @@ export default defineComponent({ | |||
'preview': '任务详情', | |||
'update': '编辑任务' | |||
} | |||
getPilotList(); | |||
getEquipment(); | |||
getEquipmentMount(); | |||
getPilotList() | |||
getEquipment() | |||
getEquipmentMount() | |||
const { formItem, userForm, userRules } = form | |||
const formRef = ref() | |||
const ossRefs = ref([]) | |||
@@ -132,29 +165,29 @@ export default defineComponent({ | |||
data.userForm.imageStatus = status | |||
} | |||
let geocoder = null; | |||
let geocoder = null | |||
// 地图 | |||
GMap.then((AMap) => { | |||
let Gmap = null; | |||
let Gmap = null | |||
// 坐标求地址 | |||
geocoder = new AMap.Geocoder() | |||
if(props.type == 'update') { // 打开编辑 | |||
if (props.type === 'update') { // 打开编辑 | |||
Gmap = new AMap.Map('mapContainer', { | |||
zoom: 13, | |||
center: [data.userForm.startLongitude, data.userForm.startLatitude], | |||
}); | |||
center: [data.userForm.startLongitude, data.userForm.startLatitude] | |||
}) | |||
var marker = new AMap.Marker({ | |||
position: new AMap.LngLat(data.userForm.startLongitude, data.userForm.startLatitude), | |||
icon: '//vdata.amap.com/icons/b18/1/2.png', | |||
title: '起点' | |||
}); | |||
}) | |||
// 将创建的点标记添加到已有的地图实例: | |||
Gmap.add(marker); | |||
Gmap.add(marker) | |||
// 起点赋值 | |||
geocoder.getAddress([data.userForm.startLongitude, data.userForm.startLatitude], (status, result) => { | |||
if (status === 'complete' && result.info === 'OK') { | |||
@@ -171,53 +204,51 @@ export default defineComponent({ | |||
} else { | |||
Gmap = new AMap.Map('mapContainer', { | |||
zoom: 13, | |||
center: [118.773319, 31.828123], | |||
}); | |||
center: [118.773319, 31.828123] | |||
}) | |||
} | |||
// 添加缩放工具 | |||
const toolbar = new AMap.ToolBar(); | |||
Gmap.addControl(toolbar); | |||
const toolbar = new AMap.ToolBar() | |||
Gmap.addControl(toolbar) | |||
}).catch(e => console.log(e)) | |||
// 地图辅助参数 | |||
let showStart = ref(false); | |||
let showEnd = ref(false); | |||
const showStart = ref(false) | |||
const showEnd = ref(false) | |||
const startVal = ref(null); | |||
const endVal = ref(null); | |||
const startVal = ref(null) | |||
const endVal = ref(null) | |||
// 起点地图 确定事件 | |||
const startHandle = e => { | |||
const { location: { lat } } = e; | |||
const { location: { lng } } = e; | |||
geocoder.getAddress([lng, lat], function (status, result) { | |||
const { location: { lat }} = e | |||
const { location: { lng }} = e | |||
geocoder.getAddress([lng, lat], function(status, result) { | |||
if (status === 'complete' && result.info === 'OK') { | |||
startVal.value = result.regeocode.formattedAddress | |||
data.userForm.startLongitude = String(lng); | |||
data.userForm.startLatitude = String(lat); | |||
data.userForm.startLongitude = String(lng) | |||
data.userForm.startLatitude = String(lat) | |||
} | |||
}) | |||
} | |||
// 终点地图 确定事件 | |||
const endHandle = e => { | |||
const { location: { lat } } = e; | |||
const { location: { lng } } = e; | |||
geocoder.getAddress([lng, lat], function (status, result) { | |||
const { location: { lat }} = e | |||
const { location: { lng }} = e | |||
geocoder.getAddress([lng, lat], function(status, result) { | |||
if (status === 'complete' && result.info === 'OK') { | |||
endVal.value = result.regeocode.formattedAddress | |||
data.userForm.endLongitude = String(lng); | |||
data.userForm.endLatitude = String(lat); | |||
data.userForm.endLongitude = String(lng) | |||
data.userForm.endLatitude = String(lat) | |||
} | |||
}) | |||
} | |||
function handleConfirm() { | |||
formRef.value?.validate(async (errors) => { | |||
formRef.value?.validate(async(errors) => { | |||
if (!errors) { | |||
let params = { | |||
const params = { | |||
...data.userForm, | |||
taskStartTime: String(data.userForm.taskStartTime) | |||
} |
@@ -0,0 +1,50 @@ | |||
import { customRef } from 'vue' | |||
export default function(data) { | |||
const list = [ | |||
{ | |||
label: '平台', | |||
value: data.platformName | |||
}, | |||
{ | |||
label: '客户名称', | |||
value: data.tenantName | |||
}, | |||
{ | |||
label: '任务编号', | |||
value: data.taskCode | |||
}, | |||
{ | |||
label: '巡逻地点', | |||
value: data.patrolLocation | |||
}, | |||
{ | |||
label: '任务发起人', | |||
value: data.sponsorName | |||
}, | |||
{ | |||
label: '发起人联系方式', | |||
value: data.sponsorPhone | |||
}, | |||
{ | |||
label: '任务发起时间', | |||
value: data.createTime | |||
}, | |||
{ | |||
label: '期望执行时间', | |||
value: data.taskStartTime | |||
}, | |||
{ | |||
label: '备注', | |||
value: data.remark | |||
} | |||
] | |||
return customRef((track, trigger) => { | |||
return { | |||
get() { | |||
track() | |||
return list | |||
} | |||
} | |||
}) | |||
} |
@@ -0,0 +1,33 @@ | |||
import { customRef } from 'vue' | |||
const photographyWay = ['普通巡检', '正射影像', '倾斜摄影'] // 摄影方式 | |||
export default function(data) { | |||
const list = [ | |||
{ | |||
label: '执飞无人机', | |||
value: data.equipmentName | |||
}, | |||
{ | |||
label: '摄影方式', | |||
value: photographyWay[data.photographyWay - 1] | |||
}, | |||
{ | |||
label: '挂载设备', | |||
value: data.equipmentMountName | |||
}, | |||
{ | |||
label: '盒子名称', | |||
value: data.cloudBoxName, | |||
isLive: 1 | |||
} | |||
] | |||
return customRef((track, trigger) => { | |||
return { | |||
get() { | |||
track() | |||
return list | |||
} | |||
} | |||
}) | |||
} |
@@ -0,0 +1,28 @@ | |||
import { customRef } from 'vue' | |||
const photographyWay = ['普通巡检', '正射影像', '倾斜摄影'] // 摄影方式 | |||
export default function(data) { | |||
const list = [ | |||
{ | |||
label: '执飞无人机', | |||
value: data.equipmentName | |||
}, | |||
{ | |||
label: '摄影方式', | |||
value: photographyWay[data.photographyWay - 1] | |||
}, | |||
{ | |||
label: '挂载设备', | |||
value: data.equipmentMountName | |||
} | |||
] | |||
return customRef((track, trigger) => { | |||
return { | |||
get() { | |||
track() | |||
return list | |||
} | |||
} | |||
}) | |||
} |
@@ -0,0 +1,39 @@ | |||
import { customRef } from 'vue' | |||
export default function(data) { | |||
const list = [ | |||
{ | |||
label: '分配人', | |||
value: data.distributeUserName | |||
}, | |||
{ | |||
label: '分配飞手时间', | |||
value: data.distributeTime | |||
}, | |||
{ | |||
label: '飞手', | |||
value: data.flightHandName | |||
}, | |||
{ | |||
label: '飞手接单时间', | |||
value: data.ordersTime | |||
}, | |||
{ | |||
label: '飞手接单状态', | |||
value: '状态待确定?' | |||
}, | |||
{ | |||
label: '飞行开始时间', | |||
value: '暂不知道取值', | |||
current: 4 | |||
} | |||
] | |||
return customRef((track, trigger) => { | |||
return { | |||
get() { | |||
track() | |||
return list | |||
} | |||
} | |||
}) | |||
} |
@@ -0,0 +1,11 @@ | |||
import basic from './basic.js' | |||
import fly from './fly.js' | |||
import equipment from './equipment.js' | |||
import execution from './execution.js' | |||
export { | |||
basic, | |||
fly, | |||
equipment, | |||
execution | |||
} |
@@ -5,8 +5,14 @@ | |||
<headSearch :info="search" @search="handleSearch" @reset="handleSearch" /> | |||
<!-- 表格 --> | |||
<data-table ref="tableRef" :columns="columns" :row-key="(row) => row.id" :request="loadDataTable" size="large" | |||
@update:checked-row-keys="handleCheck"> | |||
<data-table | |||
ref="tableRef" | |||
:columns="columns" | |||
:row-key="(row) => row.id" | |||
:request="loadDataTable" | |||
size="large" | |||
@update:checked-row-keys="handleCheck" | |||
> | |||
<template #tableTitle> | |||
<n-button type="primary" @click="handleModal"> 新建 </n-button> | |||
</template> | |||
@@ -20,7 +26,7 @@ | |||
<!-- 详情 - 抽屉 --> | |||
<n-drawer v-model:show="showDraw" :width="'calc(100vw - 210px)'" :placement="'right'" resizable> | |||
<n-drawer-content closable> | |||
<draw-comp :detail="detail" /> | |||
<draw-comp :detail="detail" @close="showDraw = false" /> | |||
</n-drawer-content> | |||
</n-drawer> | |||
@@ -33,20 +39,19 @@ import headSearch from '@/components/Search/index.vue' | |||
import dataTable from '@/components/DataTable/index.vue' | |||
import DrawComp from './components/DrawComp.vue' | |||
import UserModal from './components/UserModal.vue' | |||
import { getTaskList } from '@/api/task/index'; | |||
import { getTaskList } from '@/api/task/index' | |||
import { unref, ref, toRefs, reactive, onUnmounted } from 'vue' | |||
export default { | |||
name: 'TaskManage', | |||
components: { dataTable, UserModal, headSearch, DrawComp }, | |||
setup() { | |||
const data = reactive({ | |||
...toRefs(table), | |||
...toRefs(search) | |||
}) | |||
const loadDataTable = async (res) => { | |||
const loadDataTable = async(res) => { | |||
const _params = { | |||
...unref(data.searchParams), | |||
...res | |||
@@ -102,4 +107,4 @@ export default { | |||
:deep(.n-drawer-body-content-wrapper) { | |||
background-color: rgba(240, 242, 245, 0.8); | |||
} | |||
</style> | |||
</style> |
@@ -0,0 +1,89 @@ | |||
import { ref, reactive } from 'vue' | |||
import { getTaskPilot } from '@/api/task/index.js' | |||
import { getEquipment as equipment, getEquipmentMount as equipmentMount, getCloud } from '@/api/equipment' | |||
import { PHOTOGRAPHY_WAY } from '@/utils/dictionary' | |||
// 无人机列表 | |||
const equipmentList = ref([]) | |||
// 挂载设备列表 | |||
const equipmentMountList = ref([]) | |||
// 飞手列表 | |||
const pilotList = ref([]) | |||
// 挂载盒子 | |||
const cloudList = ref([]) | |||
export const form = reactive({ | |||
userForm: { | |||
flightHandId: null, | |||
equipmentId: null, | |||
equipmentMountId: null, | |||
cloudBoxId: null, | |||
photographyWay: null | |||
}, | |||
userRules: { | |||
flightHandId: [{ required: true, message: '请选择飞手', trigger: 'blur' }] | |||
}, | |||
formItem: [ | |||
{ type: 'select', key: 'flightHandId', label: '飞手', props: { options: pilotList, placeholder: '请选择飞手', clearable: true }}, | |||
{ type: 'select', key: 'equipmentId', label: '执飞无人机', props: { options: equipmentList, placeholder: '请选择执飞无人机', clearable: true }}, | |||
{ type: 'select', key: 'equipmentMountId', label: '挂载设备', props: { options: equipmentMountList, placeholder: '请选择挂载设备', clearable: true }}, | |||
{ type: 'select', key: 'cloudBoxId', label: '挂载盒子', isLive: 1, props: { options: cloudList, placeholder: '请选择盒子', clearable: true }}, | |||
{ type: 'select', key: 'photographyWay', label: '拍摄方式', props: { options: PHOTOGRAPHY_WAY, placeholder: '请选择拍摄方式', clearable: true }} | |||
], | |||
// 飞手接单 - 校验 | |||
userRulesOrder: { | |||
equipmentId: [{ required: true, message: '请选择执飞无人机', trigger: 'blur' }], | |||
photographyWay: [{ required: true, message: '请选择摄影方式', trigger: 'blur' }], | |||
equipmentMountId: [{ required: true, message: '请选择挂载设备', trigger: 'blur' }] | |||
}, | |||
// 飞手接单 - 表单 | |||
formItemOrder: [ | |||
{ type: 'select', key: 'equipmentId', label: '执飞无人机', props: { options: equipmentList, placeholder: '请选择执飞无人机', clearable: true }}, | |||
{ type: 'select', key: 'photographyWay', label: '摄影方式', props: { options: PHOTOGRAPHY_WAY, placeholder: '请选择拍摄方式', clearable: true }}, | |||
{ type: 'select', key: 'equipmentMountId', label: '挂载设备', props: { options: equipmentMountList, placeholder: '请选择挂载设备', clearable: true }}, | |||
{ type: 'select', key: 'cloudBoxId', label: '盒子名称', isLive: 0, props: { options: cloudList, placeholder: '请选择盒子', clearable: true }} | |||
] | |||
}) | |||
// 获取飞手列表 | |||
export const getPilotList = async function() { | |||
const { data } = await getTaskPilot() | |||
pilotList.value = data.map(it => ({ | |||
...it, | |||
label: it.username, | |||
value: it.id | |||
})) | |||
} | |||
// 无人机列表 | |||
export const getEquipment = async function() { | |||
const { data } = await equipment() | |||
equipmentList.value = data.map(it => ({ | |||
...it, | |||
label: it.manufacturer, | |||
value: it.id | |||
})) | |||
} | |||
// 挂载设备列表 | |||
export const getEquipmentMount = async function() { | |||
const { data } = await equipmentMount() | |||
equipmentMountList.value = data.map(it => ({ | |||
...it, | |||
label: it.name, | |||
value: it.id | |||
})) | |||
} | |||
// 挂载盒子列表 | |||
export const getCloudMount = async function() { | |||
const { data } = await getCloud() | |||
cloudList.value = data.map(it => ({ | |||
...it, | |||
label: it.boxName, | |||
value: it.id | |||
})) | |||
} |
@@ -1,32 +1,16 @@ | |||
import { ref, reactive, computed } from 'vue' | |||
import { ref, reactive } from 'vue' | |||
import { getTaskPilot } from '@/api/task/index.js' | |||
import { getEquipment as equipment, getEquipmentMount as equipmentMount } from '@/api/equipment' | |||
import { PHOTOGRAPHY_WAY } from '@/utils/dictionary' | |||
// 无人机列表 | |||
const equipmentList = ref([]); | |||
const equipmentList = ref([]) | |||
// 挂载设备列表 | |||
const equipmentMountList = ref([]); | |||
const equipmentMountList = ref([]) | |||
// 飞手列表 | |||
const pilotList = ref(); | |||
// 拍摄方式 | |||
const photographyWay = [ | |||
{ | |||
label: '普通巡检', | |||
value: 1 | |||
}, | |||
{ | |||
label: '正射影像', | |||
value: 2 | |||
}, | |||
{ | |||
label: '倾斜摄影', | |||
value: 3 | |||
}, | |||
] | |||
const pilotList = ref() | |||
export const form = reactive({ | |||
userForm: { | |||
@@ -42,15 +26,15 @@ export const form = reactive({ | |||
remark: '' | |||
}, | |||
userRules: { | |||
inspectionType: [{ required: true, message: '请选择巡检类型', type: 'number',trigger: ["blur", "change"] }], | |||
inspectionType: [{ required: true, message: '请选择巡检类型', type: 'number', trigger: ['blur', 'change'] }], | |||
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }], | |||
patrolLocation: [{ required: true, message: '请输入任务起点', trigger: 'blur' }], | |||
endValue: [{ required: true, message: '请输入任务终点', trigger: 'blur' }], | |||
taskStartTime: [{ required: true, message: '请输入飞行时间', trigger: 'blur' }], | |||
flightHandId: [{ required: true, message: '请选择飞手', trigger: 'blur' }], | |||
flightHandId: [{ required: true, message: '请选择飞手', trigger: 'blur' }] | |||
}, | |||
formItem: [ | |||
{ type: 'select', key: 'inspectionType', label: '巡检类型', props: { options: [{label: '自营计划', value: 1}], maxlength: '20', placeholder: '请输入巡检类型', clearable: true } }, | |||
{ type: 'select', key: 'inspectionType', label: '巡检类型', props: { options: [{ label: '自营计划', value: 1 }], maxlength: '20', placeholder: '请输入巡检类型', clearable: true }}, | |||
{ type: 'input', key: 'taskName', label: '任务名称', props: { maxlength: '20', placeholder: '请输入任务名称', clearable: true }}, | |||
{ type: 'map' }, | |||
@@ -62,9 +46,9 @@ export const form = reactive({ | |||
{ type: 'select', key: 'flightHandId', label: '飞手', props: { options: pilotList, placeholder: '请选择飞手', clearable: true }}, | |||
{ type: 'select', key: 'equipmentId', label: '执飞无人机', props: { options: equipmentList, maxlength: '20', placeholder: '请选择执飞无人机', clearable: true }}, | |||
{ type: 'select', key: 'equipmentMountId', label: '挂载设备', props: { options: equipmentMountList, maxlength: '20', placeholder: '请选择挂载设备', clearable: true }}, | |||
{ type: 'select', key: 'photographyWay', label: '拍摄方式', props: { options: photographyWay, maxlength: '20', placeholder: '请选择拍摄方式', clearable: true }}, | |||
{ type: 'select', key: 'photographyWay', label: '拍摄方式', props: { options: PHOTOGRAPHY_WAY, maxlength: '20', placeholder: '请选择拍摄方式', clearable: true }}, | |||
{ type: 'input', key: 'remark', label: '备注', props: { type: 'textarea', autosize: { maxlength: '200', minRows: 3, maxRows: 3 }}}, | |||
{ type: 'input', key: 'remark', label: '备注', props: { type: 'textarea', autosize: { maxlength: '200', minRows: 3, maxRows: 3 }}} | |||
] | |||
}) |