2026-07-21 18:38:17 +08:00
|
|
|
<template>
|
|
|
|
|
<a-modal
|
|
|
|
|
v-model:open="visible"
|
|
|
|
|
:title="isAdd ? '新增栖息地' : '编辑栖息地'"
|
|
|
|
|
width="80vw"
|
|
|
|
|
: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="8">
|
|
|
|
|
<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="8">
|
|
|
|
|
<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="8">
|
|
|
|
|
<a-form-item label="站址" name="stlc">
|
|
|
|
|
<a-input v-model:value="formData.stlc" placeholder="请输入站址" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
2026-07-22 17:43:09 +08:00
|
|
|
<a-col :span="8">
|
|
|
|
|
<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="8">
|
|
|
|
|
<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>
|
2026-07-21 18:38:17 +08:00
|
|
|
<a-col :span="8">
|
|
|
|
|
<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="8">
|
|
|
|
|
<a-form-item label="所属电站" name="rstcd">
|
2026-07-22 17:43:09 +08:00
|
|
|
<a-select v-model:value="formData.rstcd" placeholder="请选择所属电站" allow-clear show-search :loading="engLoading" :filter-option="filterOption">
|
2026-07-21 18:38:17 +08:00
|
|
|
<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="8">
|
|
|
|
|
<a-form-item label="保护对象" name="bhdx">
|
|
|
|
|
<a-input v-model:value="formData.bhdx" placeholder="请输入保护对象" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :span="8">
|
|
|
|
|
<a-form-item label="保护范围" name="bhfw">
|
|
|
|
|
<a-input v-model:value="formData.bhfw" placeholder="请输入保护范围" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :span="8">
|
|
|
|
|
<a-form-item label="保护核心长度(km)" name="bhhxcd">
|
|
|
|
|
<a-input-number v-model:value="formData.bhhxcd" placeholder="请输入" :precision="2" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :span="8">
|
|
|
|
|
<a-form-item label="保护河流" name="bhhl">
|
|
|
|
|
<a-input v-model:value="formData.bhhl" placeholder="请输入保护河流" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :span="8">
|
|
|
|
|
<a-form-item label="保护河段" name="bhhd">
|
|
|
|
|
<a-input v-model:value="formData.bhhd" placeholder="请输入保护河段" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :span="8">
|
|
|
|
|
<a-form-item label="保护措施" name="bhcs">
|
|
|
|
|
<a-input v-model:value="formData.bhcs" placeholder="请输入保护措施" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :span="8">
|
|
|
|
|
<a-form-item label="保护方式" name="bhfs">
|
|
|
|
|
<a-input v-model:value="formData.bhfs" placeholder="请输入保护方式" style="width: 100%" />
|
|
|
|
|
</a-form-item>
|
|
|
|
|
</a-col>
|
|
|
|
|
<a-col :span="8">
|
|
|
|
|
<a-form-item label="投资(亿元)" name="inv">
|
|
|
|
|
<a-input-number v-model:value="formData.inv" placeholder="请输入" :precision="3" style="width: 100%" />
|
|
|
|
|
</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 } from 'vue';
|
|
|
|
|
import { message } from 'ant-design-vue';
|
|
|
|
|
import { addFhInfo, updateFhInfo } from '@/api/DataQueryMenuModule';
|
|
|
|
|
import { getEngInfoDropdown } from '@/api/select';
|
|
|
|
|
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
|
|
|
|
|
import ConfirmModal from '@/components/ConfirmModal/index.vue';
|
2026-07-22 09:06:17 +08:00
|
|
|
import { useDraggable } from '@/utils/drag';
|
2026-07-21 18:38:17 +08:00
|
|
|
|
|
|
|
|
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) });
|
2026-07-22 09:06:17 +08:00
|
|
|
useDraggable(visible, { boundary: true, resetOnOpen: true });
|
2026-07-21 18:38:17 +08:00
|
|
|
|
|
|
|
|
const formRef = ref();
|
|
|
|
|
const confirmLoading = ref(false);
|
|
|
|
|
const formData = ref<any>({});
|
|
|
|
|
const originalRecord = ref<any>({});
|
|
|
|
|
const confirmModalVisible = ref(false);
|
|
|
|
|
|
|
|
|
|
const formRules = ref<any>({
|
|
|
|
|
stcd: [{ required: true, message: '请输入栖息地站码', trigger: 'blur' }],
|
|
|
|
|
stnm: [{ required: true, message: '请输入栖息地名称', trigger: 'blur' }]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const engInfoOptions = ref<any[]>([]);
|
|
|
|
|
|
|
|
|
|
const baseNameOptions = ref<any[]>(
|
|
|
|
|
jidiSelectEventStore.jidiData
|
|
|
|
|
.filter((item: any) => item.wbsCode !== 'all')
|
|
|
|
|
.map((item: any) => ({ label: item.wbsName, value: item.wbsCode }))
|
|
|
|
|
);
|
|
|
|
|
|
2026-07-22 17:43:09 +08:00
|
|
|
const engLoading = ref(false);
|
|
|
|
|
|
2026-07-21 18:38:17 +08:00
|
|
|
const fieldLabelMap: Record<string, string> = {
|
|
|
|
|
stcd: '栖息地站码', stnm: '栖息地名称', stlc: '站址', baseId: '水电基地',
|
|
|
|
|
rstcd: '所属电站', bhdx: '保护对象', bhfw: '保护范围',
|
|
|
|
|
bhhxcd: '保护核心长度(km)',
|
2026-07-22 17:43:09 +08:00
|
|
|
bhhl: '保护河流', bhhd: '保护河段', bhcs: '保护措施', bhfs: '保护方式', inv: '投资(亿元)', lgtd: '经度(°)', lttd: '纬度(°)'
|
2026-07-21 18:38:17 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const selectOptionsMap: Record<string, () => any[]> = {
|
|
|
|
|
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);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const filterOption = (inputValue: string, option: any) => {
|
|
|
|
|
const label = option.label || option.value;
|
|
|
|
|
return label.includes(inputValue || '');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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 ? 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 });
|
|
|
|
|
|
|
|
|
|
watch(() => props.record, newRecord => {
|
|
|
|
|
if (newRecord) {
|
|
|
|
|
const converted = { ...newRecord };
|
|
|
|
|
originalRecord.value = { ...converted };
|
|
|
|
|
formData.value = { ...converted };
|
|
|
|
|
changeOrder.value = [];
|
|
|
|
|
}
|
|
|
|
|
}, { deep: true });
|
|
|
|
|
|
2026-07-22 17:43:09 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-07-21 18:38:17 +08:00
|
|
|
const loadDropdownData = () => {
|
|
|
|
|
baseNameOptions.value = jidiSelectEventStore.jidiData
|
|
|
|
|
.filter((item: any) => item.wbsCode !== 'all')
|
|
|
|
|
.map((item: any) => ({ label: item.wbsName, value: item.wbsCode }));
|
|
|
|
|
};
|
|
|
|
|
|
2026-07-22 17:43:09 +08:00
|
|
|
watch(() => formData.value?.baseId, (newBaseId) => {
|
|
|
|
|
formData.value.rstcd = undefined;
|
|
|
|
|
loadEngOptions(newBaseId || undefined);
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-21 18:38:17 +08:00
|
|
|
watch(() => props.open, val => {
|
|
|
|
|
if (val) {
|
|
|
|
|
loadDropdownData();
|
2026-07-22 17:43:09 +08:00
|
|
|
if (props.isAdd) { formData.value = {}; originalRecord.value = {}; changeOrder.value = []; loadEngOptions(); }
|
2026-07-21 18:38:17 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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 addFhInfo({ engInfo, source: source.trim() || '新增' });
|
|
|
|
|
} else {
|
|
|
|
|
engInfo.stcd = formData.value.stcd;
|
|
|
|
|
changeOrder.value.forEach(item => { engInfo[item.field] = formData.value[item.field]; });
|
|
|
|
|
res = await updateFhInfo({ 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>
|