Browse Source

重写和详情页

tags/v1.0.0
吴迪 2 years ago
parent
commit
56f52a1832
15 changed files with 843 additions and 412 deletions
  1. +1
    -1
      .env.localhost
  2. +2
    -1
      .gitignore
  3. +11
    -0
      package-lock.json
  4. +75
    -0
      src/api/task/index.js
  5. +0
    -3
      src/main.js
  6. +34
    -0
      src/store/task/index.js
  7. +2
    -1
      src/utils/http/interceptors.js
  8. +0
    -204
      src/views/task-manage/component/ModalComp.vue
  9. +119
    -0
      src/views/task-manage/components/DrawComp.vue
  10. +6
    -33
      src/views/task-manage/components/MapComp.vue
  11. +247
    -0
      src/views/task-manage/components/UserModal.vue
  12. +77
    -169
      src/views/task-manage/index.vue
  13. +58
    -0
      src/views/task-manage/tools/form.js
  14. +41
    -0
      src/views/task-manage/tools/search.js
  15. +170
    -0
      src/views/task-manage/tools/table.js

+ 1
- 1
.env.localhost View File

@@ -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
- 1
.gitignore View File

@@ -2,4 +2,5 @@ node_modules
.DS_Store
dist
dist-ssr
*.local
*.local
.idea

+ 11
- 0
package-lock.json View File

@@ -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",

+ 75
- 0
src/api/task/index.js View File

@@ -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
})

+ 0
- 3
src/main.js View File

@@ -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() {

+ 34
- 0
src/store/task/index.js View File

@@ -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;
}
}
})

+ 2
- 1
src/utils/http/interceptors.js View File

@@ -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

+ 0
- 204
src/views/task-manage/component/ModalComp.vue View File

@@ -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>

+ 119
- 0
src/views/task-manage/components/DrawComp.vue View File

@@ -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>

src/views/task-manage/component/MapComp.vue → src/views/task-manage/components/MapComp.vue View File

@@ -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>

+ 247
- 0
src/views/task-manage/components/UserModal.vue View File

@@ -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>

+ 77
- 169
src/views/task-manage/index.vue View File

@@ -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>

+ 58
- 0
src/views/task-manage/tools/form.js View File

@@ -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' })
}

+ 41
- 0
src/views/task-manage/tools/search.js View File

@@ -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: '请选择日期'
}
}
]
})


+ 170
- 0
src/views/task-manage/tools/table.js View File

@@ -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

Loading…
Cancel
Save