填报页面修改,沿程配置修改,添加预警和推送页面
This commit is contained in:
parent
46100d8318
commit
549849b479
@ -7,7 +7,7 @@ VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台'
|
||||
VITE_APP_PORT = 3000
|
||||
VITE_APP_BASE_API = '/dev-api'
|
||||
# 本地环境
|
||||
VITE_APP_BASE_URL = 'http://10.84.121.127:8093'
|
||||
VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
|
||||
# 测试环境
|
||||
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
|
||||
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
|
||||
|
||||
@ -12,12 +12,9 @@ VITE_APP_BASE_API = '/dev-api'
|
||||
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
|
||||
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
|
||||
# 汤伟
|
||||
VITE_APP_BASE_URL = 'http://10.84.121.127:8093'
|
||||
# VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
|
||||
# 李林
|
||||
# VITE_APP_BASE_URL = 'http://10.84.121.43:8093'
|
||||
# VITE_APP_BASE_URL = 'http://192.168.1.162:8093'
|
||||
# 李林
|
||||
# VITE_APP_BASE_URL = 'http://10.84.121.43:8093'
|
||||
VITE_APP_BASE_URL = 'http://10.84.111.25:8093'
|
||||
|
||||
# 测试环境线上10.84.121.122:
|
||||
VITE_APP_TEST_ONLINE_URL = 'https://211.99.26.225:12122'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import request from '@/utils/request';
|
||||
//水电基地数据获取
|
||||
//水电基地数据获取
|
||||
export function wbsbGetKendoList(data: any) {
|
||||
return request({
|
||||
url: '/env/hydrobase/wbsb/GetKendoList',
|
||||
@ -106,3 +106,11 @@ export function uploadFile(data: any) {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
});
|
||||
}
|
||||
// 所在位置下拉列表
|
||||
export function getAddvcdDropdownByRvcd(params: any) {
|
||||
return request({
|
||||
url: '/base/msalongb/noAuth/GetKendoList',
|
||||
method: 'post',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import request from '@/utils/request';
|
||||
// 获取所有沿程配置数据
|
||||
export function getAllConfigTree(data: any) {
|
||||
return request({
|
||||
url: '/api/dec-lygk-base-server/base/msalongb/GetKendoList',
|
||||
url: '/base/msalongb/GetKendoList',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
@ -11,7 +11,7 @@ export function getAllConfigTree(data: any) {
|
||||
// 保存沿程配置
|
||||
export function saveBaseWbsb(data: any) {
|
||||
return request({
|
||||
url: '/api/dec-lygk-base-server/base/wbsb/addOrUpdate',
|
||||
url: '/base/msalongb/save',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
@ -19,8 +19,24 @@ export function saveBaseWbsb(data: any) {
|
||||
// 删除沿程配置
|
||||
export function deleteBaseWbsb(data: any) {
|
||||
return request({
|
||||
url: '/api/dec-lygk-base-server/base/wbsb/delete',
|
||||
method: 'get',
|
||||
params: data
|
||||
url: '/base/msalongb/delete',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
// 保存沿程配置子节点
|
||||
export function saveBaseWbsbChild(data: any) {
|
||||
return request({
|
||||
url: '/base/msalongb/save',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
export function saveBaseWbsbChildDetail(data: any) {
|
||||
return request({
|
||||
url: '/base/msalongdetb/save',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ export function overviewGetOverviewSecond(data: any) {
|
||||
data
|
||||
});
|
||||
}
|
||||
//增殖站介绍 /api/dec-lygk-base-server/base/msstbprpt/GetKendoList
|
||||
//增殖站介绍
|
||||
export function msstbprptGetKendoList(data: any) {
|
||||
return request({
|
||||
url: '/fb/msstbprpt/GetKendoList',
|
||||
@ -34,7 +34,7 @@ export function msstbprptGetKendoList(data: any) {
|
||||
data
|
||||
});
|
||||
}
|
||||
// 增殖站运行数据统计
|
||||
// 增殖站运行数据统计
|
||||
export function qgcgetFbStaticsData(data: any) {
|
||||
return request({
|
||||
url: '/fb/station/qgc/getFbStaticsData',
|
||||
@ -73,4 +73,4 @@ export function msfbrdmGetKendoListCust(data: any) {
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,9 @@ service.interceptors.response.use(
|
||||
if (status === 200) {
|
||||
if (response.data.code == 401) {
|
||||
message.error(response.data.msg || '请求失败');
|
||||
setTimeout(() => {
|
||||
router.push('/login');
|
||||
}, 1000);
|
||||
return;
|
||||
} else if (response.data.code == 1) {
|
||||
message.error(response.data.msg);
|
||||
|
||||
@ -0,0 +1,784 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="isEdit ? '编辑沿程配置' : '新增沿程配置'"
|
||||
v-model:open="modalVisible"
|
||||
:confirm-loading="localLoading"
|
||||
width="1200px"
|
||||
:destroy-on-close="true"
|
||||
ok-text="保存"
|
||||
@cancel="handleCancel"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
name="edit_form"
|
||||
:labelCol="{ span: 5 }"
|
||||
>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="沿程配置名称" name="name">
|
||||
<a-input
|
||||
v-model:value="formData.name"
|
||||
style="width: 100%"
|
||||
placeholder="请输入沿程配置名称"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="配置编码" name="code">
|
||||
<a-input
|
||||
v-model:value="formData.code"
|
||||
style="width: 100%"
|
||||
placeholder="请输入配置编码"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="所在河段" name="rvnm">
|
||||
<a-input
|
||||
v-model:value="formData.rvnm"
|
||||
style="width: 100%"
|
||||
placeholder="请输入所在河段"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="备注" name="description">
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-model:value="formData.description"
|
||||
style="width: 100%"
|
||||
placeholder="请输入备注"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<div class="config-tree-container">
|
||||
<!-- 新增一级节点区域 -->
|
||||
<div v-if="addingNewNode" class="add-node-row">
|
||||
<a-select
|
||||
v-model:value="newNodeData.stcd"
|
||||
show-search
|
||||
placeholder="请选择站点"
|
||||
style="width: 300px"
|
||||
:filter-option="filterOption"
|
||||
@change="handleNodeSelect"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="handleSaveNewNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button @click="handleCancelAdd" style="margin-left: 8px">
|
||||
<MinusOutlined />
|
||||
</a-button>
|
||||
</div>
|
||||
<a-button v-else class="mb-4" type="primary" @click="handleAdd">
|
||||
<PlusOutlined /> 新增一级节点
|
||||
</a-button>
|
||||
|
||||
<!-- 树形结构 -->
|
||||
<a-tree
|
||||
v-if="treeData.length > 0"
|
||||
:tree-data="treeData"
|
||||
:default-expand-all="false"
|
||||
:selectable="false"
|
||||
block-node
|
||||
style="width: 300px"
|
||||
>
|
||||
<template #title="{ dataRef }">
|
||||
<!-- 编辑状态:只显示编辑区域 -->
|
||||
<div
|
||||
v-if="editingNode && editingNodeKey === dataRef.key"
|
||||
class="add-child-node-row w-[300px]"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="editNodeData.stcd"
|
||||
show-search
|
||||
placeholder="请选择站点"
|
||||
style="width: 300px"
|
||||
:filter-option="filterOption"
|
||||
@change="handleEditNodeSelect"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.stop="handleSaveEditNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button
|
||||
@click.stop="handleCancelEditNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
<MinusOutlined />
|
||||
</a-button>
|
||||
</div>
|
||||
<!-- 非编辑状态:显示正常节点内容 -->
|
||||
<template v-else>
|
||||
<div class="tree-node-wrapper">
|
||||
<span class="tree-node-title"> {{ getNodeTitle(dataRef) }} </span>
|
||||
<div class="tree-node-actions">
|
||||
<!-- 一级节点:支持新增子节点、编辑、排序、删除 -->
|
||||
<template v-if="!dataRef.parentId">
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleAddChild(dataRef)"
|
||||
title="添加子节点"
|
||||
>
|
||||
<PlusOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleEditNode(dataRef)"
|
||||
title="编辑"
|
||||
>
|
||||
<EditOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveUp(dataRef)"
|
||||
title="上移"
|
||||
:disabled="isFirstNode(dataRef)"
|
||||
>
|
||||
<ArrowUpOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveDown(dataRef)"
|
||||
title="下移"
|
||||
:disabled="isLastNode(dataRef)"
|
||||
>
|
||||
<ArrowDownOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click.stop="handleDeleteNode(dataRef)"
|
||||
title="删除"
|
||||
>
|
||||
<DeleteOutlined />
|
||||
</a-button>
|
||||
</template>
|
||||
<!-- 二级节点:只支持编辑、排序、删除 -->
|
||||
<template v-else>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleEditNode(dataRef)"
|
||||
title="编辑"
|
||||
>
|
||||
<EditOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveUp(dataRef)"
|
||||
title="上移"
|
||||
:disabled="isFirstNode(dataRef)"
|
||||
>
|
||||
<ArrowUpOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveDown(dataRef)"
|
||||
title="下移"
|
||||
:disabled="isLastNode(dataRef)"
|
||||
>
|
||||
<ArrowDownOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click.stop="handleDeleteNode(dataRef)"
|
||||
title="删除"
|
||||
>
|
||||
<DeleteOutlined />
|
||||
</a-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 子节点添加区域 -->
|
||||
<div
|
||||
v-if="addingChildNode && currentParentKey === dataRef.key"
|
||||
class="add-child-node-row"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="childNodeData.stcd"
|
||||
show-search
|
||||
placeholder="请选择站点"
|
||||
style="width: 300px"
|
||||
:filter-option="filterOption"
|
||||
@change="handleChildNodeSelect"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.stop="handleSaveChildNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button
|
||||
@click.stop="handleCancelAddChild"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
<MinusOutlined />
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-tree>
|
||||
<a-empty v-else description="暂无数据" style="margin-top: 20px" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, watch } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import type { Rule } from 'ant-design-vue/es/form';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
PlusOutlined,
|
||||
MinusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
ArrowUpOutlined,
|
||||
ArrowDownOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
initialValues?: any | null;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const localLoading = ref(false);
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
initialValues: null,
|
||||
loading: false
|
||||
});
|
||||
|
||||
const modalVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: val => emit('update:visible', val)
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void;
|
||||
(e: 'cancel'): void;
|
||||
(e: 'ok', values: any): void;
|
||||
}>();
|
||||
|
||||
const formRef = ref();
|
||||
|
||||
const defaultFormData = reactive({
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
code: undefined,
|
||||
rvnm: undefined,
|
||||
description: undefined
|
||||
});
|
||||
const formData: any = reactive({ ...defaultFormData });
|
||||
|
||||
const rules: Record<string, Rule[]> = {
|
||||
name: [{ required: true, message: '请输入沿程配置名称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入配置编码', trigger: 'blur' }],
|
||||
rvnm: [{ required: true, message: '请输入所在河段', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
const isEdit = computed(() => !!props.initialValues);
|
||||
|
||||
// 树形数据
|
||||
const treeData = ref<any[]>([]);
|
||||
|
||||
// 新增节点相关
|
||||
const addingNewNode = ref(false);
|
||||
const newNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
});
|
||||
|
||||
// 添加子节点相关
|
||||
const addingChildNode = ref(false);
|
||||
const currentParentKey = ref<string | null>(null);
|
||||
const childNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
});
|
||||
|
||||
// 编辑节点相关
|
||||
const editingNode = ref(false);
|
||||
const editingNodeKey = ref<string | null>(null);
|
||||
const editNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: '',
|
||||
originalData: null as any
|
||||
});
|
||||
|
||||
// 站点列表(模拟数据,实际应从接口获取)
|
||||
const stationList = ref([
|
||||
{ stcd: '1', stnm: '站点A', sttpName: '类型1' },
|
||||
{ stcd: '2', stnm: '站点B', sttpName: '类型2' },
|
||||
{ stcd: '3', stnm: '站点C', sttpName: '类型1' },
|
||||
{ stcd: '4', stnm: '站点D', sttpName: '类型3' }
|
||||
]);
|
||||
|
||||
// 生成唯一ID
|
||||
let nodeIdCounter = 0;
|
||||
const generateNodeId = () => `node_${Date.now()}_${++nodeIdCounter}`;
|
||||
|
||||
// 获取节点标题
|
||||
const getNodeTitle = (dataRef: any) => {
|
||||
if (!dataRef.parentId) {
|
||||
// 一级节点:只显示 stnm
|
||||
return dataRef.stnm || '';
|
||||
} else {
|
||||
// 二级节点:显示 stnm + sttpName
|
||||
return `${dataRef.stnm || ''} ${dataRef.sttpName || ''}`;
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索过滤
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return (
|
||||
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
);
|
||||
};
|
||||
|
||||
// 判断是否为第一个节点
|
||||
const isFirstNode = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
return siblings.length > 0 && siblings[0].key === dataRef.key;
|
||||
};
|
||||
|
||||
// 判断是否为最后一个节点
|
||||
const isLastNode = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
return (
|
||||
siblings.length > 0 && siblings[siblings.length - 1].key === dataRef.key
|
||||
);
|
||||
};
|
||||
|
||||
// 获取兄弟节点
|
||||
const getSiblings = (dataRef: any) => {
|
||||
if (!dataRef.parentId) {
|
||||
// 一级节点
|
||||
return treeData.value;
|
||||
} else {
|
||||
// 二级节点,找到父节点的 children
|
||||
const parent = findNodeByKey(treeData.value, dataRef.parentId);
|
||||
return parent?.children || [];
|
||||
}
|
||||
};
|
||||
|
||||
// 根据 key 查找节点
|
||||
const findNodeByKey = (nodes: any[], key: string): any => {
|
||||
for (const node of nodes) {
|
||||
if (node.key === key) {
|
||||
return node;
|
||||
}
|
||||
if (node.children && node.children.length > 0) {
|
||||
const found = findNodeByKey(node.children, key);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// 新增一级节点
|
||||
const handleAdd = () => {
|
||||
addingNewNode.value = true;
|
||||
newNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 选择节点
|
||||
const handleNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
newNodeData.value.stnm = station.stnm;
|
||||
newNodeData.value.sttpName = station.sttpName;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存新增节点
|
||||
const handleSaveNewNode = () => {
|
||||
if (!newNodeData.value.stcd) {
|
||||
message.error('请选择站点');
|
||||
return;
|
||||
}
|
||||
|
||||
const newNode = {
|
||||
key: generateNodeId(),
|
||||
stcd: newNodeData.value.stcd,
|
||||
stnm: newNodeData.value.stnm,
|
||||
sttpName: newNodeData.value.sttpName,
|
||||
parentId: null,
|
||||
children: []
|
||||
};
|
||||
|
||||
treeData.value.push(newNode);
|
||||
addingNewNode.value = false;
|
||||
message.success('添加成功');
|
||||
};
|
||||
|
||||
// 取消新增
|
||||
const handleCancelAdd = () => {
|
||||
addingNewNode.value = false;
|
||||
newNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 添加子节点(二级节点)
|
||||
const handleAddChild = (parentData: any) => {
|
||||
addingChildNode.value = true;
|
||||
currentParentKey.value = parentData.key;
|
||||
childNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 选择子节点
|
||||
const handleChildNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
childNodeData.value.stnm = station.stnm;
|
||||
childNodeData.value.sttpName = station.sttpName;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存新增子节点
|
||||
const handleSaveChildNode = () => {
|
||||
if (!childNodeData.value.stcd) {
|
||||
message.error('请选择站点');
|
||||
return;
|
||||
}
|
||||
|
||||
const parent = findNodeByKey(treeData.value, currentParentKey.value!);
|
||||
if (!parent) {
|
||||
message.error('父节点不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
const newChild = {
|
||||
key: generateNodeId(),
|
||||
stcd: childNodeData.value.stcd,
|
||||
stnm: childNodeData.value.stnm,
|
||||
sttpName: childNodeData.value.sttpName,
|
||||
parentId: parent.key,
|
||||
children: []
|
||||
};
|
||||
|
||||
if (!parent.children) {
|
||||
parent.children = [];
|
||||
}
|
||||
// 在子节点列表顶部添加
|
||||
parent.children.unshift(newChild);
|
||||
|
||||
addingChildNode.value = false;
|
||||
currentParentKey.value = null;
|
||||
message.success('添加子节点成功');
|
||||
};
|
||||
|
||||
// 取消添加子节点
|
||||
const handleCancelAddChild = () => {
|
||||
addingChildNode.value = false;
|
||||
currentParentKey.value = null;
|
||||
childNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 编辑节点
|
||||
const handleEditNode = (dataRef: any) => {
|
||||
editingNode.value = true;
|
||||
editingNodeKey.value = dataRef.key;
|
||||
// 保存原始数据
|
||||
editNodeData.value = {
|
||||
stcd: dataRef.stcd,
|
||||
stnm: dataRef.stnm,
|
||||
sttpName: dataRef.sttpName,
|
||||
originalData: { ...dataRef }
|
||||
};
|
||||
};
|
||||
|
||||
// 选择编辑节点
|
||||
const handleEditNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
editNodeData.value.stnm = station.stnm;
|
||||
editNodeData.value.sttpName = station.sttpName;
|
||||
editNodeData.value.stcd = station.stcd;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存编辑节点
|
||||
const handleSaveEditNode = () => {
|
||||
if (!editNodeData.value.stcd) {
|
||||
message.error('请选择站点');
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到要编辑的节点
|
||||
const node = findNodeByKey(treeData.value, editingNodeKey.value!);
|
||||
if (!node) {
|
||||
message.error('节点不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新节点数据
|
||||
node.stcd = editNodeData.value.stcd;
|
||||
node.stnm = editNodeData.value.stnm;
|
||||
node.sttpName = editNodeData.value.sttpName;
|
||||
|
||||
editingNode.value = false;
|
||||
editingNodeKey.value = null;
|
||||
message.success('编辑成功');
|
||||
};
|
||||
|
||||
// 取消编辑节点
|
||||
const handleCancelEditNode = () => {
|
||||
editingNode.value = false;
|
||||
editingNodeKey.value = null;
|
||||
editNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: '',
|
||||
originalData: null
|
||||
};
|
||||
};
|
||||
|
||||
// 上移
|
||||
const handleMoveUp = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
const index = siblings.findIndex(item => item.key === dataRef.key);
|
||||
|
||||
if (index > 0) {
|
||||
// 交换位置
|
||||
[siblings[index - 1], siblings[index]] = [
|
||||
siblings[index],
|
||||
siblings[index - 1]
|
||||
];
|
||||
message.success('上移成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 下移
|
||||
const handleMoveDown = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
const index = siblings.findIndex(item => item.key === dataRef.key);
|
||||
|
||||
if (index < siblings.length - 1) {
|
||||
// 交换位置
|
||||
[siblings[index], siblings[index + 1]] = [
|
||||
siblings[index + 1],
|
||||
siblings[index]
|
||||
];
|
||||
message.success('下移成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 删除节点
|
||||
const handleDeleteNode = (dataRef: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定要删除节点"${dataRef.stnm}"吗?`,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
if (!dataRef.parentId) {
|
||||
// 删除一级节点
|
||||
const index = treeData.value.findIndex(
|
||||
item => item.key === dataRef.key
|
||||
);
|
||||
if (index > -1) {
|
||||
treeData.value.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
// 删除二级节点
|
||||
const parent = findNodeByKey(treeData.value, dataRef.parentId);
|
||||
if (parent && parent.children) {
|
||||
const index = parent.children.findIndex(
|
||||
item => item.key === dataRef.key
|
||||
);
|
||||
if (index > -1) {
|
||||
parent.children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
message.success('删除成功');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
const submitValues = {
|
||||
...formData,
|
||||
captureDate: formData.captureDate
|
||||
? dayjs(formData.captureDate).format('YYYY-MM-DD')
|
||||
: undefined,
|
||||
configNodes: treeData.value // 提交树形数据
|
||||
};
|
||||
emit('ok', submitValues);
|
||||
} catch (error) {
|
||||
console.error('Validate Failed:', error);
|
||||
message.error('请检查表单填写是否正确');
|
||||
}
|
||||
};
|
||||
|
||||
const initForm = () => {
|
||||
if (props.initialValues) {
|
||||
const values = props.initialValues;
|
||||
Object.keys(formData).forEach(key => {
|
||||
if (values.hasOwnProperty(key)) {
|
||||
if (key === 'captureDate' && values[key]) {
|
||||
formData[key] = dayjs(values[key]);
|
||||
} else {
|
||||
formData[key] = values[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化树形数据
|
||||
if (values.configNodes && Array.isArray(values.configNodes)) {
|
||||
treeData.value = values.configNodes.map((node: any) => ({
|
||||
...node,
|
||||
children:
|
||||
node.children?.map((child: any) => ({
|
||||
...child
|
||||
})) || []
|
||||
}));
|
||||
} else {
|
||||
treeData.value = [];
|
||||
}
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
Object.assign(formData, defaultFormData);
|
||||
treeData.value = [];
|
||||
addingNewNode.value = false;
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
resetForm();
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVisible => {
|
||||
if (newVisible) {
|
||||
initForm();
|
||||
}
|
||||
},
|
||||
{ immediate: false }
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
localLoading
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.config-tree-container {
|
||||
margin-top: 16px;
|
||||
|
||||
.add-node-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-node-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding-right: 8px;
|
||||
|
||||
.tree-node-title {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tree-node-actions {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
// 确保鼠标悬停时显示操作按钮
|
||||
.tree-node-wrapper:hover {
|
||||
.tree-node-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 子节点添加区域样式
|
||||
.add-child-node-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 0 8px 24px;
|
||||
margin-top: 4px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div class="content-search">
|
||||
<BasicSearch
|
||||
ref="basicSearchRef"
|
||||
:searchList="searchList"
|
||||
:initial-values="initSearchData"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
@values-change="onValuesChange"
|
||||
>
|
||||
<template #actions>
|
||||
<a-tooltip title="新增配置">
|
||||
<a-button @click="props.handleAdd" type="primary"> 新增沿程配置 </a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue";
|
||||
|
||||
interface Props {
|
||||
handleAdd: () => void;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
}>();
|
||||
|
||||
const initSearchData = {
|
||||
configName: "",
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Input",
|
||||
name: "name",
|
||||
label: "沿程配置名称",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "Input",
|
||||
name: "rvnm",
|
||||
label: "所在河段",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit("searchFinish", values);
|
||||
};
|
||||
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
searchData.value = { ...searchData.value, ...allValues };
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
@ -0,0 +1,228 @@
|
||||
<!-- d:\wordpack\WholeProcessPlatform\frontend\src\views\system\map\components\ConfigManagement\index.vue -->
|
||||
<template>
|
||||
<div class="content">
|
||||
预警配置管理
|
||||
<!-- <ConfigManagementSearch
|
||||
ref="configManagementSearch"
|
||||
:handle-add="handleAdd"
|
||||
@reset="handleReset"
|
||||
@search-finish="onSearchFinish"
|
||||
/>
|
||||
<BasicTable
|
||||
ref="basicTable"
|
||||
:columns="columns"
|
||||
:list-url="getAllConfigTree"
|
||||
:search-params="searchParams"
|
||||
>
|
||||
<template #action="{ column, record }">
|
||||
<div class="flex gap-[6px]">
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>编辑</a-button
|
||||
>
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click="handleDelete(record)"
|
||||
>删除</a-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<ConfigManagementForm
|
||||
ref="configManagementForm"
|
||||
v-model:visible="editModalVisible"
|
||||
:initial-values="currentRecord"
|
||||
@cancel="editModalCancel"
|
||||
@ok="handleEditSubmit"
|
||||
/> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick, onMounted } from 'vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import ConfigManagementSearch from './ConfigManagementSearch.vue';
|
||||
import ConfigManagementForm from './ConfigManagementForm.vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import {
|
||||
getAllConfigTree,
|
||||
deleteBaseWbsb,
|
||||
saveBaseWbsb
|
||||
} from '@/api/system/map/ConfigManagement';
|
||||
|
||||
// 表格实例
|
||||
const basicTable = ref<any>(null);
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ text, record, index }) => index + 1
|
||||
},
|
||||
{
|
||||
title: '沿程配置名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '配置编码',
|
||||
key: 'code',
|
||||
dataIndex: 'code',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '所在河段',
|
||||
dataIndex: 'rvnm',
|
||||
key: 'rvnm',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'recordUser',
|
||||
dataIndex: 'recordUser'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'recordTime',
|
||||
dataIndex: 'recordTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'modifyTime',
|
||||
dataIndex: 'modifyTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
width: 360
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
slots: { customRender: 'action' }
|
||||
}
|
||||
];
|
||||
|
||||
// 搜索参数
|
||||
const searchParams = ref({});
|
||||
// 编辑弹窗数据
|
||||
const currentRecord = ref<any | null>(null);
|
||||
const editModalVisible = ref(false);
|
||||
|
||||
// 新增处理
|
||||
const handleAdd = () => {
|
||||
currentRecord.value = null;
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑处理
|
||||
const handleEdit = (record: any) => {
|
||||
currentRecord.value = { ...record };
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除处理
|
||||
const handleDelete = (record: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除选中的记录吗?',
|
||||
zIndex: 2002,
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await deleteBaseWbsb([record.id]);
|
||||
message.success('删除成功');
|
||||
basicTable.value.refresh();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 搜索完成处理
|
||||
const onSearchFinish = (values: any) => {
|
||||
const params = {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
values.parentId
|
||||
? {
|
||||
field: 'parentId',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.parentId
|
||||
}
|
||||
: null,
|
||||
values.name
|
||||
? {
|
||||
field: 'name',
|
||||
operator: 'contains',
|
||||
dataType: 'string',
|
||||
value: values.name
|
||||
}
|
||||
: null
|
||||
].filter(Boolean)
|
||||
};
|
||||
basicTable.value.getList(params);
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
basicTable.value.getList({
|
||||
logic: 'and',
|
||||
filters: []
|
||||
});
|
||||
};
|
||||
|
||||
// 表单取消
|
||||
const editModalCancel = () => {
|
||||
currentRecord.value = null;
|
||||
editModalVisible.value = false;
|
||||
};
|
||||
|
||||
// 表单提交
|
||||
const handleEditSubmit = async (values: any) => {
|
||||
try {
|
||||
let res = await saveBaseWbsb({
|
||||
...currentRecord.value,
|
||||
...values
|
||||
});
|
||||
message.success(`保存成功`);
|
||||
|
||||
editModalVisible.value = false;
|
||||
basicTable.value.refresh();
|
||||
} catch (error) {
|
||||
message.error(`保存失败`);
|
||||
|
||||
editModalVisible.value = false;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const initOption = () => {};
|
||||
onMounted(() => {
|
||||
initOption();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.config-management {
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="isEdit ? '编辑图层' : '新增图层'"
|
||||
v-model:open="modalVisible"
|
||||
:confirm-loading="props.loading"
|
||||
width="600px"
|
||||
:destroy-on-close="true"
|
||||
@cancel="handleCancel"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
name="edit_form"
|
||||
:labelCol="{ span: 5 }"
|
||||
>
|
||||
<a-form-item label="图层名称" name="title">
|
||||
<a-input
|
||||
v-model:value="formData.title"
|
||||
style="width: 100%"
|
||||
placeholder="请输入图层名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="图层编码" name="code">
|
||||
<a-input
|
||||
v-model:value="formData.code"
|
||||
style="width: 100%"
|
||||
placeholder="请输入图层编码"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="图层类型" name="type" v-if="isInterface">
|
||||
<a-select
|
||||
:options="typeOpiton"
|
||||
v-model:value="formData.type"
|
||||
:fieldNames="{
|
||||
label: 'dictName',
|
||||
value: 'itemCode'
|
||||
}"
|
||||
style="width: 100%"
|
||||
placeholder="请输入图层类型"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="标签显示级别" name="treeLevel" v-if="!isInterface">
|
||||
<a-input-number
|
||||
v-model:value="formData.treeLevel"
|
||||
style="width: 100%"
|
||||
placeholder="请输入标签显示级别"
|
||||
:min="0"
|
||||
:max="24"
|
||||
:step="1"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="锚点接口" name="url" v-if="isInterface">
|
||||
<a-input
|
||||
v-model:value="formData.url"
|
||||
style="width: 100%"
|
||||
placeholder="请输入锚点接口"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="接口参数" name="anchorParamJson" v-if="isInterface">
|
||||
<a-textarea
|
||||
:rows="6"
|
||||
v-model:value="formData.anchorParamJson"
|
||||
style="width: 100%"
|
||||
placeholder="请输入接口参数"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="三维接口"
|
||||
name="urlThd"
|
||||
v-if="isInterface && formData.type === 'geojson'"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="formData.urlThd"
|
||||
style="width: 100%"
|
||||
placeholder="请输入三维接口"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="gisJson"
|
||||
name="paramJson"
|
||||
v-if="isInterface && formData.type === 'geojson'"
|
||||
>
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-model:value="formData.paramJson"
|
||||
style="width: 100%"
|
||||
placeholder="请输入gisJson"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="备注"
|
||||
name="description"
|
||||
v-if="!isInterface || formData.type === 'geojson'"
|
||||
>
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-model:value="formData.description"
|
||||
style="width: 100%"
|
||||
placeholder="请输入备注"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import type { Rule } from 'ant-design-vue/es/form';
|
||||
import { getDictItemsByCode } from '@/api/dict';
|
||||
|
||||
// 定义 Props
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
initialValues?: any | null;
|
||||
loading?: boolean;
|
||||
isInterface?: boolean;
|
||||
}
|
||||
// 加载状态
|
||||
const localLoading = ref(false);
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
initialValues: null,
|
||||
loading: false,
|
||||
isInterface: false
|
||||
});
|
||||
const modalVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: val => emit('update:visible', val)
|
||||
});
|
||||
// 定义 Emits
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void;
|
||||
(e: 'cancel'): void;
|
||||
(e: 'ok', values: any, type: string): void;
|
||||
}>();
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref();
|
||||
// 1. 新增用于存储手动验证错误信息的响应式变量
|
||||
const bodyLengthError = ref<string>('');
|
||||
const weightError = ref<string>('');
|
||||
|
||||
// 表单数据模型
|
||||
const defaultFormData = reactive({
|
||||
id: undefined,
|
||||
title: undefined,
|
||||
code: undefined,
|
||||
type: undefined,
|
||||
treeLevel: undefined,
|
||||
description: undefined,
|
||||
parentId: undefined,
|
||||
url: undefined,
|
||||
urlThd: undefined,
|
||||
paramJson: undefined,
|
||||
anchorParamJson: undefined
|
||||
});
|
||||
const typeOpiton = ref<any>([]);
|
||||
const formData: any = reactive({ ...defaultFormData });
|
||||
// 验证规则
|
||||
const rules: Record<string, Rule[]> = {
|
||||
title: [{ required: true, message: '请输入图层名称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入图层编码', trigger: 'blur' }],
|
||||
type: [{ required: true, message: '请输入图层类型', trigger: 'change' }],
|
||||
treeLevel: [
|
||||
{ required: true, message: '请输入标签显示级别', trigger: 'blur' }
|
||||
]
|
||||
};
|
||||
|
||||
// 计算是否为编辑模式
|
||||
const isEdit = computed(() => !!props.initialValues);
|
||||
// 确认操作
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
// 验证表单
|
||||
await formRef.value.validate();
|
||||
// 准备提交数据
|
||||
const submitValues = {
|
||||
...formData
|
||||
};
|
||||
emit('ok', submitValues, 'form');
|
||||
} catch (error) {
|
||||
console.error('Validate Failed:', error);
|
||||
message.error('请检查表单填写是否正确');
|
||||
}
|
||||
};
|
||||
const initForm = () => {
|
||||
if (props.initialValues) {
|
||||
// --- 编辑模式:回填数据 ---
|
||||
const values = props.initialValues;
|
||||
if (props.isInterface) {
|
||||
initType();
|
||||
}
|
||||
// 回填其他普通字段
|
||||
Object.keys(formData).forEach(key => {
|
||||
// 确保字段存在于 initialValues 中再赋值,避免覆盖默认值
|
||||
if (values.hasOwnProperty(key)) {
|
||||
formData[key] = values[key];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
};
|
||||
const initType = () => {
|
||||
getDictItemsByCode({ dictCode: 'LayerTypeCode' }).then(res => {
|
||||
typeOpiton.value = res.data;
|
||||
});
|
||||
};
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
Object.assign(formData, defaultFormData);
|
||||
// 清空手动验证的错误信息
|
||||
bodyLengthError.value = '';
|
||||
weightError.value = '';
|
||||
};
|
||||
|
||||
// 取消操作
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
resetForm();
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVisible => {
|
||||
if (newVisible) {
|
||||
initForm();
|
||||
}
|
||||
},
|
||||
{ immediate: false }
|
||||
);
|
||||
|
||||
// 监听图层类型变化,清空相关字段
|
||||
watch(
|
||||
() => formData.type,
|
||||
(newType, oldType) => {
|
||||
if (oldType && newType !== oldType) {
|
||||
// 类型切换时清空相关字段
|
||||
formData.urlThd = undefined;
|
||||
formData.paramJson = undefined;
|
||||
if (oldType === 'geojson') {
|
||||
formData.description = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
localLoading
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="content-search">
|
||||
<BasicSearch
|
||||
ref="basicSearchRef"
|
||||
:searchList="searchList"
|
||||
:initial-values="initSearchData"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
@values-change="onValuesChange"
|
||||
>
|
||||
<template #actions>
|
||||
<a-tooltip title="新增图层">
|
||||
<a-button @click="props.handleAdd" type="primary"> 新增图层 </a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, watch } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue"; // 确保路径正确
|
||||
|
||||
interface Props {
|
||||
handleAdd: (record: any) => void;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
}>();
|
||||
|
||||
const initSearchData = {
|
||||
title: "",
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Input",
|
||||
name: "title",
|
||||
label: "图层名称",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
// --- Methods ---
|
||||
|
||||
// 2. 搜索表单逻辑
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit("searchFinish", values);
|
||||
};
|
||||
// 值改变
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
searchData.value = { ...searchData.value, ...allValues };
|
||||
};
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -0,0 +1,358 @@
|
||||
<!-- d:\wordpack\WholeProcessPlatform\frontend\src\views\system\map\components\LayerManagement\index.vue -->
|
||||
<template>
|
||||
<div class="content">
|
||||
预警规则
|
||||
<!-- <LayerManagementSearch
|
||||
ref="layerManagementSearch"
|
||||
:handle-add="handleAdd"
|
||||
@reset="handleReset"
|
||||
@search-finish="onSearchFinish"
|
||||
/>
|
||||
<BasicTable
|
||||
ref="basicTable"
|
||||
:columns="columns"
|
||||
:list-url="getAllMapLayerTree"
|
||||
:search-params="searchParams"
|
||||
>
|
||||
<template #action="{ record }">
|
||||
<div class="flex gap-[6px]">
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>编辑</a-button
|
||||
>
|
||||
<a-button
|
||||
v-if="record.children && record.children.length == 0"
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEditInterface(record)"
|
||||
>编辑接口</a-button
|
||||
>
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleAdd(record)"
|
||||
>新增子图层</a-button
|
||||
>
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click="handleDelete(record)"
|
||||
>删除</a-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<template #enable="{ record }">
|
||||
<a-switch
|
||||
:checked="record.enable === 1"
|
||||
@change="(checked: boolean) => handleEnableChange(record, checked)"
|
||||
/>
|
||||
</template>
|
||||
<template #checkable="{ record }">
|
||||
<a-switch
|
||||
:checked="record.checkable === 1"
|
||||
@change="(checked: boolean) => handleCheckableChange(record, checked)"
|
||||
/>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<LayerManagementForm
|
||||
ref="layerManagementForm"
|
||||
v-model:visible="editModalVisible"
|
||||
:initial-values="currentRecord"
|
||||
:is-interface="isInterface"
|
||||
:loading="editLoading"
|
||||
@cancel="editModalCancel"
|
||||
@ok="handleEditSubmit"
|
||||
/> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick } from 'vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import LayerManagementSearch from './LayerManagementSearch.vue';
|
||||
import LayerManagementForm from './LayerManagementForm.vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import {
|
||||
getAllMapLayerTree,
|
||||
saveMapLayer,
|
||||
deleteMapLayer
|
||||
} from '@/api/system/map/LayerManagement';
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: '',
|
||||
dataIndex: '',
|
||||
key: '',
|
||||
width: 50,
|
||||
customRender: () => {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ record, index }: any) => {
|
||||
// 对于树形结构,计算当前记录在其父节点的 children 中的位置
|
||||
// 如果没有 parentId,说明是根节点,需要计算在所有根节点中的序号
|
||||
if (!record.parentId) {
|
||||
// 根节点:计算在 dataSource 中是第几个根节点
|
||||
let rootIndex = 0;
|
||||
for (let i = 0; i < basicTable.value.tableData.length; i++) {
|
||||
const item = basicTable.value.tableData[i];
|
||||
// 只统计根节点(没有 parentId 的节点)
|
||||
if (!item.parentId) {
|
||||
rootIndex++;
|
||||
// 找到当前记录,返回其序号
|
||||
if (
|
||||
item.id === record.id ||
|
||||
(item.key === record.key && item.id === record.id)
|
||||
) {
|
||||
return rootIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rootIndex;
|
||||
} else {
|
||||
// 子节点:在其父节点的 children 中查找索引
|
||||
const findParentAndIndex = (data: any[], parentId: string): number => {
|
||||
for (const item of data) {
|
||||
if (item.key === parentId || item.id === parentId) {
|
||||
// 找到父节点,在其 children 中查找当前记录的位置
|
||||
if (item.children && item.children.length > 0) {
|
||||
const childIndex = item.children.findIndex(
|
||||
(child: any) =>
|
||||
child.key === record.key || child.id === record.id
|
||||
);
|
||||
return childIndex + 1;
|
||||
}
|
||||
}
|
||||
// 递归查找更深层的父节点
|
||||
if (item.children && item.children.length > 0) {
|
||||
const result = findParentAndIndex(item.children, parentId);
|
||||
if (result > 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
return findParentAndIndex(basicTable.value.tableData, record.parentId);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '图层名称',
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '图层编码',
|
||||
dataIndex: 'code',
|
||||
key: 'code',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '标签显示级别',
|
||||
dataIndex: 'treeLevel',
|
||||
key: 'treeLevel',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '是否启用',
|
||||
dataIndex: 'enable',
|
||||
key: 'enable',
|
||||
width: 80,
|
||||
slots: { customRender: 'enable' }
|
||||
},
|
||||
{
|
||||
title: '是否可选',
|
||||
dataIndex: 'checkable',
|
||||
key: 'checkable',
|
||||
width: 80,
|
||||
slots: { customRender: 'checkable' }
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'description',
|
||||
key: 'description'
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'displayRecordUser',
|
||||
dataIndex: 'displayRecordUser'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'recordTime',
|
||||
dataIndex: 'recordTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'modifyTime',
|
||||
dataIndex: 'modifyTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 220,
|
||||
fixed: 'right',
|
||||
slots: { customRender: 'action' }
|
||||
}
|
||||
];
|
||||
// 表格实例
|
||||
const basicTable = ref<any>(null);
|
||||
// 搜索参数
|
||||
const searchParams = ref({});
|
||||
// 编辑弹窗数据
|
||||
const isInterface = ref(false);
|
||||
const editModalVisible = ref(false);
|
||||
const editLoading = ref(false);
|
||||
const parentId = ref<string | null>(null);
|
||||
const currentRecord = ref<any | null>(null);
|
||||
// 添加处理
|
||||
const handleAdd = (record: any) => {
|
||||
currentRecord.value = null;
|
||||
parentId.value = record.id;
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
// 过滤掉值为 '-' 的字段
|
||||
const filterRecord = (record: any) => {
|
||||
const filtered: any = {};
|
||||
const keepKeys = ['code']; // 这些键始终保留
|
||||
Object.keys(record).forEach(key => {
|
||||
if (keepKeys.includes(key) || record[key] !== '-') {
|
||||
filtered[key] = record[key];
|
||||
}
|
||||
});
|
||||
return filtered;
|
||||
};
|
||||
|
||||
// 编辑处理
|
||||
const handleEdit = (record: any) => {
|
||||
console.log('handleEdit', record);
|
||||
parentId.value = null;
|
||||
isInterface.value = false;
|
||||
currentRecord.value = filterRecord(record);
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
// 编辑接口处理
|
||||
const handleEditInterface = (record: any) => {
|
||||
console.log('handleEdit', record);
|
||||
currentRecord.value = filterRecord(record);
|
||||
console.log('handleEdit', currentRecord.value);
|
||||
isInterface.value = true;
|
||||
parentId.value = null;
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除处理
|
||||
const handleDelete = async (record: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除选中的记录吗?',
|
||||
zIndex: 2002,
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await deleteMapLayer([record.id]);
|
||||
message.success('删除成功');
|
||||
basicTable.value.refresh();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索
|
||||
const onSearchFinish = (values: any) => {
|
||||
searchParams.value = values;
|
||||
nextTick(() => {
|
||||
basicTable.value.getList();
|
||||
});
|
||||
};
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchParams.value = {};
|
||||
nextTick(() => {
|
||||
basicTable.value.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
// 是否启用切换处理
|
||||
const handleEnableChange = (record: any, checked: boolean) => {
|
||||
currentRecord.value = filterRecord(record);
|
||||
console.log(currentRecord.value);
|
||||
record.enable = checked ? 1 : 0;
|
||||
handleEditSubmit({ enable: checked ? 1 : 0 }, 'switch');
|
||||
};
|
||||
|
||||
// 是否可选切换处理
|
||||
const handleCheckableChange = (record: any, checked: boolean) => {
|
||||
currentRecord.value = filterRecord(record);
|
||||
record.checkable = checked ? 1 : 0;
|
||||
handleEditSubmit({ checkable: checked ? 1 : 0 }, 'switch');
|
||||
};
|
||||
// 表单
|
||||
const editModalCancel = () => {
|
||||
isInterface.value = false;
|
||||
parentId.value = null;
|
||||
currentRecord.value = null;
|
||||
editModalVisible.value = false;
|
||||
};
|
||||
const handleEditSubmit = async (values: any, type: string) => {
|
||||
editLoading.value = true;
|
||||
try {
|
||||
let res = await saveMapLayer({
|
||||
...currentRecord.value,
|
||||
...values,
|
||||
parentId: parentId.value
|
||||
});
|
||||
if (res.code == 0) {
|
||||
if (type === 'switch') {
|
||||
message.success('修改状态成功');
|
||||
} else {
|
||||
message.success(`保存成功`);
|
||||
}
|
||||
editModalVisible.value = false;
|
||||
basicTable.value.refresh();
|
||||
} else {
|
||||
if (type === 'switch') {
|
||||
message.success('修改状态成功');
|
||||
} else {
|
||||
message.success(`保存成功`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (type === 'switch') {
|
||||
message.error('修改状态失败');
|
||||
} else {
|
||||
message.error(`保存失败`);
|
||||
}
|
||||
} finally {
|
||||
editLoading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.ant-table-cell-with-append) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.ant-table-row-expand-icon) {
|
||||
width: 17px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
</style>
|
||||
89
frontend/src/views/system/alertRules/index.vue
Normal file
89
frontend/src/views/system/alertRules/index.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="map-page">
|
||||
<!-- Ant Design Tabs -->
|
||||
<a-tabs v-model:activeKey="activeTab" class="map-tabs">
|
||||
<a-tab-pane v-for="tab in tabs" :key="tab.value" :tab="tab.name">
|
||||
<!-- 动态加载对应的组件 -->
|
||||
<component :is="getComponent(tab.value)" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineAsyncComponent } from 'vue';
|
||||
|
||||
// Tab 配置
|
||||
const tabs = [
|
||||
{
|
||||
name: '预警规则',
|
||||
value: 'rules'
|
||||
},
|
||||
{
|
||||
name: '预警配置管理',
|
||||
value: 'config'
|
||||
}
|
||||
];
|
||||
|
||||
// 当前激活的 tab
|
||||
const activeTab = ref('rules');
|
||||
|
||||
// 获取对应组件的方法
|
||||
const getComponent = (value: string) => {
|
||||
const componentMap: Record<string, any> = {
|
||||
rules: defineAsyncComponent(
|
||||
() => import('./components/RulesManagement/index.vue')
|
||||
),
|
||||
config: defineAsyncComponent(
|
||||
() => import('./components/ConfigManagement/index.vue')
|
||||
)
|
||||
};
|
||||
|
||||
return componentMap[value] || null;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.map-page {
|
||||
position: relative;
|
||||
z-index: 900;
|
||||
pointer-events: all;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-top: 2px;
|
||||
background-color: #ffffff;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 900;
|
||||
pointer-events: all;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
:deep(.ant-form-item) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-tabs) {
|
||||
height: 100%; // 减去 tabs header 的高度
|
||||
padding: 0 13px;
|
||||
}
|
||||
.map-tabs {
|
||||
:deep(.ant-tabs-content) {
|
||||
height: 100%; // 减去 tabs header 的高度
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-tabpane) {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -26,32 +26,40 @@
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="配置编码" name="code">
|
||||
<a-form-item label="沿程配置编码" name="code">
|
||||
<a-input
|
||||
v-model:value="formData.code"
|
||||
style="width: 100%"
|
||||
placeholder="请输入配置编码"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
placeholder="请输入沿程配置编码"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="所在河段" name="rvnm">
|
||||
<a-input
|
||||
v-model:value="formData.rvnm"
|
||||
<a-form-item label="所在河段" name="rvcd">
|
||||
<a-select
|
||||
v-model:value="formData.rvcd"
|
||||
show-search
|
||||
style="width: 100%"
|
||||
placeholder="请输入所在河段"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
placeholder="请选择所在河段"
|
||||
:options="riverOptions"
|
||||
:filter-option="filterOption"
|
||||
@change="handleRiverSelect"
|
||||
:disabled="isEdit"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="备注" name="description">
|
||||
<a-form-item label="备注" name="remark">
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-model:value="formData.description"
|
||||
v-model:value="formData.remark"
|
||||
style="width: 100%"
|
||||
placeholder="请输入备注"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<div class="config-tree-container">
|
||||
@ -70,7 +78,7 @@
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
{{ item.ennm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
@ -109,14 +117,16 @@
|
||||
placeholder="请选择站点"
|
||||
style="width: 300px"
|
||||
:filter-option="filterOption"
|
||||
@change="handleEditNodeSelect"
|
||||
@change="() => handleEditNodeSelect(dataRef)"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
v-for="item in dataRef.parentId
|
||||
? childStationList
|
||||
: stationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
{{ dataRef.parentId ? item.stnm : item.ennm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
@ -238,7 +248,7 @@
|
||||
@change="handleChildNodeSelect"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
v-for="item in childStationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
@ -280,18 +290,21 @@ import {
|
||||
ArrowUpOutlined,
|
||||
ArrowDownOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
import { getEngInfoDropdown, getAddvcdDropdownByRvcd } from '@/api/select';
|
||||
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
initialValues?: any | null;
|
||||
loading?: boolean;
|
||||
riverOptions?: any[];
|
||||
}
|
||||
|
||||
const localLoading = ref(false);
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
initialValues: null,
|
||||
loading: false
|
||||
loading: false,
|
||||
riverOptions: () => []
|
||||
});
|
||||
|
||||
const modalVisible = computed({
|
||||
@ -311,15 +324,20 @@ const defaultFormData = reactive({
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
code: undefined,
|
||||
rvnm: undefined,
|
||||
description: undefined
|
||||
rvcd: undefined,
|
||||
remark: undefined
|
||||
});
|
||||
const formData: any = reactive({ ...defaultFormData });
|
||||
|
||||
const rules: Record<string, Rule[]> = {
|
||||
name: [{ required: true, message: '请输入沿程配置名称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入配置编码', trigger: 'blur' }],
|
||||
rvnm: [{ required: true, message: '请输入所在河段', trigger: 'blur' }]
|
||||
rvcd: [{ required: true, message: '请选择所在河段', trigger: 'change' }]
|
||||
};
|
||||
|
||||
const handleRiverSelect = async (value: string) => {
|
||||
const res = await getEngInfoDropdown({ rvcd: value });
|
||||
stationList.value = res.data || [];
|
||||
};
|
||||
|
||||
const isEdit = computed(() => !!props.initialValues);
|
||||
@ -331,7 +349,7 @@ const treeData = ref<any[]>([]);
|
||||
const addingNewNode = ref(false);
|
||||
const newNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: ''
|
||||
});
|
||||
|
||||
@ -340,7 +358,7 @@ const addingChildNode = ref(false);
|
||||
const currentParentKey = ref<string | null>(null);
|
||||
const childNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: ''
|
||||
});
|
||||
|
||||
@ -349,18 +367,13 @@ const editingNode = ref(false);
|
||||
const editingNodeKey = ref<string | null>(null);
|
||||
const editNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: '',
|
||||
originalData: null as any
|
||||
});
|
||||
|
||||
// 站点列表(模拟数据,实际应从接口获取)
|
||||
const stationList = ref([
|
||||
{ stcd: '1', stnm: '站点A', sttpName: '类型1' },
|
||||
{ stcd: '2', stnm: '站点B', sttpName: '类型2' },
|
||||
{ stcd: '3', stnm: '站点C', sttpName: '类型1' },
|
||||
{ stcd: '4', stnm: '站点D', sttpName: '类型3' }
|
||||
]);
|
||||
const stationList = ref([]);
|
||||
const childStationList = ref([]);
|
||||
|
||||
// 生成唯一ID
|
||||
let nodeIdCounter = 0;
|
||||
@ -369,19 +382,19 @@ const generateNodeId = () => `node_${Date.now()}_${++nodeIdCounter}`;
|
||||
// 获取节点标题
|
||||
const getNodeTitle = (dataRef: any) => {
|
||||
if (!dataRef.parentId) {
|
||||
// 一级节点:只显示 stnm
|
||||
return dataRef.stnm || '';
|
||||
return dataRef.ennm || '';
|
||||
} else {
|
||||
// 二级节点:显示 stnm + sttpName
|
||||
return `${dataRef.stnm || ''} ${dataRef.sttpName || ''}`;
|
||||
return `${dataRef.ennm || ''} ${dataRef.sttpName || ''}`;
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索过滤
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return (
|
||||
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
);
|
||||
const filterOption = (inputValue: string, option: any) => {
|
||||
const label = option.label || option.name || '';
|
||||
const reachcdName = option.reachcdName || '';
|
||||
const keyword = inputValue || '';
|
||||
|
||||
return label.indexOf(keyword) !== -1 || reachcdName.indexOf(keyword) !== -1;
|
||||
};
|
||||
|
||||
// 判断是否为第一个节点
|
||||
@ -426,10 +439,14 @@ const findNodeByKey = (nodes: any[], key: string): any => {
|
||||
|
||||
// 新增一级节点
|
||||
const handleAdd = () => {
|
||||
if (!formData.rvcd) {
|
||||
message.warning('请先选择所在河段');
|
||||
return;
|
||||
}
|
||||
addingNewNode.value = true;
|
||||
newNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
@ -438,7 +455,7 @@ const handleAdd = () => {
|
||||
const handleNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
newNodeData.value.stnm = station.stnm;
|
||||
newNodeData.value.ennm = station.ennm;
|
||||
newNodeData.value.sttpName = station.sttpName;
|
||||
}
|
||||
};
|
||||
@ -453,7 +470,7 @@ const handleSaveNewNode = () => {
|
||||
const newNode = {
|
||||
key: generateNodeId(),
|
||||
stcd: newNodeData.value.stcd,
|
||||
stnm: newNodeData.value.stnm,
|
||||
ennm: newNodeData.value.ennm,
|
||||
sttpName: newNodeData.value.sttpName,
|
||||
parentId: null,
|
||||
children: []
|
||||
@ -469,27 +486,29 @@ const handleCancelAdd = () => {
|
||||
addingNewNode.value = false;
|
||||
newNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 添加子节点(二级节点)
|
||||
const handleAddChild = (parentData: any) => {
|
||||
const handleAddChild = async (parentData: any) => {
|
||||
addingChildNode.value = true;
|
||||
currentParentKey.value = parentData.key;
|
||||
childNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
const res = await getAddvcdDropdownByRvcd({ stcd: parentData.stcd });
|
||||
childStationList.value = res.data || [];
|
||||
};
|
||||
|
||||
// 选择子节点
|
||||
const handleChildNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
const station = childStationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
childNodeData.value.stnm = station.stnm;
|
||||
childNodeData.value.ennm = station.stnm;
|
||||
childNodeData.value.sttpName = station.sttpName;
|
||||
}
|
||||
};
|
||||
@ -510,7 +529,7 @@ const handleSaveChildNode = () => {
|
||||
const newChild = {
|
||||
key: generateNodeId(),
|
||||
stcd: childNodeData.value.stcd,
|
||||
stnm: childNodeData.value.stnm,
|
||||
ennm: childNodeData.value.ennm,
|
||||
sttpName: childNodeData.value.sttpName,
|
||||
parentId: parent.key,
|
||||
children: []
|
||||
@ -533,29 +552,38 @@ const handleCancelAddChild = () => {
|
||||
currentParentKey.value = null;
|
||||
childNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 编辑节点
|
||||
const handleEditNode = (dataRef: any) => {
|
||||
const handleEditNode = async (dataRef: any) => {
|
||||
editingNode.value = true;
|
||||
editingNodeKey.value = dataRef.key;
|
||||
// 保存原始数据
|
||||
editNodeData.value = {
|
||||
stcd: dataRef.stcd,
|
||||
stnm: dataRef.stnm,
|
||||
ennm: dataRef.ennm,
|
||||
sttpName: dataRef.sttpName,
|
||||
originalData: { ...dataRef }
|
||||
};
|
||||
if (dataRef.parentId) {
|
||||
const parent = findNodeByKey(treeData.value, dataRef.parentId);
|
||||
if (parent) {
|
||||
const res = await getAddvcdDropdownByRvcd({ stcd: parent.stcd });
|
||||
childStationList.value = res.data || [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 选择编辑节点
|
||||
const handleEditNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
const handleEditNodeSelect = (dataRef: any) => {
|
||||
const value = editNodeData.value.stcd;
|
||||
const list = dataRef.parentId ? childStationList.value : stationList.value;
|
||||
const station = list.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
editNodeData.value.stnm = station.stnm;
|
||||
editNodeData.value.ennm = dataRef.parentId ? station.stnm : station.ennm;
|
||||
editNodeData.value.sttpName = station.sttpName;
|
||||
editNodeData.value.stcd = station.stcd;
|
||||
}
|
||||
@ -577,7 +605,7 @@ const handleSaveEditNode = () => {
|
||||
|
||||
// 更新节点数据
|
||||
node.stcd = editNodeData.value.stcd;
|
||||
node.stnm = editNodeData.value.stnm;
|
||||
node.ennm = editNodeData.value.ennm;
|
||||
node.sttpName = editNodeData.value.sttpName;
|
||||
|
||||
editingNode.value = false;
|
||||
@ -591,7 +619,7 @@ const handleCancelEditNode = () => {
|
||||
editingNodeKey.value = null;
|
||||
editNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
ennm: '',
|
||||
sttpName: '',
|
||||
originalData: null
|
||||
};
|
||||
@ -631,7 +659,7 @@ const handleMoveDown = (dataRef: any) => {
|
||||
const handleDeleteNode = (dataRef: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定要删除节点"${dataRef.stnm}"吗?`,
|
||||
content: `确定要删除节点"${dataRef.ennm}"吗?`,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
@ -677,7 +705,7 @@ const handleOk = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const initForm = () => {
|
||||
const initForm = async () => {
|
||||
if (props.initialValues) {
|
||||
const values = props.initialValues;
|
||||
Object.keys(formData).forEach(key => {
|
||||
@ -702,6 +730,12 @@ const initForm = () => {
|
||||
} else {
|
||||
treeData.value = [];
|
||||
}
|
||||
|
||||
// 编辑时调用接口获取一级站点列表
|
||||
if (formData.rvcd) {
|
||||
const res = await getEngInfoDropdown({ rvcd: formData.rvcd });
|
||||
stationList.value = res.data || [];
|
||||
}
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
|
||||
@ -10,7 +10,9 @@
|
||||
>
|
||||
<template #actions>
|
||||
<a-tooltip title="新增配置">
|
||||
<a-button @click="props.handleAdd" type="primary"> 新增沿程配置 </a-button>
|
||||
<a-button @click="props.handleAdd" type="primary">
|
||||
新增沿程配置
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
@ -18,46 +20,52 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue";
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import BasicSearch from '@/components/BasicSearch/index.vue';
|
||||
|
||||
interface Props {
|
||||
handleAdd: () => void;
|
||||
riverOptions: any[];
|
||||
riverOptionsLoad: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
(e: 'reset', values: any): void;
|
||||
(e: 'searchFinish', values: any): void;
|
||||
}>();
|
||||
|
||||
const initSearchData = {
|
||||
configName: "",
|
||||
name: null,
|
||||
rvcd: null
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Input",
|
||||
name: "name",
|
||||
label: "沿程配置名称",
|
||||
type: 'Input',
|
||||
name: 'name',
|
||||
label: '沿程配置名称',
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
allowClear: true
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "Input",
|
||||
name: "rvnm",
|
||||
label: "所在河段",
|
||||
type: 'Select',
|
||||
name: 'rvcd',
|
||||
label: '所在河段',
|
||||
width: 300,
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
allowClear: true
|
||||
},
|
||||
},
|
||||
options: props.riverOptions,
|
||||
loading: props.riverOptionsLoad
|
||||
}
|
||||
]);
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit("searchFinish", values);
|
||||
emit('searchFinish', values);
|
||||
};
|
||||
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
@ -65,11 +73,11 @@ const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
emit('reset', initSearchData);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
emit('searchFinish', initSearchData);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
<ConfigManagementSearch
|
||||
ref="configManagementSearch"
|
||||
:handle-add="handleAdd"
|
||||
:river-options="riverOptions"
|
||||
:river-options-load="riverOptionsLoad"
|
||||
@reset="handleReset"
|
||||
@search-finish="onSearchFinish"
|
||||
/>
|
||||
@ -37,6 +39,8 @@
|
||||
ref="configManagementForm"
|
||||
v-model:visible="editModalVisible"
|
||||
:initial-values="currentRecord"
|
||||
:river-options="riverOptions"
|
||||
:river-options-load="riverOptionsLoad"
|
||||
@cancel="editModalCancel"
|
||||
@ok="handleEditSubmit"
|
||||
/>
|
||||
@ -52,8 +56,10 @@ import { message, Modal } from 'ant-design-vue';
|
||||
import {
|
||||
getAllConfigTree,
|
||||
deleteBaseWbsb,
|
||||
saveBaseWbsb
|
||||
saveBaseWbsbChild,
|
||||
saveBaseWbsbChildDetail
|
||||
} from '@/api/system/map/ConfigManagement';
|
||||
import { getRvcdDropdown } from '@/api/select';
|
||||
|
||||
// 表格实例
|
||||
const basicTable = ref<any>(null);
|
||||
@ -129,9 +135,20 @@ const handleAdd = () => {
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 过滤掉值为 '-' 的字段
|
||||
const filterRecord = (record: any) => {
|
||||
const filtered: any = {};
|
||||
Object.keys(record).forEach(key => {
|
||||
if (record[key] !== '-') {
|
||||
filtered[key] = record[key];
|
||||
}
|
||||
});
|
||||
return filtered;
|
||||
};
|
||||
|
||||
// 编辑处理
|
||||
const handleEdit = (record: any) => {
|
||||
currentRecord.value = { ...record };
|
||||
currentRecord.value = filterRecord(record);
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
@ -144,8 +161,12 @@ const handleDelete = (record: any) => {
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await deleteBaseWbsb([record.id]);
|
||||
message.success('删除成功');
|
||||
basicTable.value.refresh();
|
||||
if (res.code == 0) {
|
||||
message.success('删除成功');
|
||||
basicTable.value.refresh();
|
||||
} else {
|
||||
message.error('删除失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
return;
|
||||
@ -159,12 +180,12 @@ const onSearchFinish = (values: any) => {
|
||||
const params = {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
values.parentId
|
||||
values.rvcd
|
||||
? {
|
||||
field: 'parentId',
|
||||
field: 'rvcd',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.parentId
|
||||
value: values.rvcd
|
||||
}
|
||||
: null,
|
||||
values.name
|
||||
@ -197,23 +218,79 @@ const editModalCancel = () => {
|
||||
// 表单提交
|
||||
const handleEditSubmit = async (values: any) => {
|
||||
try {
|
||||
let res = await saveBaseWbsb({
|
||||
const formData = {
|
||||
...currentRecord.value,
|
||||
...values
|
||||
});
|
||||
message.success(`保存成功`);
|
||||
};
|
||||
delete formData.configNodes;
|
||||
|
||||
editModalVisible.value = false;
|
||||
basicTable.value.refresh();
|
||||
Object.keys(formData).forEach(key => {
|
||||
if (key.includes('-')) {
|
||||
delete formData[key];
|
||||
}
|
||||
});
|
||||
|
||||
let res = await saveBaseWbsbChild(formData);
|
||||
if (res.code == 0) {
|
||||
const alongId = res.data;
|
||||
const treeData = values.configNodes || [];
|
||||
|
||||
if (treeData.length > 0) {
|
||||
const formatTreeData = (
|
||||
nodes: any[],
|
||||
parentId: string | null = null
|
||||
) => {
|
||||
return nodes.map(node => ({
|
||||
alongId,
|
||||
stcd: node.stcd,
|
||||
stnm: node.ennm,
|
||||
sttpName: node.sttpName,
|
||||
parentId: parentId ? parentId : null,
|
||||
children:
|
||||
node.children && node.children.length > 0
|
||||
? formatTreeData(node.children, node.key)
|
||||
: []
|
||||
}));
|
||||
};
|
||||
|
||||
const detailData = formatTreeData(treeData);
|
||||
|
||||
const detailRes = await saveBaseWbsbChildDetail(detailData);
|
||||
if (detailRes.code == 0) {
|
||||
message.success(`保存成功`);
|
||||
editModalVisible.value = false;
|
||||
basicTable.value.refresh();
|
||||
} else {
|
||||
message.error(`保存子节点失败`);
|
||||
}
|
||||
} else {
|
||||
message.success(`保存成功`);
|
||||
editModalVisible.value = false;
|
||||
basicTable.value.refresh();
|
||||
}
|
||||
} else {
|
||||
message.error(`保存失败`);
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(`保存失败`);
|
||||
|
||||
editModalVisible.value = false;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const initOption = () => {};
|
||||
const riverOptions = ref<any>([]);
|
||||
const riverOptionsLoad = ref(false);
|
||||
const initOption = () => {
|
||||
const params = {};
|
||||
riverOptionsLoad.value = true;
|
||||
getRvcdDropdown(params).then((res: any) => {
|
||||
res.data.forEach((item: any) => {
|
||||
item.value = item.rvcd;
|
||||
item.label = item.rvnm;
|
||||
});
|
||||
riverOptions.value = res.data || [];
|
||||
riverOptionsLoad.value = false;
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
initOption();
|
||||
});
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<a-modal
|
||||
:title="isEdit ? '编辑图例数据' : '新增图例数据'"
|
||||
v-model:open="modalVisible"
|
||||
:confirm-loading="localLoading"
|
||||
:confirm-loading="confirmLoading"
|
||||
width="600px"
|
||||
:destroy-on-close="true"
|
||||
@cancel="handleCancel"
|
||||
@ -194,6 +194,10 @@ const modalVisible = computed({
|
||||
set: val => emit('update:visible', val)
|
||||
});
|
||||
|
||||
const confirmLoading = computed(() => {
|
||||
return localLoading.value || props.loading;
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void;
|
||||
(e: 'cancel'): void;
|
||||
@ -276,6 +280,7 @@ const handleLayerSelect = (value: any) => {
|
||||
};
|
||||
|
||||
const handleOk = async () => {
|
||||
localLoading.value = true;
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
// 过滤掉 undefined 的字段,不提交空值
|
||||
@ -329,6 +334,7 @@ const handleOk = async () => {
|
||||
} catch (error) {
|
||||
console.error('Validate Failed:', error);
|
||||
message.error('请检查表单填写是否正确');
|
||||
localLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
@ -350,6 +356,7 @@ const resetForm = () => {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
Object.assign(formData, defaultFormData);
|
||||
localLoading.value = false;
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -358,11 +365,22 @@ const handleCancel = () => {
|
||||
resetForm();
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.loading,
|
||||
newLoading => {
|
||||
if (newLoading) {
|
||||
localLoading.value = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVisible => {
|
||||
if (newVisible) {
|
||||
initForm();
|
||||
} else {
|
||||
localLoading.value = false;
|
||||
}
|
||||
},
|
||||
{ immediate: false }
|
||||
|
||||
@ -66,6 +66,7 @@
|
||||
:LayerOptions="LayerOptions"
|
||||
v-model:visible="editModalVisible"
|
||||
:initial-values="currentRecord"
|
||||
:loading="editLoading"
|
||||
@cancel="editModalCancel"
|
||||
@ok="handleEditSubmit"
|
||||
/>
|
||||
@ -249,6 +250,7 @@ const LegendOptions = ref<any[]>([]);
|
||||
const LayerOptions = ref<any[]>([]);
|
||||
const currentRecord = ref<any | null>(null);
|
||||
const editModalVisible = ref(false);
|
||||
const editLoading = ref(false);
|
||||
const handleAdd = () => {
|
||||
currentRecord.value = null;
|
||||
ensureOptionsLoaded().then(() => {
|
||||
@ -401,11 +403,16 @@ const editModalCancel = () => {
|
||||
|
||||
// 表单提交
|
||||
const handleEditSubmit = async (values: any, type: string) => {
|
||||
editLoading.value = true;
|
||||
try {
|
||||
let res = await saveMapLegend({
|
||||
...currentRecord.value,
|
||||
...values
|
||||
});
|
||||
if (res.code == 1) {
|
||||
message.error('保存失败');
|
||||
return;
|
||||
}
|
||||
if (type === 'switch') {
|
||||
message.success('修改状态成功');
|
||||
} else {
|
||||
@ -421,6 +428,8 @@ const handleEditSubmit = async (values: any, type: string) => {
|
||||
}
|
||||
editModalVisible.value = false;
|
||||
return;
|
||||
} finally {
|
||||
editLoading.value = false;
|
||||
}
|
||||
};
|
||||
const initOption = () => {
|
||||
|
||||
@ -0,0 +1,784 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="isEdit ? '编辑沿程配置' : '新增沿程配置'"
|
||||
v-model:open="modalVisible"
|
||||
:confirm-loading="localLoading"
|
||||
width="1200px"
|
||||
:destroy-on-close="true"
|
||||
ok-text="保存"
|
||||
@cancel="handleCancel"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
name="edit_form"
|
||||
:labelCol="{ span: 5 }"
|
||||
>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="沿程配置名称" name="name">
|
||||
<a-input
|
||||
v-model:value="formData.name"
|
||||
style="width: 100%"
|
||||
placeholder="请输入沿程配置名称"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="配置编码" name="code">
|
||||
<a-input
|
||||
v-model:value="formData.code"
|
||||
style="width: 100%"
|
||||
placeholder="请输入配置编码"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="所在河段" name="rvnm">
|
||||
<a-input
|
||||
v-model:value="formData.rvnm"
|
||||
style="width: 100%"
|
||||
placeholder="请输入所在河段"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="备注" name="description">
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-model:value="formData.description"
|
||||
style="width: 100%"
|
||||
placeholder="请输入备注"
|
||||
/> </a-form-item
|
||||
></a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<div class="config-tree-container">
|
||||
<!-- 新增一级节点区域 -->
|
||||
<div v-if="addingNewNode" class="add-node-row">
|
||||
<a-select
|
||||
v-model:value="newNodeData.stcd"
|
||||
show-search
|
||||
placeholder="请选择站点"
|
||||
style="width: 300px"
|
||||
:filter-option="filterOption"
|
||||
@change="handleNodeSelect"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="handleSaveNewNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button @click="handleCancelAdd" style="margin-left: 8px">
|
||||
<MinusOutlined />
|
||||
</a-button>
|
||||
</div>
|
||||
<a-button v-else class="mb-4" type="primary" @click="handleAdd">
|
||||
<PlusOutlined /> 新增一级节点
|
||||
</a-button>
|
||||
|
||||
<!-- 树形结构 -->
|
||||
<a-tree
|
||||
v-if="treeData.length > 0"
|
||||
:tree-data="treeData"
|
||||
:default-expand-all="false"
|
||||
:selectable="false"
|
||||
block-node
|
||||
style="width: 300px"
|
||||
>
|
||||
<template #title="{ dataRef }">
|
||||
<!-- 编辑状态:只显示编辑区域 -->
|
||||
<div
|
||||
v-if="editingNode && editingNodeKey === dataRef.key"
|
||||
class="add-child-node-row w-[300px]"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="editNodeData.stcd"
|
||||
show-search
|
||||
placeholder="请选择站点"
|
||||
style="width: 300px"
|
||||
:filter-option="filterOption"
|
||||
@change="handleEditNodeSelect"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.stop="handleSaveEditNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button
|
||||
@click.stop="handleCancelEditNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
<MinusOutlined />
|
||||
</a-button>
|
||||
</div>
|
||||
<!-- 非编辑状态:显示正常节点内容 -->
|
||||
<template v-else>
|
||||
<div class="tree-node-wrapper">
|
||||
<span class="tree-node-title"> {{ getNodeTitle(dataRef) }} </span>
|
||||
<div class="tree-node-actions">
|
||||
<!-- 一级节点:支持新增子节点、编辑、排序、删除 -->
|
||||
<template v-if="!dataRef.parentId">
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleAddChild(dataRef)"
|
||||
title="添加子节点"
|
||||
>
|
||||
<PlusOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleEditNode(dataRef)"
|
||||
title="编辑"
|
||||
>
|
||||
<EditOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveUp(dataRef)"
|
||||
title="上移"
|
||||
:disabled="isFirstNode(dataRef)"
|
||||
>
|
||||
<ArrowUpOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveDown(dataRef)"
|
||||
title="下移"
|
||||
:disabled="isLastNode(dataRef)"
|
||||
>
|
||||
<ArrowDownOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click.stop="handleDeleteNode(dataRef)"
|
||||
title="删除"
|
||||
>
|
||||
<DeleteOutlined />
|
||||
</a-button>
|
||||
</template>
|
||||
<!-- 二级节点:只支持编辑、排序、删除 -->
|
||||
<template v-else>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleEditNode(dataRef)"
|
||||
title="编辑"
|
||||
>
|
||||
<EditOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveUp(dataRef)"
|
||||
title="上移"
|
||||
:disabled="isFirstNode(dataRef)"
|
||||
>
|
||||
<ArrowUpOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click.stop="handleMoveDown(dataRef)"
|
||||
title="下移"
|
||||
:disabled="isLastNode(dataRef)"
|
||||
>
|
||||
<ArrowDownOutlined />
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click.stop="handleDeleteNode(dataRef)"
|
||||
title="删除"
|
||||
>
|
||||
<DeleteOutlined />
|
||||
</a-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 子节点添加区域 -->
|
||||
<div
|
||||
v-if="addingChildNode && currentParentKey === dataRef.key"
|
||||
class="add-child-node-row"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="childNodeData.stcd"
|
||||
show-search
|
||||
placeholder="请选择站点"
|
||||
style="width: 300px"
|
||||
:filter-option="filterOption"
|
||||
@change="handleChildNodeSelect"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in stationList"
|
||||
:key="item.stcd"
|
||||
:value="item.stcd"
|
||||
>
|
||||
{{ item.stnm }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-button
|
||||
type="primary"
|
||||
@click.stop="handleSaveChildNode"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button
|
||||
@click.stop="handleCancelAddChild"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
<MinusOutlined />
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-tree>
|
||||
<a-empty v-else description="暂无数据" style="margin-top: 20px" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, watch } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import type { Rule } from 'ant-design-vue/es/form';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
PlusOutlined,
|
||||
MinusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
ArrowUpOutlined,
|
||||
ArrowDownOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
initialValues?: any | null;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const localLoading = ref(false);
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
initialValues: null,
|
||||
loading: false
|
||||
});
|
||||
|
||||
const modalVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: val => emit('update:visible', val)
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void;
|
||||
(e: 'cancel'): void;
|
||||
(e: 'ok', values: any): void;
|
||||
}>();
|
||||
|
||||
const formRef = ref();
|
||||
|
||||
const defaultFormData = reactive({
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
code: undefined,
|
||||
rvnm: undefined,
|
||||
description: undefined
|
||||
});
|
||||
const formData: any = reactive({ ...defaultFormData });
|
||||
|
||||
const rules: Record<string, Rule[]> = {
|
||||
name: [{ required: true, message: '请输入沿程配置名称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入配置编码', trigger: 'blur' }],
|
||||
rvnm: [{ required: true, message: '请输入所在河段', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
const isEdit = computed(() => !!props.initialValues);
|
||||
|
||||
// 树形数据
|
||||
const treeData = ref<any[]>([]);
|
||||
|
||||
// 新增节点相关
|
||||
const addingNewNode = ref(false);
|
||||
const newNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
});
|
||||
|
||||
// 添加子节点相关
|
||||
const addingChildNode = ref(false);
|
||||
const currentParentKey = ref<string | null>(null);
|
||||
const childNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
});
|
||||
|
||||
// 编辑节点相关
|
||||
const editingNode = ref(false);
|
||||
const editingNodeKey = ref<string | null>(null);
|
||||
const editNodeData = ref({
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: '',
|
||||
originalData: null as any
|
||||
});
|
||||
|
||||
// 站点列表(模拟数据,实际应从接口获取)
|
||||
const stationList = ref([
|
||||
{ stcd: '1', stnm: '站点A', sttpName: '类型1' },
|
||||
{ stcd: '2', stnm: '站点B', sttpName: '类型2' },
|
||||
{ stcd: '3', stnm: '站点C', sttpName: '类型1' },
|
||||
{ stcd: '4', stnm: '站点D', sttpName: '类型3' }
|
||||
]);
|
||||
|
||||
// 生成唯一ID
|
||||
let nodeIdCounter = 0;
|
||||
const generateNodeId = () => `node_${Date.now()}_${++nodeIdCounter}`;
|
||||
|
||||
// 获取节点标题
|
||||
const getNodeTitle = (dataRef: any) => {
|
||||
if (!dataRef.parentId) {
|
||||
// 一级节点:只显示 stnm
|
||||
return dataRef.stnm || '';
|
||||
} else {
|
||||
// 二级节点:显示 stnm + sttpName
|
||||
return `${dataRef.stnm || ''} ${dataRef.sttpName || ''}`;
|
||||
}
|
||||
};
|
||||
|
||||
// 搜索过滤
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return (
|
||||
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
);
|
||||
};
|
||||
|
||||
// 判断是否为第一个节点
|
||||
const isFirstNode = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
return siblings.length > 0 && siblings[0].key === dataRef.key;
|
||||
};
|
||||
|
||||
// 判断是否为最后一个节点
|
||||
const isLastNode = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
return (
|
||||
siblings.length > 0 && siblings[siblings.length - 1].key === dataRef.key
|
||||
);
|
||||
};
|
||||
|
||||
// 获取兄弟节点
|
||||
const getSiblings = (dataRef: any) => {
|
||||
if (!dataRef.parentId) {
|
||||
// 一级节点
|
||||
return treeData.value;
|
||||
} else {
|
||||
// 二级节点,找到父节点的 children
|
||||
const parent = findNodeByKey(treeData.value, dataRef.parentId);
|
||||
return parent?.children || [];
|
||||
}
|
||||
};
|
||||
|
||||
// 根据 key 查找节点
|
||||
const findNodeByKey = (nodes: any[], key: string): any => {
|
||||
for (const node of nodes) {
|
||||
if (node.key === key) {
|
||||
return node;
|
||||
}
|
||||
if (node.children && node.children.length > 0) {
|
||||
const found = findNodeByKey(node.children, key);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// 新增一级节点
|
||||
const handleAdd = () => {
|
||||
addingNewNode.value = true;
|
||||
newNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 选择节点
|
||||
const handleNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
newNodeData.value.stnm = station.stnm;
|
||||
newNodeData.value.sttpName = station.sttpName;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存新增节点
|
||||
const handleSaveNewNode = () => {
|
||||
if (!newNodeData.value.stcd) {
|
||||
message.error('请选择站点');
|
||||
return;
|
||||
}
|
||||
|
||||
const newNode = {
|
||||
key: generateNodeId(),
|
||||
stcd: newNodeData.value.stcd,
|
||||
stnm: newNodeData.value.stnm,
|
||||
sttpName: newNodeData.value.sttpName,
|
||||
parentId: null,
|
||||
children: []
|
||||
};
|
||||
|
||||
treeData.value.push(newNode);
|
||||
addingNewNode.value = false;
|
||||
message.success('添加成功');
|
||||
};
|
||||
|
||||
// 取消新增
|
||||
const handleCancelAdd = () => {
|
||||
addingNewNode.value = false;
|
||||
newNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 添加子节点(二级节点)
|
||||
const handleAddChild = (parentData: any) => {
|
||||
addingChildNode.value = true;
|
||||
currentParentKey.value = parentData.key;
|
||||
childNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 选择子节点
|
||||
const handleChildNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
childNodeData.value.stnm = station.stnm;
|
||||
childNodeData.value.sttpName = station.sttpName;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存新增子节点
|
||||
const handleSaveChildNode = () => {
|
||||
if (!childNodeData.value.stcd) {
|
||||
message.error('请选择站点');
|
||||
return;
|
||||
}
|
||||
|
||||
const parent = findNodeByKey(treeData.value, currentParentKey.value!);
|
||||
if (!parent) {
|
||||
message.error('父节点不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
const newChild = {
|
||||
key: generateNodeId(),
|
||||
stcd: childNodeData.value.stcd,
|
||||
stnm: childNodeData.value.stnm,
|
||||
sttpName: childNodeData.value.sttpName,
|
||||
parentId: parent.key,
|
||||
children: []
|
||||
};
|
||||
|
||||
if (!parent.children) {
|
||||
parent.children = [];
|
||||
}
|
||||
// 在子节点列表顶部添加
|
||||
parent.children.unshift(newChild);
|
||||
|
||||
addingChildNode.value = false;
|
||||
currentParentKey.value = null;
|
||||
message.success('添加子节点成功');
|
||||
};
|
||||
|
||||
// 取消添加子节点
|
||||
const handleCancelAddChild = () => {
|
||||
addingChildNode.value = false;
|
||||
currentParentKey.value = null;
|
||||
childNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: ''
|
||||
};
|
||||
};
|
||||
|
||||
// 编辑节点
|
||||
const handleEditNode = (dataRef: any) => {
|
||||
editingNode.value = true;
|
||||
editingNodeKey.value = dataRef.key;
|
||||
// 保存原始数据
|
||||
editNodeData.value = {
|
||||
stcd: dataRef.stcd,
|
||||
stnm: dataRef.stnm,
|
||||
sttpName: dataRef.sttpName,
|
||||
originalData: { ...dataRef }
|
||||
};
|
||||
};
|
||||
|
||||
// 选择编辑节点
|
||||
const handleEditNodeSelect = (value: string) => {
|
||||
const station = stationList.value.find(item => item.stcd === value);
|
||||
if (station) {
|
||||
editNodeData.value.stnm = station.stnm;
|
||||
editNodeData.value.sttpName = station.sttpName;
|
||||
editNodeData.value.stcd = station.stcd;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存编辑节点
|
||||
const handleSaveEditNode = () => {
|
||||
if (!editNodeData.value.stcd) {
|
||||
message.error('请选择站点');
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到要编辑的节点
|
||||
const node = findNodeByKey(treeData.value, editingNodeKey.value!);
|
||||
if (!node) {
|
||||
message.error('节点不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新节点数据
|
||||
node.stcd = editNodeData.value.stcd;
|
||||
node.stnm = editNodeData.value.stnm;
|
||||
node.sttpName = editNodeData.value.sttpName;
|
||||
|
||||
editingNode.value = false;
|
||||
editingNodeKey.value = null;
|
||||
message.success('编辑成功');
|
||||
};
|
||||
|
||||
// 取消编辑节点
|
||||
const handleCancelEditNode = () => {
|
||||
editingNode.value = false;
|
||||
editingNodeKey.value = null;
|
||||
editNodeData.value = {
|
||||
stcd: undefined,
|
||||
stnm: '',
|
||||
sttpName: '',
|
||||
originalData: null
|
||||
};
|
||||
};
|
||||
|
||||
// 上移
|
||||
const handleMoveUp = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
const index = siblings.findIndex(item => item.key === dataRef.key);
|
||||
|
||||
if (index > 0) {
|
||||
// 交换位置
|
||||
[siblings[index - 1], siblings[index]] = [
|
||||
siblings[index],
|
||||
siblings[index - 1]
|
||||
];
|
||||
message.success('上移成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 下移
|
||||
const handleMoveDown = (dataRef: any) => {
|
||||
const siblings = getSiblings(dataRef);
|
||||
const index = siblings.findIndex(item => item.key === dataRef.key);
|
||||
|
||||
if (index < siblings.length - 1) {
|
||||
// 交换位置
|
||||
[siblings[index], siblings[index + 1]] = [
|
||||
siblings[index + 1],
|
||||
siblings[index]
|
||||
];
|
||||
message.success('下移成功');
|
||||
}
|
||||
};
|
||||
|
||||
// 删除节点
|
||||
const handleDeleteNode = (dataRef: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: `确定要删除节点"${dataRef.stnm}"吗?`,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
if (!dataRef.parentId) {
|
||||
// 删除一级节点
|
||||
const index = treeData.value.findIndex(
|
||||
item => item.key === dataRef.key
|
||||
);
|
||||
if (index > -1) {
|
||||
treeData.value.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
// 删除二级节点
|
||||
const parent = findNodeByKey(treeData.value, dataRef.parentId);
|
||||
if (parent && parent.children) {
|
||||
const index = parent.children.findIndex(
|
||||
item => item.key === dataRef.key
|
||||
);
|
||||
if (index > -1) {
|
||||
parent.children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
message.success('删除成功');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
const submitValues = {
|
||||
...formData,
|
||||
captureDate: formData.captureDate
|
||||
? dayjs(formData.captureDate).format('YYYY-MM-DD')
|
||||
: undefined,
|
||||
configNodes: treeData.value // 提交树形数据
|
||||
};
|
||||
emit('ok', submitValues);
|
||||
} catch (error) {
|
||||
console.error('Validate Failed:', error);
|
||||
message.error('请检查表单填写是否正确');
|
||||
}
|
||||
};
|
||||
|
||||
const initForm = () => {
|
||||
if (props.initialValues) {
|
||||
const values = props.initialValues;
|
||||
Object.keys(formData).forEach(key => {
|
||||
if (values.hasOwnProperty(key)) {
|
||||
if (key === 'captureDate' && values[key]) {
|
||||
formData[key] = dayjs(values[key]);
|
||||
} else {
|
||||
formData[key] = values[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化树形数据
|
||||
if (values.configNodes && Array.isArray(values.configNodes)) {
|
||||
treeData.value = values.configNodes.map((node: any) => ({
|
||||
...node,
|
||||
children:
|
||||
node.children?.map((child: any) => ({
|
||||
...child
|
||||
})) || []
|
||||
}));
|
||||
} else {
|
||||
treeData.value = [];
|
||||
}
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
Object.assign(formData, defaultFormData);
|
||||
treeData.value = [];
|
||||
addingNewNode.value = false;
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
resetForm();
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVisible => {
|
||||
if (newVisible) {
|
||||
initForm();
|
||||
}
|
||||
},
|
||||
{ immediate: false }
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
localLoading
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.config-tree-container {
|
||||
margin-top: 16px;
|
||||
|
||||
.add-node-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-node-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding-right: 8px;
|
||||
|
||||
.tree-node-title {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tree-node-actions {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
// 确保鼠标悬停时显示操作按钮
|
||||
.tree-node-wrapper:hover {
|
||||
.tree-node-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 子节点添加区域样式
|
||||
.add-child-node-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 0 8px 24px;
|
||||
margin-top: 4px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div class="content-search">
|
||||
<BasicSearch
|
||||
ref="basicSearchRef"
|
||||
:searchList="searchList"
|
||||
:initial-values="initSearchData"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
@values-change="onValuesChange"
|
||||
>
|
||||
<template #actions>
|
||||
<a-tooltip title="新增配置">
|
||||
<a-button @click="props.handleAdd" type="primary"> 新增沿程配置 </a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue";
|
||||
|
||||
interface Props {
|
||||
handleAdd: () => void;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
}>();
|
||||
|
||||
const initSearchData = {
|
||||
configName: "",
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Input",
|
||||
name: "name",
|
||||
label: "沿程配置名称",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "Input",
|
||||
name: "rvnm",
|
||||
label: "所在河段",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit("searchFinish", values);
|
||||
};
|
||||
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
searchData.value = { ...searchData.value, ...allValues };
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
@ -0,0 +1,228 @@
|
||||
<!-- d:\wordpack\WholeProcessPlatform\frontend\src\views\system\map\components\ConfigManagement\index.vue -->
|
||||
<template>
|
||||
<div class="content">
|
||||
推送配置
|
||||
<!-- <ConfigManagementSearch
|
||||
ref="configManagementSearch"
|
||||
:handle-add="handleAdd"
|
||||
@reset="handleReset"
|
||||
@search-finish="onSearchFinish"
|
||||
/>
|
||||
<BasicTable
|
||||
ref="basicTable"
|
||||
:columns="columns"
|
||||
:list-url="getAllConfigTree"
|
||||
:search-params="searchParams"
|
||||
>
|
||||
<template #action="{ column, record }">
|
||||
<div class="flex gap-[6px]">
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>编辑</a-button
|
||||
>
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click="handleDelete(record)"
|
||||
>删除</a-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<ConfigManagementForm
|
||||
ref="configManagementForm"
|
||||
v-model:visible="editModalVisible"
|
||||
:initial-values="currentRecord"
|
||||
@cancel="editModalCancel"
|
||||
@ok="handleEditSubmit"
|
||||
/> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick, onMounted } from 'vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import ConfigManagementSearch from './ConfigManagementSearch.vue';
|
||||
import ConfigManagementForm from './ConfigManagementForm.vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import {
|
||||
getAllConfigTree,
|
||||
deleteBaseWbsb,
|
||||
saveBaseWbsb
|
||||
} from '@/api/system/map/ConfigManagement';
|
||||
|
||||
// 表格实例
|
||||
const basicTable = ref<any>(null);
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ text, record, index }) => index + 1
|
||||
},
|
||||
{
|
||||
title: '沿程配置名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '配置编码',
|
||||
key: 'code',
|
||||
dataIndex: 'code',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '所在河段',
|
||||
dataIndex: 'rvnm',
|
||||
key: 'rvnm',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'recordUser',
|
||||
dataIndex: 'recordUser'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'recordTime',
|
||||
dataIndex: 'recordTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'modifyTime',
|
||||
dataIndex: 'modifyTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
width: 360
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
slots: { customRender: 'action' }
|
||||
}
|
||||
];
|
||||
|
||||
// 搜索参数
|
||||
const searchParams = ref({});
|
||||
// 编辑弹窗数据
|
||||
const currentRecord = ref<any | null>(null);
|
||||
const editModalVisible = ref(false);
|
||||
|
||||
// 新增处理
|
||||
const handleAdd = () => {
|
||||
currentRecord.value = null;
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑处理
|
||||
const handleEdit = (record: any) => {
|
||||
currentRecord.value = { ...record };
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除处理
|
||||
const handleDelete = (record: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除选中的记录吗?',
|
||||
zIndex: 2002,
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await deleteBaseWbsb([record.id]);
|
||||
message.success('删除成功');
|
||||
basicTable.value.refresh();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 搜索完成处理
|
||||
const onSearchFinish = (values: any) => {
|
||||
const params = {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
values.parentId
|
||||
? {
|
||||
field: 'parentId',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.parentId
|
||||
}
|
||||
: null,
|
||||
values.name
|
||||
? {
|
||||
field: 'name',
|
||||
operator: 'contains',
|
||||
dataType: 'string',
|
||||
value: values.name
|
||||
}
|
||||
: null
|
||||
].filter(Boolean)
|
||||
};
|
||||
basicTable.value.getList(params);
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
basicTable.value.getList({
|
||||
logic: 'and',
|
||||
filters: []
|
||||
});
|
||||
};
|
||||
|
||||
// 表单取消
|
||||
const editModalCancel = () => {
|
||||
currentRecord.value = null;
|
||||
editModalVisible.value = false;
|
||||
};
|
||||
|
||||
// 表单提交
|
||||
const handleEditSubmit = async (values: any) => {
|
||||
try {
|
||||
let res = await saveBaseWbsb({
|
||||
...currentRecord.value,
|
||||
...values
|
||||
});
|
||||
message.success(`保存成功`);
|
||||
|
||||
editModalVisible.value = false;
|
||||
basicTable.value.refresh();
|
||||
} catch (error) {
|
||||
message.error(`保存失败`);
|
||||
|
||||
editModalVisible.value = false;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const initOption = () => {};
|
||||
onMounted(() => {
|
||||
initOption();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.config-management {
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:title="isEdit ? '编辑图层' : '新增图层'"
|
||||
v-model:open="modalVisible"
|
||||
:confirm-loading="props.loading"
|
||||
width="600px"
|
||||
:destroy-on-close="true"
|
||||
@cancel="handleCancel"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
name="edit_form"
|
||||
:labelCol="{ span: 5 }"
|
||||
>
|
||||
<a-form-item label="图层名称" name="title">
|
||||
<a-input
|
||||
v-model:value="formData.title"
|
||||
style="width: 100%"
|
||||
placeholder="请输入图层名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="图层编码" name="code">
|
||||
<a-input
|
||||
v-model:value="formData.code"
|
||||
style="width: 100%"
|
||||
placeholder="请输入图层编码"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="图层类型" name="type" v-if="isInterface">
|
||||
<a-select
|
||||
:options="typeOpiton"
|
||||
v-model:value="formData.type"
|
||||
:fieldNames="{
|
||||
label: 'dictName',
|
||||
value: 'itemCode'
|
||||
}"
|
||||
style="width: 100%"
|
||||
placeholder="请输入图层类型"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="标签显示级别" name="treeLevel" v-if="!isInterface">
|
||||
<a-input-number
|
||||
v-model:value="formData.treeLevel"
|
||||
style="width: 100%"
|
||||
placeholder="请输入标签显示级别"
|
||||
:min="0"
|
||||
:max="24"
|
||||
:step="1"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="锚点接口" name="url" v-if="isInterface">
|
||||
<a-input
|
||||
v-model:value="formData.url"
|
||||
style="width: 100%"
|
||||
placeholder="请输入锚点接口"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="接口参数" name="anchorParamJson" v-if="isInterface">
|
||||
<a-textarea
|
||||
:rows="6"
|
||||
v-model:value="formData.anchorParamJson"
|
||||
style="width: 100%"
|
||||
placeholder="请输入接口参数"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="三维接口"
|
||||
name="urlThd"
|
||||
v-if="isInterface && formData.type === 'geojson'"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="formData.urlThd"
|
||||
style="width: 100%"
|
||||
placeholder="请输入三维接口"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="gisJson"
|
||||
name="paramJson"
|
||||
v-if="isInterface && formData.type === 'geojson'"
|
||||
>
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-model:value="formData.paramJson"
|
||||
style="width: 100%"
|
||||
placeholder="请输入gisJson"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="备注"
|
||||
name="description"
|
||||
v-if="!isInterface || formData.type === 'geojson'"
|
||||
>
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-model:value="formData.description"
|
||||
style="width: 100%"
|
||||
placeholder="请输入备注"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import type { Rule } from 'ant-design-vue/es/form';
|
||||
import { getDictItemsByCode } from '@/api/dict';
|
||||
|
||||
// 定义 Props
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
initialValues?: any | null;
|
||||
loading?: boolean;
|
||||
isInterface?: boolean;
|
||||
}
|
||||
// 加载状态
|
||||
const localLoading = ref(false);
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
initialValues: null,
|
||||
loading: false,
|
||||
isInterface: false
|
||||
});
|
||||
const modalVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: val => emit('update:visible', val)
|
||||
});
|
||||
// 定义 Emits
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', value: boolean): void;
|
||||
(e: 'cancel'): void;
|
||||
(e: 'ok', values: any, type: string): void;
|
||||
}>();
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref();
|
||||
// 1. 新增用于存储手动验证错误信息的响应式变量
|
||||
const bodyLengthError = ref<string>('');
|
||||
const weightError = ref<string>('');
|
||||
|
||||
// 表单数据模型
|
||||
const defaultFormData = reactive({
|
||||
id: undefined,
|
||||
title: undefined,
|
||||
code: undefined,
|
||||
type: undefined,
|
||||
treeLevel: undefined,
|
||||
description: undefined,
|
||||
parentId: undefined,
|
||||
url: undefined,
|
||||
urlThd: undefined,
|
||||
paramJson: undefined,
|
||||
anchorParamJson: undefined
|
||||
});
|
||||
const typeOpiton = ref<any>([]);
|
||||
const formData: any = reactive({ ...defaultFormData });
|
||||
// 验证规则
|
||||
const rules: Record<string, Rule[]> = {
|
||||
title: [{ required: true, message: '请输入图层名称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入图层编码', trigger: 'blur' }],
|
||||
type: [{ required: true, message: '请输入图层类型', trigger: 'change' }],
|
||||
treeLevel: [
|
||||
{ required: true, message: '请输入标签显示级别', trigger: 'blur' }
|
||||
]
|
||||
};
|
||||
|
||||
// 计算是否为编辑模式
|
||||
const isEdit = computed(() => !!props.initialValues);
|
||||
// 确认操作
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
// 验证表单
|
||||
await formRef.value.validate();
|
||||
// 准备提交数据
|
||||
const submitValues = {
|
||||
...formData
|
||||
};
|
||||
emit('ok', submitValues, 'form');
|
||||
} catch (error) {
|
||||
console.error('Validate Failed:', error);
|
||||
message.error('请检查表单填写是否正确');
|
||||
}
|
||||
};
|
||||
const initForm = () => {
|
||||
if (props.initialValues) {
|
||||
// --- 编辑模式:回填数据 ---
|
||||
const values = props.initialValues;
|
||||
if (props.isInterface) {
|
||||
initType();
|
||||
}
|
||||
// 回填其他普通字段
|
||||
Object.keys(formData).forEach(key => {
|
||||
// 确保字段存在于 initialValues 中再赋值,避免覆盖默认值
|
||||
if (values.hasOwnProperty(key)) {
|
||||
formData[key] = values[key];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
};
|
||||
const initType = () => {
|
||||
getDictItemsByCode({ dictCode: 'LayerTypeCode' }).then(res => {
|
||||
typeOpiton.value = res.data;
|
||||
});
|
||||
};
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
Object.assign(formData, defaultFormData);
|
||||
// 清空手动验证的错误信息
|
||||
bodyLengthError.value = '';
|
||||
weightError.value = '';
|
||||
};
|
||||
|
||||
// 取消操作
|
||||
const handleCancel = () => {
|
||||
emit('update:visible', false);
|
||||
emit('cancel');
|
||||
resetForm();
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVisible => {
|
||||
if (newVisible) {
|
||||
initForm();
|
||||
}
|
||||
},
|
||||
{ immediate: false }
|
||||
);
|
||||
|
||||
// 监听图层类型变化,清空相关字段
|
||||
watch(
|
||||
() => formData.type,
|
||||
(newType, oldType) => {
|
||||
if (oldType && newType !== oldType) {
|
||||
// 类型切换时清空相关字段
|
||||
formData.urlThd = undefined;
|
||||
formData.paramJson = undefined;
|
||||
if (oldType === 'geojson') {
|
||||
formData.description = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
localLoading
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="content-search">
|
||||
<BasicSearch
|
||||
ref="basicSearchRef"
|
||||
:searchList="searchList"
|
||||
:initial-values="initSearchData"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
@values-change="onValuesChange"
|
||||
>
|
||||
<template #actions>
|
||||
<a-tooltip title="新增图层">
|
||||
<a-button @click="props.handleAdd" type="primary"> 新增图层 </a-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, watch } from "vue";
|
||||
import BasicSearch from "@/components/BasicSearch/index.vue"; // 确保路径正确
|
||||
|
||||
interface Props {
|
||||
handleAdd: (record: any) => void;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "reset", values: any): void;
|
||||
(e: "searchFinish", values: any): void;
|
||||
}>();
|
||||
|
||||
const initSearchData = {
|
||||
title: "",
|
||||
};
|
||||
|
||||
const searchData = ref<any>({ ...initSearchData });
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: "Input",
|
||||
name: "title",
|
||||
label: "图层名称",
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
// --- Methods ---
|
||||
|
||||
// 2. 搜索表单逻辑
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit("searchFinish", values);
|
||||
};
|
||||
// 值改变
|
||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||
searchData.value = { ...searchData.value, ...allValues };
|
||||
};
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
emit("reset", initSearchData);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
emit("searchFinish", initSearchData);
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -0,0 +1,358 @@
|
||||
<!-- d:\wordpack\WholeProcessPlatform\frontend\src\views\system\map\components\LayerManagement\index.vue -->
|
||||
<template>
|
||||
<div class="content">
|
||||
推送历史
|
||||
<!-- <LayerManagementSearch
|
||||
ref="layerManagementSearch"
|
||||
:handle-add="handleAdd"
|
||||
@reset="handleReset"
|
||||
@search-finish="onSearchFinish"
|
||||
/>
|
||||
<BasicTable
|
||||
ref="basicTable"
|
||||
:columns="columns"
|
||||
:list-url="getAllMapLayerTree"
|
||||
:search-params="searchParams"
|
||||
>
|
||||
<template #action="{ record }">
|
||||
<div class="flex gap-[6px]">
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>编辑</a-button
|
||||
>
|
||||
<a-button
|
||||
v-if="record.children && record.children.length == 0"
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEditInterface(record)"
|
||||
>编辑接口</a-button
|
||||
>
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleAdd(record)"
|
||||
>新增子图层</a-button
|
||||
>
|
||||
<a-button
|
||||
class="!p-0"
|
||||
type="link"
|
||||
size="small"
|
||||
danger
|
||||
@click="handleDelete(record)"
|
||||
>删除</a-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<template #enable="{ record }">
|
||||
<a-switch
|
||||
:checked="record.enable === 1"
|
||||
@change="(checked: boolean) => handleEnableChange(record, checked)"
|
||||
/>
|
||||
</template>
|
||||
<template #checkable="{ record }">
|
||||
<a-switch
|
||||
:checked="record.checkable === 1"
|
||||
@change="(checked: boolean) => handleCheckableChange(record, checked)"
|
||||
/>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<LayerManagementForm
|
||||
ref="layerManagementForm"
|
||||
v-model:visible="editModalVisible"
|
||||
:initial-values="currentRecord"
|
||||
:is-interface="isInterface"
|
||||
:loading="editLoading"
|
||||
@cancel="editModalCancel"
|
||||
@ok="handleEditSubmit"
|
||||
/> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick } from 'vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import LayerManagementSearch from './LayerManagementSearch.vue';
|
||||
import LayerManagementForm from './LayerManagementForm.vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import {
|
||||
getAllMapLayerTree,
|
||||
saveMapLayer,
|
||||
deleteMapLayer
|
||||
} from '@/api/system/map/LayerManagement';
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: '',
|
||||
dataIndex: '',
|
||||
key: '',
|
||||
width: 50,
|
||||
customRender: () => {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 60,
|
||||
align: 'center',
|
||||
customRender: ({ record, index }: any) => {
|
||||
// 对于树形结构,计算当前记录在其父节点的 children 中的位置
|
||||
// 如果没有 parentId,说明是根节点,需要计算在所有根节点中的序号
|
||||
if (!record.parentId) {
|
||||
// 根节点:计算在 dataSource 中是第几个根节点
|
||||
let rootIndex = 0;
|
||||
for (let i = 0; i < basicTable.value.tableData.length; i++) {
|
||||
const item = basicTable.value.tableData[i];
|
||||
// 只统计根节点(没有 parentId 的节点)
|
||||
if (!item.parentId) {
|
||||
rootIndex++;
|
||||
// 找到当前记录,返回其序号
|
||||
if (
|
||||
item.id === record.id ||
|
||||
(item.key === record.key && item.id === record.id)
|
||||
) {
|
||||
return rootIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rootIndex;
|
||||
} else {
|
||||
// 子节点:在其父节点的 children 中查找索引
|
||||
const findParentAndIndex = (data: any[], parentId: string): number => {
|
||||
for (const item of data) {
|
||||
if (item.key === parentId || item.id === parentId) {
|
||||
// 找到父节点,在其 children 中查找当前记录的位置
|
||||
if (item.children && item.children.length > 0) {
|
||||
const childIndex = item.children.findIndex(
|
||||
(child: any) =>
|
||||
child.key === record.key || child.id === record.id
|
||||
);
|
||||
return childIndex + 1;
|
||||
}
|
||||
}
|
||||
// 递归查找更深层的父节点
|
||||
if (item.children && item.children.length > 0) {
|
||||
const result = findParentAndIndex(item.children, parentId);
|
||||
if (result > 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
return findParentAndIndex(basicTable.value.tableData, record.parentId);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '图层名称',
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '图层编码',
|
||||
dataIndex: 'code',
|
||||
key: 'code',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '标签显示级别',
|
||||
dataIndex: 'treeLevel',
|
||||
key: 'treeLevel',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '是否启用',
|
||||
dataIndex: 'enable',
|
||||
key: 'enable',
|
||||
width: 80,
|
||||
slots: { customRender: 'enable' }
|
||||
},
|
||||
{
|
||||
title: '是否可选',
|
||||
dataIndex: 'checkable',
|
||||
key: 'checkable',
|
||||
width: 80,
|
||||
slots: { customRender: 'checkable' }
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'description',
|
||||
key: 'description'
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'displayRecordUser',
|
||||
dataIndex: 'displayRecordUser'
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'recordTime',
|
||||
dataIndex: 'recordTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'modifyTime',
|
||||
dataIndex: 'modifyTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 220,
|
||||
fixed: 'right',
|
||||
slots: { customRender: 'action' }
|
||||
}
|
||||
];
|
||||
// 表格实例
|
||||
const basicTable = ref<any>(null);
|
||||
// 搜索参数
|
||||
const searchParams = ref({});
|
||||
// 编辑弹窗数据
|
||||
const isInterface = ref(false);
|
||||
const editModalVisible = ref(false);
|
||||
const editLoading = ref(false);
|
||||
const parentId = ref<string | null>(null);
|
||||
const currentRecord = ref<any | null>(null);
|
||||
// 添加处理
|
||||
const handleAdd = (record: any) => {
|
||||
currentRecord.value = null;
|
||||
parentId.value = record.id;
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
// 过滤掉值为 '-' 的字段
|
||||
const filterRecord = (record: any) => {
|
||||
const filtered: any = {};
|
||||
const keepKeys = ['code']; // 这些键始终保留
|
||||
Object.keys(record).forEach(key => {
|
||||
if (keepKeys.includes(key) || record[key] !== '-') {
|
||||
filtered[key] = record[key];
|
||||
}
|
||||
});
|
||||
return filtered;
|
||||
};
|
||||
|
||||
// 编辑处理
|
||||
const handleEdit = (record: any) => {
|
||||
console.log('handleEdit', record);
|
||||
parentId.value = null;
|
||||
isInterface.value = false;
|
||||
currentRecord.value = filterRecord(record);
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
// 编辑接口处理
|
||||
const handleEditInterface = (record: any) => {
|
||||
console.log('handleEdit', record);
|
||||
currentRecord.value = filterRecord(record);
|
||||
console.log('handleEdit', currentRecord.value);
|
||||
isInterface.value = true;
|
||||
parentId.value = null;
|
||||
editModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除处理
|
||||
const handleDelete = async (record: any) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除选中的记录吗?',
|
||||
zIndex: 2002,
|
||||
onOk: async () => {
|
||||
try {
|
||||
let res = await deleteMapLayer([record.id]);
|
||||
message.success('删除成功');
|
||||
basicTable.value.refresh();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// 搜索
|
||||
const onSearchFinish = (values: any) => {
|
||||
searchParams.value = values;
|
||||
nextTick(() => {
|
||||
basicTable.value.getList();
|
||||
});
|
||||
};
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchParams.value = {};
|
||||
nextTick(() => {
|
||||
basicTable.value.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
// 是否启用切换处理
|
||||
const handleEnableChange = (record: any, checked: boolean) => {
|
||||
currentRecord.value = filterRecord(record);
|
||||
console.log(currentRecord.value);
|
||||
record.enable = checked ? 1 : 0;
|
||||
handleEditSubmit({ enable: checked ? 1 : 0 }, 'switch');
|
||||
};
|
||||
|
||||
// 是否可选切换处理
|
||||
const handleCheckableChange = (record: any, checked: boolean) => {
|
||||
currentRecord.value = filterRecord(record);
|
||||
record.checkable = checked ? 1 : 0;
|
||||
handleEditSubmit({ checkable: checked ? 1 : 0 }, 'switch');
|
||||
};
|
||||
// 表单
|
||||
const editModalCancel = () => {
|
||||
isInterface.value = false;
|
||||
parentId.value = null;
|
||||
currentRecord.value = null;
|
||||
editModalVisible.value = false;
|
||||
};
|
||||
const handleEditSubmit = async (values: any, type: string) => {
|
||||
editLoading.value = true;
|
||||
try {
|
||||
let res = await saveMapLayer({
|
||||
...currentRecord.value,
|
||||
...values,
|
||||
parentId: parentId.value
|
||||
});
|
||||
if (res.code == 0) {
|
||||
if (type === 'switch') {
|
||||
message.success('修改状态成功');
|
||||
} else {
|
||||
message.success(`保存成功`);
|
||||
}
|
||||
editModalVisible.value = false;
|
||||
basicTable.value.refresh();
|
||||
} else {
|
||||
if (type === 'switch') {
|
||||
message.success('修改状态成功');
|
||||
} else {
|
||||
message.success(`保存成功`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (type === 'switch') {
|
||||
message.error('修改状态失败');
|
||||
} else {
|
||||
message.error(`保存失败`);
|
||||
}
|
||||
} finally {
|
||||
editLoading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.ant-table-cell-with-append) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.ant-table-row-expand-icon) {
|
||||
width: 17px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
</style>
|
||||
89
frontend/src/views/system/pushManagement/index.vue
Normal file
89
frontend/src/views/system/pushManagement/index.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="map-page">
|
||||
<!-- Ant Design Tabs -->
|
||||
<a-tabs v-model:activeKey="activeTab" class="map-tabs">
|
||||
<a-tab-pane v-for="tab in tabs" :key="tab.value" :tab="tab.name">
|
||||
<!-- 动态加载对应的组件 -->
|
||||
<component :is="getComponent(tab.value)" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineAsyncComponent } from 'vue';
|
||||
|
||||
// Tab 配置
|
||||
const tabs = [
|
||||
{
|
||||
name: '推送配置',
|
||||
value: 'config'
|
||||
},
|
||||
{
|
||||
name: '推送历史',
|
||||
value: 'history'
|
||||
}
|
||||
];
|
||||
|
||||
// 当前激活的 tab
|
||||
const activeTab = ref('config');
|
||||
|
||||
// 获取对应组件的方法
|
||||
const getComponent = (value: string) => {
|
||||
const componentMap: Record<string, any> = {
|
||||
config: defineAsyncComponent(
|
||||
() => import('./components/ConfigManagement/index.vue')
|
||||
),
|
||||
history: defineAsyncComponent(
|
||||
() => import('./components/HistoryManagement/index.vue')
|
||||
)
|
||||
};
|
||||
|
||||
return componentMap[value] || null;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.map-page {
|
||||
position: relative;
|
||||
z-index: 900;
|
||||
pointer-events: all;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-top: 2px;
|
||||
background-color: #ffffff;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 900;
|
||||
pointer-events: all;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
:deep(.ant-form-item) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-tabs) {
|
||||
height: 100%; // 减去 tabs header 的高度
|
||||
padding: 0 13px;
|
||||
}
|
||||
.map-tabs {
|
||||
:deep(.ant-tabs-content) {
|
||||
height: 100%; // 减去 tabs header 的高度
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-tabpane) {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user