@@ -5,7 +5,7 @@ VITE_PUBLIC_PATH = '/' | |||
VITE_APP_USE_MOCK = false | |||
# proxy | |||
VITE_PROXY = [["/api-local","http://127.0.0.1:8002/api"],["/api-mock","http://127.0.0.1:8003"]] | |||
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' |
@@ -2,4 +2,5 @@ node_modules | |||
.DS_Store | |||
dist | |||
dist-ssr | |||
*.local | |||
*.local | |||
.idea |
@@ -8,6 +8,7 @@ | |||
"name": "vite_vue3", | |||
"version": "0.0.0", | |||
"dependencies": { | |||
"@amap/amap-jsapi-loader": "^1.0.1", | |||
"@tinymce/tinymce-vue": "^4.0.5", | |||
"@vicons/antd": "^0.10.0", | |||
"@vicons/ionicons5": "^0.10.0", | |||
@@ -60,6 +61,11 @@ | |||
"node": "8 || 10 || 12 || 14 || 16 || 17" | |||
} | |||
}, | |||
"node_modules/@amap/amap-jsapi-loader": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz", | |||
"integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw==" | |||
}, | |||
"node_modules/@ampproject/remapping": { | |||
"version": "2.1.2", | |||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", | |||
@@ -12134,6 +12140,11 @@ | |||
"js-message": "1.0.7" | |||
} | |||
}, | |||
"@amap/amap-jsapi-loader": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz", | |||
"integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw==" | |||
}, | |||
"@ampproject/remapping": { | |||
"version": "2.1.2", | |||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", |
@@ -0,0 +1,75 @@ | |||
import { defAxios as request } from '@/utils/http' | |||
/** | |||
* 任务查询 | |||
* @returns | |||
*/ | |||
export const getTaskList = () => request({ | |||
url: '/task/getTaskList', | |||
method: 'GET' | |||
}) | |||
/** | |||
* 任务详情 | |||
* @param {*} params id | |||
* @returns | |||
*/ | |||
export const getTaskInfo = params => request({ | |||
url: '/task/getInfo', | |||
method: 'GET', | |||
params | |||
}) | |||
/** | |||
* 获取飞手列表 | |||
* @returns | |||
*/ | |||
export const getTaskPilot = () => request({ | |||
url: '/task/getPilot', | |||
method: 'GET' | |||
}) | |||
/** | |||
* 添加任务 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export const taskAdd = params => request({ | |||
url: '/task/add', | |||
method: 'POST', | |||
params | |||
}) | |||
/** | |||
* 添加任务 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export const taskEdit = params => request({ | |||
url: '/task/edit', | |||
method: 'PUT', | |||
params | |||
}) | |||
/** | |||
* 删除任务 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export const taskDel = params => request({ | |||
url: '/delete', | |||
method: 'DELETE', | |||
params | |||
}) | |||
/** | |||
* 分配飞手 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export const distributionPilot = params => request({ | |||
url: '/task/distributionPilot', | |||
method: 'PUT', | |||
params | |||
}) |
@@ -5,9 +5,6 @@ import { createApp } from 'vue' | |||
import { setupRouter } from '@/router' | |||
import { setupStore } from '@/store' | |||
import { useMessage } from 'naive-ui' | |||
window.$message = useMessage() | |||
import App from './App.vue' | |||
function setupApp() { |
@@ -0,0 +1,34 @@ | |||
import { defineStore } from 'pinia' | |||
export const useTaskStore = defineStore({ | |||
id: 'taskStore', | |||
state: () => ({ | |||
taskState: [ | |||
{ | |||
label: '任务待分配', | |||
value: 5 | |||
}, | |||
{ | |||
label: '任务已分配', | |||
value: 10 | |||
}, | |||
{ | |||
label: '飞手已接单', | |||
value: 15 | |||
}, | |||
{ | |||
label: '任务飞行中', | |||
value: 20 | |||
}, | |||
{ | |||
label: '任务已完成', | |||
value: 25 | |||
} | |||
] | |||
}), | |||
getters: { | |||
getTaskState() { | |||
return this.taskState; | |||
} | |||
} | |||
}) |
@@ -13,7 +13,8 @@ export function setupInterceptor(service) { | |||
if (isWithoutToken(config)) { | |||
return config | |||
} | |||
const token = getToken() | |||
// const token = getToken() | |||
const token = 'token' | |||
if (token) { | |||
config.headers.Authorization = token | |||
return config |
@@ -1,204 +0,0 @@ | |||
<template> | |||
<n-form ref="formRef" :model="model" :rules="rules" label-placement="left" label-width="auto" | |||
require-mark-placement="right-hanging" :size="'medium'" :style="{ | |||
maxWidth: '640px' | |||
}"> | |||
<n-form-item label="巡检类型 :" path="multipleSelectValue" require-mark-placement="left"> | |||
<n-select v-model:value="model.multipleSelectValue" placeholder="请选择巡检类型" :options="generalOptions" clearable /> | |||
</n-form-item> | |||
<n-form-item label="任务名称 :" path="inputValue" require-mark-placement="left"> | |||
<n-input v-model:value="model.inputValue" placeholder="请输入任务名称" /> | |||
</n-form-item> | |||
<div id="mapContainer" class="map"></div> | |||
<n-form-item label="任务起点 :" path="inputValue" require-mark-placement="left"> | |||
<n-button @click="showMap = true" quaternary type="info"> 去标记 | |||
<n-icon size="20" :component="LocationSharp" /> | |||
</n-button> | |||
</n-form-item> | |||
<n-form-item label="任务终点 :" path="inputValue" require-mark-placement="left"> | |||
<n-button @click="showMap = true" quaternary type="info"> 去标记 | |||
<n-icon size="20" :component="LocationSharp" /> | |||
</n-button> | |||
</n-form-item> | |||
<n-form-item label="飞行时间 :" path="timePickerValue" require-mark-placement="left"> | |||
<n-date-picker v-model:value="model.timePickerValue" type="datetime" /> | |||
</n-form-item> | |||
<n-form-item label="飞手 :" path="multipleSelectValue" require-mark-placement="left"> | |||
<n-select v-model:value="model.multipleSelectValue" placeholder="请选择飞手" :options="generalOptions" clearable /> | |||
</n-form-item> | |||
<n-form-item label="执飞无人机 :" path="multipleSelectValue"> | |||
<n-select v-model:value="model.multipleSelectValue" placeholder="请选择执飞无人机" :options="generalOptions" clearable /> | |||
</n-form-item> | |||
<n-form-item label="挂载设备 :" path="multipleSelectValue"> | |||
<n-select v-model:value="model.multipleSelectValue" placeholder="请选择挂载设备" :options="generalOptions" clearable /> | |||
</n-form-item> | |||
<n-form-item label="拍摄方式 :" path="multipleSelectValue"> | |||
<n-select v-model:value="model.multipleSelectValue" placeholder="请选择拍摄方式" :options="generalOptions" clearable /> | |||
</n-form-item> | |||
<n-form-item label="备注 :" path="textareaValue"> | |||
<n-input v-model:value="model.textareaValue" placeholder="请输入备注" type="textarea" :autosize="{ | |||
minRows: 3, | |||
maxRows: 5 | |||
}" /> | |||
</n-form-item> | |||
</n-form> | |||
<n-modal v-model:show="showMap" :mask-closable="false" preset="dialog" title="" positive-text="确定" | |||
@positive-click="mapClick" @negative-click="showMap = false"> | |||
<map-comp ></map-comp> | |||
</n-modal> | |||
</template> | |||
<script setup name="ModalComp"> | |||
import { NButton } from 'naive-ui' | |||
import { ref, onMounted, watch } from 'vue' | |||
import { LocationSharp } from '@vicons/ionicons5' | |||
import AMapLoader from '@amap/amap-jsapi-loader'; | |||
import MapComp from './MapComp.vue' | |||
let Gmap = null; | |||
let startMakrer = null; | |||
let endMakrer = null; | |||
let showMap = ref(false); | |||
// const mapVal = ref(null); | |||
// watch(mapVal, (val) => { | |||
// console.log('mapVal', val); | |||
// }) | |||
AMapLoader.load({ | |||
"key": "20535a30fa0f3aae9c7bbe4407270792", | |||
"version": "2.0", | |||
"plugins": ['AMap.ToolBar'] | |||
}).then((AMap) => { | |||
Gmap = new AMap.Map('mapContainer', { | |||
zoom: 13, | |||
center: [118.773319, 31.828123], | |||
}); | |||
// 添加缩放工具 | |||
const toolbar = new AMap.ToolBar(); | |||
Gmap.addControl(toolbar); | |||
// Gmap.on('click', ({})) | |||
}).catch(e => console.log(e)) | |||
const props = defineProps({ | |||
FormData: { | |||
type: [Array, Object] | |||
} | |||
}) | |||
const model = ref({ | |||
inputValue: null, | |||
multipleSelectValue: null, | |||
timePickerValue: null, | |||
textareaValue: null, | |||
}) | |||
const rules = ref({ | |||
multipleSelectValue: { | |||
required: true, | |||
trigger: ["blur", "input"], | |||
message: "请输入巡检类型" | |||
}, | |||
inputValue: { | |||
required: true, | |||
trigger: ["blur", "input"], | |||
message: "请输入任务名称" | |||
}, | |||
timePickerValue: { | |||
required: true, | |||
trigger: ["blur", "input"], | |||
message: "请选择飞行时间" | |||
}, | |||
}) | |||
const generalOptions = ['groode', 'veli good', 'emazing', 'lidiculous'].map( | |||
(v) => ({ | |||
label: v, | |||
value: v | |||
}) | |||
) | |||
// 标记起点 | |||
const startClick = () => { | |||
// console.log(Gmap); | |||
// startBtn.value = !startBtn.value | |||
Gmap.on('click', ({ lnglat: { lat, lng } }) => { | |||
console.log('startMakrer:', startMakrer); | |||
if (startMakrer) { | |||
Gmap.remove(startMakrer); | |||
} | |||
startMakrer = new AMap.Marker({ | |||
position: new AMap.LngLat(lng, lat), | |||
title: '起点' | |||
}); | |||
// 将创建的点标记添加到已有的地图实例: | |||
Gmap.add(startMakrer); | |||
}) | |||
} | |||
// 标记终点 | |||
const endClick = () => { | |||
Gmap.on('click', ({ lnglat: { lat, lng } }) => { | |||
console.log('endMakrer:', endMakrer); | |||
if (endMakrer) { | |||
Gmap.remove(endMakrer); | |||
} | |||
endMakrer = new AMap.Marker({ | |||
position: new AMap.LngLat(lng, lat), | |||
title: '终点' | |||
}); | |||
// 将创建的点标记添加到已有的地图实例: | |||
Gmap.add(endMakrer); | |||
}) | |||
} | |||
// 地图弹窗的确定 | |||
const mapClick = () => { | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.map { | |||
width: 100%; | |||
height: 155px; | |||
margin-bottom: 10px; | |||
} | |||
:deep(.amap-logo) { | |||
display: none; | |||
opacity: 0 !important; | |||
} | |||
:deep(.amap-copyright) { | |||
opacity: 0; | |||
} | |||
:deep(.__date-picker-trigger-1jezgko) { | |||
width: 100%; | |||
} | |||
</style> |
@@ -0,0 +1,119 @@ | |||
<template> | |||
<div class="head"> | |||
<n-steps size="small" :current="current" :status="'process'"> | |||
<n-step :title="it.label" v-for="(it, i) in stepList" :key="i + it.label" /> | |||
</n-steps> | |||
</div> | |||
<div class="basic"> | |||
<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> | |||
</n-descriptions> | |||
</div> | |||
<div class="basic"> | |||
<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> | |||
</n-descriptions> | |||
</div> | |||
<div class="basic"> | |||
<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> | |||
</n-descriptions> | |||
</div> | |||
</template> | |||
<script setup name="DrawComp"> | |||
import { ref, computed } from 'vue' | |||
import { useTaskStore } from '@/store/task' | |||
const props = defineProps({ | |||
}) | |||
const basicInfo = [ | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
{ | |||
label: "平台", | |||
value: "内部飞行" | |||
}, | |||
] | |||
const stepList = computed(() => useTaskStore().getTaskState) | |||
const current = ref(2) | |||
</script> | |||
<style lang="scss" scoped> | |||
.head { | |||
margin: 20px; | |||
padding: 50px 10px 50px 30px; | |||
background-color: #fff; | |||
} | |||
.basic { | |||
margin: 20px; | |||
background-color: #fff; | |||
} | |||
:deep(.n-descriptions-header) { | |||
font-weight: bold; | |||
margin: 10px; | |||
padding: 20px 0; | |||
border-bottom: 1px solid rgba(240, 242, 245, 0.8); | |||
} | |||
:deep(.n-descriptions-table) { | |||
margin: 10px; | |||
padding: 10px; | |||
} | |||
:deep(.n-drawer-body-content-wrapper) { | |||
background-color: rgba(240, 242, 245, 1); | |||
} | |||
</style> |
@@ -6,12 +6,9 @@ | |||
</template> | |||
<script setup name="mapComp"> | |||
import { ref, watch } from 'vue' | |||
import AMapLoader from '@amap/amap-jsapi-loader'; | |||
let poiResult = ref(null); | |||
const emit = defineEmits(['mapEmit']) | |||
AMapLoader.load({ | |||
"key": "20535a30fa0f3aae9c7bbe4407270792", | |||
@@ -37,50 +34,26 @@ AMapLoader.load({ | |||
input: 'pickerInput' | |||
}); | |||
const auto = new AMap.AutoComplete({ | |||
input: "pickerInput" | |||
}); | |||
auto.on("select", e => { | |||
console.log(e); | |||
}) | |||
poiPicker.on('poiPicked', ({ item }) => { | |||
let inp = document.getElementById('pickerInput'); | |||
inp.value = item.name; | |||
const marker = new AMap.Marker({ | |||
title: item.address | |||
}); | |||
poiResult.value = item; | |||
marker.setMap(map); | |||
marker.setPosition(item.location); | |||
map.setCenter(marker.getPosition()); | |||
}) | |||
}); | |||
emit('mapEmit', item); | |||
// AMap.plugin(['AMap.PlaceSearch', 'AMap.AutoComplete'], function () { | |||
// var auto = new AMap.AutoComplete(autoOptions); | |||
// var placeSearch = new AMap.PlaceSearch({ | |||
// map: map | |||
// }); //构造地点查询类 | |||
// auto.on("select", select);//注册监听,当选中某条记录时会触发 | |||
// function select(e) { | |||
// console.log(e); | |||
// placeSearch.setCity(e.poi.adcode); | |||
// placeSearch.search(e.poi.name); //关键字查询查询 | |||
// } | |||
// }); | |||
}) | |||
}); | |||
}).catch(e => console.log(e)) | |||
defineExpose({ poiResult }) | |||
</script> | |||
<style lang="scss" scoped> |
@@ -0,0 +1,247 @@ | |||
<template> | |||
<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" | |||
> | |||
<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" /> | |||
<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> | |||
<n-input v-if="item.type === 'inputStart'" v-model:value="userForm[item.key]" v-bind="item.props"> | |||
<template #suffix> | |||
<n-button @click="showStart = true" quaternary type="info">去标记 | |||
<n-icon size="20" color="rgba(42, 130, 228, 1)"> | |||
<LocationSharp /> | |||
</n-icon> | |||
</n-button> | |||
</template> | |||
</n-input> | |||
<n-input v-if="item.type === 'inputEnd'" v-model:value="userForm[item.key]" v-bind="item.props"> | |||
<template #suffix> | |||
<n-button @click="showEnd = true" quaternary type="info">去标记 | |||
<n-icon size="20" color="rgba(42, 130, 228, 1)"> | |||
<LocationSharp /> | |||
</n-icon> | |||
</n-button> | |||
</template> | |||
</n-input> | |||
<n-date-picker v-if="item.type === 'date'" v-model:value="userForm[item.key]" v-bind="item.props" type="datetime" /> | |||
<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> | |||
</n-space> | |||
</n-radio-group> | |||
</n-form-item> | |||
</template> | |||
</n-form> | |||
</template> | |||
</Modal> | |||
<n-modal v-model:show="showStart" :mask-closable="false" preset="dialog" title="" positive-text="确定" | |||
@positive-click="userForm.startValue = startVal.name" @negative-click="showStart = false"> | |||
<map-comp @mapEmit="startVal = $event"></map-comp> | |||
</n-modal> | |||
<n-modal v-model:show="showEnd" :mask-closable="false" preset="dialog" title="" positive-text="确定" | |||
@positive-click="userForm.endValue = endVal.name" @negative-click="showEnd = false"> | |||
<map-comp @mapEmit="endVal = $event"></map-comp> | |||
</n-modal> | |||
</template> | |||
<script> | |||
import { form, getDeptOptions, getRoleOptions } from '../tools/form.js' | |||
import { defineComponent, ref, reactive, computed, toRefs } from 'vue' | |||
import Modal from '@/components/Modal/index.vue' | |||
import UploadOss from '@/components/UploadOss/index.vue' | |||
import { addUser, editUser } from '@/api/system/user/index' | |||
import { LocationSharp } from '@vicons/ionicons5' | |||
import AMapLoader from '@amap/amap-jsapi-loader' | |||
import MapComp from './MapComp.vue' | |||
export default defineComponent({ | |||
name: 'UserModal', | |||
components: { Modal, UploadOss, MapComp, LocationSharp }, | |||
props: { | |||
visible: { | |||
type: Boolean, | |||
default: false | |||
}, | |||
type: { | |||
type: String, | |||
default: 'create' | |||
}, | |||
data: { | |||
type: Object, | |||
default: () => null | |||
} | |||
}, | |||
emits: { | |||
'update:visible': null, | |||
'reload': null | |||
}, | |||
setup(props, { emit }) { | |||
const MODAL_TYPE = { | |||
'create': '新建任务', | |||
'preview': '任务详情', | |||
'update': '编辑任务' | |||
} | |||
getDeptOptions() | |||
getRoleOptions() | |||
const { userForm, userRules } = form | |||
const formRef = ref() | |||
const ossRefs = ref([]) | |||
const data = reactive({ | |||
userForm: { | |||
...userForm, | |||
...props.data, | |||
roleIds: props?.data?.roles.map((item) => { return item.id }) || [] | |||
}, | |||
userRules: { | |||
...userRules | |||
}, | |||
disabled: props.type === 'preview' | |||
}) | |||
const getModalOptions = computed(() => { | |||
return { | |||
show: props.visible, | |||
title: MODAL_TYPE[props.type], | |||
negativeText: '取消', | |||
positiveText: '确认' | |||
} | |||
}) | |||
const getFormOptions = computed(() => { | |||
return { | |||
...form.formItem | |||
} | |||
}) | |||
function handleUploadStatus(status) { | |||
data.userForm.imageStatus = status | |||
} | |||
// 地图 | |||
AMapLoader.load({ | |||
"key": "20535a30fa0f3aae9c7bbe4407270792", | |||
"version": "2.0", | |||
"plugins": ['AMap.ToolBar'] | |||
}).then((AMap) => { | |||
Gmap = new AMap.Map('mapContainer', { | |||
zoom: 13, | |||
center: [118.773319, 31.828123], | |||
}); | |||
// 添加缩放工具 | |||
const toolbar = new AMap.ToolBar(); | |||
Gmap.addControl(toolbar); | |||
}).catch(e => console.log(e)) | |||
// 地图辅助参数 | |||
let showStart = ref(false); | |||
let showEnd = ref(false); | |||
const startVal = ref(null); | |||
const endVal = ref(null); | |||
function handleConfirm() { | |||
formRef.value?.validate((errors) => { | |||
if (!errors) { | |||
const uploads = ossRefs.value.map((item, index) => { | |||
return item.startUpload() | |||
}) | |||
Promise.all(uploads) | |||
.then(response => { | |||
const isError = response.map((item) => { | |||
return item.includes('error') | |||
}) | |||
if (!isError.includes(true)) { | |||
const imageStr = response.join() | |||
const params = { | |||
...data.userForm, | |||
// avatar: imageStr | |||
avatar: '/imagedir/2uim2hpl94u_1655380018696.png' | |||
} | |||
if (params.id) { | |||
/* 编辑 */ | |||
editUser(params) | |||
.then(res => { | |||
if (res.code === 0) { | |||
emit('reload') | |||
handleClose() | |||
} | |||
}) | |||
} else { | |||
/* 新增 */ | |||
addUser(params) | |||
.then(res => { | |||
if (res.code === 0) { | |||
emit('reload') | |||
handleClose() | |||
} | |||
}) | |||
} | |||
} else { | |||
$message.error('文件上传失败,请稍后重试') | |||
} | |||
}) | |||
} else { | |||
$message.error('请完善必填信息') | |||
} | |||
}) | |||
} | |||
/* 关闭弹窗 */ | |||
const handleClose = () => { | |||
emit('update:visible', false) | |||
} | |||
return { | |||
...toRefs(data), | |||
formRef, | |||
ossRefs, | |||
getModalOptions, | |||
getFormOptions, | |||
handleUploadStatus, | |||
handleConfirm, | |||
handleClose, | |||
showStart, | |||
showEnd, | |||
startVal, | |||
endVal | |||
} | |||
} | |||
}) | |||
</script> | |||
<style scoped lang='scss'> | |||
.map { | |||
width: 100%; | |||
height: 155px; | |||
margin-bottom: 10px; | |||
} | |||
:deep(.__date-picker-trigger-1jezgko) { | |||
width: 100%; | |||
} | |||
:deep(.__button-1jezgko-hlmmi) { | |||
padding-right: 0; | |||
} | |||
</style> |
@@ -1,191 +1,99 @@ | |||
<template> | |||
<div class="task-wrapper"> | |||
<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"> | |||
<template #tableTitle> | |||
<n-button type="primary" @click="handleModal"> 新建 </n-button> | |||
</template> | |||
</data-table> | |||
<div class="task-search"> | |||
<n-input v-model:value="stateVal" autosize class="task-inp" type="text" placeholder="任务状态" /> | |||
<n-input v-model:value="pingVal" autosize class="task-inp" type="text" placeholder="任务状态" /> | |||
<n-input v-model:value="zuVal" autosize class="task-inp" type="text" placeholder="任务状态" /> | |||
<n-date-picker v-model:value="dateVal" class="task-inp" type="date" /> | |||
<n-input v-model:value="stateVal2" autosize class="task-inp" type="text" placeholder="任务状态" /> | |||
<div class="btns"> | |||
<n-button @click="resetHandle" class="reset">重置</n-button> | |||
<n-button @click="searchHandle" type="info">搜索</n-button> | |||
</div> | |||
</div> | |||
<!-- 新增、编辑弹窗 --> | |||
<UserModal v-if="modalShow" v-model:visible="modalShow" :type="modalType" :data="rowData" @reload="handleSearch" /> | |||
<div class="task-btns"> | |||
<n-button type="info" color="rgba(24, 144, 255, 1)" width="50" @click="showModal = true"> | |||
<n-icon size="20" :component="AddOutline" /> 新建 | |||
</n-button> | |||
</div> | |||
<!-- 详情 - 抽屉 --> | |||
<n-drawer v-model:show="showDraw" :width="'calc(100vw - 210px)'" :placement="'right'" resizable> | |||
<n-drawer-content closable> | |||
<draw-comp /> | |||
</n-drawer-content> | |||
</n-drawer> | |||
<div class="task-tables"> | |||
<n-data-table :columns="columns" :data="data" :pagination="pagination" :bordered="false" /> | |||
</div> | |||
<n-modal v-model:show="showModal" :mask-closable="false" preset="dialog" title="新建任务" positive-text="确定" | |||
negative-text="取消" @positive-click="addTask" @negative-click="showModal = false"> | |||
<modal-comp></modal-comp> | |||
</n-modal> | |||
</div> | |||
</template> | |||
<script setup name="TaskManage"> | |||
import { h, ref, reactive } from "vue"; | |||
import { NButton, NIcon, useMessage, useDialog } from "naive-ui"; | |||
import { AddOutline } from "@vicons/ionicons5"; | |||
import ModalComp from './component/ModalComp.vue' | |||
// const message = useMessage(); | |||
// console.log(useMessage()); | |||
const dialog = useDialog(); | |||
const stateVal = ref(''); // 任务状态 | |||
const pingVal = ref(''); // 平台名称 | |||
const zuVal = ref(''); // 租户名称 | |||
const dateVal = ref(null); // 日期 | |||
const stateVal2 = ref(''); // 任务状态? | |||
const showModal = ref(true); // 弹窗框 | |||
// 表格 - 内容 | |||
const data = reactive([ | |||
{ no: 3, title: "Wonderwall", length: "4:18" }, | |||
{ no: 4, title: "Don't Look Back in Anger", length: "4:48" }, | |||
{ no: 12, title: "Champagne Supernova", length: "7:27" } | |||
]); | |||
// 表格 - 列 | |||
const columns = reactive( | |||
[ | |||
{ | |||
title: "No", | |||
key: "no" | |||
}, | |||
{ | |||
title: "Title", | |||
key: "title" | |||
}, | |||
{ | |||
title: "Length", | |||
key: "length" | |||
}, | |||
{ | |||
title: "Action", | |||
key: "actions", | |||
render(row) { | |||
return h( | |||
'div', null, [ | |||
h(NButton, { | |||
quaternary: true, | |||
type: 'info', | |||
size: "small", | |||
onClick: () => console.log('详情', row) | |||
}, { default: () => '详情' }), | |||
h(NButton, { | |||
quaternary: true, | |||
type: 'info', | |||
size: "small", | |||
style: { | |||
// display: 'none', | |||
}, | |||
onClick: () => console.log('编辑', row) | |||
}, { default: () => '编辑' }), | |||
h(NButton, { | |||
quaternary: true, | |||
type: 'error', | |||
size: "small", | |||
style: { | |||
display: row.no == 12 ? 'none' : '', | |||
}, | |||
onClick: () => delHandle(row) | |||
}, { default: () => '删除' }), | |||
] | |||
); | |||
<script> | |||
import { search } from './tools/search.js' | |||
import table from './tools/table.js' | |||
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 { getTaskPilot } 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 _params = { | |||
...unref(data.searchParams), | |||
...res | |||
} | |||
return await getTaskPilot(_params) | |||
} | |||
] | |||
); | |||
// 分页 | |||
const pagination = reactive({ | |||
pageSize: 10 | |||
}); | |||
// 重置 | |||
const resetHandle = () => { | |||
stateVal.value = ''; | |||
pingVal.value = ''; | |||
zuVal.value = ''; | |||
dateVal.value = null; | |||
stateVal2.value = ''; | |||
} | |||
// 搜索 | |||
const searchHandle = () => { | |||
} | |||
// 删除 | |||
const delHandle = (row) => { | |||
dialog.warning({ | |||
title: "警告", | |||
content: "你确定要删除此条内容?", | |||
positiveText: "删除", | |||
negativeText: "取消", | |||
onPositiveClick: () => { | |||
window.$message.success('删除成功!!') | |||
}, | |||
onNegativeClick: () => { | |||
console.log("取消", row); | |||
// 新增 | |||
function handleModal() { | |||
data.rowData = null | |||
data.modalType = 'create' | |||
data.modalShow = true | |||
} | |||
}); | |||
} | |||
// 新增 | |||
const addTask = () => { | |||
console.log('新增'); | |||
showModal.value = false | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.task-wrapper { | |||
margin: 20px; | |||
background-color: white; | |||
border: 1px solid red; | |||
.task-search { | |||
margin: 20px; | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: space-between; | |||
.task-inp { | |||
width: 200px; | |||
margin-bottom: 20px; | |||
// 选择表格数据 | |||
const selectedIds = ref([]) | |||
function handleCheck(rowKeys) { | |||
selectedIds.value = rowKeys | |||
} | |||
.btns { | |||
.reset { | |||
margin-right: 20px; | |||
// 批量删除 | |||
function deleteComplex() { | |||
if (selectedIds.value.length) { | |||
data.deleteData(selectedIds.value) | |||
} else { | |||
$message.warning('请至少选中一条数据') | |||
} | |||
} | |||
} | |||
.task-btns { | |||
margin: 20px; | |||
} | |||
onUnmounted(() => { | |||
data.searchParams = null | |||
}) | |||
return { | |||
...toRefs(data), | |||
loadDataTable, | |||
handleModal, | |||
selectedIds, | |||
deleteComplex, | |||
handleCheck | |||
} | |||
}, | |||
methods: { | |||
:deep(.n-data-table-thead) { | |||
--n-merged-th-color: rgba(230, 247, 255, 1); | |||
} | |||
} | |||
</script> | |||
<style scoped lang='scss'> | |||
.n-button+.n-button { | |||
margin-left: 10px; | |||
} | |||
:deep(.n-drawer-body-content-wrapper) { | |||
background-color: rgba(240, 242, 245, 0.8); | |||
} | |||
</style> |
@@ -0,0 +1,58 @@ | |||
import { ref, reactive } from 'vue' | |||
import { USER_STATUS } from '@/utils/dictionary.js' | |||
import { getDeptAll } from '@/api/system/dept/index' | |||
import { getRoleAll } from '@/api/system/role/index' | |||
import { dataToSelect } from '@/utils/handleData.js' | |||
const departmentOptions = ref() | |||
const rolesOptions = ref() | |||
export const form = reactive({ | |||
userForm: { | |||
avatar: '', | |||
code: '', | |||
deptId: null, | |||
username: '', | |||
realname: '', | |||
password: '', | |||
roleIds: [], | |||
status: 1, | |||
note: '' | |||
}, | |||
userRules: { | |||
typeName: [{ required: true, message: '请选择巡检类型', type: 'string', trigger: 'blur' }], | |||
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }], | |||
startValue: [{ required: true, message: '请输入任务起点', trigger: 'blur' }], | |||
endValue: [{ required: true, message: '请输入任务终点', trigger: 'blur' }], | |||
dateVal: [{ required: true, message: '请输入飞行时间', trigger: 'blur' }], | |||
username: [{ required: true, message: '请选择飞手', trigger: 'blur' }], | |||
}, | |||
formItem: [ | |||
{ type: 'select', key: 'typeName', label: '巡检类型', props: { maxlength: '20', placeholder: '请输入巡检类型', clearable: true } }, | |||
{ type: 'input', key: 'taskName', label: '任务名称', props: { maxlength: '20', placeholder: '请输入任务名称', clearable: true }}, | |||
{ type: 'map' }, | |||
{ type: 'inputStart', key: 'startValue', label: '任务起点', props: { maxlength: '20', placeholder: '请选择任务起点', clearable: true }}, | |||
{ type: 'inputEnd', key: 'endValue', label: '任务终点', props: { maxlength: '20', placeholder: '请选择任务终点', clearable: true }}, | |||
{ type: 'date', key: 'dateVal', label: '飞行时间', props: { maxlength: '20', placeholder: '请选择飞行时间', clearable: true }}, | |||
{ type: 'select', key: 'username', label: '飞手', props: { maxlength: '20', placeholder: '请选择飞手', clearable: true }}, | |||
{ type: 'select', key: 'zhifei', label: '执飞无人机', props: { maxlength: '20', placeholder: '请选择执飞无人机', clearable: true }}, | |||
{ type: 'select', key: 'guazai', label: '挂载设备', props: { maxlength: '20', placeholder: '请选择挂载设备', clearable: true }}, | |||
{ type: 'select', key: 'paishe', label: '拍摄方式', props: { maxlength: '20', placeholder: '请选择拍摄方式', clearable: true }}, | |||
{ type: 'input', key: 'note', label: '备注', props: { type: 'textarea', autosize: { maxlength: '200', minRows: 3, maxRows: 3 }}}, | |||
] | |||
}) | |||
export const getDeptOptions = async function() { | |||
const res = await getDeptAll() | |||
departmentOptions.value = dataToSelect(res.data, { label: 'name', value: 'id' }) | |||
} | |||
// 获取角色列表 | |||
export const getRoleOptions = async function() { | |||
const res = await getRoleAll() | |||
rolesOptions.value = dataToSelect(res.data, { label: 'name', value: 'id' }) | |||
} |
@@ -0,0 +1,41 @@ | |||
import { ref, reactive, computed } from 'vue' | |||
import { useTaskStore } from '@/store/task' | |||
const list = computed(() => useTaskStore().getTaskState) | |||
export const search = reactive({ | |||
search: [ | |||
{ | |||
label: '任务状态', | |||
type: 'select', | |||
key: 'stateName', | |||
props: { | |||
placeholder: '请输入任务状态', | |||
options: list | |||
} | |||
}, | |||
{ | |||
label: '客户名称', | |||
key: 'userName', | |||
props: { | |||
placeholder: '请输入客户名称' | |||
} | |||
}, | |||
{ | |||
label: '任务名称', | |||
key: 'taskName', | |||
props: { | |||
placeholder: '请选择任务名称' | |||
} | |||
}, | |||
{ | |||
label: '选择日期', | |||
type: 'date', | |||
key: 'dateVal', | |||
props: { | |||
placeholder: '请选择日期' | |||
} | |||
} | |||
] | |||
}) | |||
@@ -0,0 +1,170 @@ | |||
import { h, ref, reactive } from 'vue' | |||
import TableImage from '@/components/DataTable/tools/Image.vue' | |||
import TableTags from '@/components/DataTable/tools/Tags.vue' | |||
import TableSwitch from '@/components/DataTable/tools/Switch.vue' | |||
import TableAction from '@/components/DataTable/tools/Action.vue' | |||
import { resetPassword, deleteUser, setUserStatus } from '@/api/system/user/index.js' | |||
/* 注册table */ | |||
const tableRef = ref() | |||
const searchParams = ref() | |||
function handleSearch(params) { | |||
searchParams.value = { ...params } | |||
tableRef.value.reFetch({ searchParams }) | |||
} | |||
/** | |||
* @description: 获取数据及操作 | |||
* @param {*} row 单行数据 | |||
* @param {*} type 操作类型 create:创建,preview:预览,edit:编辑 | |||
* @return {*} | |||
*/ | |||
function getRowData(row, type) { | |||
data.rowData = row | |||
data.modalType = type | |||
data.showDraw = true | |||
} | |||
// 设置状态 | |||
function setStatus(row) { | |||
setUserStatus({ id: row.data.id, status: row.value }).then(res => { | |||
if (res.code === 0) { | |||
handleSearch() | |||
$message.success(res.msg) | |||
} else { | |||
$message.error(res.msg) | |||
} | |||
}).catch(e => { | |||
console.log(e) | |||
}) | |||
} | |||
/** | |||
* @description: 重置密码 | |||
* @param {Number} id 选中数据id | |||
* @return {*} | |||
*/ | |||
function handlePasswordReset(id) { | |||
resetPassword({ id }) | |||
.then(res => { | |||
if (res.code === 0) { | |||
handleSearch() | |||
} | |||
}).catch(e => { | |||
console.log(e) | |||
}) | |||
} | |||
/** | |||
* @description: 删除用户接口 | |||
* @param {Array} ids 用户id集合 | |||
* @return {*} | |||
*/ | |||
function deleteData(ids) { | |||
deleteUser(ids).then((res) => { | |||
if (res.code === 0) { | |||
handleSearch() | |||
} | |||
}).catch(e => { | |||
console.log(e) | |||
}) | |||
} | |||
const data = reactive({ | |||
tableRef, | |||
searchParams, | |||
rowData: {}, | |||
modalType: 'create', | |||
modalShow: false, | |||
showDraw: false, | |||
handleSearch, | |||
deleteData, | |||
columns: [ | |||
{ | |||
title: '任务编码', | |||
key: 'code', | |||
align: 'center' | |||
}, | |||
{ | |||
title: '任务名称', | |||
key: 'username', | |||
align: 'center' | |||
}, | |||
{ | |||
title: '客户名称', | |||
key: 'realname', | |||
align: 'center' | |||
}, | |||
{ | |||
title: '期望执行时间', | |||
key: 'deptName', | |||
align: 'center' | |||
}, | |||
{ | |||
title: '任务地点', | |||
key: 'createTime', | |||
align: 'center', | |||
}, | |||
{ | |||
title: '任务状态', | |||
key: 'updateTime', | |||
align: 'center', | |||
}, | |||
{ | |||
title: '飞手', | |||
key: 'status', | |||
align: 'center', | |||
}, | |||
{ | |||
title: '操作', | |||
align: 'center', | |||
width: 150, | |||
fixed: 'right', | |||
render(row) { | |||
return h(TableAction, { | |||
actions: [ | |||
{ | |||
label: '详情', | |||
type: 'button', | |||
props: { | |||
type: 'primary', | |||
text: true, | |||
onClick: getRowData.bind(null, row) | |||
}, | |||
auth: 'basic_list' | |||
}, | |||
{ | |||
label: '编辑', | |||
type: 'popconfirm', | |||
props: { | |||
onPositiveClick: handlePasswordReset.bind(null, row.id) | |||
}, | |||
ButtonProps: { | |||
text: true, | |||
type: 'primary' | |||
}, | |||
auth: 'basic_list' | |||
}, | |||
{ | |||
label: '删除', | |||
type: 'popconfirm', | |||
auth: 'basic_list', | |||
tip: '确定删除这条数据吗?', | |||
props: { | |||
onPositiveClick: deleteData.bind(null, [row.id]) | |||
}, | |||
ButtonProps: { | |||
text: true, | |||
type: 'primary' | |||
} | |||
} | |||
], | |||
align: 'center' | |||
}) | |||
} | |||
} | |||
] | |||
}) | |||
export default data |