WholeProcessPlatform/frontend-sjgl/src/views/conventionalHydropower/tempMit/EditDwModal.vue
王兴凯 35db4003a1 将数据管理子系统的页面挪到全过程新框架,自定义筛选列打开时会自己刷新表格一下,
环保数据改为监测数据,操作列去掉,,,把地图配置,无用api,无用代码,组件去掉。
2026-08-28 10:08:15 +08:00

565 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-modal
v-model:open="visible"
:title="isAdd ? '新增低温水减缓设施' : '编辑低温水减缓设施'"
width="60vw"
:confirm-loading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
>
<a-form
ref="formRef"
:model="formData"
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
:rules="formRules"
class="max-h-[70vh] overflow-y-auto pr-4"
>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="设施编码" name="stcd">
<a-input
v-model:value="formData.stcd"
placeholder="请输入设施编码"
:disabled="!isAdd"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="设施名称" name="stnm">
<a-input
v-model:value="formData.stnm"
placeholder="请输入设施名称"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="设施类型" name="sttp">
<a-select
v-model:value="formData.sttp"
placeholder="请选择设施类型"
allow-clear
show-search
:filter-option="filterOption"
>
<a-select-option
v-for="item in sttpOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>{{ item.label }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="站址" name="stlc">
<a-input
v-model:value="formData.stlc"
placeholder="请输入站址"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="经度(°)" name="lgtd">
<a-input-number v-model:value="formData.lgtd" placeholder="请输入" :precision="6" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="纬度(°)" name="lttd">
<a-input-number v-model:value="formData.lttd" placeholder="请输入" :precision="6" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="水电基地" name="baseId">
<a-select
v-model:value="formData.baseId"
placeholder="请选择水电基地"
allow-clear
show-search
:filter-option="filterOption"
>
<a-select-option
v-for="item in baseNameOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>{{ item.label }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="所属电站" name="rstcd">
<a-select
v-model:value="formData.rstcd"
placeholder="请选择所属电站"
allow-clear
show-search
:loading="engLoading"
:filter-option="filterOption"
>
<a-select-option
v-for="item in engInfoOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>{{ item.label }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="是否启用" name="usfl">
<a-select
v-model:value="formData.usfl"
placeholder="请选择是否启用"
allow-clear
>
<a-select-option :value="1">启用</a-select-option>
<a-select-option :value="0">禁用</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="建成日期" name="jcdt">
<a-date-picker
v-model:value="formData.jcdt"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择建成日期"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="总投资(亿元)" name="inv">
<a-input-number
v-model:value="formData.inv"
placeholder="请输入投资"
style="width: 100%"
:min="0"
:precision="4"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="监测频次(min)" name="dtfrqcy">
<a-input-number
v-model:value="formData.dtfrqcy"
placeholder="请输入监测频次"
style="width: 100%"
:min="0"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="是否有调度规程" name="dispatch">
<a-select
v-model:value="formData.dispatch"
placeholder="请选择"
allow-clear
>
<a-select-option :value="1">有</a-select-option>
<a-select-option :value="0">无</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="调度规程描述" name="dispatchDes">
<a-input
v-model:value="formData.dispatchDes"
placeholder="请输入调度规程描述"
style="width: 100%"
/>
</a-form-item>
</a-col>
<!-- <a-col :span="24">
<a-form-item label="简介" name="introduce" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-textarea
v-model:value="formData.introduce"
placeholder="请输入简介"
:maxlength="1000"
show-count
:rows="2"
/>
</a-form-item>
</a-col> -->
<a-col :span="24">
<a-form-item label="备注" name="remark" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-textarea
v-model:value="formData.remark"
placeholder="请输入备注"
:maxlength="150"
show-count
:rows="2"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-modal>
<ConfirmModal
v-model:open="confirmModalVisible"
:diff-list="diffList"
:confirm-loading="confirmLoading"
@confirm="handleConfirmSubmit"
@cancel="handleConfirmCancel"
/>
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue';
import { message } from 'ant-design-vue';
import { addDwInfo, updateDwInfo } from '@/api/DataQueryMenuModule';
import { getEngInfoDropdown } from '@/api/select';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { sttpGetKendoList } from '@/api/system/map/ConfigManagement';
import ConfirmModal from '@/components/ConfirmModal/index.vue';
import { useDraggable } from '@/utils/drag';
const props = defineProps<{
open: boolean;
record?: any;
isAdd?: boolean;
}>();
const emit = defineEmits(['update:open', 'success']);
const jidiSelectEventStore = useJidiSelectEventStore();
const visible = computed({
get: () => props.open,
set: val => emit('update:open', val)
});
useDraggable(visible, { boundary: true, resetOnOpen: true });
const formRef = ref();
const confirmLoading = ref(false);
const formData = ref<any>({});
const originalRecord = ref<any>({});
const originalLabels = ref<Record<string, string>>({});
const confirmModalVisible = ref(false);
const formRules = ref<any>({
stcd: [{ required: true, message: '请输入设施编码', trigger: 'blur' }],
stnm: [{ required: true, message: '请输入设施名称', trigger: 'blur' }],
sttp: [{ required: true, message: '请选择设施类型', trigger: 'change' }]
});
// 下拉选项
const engInfoOptions = ref<any[]>([]);
const sttpOptions = ref<any[]>([]);
const baseNameOptions = computed(() =>
jidiSelectEventStore.jidiData
.filter((item: any) => item.wbsCode !== 'all')
.map((item: any) => ({
label: item.wbsName,
value: item.wbsCode
}))
);
const engLoading = ref(false);
// 字段名 → 中文名映射
const fieldLabelMap: Record<string, string> = {
stcd: '设施编码',
stnm: '设施名称',
sttp: '设施类型',
stlc: '站址',
lgtd: '经度(°)',
lttd: '纬度(°)',
baseId: '水电基地',
rstcd: '所属电站',
usfl: '是否启用',
jcdt: '建成日期',
inv: '总投资',
dtfrqcy: '监测频次',
dispatch: '是否有调度规程',
dispatchDes: '调度规程描述',
introduce: '简介',
remark: '备注'
};
// select 选项映射
const selectOptionsMap: Record<string, () => any[]> = {
sttp: () => sttpOptions.value,
usfl: () => [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 }
],
dispatch: () => [
{ label: '有', value: 1 },
{ label: '无', value: 0 }
],
baseId: () => baseNameOptions.value,
rstcd: () => engInfoOptions.value
};
// 按修改顺序记录变更
const changeOrder = ref<
{ field: string; label: string; oldValue: string; newValue: string }[]
>([]);
const diffList = changeOrder;
const resolveSelectLabel = (field: string, value: any): string => {
if (value === null || value === undefined || value === '') return '空';
const getOptions = selectOptionsMap[field];
if (getOptions) {
const opt = getOptions().find(
(o: any) => String(o.value) === String(value)
);
if (opt) return opt.label;
}
return String(value);
};
// 解析原始值的显示名rstcd 直接用 record 自带的电站名称 ennm不依赖异步选项
const resolveOriginalLabel = (field: string): string => {
const original = originalRecord.value;
if (field === 'rstcd') {
const ennm = original.ennm || original.rstcdName;
if (ennm) return String(ennm);
}
return resolveSelectLabel(field, original[field]);
};
const filterOption = (inputValue: string, option: any) => {
const label = option.label || option.value;
const keyword = inputValue || '';
return label.includes(keyword);
};
// 监听 formData 变化
watch(
() => formData.value,
newData => {
const original = originalRecord.value;
for (const key in newData) {
const oldVal = original[key];
const newVal = newData[key];
if (oldVal !== newVal) {
const existingIdx = changeOrder.value.findIndex(c => c.field === key);
const oldNorm =
oldVal === null || oldVal === undefined || oldVal === '-'
? null
: oldVal;
const newNorm = newVal === null || newVal === undefined ? null : newVal;
if (oldNorm === newNorm) continue;
if (
oldNorm !== null &&
newNorm !== null &&
!isNaN(Number(oldNorm)) &&
!isNaN(Number(newNorm)) &&
Number(oldNorm) === Number(newNorm)
)
continue;
const isSelect = !!selectOptionsMap[key];
const oldDisplay = isSelect
? (originalLabels.value[key] ?? resolveSelectLabel(key, oldNorm))
: oldNorm === null
? '空'
: String(oldNorm);
const newDisplay = isSelect
? resolveSelectLabel(key, newNorm)
: newNorm === null
? '空'
: String(newNorm);
const entry = {
field: key,
label: fieldLabelMap[key] || key,
oldValue: oldDisplay,
newValue: newDisplay
};
if (existingIdx >= 0) {
changeOrder.value[existingIdx] = entry;
} else {
changeOrder.value.push(entry);
}
} else {
changeOrder.value = changeOrder.value.filter(c => c.field !== key);
}
}
},
{ deep: true }
);
// 监听 record 变化
const isInitLoading = ref(false);
watch(
() => props.record,
newRecord => {
if (newRecord) {
isInitLoading.value = true;
const converted = { ...newRecord };
// 将 "-" 还原为 null避免 date-picker 显示 Invalid Date
for (const key in converted) {
if (converted[key] === '-') {
converted[key] = null;
}
}
originalRecord.value = { ...converted };
formData.value = { ...converted };
changeOrder.value = [];
// 编辑时必定加载电站选项,保证 rstcd 回显与 diff 解析
loadEngOptions(converted.baseId || undefined);
// 提前解析 select 字段的原始显示名,防止联动刷新选项后丢失 label
const labels: Record<string, string> = {};
for (const key in converted) {
if (selectOptionsMap[key]) {
labels[key] = resolveOriginalLabel(key);
}
}
originalLabels.value = labels;
// 表单填充完成后自动复位标志,避免残留 true 导致后续切换流域不清空电站
nextTick(() => {
isInitLoading.value = false;
});
}
},
{ deep: true }
);
// 选项加载完成后重新解析原始显示名,避免 record 加载时选项未就绪导致存成 code
watch(
[baseNameOptions, engInfoOptions, sttpOptions],
() => {
const original = originalRecord.value;
if (!original || Object.keys(original).length === 0) return;
const labels: Record<string, string> = {};
for (const key in original) {
if (selectOptionsMap[key]) {
labels[key] = resolveOriginalLabel(key);
}
}
originalLabels.value = labels;
}
);
const loadEngOptions = async (baseId?: string) => {
engLoading.value = true;
try {
const params = baseId ? { baseId } : {};
const res = await getEngInfoDropdown(params);
engInfoOptions.value = (res.data || []).map((item: any) => ({ label: item.ennm, value: item.stcd }));
} catch (error) {
console.error('获取电站列表失败:', error);
} finally {
engLoading.value = false;
}
};
// 加载下拉数据
const loadDropdownData = () => {
// 加载设施类型
sttpGetKendoList({
filter: {
logic: 'and',
filters: [
{
field: 'sttpCode',
operator: 'in',
dataType: 'string',
value: ["DW", "DW_1", "DW_2", "DW_3", "DW_4", "DW_5", "DW_6", "DW_9"]
}
]
}
}).then(res => {
sttpOptions.value = (res.data?.data || []).map((item: any) => ({
label: item.sttpName,
value: item.sttpCode
}));
});
// 从 store 获取水电基地数据computed 已自动响应,无需手动赋值)
};
watch(() => formData.value?.baseId, (newBaseId) => {
// record 加载时已在 record watch 中加载过电站选项,这里仅跳过清空
if (isInitLoading.value) {
return;
}
formData.value.rstcd = undefined;
loadEngOptions(newBaseId || undefined);
});
watch(
() => props.open,
val => {
if (val) {
loadDropdownData();
if (props.isAdd) {
formData.value = {};
originalRecord.value = {};
changeOrder.value = [];
loadEngOptions();
}
}
}
);
const handleOk = async () => {
try {
await formRef.value?.validateFields();
if (!props.isAdd && changeOrder.value.length === 0) {
message.info('未检测到任何修改');
return;
}
confirmModalVisible.value = true;
} catch (error) {
console.error('验证失败:', error);
}
};
const handleConfirmSubmit = async (source: string) => {
confirmLoading.value = true;
try {
const engInfo: Record<string, any> = {};
let res: any;
if (props.isAdd) {
Object.assign(engInfo, formData.value);
res = await addDwInfo({
engInfo,
source: source.trim() || '新增'
});
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
// select 清空后值为 undefined/null统一转为空字符串避免序列化时字段被省略
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateDwInfo({
engInfo,
source: source.trim() || '编辑'
});
}
if (res?.code == 0 || res?.success) {
message.success(props.isAdd ? '新增成功' : '编辑成功');
confirmModalVisible.value = false;
visible.value = false;
emit('success');
} else {
message.error(res?.msg || (props.isAdd ? '新增失败' : '编辑失败'));
}
} catch (error) {
message.error('提交失败,请重试');
} finally {
confirmLoading.value = false;
}
};
const handleConfirmCancel = () => {
confirmModalVisible.value = false;
};
const handleCancel = () => {
visible.value = false;
confirmModalVisible.value = false;
formRef.value?.resetFields();
};
</script>