# title | # title | ||||
VITE_APP_TITLE = '汤山林场巡检管理平台' | |||||
VITE_APP_TITLE = '林场巡检管理平台' | |||||
# 端口号 | # 端口号 | ||||
VITE_PORT = 3050 | VITE_PORT = 3050 |
"eslint-plugin-vue": "^8.5.0", | "eslint-plugin-vue": "^8.5.0", | ||||
"esno": "^0.13.0", | "esno": "^0.13.0", | ||||
"fs-extra": "^10.0.1", | "fs-extra": "^10.0.1", | ||||
"naive-ui": "^2.27.0", | |||||
"naive-ui": "^2.34.3", | |||||
"sass": "^1.49.11", | "sass": "^1.49.11", | ||||
"unocss": "^0.16.4", | "unocss": "^0.16.4", | ||||
"unplugin-vue-components": "^0.18.5", | "unplugin-vue-components": "^0.18.5", |
data | data | ||||
}) | }) | ||||
} | } | ||||
/** | |||||
* @description: 问题详情 | |||||
* @param {*} data | |||||
* @return {*} | |||||
*/ | |||||
export function orderDetail(params) { | |||||
return request({ | |||||
url: '/workOrder/question/detail', | |||||
method: 'GET', | |||||
params | |||||
}) | |||||
} |
}) | }) | ||||
} | } | ||||
/** | |||||
* @description: 下载报告 | |||||
* @param {*} id | |||||
* @return {*} | |||||
*/ | |||||
export function reportHandleDownload(id) { | |||||
return request({ | |||||
url: `report/${id}/handleWord`, | |||||
method: 'GET', | |||||
headers: { | |||||
responseType: 'arraybuffer' | |||||
} | |||||
}) | |||||
} | |||||
/* | |||||
* @Author: whyafterme | |||||
* @Date: 2022-06-16 11:39:28 | |||||
* @LastEditTime: 2022-06-29 13:51:40 | |||||
* @LastEditors: whyafterme | |||||
* @Description: | |||||
* @FilePath: \web\src\components\IconBoard\tools\icon.js | |||||
*/ | |||||
import { | import { | ||||
EditOutlined, LogoutOutlined | EditOutlined, LogoutOutlined | ||||
} from '@vicons/antd' | } from '@vicons/antd' |
/* 布局模式 vertical / horizontal */ | /* 布局模式 vertical / horizontal */ | ||||
/* layoutMode: 'vertical', */ | /* layoutMode: 'vertical', */ | ||||
/* 导航模式 sidebar / header */ | /* 导航模式 sidebar / header */ | ||||
title: '汤山林场巡检管理平台', | |||||
title: '林场巡检管理平台', | |||||
menuMode: 'sidebar', | menuMode: 'sidebar', | ||||
headerSetting: { | headerSetting: { | ||||
isReload: true | isReload: true |
{ label: '待生成', value: 0 }, | { label: '待生成', value: 0 }, | ||||
{ label: '已生成', value: 1 }, | { label: '已生成', value: 1 }, | ||||
{ label: '待分配', value: 5 }, | { label: '待分配', value: 5 }, | ||||
{ label: '处理中', value: 10 }, | |||||
{ label: '已分配', value: 10 }, | |||||
{ label: '已完成', value: 15 } | { label: '已完成', value: 15 } | ||||
] | ] | ||||
{ label: '已完成', value: 15 } | { label: '已完成', value: 15 } | ||||
] | ] | ||||
export const ORDER_STATUS3 = [ | |||||
{ label: '处理中', value: 10 }, | |||||
{ label: '已完成', value: 15 } | |||||
] | |||||
export const QUES_STATUS = [ | export const QUES_STATUS = [ | ||||
{ label: '待处理', value: 0 }, | { label: '待处理', value: 0 }, | ||||
{ label: '已处理', value: 1 } | { label: '已处理', value: 1 } |
<div class="login__container"> | <div class="login__container"> | ||||
<div class="container__left" /> | <div class="container__left" /> | ||||
<div class="container__right"> | <div class="container__right"> | ||||
<div class="right__title">汤山林场巡检管理平台</div> | |||||
<div class="right__title">林场巡检管理平台</div> | |||||
<div class="right__form"> | <div class="right__form"> | ||||
<n-form | <n-form | ||||
ref="formRef" | ref="formRef" |
<script> | <script> | ||||
import { QUESTION_TYPE } from '@/utils/dictionary.js' | import { QUESTION_TYPE } from '@/utils/dictionary.js' | ||||
import { getReportDetail, reportDownload } from '@/api/report/index.js' | |||||
import { getReportDetail, reportHandleDownload } from '@/api/report/index.js' | |||||
import { defineComponent, reactive, toRefs, computed, watch } from 'vue' | import { defineComponent, reactive, toRefs, computed, watch } from 'vue' | ||||
export default defineComponent({ | export default defineComponent({ | ||||
}) | }) | ||||
function handleDownload() { | function handleDownload() { | ||||
reportDownload(props.data.id) | |||||
reportHandleDownload(props.data.id) | |||||
.then((res) => { | .then((res) => { | ||||
const download = document.createElement('iframe') | const download = document.createElement('iframe') | ||||
download.src = res.data | download.src = res.data |
const loadDataTable = async(res) => { | const loadDataTable = async(res) => { | ||||
const _params = { | const _params = { | ||||
...unref(data.searchParams), | ...unref(data.searchParams), | ||||
handleFlag: 1, | |||||
...res | ...res | ||||
} | } | ||||
return await getOrderList(_params) | return await getOrderList(_params) |
import { reactive } from 'vue' | import { reactive } from 'vue' | ||||
import { ORDER_STATUS2 } from '@/utils/dictionary.js' | |||||
import { ORDER_STATUS3 } from '@/utils/dictionary.js' | |||||
export const search = reactive([ | export const search = reactive([ | ||||
{ | { | ||||
} | } | ||||
}, | }, | ||||
{ | { | ||||
label: '工单分配状态', | |||||
label: '工单状态', | |||||
key: 'status', | key: 'status', | ||||
type: 'select', | type: 'select', | ||||
props: { | props: { | ||||
placeholder: '请选择工单分配状态', | |||||
options: ORDER_STATUS2 | |||||
placeholder: '请选择工单状态', | |||||
options: ORDER_STATUS3 | |||||
} | } | ||||
}, | }, | ||||
{ | { |
import { ORDER_STATUS } from '@/utils/dictionary.js' | |||||
import { ORDER_STATUS3 } from '@/utils/dictionary.js' | |||||
import TableTags from '@/components/DataTable/tools/Tags.vue' | import TableTags from '@/components/DataTable/tools/Tags.vue' | ||||
import TableAction from '@/components/DataTable/tools/Action.vue' | import TableAction from '@/components/DataTable/tools/Action.vue' | ||||
import { h, ref, reactive } from 'vue' | import { h, ref, reactive } from 'vue' | ||||
const searchParams = ref() | const searchParams = ref() | ||||
function handleSearch(params) { | function handleSearch(params) { | ||||
console.log(params) | |||||
searchParams.value = { ...params } | |||||
searchParams.value = { ...params, handleFlag: 1 } | |||||
if (params?.time?.length) { | if (params?.time?.length) { | ||||
searchParams.value = { | searchParams.value = { | ||||
...params, | ...params, | ||||
render(row) { | render(row) { | ||||
return h(TableTags, { | return h(TableTags, { | ||||
data: row.status, | data: row.status, | ||||
filters: ORDER_STATUS | |||||
filters: ORDER_STATUS3 | |||||
}) | }) | ||||
} | } | ||||
}, | }, |
<template> | |||||
<Modal | |||||
:options="getModalOptions" | |||||
:on-positive-click="handleConfirm" | |||||
:on-negative-click="handleClose" | |||||
:on-close="handleClose" | |||||
> | |||||
<template #Context> | |||||
<n-form | |||||
ref="formRef" | |||||
:model="questionForm" | |||||
:rules="questionRules" | |||||
:label-width="120" | |||||
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"> | |||||
<n-input v-if="item.type === 'input'" v-model:value="questionForm[item.key]" v-bind="item.props" /> | |||||
<n-select v-if="item.type === 'select'" v-model:value="questionForm[item.key]" v-bind="item.props" /> | |||||
<n-image v-if="item.type === 'image'" v-model:src="questionForm[item.key]" v-bind="item.props" /> | |||||
<UploadOss v-if="item.type === 'oss'" :limit="5" :default-list="questionForm[item.file]" /> | |||||
</n-form-item> | |||||
</template> | |||||
</n-form> | |||||
</template> | |||||
</Modal> | |||||
</template> | |||||
<script> | |||||
import { form } from '../tools/quesForm.js' | |||||
import { defineComponent, ref, reactive, computed, toRefs } from 'vue' | |||||
import Modal from '@/components/Modal/index.vue' | |||||
import UploadOss from '@/components/UploadOss/index.vue' | |||||
export default defineComponent({ | |||||
name: 'UserModal', | |||||
components: { Modal, UploadOss }, | |||||
props: { | |||||
visible: { | |||||
type: Boolean, | |||||
default: false | |||||
}, | |||||
type: { | |||||
type: String, | |||||
default: 'preview' | |||||
}, | |||||
orderId: { | |||||
type: Number, | |||||
default: null | |||||
}, | |||||
data: { | |||||
type: Object, | |||||
default: () => null | |||||
} | |||||
}, | |||||
emits: { | |||||
'update:visible': null, | |||||
'reload': null | |||||
}, | |||||
setup(props, { emit }) { | |||||
const MODAL_TYPE = { | |||||
'preview': '问题详情', | |||||
'update': '处理问题' | |||||
} | |||||
const { questionForm, questionRules } = form | |||||
const formRef = ref() | |||||
const data = reactive({ | |||||
questionForm: { | |||||
...questionForm, | |||||
imageStatus: '', | |||||
...props.data, | |||||
position: `${props.data.lng},${props.data.lat}` | |||||
}, | |||||
questionRules: { | |||||
...questionRules | |||||
}, | |||||
disabled: props.type === 'preview' | |||||
}) | |||||
const getModalOptions = computed(() => { | |||||
return { | |||||
show: props.visible, | |||||
title: MODAL_TYPE[props.type], | |||||
negativeText: '取消', | |||||
positiveText: '确认' | |||||
} | |||||
}) | |||||
const getFormOptions = computed(() => { | |||||
if (props.type === 'preview' && props.data.status === 0) { | |||||
const list = form.formItem.filter((item) => !item.mode) | |||||
return { | |||||
...list | |||||
} | |||||
} else { | |||||
return { | |||||
...form.formItem | |||||
} | |||||
} | |||||
}) | |||||
function handleConfirm() { | |||||
handleClose() | |||||
} | |||||
/* 关闭弹窗 */ | |||||
const handleClose = () => { | |||||
emit('update:visible', false) | |||||
} | |||||
return { | |||||
...toRefs(data), | |||||
formRef, | |||||
getModalOptions, | |||||
getFormOptions, | |||||
handleConfirm, | |||||
handleClose | |||||
} | |||||
} | |||||
}) | |||||
</script> | |||||
<style scoped lang='scss'> | |||||
</style> |
<MapDrawer v-model:visible="mapDrawer" :data="rowData" /> | <MapDrawer v-model:visible="mapDrawer" :data="rowData" /> | ||||
<QuestionModal v-if="modalShow" v-model:visible="modalShow" :type="modalType" :data="rowData" /> | |||||
<PreviewModal v-if="previewModal" v-model:visible="previewModal" :data="pageData" :select-row="rowData" /> | <PreviewModal v-if="previewModal" v-model:visible="previewModal" :data="pageData" :select-row="rowData" /> | ||||
</template> | </template> | ||||
import DataTable from '@/components/DataTable/index.vue' | import DataTable from '@/components/DataTable/index.vue' | ||||
import MapDrawer from './components/MapDrawer.vue' | import MapDrawer from './components/MapDrawer.vue' | ||||
import PreviewModal from './components/PreviewModal.vue' | import PreviewModal from './components/PreviewModal.vue' | ||||
import QuestionModal from './components/QuestionModal.vue' | |||||
import { reactive, ref, unref, toRefs, onUnmounted } from 'vue' | import { reactive, ref, unref, toRefs, onUnmounted } from 'vue' | ||||
import { getQuestionList } from '@/api/task/index.js' | import { getQuestionList } from '@/api/task/index.js' | ||||
import { generateOrder } from '@/api/order/index.js' | import { generateOrder } from '@/api/order/index.js' | ||||
export default { | export default { | ||||
name: 'QuestionList', | name: 'QuestionList', | ||||
components: { HeadSearch, DataTable, MapDrawer, PreviewModal }, | |||||
components: { HeadSearch, DataTable, MapDrawer, PreviewModal, QuestionModal }, | |||||
setup() { | setup() { | ||||
const data = reactive({ | const data = reactive({ | ||||
search, | search, |
import { ref, reactive } from 'vue' | |||||
import { QUESTION_TYPE_ALL, QUES_STATUS } from '@/utils/dictionary.js' | |||||
export const form = reactive({ | |||||
questionForm: { | |||||
handlerResult: '' | |||||
}, | |||||
questionRules: { | |||||
imageStatus: { required: true, message: '请选择图片', trigger: ['blur', 'change'] } | |||||
}, | |||||
formItem: [ | |||||
{ type: 'select', key: 'type', label: '问题类型', props: { options: QUESTION_TYPE_ALL, disabled: true }}, | |||||
{ type: 'input', key: 'position', label: '问题经纬度', props: { disabled: true }}, | |||||
{ type: 'input', key: 'createTime', label: '问题发现时间', props: { disabled: true }}, | |||||
{ type: 'image', key: 'fileMarkerUrl', label: '问题图片', props: { width: 100 }}, | |||||
{ type: 'select', key: 'status', label: '问题状态', props: { options: QUES_STATUS, disabled: true }}, | |||||
{ type: 'oss', refIndex: 0, key: 'imageStatus', file: 'handlerImage', label: '封面', mode: true }, | |||||
{ type: 'input', key: 'handlerResult', label: '描述', props: { type: 'textarea', maxlength: 255 }, mode: true } | |||||
] | |||||
}) | |||||
import TableImage from '@/components/DataTable/tools/Image.vue' | import TableImage from '@/components/DataTable/tools/Image.vue' | ||||
import TableTags from '@/components/DataTable/tools/Tags.vue' | import TableTags from '@/components/DataTable/tools/Tags.vue' | ||||
import TableAction from '@/components/DataTable/tools/Action.vue' | import TableAction from '@/components/DataTable/tools/Action.vue' | ||||
import { orderDetail } from '@/api/order/index.js' | |||||
import { h, ref, reactive } from 'vue' | import { h, ref, reactive } from 'vue' | ||||
/* 注册table */ | /* 注册table */ | ||||
tableRef.value.reFetch({ searchParams }) | tableRef.value.reFetch({ searchParams }) | ||||
} | } | ||||
function handlePreview(row) { | |||||
data.orderModal = true | |||||
data.rowData = row | |||||
async function handlePreview(row) { | |||||
if (row.handleStatus === 0) { | |||||
data.rowData = { | |||||
...row, | |||||
status: 0 | |||||
} | |||||
} | |||||
if (row.handleStatus === 1) { | |||||
const res = await orderDetail({ questionId: row.id }) | |||||
data.rowData = { | |||||
...row, | |||||
handlerImage: res.data.questionHandle.handlerImage, | |||||
handlerResult: res.data.questionHandle.handlerResult | |||||
} | |||||
} | |||||
data.modalShow = true | |||||
} | } | ||||
/* 位置 */ | /* 位置 */ | ||||
tableRef, | tableRef, | ||||
searchParams, | searchParams, | ||||
rowData: {}, | rowData: {}, | ||||
orderModal: false, | |||||
modalShow: false, | |||||
mapDrawer: false, | mapDrawer: false, | ||||
previewModal: false, | previewModal: false, | ||||
handleSearch, | handleSearch, |
<n-gi><span>{{ item.questionDesc ? item.questionDesc : '-' }}</span></n-gi> | <n-gi><span>{{ item.questionDesc ? item.questionDesc : '-' }}</span></n-gi> | ||||
<n-gi><span>问题图片</span></n-gi> | <n-gi><span>问题图片</span></n-gi> | ||||
<n-gi><n-image :src="item.fileMarkerUrl" /></n-gi> | <n-gi><n-image :src="item.fileMarkerUrl" /></n-gi> | ||||
<n-gi v-if="type === 'result' && item.questionHandleList"><span>处理结果</span></n-gi> | |||||
<n-gi v-if="type === 'result' && item.questionHandleList"><n-image v-for="(cItem,cIndex) in item.questionHandleList" :key="cIndex" :src="cItem.handlerImage" /></n-gi> | |||||
<n-gi v-if="type === 'result' && item.questionHandleList.length"><span>处理结果</span></n-gi> | |||||
<n-gi v-if="type === 'result' && item.questionHandleList.length"><n-image v-for="(cItem,cIndex) in item.questionHandleList" :key="cIndex" :src="cItem.handlerImage" /></n-gi> | |||||
</n-grid> | </n-grid> | ||||
</div> | </div> | ||||
<!-- </n-image-group> --> | <!-- </n-image-group> --> | ||||
<script> | <script> | ||||
import { QUESTION_TYPE } from '@/utils/dictionary.js' | import { QUESTION_TYPE } from '@/utils/dictionary.js' | ||||
import { getReportDetail, reportDownload } from '@/api/report/index.js' | |||||
import { getReportDetail, reportDownload, reportHandleDownload } from '@/api/report/index.js' | |||||
import { defineComponent, reactive, toRefs, computed, watch } from 'vue' | import { defineComponent, reactive, toRefs, computed, watch } from 'vue' | ||||
export default defineComponent({ | export default defineComponent({ | ||||
}) | }) | ||||
function handleDownload() { | function handleDownload() { | ||||
reportDownload(props.data.id) | |||||
.then((res) => { | |||||
const download = document.createElement('iframe') | |||||
download.src = res.data | |||||
download.style.display = 'none' | |||||
document.body.appendChild(download) | |||||
setTimeout(() => { | |||||
document.body.removeChild(download) | |||||
}, 300) | |||||
}) | |||||
if (props.type === 'inspection') { | |||||
reportDownload(props.data.id) | |||||
.then((res) => { | |||||
const download = document.createElement('iframe') | |||||
download.src = res.data | |||||
download.style.display = 'none' | |||||
document.body.appendChild(download) | |||||
setTimeout(() => { | |||||
document.body.removeChild(download) | |||||
}, 300) | |||||
}) | |||||
} | |||||
if (props.type === 'result') { | |||||
reportHandleDownload(props.data.id) | |||||
.then((res) => { | |||||
const download = document.createElement('iframe') | |||||
download.src = res.data | |||||
download.style.display = 'none' | |||||
document.body.appendChild(download) | |||||
setTimeout(() => { | |||||
document.body.removeChild(download) | |||||
}, 300) | |||||
}) | |||||
} | |||||
} | } | ||||
return { | return { |