| | |
| | | import noDataImg from '@/assets/element-img/no-data.png' |
| | | import type { DataTableColumns } from 'naive-ui' |
| | | import { useBoolean } from '@/hooks' |
| | | import { NButton, NDatePicker, NInput, NSelect, NSpace, NSwitch } from 'naive-ui' |
| | | import { NButton, NDatePicker, NInput, NSelect, NSwitch } from 'naive-ui' |
| | | import SearchPanel from '@/components/custom/SearchPanel.vue' |
| | | import Pagination from '@/components/common/Pagination.vue' |
| | | import OperationLogModal from '@/components/custom/OperationLogModal.vue' |
| | | import { |
| | | addUturnConfig, |
| | | batchImportUturnConfig, |
| | | deleteUturnConfig, |
| | | downloadUturnConfigTemplate, |
| | | editUturnConfig, |
| | | enableSwitchUturnConfig, |
| | | exportUturnConfigExcel, |
| | | fetchUturnConfigDetail, |
| | | fetchUturnConfigPageList, |
| | | } from '@/service/api/uturnAvoidConfig' |
| | | import { fetchPointList } from '@/service/api/point' |
| | | import { downloadFile } from '@/utils/common' |
| | | import { getMultiSelectRowClassName, shouldIgnoreTableRowClick, toggleMultiSelectRowKey } from '@/utils/table' |
| | | import dayjs from 'dayjs' |
| | |
| | | const model = ref({ ...initialModel }) |
| | | const isStatusSelectOpen = ref(false) |
| | | |
| | | // 点位选项(用于「站点附近起步」Tab 的点位名称筛选与点位经纬度展示) |
| | | interface PointOption { |
| | | label: string |
| | | value: string |
| | | id: number |
| | | lon?: number |
| | | lat?: number |
| | | } |
| | | const pointOptions = ref<PointOption[]>([]) |
| | | const pointMap = ref<Record<number, { name: string, lon?: number, lat?: number }>>({}) |
| | | |
| | | async function loadPointOptions() { |
| | | try { |
| | | const res = await fetchPointList({}) |
| | | if (res.code === 200 && Array.isArray(res.data)) { |
| | | const map: Record<number, { name: string, lon?: number, lat?: number }> = {} |
| | | const opts: PointOption[] = [] |
| | | res.data.forEach((p) => { |
| | | if (p.id == null) |
| | | return |
| | | const name = p.pointName || '' |
| | | map[p.id] = { name, lon: p.pointLon, lat: p.pointLat } |
| | | opts.push({ label: name, value: name, id: p.id, lon: p.pointLon, lat: p.pointLat }) |
| | | }) |
| | | pointMap.value = map |
| | | pointOptions.value = opts |
| | | } |
| | | } |
| | | catch {} |
| | | } |
| | | |
| | | const statusOptions = [ |
| | | { label: '启用中', value: true }, |
| | | { label: '已停用', value: false }, |
| | |
| | | { |
| | | label: activeTab.value === 'NARROW_UTURN' ? '位置名称' : '点位名称', |
| | | path: 'name', |
| | | render: () => <NInput v-model:value={model.value.name} placeholder={activeTab.value === 'NARROW_UTURN' ? '请输入位置名称' : '请输入点位名称'} clearable />, |
| | | render: () => activeTab.value === 'NARROW_UTURN' |
| | | ? <NInput v-model:value={model.value.name} placeholder="请输入位置名称" clearable /> |
| | | : ( |
| | | <NSelect |
| | | v-model:value={model.value.name} |
| | | options={pointOptions.value} |
| | | placeholder="请选择点位名称" |
| | | filterable |
| | | clearable |
| | | /> |
| | | ), |
| | | }, |
| | | { |
| | | label: '创建时间', |
| | |
| | | // ==================== 列表数据 ==================== |
| | | const listData = ref<any[]>([]) |
| | | const checkedRowKeys = ref<Array<string | number>>([]) |
| | | const showOperationLogModal = ref(false) |
| | | const TABLE_ROW_CLICK_IGNORE_SELECTORS = ['.table-row-link'] |
| | | |
| | | const pagination = reactive({ |
| | |
| | | |
| | | if (activeTab.value === 'STATION_START') { |
| | | cols.push({ |
| | | title: '点位ID', |
| | | key: 'startPointId', |
| | | width: 100, |
| | | title: '点位经纬度', |
| | | key: 'startPointCoord', |
| | | width: 200, |
| | | align: 'left', |
| | | ellipsis: true, |
| | | ellipsis: { tooltip: true }, |
| | | resizable: true, |
| | | render(row) { |
| | | return row.startPointId || '-' |
| | | const info = row.startPointId ? pointMap.value[row.startPointId] : undefined |
| | | if (info && info.lon != null && info.lat != null) |
| | | return `(${info.lon},${info.lat})` |
| | | // 兼容后端可能直接下发的经纬度字段 |
| | | const lon = row.startPointLon ?? row.pointLon |
| | | const lat = row.startPointLat ?? row.pointLat |
| | | if (lon != null && lat != null) |
| | | return `(${lon},${lat})` |
| | | return '-' |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | cols.push( |
| | | { |
| | | title: '路径点经纬度', |
| | | title: activeTab.value === 'NARROW_UTURN' ? '路径经纬度' : '路径点经纬度', |
| | | key: 'uturnPointsJson', |
| | | width: 240, |
| | | align: 'left', |
| | | ellipsis: true, |
| | | ellipsis: { tooltip: true }, |
| | | resizable: true, |
| | | render(row) { |
| | | return formatPointsJson(row.uturnPointsJson) |
| | | }, |
| | | }, |
| | | { |
| | | title: '途径点经纬度', |
| | | title: activeTab.value === 'NARROW_UTURN' ? '途径点经纬度' : '途径点', |
| | | key: 'detourWaypointsJson', |
| | | width: 240, |
| | | align: 'left', |
| | | ellipsis: true, |
| | | ellipsis: { tooltip: true }, |
| | | resizable: true, |
| | | render(row) { |
| | | return formatPointsJson(row.detourWaypointsJson) |
| | |
| | | { |
| | | title: '操作', |
| | | key: 'actions', |
| | | width: 120, |
| | | width: 90, |
| | | align: 'left', |
| | | fixed: 'right', |
| | | render(row) { |
| | | const isEnabled = row.enabled === true || row.enabled === 1 |
| | | return ( |
| | | <NSpace wrap={false}> |
| | | <NButton text type="primary" onClick={() => handleEdit(row)}>编辑</NButton> |
| | | <NButton text type="primary" onClick={() => handleEnableSwitch(row)}> |
| | | {isEnabled ? '停用' : '启用'} |
| | | </NButton> |
| | | </NSpace> |
| | | <NButton text type={isEnabled ? 'error' : 'primary'} onClick={() => handleEnableSwitch(row)}> |
| | | {isEnabled ? '停用' : '启用'} |
| | | </NButton> |
| | | ) |
| | | }, |
| | | }, |
| | |
| | | }) |
| | | } |
| | | |
| | | // ==================== 新增/编辑弹窗 ==================== |
| | | // ==================== 新增弹窗 ==================== |
| | | const showFormModal = ref(false) |
| | | const isEditMode = ref(false) |
| | | const formModel = ref({ |
| | | id: null as number | null, |
| | | name: '', |
| | | uturnPointsText: '', |
| | | detourWaypointsText: '', |
| | |
| | | }) |
| | | |
| | | function handleAdd() { |
| | | isEditMode.value = false |
| | | formModel.value = { |
| | | id: null, |
| | | name: '', |
| | | uturnPointsText: '', |
| | | detourWaypointsText: '', |
| | |
| | | startPointId: null, |
| | | } |
| | | showFormModal.value = true |
| | | } |
| | | |
| | | async function handleEdit(row: any) { |
| | | isEditMode.value = true |
| | | const res = await fetchUturnConfigDetail(row.id) |
| | | if (res.code === 200 && res.data) { |
| | | const data = res.data |
| | | formModel.value = { |
| | | id: data.id, |
| | | name: data.name || '', |
| | | uturnPointsText: formatPointsJson(data.uturnPointsJson).replace(/; /g, ';'), |
| | | detourWaypointsText: formatPointsJson(data.detourWaypointsJson).replace(/; /g, ';'), |
| | | radius: data.radius, |
| | | enabled: data.enabled === true || data.enabled === 1, |
| | | startPointId: data.startPointId, |
| | | } |
| | | showFormModal.value = true |
| | | } |
| | | } |
| | | |
| | | function parsePointsText(text: string): number[][] | null { |
| | |
| | | } |
| | | |
| | | try { |
| | | let res |
| | | if (isEditMode.value) { |
| | | payload.id = formModel.value.id |
| | | res = await editUturnConfig(payload) |
| | | } |
| | | else { |
| | | res = await addUturnConfig(payload) |
| | | } |
| | | const res = await addUturnConfig(payload) |
| | | if (res.code === 200) { |
| | | message.success(isEditMode.value ? '编辑成功' : '新增成功') |
| | | message.success('新增成功') |
| | | showFormModal.value = false |
| | | getList() |
| | | } |
| | |
| | | getList() |
| | | } |
| | | |
| | | function handleOpenOperationLog() { |
| | | showOperationLogModal.value = true |
| | | } |
| | | |
| | | onMounted(() => { |
| | | loadPointOptions() |
| | | getList() |
| | | }) |
| | | </script> |
| | |
| | | <NButton :disabled="checkedRowKeys.length === 0" @click="handleBatchExport"> |
| | | 批量导出 |
| | | </NButton> |
| | | </n-flex> |
| | | <n-flex> |
| | | <NButton @click="handleDownloadTemplate"> |
| | | 下载模板 |
| | | </NButton> |
| | |
| | | style="display: none;" |
| | | @change="handleFileChange" |
| | | > |
| | | </n-flex> |
| | | <n-flex> |
| | | <NButton @click="handleOpenOperationLog"> |
| | | 操作日志 |
| | | </NButton> |
| | | <NButton type="primary" @click="handleAdd"> |
| | | 新增 |
| | | </NButton> |
| | |
| | | </div> |
| | | </n-card> |
| | | |
| | | <!-- 新增/编辑弹窗 --> |
| | | <!-- 新增弹窗 --> |
| | | <n-modal |
| | | v-model:show="showFormModal" |
| | | :title="isEditMode ? '编辑' : '新增'" |
| | | title="新增" |
| | | preset="dialog" |
| | | :mask-closable="false" |
| | | style="width: 560px;" |
| | |
| | | </NButton> |
| | | </template> |
| | | </n-modal> |
| | | |
| | | <OperationLogModal v-model:show="showOperationLogModal" /> |
| | | </div> |
| | | </template> |
| | | |