Merge branch 'master' of http://139.196.74.78:10010/r/jagzwxm/ja_web
10 files modified
2 files renamed
5 files deleted
12 files added
| | |
| | | <basic-container> |
| | | <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search"> |
| | | <el-form-item label="场景名称" prop="sceneName"> |
| | | <el-input class="ztzf-data-cockpit-search-input" v-model="searchParams.sceneName" placeholder="请输入" |
| | | clearable @clear="handleSearch" /> |
| | | <el-input |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.sceneName" |
| | | placeholder="请输入" |
| | | clearable |
| | | @clear="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="场景类型" prop="sceneType"> |
| | | <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model="searchParams.sceneType" placeholder="请选择" clearable @change="handleSearch"> |
| | | <el-option v-for="item in dictObj.sceneType" :key="item.dictKey" :label="item.dictValue" |
| | | :value="item.dictKey" /> |
| | | <el-select |
| | | class="ztzf-data-cockpit-select" |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model="searchParams.sceneType" |
| | | placeholder="请选择" |
| | | clearable |
| | | @change="handleSearch" |
| | | > |
| | | <el-option |
| | | v-for="item in dictObj.sceneType" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="场景状态" prop="status"> |
| | | <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model="searchParams.status" placeholder="请选择" clearable @change="handleSearch"> |
| | | <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | <el-select |
| | | class="ztzf-data-cockpit-select" |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model="searchParams.status" |
| | | placeholder="请选择" |
| | | clearable |
| | | @change="handleSearch" |
| | | > |
| | | <el-option |
| | | v-for="item in dictObj.sceneStatus" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | |
| | | <el-table class="ztzf-data-cockpit-table" :data="list" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="46" /> |
| | | <el-table-column type="index" show-overflow-tooltip width="64" label="序号" /> |
| | | |
| | | |
| | | <el-table-column prop="sceneName" show-overflow-tooltip width="130" label="场景名称" /> |
| | | <el-table-column prop="sceneType" show-overflow-tooltip width="120" label="场景类型"> |
| | | <template v-slot="{ row }"> |
| | |
| | | </div> |
| | | |
| | | <div class="ztzf-table-pagination"> |
| | | <el-pagination popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" :total="total" @change="getList" /> |
| | | <el-pagination |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" |
| | | :total="total" |
| | | @change="getList" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | const dialogRef = ref(null) // 弹框实例 |
| | | const dialogVisible = ref(false) |
| | | |
| | | const statusOptions = ref([ |
| | | { label: '正常', value: 0 }, |
| | | { label: '停用', value: 1 }, |
| | | ]) |
| | | |
| | | // 获取列表 |
| | | async function getList () { |
| | | async function getList() { |
| | | loading.value = true |
| | | try { |
| | | const res = await fwDefenseScenePageApi(searchParams.value) |
| | |
| | | } |
| | | |
| | | // 查询 |
| | | function handleSearch () { |
| | | function handleSearch() { |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 重置查询 |
| | | function resetForm () { |
| | | function resetForm() { |
| | | queryParamsRef.value?.resetFields() |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 删除 |
| | | async function handleDelete (row) { |
| | | async function handleDelete(row) { |
| | | const tips = row ? '该条' : '选中的项' |
| | | await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning' }) |
| | | const ids = row ? row.id : selectedIds.value.join(',') |
| | |
| | | } |
| | | |
| | | // 勾选值设置 |
| | | function handleSelectionChange (rows) { |
| | | function handleSelectionChange(rows) { |
| | | selectedIds.value = rows.map(item => item.id) |
| | | } |
| | | |
| | | function formatLocation (row) { |
| | | function formatLocation(row) { |
| | | if (row?.longitude == null || row?.latitude == null) return '' |
| | | return `${_.round(row.longitude, 6)}, ${_.round(row.latitude, 6)}` |
| | | } |
| | |
| | | sceneType: [], // 场景类型 |
| | | deviceMode: [], // 设备模式 |
| | | areaType: [], // 区域类型 |
| | | sceneStatus: [], // 场景状态 |
| | | }) |
| | | provide('dictObj', dictObj) |
| | | |
| | | // 获取字典 |
| | | function getDictList () { |
| | | getDictionaryByCode('sceneType,deviceMode,areaType').then(res => { |
| | | function getDictList() { |
| | | getDictionaryByCode('sceneType,deviceMode,areaType,sceneStatus').then(res => { |
| | | dictObj.value = res.data.data |
| | | }) |
| | | } |
| | | |
| | | // 新增/编辑/查看 弹框 |
| | | function openForm (mode, row) { |
| | | function openForm(mode, row) { |
| | | dialogVisible.value = true |
| | | nextTick(() => { |
| | | dialogRef.value?.open({ mode, row }) |
| | |
| | | <basic-container> |
| | | <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search"> |
| | | <el-form-item label="名称" prop="deviceName"> |
| | | <el-input class="ztzf-data-cockpit-search-input" v-model="searchParams.deviceName" placeholder="请输入" |
| | | clearable @clear="handleSearch" /> |
| | | <el-input |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.deviceName" |
| | | placeholder="请输入" |
| | | clearable |
| | | @clear="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="类型" prop="deviceType"> |
| | | <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model="searchParams.deviceType" placeholder="请选择" clearable @change="handleSearch"> |
| | | <el-option v-for="item in dictObj.deviceType" :key="item.dictKey" :label="item.dictValue" |
| | | :value="item.dictKey" /> |
| | | <el-select |
| | | class="ztzf-data-cockpit-select" |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model="searchParams.deviceType" |
| | | placeholder="请选择" |
| | | clearable |
| | | @change="handleSearch" |
| | | > |
| | | <el-option |
| | | v-for="item in dictObj.deviceType" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="部门" prop="belongDept"> |
| | | <el-tree-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-tree-select-popper" |
| | | v-model="searchParams.belongDept" :data="deptTree" :props="treeProps" node-key="id" check-strictly |
| | | clearable @change="handleSearch" /> |
| | | <el-tree-select |
| | | class="ztzf-data-cockpit-select" |
| | | popper-class="ztzf-data-cockpit-tree-select-popper" |
| | | v-model="searchParams.belongDept" |
| | | :data="deptTree" |
| | | :props="treeProps" |
| | | node-key="id" |
| | | check-strictly |
| | | clearable |
| | | @change="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="时间"> |
| | | <el-date-picker popper-class="ztzf-data-cockpit-date-picker-popper" |
| | | class="ztzf-data-cockpit-date-picker" v-model="dateRange" type="daterange" range-separator="至" |
| | | start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD HH:mm:ss" |
| | | @change="handleSearch" /> |
| | | <el-date-picker |
| | | popper-class="ztzf-data-cockpit-date-picker-popper" |
| | | class="ztzf-data-cockpit-date-picker" |
| | | v-model="dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | @change="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item class="history-search-actions"> |
| | |
| | | <el-table-column prop="charger" show-overflow-tooltip width="100" label="负责人" /> |
| | | <el-table-column prop="yxzt" show-overflow-tooltip width="116" label="运行状态"> |
| | | <template v-slot="{ row }"> |
| | | {{ DEVICE_STATUS[row.status] || '-' }} |
| | | {{ getDictLabel(row.status, dictObj.deviceStatus) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" class-name="operation-btns"> |
| | |
| | | </div> |
| | | |
| | | <div class="ztzf-table-pagination"> |
| | | <el-pagination popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" :total="total" @change="getList" /> |
| | | <el-pagination |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" |
| | | :total="total" |
| | | @change="getList" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import { getDeptTree } from '@/api/system/dept' |
| | | import { blobDownload, dateRangeFormat, getDictLabel, formatDateToSlash } from '@ztzf/utils' |
| | | import { DEVICE_STATUS } from '@ztzf/constants' |
| | | import DeviceTrackDiaLog from '@/views/basicManage/deviceStock/DeviceTrackDiaLog.vue' |
| | | import DeviceScrapDiaLog from '@/views/basicManage/deviceStock/DeviceScrapDiaLog.vue' |
| | | |
| | |
| | | provide('deptTree', deptTree) |
| | | |
| | | // 获取列表 |
| | | async function getList () { |
| | | async function getList() { |
| | | const range = dateRangeFormat(dateRange.value) |
| | | loading.value = true |
| | | try { |
| | |
| | | } |
| | | |
| | | // 查询 |
| | | function handleSearch () { |
| | | function handleSearch() { |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 重置查询 |
| | | function resetForm () { |
| | | function resetForm() { |
| | | dateRange.value = [] |
| | | queryParamsRef.value?.resetFields() |
| | | searchParams.value.current = 1 |
| | |
| | | } |
| | | |
| | | // 查看 |
| | | function handleView (row) { |
| | | function handleView(row) { |
| | | dialogRef.value?.open({ mode: 'view', row: { ...row } }) |
| | | } |
| | | |
| | | // 编辑 |
| | | function handleEdit (row) { |
| | | function handleEdit(row) { |
| | | dialogRef.value?.open({ mode: 'edit', row: { ...row } }) |
| | | } |
| | | |
| | | function outbound (row) { |
| | | function outbound(row) { |
| | | outboundDialogRef.value?.open({ mode: 'edit', row: { ...row } }) |
| | | } |
| | | |
| | | function scrap (row) { |
| | | function scrap(row) { |
| | | scrapDialogRef.value?.open({ mode: 'edit', row: { ...row } }) |
| | | } |
| | | |
| | | // 删除 |
| | | async function handleDelete (row) { |
| | | async function handleDelete(row) { |
| | | const tips = row ? '该条' : '选中的项' |
| | | await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning' }) |
| | | const ids = row ? row.id : selectedIds.value.join(',') |
| | |
| | | } |
| | | |
| | | // 勾选值设置 |
| | | function handleSelectionChange (rows) { |
| | | function handleSelectionChange(rows) { |
| | | selectedIds.value = rows.map(item => item.id) |
| | | } |
| | | |
| | | function exportFile () { |
| | | function exportFile() { |
| | | exportLoading.value = true |
| | | exportFwDeviceApi() |
| | | .then(res => { |
| | |
| | | } |
| | | |
| | | // 获取字典 |
| | | function getDictList () { |
| | | getDictionaryByCode('deviceType,deviceAtt').then(res => { |
| | | function getDictList() { |
| | | getDictionaryByCode('deviceType,deviceAtt,deviceStatus').then(res => { |
| | | dictObj.value = res.data.data |
| | | }) |
| | | } |
| | | |
| | | // 获取部门树 |
| | | function getDeptTreeFun () { |
| | | function getDeptTreeFun() { |
| | | getDeptTree().then(res => { |
| | | deptTree.value = res.data.data |
| | | }) |
| | | } |
| | | |
| | | // 新增 |
| | | function handleAdd () { |
| | | function handleAdd() { |
| | | dialogRef.value?.open({ mode: 'add' }) |
| | | } |
| | | |
| New file |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false"> |
| | | <div v-if="readonly"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <div>无人机名称: {{ formData.droneName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>无人机类型: {{ formData.droneType }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>无人机设备编码: {{ formData.droneDeviceCode }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>发现时间: {{ formData.findTime }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>反制效果: {{ getDictLabel(formData.counterEffect, dictObj.counterEffect) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>反制方式: {{ getCounterWayLabel(formData.counterWay) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>反制设备名称: {{ formData.deviceName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>反制设备型号: {{ formData.deviceModel }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>反制设备类型: {{ getDeviceTypeLabel(formData.deviceType) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>反制设备编码: {{ formData.deviceCode }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>区域编码: {{ formData.areaCode }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>部署位置: {{ getDeployPosition() }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>覆盖范围: {{ formData.coverRadiusM ? `${formData.coverRadiusM}米` : '' }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>工作模式: {{ getWorkModeLabel(formData.workMode) }}</div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <template #footer> |
| | | <el-button @click="handleCancel">关闭</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref, inject } from 'vue' |
| | | import { fwEffectEvalDetailApi } from './countermeasureEvaluationApi' |
| | | import { getDictLabel } from '../../../../../../packages/utils' |
| | | |
| | | // 初始化表单数据 |
| | | const initForm = () => ({ |
| | | droneName: '', // 无人机名称 |
| | | droneType: '', // 无人机类型 |
| | | droneDeviceCode: '', // 无人机设备编码 |
| | | findTime: '', // 发现时间 |
| | | counterEffect: '', // 反制效果 |
| | | counterWay: '', // 反制方式 |
| | | deviceName: '', // 反制设备名称 |
| | | deviceModel: '', // 反制设备型号 |
| | | deviceType: '', // 反制设备类型 |
| | | deviceCode: '', // 反制设备编码 |
| | | areaCode: '', // 区域编码 |
| | | deployLongitude: '', // 部署经度 |
| | | deployLatitude: '', // 部署纬度 |
| | | coverRadiusM: '', // 覆盖范围 |
| | | workMode: '', // 工作模式 |
| | | }) |
| | | |
| | | // 注入字典数据 |
| | | const dictObj = inject('dictObj') |
| | | // 注入反制效果选项 |
| | | |
| | | const formData = ref(initForm()) // 表单数据 |
| | | const visible = defineModel() // 弹框显隐 |
| | | const dialogMode = ref('view') // 弹框模式 |
| | | const readonly = computed(() => dialogMode.value === 'view') |
| | | const titleEnum = ref({ view: '查看' }) |
| | | |
| | | // 关闭弹框 |
| | | function handleCancel() { |
| | | visible.value = false |
| | | } |
| | | |
| | | // 获取反制方式标签 |
| | | function getCounterWayLabel(value) { |
| | | const map = { '1': '信号干扰', '2': '诱导驱离' } |
| | | return map[value] || value || '无' |
| | | } |
| | | |
| | | // 获取设备类型标签 |
| | | function getDeviceTypeLabel(value) { |
| | | const item = dictObj.value?.deviceType?.find(item => item.dictKey === value) |
| | | return item ? item.dictValue : value |
| | | } |
| | | |
| | | // 获取工作模式标签 |
| | | function getWorkModeLabel(value) { |
| | | const map = { '1': '机动', '2': '固定' } |
| | | return map[value] || value |
| | | } |
| | | |
| | | // 获取部署位置 |
| | | function getDeployPosition() { |
| | | if (formData.value.deployLongitude && formData.value.deployLatitude) { |
| | | return `${formData.value.deployLongitude}, ${formData.value.deployLatitude}` |
| | | } |
| | | return '' |
| | | } |
| | | |
| | | // 加载详情 |
| | | async function loadDetail() { |
| | | if (!formData.value.id) return |
| | | const res = await fwEffectEvalDetailApi({ id: formData.value.id }) |
| | | formData.value = res?.data?.data ?? {} |
| | | } |
| | | |
| | | // 打开弹框 |
| | | async function open({ mode, row } = {}) { |
| | | dialogMode.value = mode || 'view' |
| | | formData.value = row ? { ...row } : initForm() |
| | | dialogMode.value === 'view' && (await loadDetail()) |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
| New file |
| | |
| | | import request from '@/axios' |
| | | |
| | | // 分页查询反制效果评估列表 |
| | | export const fwEffectEvalPageApi = params => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwEffectEval/page`, |
| | | method: 'get', |
| | | params, |
| | | }) |
| | | } |
| | | |
| | | // 获取反制效果评估详情 |
| | | export const fwEffectEvalDetailApi = params => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwEffectEval/detail`, |
| | | method: 'get', |
| | | params, |
| | | }) |
| | | } |
| New file |
| | |
| | | <template> |
| | | <basic-container> |
| | | <el-form ref="queryParamsRef" :model="searchParams"> |
| | | <el-row :gutter="16"> |
| | | <el-col :span="4"> |
| | | <el-form-item label="设备名称" prop="deviceName"> |
| | | <el-input v-model="searchParams.deviceName" placeholder="请输入" clearable @clear="handleSearch" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="设备类型" prop="deviceType"> |
| | | <el-select v-model="searchParams.deviceType" placeholder="请选择" clearable @change="handleSearch"> |
| | | <el-option |
| | | v-for="item in dictObj.deviceType" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="反制效果" prop="counterEffect"> |
| | | <el-select v-model="searchParams.counterEffect" placeholder="请选择" clearable @change="handleSearch"> |
| | | <el-option |
| | | v-for="item in dictObj.counterEffect" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-button @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="handleSearch">查询</el-button> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column type="index" width="60" label="序号" /> |
| | | <el-table-column prop="droneName" label="无人机名称" /> |
| | | <el-table-column prop="droneType" label="无人机类型" /> |
| | | <el-table-column prop="droneDeviceCode" label="无人机设备编码" /> |
| | | <el-table-column prop="findTime" label="发现时间" /> |
| | | <el-table-column prop="counterEffect" label="反制效果"> |
| | | <template v-slot="{ row }"> |
| | | {{ getDictLabel(row.counterEffect, dictObj.counterEffect) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="deviceName" label="反制设备名称" /> |
| | | <el-table-column prop="deviceModel" label="反制设备型号" /> |
| | | <el-table-column prop="deviceType" label="反制设备类型"> |
| | | <template v-slot="{ row }"> |
| | | {{ getDictLabel(row.deviceType, dictObj.deviceType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="deviceCode" label="反制设备编码" /> |
| | | <el-table-column prop="areaCode" label="场景" /> |
| | | <el-table-column prop="areaCode" label="区域" /> |
| | | <el-table-column label="部署位置"> |
| | | <template v-slot="{ row }"> |
| | | {{ row.deployLongitude && row.deployLatitude ? `${row.deployLongitude}, ${row.deployLatitude}` : '' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="coverRadiusM" label="覆盖范围"> |
| | | <template v-slot="{ row }"> |
| | | {{ row.coverRadiusM ? `${row.coverRadiusM}米` : '' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="workMode" label="工作模式"> |
| | | <template v-slot="{ row }"> |
| | | {{ getWorkModeLabel(row.workMode) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="100"> |
| | | <template v-slot="{ row }"> |
| | | <el-link @click="openForm('view', row)" type="primary">查看</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div> |
| | | <el-pagination |
| | | v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" |
| | | :total="total" |
| | | @change="getList" |
| | | /> |
| | | </div> |
| | | |
| | | <FormDiaLog v-if="dialogVisible" v-model="dialogVisible" ref="dialogRef" /> |
| | | </basic-container> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref, nextTick, provide } from 'vue' |
| | | import { fwEffectEvalPageApi } from './countermeasureEvaluationApi' |
| | | import FormDiaLog from './FormDiaLog.vue' |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import { getDictLabel } from '@ztzf/utils' |
| | | |
| | | // 初始化查询参数 |
| | | const initSearchParams = () => ({ |
| | | deviceName: '', // 设备名称 |
| | | deviceType: '', // 设备类型 |
| | | counterEffect: '', // 反制效果 |
| | | current: 1, // 当前页 |
| | | size: 10, // 每页大小 |
| | | }) |
| | | |
| | | const searchParams = ref(initSearchParams()) // 查询参数 |
| | | const total = ref(0) // 总条数 |
| | | const loading = ref(false) // 列表加载中 |
| | | const list = ref([]) // 列表数据 |
| | | const queryParamsRef = ref(null) // 查询表单实例 |
| | | const dialogRef = ref(null) // 弹框实例 |
| | | const dialogVisible = ref(null) // 弹框显隐 |
| | | const dictObj = ref({ |
| | | deviceType: [], // 设备类型 |
| | | counterEffect: [], // 反制效果 |
| | | }) |
| | | |
| | | // 注入字典和反制效果选项供FormDiaLog使用 |
| | | provide('dictObj', dictObj) |
| | | |
| | | // 获取列表 |
| | | async function getList() { |
| | | loading.value = true |
| | | try { |
| | | const params = { ...searchParams.value } |
| | | const res = await fwEffectEvalPageApi(params) |
| | | list.value = res?.data?.data?.records ?? [] |
| | | total.value = res?.data?.data?.total ?? 0 |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // 查询 |
| | | function handleSearch() { |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 重置查询 |
| | | function resetForm() { |
| | | queryParamsRef.value?.resetFields() |
| | | searchParams.value = initSearchParams() |
| | | getList() |
| | | } |
| | | |
| | | |
| | | // 获取工作模式标签 |
| | | function getWorkModeLabel(value) { |
| | | const map = { '1': '机动', '2': '固定' } |
| | | return map[value] || value |
| | | } |
| | | |
| | | // 获取字典 |
| | | function getDictList() { |
| | | getDictionaryByCode('deviceType,counterEffect').then(res => { |
| | | dictObj.value = res.data.data |
| | | }) |
| | | } |
| | | |
| | | // 查看弹框 |
| | | function openForm(mode, row) { |
| | | dialogVisible.value = true |
| | | nextTick(() => { |
| | | dialogRef.value?.open({ mode, row }) |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | getDictList() |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"></style> |
| File was renamed from applications/drone-command/src/views/detectionCountermeasure/detectionRange.vue |
| | |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import { getDictLabel } from '@ztzf/utils' |
| | | import { detectionRangePageApi, detectionRangeSubmitApi } from '@/api/detectionCountermeasure/detectionRange' |
| | | import DetectionRangeDialog from './components/DetectionRangeDialog.vue' |
| | | import DetectionRangeDialog from './DetectionRangeDialog.vue' |
| | | |
| | | const initSearchParams = () => ({ |
| | | deviceName: '', // 设备名称 |
| New file |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false"> |
| | | <div v-if="readonly"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <div>起始扇区: {{ formData.startSector }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>终止扇区: {{ formData.endSector }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>搜索模式: {{ formData.searchMode }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>雷达频点: {{ formData.radarFreq }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>伺服模式: {{ formData.servoMode }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>伺服数据模式: {{ formData.servoDataMode }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>轴选择: {{ formData.axisSelect }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>伺服转速度: {{ formData.servoTurnSpeed }}</div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="120px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="起始扇区" prop="startSector"> |
| | | <el-input v-model="formData.startSector" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="终止扇区" prop="endSector"> |
| | | <el-input v-model="formData.endSector" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="搜索模式" prop="searchMode"> |
| | | <el-select v-model="formData.searchMode" placeholder="请选择" clearable> |
| | | <el-option v-for="item in searchModeOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="雷达频点" prop="radarFreq"> |
| | | <el-input v-model="formData.radarFreq" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="伺服模式" prop="servoMode"> |
| | | <el-select v-model="formData.servoMode" placeholder="请选择" clearable> |
| | | <el-option v-for="item in servoModeOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="伺服数据模式" prop="servoDataMode"> |
| | | <el-select v-model="formData.servoDataMode" placeholder="请选择" clearable> |
| | | <el-option |
| | | v-for="item in servoDataModeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="轴选择" prop="axisSelect"> |
| | | <el-select v-model="formData.axisSelect" placeholder="请选择" clearable> |
| | | <el-option v-for="item in axisSelectOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="伺服转速度" prop="servoTurnSpeed"> |
| | | <el-input v-model="formData.servoTurnSpeed" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button> |
| | | <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit"> |
| | | 确定 |
| | | </el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { fwDeviceConfigDetailApi, fwDeviceConfigSubmitApi } from './deviceAppConfigApi' |
| | | import { fieldRules } from '@ztzf/utils' |
| | | |
| | | const configKeys = [ |
| | | 'startSector', |
| | | 'endSector', |
| | | 'searchMode', |
| | | 'radarFreq', |
| | | 'servoMode', |
| | | 'servoDataMode', |
| | | 'axisSelect', |
| | | 'servoTurnSpeed', |
| | | ] |
| | | |
| | | // 初始化表单 |
| | | const initForm = () => ({ |
| | | id: '', |
| | | deviceId: '', |
| | | startSector: '', |
| | | endSector: '', |
| | | searchMode: '', |
| | | radarFreq: '', |
| | | servoMode: '', |
| | | servoDataMode: '', |
| | | axisSelect: '', |
| | | servoTurnSpeed: '', |
| | | }) |
| | | |
| | | const emit = defineEmits(['success']) |
| | | const formRef = ref(null) // 表单实例 |
| | | const formData = ref(initForm()) // 表单数据 |
| | | const visible = defineModel() // 弹框显隐 |
| | | const dialogMode = ref('view') // 弹框模式 |
| | | const submitting = ref(false) // 提交中 |
| | | const readonly = computed(() => dialogMode.value === 'view') |
| | | const titleEnum = ref({ edit: '编辑', view: '查看' }) |
| | | |
| | | const searchModeOptions = [ |
| | | { label: '0', value: '0' }, |
| | | { label: '90', value: '90' }, |
| | | { label: '180', value: '180' }, |
| | | ] |
| | | const servoModeOptions = [ |
| | | { label: '周扫', value: '周扫' }, |
| | | { label: '扇区', value: '扇区' }, |
| | | { label: '定位', value: '定位' }, |
| | | ] |
| | | const servoDataModeOptions = [{ label: '编码器', value: '编码器' }] |
| | | const axisSelectOptions = [{ label: '方位', value: '方位' }] |
| | | |
| | | const rules = { |
| | | startSector: fieldRules(true, 50), |
| | | endSector: fieldRules(true, 50), |
| | | searchMode: fieldRules(true), |
| | | radarFreq: fieldRules(true, 50), |
| | | servoMode: fieldRules(true), |
| | | servoDataMode: fieldRules(true), |
| | | axisSelect: fieldRules(true), |
| | | servoTurnSpeed: fieldRules(true, 50), |
| | | } |
| | | |
| | | // 提取配置字段 |
| | | function pickConfigFields(target) { |
| | | return configKeys.reduce((acc, key) => { |
| | | acc[key] = target?.[key] ?? '' |
| | | return acc |
| | | }, {}) |
| | | } |
| | | |
| | | // 关闭弹框 |
| | | function handleCancel() { |
| | | visible.value = false |
| | | } |
| | | |
| | | // 提交更新 |
| | | async function handleSubmit() { |
| | | const isValid = await formRef.value?.validate().catch(() => false) |
| | | if (!isValid) return |
| | | submitting.value = true |
| | | try { |
| | | const configJson = JSON.stringify(pickConfigFields(formData.value)) |
| | | const payload = { ...formData.value, configJson } |
| | | configKeys.forEach(key => { |
| | | delete payload[key] |
| | | }) |
| | | await fwDeviceConfigSubmitApi(payload) |
| | | ElMessage.success('更新成功') |
| | | visible.value = false |
| | | emit('success') |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | |
| | | // 打开弹框 |
| | | async function open({ mode, row } = {}) { |
| | | dialogMode.value = mode || 'view' |
| | | formData.value = { ...initForm(), deviceId: row.id } |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| New file |
| | |
| | | import request from '@/axios' |
| | | |
| | | // 查询详情 |
| | | export const fwDeviceConfigDetailApi = params => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwDeviceConfig/detail`, |
| | | method: 'get', |
| | | params, |
| | | }) |
| | | } |
| | | |
| | | // 提交更新 |
| | | export const fwDeviceConfigSubmitApi = data => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwDeviceConfig/submit`, |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | } |
| New file |
| | |
| | | <template> |
| | | <basic-container> |
| | | <el-form ref="queryParamsRef" :model="searchParams"> |
| | | <el-row :gutter="16"> |
| | | <el-col :span="4"> |
| | | <el-form-item label="设备名称" prop="deviceName"> |
| | | <el-input v-model="searchParams.deviceName" placeholder="请输入" clearable @clear="handleSearch" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="设备类型" prop="deviceType"> |
| | | <el-select v-model="searchParams.deviceType" placeholder="请选择" clearable @change="handleSearch"> |
| | | <el-option |
| | | v-for="item in dictObj.deviceType" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-button @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="handleSearch">查询</el-button> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <el-table v-loading="loading" :data="list"> |
| | | <el-table-column type="index" width="60" label="序号" /> |
| | | <el-table-column prop="deviceType" label="设备类型"> |
| | | <template v-slot="{ row }"> |
| | | {{ getDictLabel(row.deviceType, dictObj.deviceType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="deviceModel" label="设备型号" /> |
| | | <el-table-column prop="deviceName" label="设备名称" /> |
| | | <el-table-column prop="deviceCode" label="设备编码" /> |
| | | <el-table-column prop="deployLocation" label="部署位置" /> |
| | | <el-table-column prop="manufacturer" label="厂商" /> |
| | | <el-table-column prop="contactPhone" label="联系方式" /> |
| | | <el-table-column prop="sceneName" label="所属场景" /> |
| | | <el-table-column label="操作"> |
| | | <template v-slot="{ row }"> |
| | | <el-link @click="openForm('edit', row)" type="warning">配置接口</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div> |
| | | <el-pagination |
| | | v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" |
| | | :total="total" |
| | | @change="getList" |
| | | /> |
| | | </div> |
| | | |
| | | <FormDiaLog v-if="dialogVisible" v-model="dialogVisible" ref="dialogRef" @success="getList" /> |
| | | </basic-container> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { nextTick, onMounted, provide, ref } from 'vue' |
| | | import FormDiaLog from './FormDiaLog.vue' |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import { getDictLabel } from '@ztzf/utils' |
| | | import { fwDevicePageApi } from '@/views/basicManage/deviceStock/fwDevice' |
| | | |
| | | // 初始化查询参数 |
| | | const initSearchParams = () => ({ |
| | | deviceName: '', // 设备名称 |
| | | deviceType: '', // 设备类型 |
| | | current: 1, // 当前页 |
| | | size: 10, // 每页大小 |
| | | }) |
| | | |
| | | const searchParams = ref(initSearchParams()) // 查询参数 |
| | | const total = ref(0) // 总条数 |
| | | const loading = ref(false) // 列表加载中 |
| | | const list = ref([]) // 列表数据 |
| | | const queryParamsRef = ref(null) // 查询表单实例 |
| | | const dialogRef = ref(null) // 弹框实例 |
| | | const dialogVisible = ref(false) |
| | | |
| | | const dictObj = ref({ |
| | | deviceType: [], //设备类型 |
| | | }) |
| | | provide('dictObj', dictObj) |
| | | |
| | | // 获取列表 |
| | | async function getList() { |
| | | loading.value = true |
| | | try { |
| | | const res = await fwDevicePageApi(searchParams.value) |
| | | list.value = res?.data?.data?.records ?? [] |
| | | total.value = res?.data?.data?.total ?? 0 |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // 查询 |
| | | function handleSearch() { |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 重置查询 |
| | | function resetForm() { |
| | | queryParamsRef.value?.resetFields() |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 获取字典 |
| | | function getDictList() { |
| | | getDictionaryByCode('deviceType').then(res => { |
| | | dictObj.value = res.data.data |
| | | }) |
| | | } |
| | | |
| | | // 编辑/查看 弹框 |
| | | function openForm(mode, row) { |
| | | dialogVisible.value = true |
| | | nextTick(() => { |
| | | dialogRef.value?.open({ mode, row }) |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | getDictList() |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"></style> |
| New file |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" :title="titleEnum[dialogMode]"> |
| | | <div v-if="readonly"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <div>设备名称: {{ formData.deviceName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>设备编码: {{ formData.deviceCode }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>设备状态: {{ getDeviceStatusLabel(formData.deviceStatus) }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>场景: {{ formData.defenseSceneName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>区域: {{ formData.areaDivideName }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>调度人员: {{ formData.dispatchUser }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>调度位置: {{ formData.longitude }}, {{ formData.latitude }}</div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div>调度日期: {{ formData.dispatchStartTime }} ~ {{ formData.dispatchEndTime }}</div> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <div>调度内容: {{ formData.dispatchContent }}</div> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <div>调度结果: {{ formData.dispatchResult }}</div> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <div>处理措施: {{ formData.disposeMeasure }}</div> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备名称" prop="deviceId"> |
| | | <el-select v-model="formData.deviceId" placeholder="请选择" clearable @change="handleDeviceChange"> |
| | | <el-option v-for="item in deviceList" :key="item.id" :label="item.deviceName" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备编码" prop="deviceCode"> |
| | | <el-input v-model="formData.deviceCode" disabled placeholder="选择设备后自动带出" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备状态" prop="deviceStatus"> |
| | | <el-input v-model="formData.deviceStatusLabel" disabled placeholder="选择设备后自动带出" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="场景" prop="defenseSceneId"> |
| | | <el-select v-model="formData.defenseSceneId" placeholder="请选择" clearable @change="handleSceneChange"> |
| | | <el-option v-for="item in sceneList" :key="item.id" :label="item.sceneName" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="区域" prop="areaDivideId"> |
| | | <el-select |
| | | v-model="formData.areaDivideId" |
| | | placeholder="请先选择场景" |
| | | clearable |
| | | :disabled="!formData.defenseSceneId" |
| | | > |
| | | <el-option v-for="item in areaList" :key="item.id" :label="item.areaName" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="调度人员" prop="dispatchUser"> |
| | | <el-input v-model="formData.dispatchUser" maxlength="50" placeholder="请输入" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="调度日期" prop="dispatchDateRange"> |
| | | <el-date-picker |
| | | v-model="formData.dispatchDateRange" |
| | | type="datetimerange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="调度位置" prop="longitude"> |
| | | <el-button @click="selectLocation" style="width: 100%"> |
| | | {{ |
| | | formData.longitude && formData.latitude ? `${formData.longitude}, ${formData.latitude}` : '点击选择位置' |
| | | }} |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="调度内容" prop="dispatchContent"> |
| | | <el-input |
| | | v-model="formData.dispatchContent" |
| | | type="textarea" |
| | | :rows="3" |
| | | maxlength="500" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="调度结果" prop="dispatchResult"> |
| | | <el-input |
| | | v-model="formData.dispatchResult" |
| | | type="textarea" |
| | | :rows="3" |
| | | maxlength="500" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="处理措施" prop="disposeMeasure"> |
| | | <el-input |
| | | v-model="formData.disposeMeasure" |
| | | type="textarea" |
| | | :rows="3" |
| | | maxlength="500" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button> |
| | | <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit"> |
| | | 确定 |
| | | </el-button> |
| | | </template> |
| | | |
| | | <el-dialog v-model="visible1" title="选择位置" destroy-on-close @closed="positionClosed"> |
| | | <div class="ztzf-cesium" id="mapContainer"></div> |
| | | <template #footer> |
| | | <el-button @click="handleMapCancel">取消</el-button> |
| | | <el-button type="primary" @click="handleMapConfirm">确定</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, nextTick, ref, inject } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { fwTaskScheduleDetailApi, fwTaskScheduleSubmitApi } from './taskScheduleApi' |
| | | import { fwAreaDivideListApi } from '@/views/areaManage/partition/partitionApi' |
| | | import { fieldRules } from '@ztzf/utils' |
| | | import { PublicCesium } from '@/utils/cesium/publicCesium' |
| | | import * as Cesium from 'cesium' |
| | | |
| | | // 初始化表单 |
| | | const initForm = () => ({ |
| | | deviceId: '', // 设备ID |
| | | deviceCode: '', // 设备编码 |
| | | deviceName: '', // 设备名称 |
| | | deviceStatus: '', // 设备状态 |
| | | deviceStatusLabel: '', // 设备状态标签 |
| | | defenseSceneId: '', // 场景ID |
| | | defenseSceneName: '', // 场景名称 |
| | | areaDivideId: '', // 区域ID |
| | | areaDivideName: '', // 区域名称 |
| | | areaCode: '', // 区域编码 |
| | | dispatchUser: '', // 调度人员 |
| | | dispatchStartTime: '', // 调度开始时间 |
| | | dispatchEndTime: '', // 调度结束时间 |
| | | dispatchDateRange: [], // 调度日期范围 |
| | | dispatchContent: '', // 调度内容 |
| | | dispatchResult: '', // 调度结果 |
| | | disposeMeasure: '', // 处理措施 |
| | | longitude: null, // 经度 |
| | | latitude: null, // 纬度 |
| | | }) |
| | | |
| | | const props = defineProps({ |
| | | sceneList: { type: Array, default: () => [] }, |
| | | deviceList: { type: Array, default: () => [] }, |
| | | }) |
| | | |
| | | // 注入字典数据 |
| | | const dictObj = inject('dictObj') |
| | | |
| | | const emit = defineEmits(['success']) |
| | | const formRef = ref(null) // 表单实例 |
| | | const formData = ref(initForm()) // 表单数据 |
| | | const visible = defineModel() // 弹框显隐 |
| | | const visible1 = ref(false) // 地图弹框显隐 |
| | | const dialogMode = ref('add') // 弹框模式 |
| | | const submitting = ref(false) // 提交中 |
| | | const readonly = computed(() => dialogMode.value === 'view') |
| | | const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' }) |
| | | const tempLocation = ref({ longitude: null, latitude: null }) |
| | | const areaList = ref([]) // 区域列表 |
| | | |
| | | const rules = { |
| | | deviceId: [{ required: true, message: '请选择设备', trigger: 'change' }], |
| | | defenseSceneId: [{ required: true, message: '请选择场景', trigger: 'change' }], |
| | | areaDivideId: [{ required: true, message: '请选择区域', trigger: 'change' }], |
| | | dispatchUser: fieldRules(true, 50), |
| | | } |
| | | |
| | | // 获取设备状态标签 |
| | | function getDeviceStatusLabel(status) { |
| | | const statusMap = { 0: '离线', 1: '在线' } |
| | | return statusMap[status] || status |
| | | } |
| | | |
| | | // 设备选择变化处理 |
| | | function handleDeviceChange(deviceId) { |
| | | const device = props.deviceList.find(item => item.id === deviceId) |
| | | if (device) { |
| | | formData.value.deviceName = device.deviceName |
| | | formData.value.deviceCode = device.deviceCode |
| | | formData.value.deviceStatus = device.deviceStatus |
| | | formData.value.deviceStatusLabel = getDeviceStatusLabel(device.deviceStatus) |
| | | } else { |
| | | formData.value.deviceName = '' |
| | | formData.value.deviceCode = '' |
| | | formData.value.deviceStatus = '' |
| | | formData.value.deviceStatusLabel = '' |
| | | } |
| | | } |
| | | |
| | | // 场景选择变化处理 |
| | | async function handleSceneChange(sceneId) { |
| | | formData.value.areaDivideId = '' |
| | | if (sceneId) { |
| | | await loadAreaList(sceneId) |
| | | } else { |
| | | areaList.value = [] |
| | | } |
| | | } |
| | | |
| | | // 加载区域列表 |
| | | async function loadAreaList(sceneId) { |
| | | const res = await fwAreaDivideListApi({ sceneId }) |
| | | areaList.value = res?.data?.data ?? [] |
| | | } |
| | | |
| | | // 关闭弹框 |
| | | function handleCancel() { |
| | | visible.value = false |
| | | } |
| | | |
| | | // 提交新增/编辑 |
| | | async function handleSubmit() { |
| | | const isValid = await formRef.value?.validate().catch(() => false) |
| | | if (!isValid) return |
| | | submitting.value = true |
| | | try { |
| | | // 处理调度日期 |
| | | if (formData.value.dispatchDateRange?.length === 2) { |
| | | formData.value.dispatchStartTime = formData.value.dispatchDateRange[0] |
| | | formData.value.dispatchEndTime = formData.value.dispatchDateRange[1] |
| | | } |
| | | await fwTaskScheduleSubmitApi(formData.value) |
| | | ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功') |
| | | visible.value = false |
| | | emit('success') |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | |
| | | // 加载详情 |
| | | async function loadDetail() { |
| | | if (!formData.value.id) return |
| | | const res = await fwTaskScheduleDetailApi({ id: formData.value.id }) |
| | | const data = res?.data?.data ?? {} |
| | | formData.value = { |
| | | ...data, |
| | | deviceStatusLabel: getDeviceStatusLabel(data.deviceStatus), |
| | | dispatchDateRange: |
| | | data.dispatchStartTime && data.dispatchEndTime ? [data.dispatchStartTime, data.dispatchEndTime] : [], |
| | | } |
| | | // 如果有场景ID,加载区域列表 |
| | | if (data.defenseSceneId) { |
| | | await loadAreaList(data.defenseSceneId) |
| | | } |
| | | } |
| | | |
| | | // 左键点击事件处理 |
| | | function LeftClickEvent(click) { |
| | | const pos = click.position |
| | | const cartesian3 = viewer.camera.pickEllipsoid(pos, viewer.scene.globe.ellipsoid) |
| | | if (!cartesian3) { |
| | | return { longitude: 112, latitude: 23 } |
| | | } |
| | | const carto = Cesium.Cartographic.fromCartesian(cartesian3) |
| | | const longitude = Cesium.Math.toDegrees(carto.longitude) |
| | | const latitude = Cesium.Math.toDegrees(carto.latitude) |
| | | tempLocation.value = { longitude, latitude } |
| | | // 添加红点并渲染经纬度标签 |
| | | if (!redPointEntity) { |
| | | redPointEntity = viewer.entities.add({ |
| | | position: Cesium.Cartesian3.fromDegrees(longitude, latitude), |
| | | point: { |
| | | color: Cesium.Color.RED, |
| | | pixelSize: 10, |
| | | }, |
| | | label: { |
| | | text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`, |
| | | font: '14px', |
| | | fillColor: Cesium.Color.WHITE, |
| | | backgroundColor: Cesium.Color.BLACK.withAlpha(0.45), |
| | | backgroundPadding: new Cesium.Cartesian2(5, 5), |
| | | pixelOffset: new Cesium.Cartesian2(0, -20), |
| | | showBackground: true, |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | horizontalOrigin: Cesium.HorizontalOrigin.CENTER, |
| | | verticalOrigin: Cesium.VerticalOrigin.CENTER, |
| | | outlineWidth: 1, |
| | | outlineColor: Cesium.Color.WHITE, |
| | | eyeOffset: new Cesium.Cartesian3(0, 0, -20), |
| | | }, |
| | | }) |
| | | } else { |
| | | redPointEntity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude) |
| | | redPointEntity.label.text = `${longitude.toFixed(6)}, ${latitude.toFixed(6)}` |
| | | } |
| | | } |
| | | |
| | | // 地图弹框关闭处理 |
| | | function positionClosed() { |
| | | redPointEntity = null |
| | | } |
| | | |
| | | let viewer |
| | | let redPointEntity |
| | | |
| | | // 选择位置 |
| | | async function selectLocation() { |
| | | visible1.value = true |
| | | await nextTick() |
| | | const publicCesiumInstance = new PublicCesium({ |
| | | dom: 'mapContainer', |
| | | flatMode: false, |
| | | terrain: true, |
| | | layerMode: 4, |
| | | boundary: false, |
| | | }) |
| | | publicCesiumInstance.addLeftClickEvent(null, LeftClickEvent) |
| | | viewer = publicCesiumInstance.getViewer() |
| | | } |
| | | |
| | | // 地图取消 |
| | | function handleMapCancel() { |
| | | tempLocation.value = { longitude: null, latitude: null } |
| | | visible1.value = false |
| | | } |
| | | |
| | | // 地图确认 |
| | | function handleMapConfirm() { |
| | | if (tempLocation.value.longitude != null && tempLocation.value.latitude != null) { |
| | | formData.value.longitude = _.round(tempLocation.value.longitude, 6) |
| | | formData.value.latitude = _.round(tempLocation.value.latitude, 6) |
| | | } |
| | | visible1.value = false |
| | | } |
| | | |
| | | // 打开弹框 |
| | | async function open({ mode, row } = {}) { |
| | | dialogMode.value = mode || 'add' |
| | | formData.value = dialogMode.value === 'add' ? initForm() : { ...row } |
| | | if (dialogMode.value !== 'add') { |
| | | await loadDetail() |
| | | } |
| | | } |
| | | |
| | | defineExpose({ open }) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | #mapContainer { |
| | | width: 100%; |
| | | height: 500px; |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <basic-container> |
| | | <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search"> |
| | | <el-form-item label="设备名称" prop="deviceId"> |
| | | <el-select |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.deviceId" |
| | | placeholder="请选择" |
| | | clearable |
| | | @clear="handleSearch" |
| | | @change="handleSearch" |
| | | > |
| | | <el-option v-for="item in deviceList" :key="item.id" :label="item.deviceName" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="设备类型" prop="deviceType"> |
| | | <el-select |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.deviceType" |
| | | placeholder="请选择" |
| | | clearable |
| | | @clear="handleSearch" |
| | | @change="handleSearch" |
| | | > |
| | | <el-option |
| | | v-for="item in dictObj.deviceType" |
| | | :key="item.dictKey" |
| | | :label="item.dictValue" |
| | | :value="item.dictKey" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="设备编号" prop="deviceCode"> |
| | | <el-input |
| | | class="ztzf-data-cockpit-search-input" |
| | | v-model="searchParams.deviceCode" |
| | | placeholder="请输入" |
| | | clearable |
| | | @clear="handleSearch" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item class="history-search-actions"> |
| | | <el-button :icon="RefreshRight" @click="resetForm"></el-button> |
| | | <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="ztzf-table-toolbar"> |
| | | <el-button :icon="Plus" color="#284FE3" type="primary" @click="openForm('add')">新增</el-button> |
| | | <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button> |
| | | </div> |
| | | |
| | | <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)"> |
| | | <div class="ztzf-table-content ztzf-table-content-bg"> |
| | | <el-table class="ztzf-data-cockpit-table" :data="list" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="46" /> |
| | | <el-table-column type="index" show-overflow-tooltip width="64" label="序号" /> |
| | | <el-table-column prop="deviceName" show-overflow-tooltip width="140" label="设备名称" /> |
| | | <el-table-column prop="deviceCode" show-overflow-tooltip width="140" label="设备编码" /> |
| | | <el-table-column prop="deviceStatus" show-overflow-tooltip width="100" label="设备状态"> |
| | | <template v-slot="{ row }"> |
| | | {{ getDictLabel(row.deviceStatus, dictObj.deviceStatus) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="areaDivideName" show-overflow-tooltip width="120" label="区域" /> |
| | | <el-table-column prop="defenseSceneName" show-overflow-tooltip width="120" label="场景" /> |
| | | <el-table-column show-overflow-tooltip width="200" label="调度位置"> |
| | | <template v-slot="{ row }">{{ row.longitude }}, {{ row.latitude }}</template> |
| | | </el-table-column> |
| | | <el-table-column prop="dispatchUser" show-overflow-tooltip width="100" label="调度人员" /> |
| | | <el-table-column show-overflow-tooltip width="180" label="调度日期"> |
| | | <template v-slot="{ row }"> |
| | | {{ formatDispatchDate(row) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="dispatchContent" show-overflow-tooltip width="160" label="调度内容" /> |
| | | <el-table-column prop="dispatchResult" show-overflow-tooltip width="160" label="调度结果" /> |
| | | <el-table-column prop="disposeMeasure" show-overflow-tooltip width="160" label="处理措施" /> |
| | | <!-- <el-table-column label="操作" class-name="operation-btns" fixed="right" width="120"> |
| | | <template v-slot="{ row }"> |
| | | <el-link @click="openForm('edit', row)">编辑</el-link> |
| | | <el-link @click="handleDelete(row)">删除</el-link> |
| | | </template> |
| | | </el-table-column>--> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <div class="ztzf-table-pagination"> |
| | | <el-pagination |
| | | popper-class="ztzf-data-cockpit-select-popper" |
| | | v-model:current-page="searchParams.current" |
| | | v-model:page-size="searchParams.size" |
| | | layout="total, prev, pager, next, sizes" |
| | | :total="total" |
| | | @change="getList" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <FormDiaLog |
| | | ref="dialogRef" |
| | | @success="getList" |
| | | v-if="dialogVisible" |
| | | v-model="dialogVisible" |
| | | :sceneList="sceneList" |
| | | :deviceList="deviceList" |
| | | /> |
| | | </basic-container> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Search, RefreshRight, Plus } from '@element-plus/icons-vue' |
| | | import { nextTick, onMounted, ref, provide } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { fwTaskSchedulePageApi, fwTaskScheduleRemoveApi } from './taskScheduleApi' |
| | | import { fwDefenseSceneListApi } from '@/views/areaManage/sceneConfig/sceneConfigApi' |
| | | import { fwDeviceListApi } from '@/views/basicManage/deviceStock/fwDevice' |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import FormDiaLog from './FormDiaLog.vue' |
| | | import { getDictLabel } from '@ztzf/utils' |
| | | |
| | | // 初始化查询参数 |
| | | const initSearchParams = () => ({ |
| | | deviceId: '', // 设备名称 |
| | | deviceType: '', // 设备类型 |
| | | deviceCode: '', // 设备编号 |
| | | current: 1, // 当前页 |
| | | size: 10, // 每页大小 |
| | | }) |
| | | const searchParams = ref(initSearchParams()) // 查询参数 |
| | | const total = ref(0) // 总条数 |
| | | const loading = ref(false) // 列表加载中 |
| | | const list = ref([]) // 列表数据 |
| | | const selectedIds = ref([]) // 勾选的ID列表 |
| | | const queryParamsRef = ref(null) // 查询表单实例 |
| | | const dialogRef = ref(null) // 弹框实例 |
| | | const dialogVisible = ref(false) |
| | | const dictObj = ref({ |
| | | deviceType: [], // 设备类型 |
| | | deviceStatus: [], // 设备状态 |
| | | }) |
| | | const sceneList = ref([]) // 场景列表 |
| | | const deviceList = ref([]) // 设备列表 |
| | | |
| | | // 注入字典到子组件 |
| | | provide('dictObj', dictObj) |
| | | |
| | | // 格式化调度日期 |
| | | function formatDispatchDate(row) { |
| | | if (row.dispatchStartTime && row.dispatchEndTime) { |
| | | return `${row.dispatchStartTime} ~ ${row.dispatchEndTime}` |
| | | } |
| | | return row.dispatchStartTime || row.dispatchEndTime || '' |
| | | } |
| | | |
| | | // 获取列表 |
| | | async function getList() { |
| | | loading.value = true |
| | | try { |
| | | const res = await fwTaskSchedulePageApi(searchParams.value) |
| | | list.value = res?.data?.data?.records ?? [] |
| | | total.value = res?.data?.data?.total ?? 0 |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // 查询 |
| | | function handleSearch() { |
| | | searchParams.value.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 重置查询 |
| | | function resetForm() { |
| | | queryParamsRef.value?.resetFields() |
| | | searchParams.value = initSearchParams() |
| | | getList() |
| | | } |
| | | |
| | | // 删除 |
| | | async function handleDelete(row) { |
| | | const tips = row ? '该条' : '选中的项' |
| | | await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', { type: 'warning' }) |
| | | const ids = row ? row.id : selectedIds.value.join(',') |
| | | await fwTaskScheduleRemoveApi({ ids }) |
| | | ElMessage.success('删除成功') |
| | | selectedIds.value = [] |
| | | getList() |
| | | } |
| | | |
| | | // 勾选值设置 |
| | | function handleSelectionChange(rows) { |
| | | selectedIds.value = rows.map(item => item.id) |
| | | } |
| | | |
| | | // 新增/编辑 |
| | | function openForm(mode, row) { |
| | | dialogVisible.value = true |
| | | nextTick(() => { |
| | | dialogRef.value?.open({ mode, row }) |
| | | }) |
| | | } |
| | | |
| | | // 加载字典数据 |
| | | function getDictList() { |
| | | getDictionaryByCode('deviceType,deviceStatus').then(res => { |
| | | dictObj.value = res.data.data |
| | | }) |
| | | } |
| | | |
| | | // 加载场景列表 |
| | | async function loadSceneList() { |
| | | const res = await fwDefenseSceneListApi() |
| | | sceneList.value = res?.data?.data ?? [] |
| | | } |
| | | |
| | | // 加载设备列表 |
| | | async function loadDeviceList() { |
| | | const res = await fwDeviceListApi() |
| | | deviceList.value = res?.data?.data ?? [] |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getDictList() |
| | | loadSceneList() |
| | | loadDeviceList() |
| | | getList() |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"></style> |
| New file |
| | |
| | | import request from '@/axios' |
| | | |
| | | // 分页查询任务调度列表 |
| | | export const fwTaskSchedulePageApi = params => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwTaskSchedule/page`, |
| | | method: 'get', |
| | | params, |
| | | }) |
| | | } |
| | | |
| | | // 查询任务调度详情 |
| | | export const fwTaskScheduleDetailApi = params => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwTaskSchedule/detail`, |
| | | method: 'get', |
| | | params, |
| | | }) |
| | | } |
| | | |
| | | // 新增或修改任务调度 |
| | | export const fwTaskScheduleSubmitApi = data => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwTaskSchedule/submit`, |
| | | method: 'post', |
| | | data, |
| | | }) |
| | | } |
| | | |
| | | // 逻辑删除任务调度 |
| | | export const fwTaskScheduleRemoveApi = params => { |
| | | return request({ |
| | | url: `/drone-fw/detection/fwTaskSchedule/remove`, |
| | | method: 'post', |
| | | params, |
| | | }) |
| | | } |
| | |
| | | {{ getDeviceTypeName(row.droneType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="deviceCode" label="设备编码" /> |
| | | <el-table-column prop="deviceSn" label="设备编码" /> |
| | | <el-table-column label="设备状态"> |
| | | <template v-slot="{ row }"> |
| | | {{ getDeviceStatus(row) }} |
| | | {{ getDictLabel(row.deviceStatus, dictObj.deviceStatus) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | import { getDictionaryByCode } from '@/api/system/dictbiz' |
| | | import { exportFwDroneAlarmRecordApi, fwDroneAlarmRecordPageApi } from './fwDroneAlarmRecord' |
| | | import FormDiaLog from './FormDiaLog.vue' |
| | | import { blobDownload, dateRangeFormat } from '@ztzf/utils' |
| | | import { blobDownload, dateRangeFormat, getDictLabel } from '@ztzf/utils' |
| | | |
| | | const initSearchParams = () => ({ |
| | | droneName: '', // 无人机名称 |
| | |
| | | getList() |
| | | } |
| | | |
| | | // 查看 |
| | | function handleView(row) { |
| | | dialogRef.value?.open({ mode: 'view', row: { ...row } }) |
| | | } |
| | | |
| | | function exportFile() { |
| | | exportLoading.value = true |
| | | exportFwDroneAlarmRecordApi() |
| | |
| | | }) |
| | | } |
| | | |
| | | function getDeviceStatus(row) { |
| | | return row.deviceStatus ?? row.status ?? '-' |
| | | } |
| | | |
| | | function getDeviceTypeName(value) { |
| | | return deviceTypeMap.value.get(value) || value || '-' |
| | | } |
| | | |
| | | // 获取字典 |
| | | function getDictList() { |
| | | getDictionaryByCode('deviceType').then(res => { |
| | | getDictionaryByCode('deviceType,deviceStatus').then(res => { |
| | | dictObj.value = res.data.data |
| | | }) |
| | | } |
| | |
| | | <template> |
| | | <div class="page-container"> |
| | | <div class="map" id="map"></div> |
| | | |
| | | <div class="weather-box" v-show="weatherShow"> |
| | | <div class="icon"> |
| | | <van-image :src="WEATHER?.[weather] || ''" width="100%" height="100%"></van-image> |
| | | </div> |
| | | |
| | | <div class="content"> |
| | | <span class="tq">{{ weather }} {{ temperature }}</span> |
| | | <span class="tq">风速:{{ windVelocity }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="back-btn" @click="goBackWork" v-show="workNavigationShow"> |
| | | <van-image width="20" height="20" :src="backIcon" /> |
| | | <div class="label">返回</div> |
| | | </div> |
| | | <div class="layer-btn" @click="layerChangePopupShow = true" v-show="layerShow"> |
| | | <van-image width="20" height="20" :src="layerIcon" /> |
| | | <div class="label">图层</div> |
| | | </div> |
| | | |
| | | <div class="location-btn" @click="setMapLocation" v-show="locationShow"> |
| | | <van-image width="20" height="20" :src="locationIcon" /> |
| | | <div class="label">定位</div> |
| | | </div> |
| | | <!-- 事件导航按钮 --> |
| | | <div class="work-btn" v-show="workNavigationShow"> |
| | | <van-button round block type="primary" color="#1D6FE9" @click="openAmap">事件导航</van-button> |
| | | </div> |
| | | <slot name="searchBar"></slot> |
| | | <slot name="eventNav"></slot> |
| | | |
| | | <van-popup v-model:show="layerChangePopupShow" position="bottom" round> |
| | | <div class="popup-container"> |
| | | <div class="category-content"> |
| | | <div class="header"> |
| | | <div class="title">底图切换</div> |
| | | </div> |
| | | |
| | | <div class="content"> |
| | | <div |
| | | class="layer-box" |
| | | :class="{ on: setSelectMapLayerKey === item.key }" |
| | | v-for="(item, ind) in layers" |
| | | :key="ind" |
| | | @click="setMapLayer(item)" |
| | | > |
| | | <div class="image"> |
| | | <van-image :src="item.src" width="100%" height="100%"></van-image> |
| | | </div> |
| | | <div class="label">{{ item.name }}</div> |
| | | </div> |
| | | </div> |
| | | <div class="location-btn" @click="setMapLocation" v-show="locationShow"> |
| | | <van-image width="20" height="20" :src="locationIcon" /> |
| | | <div class="label">定位</div> |
| | | </div> |
| | | </div> |
| | | </van-popup> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { searchGeocoder } from '@/utils/util' |
| | | import mapnavIcon from '@/appDataSource/appwork/mapnav.svg' |
| | | import backIcon from '@/appDataSource/leafletMapIcon/back-icon.svg' |
| | | import incidentPoint from '@/appDataSource/appwork/positioning.svg' |
| | | import droneIcon from '@/appDataSource/leafletMapIcon/drone-icon.svg' |
| | | import incidentPoint from '@/appDataSource/appwork/positioning1.svg' |
| | | import userLocationIcon from '@/appDataSource/leafletMapIcon/user-location.svg' |
| | | import layerIcon from '@/appDataSource/leafletMapIcon/layer-icon.svg' |
| | | import locationIcon from '@/appDataSource/leafletMapIcon/location-icon.svg' |
| | | import { useStore } from 'vuex' |
| | | import { getDroneSuggest } from '@/api/home/common' |
| | | import DroneMarkerPopup from '@/appComponents/DroneMarkerPopup/index.vue' |
| | | import EventMarkerPopup from '@/appComponents/EventMarkerPopup/index.vue' |
| | | import { basemapLayer0, basemapLayer1, basemapLayer2, basemapLayer3 } from '@/const/leafletConst' |
| | | |
| | | import L from 'leaflet' |
| | |
| | | import sl from '@/appDataSource/leafletMapIcon/sl.svg' |
| | | import yx from '@/appDataSource/leafletMapIcon/yx.svg' |
| | | import EventBus from '@/utils/eventBus' |
| | | import { polygonTransformScale } from '@/utils/turfFunc' |
| | | import { getEventImage } from '@/utils/stateToImageMap/event' |
| | | import { getDroneStatusImage } from '@/utils/stateToImageMap/drone' |
| | | import { WEATHER } from '@/const/weather' |
| | | |
| | | import { wgs84ToGcj02 } from '@/utils/coordinateTransformation' |
| | | const emit = defineEmits(['location-selected']) |
| | | import _ from 'lodash' |
| | | import { useAreaBoundary } from '@/hooks/useAreaBoundary' |
| | | const { weatherShow, layerShow, locationShow, createWorkShow, workNavigationShow, mapCurrentDetail, clearMarker } = |
| | | const { locationShow, createWorkShow, workNavigationShow, mapCurrentDetail, clearMarker } = |
| | | defineProps({ |
| | | weatherShow: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | layerShow: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | locationShow: { |
| | | type: Boolean, |
| | | default: false, |
| | |
| | | }, |
| | | ] |
| | | |
| | | const layerChangePopupShow = ref(false) |
| | | const setSelectMapLayerKey = ref(1) // 选择的地图图层 |
| | | let boundaryInstance = useAreaBoundary({ initFly: true }) |
| | | let markersLayer = null |
| | | const initMap = () => { |
| | | if (map) return |
| | |
| | | doubleClickZoom: false, |
| | | editable: true, //绘制控件 |
| | | }).setView([25.992338, 114.823254], 13) |
| | | boundaryInstance.initBoundary(map) |
| | | |
| | | markersLayer = L.layerGroup().addTo(map) // 创建一个标注层,便于管理和移除 |
| | | if (createWorkShow) { |
| | |
| | | const store = useStore() |
| | | const selectedAreaCode = computed(() => store.state.user.selectedAreaCode) |
| | | |
| | | const weather = ref('') |
| | | // 风速 |
| | | const windVelocity = ref('') |
| | | const temperature = ref('') |
| | | // 获取天气建议 |
| | | const getWeatherSuggest = () => { |
| | | getDroneSuggest({ areaCode: selectedAreaCode.value }).then(res => { |
| | | if (res.data.code !== 0) return |
| | | weather.value = res.data.data.weather |
| | | windVelocity.value = res.data.data.windPower |
| | | temperature.value = res.data.data.temperature |
| | | }) |
| | | } |
| | | const goBackWork = () => { |
| | | const transmitData = { data: { type: 'workDetailback' } } |
| | | wx.miniProgram.navigateBack({ |
| | | delta: 1, |
| | | }) |
| | | wx.miniProgram.postMessage(transmitData) |
| | | uni.postMessage(transmitData) |
| | | |
| | | markersLayer.removeLayer(incidentMarker) |
| | | } |
| | | // 存储事件点标记实例,用于后续更新或移除 |
| | | let incidentMarker = null |
| | | |
| | |
| | | { immediate: true, deep: true } |
| | | ) |
| | | |
| | | const openAmap = () => { |
| | | if (!mapCurrentDetailData.value.longitude || !mapCurrentDetailData.value.latitude) { |
| | | showToast('未获取到事件坐标') |
| | | return |
| | | } |
| | | // wgs84ToGcj02(Number(item.longitude), Number(item.latitude)) |
| | | // wgs84ToGcj02(mapCurrentDetailData.value.longitude, mapCurrentDetailData.value.latitude) |
| | | const [gcjLng, gcjLat] = wgs84ToGcj02( |
| | | Number(mapCurrentDetailData.value.longitude), |
| | | Number(mapCurrentDetailData.value.latitude) |
| | | ) |
| | | |
| | | // 高德地图URL Scheme |
| | | const url = `https://uri.amap.com/marker?position=${gcjLng},${gcjLat}&name=%E4%BA%8B%E4%BB%B6%E7%82%B9&from='ztzf'` |
| | | |
| | | const transmitData = { data: { type: 'browser', data: { url: url } } } |
| | | wx.miniProgram.navigateTo({ url: `/subPackages/browser/index?url=${encodeURIComponent(url)}` }) |
| | | wx.miniProgram.postMessage(transmitData) |
| | | uni.postMessage(transmitData) |
| | | } |
| | | onMounted(async () => { |
| | | getWeatherSuggest() |
| | | |
| | | await nextTick() |
| | | initMap() |
| | |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | // 事件导航按钮 |
| | | .work-btn { |
| | | position: absolute; |
| | | bottom: 80px; |
| | | left: 0; |
| | | right: 0; |
| | | z-index: 996; |
| | | padding: 0 16px; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .work-btn :deep(.van-button) { |
| | | width: 100%; |
| | | max-width: 194px; |
| | | height: 38px; |
| | | } |
| | | |
| | | .weather-box { |
| | | padding: 4px 0; |
| | | padding-right: 6px; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | position: absolute; |
| | | top: 12px; |
| | | left: 12px; |
| | | |
| | | height: 48px; |
| | | background: #fff; |
| | | z-index: 996; |
| | | |
| | | box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.18); |
| | | border-radius: 6px 6px 6px 6px; |
| | | |
| | | .icon { |
| | | margin-left: 10px; |
| | | width: 24px; |
| | | height: 24px; |
| | | } |
| | | |
| | | .content { |
| | | height: 100%; |
| | | margin-left: 4px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-around; |
| | | |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #757575; |
| | | text-align: left; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | } |
| | | |
| | | .tq { |
| | | margin: 0 5px; |
| | | } |
| | | .qk { |
| | | margin-left: 5px; |
| | | color: #04f043; |
| | | } |
| | | .yellowqk { |
| | | margin-left: 5px; |
| | | color: yellow; |
| | | } |
| | | .redqk { |
| | | margin-left: 5px; |
| | | color: red; |
| | | } |
| | | } |
| | | |
| | | .location-btn, |
| | | .layer-btn, |
| | | .back-btn { |
| | | .location-btn{ |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | |
| | | font-size: 10px; |
| | | } |
| | | } |
| | | .back-btn { |
| | | bottom: 185px; |
| | | } |
| | | .layer-btn { |
| | | bottom: 130px; |
| | | } |
| | | |
| | | .location-btn { |
| | | bottom: 76px; |
| | | } |
| | | } |
| | | |
| | | .popup-container { |
| | | padding: 10px 22px; |
| | | background: #fff; |
| | | border-radius: 12px 12px 0 0; |
| | | |
| | | .category-content { |
| | | .header { |
| | | height: 20px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | color: #222324; |
| | | line-height: 20px; |
| | | text-align: left; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | } |
| | | |
| | | .content { |
| | | padding: 12px; |
| | | display: flex; |
| | | background: #fff; |
| | | border-radius: 16px; |
| | | |
| | | .layer-box { |
| | | margin-left: calc((100% / 3 - 84px) * 3 / 2); |
| | | |
| | | &:first-child { |
| | | margin-left: 0; |
| | | } |
| | | |
| | | &.on { |
| | | .image { |
| | | position: relative; |
| | | |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | border-radius: 4px 4px 4px 4px; |
| | | border: 4px solid #1d6fe9; |
| | | z-index: 1; |
| | | box-sizing: border-box; |
| | | } |
| | | } |
| | | |
| | | .label { |
| | | color: #1d6fe9; |
| | | } |
| | | } |
| | | |
| | | .image { |
| | | width: 84px; |
| | | height: 82px; |
| | | border-radius: 4px 4px 4px 4px; |
| | | overflow: hidden; |
| | | box-sizing: border-box; |
| | | border: none; |
| | | } |
| | | |
| | | .label { |
| | | margin-top: 6px; |
| | | height: 20px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #222324; |
| | | line-height: 20px; |
| | | text-align: center; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | } |
| | | } |
| | | |
| | | .layer-box:nth-child(3n + 1) { |
| | | margin-left: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <g id="Frame" clip-path="url(#clip0_109_1462)"> |
| | | <path id="Vector" d="M11.9166 19.4328C9.73119 19.1548 7.73368 18.055 6.33004 16.357C4.9264 14.659 4.22197 12.4903 4.35992 10.2916C4.49788 8.09294 5.46786 6.02927 7.07273 4.52007C8.67759 3.01087 10.7969 2.16939 12.9999 2.16666C15.2056 2.16502 17.329 3.00444 18.9373 4.51389C20.5456 6.02334 21.5179 8.08923 21.656 10.2906C21.7942 12.492 21.0877 14.6632 19.6807 16.3619C18.2736 18.0605 16.2719 19.1588 14.0833 19.4328V21.6797C18.3581 21.7793 21.6666 22.4629 21.6666 23.2917C21.6666 24.1887 17.7861 24.9167 12.9999 24.9167C8.21375 24.9167 4.33325 24.1887 4.33325 23.2917C4.33325 22.4629 7.64175 21.7793 11.9166 21.6797V19.4328ZM12.9999 13C13.5746 13 14.1257 12.7717 14.532 12.3654C14.9383 11.9591 15.1666 11.408 15.1666 10.8333C15.1666 10.2587 14.9383 9.70759 14.532 9.30126C14.1257 8.89493 13.5746 8.66666 12.9999 8.66666C12.4253 8.66666 11.8742 8.89493 11.4679 9.30126C11.0615 9.70759 10.8333 10.2587 10.8333 10.8333C10.8333 11.408 11.0615 11.9591 11.4679 12.3654C11.8742 12.7717 12.4253 13 12.9999 13Z" fill="#FF2121"/> |
| | | </g> |
| | | <defs> |
| | | <clipPath id="clip0_109_1462"> |
| | | <rect width="26" height="26" fill="white"/> |
| | | </clipPath> |
| | | </defs> |
| | | </svg> |
| | |
| | | <template> |
| | | <div class="wrapper" :style="{ paddingTop: route.query.topMargin + 'px' }"> |
| | | <div class="wrapper" > |
| | | <WorkMap |
| | | :weatherShow="true" |
| | | :layerShow="true" |
| | |
| | | :workNavigationShow="true" |
| | | :mapCurrentDetail="mapCurrentDetail" |
| | | > |
| | | <template #eventNav> |
| | | <EventNavigation :mapCurrentDetail="mapCurrentDetail"></EventNavigation> |
| | | </template> |
| | | <!-- <template #eventNav>--> |
| | | <!-- <EventNavigation :mapCurrentDetail="mapCurrentDetail"></EventNavigation>--> |
| | | <!-- </template>--> |
| | | </WorkMap> |
| | | </div> |
| | | </template> |
| | |
| | | const store = useStore() |
| | | const userInfo = computed(() => store?.state?.user?.userInfo) |
| | | const route = useRoute() |
| | | const mapCurrentDetail = ref({}) |
| | | const mapCurrentDetail = ref({ |
| | | "id": 8474, |
| | | "wayline_job_id": "51835088-cd94-42f8-b2ec-a9069ced4e7b", |
| | | "event_name": "测试", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "file_path": "upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "longitude": "115.85649472222222", |
| | | "latitude": "28.624301527777778", |
| | | "create_time": "2026-01-13 16:51:57", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260113002", |
| | | "ai_types": "道路裂缝", |
| | | "ai_type_key_list": [ |
| | | "DLLFSB" |
| | | ], |
| | | "work_order_type_dict_key": "ZHZLL", |
| | | "work_order_type": "交通运输与交管", |
| | | "create_user": "曾超杰", |
| | | "update_user": "管理员", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "2009140684346388482", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1123598821738675201", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1806号南昌台湾健康产业城", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "content": "测试", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照2", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-13 16:51:57" |
| | | }) |
| | | const eventNum = ref('') |
| | | // 机巢数据 |
| | | let machineData = ref([]); |
| | |
| | | } |
| | | } |
| | | onMounted(async () => { |
| | | handleNodeClick() |
| | | // handleNodeClick() |
| | | eventNum.value = route.query.currentItem |
| | | await getDataList(eventNum.value) |
| | | // await getDataList(eventNum.value) |
| | | }) |
| | | </script> |
| | | |
| | |
| | | |
| | | // 设备状态 |
| | | export const DEVICE_STATUS = { |
| | | 0: '在线', |
| | | 1: '离线', |
| | | 2: '故障', |
| | | 3: '报废', |
| | | } |
| | | export const DEVICE_STATUS_LIST = Object.keys(DEVICE_STATUS).map(key => ({ value: key, label: DEVICE_STATUS[key] })) |
| | |
| | | |
| | | |
| | | export function getDictLabel(value, dictList) { |
| | | return dictList.find(item => item.dictKey === value)?.dictValue || value || '-' |
| | | return dictList.find(item => item.dictKey === String(value))?.dictValue || value || '' |
| | | } |
| | | |
| | | export function blobDownload(res) { |
| | |
| | | { |
| | | "path": "workDetail/index", |
| | | "style": { |
| | | "navigationBarTitleText": "工单详情" |
| | | "navigationBarTitleText": "工单详情", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | |
| | | "text": "工单管理" |
| | | }, |
| | | { |
| | | "iconPath": "static/images/tabbar/icon_order.png", |
| | | "selectedIconPath": "static/images/tabbar/icon_order_selected.png", |
| | | "iconPath": "static/images/tabbar/icon_speech.png", |
| | | "selectedIconPath": "static/images/tabbar/icon_speech_selected.png", |
| | | "pagePath": "pages/voiceCall/index", |
| | | "text": "语音通话" |
| | | }, |
| | |
| | | <up-tabs :list="tabList" @click="handleClick"></up-tabs> |
| | | </div> |
| | | |
| | | <div class="eventBox"> |
| | | <div class="eventItem" v-for="(item,index) in dataList" :key="index"> |
| | | <img :src="item.photo_url" alt="" @click="detailHandle(item)" /> |
| | | <div class="informationDisplay"> |
| | | <div class="itemTitle">{{item.event_name}}</div> |
| | | <div class="itemContent">{{formatDate(item.create_time) }}</div> |
| | | <scroll-view class="eventBox" scroll-y :lower-threshold="80" @scrolltolower="loadMore"> |
| | | <div class="eventList"> |
| | | <div class="eventItem" v-for="(item,index) in dataList" :key="index"> |
| | | <img :src="item.photo_url" alt="" @click="detailHandle(item)" /> |
| | | <div class="informationDisplay"> |
| | | <!-- <div class="itemTitle">{{item.event_name}}</div>--> |
| | | <div class="itemContent">{{formatDate(item.create_time) }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 加载提示 --> |
| | | <div class="loadingMore"> |
| | | <text v-if="loading">加载中...</text> |
| | | |
| | | </div> |
| | | </scroll-view> |
| | | </div> |
| | | |
| | | </div> |
| | |
| | | import { getStatusBarHeight } from '@/utils/common'; |
| | | const userStore = useUserStore() |
| | | const userInfo = userStore.userInfo |
| | | const dataList = ref([]) |
| | | const dataList = ref([ |
| | | { |
| | | "id": 8474, |
| | | "wayline_job_id": "51835088-cd94-42f8-b2ec-a9069ced4e7b", |
| | | "event_name": "测试", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "file_path": "upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "longitude": "115.85649472222222", |
| | | "latitude": "28.624301527777778", |
| | | "create_time": "2026-01-13 16:51:57", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260113002", |
| | | "ai_types": "道路裂缝", |
| | | "ai_type_key_list": [ |
| | | "DLLFSB" |
| | | ], |
| | | "work_order_type_dict_key": "ZHZLL", |
| | | "work_order_type": "交通运输与交管", |
| | | "create_user": "曾超杰", |
| | | "update_user": "管理员", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "2009140684346388482", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1123598821738675201", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1806号南昌台湾健康产业城", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "content": "测试", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照2", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-13 16:51:57" |
| | | }, |
| | | { |
| | | "id": 8472, |
| | | "wayline_job_id": "6beae73e-2d5d-47e5-859b-e2a1955d6e3b", |
| | | "event_name": "车事件", |
| | | "event_dict_key": "Traffic_flow", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket//6beae73e-2d5d-47e5-859b-e2a1955d6e3b/DJI_202601091336_002_6beae73e-2d5d-47e5-859b-e2a1955d6e3b/车AI20260112144421001.jpeg", |
| | | "file_path": "/6beae73e-2d5d-47e5-859b-e2a1955d6e3b/DJI_202601091336_002_6beae73e-2d5d-47e5-859b-e2a1955d6e3b/车AI20260112144421001.jpeg", |
| | | "longitude": "115.85502433333333", |
| | | "latitude": "28.623021472222224", |
| | | "create_time": "2026-01-12 14:44:25", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "AI20260112144421001", |
| | | "remark": "江西省南昌市西湖区朝农街道翠菊路银燕物流基地发生车事件", |
| | | "ai_types": "车", |
| | | "ai_type_key_list": [ |
| | | "CGL_CLLTJ" |
| | | ], |
| | | "work_order_type_dict_key": "ZHZLL", |
| | | "work_order_type": "交通运输与交管", |
| | | "create_user": "曾超杰", |
| | | "update_user": "空间大厦管理员", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "2009140684346388482", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1979075301412524033", |
| | | "address": "江西省南昌市西湖区朝农街道翠菊路银燕物流基地", |
| | | "content": "测试", |
| | | "work_type": "2", |
| | | "job_name": "马上智飞202601091336", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-09 13:36:42" |
| | | }, |
| | | { |
| | | "id": 8464, |
| | | "wayline_job_id": "8b4b7529-13ee-4885-a7b8-4a52667444fb", |
| | | "event_name": "1212", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260107/5e6bc6ecedd830f2415a959667b3841a.jpeg", |
| | | "file_path": "upload/20260107/5e6bc6ecedd830f2415a959667b3841a.jpeg", |
| | | "longitude": "115.85803208048642", |
| | | "latitude": "28.625135341676483", |
| | | "create_time": "2026-01-07 11:18:35", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260107003", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "罗广辉", |
| | | "update_user": "空间大厦管理员", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1896495271624384514", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1979075301412524033", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路世纪吉的堡幼儿园", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260107/5e6bc6ecedd830f2415a959667b3841a.jpeg", |
| | | "content": "2121", |
| | | "work_type": "3", |
| | | "job_name": "马上智飞202601051720", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-07 11:18:35" |
| | | }, |
| | | { |
| | | "id": 8463, |
| | | "wayline_job_id": "8b4b7529-13ee-4885-a7b8-4a52667444fb", |
| | | "event_name": "122112", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260107/a52b1adda405b94a4f9436e43e1b3185.jpeg", |
| | | "file_path": "upload/20260107/a52b1adda405b94a4f9436e43e1b3185.jpeg", |
| | | "longitude": "115.85780692063119", |
| | | "latitude": "28.624775436656122", |
| | | "create_time": "2026-01-07 11:17:47", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260107002", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "罗广辉", |
| | | "update_user": "空间大厦管理员", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1896495271624384514", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1979075301412524033", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路世纪吉的堡幼儿园", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260107/a52b1adda405b94a4f9436e43e1b3185.jpeg", |
| | | "content": "1", |
| | | "work_type": "3", |
| | | "job_name": "马上智飞202601051720", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-07 11:17:48" |
| | | }, |
| | | { |
| | | "id": 8462, |
| | | "wayline_job_id": "8b4b7529-13ee-4885-a7b8-4a52667444fb", |
| | | "event_name": "1", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260107/a138491d214cc0ce7a5a3eedf6b79680.jpeg", |
| | | "file_path": "upload/20260107/a138491d214cc0ce7a5a3eedf6b79680.jpeg", |
| | | "longitude": "115.85763536212585", |
| | | "latitude": "28.626095211224335", |
| | | "create_time": "2026-01-07 11:14:41", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260107001", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "罗广辉", |
| | | "update_user": "江西融媒", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1896495271624384514", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1993119267150655490", |
| | | "address": "江西省南昌市西湖区朝农街道国贸天琴湾东区", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260107/a138491d214cc0ce7a5a3eedf6b79680.jpeg", |
| | | "content": "1", |
| | | "work_type": "3", |
| | | "job_name": "马上智飞202601051720", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-07 11:14:42" |
| | | }, |
| | | { |
| | | "id": 8461, |
| | | "wayline_job_id": "038b8f48-1704-4adc-abb7-7deb85eba101", |
| | | "event_name": "测试", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/c94dca50d34e13f53fd5a5c05abfe03f.jpeg", |
| | | "file_path": "upload/20260106/c94dca50d34e13f53fd5a5c05abfe03f.jpeg", |
| | | "longitude": "115.85623975", |
| | | "latitude": "28.624919472222224", |
| | | "create_time": "2026-01-06 13:38:03", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260106018", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "张含笑", |
| | | "update_user": "张含笑", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1909067460995813377", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1909067460995813377", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1818号国贸天琴湾", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/c94dca50d34e13f53fd5a5c05abfe03f.jpeg", |
| | | "content": "123", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照-1-5", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-06 13:38:03" |
| | | }, |
| | | { |
| | | "id": 8460, |
| | | "wayline_job_id": "8b4b7529-13ee-4885-a7b8-4a52667444fb", |
| | | "event_name": "11", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/6ef9355b143d4e89d83c77d18f4e312f.jpeg", |
| | | "file_path": "upload/20260106/6ef9355b143d4e89d83c77d18f4e312f.jpeg", |
| | | "longitude": "115.85763536212585", |
| | | "latitude": "28.626095211224335", |
| | | "create_time": "2026-01-06 11:08:51", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260106017", |
| | | "ai_types": "建筑垃圾", |
| | | "ai_type_key_list": [ |
| | | "GCL_JZLJSB" |
| | | ], |
| | | "work_order_type_dict_key": "CGL", |
| | | "work_order_type": "城市管理与综合执法", |
| | | "create_user": "张含笑", |
| | | "update_user": "罗广辉", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1909067460995813377", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1896495271624384514", |
| | | "address": "江西省南昌市西湖区朝农街道国贸天琴湾东区", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/6ef9355b143d4e89d83c77d18f4e312f.jpeg", |
| | | "content": "12", |
| | | "work_type": "3", |
| | | "job_name": "马上智飞202601051720", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-06 11:08:52" |
| | | }, |
| | | { |
| | | "id": 8459, |
| | | "wayline_job_id": "038b8f48-1704-4adc-abb7-7deb85eba101", |
| | | "event_name": "122", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/96c7769b12f2e55b7e788e8f35b0364b.jpeg", |
| | | "file_path": "upload/20260106/96c7769b12f2e55b7e788e8f35b0364b.jpeg", |
| | | "longitude": "115.85623975", |
| | | "latitude": "28.624919472222224", |
| | | "create_time": "2026-01-06 11:08:00", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260106016", |
| | | "ai_types": "水生植物漂浮物", |
| | | "ai_type_key_list": [ |
| | | "SMPFWSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "张含笑", |
| | | "update_user": "张含笑", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1909067460995813377", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1909067460995813377", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1818号国贸天琴湾", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/96c7769b12f2e55b7e788e8f35b0364b.jpeg", |
| | | "content": "1", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照-1-5", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-06 11:08:00" |
| | | }, |
| | | { |
| | | "id": 8458, |
| | | "wayline_job_id": "8b4b7529-13ee-4885-a7b8-4a52667444fb", |
| | | "event_name": "12", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/2e065c4f0e78d4fa1cfdd15f65397b85.jpeg", |
| | | "file_path": "upload/20260106/2e065c4f0e78d4fa1cfdd15f65397b85.jpeg", |
| | | "longitude": "115.85677911492691", |
| | | "latitude": "28.62569394530331", |
| | | "create_time": "2026-01-06 11:00:53", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260106015", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "张含笑", |
| | | "update_user": "罗广辉", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1909067460995813377", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1896495271624384514", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1836号国贸天琴湾东区", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/2e065c4f0e78d4fa1cfdd15f65397b85.jpeg", |
| | | "content": "22", |
| | | "work_type": "3", |
| | | "job_name": "马上智飞202601051720", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-06 11:00:54" |
| | | }, |
| | | { |
| | | "id": 8457, |
| | | "wayline_job_id": "038b8f48-1704-4adc-abb7-7deb85eba101", |
| | | "event_name": "发布事件", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/ecdfe6c661dba2fa03efcc19a5863680.jpeg", |
| | | "file_path": "upload/20260106/ecdfe6c661dba2fa03efcc19a5863680.jpeg", |
| | | "longitude": "115.85623975", |
| | | "latitude": "28.624919472222224", |
| | | "create_time": "2026-01-06 10:43:29", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260106014", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "张含笑", |
| | | "update_user": "张含笑", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1909067460995813377", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1909067460995813377", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1818号国贸天琴湾", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/ecdfe6c661dba2fa03efcc19a5863680.jpeg", |
| | | "content": "11", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照-1-5", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-06 10:43:30" |
| | | }, |
| | | { |
| | | "id": 8456, |
| | | "wayline_job_id": "038b8f48-1704-4adc-abb7-7deb85eba101", |
| | | "event_name": "122", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/fc9820c440da478fa5312e8647e1e311.jpeg", |
| | | "file_path": "upload/20260106/fc9820c440da478fa5312e8647e1e311.jpeg", |
| | | "longitude": "115.85623975", |
| | | "latitude": "28.624919472222224", |
| | | "create_time": "2026-01-06 10:38:20", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260106013", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "张含笑", |
| | | "update_user": "张含笑", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1909067460995813377", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1909067460995813377", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1818号国贸天琴湾", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/fc9820c440da478fa5312e8647e1e311.jpeg", |
| | | "content": "3", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照-1-5", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-06 10:38:20" |
| | | }, |
| | | { |
| | | "id": 8455, |
| | | "wayline_job_id": "038b8f48-1704-4adc-abb7-7deb85eba101", |
| | | "event_name": "122", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/d9a152ab1484348be5e126f854eca86a.jpeg", |
| | | "file_path": "upload/20260106/d9a152ab1484348be5e126f854eca86a.jpeg", |
| | | "longitude": "115.85623975", |
| | | "latitude": "28.624919472222224", |
| | | "create_time": "2026-01-06 10:38:18", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260106012", |
| | | "ai_types": "水体污染", |
| | | "ai_type_key_list": [ |
| | | "STWLSB" |
| | | ], |
| | | "work_order_type_dict_key": "SLL", |
| | | "work_order_type": "生态环境与水务", |
| | | "create_user": "张含笑", |
| | | "update_user": "张含笑", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "1909067460995813377", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1909067460995813377", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1818号国贸天琴湾", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260106/d9a152ab1484348be5e126f854eca86a.jpeg", |
| | | "content": "3", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照-1-5", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-06 10:38:18" |
| | | } |
| | | ]) |
| | | const currentTab=ref('all') |
| | | const loading = ref(false) |
| | | const hasMore = ref(true) |
| | | const tabList = ref([ |
| | | { |
| | | name: '全部工单', |
| | |
| | | badge: { |
| | | value: 1 |
| | | } |
| | | }, |
| | | } |
| | | |
| | | |
| | | ]) |
| | |
| | | const listParams = ref({ |
| | | status: null, |
| | | current: 1, |
| | | size: 9999, |
| | | size: 12, |
| | | source: 1, |
| | | department:'', |
| | | keyword:'' |
| | | |
| | | }) |
| | | const getDataList = () => { |
| | | if (loading.value || !hasMore.value) return |
| | | |
| | | loading.value = true |
| | | const params = { |
| | | current: 1, |
| | | size: 9999, |
| | | current: listParams.value.current, |
| | | size: listParams.value.size, |
| | | source: 1, |
| | | status:listParams.value.status, |
| | | event_name:listParams.value.keyword, |
| | |
| | | } |
| | | getList(params).then(res => { |
| | | |
| | | const response = res.data.data.records |
| | | dataList.value = response |
| | | const response = res.data.data |
| | | const records = response.records || [] |
| | | |
| | | // 根据当前页码决定是替换还是追加数据 |
| | | if (listParams.value.current === 1) { |
| | | dataList.value = records |
| | | } else { |
| | | dataList.value = [...dataList.value, ...records] |
| | | } |
| | | |
| | | // 判断是否还有更多数据 |
| | | if (records.length < listParams.value.size || response.current >= response.pages) { |
| | | hasMore.value = false |
| | | } else { |
| | | hasMore.value = true |
| | | } |
| | | }).finally(() => { |
| | | loading.value = false |
| | | }) |
| | | } |
| | | |
| | | |
| | | |
| | | // const getstatusCountData=()=>{ |
| | | // getstatusCount().then(res=>{ |
| | | // const response = res.data.data |
| | |
| | | const handleClick = (item) => { |
| | | currentTab.value = item.key |
| | | listParams.value.status = item.status |
| | | listParams.value.current = 1 |
| | | hasMore.value = true |
| | | dataList.value = [] |
| | | getDataList() |
| | | } |
| | | const loadMore = () => { |
| | | if (loading.value || !hasMore.value) return |
| | | listParams.value.current++ |
| | | getDataList() |
| | | } |
| | | |
| | | const detailHandle = (val) => { |
| | | uni.navigateTo({ |
| | | url: `/subPackages/workDetail/index?eventNum=${val.event_num}`, |
| | |
| | | } |
| | | const topMargin = getStatusBarHeight() |
| | | onShow(() => { |
| | | getDataList() |
| | | |
| | | // listParams.value.current = 1 |
| | | // hasMore.value = true |
| | | // dataList.value = [] |
| | | // getDataList() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | flex-direction: column; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | width: 100%; |
| | | overflow-x: hidden; |
| | | .searchTop { |
| | | display: flex; |
| | | align-items: center; |
| | |
| | | :deep(){ |
| | | |
| | | .u-tabs__wrapper__nav__line{ |
| | | width: 80rpx !important; |
| | | // width: 80rpx !important; |
| | | background: #1D6FE9 !important; |
| | | } |
| | | .u-badge { |
| | | background-color: #1d6fe9 !important; |
| | | margin-top: -17px !important; |
| | | margin-left: -5px !important; |
| | | } |
| | | } |
| | | |
| | |
| | | display: flex; |
| | | flex-direction: column; |
| | | flex: 1; |
| | | width: 100%; |
| | | box-sizing: border-box; |
| | | } |
| | | .eventBox { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 20rpx; |
| | | padding: 20rpx 0; |
| | | overflow-y: auto; |
| | | overflow-x: hidden; |
| | | height: 0; |
| | | flex-grow: 1; |
| | | align-content: flex-start; |
| | | width: 100%; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .eventList { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 20rpx; |
| | | width: 100%; |
| | | box-sizing: border-box; |
| | | justify-content: space-between; |
| | | |
| | | .eventItem { |
| | | width: calc(50% - 10rpx); |
| | | background-color: #fff; |
| | | border-radius: 12rpx; |
| | | overflow: hidden; |
| | | position: relative; |
| | | box-sizing: border-box; |
| | | max-width: 100%; |
| | | |
| | | img { |
| | | width: 341rpx; |
| | | height: 196rpx; |
| | | width: 100%; |
| | | height: 208rpx; |
| | | border-radius: 12rpx; |
| | | overflow: hidden; |
| | | } |
| | | .informationDisplay{ |
| | | width: 100%; |
| | | position: absolute; |
| | | bottom: 3px; |
| | | background: rgba(11,11,11,0.35); |
| | | border-radius: 0rpx 0rpx 12rpx 12rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 10rpx 20rpx 10rpx 12rpx; |
| | | justify-content: flex-end; |
| | | padding: 10rpx 0rpx 10rpx 0rpx; |
| | | .itemTitle { |
| | | width: 144rpx; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 24rpx; |
| | | color: rgba(0,0,0,0.5); |
| | | color: #FFFFFF; |
| | | padding-right: 14rpx; |
| | | |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | .loadingMore { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | height: 80rpx; |
| | | font-size: 28rpx; |
| | | color: #999; |
| | | width: 100%; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <!-- 工单详情 --> |
| | | <template> |
| | | <div class="workDetailContainer"> |
| | | <!-- 自定义导航栏 --> |
| | | <u-navbar |
| | | title="工单详情" |
| | | :is-back="true" |
| | | back-text="" |
| | | :back-icon-size="40" |
| | | @left-click="onBackClick" |
| | | > |
| | | <template #right> |
| | | <div class="share-btn" @click="onShareClick">分享</div> |
| | | </template> |
| | | </u-navbar> |
| | | <div class="detailTop"> |
| | | <div class="image-container"> |
| | | <u-swiper |
| | |
| | | <div class="workOrderContainer"> |
| | | <div class="orderRow"> |
| | | <div class="rowTitle">工单编号</div> |
| | | <div>{{workDetailData.event_num}}</div> |
| | | <div>{{ workDetailData.event_num }}</div> |
| | | </div> |
| | | <div class="orderRow"> |
| | | <div class="rowTitle">工单处置人</div> |
| | | <div>{{workDetailData.event_num?.slice(0, 2) === 'AI' ? 'AI 小飞':workDetailData.creator}} |
| | | </div> |
| | | <div>{{ workDetailData.event_num?.slice(0, 2) === 'AI' ? 'AI 小飞' : workDetailData.creator }}</div> |
| | | </div> |
| | | <div class="orderRow"> |
| | | <div class="rowTitle">处置部门</div> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | <!-- 操作按钮 --> |
| | | <div class="actionButton"> |
| | | <div class="btngroups" > |
| | | <div class="btngroups"> |
| | | <up-button type="primary" color="#AEAEAE" text="退回"></up-button> |
| | | <up-button type="primary" color="#1D6FE9" text="确认"></up-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </template> |
| | | |
| | | <script setup> |
| | | // import { getShowImg, getSmallImg } from '@/utils/util' |
| | | import {getList,flowEvent} from '/src/api/work/index.js' |
| | | import { ref, computed } from 'vue' |
| | | import { getList, flowEvent } from '/src/api/work/index.js' |
| | | import dayjs from 'dayjs' |
| | | |
| | | const formatDate = dateString => { |
| | | return dayjs(dateString).format('MM/DD HH:mm') |
| | | } |
| | | const eventNum = ref(''); |
| | | const eventNum = ref('') |
| | | // 工单内容 |
| | | const workDetailData = ref({}) |
| | | onLoad(async (options) => { |
| | | eventNum.value = options.eventNum; |
| | | await getDataList(eventNum.value); |
| | | |
| | | }); |
| | | const getDataList = async (val) => { |
| | | const workDetailData = ref({ |
| | | "id": 8474, |
| | | "wayline_job_id": "51835088-cd94-42f8-b2ec-a9069ced4e7b", |
| | | "event_name": "测试", |
| | | "device_sn": "7CTDM5E00B3H61", |
| | | "status": 3, |
| | | "photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "file_path": "upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "longitude": "115.85649472222222", |
| | | "latitude": "28.624301527777778", |
| | | "create_time": "2026-01-13 16:51:57", |
| | | "media_type": "PHOTO_TYPE", |
| | | "event_num": "BHJC20260113002", |
| | | "ai_types": "道路裂缝", |
| | | "ai_type_key_list": [ |
| | | "DLLFSB" |
| | | ], |
| | | "work_order_type_dict_key": "ZHZLL", |
| | | "work_order_type": "交通运输与交管", |
| | | "create_user": "曾超杰", |
| | | "update_user": "管理员", |
| | | "dept_name": "中图智飞(江西省)", |
| | | "create_user_id": "2009140684346388482", |
| | | "user_id": "1991745495648227330", |
| | | "handle_user_id": "1123598821738675201", |
| | | "address": "江西省南昌市西湖区朝农街道抚生南路1806号南昌台湾健康产业城", |
| | | "update_photo_url": "https://wrj.shuixiongit.com/minio/cloud-bucket/upload/20260113/f090f03fdc52499473ab9cbfcdc0876d.jpeg", |
| | | "content": "测试", |
| | | "work_type": "3", |
| | | "job_name": "定向拍照2", |
| | | "is_review": 0, |
| | | "job_create_time": "2026-01-13 16:51:57" |
| | | },) |
| | | onLoad(async options => { |
| | | eventNum.value = options.eventNum |
| | | // await getDataList(eventNum.value) |
| | | }) |
| | | const getDataList = async val => { |
| | | const params = { |
| | | current: 1, |
| | | size: 9999, |
| | | source: 1, |
| | | event_name: val |
| | | event_name: val, |
| | | } |
| | | const res = await getList(params); |
| | | const response = res.data.data.records; |
| | | workDetailData.value = response[0]; |
| | | const res = await getList(params) |
| | | const response = res.data.data.records |
| | | workDetailData.value = response[0] |
| | | |
| | | console.log('详情',response); |
| | | console.log('详情', response) |
| | | } |
| | | // 图片预览 |
| | | |
| | | const previewImage = (index) => { |
| | | if (getImageList.value.length === 0) return; |
| | | const currentIndex = typeof index === 'number' ? index : 0; |
| | | const previewImage = index => { |
| | | if (getImageList.value.length === 0) return |
| | | const currentIndex = typeof index === 'number' ? index : 0 |
| | | uni.previewImage({ |
| | | urls: getImageList.value, |
| | | current: currentIndex |
| | | }); |
| | | }; |
| | | const getImageList =computed(()=>{ |
| | | current: currentIndex, |
| | | }) |
| | | } |
| | | const getImageList = computed(() => { |
| | | const imageArr = [] |
| | | const detail = workDetailData.value |
| | | if (detail.photo_url) { |
| | |
| | | imageArr.push(smallUrl) |
| | | } |
| | | if (detail.update_photo_url) { |
| | | const smallUrl =detail.update_photo_url |
| | | const smallUrl = detail.update_photo_url |
| | | imageArr.push(smallUrl) |
| | | } |
| | | return imageArr |
| | |
| | | url: `/subPackages/workDetail/mapWork/index?eventNum=${item.event_num}`, |
| | | }) |
| | | } |
| | | |
| | | // 分享按钮点击事件 |
| | | const onShareClick = () => { |
| | | // 检查当前平台是否支持分享功能 |
| | | const platform = uni.getSystemInfoSync().platform |
| | | |
| | | // H5平台不支持uni.share API |
| | | if (platform === 'web') { |
| | | uni.showToast({ |
| | | title: 'H5平台暂不支持分享功能', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | uni.showActionSheet({ |
| | | itemList: ['分享给微信好友', '分享到朋友圈'], |
| | | success: res => { |
| | | // 检查uni.share是否存在 |
| | | if (typeof uni.share !== 'function') { |
| | | uni.showToast({ |
| | | title: '当前环境不支持分享功能', |
| | | icon: 'none' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | try { |
| | | switch (res.tapIndex) { |
| | | case 0: |
| | | // 分享给微信好友 |
| | | uni.share({ |
| | | provider: 'weixin', |
| | | scene: 'WXSceneSession', |
| | | type: 0, |
| | | title: '工单详情', |
| | | summary: workDetailData.value.event_name, |
| | | href: 'https://example.com/workDetail?eventNum=' + workDetailData.value.event_num, |
| | | imageUrl: workDetailData.value.photo_url, |
| | | success: () => { |
| | | uni.showToast({ title: '分享成功', icon: 'success' }) |
| | | }, |
| | | fail: (err) => { |
| | | console.log('分享失败', err.errMsg) |
| | | uni.showToast({ |
| | | title: err.errMsg, |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | }) |
| | | break |
| | | case 1: |
| | | // 分享到朋友圈 |
| | | uni.share({ |
| | | provider: 'weixin', |
| | | scene: 'WXSceneTimeline', |
| | | type: 0, |
| | | title: workDetailData.value.event_name, |
| | | summary: '查看工单详情', |
| | | href: 'https://example.com/workDetail?eventNum=' + workDetailData.value.event_num, |
| | | imageUrl: workDetailData.value.photo_url, |
| | | success: () => { |
| | | uni.showToast({ title: '分享成功', icon: 'success' }) |
| | | }, |
| | | fail: (err) => { |
| | | console.log('分享失败', err) |
| | | uni.showToast({ |
| | | title: '分享失败,请检查配置', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | }) |
| | | break |
| | | } |
| | | } catch (error) { |
| | | console.error('分享出错:', error) |
| | | uni.showToast({ |
| | | title: '分享功能异常', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 返回按钮点击事件 |
| | | const onBackClick = () => { |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | // 监听导航栏右侧按钮点击事件(兼容原来的配置) |
| | | const onNavigationBarButtonTap = e => { |
| | | if (e.index === 0) { |
| | | onShareClick() |
| | | } |
| | | } |
| | | </script> |
| | | <style lang="scss" scoped> |
| | | .workDetailContainer { |
| | | // 添加导航栏高度的padding-top,避免内容被遮挡 |
| | | padding-top: 44px; |
| | | // 分享按钮样式 |
| | | .share-btn { |
| | | color: #1D6FE9; |
| | | font-size: 14px; |
| | | padding: 0 10px; |
| | | line-height: 44px; |
| | | } |
| | | .detailTop { |
| | | .image-container { |
| | | position: relative; |
| | |
| | | justify-content: center; |
| | | align-items: center; |
| | | z-index: 10; |
| | | |
| | | } |
| | | .u-swiper-indicator__wrapper__dot--active{ |
| | | .u-swiper-indicator__wrapper__dot--active { |
| | | width: 5px !important; |
| | | } |
| | | } |
| | |
| | | height: 60rpx; |
| | | line-height: 60rpx; |
| | | background: rgba(7, 7, 7, 0.4); |
| | | |
| | | } |
| | | |
| | | .titleText { |
| | |
| | | align-items: center; |
| | | color: #fff; |
| | | |
| | | .itemName, .itemTime { |
| | | .itemName, |
| | | .itemTime { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 28rpx; |
| | | color: #FFFFFF; |
| | | color: #ffffff; |
| | | } |
| | | .itemName { |
| | | padding-left: 20rpx; |
| | | } |
| | | .itemTime{ |
| | | .itemTime { |
| | | padding-right: 20rpx; |
| | | } |
| | | } |
| | |
| | | font-size: 30rpx; |
| | | color: #222324; |
| | | white-space: nowrap; |
| | | |
| | | } |
| | | .rowAddress { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 28rpx; |
| | | color: #1D6FE9; |
| | | color: #1d6fe9; |
| | | //white-space: nowrap; |
| | | ///* 禁止换行 */ |
| | | //overflow: hidden; |
| | |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | :deep(.u-button){ |
| | | :deep(.u-button) { |
| | | width: 276rpx !important; |
| | | height: 100rpx !important; |
| | | &:last-child { |
| | | margin-left: 30rpx; |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |