项目bug更改
This commit is contained in:
parent
35db4003a1
commit
6ec994502a
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -405,6 +405,7 @@ const emit = defineEmits<{
|
||||
(e: 'finish', values: any): void;
|
||||
(e: 'valuesChange', changedValues: any, allValues: any): void;
|
||||
(e: 'reset'): void;
|
||||
(e: 'initDone', values: any): void;
|
||||
}>();
|
||||
|
||||
const formRef = ref<any>();
|
||||
@ -427,7 +428,7 @@ const validSearchList = computed(() => {
|
||||
});
|
||||
|
||||
// --- 初始化逻辑 ---
|
||||
const initForm = () => {
|
||||
const initForm = async () => {
|
||||
const initial = JSON.parse(JSON.stringify(props.initialValues || {}));
|
||||
|
||||
// 1. 清空 formData
|
||||
@ -437,7 +438,7 @@ const initForm = () => {
|
||||
Object.assign(formData, initial);
|
||||
|
||||
// 3. 过滤掉 searchList 中为 false/null/undefined 的项,并生成规则
|
||||
validSearchList.value.forEach(item => {
|
||||
for (const item of validSearchList.value) {
|
||||
if (item.type == 'waterStation') {
|
||||
// 下拉菜单
|
||||
shuJuTianBaoStore.getBaseOption();
|
||||
@ -445,15 +446,23 @@ const initForm = () => {
|
||||
shuJuTianBaoStore.getEngOption(formData.rvcd,'rvcd');
|
||||
}
|
||||
if (item.type == 'jidiData') {
|
||||
shuJuTianBaoStore.getBaseOption();
|
||||
shuJuTianBaoStore.getEngOption(formData[item.name] || 'all','baseId');
|
||||
// 先把默认值摘下并清空显示,等基地数据加载完、判断有无值后再回填,避免 'all' 闪现
|
||||
const initialBaseValue = formData[item.name];
|
||||
formData[item.name] = null;
|
||||
await shuJuTianBaoStore.getBaseOption();
|
||||
const hasBaseValue = shuJuTianBaoStore.baseOption.length > 0;
|
||||
if (hasBaseValue) {
|
||||
// 有值才补默认值并加载电站;无值保持 null
|
||||
formData[item.name] = initialBaseValue || 'all';
|
||||
shuJuTianBaoStore.getEngOption(formData[item.name],'baseId');
|
||||
}
|
||||
}
|
||||
if (item.fieldProps?.required) {
|
||||
rules[item.name] = [
|
||||
{ required: true, message: `${item.label}不能为空`, trigger: 'blur' }
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -501,8 +510,10 @@ const stcdIdChange = (value: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initForm();
|
||||
onMounted(async () => {
|
||||
await initForm();
|
||||
// 初始化完成(含基地数据加载)后通知外部,供等待时序的页面发起首次查询
|
||||
emit('initDone', { ...formData });
|
||||
});
|
||||
|
||||
watch(
|
||||
|
||||
@ -176,11 +176,11 @@ const columnMetaMap: Record<string, any> = {
|
||||
addvcdName: { width: 150, sort: true, ellipsis: true },
|
||||
stlc: { width: 200, sort: true, ellipsis: true },
|
||||
baseName: { width: 120, ellipsis: true },
|
||||
jcdt: { width: 120, sort: true, ellipsis: true, customRender: dateRender },
|
||||
jcdt: { width: 180, sort: true, ellipsis: true, customRender: dateRender },
|
||||
piodt: { width: 160, sort: true, ellipsis: true, customRender: dateRender },
|
||||
aiodt: { width: 150, sort: true, ellipsis: true, customRender: dateRender },
|
||||
bldsttCcodeName: { width: 100, sort: true, ellipsis: true },
|
||||
hynm: { width: 150, sort: true, ellipsis: true },
|
||||
hynm: { width: 240, sort: true, ellipsis: true },
|
||||
topHynm: { width: 150, sort: true, ellipsis: true },
|
||||
nrupar: { width: 180, sort: true },
|
||||
dstcrvr: { width: 150, sort: true },
|
||||
@ -243,7 +243,7 @@ const columnMetaMap: Record<string, any> = {
|
||||
yrge: { width: 200, sort: true },
|
||||
ushr: { width: 150, sort: true },
|
||||
k: { width: 150, sort: true, ellipsis: true },
|
||||
dmtp: { width: 100, sort: true, ellipsis: true },
|
||||
dmtp: { width: 150, sort: true, ellipsis: true },
|
||||
dmcrel: { width: 130, sort: true },
|
||||
mxdmhg: { width: 120, sort: true },
|
||||
dmlen: { width: 130, sort: true },
|
||||
|
||||
@ -103,7 +103,7 @@
|
||||
style="width: 100%"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="opt in shuJuTianBaoStore.lyOption"
|
||||
v-for="opt in fishLyOption"
|
||||
:key="opt.rvcd"
|
||||
:value="opt.rvcd"
|
||||
:label="opt.rvnm"
|
||||
@ -307,11 +307,8 @@
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!-- 图片上传 -->
|
||||
<a-row :gutter="16" class="mt-4">
|
||||
<a-col :span="24">
|
||||
<a-form-item label="图片" :label-col="{ span: 3 }" :wrapper-col="{ span: 21 }">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="图片" >
|
||||
<a-upload
|
||||
v-model:file-list="fileList"
|
||||
:multiple="true"
|
||||
@ -328,6 +325,10 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!-- 图片上传 -->
|
||||
<a-row :gutter="16" class="mt-4">
|
||||
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
@ -350,6 +351,11 @@ import { useDraggable } from '@/utils/drag';
|
||||
import { useShuJuTianBaoStore } from '@/store/modules/shuJuTianBao';
|
||||
const shuJuTianBaoStore = useShuJuTianBaoStore();
|
||||
|
||||
// 所属流域选项:过滤掉 "当前全部",避免作为默认值选中
|
||||
const fishLyOption = computed(() =>
|
||||
shuJuTianBaoStore.lyOption.filter((opt: any) => opt.rvcd !== 'all')
|
||||
);
|
||||
|
||||
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
|
||||
|
||||
const props = defineProps<{
|
||||
@ -438,7 +444,7 @@ const fieldLabelMap: Record<string, string> = {
|
||||
|
||||
// select 选项映射
|
||||
const selectOptionsMap: Record<string, () => any[]> = {
|
||||
rvcd: () => shuJuTianBaoStore.lyOption.map((opt: any) => ({
|
||||
rvcd: () => fishLyOption.value.map((opt: any) => ({
|
||||
label: opt.rvnm,
|
||||
value: opt.rvcd
|
||||
})),
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
:zhujianfujian="'fu'"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
@init-done="handleInitDone"
|
||||
>
|
||||
<template #actions>
|
||||
<a-button @click="hideBtn">{{ isHide ? '展开' : '隐藏' }}</a-button>
|
||||
@ -16,7 +17,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import BasicSearch from '@/components/BasicSearch/index.vue';
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -78,9 +79,10 @@ const seeEdit = () => {
|
||||
emit('seeEdit');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
emit('search-finish', { ...initSearchData });
|
||||
});
|
||||
// 等 BasicSearch 初始化完成(基地数据加载、默认值修正)后再发起首次查询
|
||||
const handleInitDone = (values: any) => {
|
||||
emit('search-finish', { ...values });
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
basicSearchRef
|
||||
|
||||
@ -182,17 +182,6 @@
|
||||
</a-select>
|
||||
</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
|
||||
@ -281,7 +270,6 @@ const fieldLabelMap: Record<string, string> = {
|
||||
dtfrqcy: '监测频次',
|
||||
jbtxcs: '基本特性参数',
|
||||
blprd: '所属建设阶段',
|
||||
introduce: '简介',
|
||||
remark: '备注'
|
||||
};
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
|
||||
<OperationLogModal v-model:open="operationLogVisible" :table-name="'SD_OTTE_B_H'" :record-name-title="'工程名称'" />
|
||||
<OperationLogModal v-model:open="operationLogVisible" :table-name="'SD_OTWE_B_H'" :record-name-title="'工程名称'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@ -1,71 +1,168 @@
|
||||
<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-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-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-input
|
||||
v-model:value="formData.stnm"
|
||||
placeholder="请输入设施名称"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<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
|
||||
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="8">
|
||||
<a-form-item label="站址/位置" name="stlc">
|
||||
<a-input v-model:value="formData.stlc" placeholder="请输入站址" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.stlc"
|
||||
placeholder="请输入站址"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<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
|
||||
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">
|
||||
<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
|
||||
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="8">
|
||||
<a-form-item label="经度(°)" name="lgtd">
|
||||
<a-input-number v-model:value="formData.lgtd" placeholder="请输入" :precision="6" style="width: 100%" />
|
||||
<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-input-number
|
||||
v-model:value="formData.lttd"
|
||||
placeholder="请输入"
|
||||
:precision="6"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="高程(m)" name="elev">
|
||||
<a-input-number v-model:value="formData.elev" placeholder="请输入" :precision="6" style="width: 100%" />
|
||||
<a-input-number
|
||||
v-model:value="formData.elev"
|
||||
placeholder="请输入"
|
||||
:precision="6"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="开工日期" name="swdt">
|
||||
<a-date-picker v-model:value="formData.swdt" format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" :disabled-date="disabledSwdtDate" placeholder="请选择开工日期" style="width: 100%" />
|
||||
<a-date-picker
|
||||
v-model:value="formData.swdt"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
:disabled-date="disabledSwdtDate"
|
||||
placeholder="请选择开工日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<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" :disabled-date="disabledJcdtDate" placeholder="请选择建成日期" style="width: 100%" />
|
||||
<a-date-picker
|
||||
v-model:value="formData.jcdt"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
:disabled-date="disabledJcdtDate"
|
||||
placeholder="请选择建成日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="建设状态" name="bldsttCode">
|
||||
<a-select v-model:value="formData.bldsttCode" placeholder="请选择建设状态" allow-clear>
|
||||
<a-select
|
||||
v-model:value="formData.bldsttCode"
|
||||
placeholder="请选择建设状态"
|
||||
allow-clear
|
||||
>
|
||||
<a-select-option :value="0">规划</a-select-option>
|
||||
<a-select-option :value="1">在建</a-select-option>
|
||||
<a-select-option :value="2">已建</a-select-option>
|
||||
@ -74,59 +171,114 @@
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="投资(亿元)" name="inv">
|
||||
<a-input-number v-model:value="formData.inv" placeholder="请输入" :precision="4" style="width: 100%" />
|
||||
<a-input-number
|
||||
v-model:value="formData.inv"
|
||||
placeholder="请输入"
|
||||
:precision="4"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="上游码头位置" name="symtlc">
|
||||
<a-input v-model:value="formData.symtlc" placeholder="请输入" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.symtlc"
|
||||
placeholder="请输入"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="上游码头型式" name="symtxs">
|
||||
<a-input v-model:value="formData.symtxs" placeholder="请输入" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.symtxs"
|
||||
placeholder="请输入"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="下游码头位置" name="xymtlc">
|
||||
<a-input v-model:value="formData.xymtlc" placeholder="请输入" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.xymtlc"
|
||||
placeholder="请输入"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="下游码头型式" name="xymtxs">
|
||||
<a-input v-model:value="formData.xymtxs" placeholder="请输入" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.xymtxs"
|
||||
placeholder="请输入"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="集诱鱼方式" name="jyfs">
|
||||
<a-input v-model:value="formData.jyfs" placeholder="请输入" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.jyfs"
|
||||
placeholder="请输入"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="运鱼设施方式" name="yyfs">
|
||||
<a-input v-model:value="formData.yyfs" placeholder="请输入" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.yyfs"
|
||||
placeholder="请输入"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="过鱼规模(尾)" name="sjgycnt">
|
||||
<a-input v-model:value="formData.sjgycnt" placeholder="请输入" style="width: 100%" />
|
||||
<a-input
|
||||
v-model:value="formData.sjgycnt"
|
||||
placeholder="请输入"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="过鱼月份" name="fpssmn">
|
||||
<a-select :key="visible" v-model:value="formData.fpssmn" mode="multiple" placeholder="请选择过鱼月份" allow-clear>
|
||||
<a-select-option v-for="item in fpssmnOptions" :key="item.value" :label="item.label" :value="item.value">{{ item.label }}</a-select-option>
|
||||
<a-select
|
||||
:key="visible"
|
||||
v-model:value="formData.fpssmn"
|
||||
mode="multiple"
|
||||
placeholder="请选择过鱼月份"
|
||||
allow-clear
|
||||
:max-tag-count="4"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in fpssmnOptions"
|
||||
: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="监测频次(min)" name="dtfrqcy">
|
||||
<a-input-number v-model:value="formData.dtfrqcy" placeholder="请输入" :precision="0" style="width: 100%" />
|
||||
<a-input-number
|
||||
v-model:value="formData.dtfrqcy"
|
||||
placeholder="请输入"
|
||||
:precision="0"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="监测方式" name="mway">
|
||||
<a-select v-model:value="formData.mway" placeholder="请选择监测方式" allow-clear>
|
||||
<a-select
|
||||
v-model:value="formData.mway"
|
||||
placeholder="请选择监测方式"
|
||||
allow-clear
|
||||
>
|
||||
<a-select-option :value="1">人工</a-select-option>
|
||||
<a-select-option :value="2">自动</a-select-option>
|
||||
</a-select>
|
||||
@ -136,7 +288,13 @@
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<ConfirmModal v-model:open="confirmModalVisible" :diff-list="diffList" :confirm-loading="confirmLoading" @confirm="handleConfirmSubmit" @cancel="handleConfirmCancel" />
|
||||
<ConfirmModal
|
||||
v-model:open="confirmModalVisible"
|
||||
:diff-list="diffList"
|
||||
:confirm-loading="confirmLoading"
|
||||
@confirm="handleConfirmSubmit"
|
||||
@cancel="handleConfirmCancel"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@ -154,7 +312,10 @@ 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) });
|
||||
const visible = computed({
|
||||
get: () => props.open,
|
||||
set: val => emit('update:open', val)
|
||||
});
|
||||
useDraggable(visible, { boundary: true, resetOnOpen: true });
|
||||
|
||||
const formRef = ref();
|
||||
@ -166,29 +327,53 @@ const confirmModalVisible = ref(false);
|
||||
|
||||
const formRules = ref<any>({
|
||||
stcd: [{ required: true, message: '请输入设施编码', trigger: 'blur' }],
|
||||
stnm: [{ required: true, message: '请输入设施名称', trigger: 'blur' }]
|
||||
stnm: [{ required: true, message: '请输入设施名称', trigger: 'blur' }],
|
||||
sttp: [{ required: true, message: '请输入设施名称', trigger: 'blur' }]
|
||||
});
|
||||
|
||||
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 }))
|
||||
jidiSelectEventStore.jidiData
|
||||
.filter((item: any) => item.wbsCode !== 'all')
|
||||
.map((item: any) => ({ label: item.wbsName, value: item.wbsCode }))
|
||||
);
|
||||
|
||||
const engLoading = ref(false);
|
||||
|
||||
// 过鱼月份静态选项 1月-12月
|
||||
const fpssmnOptions = ref(Array.from({ length: 12 }, (_, i) => ({ label: `${i + 1}月`, value: `${i + 1}` })));
|
||||
const fpssmnOptions = ref(
|
||||
Array.from({ length: 12 }, (_, i) => ({
|
||||
label: `${i + 1}月`,
|
||||
value: `${i + 1}`
|
||||
}))
|
||||
);
|
||||
|
||||
const fieldLabelMap: Record<string, string> = {
|
||||
stcd: '设施编码', stnm: '设施名称', sttp: '设施类型', stlc: '站址/位置',
|
||||
baseId: '水电基地', rstcd: '所属电站', lgtd: '经度(°)', lttd: '纬度(°)',
|
||||
elev: '高程(m)', swdt: '开工日期', jcdt: '建成日期', bldsttCode: '建设状态',
|
||||
inv: '投资(亿元)', symtlc: '上游码头位置', symtxs: '上游码头型式',
|
||||
xymtlc: '下游码头位置', xymtxs: '下游码头型式', jyfs: '集诱鱼方式',
|
||||
yyfs: '运鱼设施方式', sjgycnt: '过鱼规模(尾)', fpssmn: '过鱼月份',
|
||||
dtfrqcy: '监测频次(min)', mway: '监测方式'
|
||||
stcd: '设施编码',
|
||||
stnm: '设施名称',
|
||||
sttp: '设施类型',
|
||||
stlc: '站址/位置',
|
||||
baseId: '水电基地',
|
||||
rstcd: '所属电站',
|
||||
lgtd: '经度(°)',
|
||||
lttd: '纬度(°)',
|
||||
elev: '高程(m)',
|
||||
swdt: '开工日期',
|
||||
jcdt: '建成日期',
|
||||
bldsttCode: '建设状态',
|
||||
inv: '投资(亿元)',
|
||||
symtlc: '上游码头位置',
|
||||
symtxs: '上游码头型式',
|
||||
xymtlc: '下游码头位置',
|
||||
xymtxs: '下游码头型式',
|
||||
jyfs: '集诱鱼方式',
|
||||
yyfs: '运鱼设施方式',
|
||||
sjgycnt: '过鱼规模(尾)',
|
||||
fpssmn: '过鱼月份',
|
||||
dtfrqcy: '监测频次(min)',
|
||||
mway: '监测方式'
|
||||
};
|
||||
|
||||
const selectOptionsMap: Record<string, () => any[]> = {
|
||||
@ -207,7 +392,9 @@ const selectOptionsMap: Record<string, () => any[]> = {
|
||||
fpssmn: () => fpssmnOptions.value
|
||||
};
|
||||
|
||||
const changeOrder = ref<{ field: string; label: string; oldValue: string; newValue: string }[]>([]);
|
||||
const changeOrder = ref<
|
||||
{ field: string; label: string; oldValue: string; newValue: string }[]
|
||||
>([]);
|
||||
const diffList = changeOrder;
|
||||
|
||||
const resolveSelectLabel = (field: string, value: any): string => {
|
||||
@ -215,16 +402,21 @@ const resolveSelectLabel = (field: string, value: any): string => {
|
||||
// fpssmn 多选:按逗号分隔,分别解析 label 再合并
|
||||
if (field === 'fpssmn') {
|
||||
const arr = Array.isArray(value) ? value : String(value).split(',');
|
||||
return arr.map((v: any) => {
|
||||
const trimmed = String(v).trim();
|
||||
if (!trimmed) return '';
|
||||
const opt = fpssmnOptions.value.find((o) => String(o.value) === trimmed);
|
||||
return opt ? opt.label : trimmed;
|
||||
}).filter(Boolean).join('、');
|
||||
return arr
|
||||
.map((v: any) => {
|
||||
const trimmed = String(v).trim();
|
||||
if (!trimmed) return '';
|
||||
const opt = fpssmnOptions.value.find(o => String(o.value) === trimmed);
|
||||
return opt ? opt.label : trimmed;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('、');
|
||||
}
|
||||
const getOptions = selectOptionsMap[field];
|
||||
if (getOptions) {
|
||||
const opt = getOptions().find((o: any) => String(o.value) === String(value));
|
||||
const opt = getOptions().find(
|
||||
(o: any) => String(o.value) === String(value)
|
||||
);
|
||||
if (opt) return opt.label;
|
||||
}
|
||||
return String(value);
|
||||
@ -257,94 +449,137 @@ const disabledJcdtDate = (current: any) => {
|
||||
return current && current < dayjs(formData.value.swdt).startOf('day');
|
||||
};
|
||||
|
||||
watch(() => formData.value, newData => {
|
||||
const original = originalRecord.value;
|
||||
for (const key in newData) {
|
||||
const oldVal = original[key];
|
||||
const newVal = newData[key];
|
||||
if (oldVal !== newVal) {
|
||||
// fpssmn 多选:数组 vs 字符串比较,需标准化
|
||||
if (key === 'fpssmn') {
|
||||
const normalize = (v: any) => {
|
||||
if (!v) return '';
|
||||
const arr = Array.isArray(v) ? v : String(v).split(',');
|
||||
return arr.map((s: string) => s.trim()).filter(Boolean).sort().join(',');
|
||||
watch(
|
||||
() => formData.value,
|
||||
newData => {
|
||||
const original = originalRecord.value;
|
||||
for (const key in newData) {
|
||||
const oldVal = original[key];
|
||||
const newVal = newData[key];
|
||||
if (oldVal !== newVal) {
|
||||
// fpssmn 多选:数组 vs 字符串比较,需标准化
|
||||
if (key === 'fpssmn') {
|
||||
const normalize = (v: any) => {
|
||||
if (!v) return '';
|
||||
const arr = Array.isArray(v) ? v : String(v).split(',');
|
||||
return arr
|
||||
.map((s: string) => s.trim())
|
||||
.filter(Boolean)
|
||||
.sort()
|
||||
.join(',');
|
||||
};
|
||||
if (normalize(oldVal) === normalize(newVal)) continue;
|
||||
}
|
||||
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 (normalize(oldVal) === normalize(newVal)) continue;
|
||||
if (existingIdx >= 0) changeOrder.value[existingIdx] = entry;
|
||||
else changeOrder.value.push(entry);
|
||||
} else {
|
||||
changeOrder.value = changeOrder.value.filter(c => c.field !== key);
|
||||
}
|
||||
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 });
|
||||
},
|
||||
{ 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;
|
||||
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 };
|
||||
// fpssmn 多选回显:逗号分隔字符串 → 数组
|
||||
const fpssmnArr = converted.fpssmn ? String(converted.fpssmn).split(',').map((s: string) => s.trim()).filter(Boolean) : [];
|
||||
formData.value = { ...converted, fpssmn: fpssmnArr.length > 0 ? fpssmnArr : undefined };
|
||||
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);
|
||||
originalRecord.value = { ...converted };
|
||||
// fpssmn 多选回显:逗号分隔字符串 → 数组
|
||||
const fpssmnArr = converted.fpssmn
|
||||
? String(converted.fpssmn)
|
||||
.split(',')
|
||||
.map((s: string) => s.trim())
|
||||
.filter(Boolean)
|
||||
: [];
|
||||
formData.value = {
|
||||
...converted,
|
||||
fpssmn: fpssmnArr.length > 0 ? fpssmnArr : undefined
|
||||
};
|
||||
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;
|
||||
});
|
||||
}
|
||||
originalLabels.value = labels;
|
||||
// 表单填充完成后自动复位标志,避免残留 true 导致后续切换流域不清空电站
|
||||
nextTick(() => {
|
||||
isInitLoading.value = false;
|
||||
});
|
||||
}
|
||||
}, { deep: true });
|
||||
},
|
||||
{ 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
);
|
||||
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 }));
|
||||
engInfoOptions.value = (res.data || []).map((item: any) => ({
|
||||
label: item.ennm,
|
||||
value: item.stcd
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('获取电站列表失败:', error);
|
||||
} finally {
|
||||
@ -354,41 +589,65 @@ const loadEngOptions = async (baseId?: string) => {
|
||||
|
||||
const loadDropdownData = () => {
|
||||
sttpGetKendoList({
|
||||
filter: { logic: 'and', filters: [{ field: 'sttpCode', operator: 'in', dataType: 'string', value: ['FP', 'FP_1', 'FP_2', 'FP_3', 'FP_4', 'FP_5'] }] }
|
||||
filter: {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
{
|
||||
field: 'sttpCode',
|
||||
operator: 'in',
|
||||
dataType: 'string',
|
||||
value: ['FP', 'FP_1', 'FP_2', 'FP_3', 'FP_4', 'FP_5']
|
||||
}
|
||||
]
|
||||
}
|
||||
}).then(res => {
|
||||
sttpOptions.value = (res.data?.data || []).map((item: any) => ({ label: item.sttpName, value: item.sttpCode }));
|
||||
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) {
|
||||
if (props.isAdd) {
|
||||
formData.value = { fpssmn: [] };
|
||||
originalRecord.value = {};
|
||||
changeOrder.value = [];
|
||||
loadEngOptions();
|
||||
watch(
|
||||
() => formData.value?.baseId,
|
||||
newBaseId => {
|
||||
// record 加载时已在 record watch 中加载过电站选项,这里仅跳过清空
|
||||
if (isInitLoading.value) {
|
||||
return;
|
||||
}
|
||||
loadDropdownData();
|
||||
formData.value.rstcd = undefined;
|
||||
loadEngOptions(newBaseId || undefined);
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
val => {
|
||||
if (val) {
|
||||
if (props.isAdd) {
|
||||
formData.value = { fpssmn: [] };
|
||||
originalRecord.value = {};
|
||||
changeOrder.value = [];
|
||||
loadEngOptions();
|
||||
}
|
||||
loadDropdownData();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
await formRef.value?.validateFields();
|
||||
if (!props.isAdd && changeOrder.value.length === 0) { message.info('未检测到任何修改'); return; }
|
||||
if (!props.isAdd && changeOrder.value.length === 0) {
|
||||
message.info('未检测到任何修改');
|
||||
return;
|
||||
}
|
||||
confirmModalVisible.value = true;
|
||||
} catch (error) { console.error('验证失败:', error); }
|
||||
} catch (error) {
|
||||
console.error('验证失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirmSubmit = async (source: string) => {
|
||||
@ -399,7 +658,8 @@ const handleConfirmSubmit = async (source: string) => {
|
||||
if (props.isAdd) {
|
||||
Object.assign(engInfo, formData.value);
|
||||
// fpssmn 多选:数组 → 逗号分隔字符串
|
||||
if (Array.isArray(engInfo.fpssmn)) engInfo.fpssmn = engInfo.fpssmn.join(',');
|
||||
if (Array.isArray(engInfo.fpssmn))
|
||||
engInfo.fpssmn = engInfo.fpssmn.join(',');
|
||||
res = await addFpInfo({ engInfo, source: source.trim() || '新增' });
|
||||
} else {
|
||||
engInfo.stcd = formData.value.stcd;
|
||||
@ -412,7 +672,8 @@ const handleConfirmSubmit = async (source: string) => {
|
||||
engInfo[item.field] = val;
|
||||
});
|
||||
// fpssmn 多选:数组 → 逗号分隔字符串
|
||||
if (Array.isArray(engInfo.fpssmn)) engInfo.fpssmn = engInfo.fpssmn.join(',');
|
||||
if (Array.isArray(engInfo.fpssmn))
|
||||
engInfo.fpssmn = engInfo.fpssmn.join(',');
|
||||
res = await updateFpInfo({ engInfo, source: source.trim() || '编辑' });
|
||||
}
|
||||
if (res?.code == 0 || res?.success) {
|
||||
@ -420,11 +681,22 @@ const handleConfirmSubmit = async (source: string) => {
|
||||
confirmModalVisible.value = false;
|
||||
visible.value = false;
|
||||
emit('success');
|
||||
} else { message.error(res?.msg || (props.isAdd ? '新增失败' : '编辑失败')); }
|
||||
} catch (error) { message.error('提交失败,请重试'); }
|
||||
finally { confirmLoading.value = false; }
|
||||
} 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(); };
|
||||
const handleConfirmCancel = () => {
|
||||
confirmModalVisible.value = false;
|
||||
};
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
confirmModalVisible.value = false;
|
||||
formRef.value?.resetFields();
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -120,17 +120,6 @@
|
||||
/>
|
||||
</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="3"
|
||||
/>
|
||||
</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
|
||||
@ -213,7 +202,6 @@ const fieldLabelMap: Record<string, string> = {
|
||||
baseId: '水电基地',
|
||||
rstcd: '所属电站',
|
||||
jcdt: '建成日期',
|
||||
introduce: '简介',
|
||||
remark: '备注',
|
||||
lgtd: '经度(°)',
|
||||
lttd: '纬度(°)'
|
||||
|
||||
@ -120,6 +120,7 @@
|
||||
placeholder="请选择保护对象"
|
||||
allow-clear
|
||||
show-search
|
||||
:max-tag-count="2"
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select-option
|
||||
|
||||
@ -67,10 +67,10 @@ const columns = ref<any[]>([
|
||||
{ key: 'stcd', title: '栖息地站码', dataIndex: 'stcd', visible: true, width: 320, ellipsis: true },
|
||||
{ key: 'baseName', title: '水电基地', dataIndex: 'baseName', visible: true, width: 120, ellipsis: true },
|
||||
{ key: 'ennm', title: '所属电站', dataIndex: 'ennm', visible: true, width: 150, ellipsis: true },
|
||||
{ key: 'bhdxName', title: '保护对象', dataIndex: 'bhdxName', visible: true, width: 240, ellipsis: true },
|
||||
{ key: 'bhhl', title: '保护河流', dataIndex: 'bhhl', visible: true, width: 120, ellipsis: true },
|
||||
{ key: 'bhdx', title: '保护对象', dataIndex: 'bhdx', visible: true, width: 240, ellipsis: true },
|
||||
{ key: 'bhhl', title: '保护河流', dataIndex: 'bhhl', visible: true, width: 140, ellipsis: true },
|
||||
{ key: 'bhhd', title: '保护河段', dataIndex: 'bhhd', visible: true, width: 240, ellipsis: true },
|
||||
{ key: 'bhfw', title: '保护范围', dataIndex: 'bhfw', visible: true, width: 120, ellipsis: true },
|
||||
{ key: 'bhfw', title: '保护范围', dataIndex: 'bhfw', visible: true, width: 240, ellipsis: true },
|
||||
{ key: 'bhhxcd', title: '保护核心长度(km)', dataIndex: 'bhhxcd', visible: true, width: 140 },
|
||||
|
||||
{ key: 'bhcs', title: '保护措施', dataIndex: 'bhcs', visible: true, width: 120, ellipsis: true },
|
||||
|
||||
@ -130,14 +130,11 @@
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="保护原因" name="bhyy">
|
||||
<a-select
|
||||
<a-input
|
||||
v-model:value="formData.bhyy"
|
||||
placeholder="请选择保护原因"
|
||||
allow-clear
|
||||
>
|
||||
<a-select-option :value="1">是</a-select-option>
|
||||
<a-select-option :value="0">否</a-select-option>
|
||||
</a-select>
|
||||
placeholder="请输入保护原因"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
@ -183,17 +180,6 @@
|
||||
/>
|
||||
</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
|
||||
@ -295,10 +281,6 @@ const selectOptionsMap: Record<string, () => any[]> = {
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '禁用', value: 0 }
|
||||
],
|
||||
bhyy: () => [
|
||||
{ label: '是', value: 1 },
|
||||
{ label: '否', value: 0 }
|
||||
],
|
||||
baseId: () => baseNameOptions.value,
|
||||
rstcd: () => engInfoOptions.value
|
||||
};
|
||||
|
||||
@ -120,17 +120,6 @@
|
||||
/>
|
||||
</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="3"
|
||||
/>
|
||||
</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
|
||||
@ -216,7 +205,6 @@ const fieldLabelMap: Record<string, string> = {
|
||||
baseId: '水电基地',
|
||||
rstcd: '所属电站',
|
||||
jcdt: '建成日期',
|
||||
introduce: '简介',
|
||||
remark: '备注',
|
||||
lgtd: '经度(°)',
|
||||
lttd: '纬度(°)'
|
||||
|
||||
@ -171,17 +171,6 @@
|
||||
/>
|
||||
</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
|
||||
@ -275,7 +264,6 @@ const fieldLabelMap: Record<string, string> = {
|
||||
dtfrqcy: '监测频次',
|
||||
fwdx: '服务对象',
|
||||
gcfs: '观察方式',
|
||||
introduce: '简介',
|
||||
remark: '备注'
|
||||
};
|
||||
|
||||
|
||||
@ -182,17 +182,6 @@
|
||||
</a-select>
|
||||
</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
|
||||
@ -283,7 +272,6 @@ const fieldLabelMap: Record<string, string> = {
|
||||
dtfrqcy: '监测频次',
|
||||
jbtxcs: '基本特性参数',
|
||||
blprd: '所属建设阶段',
|
||||
introduce: '简介',
|
||||
remark: '备注'
|
||||
};
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
|
||||
<OperationLogModal v-model:open="operationLogVisible" :table-name="'SD_OTWE_B_H'" :record-name-title="'工程名称'" />
|
||||
<OperationLogModal v-model:open="operationLogVisible" :table-name="'SD_OTTE_B_H'" :record-name-title="'工程名称'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@ -40,13 +40,13 @@ const deleteModalRef = ref();
|
||||
const operationLogVisible = ref(false);
|
||||
|
||||
const columns = ref<any[]>([
|
||||
{ key: 'stnm', title: '增殖站名称', dataIndex: 'stnm', visible: true, width: 160,fixed: 'left', ellipsis: true },
|
||||
{ key: 'stnm', title: '增殖站名称', dataIndex: 'stnm', visible: true, width: 240,fixed: 'left', ellipsis: true },
|
||||
{ key: 'stcd', title: '增殖站编码', dataIndex: 'stcd', visible: true, width: 180, ellipsis: true },
|
||||
|
||||
{ key: 'baseName', title: '水电基地', dataIndex: 'baseName', visible: true, width: 120, ellipsis: true },
|
||||
{ key: 'ennm', title: '所属电站', dataIndex: 'ennm', visible: true, width: 100, ellipsis: true },
|
||||
|
||||
{ key: 'zzfldx', title: '放流对象', dataIndex: 'zzfldx', visible: true, width: 120, ellipsis: true },
|
||||
{ key: 'zzfldx', title: '放流对象', dataIndex: 'zzfldx', visible: true, width: 260, ellipsis: true },
|
||||
{ key: 'zzflcnt', title: '放流规模(尾)', dataIndex: 'zzflcnt', visible: true, width: 120 },
|
||||
|
||||
{ key: 'zzflbjfs', title: '标记方式', dataIndex: 'zzflbjfs', visible: true, width: 100, ellipsis: true },
|
||||
@ -56,7 +56,7 @@ const columns = ref<any[]>([
|
||||
{ key: 'zzflfllc', title: '放流地点', dataIndex: 'zzflfllc', visible: true, width: 260, ellipsis: true },
|
||||
|
||||
{ key: 'zzflyzms', title: '养殖模式', dataIndex: 'zzflyzms', visible: true, width: 220, ellipsis: true },
|
||||
{ key: 'zzflgy', title: '生产工艺', dataIndex: 'zzflgy', visible: true, width: 180, ellipsis: true },
|
||||
{ key: 'zzflgy', title: '生产工艺', dataIndex: 'zzflgy', visible: true, width: 240, ellipsis: true },
|
||||
{ key: 'swdt', title: '开工日期', dataIndex: 'swdt', visible: true, width: 110, customRender: ({ text }) => { if (!text || text === '-') return '-'; const date = dayjs(text); return date.isValid() ? date.format('YYYY-MM-DD') : '-'; } },
|
||||
{ key: 'jcdt', title: '建成日期', dataIndex: 'jcdt', visible: true, width: 110, customRender: ({ text }) => { if (!text || text === '-') return '-'; const date = dayjs(text); return date.isValid() ? date.format('YYYY-MM-DD') : '-'; } },
|
||||
{ key: 'zzfltm', title: '放流时间', dataIndex: 'zzfltm', visible: true, width: 110, customRender: ({ text }) => { if (!text || text === '-') return '-'; const date = dayjs(text); return date.isValid() ? date.format('YYYY-MM-DD') : '-'; } },
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
<div
|
||||
id="map-baselayer"
|
||||
class="baselayer-switcher"
|
||||
:style="{ right: drawerOpen ? '480px' : '26px' }"
|
||||
:class="{ 'is-dzzt': hasDzztBottom }"
|
||||
:style="positionStyle"
|
||||
v-if="uiStore.mapType == '2D'"
|
||||
>
|
||||
<div
|
||||
@ -22,6 +23,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useUiStore } from '@/store/modules/ui';
|
||||
import { useMapConfigStore } from '@/modules/map/stores/map-config.store';
|
||||
import { useMapViewStore } from '@/modules/map/stores/map-view.store';
|
||||
@ -39,12 +41,32 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
const uiStore = useUiStore();
|
||||
const route = useRoute();
|
||||
const mapConfigStore = useMapConfigStore();
|
||||
const mapViewStore = useMapViewStore();
|
||||
// 抽屉展开(页面自带抽屉或全局抽屉任一打开)时,底图切换整体左移
|
||||
const drawerOpen = computed(
|
||||
() => uiStore.drawerOpen || uiStore.globalDrawerOpen
|
||||
);
|
||||
// 仅电站专题页存在底部模块时应用位置覆盖与九宫格居中样式;其余场景(无底部模块/非专题页)保持原始样式绑定
|
||||
const isDzzt = computed(() =>
|
||||
route.path.includes('dianZhanZhuanTi/dianZhanZhuanTi')
|
||||
);
|
||||
const hasDzztBottom = computed(
|
||||
() => isDzzt.value && !!uiStore.mapControlsPosition.baselayerBottom
|
||||
);
|
||||
const positionStyle = computed(() => {
|
||||
const bottom = uiStore.mapControlsPosition.baselayerBottom;
|
||||
if (hasDzztBottom.value && bottom) {
|
||||
return {
|
||||
right:
|
||||
uiStore.mapControlsPosition.baselayerRight ??
|
||||
(drawerOpen.value ? '480px' : '26px'),
|
||||
bottom
|
||||
};
|
||||
}
|
||||
return { right: drawerOpen.value ? '480px' : '26px' };
|
||||
});
|
||||
const layers = [
|
||||
{ key: 's_province_boundaries', name: '矢量', img: shiliangImg },
|
||||
{ key: 'BASEMAP-white', name: '地形', img: dixingImg },
|
||||
@ -167,5 +189,11 @@ const handleSwitch = (key: string) => {
|
||||
width: 100px !important;
|
||||
}
|
||||
}
|
||||
// 电站专题页有底部模块时:九宫格预览块相对底图切换块水平居中,沿垂直轴堆叠
|
||||
&.is-dzzt .nineSectionsImg {
|
||||
left: 50%;
|
||||
right: auto;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -286,6 +286,7 @@ import EcologicalFlow from './components/EcologicalFlow.vue'; // 生态流量
|
||||
import Attachment from './components/Attachment.vue'; // 查看报告/批复文件
|
||||
import WaterTemperatureRep from './components/WaterTemperatureRep.vue'; // 水温对比数据
|
||||
import { useModelStore } from '@/store/modules/model';
|
||||
import { useUiStore } from '@/store/modules/ui';
|
||||
import { handleTabs } from './setting.config';
|
||||
import {
|
||||
getMonitorDataWt,
|
||||
@ -304,6 +305,7 @@ import { useDraggable } from '@/utils/drag';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const modelStore = useModelStore();
|
||||
const uiStore = useUiStore();
|
||||
const tabsConfig = ref([]);
|
||||
// 加载状态:等待所有验证完成后再显示 tabs
|
||||
const isLoading = ref(true);
|
||||
@ -362,6 +364,9 @@ const checkPowerStationTopicData = async (stcd: string) => {
|
||||
const gotoEngTopic = () => {
|
||||
const stcd = modelStore.params?.stcd;
|
||||
if (!stcd) return;
|
||||
// 跳离地图前关闭全局搜索抽屉
|
||||
uiStore.setIsSearchActive(false);
|
||||
uiStore.setGlobalDrawerOpen(false);
|
||||
router.push({
|
||||
path: '/dianZhanZhuanTi/dianZhanZhuanTi',
|
||||
query: { stcd }
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
offset5
|
||||
} from '@/utils/GisUrlList';
|
||||
import { LAYOUT_GRID_SKELETONS } from '@/views/dianZhanZhuanTi/layoutGridSkeletons';
|
||||
import { useUiStore } from '@/store/modules/ui';
|
||||
declare global {
|
||||
interface Window {
|
||||
__lyConfigs?: {
|
||||
@ -340,9 +341,7 @@ export const setMapLegendPos = (
|
||||
const legend = document.querySelector('#qgc-legendtl') as HTMLElement;
|
||||
const filter = document.querySelector('#map-filter-container') as HTMLElement;
|
||||
const compassControl = document.querySelector('#map-compassControl') as HTMLElement;
|
||||
const controller = document.querySelector('#map-controller') as HTMLElement;
|
||||
const monitor = document.querySelector('#map-monitor') as HTMLElement;
|
||||
const baselayer = document.querySelector('#map-baselayer') as HTMLElement;
|
||||
|
||||
const leftList = getListByPosition(data, 'left');
|
||||
const rightList = getListByPosition(data, 'right');
|
||||
@ -386,16 +385,29 @@ export const setMapLegendPos = (
|
||||
if (compassControl) {
|
||||
compassControl.style.left = hasLeft ? l : b;
|
||||
}
|
||||
if (controller) {
|
||||
controller.style.right = hasRight ? w : '0';
|
||||
controller.style.bottom = hasBottom ? `calc(${bottomOffset} + 10px)` : '0';
|
||||
}
|
||||
if (monitor) {
|
||||
monitor.style.right = hasRight ? w : '0';
|
||||
}
|
||||
if (baselayer) {
|
||||
baselayer.style.right = hasRight ? `calc(${w} + 60px)` : '60px';
|
||||
baselayer.style.bottom = hasBottom ? bottomOffset : '0';
|
||||
|
||||
// 地图控制器/底图切换器:通过 store 发布位置覆盖,组件内联样式优先读取,
|
||||
// 避免 JS 直写 el.style 与组件自身 :style 绑定互相覆盖(刷新后重叠问题)。
|
||||
const uiStore = useUiStore();
|
||||
if (hasBottom) {
|
||||
// 有底部模块:有右模块时整体左移避让;两者同底(bottomOffset)
|
||||
uiStore.setMapControlsPosition({
|
||||
controllerRight: hasRight ? w : null,
|
||||
controllerBottom: bottomOffset,
|
||||
baselayerRight: hasRight ? `calc(${w} + 60px)` : null,
|
||||
baselayerBottom: bottomOffset
|
||||
});
|
||||
} else {
|
||||
// 无底部模块:完全回退组件自身默认样式(与非电站专题页面一致)
|
||||
uiStore.setMapControlsPosition({
|
||||
controllerRight: null,
|
||||
controllerBottom: null,
|
||||
baselayerRight: null,
|
||||
baselayerBottom: null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div
|
||||
id="map-controller"
|
||||
class="map-controller"
|
||||
:style="{ right: drawerOpen ? '480px' : '26px' }"
|
||||
:style="positionStyle"
|
||||
>
|
||||
<div
|
||||
class="map-controller-group"
|
||||
@ -60,6 +60,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, toRef, computed, onUnmounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useUiStore } from '@/store/modules/ui';
|
||||
import Calculate from './Calculate.vue';
|
||||
import LayerController from './LayerController.vue';
|
||||
@ -74,10 +75,27 @@ const map = toRef(props, 'map');
|
||||
|
||||
// 使用 Pinia store
|
||||
const uiStore = useUiStore();
|
||||
const route = useRoute();
|
||||
// 抽屉展开(页面自带抽屉或全局抽屉任一打开)时,控制器整体左移
|
||||
const drawerOpen = computed(
|
||||
() => uiStore.drawerOpen || uiStore.globalDrawerOpen
|
||||
);
|
||||
// 仅电站专题页存在底部模块时应用位置覆盖;其余场景(无底部模块/非专题页)保持原始样式绑定
|
||||
const isDzzt = computed(() =>
|
||||
route.path.includes('dianZhanZhuanTi/dianZhanZhuanTi')
|
||||
);
|
||||
const positionStyle = computed(() => {
|
||||
const bottom = uiStore.mapControlsPosition.controllerBottom;
|
||||
if (isDzzt.value && bottom) {
|
||||
return {
|
||||
right:
|
||||
uiStore.mapControlsPosition.controllerRight ??
|
||||
(drawerOpen.value ? '480px' : '26px'),
|
||||
bottom
|
||||
};
|
||||
}
|
||||
return { right: drawerOpen.value ? '480px' : '26px' };
|
||||
});
|
||||
const tjVisible = ref(false);
|
||||
|
||||
watch(
|
||||
|
||||
@ -730,6 +730,8 @@ const handleAnchorPointChange = (value: string) => {
|
||||
uiStore.setIsSearchActive(true);
|
||||
uiStore.setDrawerOpen(false);
|
||||
setTimeout(() => {
|
||||
// 若 300ms 内已跳转到电站专题页则不弹(避免抽屉在专题页闪现)
|
||||
if (route.path.includes('dianZhanZhuanTi/dianZhanZhuanTi')) return;
|
||||
uiStore.setGlobalDrawerOpen(true);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onBeforeMount, onMounted } from 'vue';
|
||||
import { ref, watch, onBeforeMount, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { useMapStore } from '@/store/modules/map';
|
||||
@ -23,6 +23,21 @@ const buildPageKeyFromPath = (path?: string) => {
|
||||
return normalizedPath || '__route-change__';
|
||||
};
|
||||
|
||||
// 根据当前路由同步主/子菜单选中状态(按 path 或 opturl 匹配,未匹配到则保持原状态)
|
||||
const syncActiveFromRoute = () => {
|
||||
permissionStore.routes.forEach((item: any) => {
|
||||
if (item.meta?.hidden) return;
|
||||
const matched = (item.children || []).find(
|
||||
(child: any) => child.path === route.path || child.opturl === route.path
|
||||
);
|
||||
if (matched) {
|
||||
activeKey.value = item.id;
|
||||
subMenus.value = item.children;
|
||||
subActiveKey.value = matched.id;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 主菜单切换
|
||||
const handleTabChange = (key: string) => {
|
||||
let data = menus.value.find((item: any) => item.id === key);
|
||||
@ -61,18 +76,19 @@ onBeforeMount(() => {
|
||||
} else {
|
||||
menus.value.push(item);
|
||||
}
|
||||
if (item.children) {
|
||||
item.children.map((child: any) => {
|
||||
if (child.path === route.path) {
|
||||
activeKey.value = item.id;
|
||||
subMenus.value = item.children;
|
||||
subActiveKey.value = child.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
syncActiveFromRoute();
|
||||
});
|
||||
|
||||
// 路由变化(如地图弹窗跳转电站专题)时同步导航栏高亮
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
syncActiveFromRoute();
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
|
||||
|
||||
@ -192,7 +192,7 @@ const scopeDateConfig = computed(() => ({
|
||||
value: [dateRange.value[0], dateRange.value[1]] as any,
|
||||
picker: (mway.value === '1' ? 'year' : 'date') as const,
|
||||
format: mway.value === '1' ? 'YYYY' : 'YYYY-MM-DD',
|
||||
width: mway.value === '1' ? '170px' : '215px'
|
||||
width: mway.value === '1' ? '170px' : '220px'
|
||||
}));
|
||||
|
||||
// ==================== 树数据转换 ====================
|
||||
|
||||
@ -2,6 +2,7 @@ import router from '@/router';
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { useUserStoreHook } from '@/store/modules/user';
|
||||
import { usePermissionStoreHook } from '@/store/modules/permission';
|
||||
import { useUiStore } from '@/store/modules/ui';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
NProgress.configure({ showSpinner: false });
|
||||
@ -130,6 +131,10 @@ router.beforeEach(async (to, from, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
router.afterEach(to => {
|
||||
NProgress.done();
|
||||
// 进入非电站专题页时清除地图控件位置覆盖(防止专题页的 store 覆盖值泄漏到其他页面)
|
||||
if (!to.path.includes('dianZhanZhuanTi')) {
|
||||
useUiStore().resetMapControlsPosition();
|
||||
}
|
||||
});
|
||||
|
||||
@ -18,6 +18,18 @@ export const useUiStore = defineStore('ui', () => {
|
||||
const globalDrawerOpen = ref(false);
|
||||
// 是否处于锚点搜索状态(选中命中 DRAWER_STTP_CODES 的锚点时 true;清空/切页等 false)
|
||||
const isSearchActive = ref(false);
|
||||
// 地图控件(地图控制器/底图切换器)位置覆盖值;null 表示回退组件自身默认(非电站专题页样式)
|
||||
const mapControlsPosition = ref<{
|
||||
controllerRight: string | null;
|
||||
controllerBottom: string | null;
|
||||
baselayerRight: string | null;
|
||||
baselayerBottom: string | null;
|
||||
}>({
|
||||
controllerRight: null,
|
||||
controllerBottom: null,
|
||||
baselayerRight: null,
|
||||
baselayerBottom: null
|
||||
});
|
||||
|
||||
// 切换抽屉状态
|
||||
const toggleDrawer = () => {
|
||||
@ -39,6 +51,26 @@ export const useUiStore = defineStore('ui', () => {
|
||||
const setIsSearchActive = (active: boolean) => {
|
||||
isSearchActive.value = active;
|
||||
};
|
||||
// 部分更新地图控件位置覆盖
|
||||
const setMapControlsPosition = (
|
||||
partial: Partial<{
|
||||
controllerRight: string | null;
|
||||
controllerBottom: string | null;
|
||||
baselayerRight: string | null;
|
||||
baselayerBottom: string | null;
|
||||
}>
|
||||
) => {
|
||||
mapControlsPosition.value = { ...mapControlsPosition.value, ...partial };
|
||||
};
|
||||
// 重置地图控件位置覆盖(恢复组件自身默认样式,即非电站专题页样式)
|
||||
const resetMapControlsPosition = () => {
|
||||
mapControlsPosition.value = {
|
||||
controllerRight: null,
|
||||
controllerBottom: null,
|
||||
baselayerRight: null,
|
||||
baselayerBottom: null
|
||||
};
|
||||
};
|
||||
|
||||
const markMapSwitchCompleted = () => {
|
||||
mapSwitchCompletedTick.value += 1;
|
||||
@ -57,6 +89,9 @@ export const useUiStore = defineStore('ui', () => {
|
||||
setGlobalDrawerOpen,
|
||||
isSearchActive,
|
||||
setIsSearchActive,
|
||||
mapControlsPosition,
|
||||
setMapControlsPosition,
|
||||
resetMapControlsPosition,
|
||||
mapType,
|
||||
mapSwitchCompletedTick,
|
||||
markMapSwitchCompleted
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
<template>
|
||||
<!-- 第一步:输入修改依据 -->
|
||||
<a-modal
|
||||
v-model:open="dataSourceVisible"
|
||||
:title="title"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@ok="handleDataSourceConfirm"
|
||||
>
|
||||
<div>
|
||||
<p style="color: red; margin-bottom: 8px">请输入修改依据以继续删除操作</p>
|
||||
<a-textarea
|
||||
v-model:value="dataSource"
|
||||
placeholder="请输入修改依据"
|
||||
:rows="4"
|
||||
/>
|
||||
</div>
|
||||
</a-modal>
|
||||
|
||||
<!-- 第二步:确认删除 -->
|
||||
<a-modal
|
||||
v-model:open="confirmVisible"
|
||||
title="确认删除"
|
||||
ok-text="确认删除"
|
||||
cancel-text="取消"
|
||||
:ok-button-props="{ danger: true }"
|
||||
:confirm-loading="confirmLoading"
|
||||
@ok="handleFinalDelete"
|
||||
>
|
||||
<div>
|
||||
<p style="color: red; font-weight: bold">请慎重操作!</p>
|
||||
<p>{{ label }}名称:{{ deleteRecord?.stnm }}</p>
|
||||
<p>修改依据:{{ dataSource || '无' }}</p>
|
||||
<p>确定要删除该{{ label }}吗?</p>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { deletePowerInfo } from '@/api/DataQueryMenuModule';
|
||||
import { useDraggable } from '@/utils/drag';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/** 自定义删除函数,接收 (record, reason) 参数 */
|
||||
deleteFn?: (record: any, reason: string) => Promise<any>;
|
||||
/** 弹窗标题 */
|
||||
title?: string;
|
||||
/** 显示标签(如"电站"、"数据") */
|
||||
label?: string;
|
||||
}>(),
|
||||
{
|
||||
title: '删除电站',
|
||||
label: '电站'
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
const dataSourceVisible = ref(false);
|
||||
const confirmVisible = ref(false);
|
||||
const confirmLoading = ref(false);
|
||||
const dataSource = ref('');
|
||||
const deleteRecord = ref<any>(null);
|
||||
const onSuccess = ref<Function>(() => {});
|
||||
|
||||
// 打开删除弹窗
|
||||
const open = (record: any, callback: Function) => {
|
||||
deleteRecord.value = record;
|
||||
dataSource.value = '';
|
||||
dataSourceVisible.value = true;
|
||||
onSuccess.value = callback;
|
||||
};
|
||||
useDraggable(dataSourceVisible, { boundary: true, resetOnOpen: true });
|
||||
useDraggable(confirmVisible, { boundary: true, resetOnOpen: true });
|
||||
// 修改依据确认
|
||||
const handleDataSourceConfirm = () => {
|
||||
dataSourceVisible.value = false;
|
||||
confirmVisible.value = true;
|
||||
};
|
||||
|
||||
// 最终删除
|
||||
const handleFinalDelete = async () => {
|
||||
confirmLoading.value = true; // 开始加载
|
||||
try {
|
||||
let res: any;
|
||||
if (props.deleteFn) {
|
||||
// 使用外部传入的删除函数
|
||||
res = await props.deleteFn(deleteRecord.value, dataSource.value);
|
||||
} else {
|
||||
// 默认使用电站删除接口
|
||||
const params = {
|
||||
ids: [deleteRecord.value.stcd],
|
||||
source: dataSource.value
|
||||
};
|
||||
res = await deletePowerInfo(params);
|
||||
}
|
||||
if (res?.code == 0 || res?.success) {
|
||||
message.success('删除成功');
|
||||
confirmVisible.value = false;
|
||||
onSuccess.value();
|
||||
} else {
|
||||
message.error(res?.msg || '删除失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('删除失败,请重试');
|
||||
} finally {
|
||||
confirmLoading.value = false; // 结束加载
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,16 @@
|
||||
sort: sort
|
||||
}"
|
||||
:list-url="getPowerTableList"
|
||||
>
|
||||
><template #action="{ record }">
|
||||
<a-button
|
||||
type="link"
|
||||
class="text-[#2f6b98]"
|
||||
size="small"
|
||||
@click="handleDetail(record)"
|
||||
>查看详情</a-button
|
||||
>
|
||||
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<!-- 自定义数据列 Modal -->
|
||||
@ -36,19 +45,6 @@
|
||||
:user-column-list="userColumnList"
|
||||
@confirm="handleColumnConfirm"
|
||||
/>
|
||||
|
||||
<!-- 编辑电站 Modal -->
|
||||
<EditPowerModal
|
||||
v-model:open="editVisible"
|
||||
:dvtp-list="dvtpList"
|
||||
:record="editRecord"
|
||||
:top-hynm-list="topHynmList"
|
||||
:hycd-list="hycdList"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
|
||||
<!-- 删除确认 Modal -->
|
||||
<DeleteConfirmModal ref="deleteModalRef" @success="handleEditSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@ -57,13 +53,9 @@ import dayjs from 'dayjs';
|
||||
import BasicDataSearch from './BasicDataSearch.vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import CustomColumnModal from './CustomColumnModal.vue';
|
||||
import EditPowerModal from './EditPowerModal.vue';
|
||||
import DeleteConfirmModal from './DeleteConfirmModal.vue';
|
||||
import {
|
||||
getCompanyList,
|
||||
getPowerTableList,
|
||||
updatePowerInfo,
|
||||
deletePowerInfo,
|
||||
getUserColumnData,
|
||||
batchSaveUserColumn
|
||||
} from '@/api/DataQueryMenuModule';
|
||||
@ -435,26 +427,6 @@ const handleDetail = (record: any) => {
|
||||
modelStore.params.stcd = record.stcd;
|
||||
modelStore.title = record.stnm;
|
||||
};
|
||||
// 编辑
|
||||
const handleEdit = (record: any) => {
|
||||
getEngInfoById({ stcd: record.stcd }).then(res => {
|
||||
console.log(res);
|
||||
editRecord.value = { ...res.data };
|
||||
});
|
||||
editVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑成功回调
|
||||
const handleEditSuccess = () => {
|
||||
initTable(currentSearchParams.value);
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = (record: any) => {
|
||||
deleteModalRef.value?.open(record, () => {
|
||||
initTable(currentSearchParams.value);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取用户自定义列配置,构建表格列
|
||||
const fetchColumnConfig = () => {
|
||||
@ -482,7 +454,13 @@ const fetchColumnConfig = () => {
|
||||
});
|
||||
|
||||
// 添加操作列
|
||||
|
||||
cols.push({
|
||||
key: 'action',
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: isEdit.value ? 180 : 100
|
||||
});
|
||||
|
||||
columns.value = cols;
|
||||
}).catch(() => {
|
||||
|
||||
@ -1,121 +0,0 @@
|
||||
<!-- <template>
|
||||
<BasicSearch
|
||||
ref="basicSearchRef"
|
||||
:searchList="searchList"
|
||||
:initial-values="initSearchData"
|
||||
:zhujianfujian="'fu'"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
>
|
||||
<template #actions>
|
||||
<a-button @click="hideBtn">{{ isHide ? '展开' : '隐藏' }}</a-button>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import BasicSearch from '@/components/BasicSearch/index.vue';
|
||||
import { sttpGetKendoList } from '@/api/system/map/ConfigManagement';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'search-finish', values: any): void;
|
||||
(e: 'reset', values: any): void;
|
||||
(e: 'add'): void;
|
||||
}>();
|
||||
|
||||
const basicSearchRef = ref();
|
||||
const isHide = ref<boolean>(false);
|
||||
const sttpOption = ref([]);
|
||||
|
||||
const initSearchData = {
|
||||
baseId: 'all',
|
||||
rstcd: null,
|
||||
stnm: null,
|
||||
sttp: null
|
||||
};
|
||||
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: 'jidiData',
|
||||
name: 'baseId',
|
||||
label: '水电基地',
|
||||
placeholder: '请输入水电基地名称',
|
||||
fieldProps: {
|
||||
allowClear: true
|
||||
},
|
||||
options: []
|
||||
},
|
||||
{
|
||||
type: 'Input',
|
||||
name: 'stnm',
|
||||
label: '站点名称',
|
||||
placeholder: '请输入站点名称',
|
||||
width: 160,
|
||||
fieldProps: {
|
||||
allowClear: true
|
||||
}
|
||||
},
|
||||
{
|
||||
col: isHide.value ? 0 : null,
|
||||
type: 'Select',
|
||||
name: 'sttp',
|
||||
label: '测站类型',
|
||||
width: 160,
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请选择测站类型'
|
||||
},
|
||||
options: sttpOption.value
|
||||
}
|
||||
]);
|
||||
|
||||
const getBaseList = async () => {
|
||||
let params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
{
|
||||
"field": "sttpCode",
|
||||
"operator": "in",
|
||||
"dataType": "string",
|
||||
"value": ["OSGB"]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
const res = await sttpGetKendoList(params);
|
||||
sttpOption.value = res.data.data.map(item => {
|
||||
return {
|
||||
label: item.sttpName,
|
||||
value: item.sttpCode
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit('search-finish', { ...values });
|
||||
};
|
||||
|
||||
const hideBtn = () => {
|
||||
isHide.value = !isHide.value;
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit('reset', initSearchData);
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
emit('add');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getBaseList();
|
||||
emit('search-finish', { ...initSearchData });
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
basicSearchRef
|
||||
});
|
||||
</script> -->
|
||||
@ -1,275 +0,0 @@
|
||||
<!-- <template>
|
||||
<div class="w-full h-full flex flex-col pt-[20px] pl-[20px] body_one">
|
||||
<PhotoSearch
|
||||
@search-finish="onSearchFinish"
|
||||
@reset="onReset"
|
||||
@add="handleAdd"
|
||||
ref="searchRef"
|
||||
/>
|
||||
|
||||
<BasicTable
|
||||
ref="tableRef"
|
||||
:enableEllipsis="true"
|
||||
:scrollX="tableScrollX"
|
||||
:scrollY="tableScrollY"
|
||||
:columns="columns"
|
||||
:list-url="getOpPageList"
|
||||
>
|
||||
<template #action="{ record }">
|
||||
<a-button
|
||||
type="link"
|
||||
class="text-[#2f6b98]"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>编辑</a-button
|
||||
>
|
||||
<a-button type="link" danger size="small" @click="handleDelete(record)"
|
||||
>删除</a-button
|
||||
>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<EditPhotoModal
|
||||
v-model:open="editVisible"
|
||||
:record="editRecord"
|
||||
:is-add="isAdd"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
|
||||
<DeleteConfirmModal
|
||||
ref="deleteModalRef"
|
||||
:delete-fn="deleteOpFn"
|
||||
:label="'倾斜摄影站点'"
|
||||
title="删除倾斜摄影站点"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, nextTick } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import PhotoSearch from './PhotoSearch.vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import EditPhotoModal from './EditPhotoModal.vue';
|
||||
import DeleteConfirmModal from '@/views/conventionalHydropower/BasicData/DeleteConfirmModal.vue';
|
||||
import { getOpPageList, deleteOpInfo } from '@/api/DataQueryMenuModule';
|
||||
import { calcTableScrollY } from '@/utils/index';
|
||||
|
||||
const tableRef = ref();
|
||||
const searchRef = ref();
|
||||
const tableScrollY = ref<string | number>(0);
|
||||
const currentSearchParams = ref<any>({});
|
||||
|
||||
// 编辑相关
|
||||
const editVisible = ref(false);
|
||||
const editRecord = ref<any>(null);
|
||||
const isAdd = ref(false);
|
||||
const deleteModalRef = ref();
|
||||
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
key: 'stnm',
|
||||
title: '站点名称',
|
||||
dataIndex: 'stnm',
|
||||
visible: true,
|
||||
width: 200,
|
||||
fixed: 'left',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'stcd',
|
||||
title: '站点编码',
|
||||
dataIndex: 'stcd',
|
||||
visible: true,
|
||||
width: 160,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'sttpName',
|
||||
title: '测站类型',
|
||||
dataIndex: 'sttpName',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'stlc',
|
||||
title: '位置',
|
||||
dataIndex: 'stlc',
|
||||
visible: true,
|
||||
width: 160,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'baseName',
|
||||
title: '水电基地',
|
||||
dataIndex: 'baseName',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'ennm',
|
||||
title: '所属电站',
|
||||
dataIndex: 'ennm',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'url',
|
||||
title: '在线地址',
|
||||
dataIndex: 'url',
|
||||
visible: true,
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'usflName',
|
||||
title: '是否启用',
|
||||
dataIndex: 'usflName',
|
||||
visible: true,
|
||||
width: 80,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'jcdt',
|
||||
title: '建成日期',
|
||||
dataIndex: 'jcdt',
|
||||
visible: true,
|
||||
width: 110,
|
||||
customRender: ({ text }) => {
|
||||
if (!text || text === '-') return '-';
|
||||
const date = dayjs(text);
|
||||
return date.isValid() ? date.format('YYYY-MM-DD') : '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'remark',
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
visible: true,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 120
|
||||
}
|
||||
]);
|
||||
|
||||
const tableScrollX = computed(() =>
|
||||
Math.max(
|
||||
columns.value.reduce(
|
||||
(sum: number, col: any) => sum + (col.width || 180),
|
||||
0
|
||||
),
|
||||
600
|
||||
)
|
||||
);
|
||||
|
||||
const buildSearchParams = (values: any) => {
|
||||
return {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
values.rstcd
|
||||
? {
|
||||
field: 'rstcd',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.rstcd
|
||||
}
|
||||
: null,
|
||||
values.baseId !== 'all'
|
||||
? {
|
||||
field: 'baseId',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.baseId
|
||||
}
|
||||
: null,
|
||||
values.stnm
|
||||
? {
|
||||
field: 'stnm',
|
||||
operator: 'contains',
|
||||
dataType: 'string',
|
||||
value: values.stnm
|
||||
}
|
||||
: null,
|
||||
values.sttp
|
||||
? {
|
||||
field: 'sttp',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.sttp
|
||||
}
|
||||
: null
|
||||
].filter(Boolean)
|
||||
};
|
||||
};
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
currentSearchParams.value = values;
|
||||
initTable(values);
|
||||
};
|
||||
|
||||
const onReset = (values: any) => {
|
||||
currentSearchParams.value = values;
|
||||
initTable(values);
|
||||
};
|
||||
|
||||
const initTable = (values: any) => {
|
||||
const params = buildSearchParams(values);
|
||||
tableRef.value.getList(params);
|
||||
};
|
||||
|
||||
// 新增
|
||||
const handleAdd = () => {
|
||||
isAdd.value = true;
|
||||
editRecord.value = null;
|
||||
editVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (record: any) => {
|
||||
isAdd.value = false;
|
||||
editRecord.value = { ...record };
|
||||
editVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑成功回调
|
||||
const handleEditSuccess = () => {
|
||||
initTable(currentSearchParams.value);
|
||||
};
|
||||
|
||||
// 删除
|
||||
const deleteOpFn = async (record: any, reason: string) => {
|
||||
return deleteOpInfo({
|
||||
ids: [record.stcd],
|
||||
source: reason
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (record: any) => {
|
||||
deleteModalRef.value?.open(record, () => {
|
||||
initTable(currentSearchParams.value);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
tableScrollY.value = calcTableScrollY();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.body_one {
|
||||
position: relative;
|
||||
z-index: 900;
|
||||
pointer-events: all;
|
||||
}
|
||||
</style> -->
|
||||
@ -1,506 +0,0 @@
|
||||
<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="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
|
||||
: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="prtcts">
|
||||
<a-input
|
||||
v-model:value="formData.prtcts"
|
||||
placeholder="请输入保护对象"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="产卵场数量(个)" name="cnt">
|
||||
<a-input-number
|
||||
v-model:value="formData.cnt"
|
||||
placeholder="请输入数量"
|
||||
style="width: 100%"
|
||||
:min="0"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="面积(km²)" name="ar">
|
||||
<a-input-number
|
||||
v-model:value="formData.ar"
|
||||
placeholder="请输入面积"
|
||||
style="width: 100%"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="营造型式" name="tp">
|
||||
<a-input
|
||||
v-model:value="formData.tp"
|
||||
placeholder="请输入营造型式"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="实施时间" name="attm">
|
||||
<a-date-picker
|
||||
v-model:value="formData.attm"
|
||||
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="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="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="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="24">
|
||||
<a-form-item label="简介" name="introduce" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||
<a-textarea
|
||||
v-model:value="formData.introduce"
|
||||
placeholder="请输入简介"
|
||||
: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="请输入备注"
|
||||
: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 } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { addSgInfo, updateSgInfo } 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 confirmModalVisible = ref(false);
|
||||
|
||||
const formRules = ref<any>({
|
||||
stcd: [{ required: true, message: '请输入产卵场编码', trigger: 'blur' }],
|
||||
stnm: [{ required: true, message: '请输入产卵场名称', trigger: 'blur' }]
|
||||
});
|
||||
|
||||
// 下拉选项
|
||||
const engInfoOptions = ref<any[]>([]);
|
||||
const sttpOptions = ref<any[]>([]);
|
||||
|
||||
const baseNameOptions = ref<any[]>(
|
||||
jidiSelectEventStore.jidiData
|
||||
.filter((item: any) => item.wbsCode !== 'all')
|
||||
.map((item: any) => ({
|
||||
label: item.wbsName,
|
||||
value: item.wbsCode
|
||||
}))
|
||||
);
|
||||
|
||||
// 字段名 → 中文名映射
|
||||
const fieldLabelMap: Record<string, string> = {
|
||||
stcd: '产卵场编码',
|
||||
stnm: '产卵场名称',
|
||||
sttp: '测站类型',
|
||||
stlc: '站址',
|
||||
baseId: '水电基地',
|
||||
rstcd: '所属电站',
|
||||
prtcts: '保护对象',
|
||||
cnt: '产卵场数量',
|
||||
ar: '面积',
|
||||
tp: '营造型式',
|
||||
attm: '实施时间',
|
||||
jcdt: '建成日期',
|
||||
usfl: '是否启用',
|
||||
inv: '投资',
|
||||
dtfrqcy: '监测频次',
|
||||
introduce: '简介',
|
||||
remark: '备注'
|
||||
};
|
||||
|
||||
// select 选项映射
|
||||
const selectOptionsMap: Record<string, () => any[]> = {
|
||||
sttp: () => sttpOptions.value,
|
||||
usfl: () => [
|
||||
{ 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);
|
||||
};
|
||||
|
||||
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
|
||||
? 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 变化
|
||||
watch(
|
||||
() => props.record,
|
||||
newRecord => {
|
||||
if (newRecord) {
|
||||
const converted = { ...newRecord };
|
||||
originalRecord.value = { ...converted };
|
||||
formData.value = { ...converted };
|
||||
changeOrder.value = [];
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 加载下拉数据
|
||||
const loadDropdownData = () => {
|
||||
// 加载测站类型
|
||||
sttpGetKendoList({
|
||||
filter: {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
{
|
||||
field: 'sttpCode',
|
||||
operator: 'in',
|
||||
dataType: 'string',
|
||||
value: ['SG']
|
||||
}
|
||||
]
|
||||
}
|
||||
}).then(res => {
|
||||
sttpOptions.value = (res.data?.data || []).map((item: any) => ({
|
||||
label: item.sttpName,
|
||||
value: item.sttpCode
|
||||
}));
|
||||
});
|
||||
baseNameOptions.value = jidiSelectEventStore.jidiData
|
||||
.filter((item: any) => item.wbsCode !== 'all')
|
||||
.map((item: any) => ({
|
||||
label: item.wbsName,
|
||||
value: item.wbsCode
|
||||
}));
|
||||
getEngInfoDropdown({}).then(res => {
|
||||
engInfoOptions.value = (res.data || []).map((item: any) => ({
|
||||
label: item.ennm,
|
||||
value: item.stcd
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
val => {
|
||||
if (val) {
|
||||
loadDropdownData();
|
||||
if (props.isAdd) {
|
||||
formData.value = {};
|
||||
originalRecord.value = {};
|
||||
changeOrder.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
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 addSgInfo({
|
||||
engInfo,
|
||||
source: source.trim() || '新增'
|
||||
});
|
||||
} else {
|
||||
engInfo.stcd = formData.value.stcd;
|
||||
changeOrder.value.forEach(item => {
|
||||
engInfo[item.field] = formData.value[item.field];
|
||||
});
|
||||
res = await updateSgInfo({
|
||||
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>
|
||||
@ -1,121 +0,0 @@
|
||||
<template>
|
||||
<BasicSearch
|
||||
ref="basicSearchRef"
|
||||
:searchList="searchList"
|
||||
:initial-values="initSearchData"
|
||||
:zhujianfujian="'fu'"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
>
|
||||
<template #actions>
|
||||
<a-button @click="hideBtn">{{ isHide ? '展开' : '隐藏' }}</a-button>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import BasicSearch from '@/components/BasicSearch/index.vue';
|
||||
import { sttpGetKendoList } from '@/api/system/map/ConfigManagement';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'search-finish', values: any): void;
|
||||
(e: 'reset', values: any): void;
|
||||
(e: 'add'): void;
|
||||
}>();
|
||||
|
||||
const basicSearchRef = ref();
|
||||
const isHide = ref<boolean>(false);
|
||||
const sttpOption = ref([]);
|
||||
|
||||
const initSearchData = {
|
||||
baseId: 'all',
|
||||
rstcd: null,
|
||||
stnm: null,
|
||||
sttp: null
|
||||
};
|
||||
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: 'jidiData',
|
||||
name: 'baseId',
|
||||
label: '水电基地',
|
||||
placeholder: '请输入水电基地名称',
|
||||
fieldProps: {
|
||||
allowClear: true
|
||||
},
|
||||
options: []
|
||||
},
|
||||
{
|
||||
type: 'Input',
|
||||
name: 'stnm',
|
||||
label: '产卵场名称',
|
||||
placeholder: '请输入产卵场名称',
|
||||
width: 160,
|
||||
fieldProps: {
|
||||
allowClear: true
|
||||
}
|
||||
},
|
||||
{
|
||||
col: isHide.value ? 0 : null,
|
||||
type: 'Select',
|
||||
name: 'sttp',
|
||||
label: '测站类型',
|
||||
width: 160,
|
||||
fieldProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请选择测站类型'
|
||||
},
|
||||
options: sttpOption.value
|
||||
}
|
||||
]);
|
||||
|
||||
const getBaseList = async () => {
|
||||
let params = {
|
||||
"filter": {
|
||||
"logic": "and",
|
||||
"filters": [
|
||||
{
|
||||
"field": "sttpCode",
|
||||
"operator": "in",
|
||||
"dataType": "string",
|
||||
"value": ["SG"]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
const res = await sttpGetKendoList(params);
|
||||
sttpOption.value = res.data.data.map(item => {
|
||||
return {
|
||||
label: item.sttpName,
|
||||
value: item.sttpCode
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit('search-finish', { ...values });
|
||||
};
|
||||
|
||||
const hideBtn = () => {
|
||||
isHide.value = !isHide.value;
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit('reset', initSearchData);
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
emit('add');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getBaseList();
|
||||
emit('search-finish', { ...initSearchData });
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
basicSearchRef
|
||||
});
|
||||
</script>
|
||||
@ -1,295 +0,0 @@
|
||||
<template>
|
||||
<div class="w-full h-full flex flex-col pt-[20px] pl-[20px] body_one">
|
||||
<!-- 搜索组件 -->
|
||||
<SpawnSearch
|
||||
@search-finish="onSearchFinish"
|
||||
@reset="onReset"
|
||||
@add="handleAdd"
|
||||
ref="searchRef"
|
||||
/>
|
||||
|
||||
<!-- 表格组件 -->
|
||||
<BasicTable
|
||||
ref="tableRef"
|
||||
:enableEllipsis="true"
|
||||
:scrollX="tableScrollX"
|
||||
:scrollY="tableScrollY"
|
||||
:columns="columns"
|
||||
:list-url="getSgPageList"
|
||||
>
|
||||
<template #action="{ record }">
|
||||
<a-button
|
||||
type="link"
|
||||
class="text-[#2f6b98]"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>编辑</a-button
|
||||
>
|
||||
<a-button type="link" danger size="small" @click="handleDelete(record)"
|
||||
>删除</a-button
|
||||
>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<!-- 编辑/新增 Modal -->
|
||||
<EditSpawnModal
|
||||
v-model:open="editVisible"
|
||||
:record="editRecord"
|
||||
:is-add="isAdd"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
|
||||
<!-- 删除确认 Modal -->
|
||||
<DeleteConfirmModal
|
||||
ref="deleteModalRef"
|
||||
:delete-fn="deleteSgFn"
|
||||
:label="'人工产卵场'"
|
||||
title="删除人工产卵场"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, nextTick } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import SpawnSearch from './SpawnSearch.vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import EditSpawnModal from './EditSpawnModal.vue';
|
||||
import DeleteConfirmModal from '@/views/conventionalHydropower/BasicData/DeleteConfirmModal.vue';
|
||||
import { getSgPageList, deleteSgInfo } from '@/api/DataQueryMenuModule';
|
||||
import { calcTableScrollY } from '@/utils/index';
|
||||
|
||||
const tableRef = ref();
|
||||
const searchRef = ref();
|
||||
const tableScrollY = ref<string | number>(0);
|
||||
const currentSearchParams = ref<any>({});
|
||||
|
||||
// 编辑相关
|
||||
const editVisible = ref(false);
|
||||
const editRecord = ref<any>(null);
|
||||
const isAdd = ref(false);
|
||||
const deleteModalRef = ref();
|
||||
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
key: 'stnm',
|
||||
title: '产卵场名称',
|
||||
dataIndex: 'stnm',
|
||||
visible: true,
|
||||
width: 200,
|
||||
fixed: 'left',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'stcd',
|
||||
title: '产卵场编码',
|
||||
dataIndex: 'stcd',
|
||||
visible: true,
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'sttpName',
|
||||
title: '测站类型',
|
||||
dataIndex: 'sttpName',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'stlc',
|
||||
title: '站址',
|
||||
dataIndex: 'stlc',
|
||||
visible: true,
|
||||
width: 160,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'baseName',
|
||||
title: '水电基地',
|
||||
dataIndex: 'baseName',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'ennm',
|
||||
title: '所属电站',
|
||||
dataIndex: 'ennm',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'prtcts',
|
||||
title: '保护对象',
|
||||
dataIndex: 'prtcts',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'cnt',
|
||||
title: '数量(个)',
|
||||
dataIndex: 'cnt',
|
||||
visible: true,
|
||||
width: 80,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'ar',
|
||||
title: '面积(km²)',
|
||||
dataIndex: 'ar',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'jcdt',
|
||||
title: '建成日期',
|
||||
dataIndex: 'jcdt',
|
||||
visible: true,
|
||||
width: 110,
|
||||
customRender: ({ text }) => {
|
||||
if (!text || text === '-') return '-';
|
||||
const date = dayjs(text);
|
||||
return date.isValid() ? date.format('YYYY-MM-DD') : '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'usflName',
|
||||
title: '是否启用',
|
||||
dataIndex: 'usflName',
|
||||
visible: true,
|
||||
width: 80,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'remark',
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
visible: true,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 120
|
||||
}
|
||||
]);
|
||||
|
||||
const tableScrollX = computed(() =>
|
||||
Math.max(
|
||||
columns.value.reduce(
|
||||
(sum: number, col: any) => sum + (col.width || 180),
|
||||
0
|
||||
),
|
||||
600
|
||||
)
|
||||
);
|
||||
|
||||
const buildSearchParams = (values: any) => {
|
||||
return {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
values.rstcd
|
||||
? {
|
||||
field: 'rstcd',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.rstcd
|
||||
}
|
||||
: null,
|
||||
values.baseId !== 'all'
|
||||
? {
|
||||
field: 'baseId',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.baseId
|
||||
}
|
||||
: null,
|
||||
values.stnm
|
||||
? {
|
||||
field: 'stnm',
|
||||
operator: 'contains',
|
||||
dataType: 'string',
|
||||
value: values.stnm
|
||||
}
|
||||
: null,
|
||||
values.sttp
|
||||
? {
|
||||
field: 'sttp',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.sttp
|
||||
}
|
||||
: null
|
||||
].filter(Boolean)
|
||||
};
|
||||
};
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
currentSearchParams.value = values;
|
||||
initTable(values);
|
||||
};
|
||||
|
||||
const onReset = (values: any) => {
|
||||
currentSearchParams.value = values;
|
||||
initTable(values);
|
||||
};
|
||||
|
||||
const initTable = (values: any) => {
|
||||
const params = buildSearchParams(values);
|
||||
tableRef.value.getList(params);
|
||||
};
|
||||
|
||||
// 新增
|
||||
const handleAdd = () => {
|
||||
isAdd.value = true;
|
||||
editRecord.value = null;
|
||||
editVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (record: any) => {
|
||||
isAdd.value = false;
|
||||
editRecord.value = { ...record };
|
||||
editVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑成功回调
|
||||
const handleEditSuccess = () => {
|
||||
initTable(currentSearchParams.value);
|
||||
};
|
||||
|
||||
// 删除
|
||||
const deleteSgFn = async (record: any, reason: string) => {
|
||||
return deleteSgInfo({
|
||||
ids: [record.stcd],
|
||||
source: reason
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (record: any) => {
|
||||
deleteModalRef.value?.open(record, () => {
|
||||
initTable(currentSearchParams.value);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
tableScrollY.value = calcTableScrollY();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.body_one {
|
||||
position: relative;
|
||||
z-index: 900;
|
||||
pointer-events: all;
|
||||
}
|
||||
</style>
|
||||
@ -1,394 +0,0 @@
|
||||
<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="ruleName">
|
||||
<a-input
|
||||
v-model:value="formData.ruleName"
|
||||
placeholder="请输入预警规则名称"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="预警规则类型" name="ruleType">
|
||||
<a-select
|
||||
v-model:value="formData.ruleType"
|
||||
placeholder="请选择预警规则类型"
|
||||
allow-clear
|
||||
>
|
||||
<a-select-option value="WQLVL">水质预警</a-select-option>
|
||||
<a-select-option value="EQMN">电站生态流量(环保部)</a-select-option>
|
||||
<a-select-option value="EQMNMWR">电站生态流量(水利部)</a-select-option>
|
||||
<a-select-option value="RSVRFSR">水位预警</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="规则编码" name="ruleCode">
|
||||
<a-select
|
||||
v-model:value="formData.ruleCode"
|
||||
placeholder="请选择规则编码"
|
||||
allow-clear
|
||||
>
|
||||
<a-select-option value="global">全局规则</a-select-option>
|
||||
<a-select-option value="common">通用告警规则</a-select-option>
|
||||
<a-select-option value="custom">自定义告警规则</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="所属测站" name="stcd">
|
||||
<a-input
|
||||
v-model:value="formData.stcd"
|
||||
placeholder="请输入所属测站"
|
||||
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
|
||||
: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="isShow">
|
||||
<a-select
|
||||
v-model:value="formData.isShow"
|
||||
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="24">
|
||||
<a-form-item label="备注" name="description" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||
<a-textarea
|
||||
v-model:value="formData.description"
|
||||
placeholder="请输入备注"
|
||||
:rows="3"
|
||||
/>
|
||||
</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 { addWarnInfo, updateWarnInfo } from '@/api/DataQueryMenuModule';
|
||||
import { getEngInfoDropdown } from '@/api/select';
|
||||
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
|
||||
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 confirmModalVisible = ref(false);
|
||||
|
||||
const formRules = ref<any>({
|
||||
ruleName: [{ required: true, message: '请输入预警规则名称', trigger: 'blur' }],
|
||||
ruleType: [{ required: true, message: '请选择预警规则类型', trigger: 'change' }]
|
||||
});
|
||||
|
||||
// 下拉选项
|
||||
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
|
||||
}))
|
||||
);
|
||||
|
||||
// 字段名 → 中文名映射
|
||||
const fieldLabelMap: Record<string, string> = {
|
||||
ruleName: '预警规则名称',
|
||||
ruleType: '预警规则类型',
|
||||
ruleCode: '规则编码',
|
||||
stcd: '所属测站',
|
||||
baseId: '水电基地',
|
||||
rstcd: '所属电站',
|
||||
isShow: '是否展示告警等级',
|
||||
description: '备注'
|
||||
};
|
||||
|
||||
// select 选项映射
|
||||
const selectOptionsMap: Record<string, () => any[]> = {
|
||||
ruleType: () => [
|
||||
{ label: '水质预警', value: 'WQLVL' },
|
||||
{ label: '电站生态流量(环保部)', value: 'EQMN' },
|
||||
{ label: '电站生态流量(水利部)', value: 'EQMNMWR' },
|
||||
{ label: '水位预警', value: 'RSVRFSR' }
|
||||
],
|
||||
ruleCode: () => [
|
||||
{ label: '全局规则', value: 'global' },
|
||||
{ label: '通用告警规则', value: 'common' },
|
||||
{ label: '自定义告警规则', value: 'custom' }
|
||||
],
|
||||
isShow: () => [
|
||||
{ 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);
|
||||
};
|
||||
|
||||
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
|
||||
? 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 变化
|
||||
watch(
|
||||
() => props.record,
|
||||
newRecord => {
|
||||
if (newRecord) {
|
||||
const converted = { ...newRecord };
|
||||
originalRecord.value = { ...converted };
|
||||
formData.value = { ...converted };
|
||||
changeOrder.value = [];
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 加载下拉数据
|
||||
const loadDropdownData = () => {
|
||||
baseNameOptions.value = jidiSelectEventStore.jidiData
|
||||
.filter((item: any) => item.wbsCode !== 'all')
|
||||
.map((item: any) => ({
|
||||
label: item.wbsName,
|
||||
value: item.wbsCode
|
||||
}));
|
||||
getEngInfoDropdown({}).then(res => {
|
||||
engInfoOptions.value = (res.data || []).map((item: any) => ({
|
||||
label: item.ennm,
|
||||
value: item.stcd
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
val => {
|
||||
if (val) {
|
||||
loadDropdownData();
|
||||
if (props.isAdd) {
|
||||
formData.value = {};
|
||||
originalRecord.value = {};
|
||||
changeOrder.value = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
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 addWarnInfo({
|
||||
engInfo,
|
||||
source: source.trim() || '新增'
|
||||
});
|
||||
} else {
|
||||
engInfo.id = formData.value.id;
|
||||
changeOrder.value.forEach(item => {
|
||||
engInfo[item.field] = formData.value[item.field];
|
||||
});
|
||||
res = await updateWarnInfo({
|
||||
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>
|
||||
@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<BasicSearch
|
||||
ref="basicSearchRef"
|
||||
:searchList="searchList"
|
||||
:initial-values="initSearchData"
|
||||
:zhujianfujian="'fu'"
|
||||
@reset="handleReset"
|
||||
@finish="onSearchFinish"
|
||||
>
|
||||
<template #actions>
|
||||
<a-button @click="hideBtn">{{ isHide ? '展开' : '隐藏' }}</a-button>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
</template>
|
||||
</BasicSearch>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import BasicSearch from '@/components/BasicSearch/index.vue';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'search-finish', values: any): void;
|
||||
(e: 'reset', values: any): void;
|
||||
(e: 'add'): void;
|
||||
}>();
|
||||
|
||||
const basicSearchRef = ref();
|
||||
const isHide = ref<boolean>(false);
|
||||
|
||||
const initSearchData = {
|
||||
baseId: 'all',
|
||||
rstcd: null,
|
||||
ruleName: null
|
||||
};
|
||||
|
||||
const searchList: any = computed(() => [
|
||||
{
|
||||
type: 'jidiData',
|
||||
name: 'baseId',
|
||||
label: '水电基地',
|
||||
placeholder: '请输入水电基地名称',
|
||||
fieldProps: {
|
||||
allowClear: true
|
||||
},
|
||||
options: []
|
||||
},
|
||||
{
|
||||
type: 'Input',
|
||||
name: 'ruleName',
|
||||
label: '规则名称',
|
||||
placeholder: '请输入规则名称',
|
||||
width: 160,
|
||||
fieldProps: {
|
||||
allowClear: true
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
emit('search-finish', { ...values });
|
||||
};
|
||||
|
||||
const hideBtn = () => {
|
||||
isHide.value = !isHide.value;
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
emit('reset', initSearchData);
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
emit('add');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
emit('search-finish', { ...initSearchData });
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
basicSearchRef
|
||||
});
|
||||
</script>
|
||||
@ -1,255 +0,0 @@
|
||||
<template>
|
||||
<div class="w-full h-full flex flex-col pt-[20px] pl-[20px] body_one">
|
||||
<!-- 搜索组件 -->
|
||||
<WarnSearch
|
||||
@search-finish="onSearchFinish"
|
||||
@reset="onReset"
|
||||
@add="handleAdd"
|
||||
ref="searchRef"
|
||||
/>
|
||||
|
||||
<!-- 表格组件 -->
|
||||
<BasicTable
|
||||
ref="tableRef"
|
||||
:enableEllipsis="true"
|
||||
:scrollX="tableScrollX"
|
||||
:scrollY="tableScrollY"
|
||||
:columns="columns"
|
||||
:list-url="getWarnPageList"
|
||||
>
|
||||
<template #action="{ record }">
|
||||
<a-button
|
||||
type="link"
|
||||
class="text-[#2f6b98]"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
>编辑</a-button
|
||||
>
|
||||
<a-button type="link" danger size="small" @click="handleDelete(record)"
|
||||
>删除</a-button
|
||||
>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<!-- 编辑/新增 Modal -->
|
||||
<EditWarnModal
|
||||
v-model:open="editVisible"
|
||||
:record="editRecord"
|
||||
:is-add="isAdd"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
|
||||
<!-- 删除确认 Modal -->
|
||||
<DeleteConfirmModal
|
||||
ref="deleteModalRef"
|
||||
:delete-fn="deleteWarnFn"
|
||||
:label="'智能告警'"
|
||||
title="删除智能告警"
|
||||
@success="handleEditSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, nextTick } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import WarnSearch from './WarnSearch.vue';
|
||||
import BasicTable from '@/components/BasicTable/index.vue';
|
||||
import EditWarnModal from './EditWarnModal.vue';
|
||||
import DeleteConfirmModal from '@/views/conventionalHydropower/BasicData/DeleteConfirmModal.vue';
|
||||
import { getWarnPageList, deleteWarnInfo } from '@/api/DataQueryMenuModule';
|
||||
import { calcTableScrollY } from '@/utils/index';
|
||||
|
||||
const tableRef = ref();
|
||||
const searchRef = ref();
|
||||
const tableScrollY = ref<string | number>(0);
|
||||
const currentSearchParams = ref<any>({});
|
||||
|
||||
// 编辑相关
|
||||
const editVisible = ref(false);
|
||||
const editRecord = ref<any>(null);
|
||||
const isAdd = ref(false);
|
||||
const deleteModalRef = ref();
|
||||
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
key: 'ruleName',
|
||||
title: '预警规则名称',
|
||||
dataIndex: 'ruleName',
|
||||
visible: true,
|
||||
width: 200,
|
||||
fixed: 'left',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'ruleType',
|
||||
title: '预警规则类型',
|
||||
dataIndex: 'ruleType',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'ruleCode',
|
||||
title: '规则编码',
|
||||
dataIndex: 'ruleCode',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'stcd',
|
||||
title: '所属测站',
|
||||
dataIndex: 'stcd',
|
||||
visible: true,
|
||||
width: 160,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'baseName',
|
||||
title: '水电基地',
|
||||
dataIndex: 'baseName',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'ennm',
|
||||
title: '所属电站',
|
||||
dataIndex: 'ennm',
|
||||
visible: true,
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'isShow',
|
||||
title: '展示告警等级',
|
||||
dataIndex: 'isShow',
|
||||
visible: true,
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
if (text === 1) return '展示';
|
||||
if (text === 0) return '不展示';
|
||||
return '-';
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
title: '备注',
|
||||
dataIndex: 'description',
|
||||
visible: true,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 120
|
||||
}
|
||||
]);
|
||||
|
||||
const tableScrollX = computed(() =>
|
||||
Math.max(
|
||||
columns.value.reduce(
|
||||
(sum: number, col: any) => sum + (col.width || 180),
|
||||
0
|
||||
),
|
||||
600
|
||||
)
|
||||
);
|
||||
|
||||
const buildSearchParams = (values: any) => {
|
||||
return {
|
||||
logic: 'and',
|
||||
filters: [
|
||||
values.rstcd
|
||||
? {
|
||||
field: 'rstcd',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.rstcd
|
||||
}
|
||||
: null,
|
||||
values.baseId !== 'all'
|
||||
? {
|
||||
field: 'baseId',
|
||||
operator: 'eq',
|
||||
dataType: 'string',
|
||||
value: values.baseId
|
||||
}
|
||||
: null,
|
||||
values.ruleName
|
||||
? {
|
||||
field: 'ruleName',
|
||||
operator: 'contains',
|
||||
dataType: 'string',
|
||||
value: values.ruleName
|
||||
}
|
||||
: null
|
||||
].filter(Boolean)
|
||||
};
|
||||
};
|
||||
|
||||
const onSearchFinish = (values: any) => {
|
||||
currentSearchParams.value = values;
|
||||
initTable(values);
|
||||
};
|
||||
|
||||
const onReset = (values: any) => {
|
||||
currentSearchParams.value = values;
|
||||
initTable(values);
|
||||
};
|
||||
|
||||
const initTable = (values: any) => {
|
||||
const params = buildSearchParams(values);
|
||||
tableRef.value.getList(params);
|
||||
};
|
||||
|
||||
// 新增
|
||||
const handleAdd = () => {
|
||||
isAdd.value = true;
|
||||
editRecord.value = null;
|
||||
editVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (record: any) => {
|
||||
isAdd.value = false;
|
||||
editRecord.value = { ...record };
|
||||
editVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑成功回调
|
||||
const handleEditSuccess = () => {
|
||||
initTable(currentSearchParams.value);
|
||||
};
|
||||
|
||||
// 删除(使用 id 作为主键)
|
||||
const deleteWarnFn = async (record: any, reason: string) => {
|
||||
return deleteWarnInfo({
|
||||
ids: [record.id],
|
||||
source: reason
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (record: any) => {
|
||||
deleteModalRef.value?.open(record, () => {
|
||||
initTable(currentSearchParams.value);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
tableScrollY.value = calcTableScrollY();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.body_one {
|
||||
position: relative;
|
||||
z-index: 900;
|
||||
pointer-events: all;
|
||||
}
|
||||
</style>
|
||||
@ -34,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, onUnmounted, watch, nextTick, provide,defineAsyncComponent } from 'vue';
|
||||
import { ref, computed, onMounted, onUnmounted, onActivated, onDeactivated, watch, nextTick, provide,defineAsyncComponent } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { getTreeConfiguredps, getPowerSubjectLayout } from '@/api/dianZhanZhuanTi';
|
||||
@ -193,7 +193,7 @@ function onTreeSelect(value: any, item: any) {
|
||||
waitForMapReady(() => {
|
||||
setTimeout(() => {
|
||||
if ((window as any).mapClass) {
|
||||
(window as any).mapClass.flyTopanto([Number(item.lgtd), Number(item.lttd)], 12);
|
||||
(window as any).mapClass.flyTopanto([Number(item.lgtd), Number(item.lttd)], 15);
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
@ -327,6 +327,9 @@ watch(
|
||||
const rows = sk?.gridTemplateRows?.split(' ') || [];
|
||||
const bottomRowHeight = rows[rows.length - 1];
|
||||
nextTick(() => setMapLegendPos(val.type, val, 460, bottomRowHeight));
|
||||
} else {
|
||||
// 无布局/布局无底部模块或 3D 模式:恢复地图控件默认样式(与非电站专题页一致)
|
||||
uiStore.resetMapControlsPosition();
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
@ -348,12 +351,10 @@ watch(
|
||||
|
||||
// ==================== 地图控件位置重置 ====================
|
||||
function resetMapControlPositions() {
|
||||
// 地图控制器/底图切换器:清除 store 位置覆盖,恢复组件自身默认样式(与非电站专题页一致)
|
||||
uiStore.resetMapControlsPosition();
|
||||
const legend = document.querySelector('#qgc-legendtl') as HTMLElement;
|
||||
const controller = document.querySelector('#map-controller') as HTMLElement;
|
||||
const baselayer = document.querySelector('#map-baselayer') as HTMLElement;
|
||||
if (legend) { legend.style.left = '0px'; legend.style.bottom = '0px'; }
|
||||
if (controller) { controller.style.right = '12px'; controller.style.bottom = '114px'; }
|
||||
if (baselayer) { baselayer.style.right = '60px'; baselayer.style.bottom = '0px'; }
|
||||
['#map-filter-container', '#map-compassControl', '#map-monitor'].forEach(sel => {
|
||||
const el = document.querySelector(sel) as HTMLElement;
|
||||
if (el) { el.style.left = ''; el.style.right = ''; el.style.bottom = ''; }
|
||||
@ -366,6 +367,39 @@ function collapseLegend() {
|
||||
icon?.parentElement?.click();
|
||||
}
|
||||
|
||||
// 图例操作轮询定时器(离开页面时清理,避免回调泄漏)
|
||||
let legendOpTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
const clearLegendOpTimer = () => {
|
||||
if (legendOpTimer !== null) {
|
||||
clearTimeout(legendOpTimer);
|
||||
legendOpTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
/** 进入专题页时收缩图例:图例尚未渲染则轮询等待,仅展开态才点击收起 */
|
||||
function collapseLegendOnEnter(retry = 0) {
|
||||
const btn = document.querySelector('.legendBtn') as HTMLElement | null;
|
||||
if (!btn) {
|
||||
if (retry < 30) {
|
||||
legendOpTimer = setTimeout(() => collapseLegendOnEnter(retry + 1), 200);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (btn.querySelector('.icon-fold')) btn.click();
|
||||
}
|
||||
|
||||
/** 离开专题页时展开图例:仅收起态才点击展开 */
|
||||
function expandLegendOnLeave(retry = 0) {
|
||||
const btn = document.querySelector('.legendBtn') as HTMLElement | null;
|
||||
if (!btn) {
|
||||
if (retry < 30) {
|
||||
legendOpTimer = setTimeout(() => expandLegendOnLeave(retry + 1), 200);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (btn.querySelector('.icon-unFold')) btn.click();
|
||||
}
|
||||
|
||||
// ==================== 监听 3D/2D 切换 ====================
|
||||
watch(
|
||||
() => uiStore.mapType,
|
||||
@ -411,6 +445,10 @@ watch(
|
||||
|
||||
// ==================== 生命周期 ====================
|
||||
onMounted(() => {
|
||||
// 进入电站专题页时统一关闭全局搜索抽屉(覆盖从任意页面/地图跳转进来的场景)
|
||||
uiStore.setIsSearchActive(false);
|
||||
uiStore.setGlobalDrawerOpen(false);
|
||||
|
||||
getTreeConfiguredps()
|
||||
.then((res: any) => {
|
||||
const result = res?.data ?? [];
|
||||
@ -432,13 +470,30 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
switchToSatellite();
|
||||
// 进入专题页时收缩图例
|
||||
collapseLegendOnEnter();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
clearLegendOpTimer();
|
||||
// 离开专题页时恢复展开图例
|
||||
expandLegendOnLeave();
|
||||
switchToVector();
|
||||
layoutData.value = null;
|
||||
resetMapControlPositions();
|
||||
});
|
||||
|
||||
// keep-alive 缓存场景:回到专题页收起、离开专题页展开(首次挂载时 mounted/activated 双触发,收起操作幂等)
|
||||
onActivated(() => {
|
||||
collapseLegendOnEnter();
|
||||
});
|
||||
|
||||
onDeactivated(() => {
|
||||
clearLegendOpTimer();
|
||||
expandLegendOnLeave();
|
||||
// keep-alive 缓存离开时同样清除地图控件位置覆盖,避免影响其他页面
|
||||
uiStore.resetMapControlsPosition();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user