数据管理子系统-问题bug修改

This commit is contained in:
王兴凯 2026-08-17 08:55:12 +08:00
parent 678caccbd7
commit ac5d153924
28 changed files with 2864 additions and 117 deletions

View File

@ -277,6 +277,60 @@ export function getFishReleaseMonitorList(data) {
});
}
// 过鱼设施人工数据 - 新增
export function addFpssRInfo(data) {
return request({
url: '/data/fpssR/add',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data
});
}
// 过鱼设施人工数据 - 编辑
export function updateFpssRInfo(data) {
return request({
url: '/data/fpssR/update',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data
});
}
// 过鱼设施人工数据 - 删除
export function deleteFpssRInfo(data) {
return request({
url: '/data/fpssR/delete',
method: 'post',
data
});
}
// 过鱼设施自动数据 - 编辑
export function updateFpssrlRInfo(data) {
return request({
url: '/base/fpssrlR/update',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data
});
}
// 过鱼设施自动数据 - 删除
export function deleteFpssrlRInfo(data) {
return request({
url: '/base/fpssrlR/delete',
method: 'post',
data
});
}
// 鱼类 放鱼
export function getFishReleaseList(data) {
return request({

View File

@ -131,21 +131,13 @@ const searchList: any = [
//
const columns = ref<any[]>([
{
key: "recordId",
key: "recordName",
title: "电站",
dataIndex: "recordId",
dataIndex: "recordName",
visible: true,
width: 120,
ellipsis: true,
},
{
key: "tableName",
title: "数据类型/所属表名",
dataIndex: "tableName",
visible: true,
width: 160,
ellipsis: true,
},
{
key: "operator",
title: "修改人",

View File

@ -0,0 +1,729 @@
<template>
<div
class="custom-fish-search-container"
ref="containerRef"
@mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
>
<!-- 1. 输入框区域 -->
<div
class="fish-input-wrapper"
:class="{ 'is-focused': isOpen, disabled: disabled }"
@click="handleWrapperClick"
>
<!--
核心逻辑
- isOpen true 强制显示 input并聚焦
- isOpen false 显示 selectedItem placeholder
-->
<!-- 情况 A: 显示输入框 (当下拉框打开时) -->
<input
v-if="isOpen"
ref="inputRef"
v-model="searchKeyword"
type="text"
class="visible-input"
@focus="handleInputFocus"
@input="handleSearchInput"
@blur="handleInputBlur"
@keydown.stop
@keydown.enter="handleEnterKey"
:disabled="disabled"
placeholder="请输入搜索..."
/>
<!-- 情况 B: 显示选中项或占位符 (当下拉框关闭时) -->
<div v-else class="display-value">
<span v-if="selectedItem" class="single-value">{{ selectedItem.name }}</span>
<span v-else class="placeholder">{{ placeholder }}</span>
</div>
<!-- 右侧图标 -->
<div class="suffix-icon">
<!-- Loading 状态 -->
<span v-if="loading" class="loading-icon"></span>
<!-- 清除图标当有值选中或正在搜索且鼠标悬停时显示 -->
<span
v-else-if="(selectedItem || searchKeyword) && isHovered"
class="clear-icon"
@click.stop="handleClear"
title="清空"
>
<CloseCircleOutlined />
</span>
<!-- 下拉箭头其他情况显示 -->
<span v-else class="arrow-icon" :class="{ rotate: isOpen }"
><DownOutlined
/></span>
</div>
</div>
<!-- 2. 下拉面板 (绝对定位) -->
<teleport to="body">
<transition name="fade">
<div
v-show="isOpen"
class="fish-dropdown-panel"
:style="dropdownStyle"
@mousedown.prevent
>
<!-- 顶部查询方式切换 -->
<div class="dropdown-header">
<span class="header-label">查询方式</span>
<span
class="mode-btn"
:class="{ active: !isIntelligentQuery }"
@click="switchQueryMode(false)"
>
相似度
</span>
<span
class="mode-btn"
:class="{ active: isIntelligentQuery }"
@click="switchQueryMode(true)"
>
智能查询
</span>
</div>
<div class="dropdown-body">
<!-- 左侧列表 -->
<div class="list-container" ref="listContainerRef">
<div v-if="loading" class="loading-wrapper">
<a-spin size="small" />
<span class="loading-text">搜索中...</span>
</div>
<div
v-for="opt in filteredOptions"
:key="opt.id"
class="dropdown-item"
:class="{
'is-active': isSelected(opt.id),
'is-hovered': hoveredId === opt.id,
}"
@click="handleSelectOption(opt)"
@mouseenter="hoveredId = opt.id"
>
<span class="item-name" v-html="highlightText(opt.name)"></span>
<span v-if="isSelected(opt.id)" class="check-icon"></span>
</div>
<div v-if="filteredOptions.length === 0" class="empty-tip">无匹配数据</div>
</div>
<!-- 中间分割线 -->
<div class="divider"></div>
<!-- 右侧详情预览 -->
<div class="detail-container">
<div v-if="currentDetailData" class="detail-content">
<div
class="detail-title"
v-html="highlightText(currentDetailData.name)"
></div>
<div class="detail-alias" :title="currentDetailData.alias">
<div
v-html="highlightText(currentDetailData.alias || '暂无别名')"
></div>
</div>
</div>
<div v-else class="detail-placeholder">请选择或悬停查看</div>
</div>
</div>
</div>
</transition>
</teleport>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, computed, nextTick, onBeforeUnmount } from "vue";
import { getFishDictoryDropdown, getSimilarFishDictoryDropdown } from "@/api/select";
import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao";
import { message } from "ant-design-vue";
import { CloseCircleOutlined, DownOutlined } from "@ant-design/icons-vue";
const shuJuTianBaoStore = useShuJuTianBaoStore();
// --- Props & Emits ---
interface Props {
modelValue: any; //
width?: string;
placeholder?: string;
disabled?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
placeholder: "鱼种类支持俗名查询",
width: "100%",
disabled: false,
});
const emit = defineEmits<{
(e: "update:modelValue", value: string, opt: any): void;
}>();
// --- State ---
const loading = ref(false);
const options = ref<any[]>([]);
const allOptions = ref<any[]>([]);
const searchKeyword = ref<string>("");
const hoveredId = ref<string | null>(null);
const isOpen = ref(false);
const isIntelligentQuery = ref(true);
const isHovered = ref(false); //
//
let searchTimer: any = null;
// DOM Refs
const containerRef = ref<HTMLElement | null>(null);
const inputRef = ref<HTMLInputElement | null>(null);
//
const dropdownStyle = computed(() => {
if (!containerRef.value) return {};
const rect = containerRef.value.getBoundingClientRect();
return {
top: `${rect.bottom + window.scrollY + 4}px`,
left: `${rect.left + window.scrollX}px`,
width: `${Math.max(rect.width, 400)}px`,
};
});
// --- Computed ---
const selectedItem = computed(() => {
if (!props.modelValue) return null;
return options.value.find((opt) => opt.id === props.modelValue);
});
const filteredOptions = computed(() => {
if (isIntelligentQuery.value) {
return options.value;
}
//
if (!searchKeyword.value) {
return allOptions.value; //
}
const lowerKeyword = searchKeyword.value.toLowerCase();
return allOptions.value.filter((item: any) => {
const nameMatch = item.name?.toLowerCase().includes(lowerKeyword);
const aliasMatch = item.alias?.toLowerCase().includes(lowerKeyword);
return nameMatch || aliasMatch;
});
});
const currentDetailData = computed(() => {
if (hoveredId.value) {
// options allOptions
return (
options.value.find((item: any) => item.id === hoveredId.value) ||
allOptions.value.find((item: any) => item.id === hoveredId.value)
);
}
if (props.modelValue) {
return allOptions.value.find((item: any) => item.id === props.modelValue);
}
return null;
});
// --- Methods ---
const isSelected = (id: string) => {
return props.modelValue === id;
};
const toggleDropdown = () => {
if (props.disabled) return;
if (isOpen.value) {
closeDropdown();
} else {
openDropdown();
}
};
const openDropdown = async () => {
isOpen.value = true;
await nextTick();
inputRef.value?.focus();
};
const closeDropdown = () => {
isOpen.value = false;
hoveredId.value = null;
};
//
const handleClear = () => {
// 1.
emit("update:modelValue", "", null);
// 2.
searchKeyword.value = "";
options.value = allOptions.value; //
// 3.
closeDropdown();
};
const handleWrapperClick = () => {
toggleDropdown();
};
const handleInputFocus = () => {
if (!isOpen.value) {
isOpen.value = true;
}
};
const handleInputBlur = () => {
setTimeout(() => {
// handleClickOutside
}, 100);
};
const handleSearchInput = () => {
hoveredId.value = null;
if (!isOpen.value) {
isOpen.value = true;
}
};
//
const executeSearch = () => {
const keyword = searchKeyword.value;
//
if (!isOpen.value) {
isOpen.value = true;
}
// 1.
if (!isIntelligentQuery.value) {
if (!keyword) {
options.value = allOptions.value;
}
// computed searchKeyword allOptions
return;
}
// 2.
if (!keyword) {
options.value = allOptions.value;
return;
}
// Loading
loading.value = true;
// ()
getSimilarFishDictoryDropdown({ name: keyword })
.then((res) => {
options.value = res.data || [];
loading.value = false;
})
.catch(() => {
loading.value = false;
});
};
//
const loadDefaultOptions = () => {
let data = shuJuTianBaoStore.getFishOption();
if (data && data.length > 0) {
allOptions.value = data;
options.value = data; //
} else {
loading.value = true;
getFishDictoryDropdown()
.then((res) => {
const list = res.data || [];
allOptions.value = list;
options.value = list;
loading.value = false;
shuJuTianBaoStore.setFishOption(list);
})
.catch(() => {
loading.value = false;
});
}
};
//
const handleEnterKey = (event: KeyboardEvent) => {
//
event.preventDefault();
//
executeSearch();
};
const handleSelectOption = (opt: any) => {
// 1.
if (props.modelValue === opt.id) {
emit("update:modelValue", "", null);
} else {
emit("update:modelValue", opt.id, opt);
}
// 2.
searchKeyword.value = "";
options.value = allOptions.value; // 便
// 3.
closeDropdown();
// 4.
inputRef.value?.blur();
};
const switchQueryMode = (val: boolean) => {
isIntelligentQuery.value = val;
message.success(val ? "智能查询已开启" : "相似度查询已开启");
if (searchKeyword.value) {
executeSearch(); //
} else {
options.value = allOptions.value;
}
};
const highlightText = (text: string) => {
if (!text) return "暂无别名";
if (!searchKeyword.value) return text;
const escapeRegExp = (str: string) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const reg = new RegExp(`(${escapeRegExp(searchKeyword.value)})`, "gi");
return text.replace(reg, `<span style="color: #ff4d4f; font-weight: bold;">$1</span>`);
};
//
const init = () => {
loadDefaultOptions();
};
//
const handleClickOutside = (event: MouseEvent) => {
if (!isOpen.value) return;
const target = event.target as HTMLElement;
const isInsideContainer = containerRef.value?.contains(target);
const isInsideDropdown = target.closest(".fish-dropdown-panel");
if (!isInsideContainer && !isInsideDropdown) {
closeDropdown();
}
};
const handleMouseEnter = () => {
if (!props.disabled) {
isHovered.value = true;
}
};
const handleMouseLeave = () => {
isHovered.value = false;
};
onMounted(() => {
init();
document.addEventListener("click", handleClickOutside);
});
onBeforeUnmount(() => {
document.removeEventListener("click", handleClickOutside);
});
</script>
<style lang="scss" scoped>
.custom-fish-search-container {
position: relative;
width: v-bind(width);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
Arial, sans-serif;
}
.fish-input-wrapper {
position: relative;
min-height: 32px;
padding: 4px 11px;
border: 1px solid #d9d9d9;
border-radius: 2px;
background-color: #fff;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: space-between;
&:hover {
border-color: #40a9ff;
}
&.is-focused {
border-color: #40a9ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.placeholder {
color: #bfbfbf;
}
.single-value {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: #333;
}
.display-value {
flex: 1;
overflow: hidden;
margin-right: 20px;
pointer-events: none; /* 让点击事件穿透到 wrapper */
text-overflow: ellipsis;
white-space: nowrap;
}
/* 输入框样式 */
.visible-input {
flex: 1;
border: none;
outline: none;
background: transparent;
font-size: 14px;
color: #333;
padding: 0;
margin: 0;
height: 22px;
line-height: 22px;
&::placeholder {
color: #bfbfbf;
}
}
.suffix-icon {
color: #bfbfbf;
font-size: 12px;
pointer-events: none;
margin-left: 8px;
display: flex;
align-items: center;
.rotate {
transform: rotate(180deg);
transition: transform 0.3s;
}
/* 新增:清除图标样式 */
.clear-icon {
pointer-events: auto; /* 允许点击 */
cursor: pointer;
font-size: 14px;
line-height: 1;
transition: color 0.3s;
&:hover {
color: #333;
}
}
}
}
.disabled {
background-color: #f5f5f5;
&:hover {
border-color: #d9d9d9;
}
.single-value {
color: rgba(0, 0, 0, 0.25);
}
}
/* 下拉面板样式 */
.fish-dropdown-panel {
position: absolute;
background: #fff;
border-radius: 4px;
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
z-index: 9999;
overflow: hidden;
margin-top: 4px;
}
.dropdown-header {
height: 36px;
padding: 0 12px;
display: flex;
align-items: center;
border-bottom: 1px solid #f0f0f0;
background: #fafafa;
user-select: none;
.header-label {
font-size: 12px;
color: #666;
margin-right: 8px;
}
.mode-btn {
font-size: 12px;
font-weight: bold;
cursor: pointer;
padding: 2px 6px;
border-radius: 2px;
color: #666;
margin-right: 8px;
&:last-child {
margin-right: 0;
}
&.active {
color: #005293;
background: rgba(0, 82, 147, 0.1);
}
&:hover:not(.active) {
color: #333;
}
}
}
.dropdown-body {
display: flex;
height: 300px;
}
.list-container {
width: 150px;
overflow-y: auto;
border-right: 1px solid #f0f0f0;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 3px;
}
.loading-wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 100px;
color: #999;
.loading-text {
margin-top: 8px;
font-size: 12px;
}
}
}
.dropdown-item {
padding: 8px 12px;
cursor: pointer;
font-size: 14px;
color: #333;
transition: background-color 0.2s;
display: flex;
justify-content: space-between;
align-items: center;
&:hover {
background-color: #f5f5f5;
}
&.is-active {
background-color: #e6f7ff;
color: #1890ff;
font-weight: 500;
}
&.is-hovered {
background-color: #fafafa;
}
.item-name {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.check-icon {
color: #1890ff;
font-weight: bold;
margin-left: 8px;
}
}
.divider {
width: 1px;
background-color: #e8e8e8;
height: 100%;
}
.detail-container {
width: 250px;
padding: 16px;
overflow-y: auto;
background: #fff;
display: flex;
flex-direction: column;
}
.detail-content {
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.detail-alias {
font-size: 14px;
color: #666;
line-height: 1.5;
word-break: break-all;
:deep(span) {
color: #ff4d4f;
font-weight: bold;
}
}
.detail-placeholder {
color: #999;
font-size: 14px;
text-align: center;
margin-top: 50%;
transform: translateY(-50%);
}
.empty-tip {
padding: 20px 0;
color: #999;
text-align: center;
font-size: 12px;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease, transform 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>

View File

@ -19,7 +19,7 @@
<!-- ===== 概述 ===== -->
<a-col :span="24"><div class="form-group-title">概述</div></a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="电站编码" name="stcd">
<a-input
v-model:value="formData.stcd"
@ -29,7 +29,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="电站名称" name="ennm">
<a-input
v-model:value="formData.ennm"
@ -38,7 +38,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="基地" name="baseId">
<a-select
v-model:value="formData.baseId"
@ -58,7 +58,7 @@
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="所在位置" name="addvcd">
<a-select
v-model:value="formData.addvcd"
@ -77,7 +77,7 @@
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="详细地址" name="stlc">
<a-input
v-model:value="formData.stlc"
@ -85,7 +85,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="所在河段" name="reachcd">
<a-select
v-model:value="formData.reachcd"
@ -105,7 +105,7 @@
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="所属公司" name="hycd">
<a-select
v-model:value="formData.hycd"
@ -124,7 +124,7 @@
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="所属集团" name="topHycd">
<a-select
v-model:value="formData.topHycd"
@ -143,7 +143,7 @@
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="建设状态" name="bldsttCode">
<a-select
v-model:value="formData.bldsttCode"
@ -159,7 +159,7 @@
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="建设时间" name="jcdt">
<a-date-picker
v-model:value="formData.jcdt"
@ -170,7 +170,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="第一台机组投产时间" name="piodt">
<a-date-picker
v-model:value="formData.piodt"
@ -181,7 +181,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="全部机组投产时间" name="aiodt">
<a-date-picker
v-model:value="formData.aiodt"
@ -196,7 +196,7 @@
<!-- ===== 水文 ===== -->
<a-col :span="24"><div class="form-group-title">水文</div></a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="坝址以上流域面积(km²)"
:labelCol="{ span: 10 }"
@ -210,7 +210,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="距河源距离(km)"
:labelCol="{ span: 10 }"
@ -224,7 +224,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="多年平均降雨量(mm)"
:labelCol="{ span: 10 }"
@ -238,7 +238,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="多年平均年径流量(亿m³)"
:labelCol="{ span: 10 }"
@ -251,7 +251,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -264,7 +264,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="1月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -278,7 +278,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="2月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -292,7 +292,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="3月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -306,7 +306,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="4月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -320,7 +320,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="5月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -334,7 +334,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="6月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -348,7 +348,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="7月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -362,7 +362,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="8月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -376,7 +376,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="9月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -390,7 +390,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="10月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -404,7 +404,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="11月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -418,7 +418,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="12月多年平均流量(m³/s)"
:labelCol="{ span: 10 }"
@ -432,7 +432,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="实测最大流量(m³/s)"
:labelCol="{ span: 10 }"
@ -445,7 +445,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="实测最小流量(m³/s)"
:labelCol="{ span: 10 }"
@ -458,7 +458,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="调查历史最大流量(m³/s)"
:labelCol="{ span: 10 }"
@ -471,7 +471,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="设计入库洪水流量(m³/s)"
:labelCol="{ span: 10 }"
@ -484,7 +484,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="设计洪水重现期(年)"
:labelCol="{ span: 10 }"
@ -493,7 +493,7 @@
<a-input v-model:value="formData.dsrcin" placeholder="请输入" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="校核入库洪水流量(m³/s)"
:labelCol="{ span: 10 }"
@ -506,7 +506,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="校核洪水重现期(年)"
:labelCol="{ span: 10 }"
@ -515,7 +515,7 @@
<a-input v-model:value="formData.chrcin" placeholder="请输入" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="实测最大洪量(三天)(亿m³)"
:labelCol="{ span: 10 }"
@ -528,7 +528,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="设计洪量(三天)(亿m³)"
:labelCol="{ span: 10 }"
@ -541,7 +541,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="校核洪量(三天)(亿m³)"
:labelCol="{ span: 10 }"
@ -554,7 +554,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="多年平均输沙量(万t)"
:labelCol="{ span: 10 }"
@ -567,7 +567,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="多年平均含沙量(kg/m³)"
:labelCol="{ span: 10 }"
@ -580,7 +580,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="实测最大含沙量(kg/m³)"
:labelCol="{ span: 10 }"
@ -597,7 +597,7 @@
<!-- ===== 水库 ===== -->
<a-col :span="24"><div class="form-group-title">水库</div></a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="校核洪水位(m)"
:labelCol="{ span: 10 }"
@ -611,7 +611,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="设计洪水位(m)"
:labelCol="{ span: 10 }"
@ -625,7 +625,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="正常蓄水位(m)"
:labelCol="{ span: 10 }"
@ -639,7 +639,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="防洪高水位(m)"
:labelCol="{ span: 10 }"
@ -653,7 +653,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="防洪限制水位(m)"
:labelCol="{ span: 10 }"
@ -667,7 +667,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="年消落水位(m)"
:labelCol="{ span: 10 }"
@ -681,7 +681,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="死水位(m)" :labelCol="{ span: 10 }" name="ddz">
<a-input-number
v-model:value="formData.ddz"
@ -691,7 +691,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="正常蓄水位水库面积(km²)"
name="nrzar"
@ -705,7 +705,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="回水长度(km)"
:labelCol="{ span: 10 }"
@ -719,7 +719,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="总库容(亿m³)"
:labelCol="{ span: 10 }"
@ -733,7 +733,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="正常蓄水位以下库容(亿m³)"
:labelCol="{ span: 10 }"
@ -746,7 +746,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="防洪库容(亿m³)"
:labelCol="{ span: 10 }"
@ -759,7 +759,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="调节库容(亿m³)"
:labelCol="{ span: 10 }"
@ -772,7 +772,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="死库容(亿m³)"
:labelCol="{ span: 10 }"
@ -785,7 +785,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="库容系数(%)" :labelCol="{ span: 10 }" name="cpsc">
<a-input-number
v-model:value="formData.cpsc"
@ -794,7 +794,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="调节性能" :labelCol="{ span: 10 }" name="rgcp">
<a-select
v-model:value="formData.rgcp"
@ -816,7 +816,7 @@
><div class="form-group-title">下泄流量及相应下游水位</div></a-col
>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="设计洪水位时最大下泄流量(m³/s)"
:labelCol="{ span: 12 }"
@ -829,7 +829,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="设计洪水位时最大下泄流量相应下游水位(m)"
:labelCol="{ span: 14 }"
@ -842,7 +842,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="校核洪水位时最大下泄流量(m³/s)"
:labelCol="{ span: 12 }"
@ -855,7 +855,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="校核洪水位时最大下泄流量相应下游水位(m)"
:labelCol="{ span: 14 }"
@ -868,7 +868,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="枯水期调节流量(m³/s)"
:labelCol="{ span: 12 }"
@ -881,7 +881,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="枯水期调节流量相应下游水位(m)"
:labelCol="{ span: 12 }"
@ -894,7 +894,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="发电最大引用流量(m³/s)"
:labelCol="{ span: 12 }"
@ -907,7 +907,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item
label="发电最大引用流量相应下游水位(m)"
:labelCol="{ span: 12 }"
@ -926,7 +926,7 @@
><div class="form-group-title">工程效益指标</div></a-col
>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="装机容量(万kW)" name="ttpwr">
<a-input-number
v-model:value="formData.ttpwr"
@ -936,7 +936,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="装机台数(台)" name="gncnt">
<a-input-number
v-model:value="formData.gncnt"
@ -945,12 +945,12 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="容量构成(台*MW)" name="gntp">
<a-input v-model:value="formData.gntp" placeholder="请输入" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="保证出力(MW)" name="grntpwr">
<a-input-number
v-model:value="formData.grntpwr"
@ -960,7 +960,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="多年平均年发电量(亿kW·h)" name="yrge">
<a-input-number
v-model:value="formData.yrge"
@ -969,7 +969,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="年利用小时数(h)" name="ushr">
<a-input-number
v-model:value="formData.ushr"
@ -978,7 +978,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="机组综合出力系数" name="k">
<a-input-number
v-model:value="formData.k"
@ -991,7 +991,7 @@
<!-- ===== 大坝 ===== -->
<a-col :span="24"><div class="form-group-title">大坝</div></a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="坝型" name="dmtp">
<a-input
v-model:value="formData.dmtp"
@ -1000,7 +1000,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="坝顶高程(m)" name="dmcrel">
<a-input-number
v-model:value="formData.dmcrel"
@ -1010,7 +1010,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="最大坝高(m)" name="mxdmhg">
<a-input-number
v-model:value="formData.mxdmhg"
@ -1020,7 +1020,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="坝顶长度(m)" name="dmlen">
<a-input-number
v-model:value="formData.dmlen"
@ -1034,7 +1034,7 @@
<!-- ===== 其他 ===== -->
<a-col :span="24"><div class="form-group-title">其他</div></a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="单独年发电量(亿kW·h)" name="sgyge">
<a-input-number
v-model:value="formData.sgyge"
@ -1043,7 +1043,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="联合年发电量(亿kW·h)" name="unyge">
<a-input-number
v-model:value="formData.unyge"
@ -1052,7 +1052,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="利用落差(m)" name="gap">
<a-input-number
v-model:value="formData.gap"
@ -1061,7 +1061,7 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-col :span="12">
<a-form-item label="开发方式" name="dvtp">
<a-select
v-model:value="formData.dvtp"
@ -1417,7 +1417,12 @@ const handleConfirmSubmit = async (source: string) => {
stcd: formData.value.stcd
};
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
appendSelectLabels(engInfo, changeOrder.value.map(c => c.field));
res = await updatePowerInfo({

View File

@ -718,7 +718,12 @@ const handleConfirmSubmit = async (source: string) => {
//
engInfo.id = formData.value.id;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
// inffile
const existingIds = fileList.value

View File

@ -539,7 +539,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateAiboxInfo({
engInfo,

View File

@ -527,7 +527,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateOtweInfo({
engInfo,

View File

@ -572,7 +572,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateAiInfo({
engInfo,

View File

@ -403,7 +403,14 @@ const handleConfirmSubmit = async (source: string) => {
res = await addFpInfo({ engInfo, source: source.trim() || '新增' });
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => { engInfo[item.field] = formData.value[item.field]; });
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
// fpssmn
if (Array.isArray(engInfo.fpssmn)) engInfo.fpssmn = engInfo.fpssmn.join(',');
res = await updateFpInfo({ engInfo, source: source.trim() || '编辑' });

View File

@ -450,7 +450,12 @@ const handleConfirmSubmit = async (source: string) => {
// stcd +
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateTeInfo({
engInfo,

View File

@ -44,6 +44,15 @@
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="图层编码" name="layerCode">
<a-input
v-model:value="formData.layerCode"
placeholder="请输入图层编码"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="经度(°)" name="lgtd">
<a-input-number
@ -246,6 +255,7 @@ const fieldLabelMap: Record<string, string> = {
stcd: '栖息地站码',
stnm: '栖息地名称',
stlc: '站址',
layerCode: '图层编码',
baseId: '水电基地',
rstcd: '所属电站',
bhdx: '保护对象',
@ -518,7 +528,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
// bhdx
if (Array.isArray(engInfo.bhdx)) engInfo.bhdx = engInfo.bhdx.join(',');

View File

@ -64,7 +64,7 @@ const operationLogVisible = ref(false);
const columns = ref<any[]>([
{ key: 'stnm', title: '栖息地名称', dataIndex: 'stnm', visible: true, width: 260, ellipsis: true },
{ key: 'stcd', title: '栖息地站码', dataIndex: 'stcd', visible: true, width: 320, fixed: 'left', ellipsis: true },
{ 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 },
@ -77,6 +77,7 @@ const columns = ref<any[]>([
{ key: 'bhfs', title: '保护方式', dataIndex: 'bhfs', visible: true, width: 120, ellipsis: true },
{ key: 'inv', title: '投资(亿元)', dataIndex: 'inv', visible: true, width: 120 },
{ key: 'stlc', title: '站址', dataIndex: 'stlc', visible: true, ellipsis: true,width: 220 },
{ key: 'layerCode', title: '图层编码', dataIndex: 'layerCode', visible: true, ellipsis: true, width: 160 },
{ key: 'action', title: '操作', dataIndex: 'action', fixed: 'right', width: 120 },
]);

View File

@ -486,7 +486,14 @@ const handleConfirmSubmit = async (source: string) => {
res = await addVaInfo({ engInfo, source: source.trim() || '新增' });
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => { engInfo[item.field] = formData.value[item.field]; });
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateVaInfo({ engInfo, source: source.trim() || '编辑' });
}
if (res?.code == 0 || res?.success) {

View File

@ -344,7 +344,14 @@ const handleConfirmSubmit = async (source: string) => {
res = await addEqInfo({ engInfo, source: source.trim() || '新增' });
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => { engInfo[item.field] = formData.value[item.field]; });
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateEqInfo({ engInfo, source: source.trim() || '编辑' });
}
if (res?.code == 0 || res?.success) {

View File

@ -265,7 +265,14 @@ const handleConfirmSubmit = async (source: string) => {
res = await addVdInfo({ engInfo, source: source.trim() || '新增' });
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => { engInfo[item.field] = formData.value[item.field]; });
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateVdInfo({ engInfo, source: source.trim() || '编辑' });
}
if (res?.code == 0 || res?.success) {

View File

@ -461,7 +461,12 @@ const handleConfirmSubmit = async (source: string) => {
// stcd +
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateWeInfo({
engInfo,

View File

@ -454,7 +454,12 @@ const handleConfirmSubmit = async (source: string) => {
// stcd +
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateWtInfo({
engInfo,

View File

@ -502,7 +502,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateWqInfo({
engInfo,

View File

@ -513,7 +513,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateSonarInfo({
engInfo,

View File

@ -525,7 +525,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateDwInfo({
engInfo,

View File

@ -534,7 +534,12 @@ const handleConfirmSubmit = async (source: string) => {
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => {
engInfo[item.field] = formData.value[item.field];
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateOtteInfo({
engInfo,

View File

@ -350,7 +350,14 @@ const handleConfirmSubmit = async (source: string) => {
res = await addFbInfo({ engInfo, source: source.trim() || '新增' });
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => { engInfo[item.field] = formData.value[item.field]; });
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateFbInfo({ engInfo, source: source.trim() || '编辑' });
}
if (res?.code == 0 || res?.success) {

View File

@ -305,7 +305,14 @@ const handleConfirmSubmit = async (source: string) => {
res = await addVpInfo({ engInfo, source: source.trim() || '新增' });
} else {
engInfo.stcd = formData.value.stcd;
changeOrder.value.forEach(item => { engInfo[item.field] = formData.value[item.field]; });
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
res = await updateVpInfo({ engInfo, source: source.trim() || '编辑' });
}
if (res?.code == 0 || res?.success) {

View File

@ -0,0 +1,841 @@
<template>
<a-modal
v-model:open="visible"
title="编辑过鱼自动数据"
width="70vw"
: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-select
v-model:value="formData.stcd"
placeholder="请选择过鱼设施"
allow-clear
show-search
:loading="facilityLoading"
:filter-option="filterOption"
style="width: 100%"
>
<a-select-option
v-for="item in facilityOptions"
: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="tm">
<a-date-picker
v-model:value="formData.tm"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择时间"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼种类" name="ftp">
<fishSearch v-model="formData.ftp" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="过鱼数量" name="fcnt">
<a-input-number
v-model:value="formData.fcnt"
placeholder="请输入过鱼数量"
:min="0"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="过鱼通道" name="channelno">
<a-input
v-model:value="formData.channelno"
placeholder="请输入过鱼通道"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼游向" name="direction">
<a-select
v-model:value="formData.direction"
placeholder="请选择鱼游向"
allow-clear
>
<a-select-option :value="0">上行</a-select-option>
<a-select-option :value="1">下行</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼尺寸" name="fsz">
<a-select
v-model:value="formData.fsz"
placeholder="请选择鱼尺寸"
allow-clear
>
<a-select-option value="大"></a-select-option>
<a-select-option value="中"></a-select-option>
<a-select-option value="小"></a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼长度(cm)" name="length">
<a-input-number
v-model:value="formData.length"
placeholder="请输入鱼长度"
:min="0"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼宽度(cm)" name="width">
<a-input-number
v-model:value="formData.width"
placeholder="请输入鱼宽度"
:min="0"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼速度(m/s)" name="fishspeed">
<a-input
v-model:value="formData.fishspeed"
placeholder="请输入鱼速度"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼位置" name="fishposition">
<a-input-number
v-model:value="formData.fishposition"
placeholder="请输入鱼位置"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="水温(℃)" name="temperature">
<a-input-number
v-model:value="formData.temperature"
placeholder="请输入水温"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="水位(m)" name="waterlevel">
<a-input-number
v-model:value="formData.waterlevel"
placeholder="请输入水位"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="流速(m/s)" name="speed">
<a-input-number
v-model:value="formData.speed"
placeholder="请输入流速"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="流量(m³/s)" name="q">
<a-input-number
v-model:value="formData.q"
placeholder="请输入流量"
:precision="3"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="溶氧(mg/L)" name="dox">
<a-input-number
v-model:value="formData.dox"
placeholder="请输入溶氧"
:precision="2"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="浊度(NTU)" name="tu">
<a-input-number
v-model:value="formData.tu"
placeholder="请输入浊度"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="备注" name="remark" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-textarea
v-model:value="formData.remark"
placeholder="请输入备注"
:maxlength="255"
show-count
:rows="2"
/>
</a-form-item>
</a-col>
</a-row>
<!-- 图片上传 -->
<a-row :gutter="16" class="mt-4">
<a-col :span="24">
<a-form-item label="图片" name="firstimgurl" :label-col="{ span: 3 }" :wrapper-col="{ span: 21 }">
<a-upload
v-model:file-list="picFileList"
:multiple="false"
:max-count="1"
list-type="picture-card"
:before-upload="handleBeforePicUpload"
@remove="handleRemove"
>
<div v-if="picFileList.length < 1">
<plus-outlined />
<div class="mt-2">上传图片</div>
</div>
</a-upload>
</a-form-item>
</a-col>
</a-row>
<!-- 视频上传 -->
<a-row :gutter="16" class="mt-4">
<a-col :span="24">
<a-form-item label="视频" name="videourl" :label-col="{ span: 3 }" :wrapper-col="{ span: 21 }">
<a-upload
v-model:file-list="vdpFileList"
:multiple="false"
:max-count="1"
:before-upload="handleBeforeVdpUpload"
@remove="handleRemove"
>
<a-button v-if="vdpFileList.length < 1">
<upload-outlined /> 上传视频
</a-button>
</a-upload>
</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, Upload } from 'ant-design-vue';
import { PlusOutlined, UploadOutlined } from '@ant-design/icons-vue';
import { updateFpssrlRInfo } from '@/api/DataQueryMenuModule';
import { getFishReleaseMonitorSectionList } from '@/api/DataQueryMenuModule';
import ConfirmModal from '@/components/ConfirmModal/index.vue';
import { useDraggable } from '@/utils/drag';
import fishSearch from '@/components/fishSearch/index.vue';
import { useShuJuTianBaoStore } from '@/store/modules/shuJuTianBao';
const shuJuTianBaoStore = useShuJuTianBaoStore();
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
const props = defineProps<{
open: boolean;
record?: any;
}>();
const emit = defineEmits(['update:open', 'success']);
const visible = computed({
get: () => props.open,
set: val => emit('update:open', val)
});
useDraggable(visible, { boundary: true, resetOnOpen: true });
const formRef = ref();
const confirmLoading = ref(false);
const formData = ref<any>({});
const originalRecord = ref<any>({});
const originalLabels = ref<Record<string, string>>({});
const confirmModalVisible = ref(false);
//
const facilityLoading = ref(false);
const facilityOptions = ref<any[]>([]);
//
const picFileList = ref<any[]>([]);
//
const vdpFileList = ref<any[]>([]);
const formRules = ref<any>({
stcd: [{ required: true, message: '请选择过鱼设施', trigger: 'change' }],
tm: [{ required: true, message: '请选择时间', trigger: 'change' }],
ftp: [{ required: true, message: '请选择鱼种类', trigger: 'blur' }],
fcnt: [{ required: true, message: '请输入过鱼数量', trigger: 'blur' }],
channelno: [{ required: true, message: '请输入过鱼通道', trigger: 'blur' }]
});
//
const fieldLabelMap: Record<string, string> = {
stcd: '过鱼设施',
tm: '时间',
ftp: '鱼种类',
fcnt: '过鱼数量',
fsz: '鱼尺寸',
length: '鱼长度(cm)',
width: '鱼宽度(cm)',
fishspeed: '鱼速度(m/s)',
direction: '鱼游向',
fishposition: '鱼位置',
firstimgurl: '图片',
videourl: '视频',
temperature: '水温(℃)',
waterlevel: '水位(m)',
speed: '流速(m/s)',
q: '流量(m³/s)',
dox: '溶氧(mg/L)',
tu: '浊度(NTU)',
channelno: '过鱼通道',
remark: '备注'
};
// select
const selectOptionsMap: Record<string, () => any[]> = {
stcd: () => facilityOptions.value,
ftp: () =>
shuJuTianBaoStore.getFishOption().map((item: any) => ({
label: item.name,
value: item.id
})),
direction: () => [
{ label: '上行', value: 0 },
{ label: '下行', value: 1 }
],
fsz: () => [
{ label: '大', value: '大' },
{ label: '中', value: '中' },
{ label: '小', value: '小' }
]
};
//
const changeOrder = ref<
{ field: string; label: string; oldValue: string; newValue: string }[]
>([]);
const diffList = changeOrder;
const filterOption = (inputValue: string, option: any) => {
const label = option.label || '';
const keyword = inputValue || '';
return label.includes(keyword);
};
const handleBeforePicUpload = (file: any) => {
const isImage =
file.type === 'image/jpeg' ||
file.type === 'image/png' ||
file.type === 'image/gif' ||
file.type === 'image/webp';
if (!isImage) {
message.error('只能上传图片文件JPG/PNG/GIF/WEBP');
return Upload.LIST_IGNORE;
}
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
message.error('图片大小不能超过 10MB');
return Upload.LIST_IGNORE;
}
picFileList.value = [...picFileList.value, file];
return false;
};
const handleBeforeVdpUpload = (file: any) => {
const isVideo =
file.type === 'video/mp4' ||
file.type === 'video/quicktime' ||
file.type === 'video/x-msvideo' ||
file.type === 'video/webm' ||
file.type === 'video/x-matroska';
if (!isVideo) {
message.error('只能上传视频文件MP4/MOV/AVI/WEBM/MKV');
return Upload.LIST_IGNORE;
}
const isLt100M = file.size / 1024 / 1024 < 100;
if (!isLt100M) {
message.error('视频大小不能超过 100MB');
return Upload.LIST_IGNORE;
}
vdpFileList.value = [...vdpFileList.value, file];
return false;
};
const handleRemove = () => {
return true;
};
// / id null/-/undefined
const normalizeIds = (val: any): string[] => {
if (val === null || val === undefined || val === '') return [];
return String(val)
.split(',')
.map(s => s.trim())
.filter(s => s && s !== '-' && s !== 'null' && s !== 'undefined');
};
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 resolveOriginalLabel = (field: string): string => {
return resolveSelectLabel(field, originalRecord.value[field]);
};
// formData
watch(
() => formData.value,
newData => {
const original = originalRecord.value;
for (const key in newData) {
const oldVal = original[key];
const newVal = newData[key];
if (oldVal !== newVal) {
const existingIdx = changeOrder.value.findIndex(c => c.field === key);
const oldNorm =
oldVal === null || oldVal === undefined || oldVal === '-'
? null
: oldVal;
const newNorm = newVal === null || newVal === undefined ? null : newVal;
if (oldNorm === newNorm) continue;
if (
oldNorm !== null &&
newNorm !== null &&
!isNaN(Number(oldNorm)) &&
!isNaN(Number(newNorm)) &&
Number(oldNorm) === Number(newNorm)
)
continue;
const isSelect = !!selectOptionsMap[key];
const oldDisplay = isSelect
? (originalLabels.value[key] ?? resolveSelectLabel(key, oldNorm))
: oldNorm === null
? '空'
: String(oldNorm);
const newDisplay = isSelect
? resolveSelectLabel(key, newNorm)
: newNorm === null
? '空'
: String(newNorm);
const entry = {
field: key,
label: fieldLabelMap[key] || key,
oldValue: oldDisplay,
newValue: newDisplay
};
if (existingIdx >= 0) {
changeOrder.value[existingIdx] = entry;
} else {
changeOrder.value.push(entry);
}
} else {
changeOrder.value = changeOrder.value.filter(c => c.field !== key);
}
}
},
{ deep: true }
);
// diff
watch(
() => picFileList.value,
newList => {
const originalIds = normalizeIds(originalRecord.value.firstimgurl);
const currentExistingIds = newList
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
const currentNewCount = newList.filter((f: any) => f.originFileObj).length;
const deletedCount = originalIds.filter(
(id: string) => !currentExistingIds.includes(id)
).length;
const addedCount = currentNewCount;
if (deletedCount > 0 || addedCount > 0) {
const existingIdx = changeOrder.value.findIndex(
c => c.field === 'firstimgurl'
);
const oldDisplay = `${originalIds.length}张图片`;
const parts: string[] = [];
if (deletedCount > 0) parts.push(`删除${deletedCount}`);
if (addedCount > 0) parts.push(`新增${addedCount}`);
const entry = {
field: 'firstimgurl',
label: '图片',
oldValue: oldDisplay,
newValue: parts.join('')
};
if (existingIdx >= 0) {
changeOrder.value[existingIdx] = entry;
} else {
changeOrder.value.push(entry);
}
} else {
changeOrder.value = changeOrder.value.filter(
c => c.field !== 'firstimgurl'
);
}
},
{ deep: true }
);
// diff
watch(
() => vdpFileList.value,
newList => {
const originalIds = normalizeIds(originalRecord.value.videourl);
const currentExistingIds = newList
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
const currentNewCount = newList.filter((f: any) => f.originFileObj).length;
const deletedCount = originalIds.filter(
(id: string) => !currentExistingIds.includes(id)
).length;
const addedCount = currentNewCount;
if (deletedCount > 0 || addedCount > 0) {
const existingIdx = changeOrder.value.findIndex(
c => c.field === 'videourl'
);
const oldDisplay = `${originalIds.length}个视频`;
const parts: string[] = [];
if (deletedCount > 0) parts.push(`删除${deletedCount}`);
if (addedCount > 0) parts.push(`新增${addedCount}`);
const entry = {
field: 'videourl',
label: '视频',
oldValue: oldDisplay,
newValue: parts.join('')
};
if (existingIdx >= 0) {
changeOrder.value[existingIdx] = entry;
} else {
changeOrder.value.push(entry);
}
} else {
changeOrder.value = changeOrder.value.filter(
c => c.field !== 'videourl'
);
}
},
{ deep: true }
);
const loadFacilities = async () => {
facilityLoading.value = true;
try {
const res = await getFishReleaseMonitorSectionList({
filter: {
logic: 'and',
filters: [
{
field: 'mway',
operator: 'eq',
dataType: 'string',
value: '2'
}
]
},
select: ['stcd', 'stnm', 'mway']
});
facilityOptions.value = (res.data?.data || []).map((item: any) => ({
label: item.stnm,
value: item.stcd
}));
} catch (error) {
console.error('获取过鱼设施列表失败:', error);
} finally {
facilityLoading.value = false;
}
};
// record
watch(
() => props.record,
newRecord => {
if (newRecord) {
const converted = { ...newRecord };
// "-" null
for (const key in converted) {
if (converted[key] === '-') {
converted[key] = null;
}
}
// select/input-number
[
'direction',
'fcnt',
'length',
'width',
'fishposition',
'temperature',
'waterlevel',
'speed',
'q',
'dox',
'tu'
].forEach(key => {
if (
converted[key] !== null &&
converted[key] !== undefined &&
converted[key] !== ''
) {
converted[key] = Number(converted[key]);
}
});
// fishSearch fishId(id)
const ftpName = converted.ftp;
if (converted.fishId) {
converted.ftp = converted.fishId;
}
originalRecord.value = { ...converted };
formData.value = { ...converted };
changeOrder.value = [];
// select label
const labels: Record<string, string> = {};
for (const key in converted) {
if (selectOptionsMap[key]) {
labels[key] = resolveOriginalLabel(key);
}
}
// ftp 使 id
if (ftpName && converted.fishId) {
labels.ftp = ftpName;
}
originalLabels.value = labels;
//
const picIds = normalizeIds(converted.firstimgurl);
if (picIds.length > 0) {
picFileList.value = picIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}&view=jpg`,
isExisting: true
}));
} else {
picFileList.value = [];
}
//
const vdpIds = normalizeIds(converted.videourl);
if (vdpIds.length > 0) {
vdpFileList.value = vdpIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}`,
isExisting: true
}));
} else {
vdpFileList.value = [];
}
}
},
{ deep: true }
);
//
watch(facilityOptions, () => {
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);
}
}
// ftp id
if (originalLabels.value.ftp) {
labels.ftp = originalLabels.value.ftp;
}
originalLabels.value = labels;
});
watch(
() => props.open,
val => {
if (val) {
loadFacilities();
// /
const picIds = normalizeIds(props.record?.firstimgurl);
picFileList.value = picIds.length
? picIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}&view=jpg`,
isExisting: true
}))
: [];
const vdpIds = normalizeIds(props.record?.videourl);
vdpFileList.value = vdpIds.length
? vdpIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}`,
isExisting: true
}))
: [];
}
}
);
const handleOk = async () => {
try {
await formRef.value?.validateFields();
if (changeOrder.value.length === 0) {
message.info('未检测到任何修改');
return;
}
confirmModalVisible.value = true;
} catch (error) {
console.error('验证失败:', error);
}
};
const buildFormData = (engInfo: Record<string, any>, source: string) => {
const formData = new FormData();
const data = {
engInfo,
source: source.trim() || '编辑'
};
formData.append('data', JSON.stringify(data));
//
picFileList.value.forEach((file: any) => {
if (file.originFileObj) {
formData.append('picFiles', file.originFileObj);
}
});
//
vdpFileList.value.forEach((file: any) => {
if (file.originFileObj) {
formData.append('vdFiles', file.originFileObj);
}
});
return formData;
};
//
const formatDateTime = (val: any): any => {
if (val === null || val === undefined || val === '') return val;
const str = String(val);
return str.length === 10 ? `${str} 00:00:00` : str;
};
const handleConfirmSubmit = async (source: string) => {
confirmLoading.value = true;
try {
//
const engInfo: Record<string, any> = {};
engInfo.id = formData.value.id;
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
// id
const existingPicIds = picFileList.value
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
if (existingPicIds.length > 0) {
engInfo.firstimgurl = existingPicIds.join(',');
} else {
delete engInfo.firstimgurl;
}
// id
const existingVdpIds = vdpFileList.value
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
if (existingVdpIds.length > 0) {
engInfo.videourl = existingVdpIds.join(',');
} else {
delete engInfo.videourl;
}
//
if (engInfo.tm) {
engInfo.tm = formatDateTime(engInfo.tm);
}
const fd = buildFormData(engInfo, source);
const res = await updateFpssrlRInfo(fd);
if (res?.code == 0 || res?.success) {
message.success('编辑成功');
confirmModalVisible.value = false;
visible.value = false;
emit('success');
} else {
message.error(res?.msg || '编辑失败');
}
} 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>

View File

@ -0,0 +1,823 @@
<template>
<a-modal
v-model:open="visible"
:title="isAdd ? '新增过鱼人工数据' : '编辑过鱼人工数据'"
width="70vw"
: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-select
v-model:value="formData.stcd"
placeholder="请选择过鱼设施"
allow-clear
show-search
:loading="facilityLoading"
:filter-option="filterOption"
style="width: 100%"
>
<a-select-option
v-for="item in facilityOptions"
: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="tm">
<a-date-picker
v-model:value="formData.tm"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择填报时间"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼种类" name="ftp">
<fishSearch v-model="formData.ftp" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="过鱼数量(尾)" name="fcnt">
<a-input-number
v-model:value="formData.fcnt"
placeholder="请输入过鱼数量"
:min="0"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼游向" name="direction">
<a-select
v-model:value="formData.direction"
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>
<a-select-option :value="3">下行折返</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="是否鱼苗" name="isfs">
<a-select
v-model:value="formData.isfs"
placeholder="请选择是否鱼苗"
allow-clear
>
<a-select-option :value="0"></a-select-option>
<a-select-option :value="1"></a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="开始日期" name="strdt">
<a-date-picker
v-model:value="formData.strdt"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="请选择开始日期"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="结束日期" name="enddt">
<a-date-picker
v-model:value="formData.enddt"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
:disabled-date="disabledEndDate"
placeholder="请选择结束日期"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="鱼类规格(cm)" name="fsz">
<a-input
v-model:value="formData.fsz"
placeholder="请输入鱼类规格"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="平均体重(g)" name="fwet">
<a-input-number
v-model:value="formData.fwet"
placeholder="请输入平均体重"
:min="0"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="当日运行次数" name="rcnt">
<a-input-number
v-model:value="formData.rcnt"
placeholder="请输入当日运行次数"
:min="0"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="引用流量" name="fq">
<a-input-number
v-model:value="formData.fq"
placeholder="请输入过鱼设施引用流量"
:min="0"
:precision="3"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="水温(℃)" name="wtmp">
<a-input-number
v-model:value="formData.wtmp"
placeholder="请输入水温"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<!-- 图片上传 -->
<a-row :gutter="16" class="mt-4">
<a-col :span="24">
<a-form-item
label="图片"
name="picpth"
:label-col="{ span: 3 }"
:wrapper-col="{ span: 21 }"
>
<a-upload
v-model:file-list="picFileList"
:multiple="false"
:max-count="1"
list-type="picture-card"
:before-upload="handleBeforePicUpload"
@remove="handleRemove"
>
<div v-if="picFileList.length < 1">
<plus-outlined />
<div class="mt-2">上传图片</div>
</div>
</a-upload>
</a-form-item>
</a-col>
</a-row>
<!-- 视频上传 -->
<a-row :gutter="16" class="mt-4">
<a-col :span="24">
<a-form-item
label="视频"
name="vdpth"
:label-col="{ span: 3 }"
:wrapper-col="{ span: 21 }"
>
<a-upload
v-model:file-list="vdpFileList"
:multiple="false"
:max-count="1"
:before-upload="handleBeforeVdpUpload"
@remove="handleRemove"
>
<a-button v-if="vdpFileList.length < 1">
<upload-outlined /> 上传视频
</a-button>
</a-upload>
</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, Upload } from 'ant-design-vue';
import { PlusOutlined, UploadOutlined } from '@ant-design/icons-vue';
import { addFpssRInfo, updateFpssRInfo } from '@/api/DataQueryMenuModule';
import { getFishReleaseMonitorSectionList } from '@/api/DataQueryMenuModule';
import ConfirmModal from '@/components/ConfirmModal/index.vue';
import { useDraggable } from '@/utils/drag';
import fishSearch from '@/components/fishSearch/index.vue';
import { useShuJuTianBaoStore } from '@/store/modules/shuJuTianBao';
const shuJuTianBaoStore = useShuJuTianBaoStore();
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
const props = defineProps<{
open: boolean;
record?: any;
isAdd?: boolean;
}>();
const emit = defineEmits(['update:open', 'success']);
const visible = computed({
get: () => props.open,
set: val => emit('update:open', val)
});
useDraggable(visible, { boundary: true, resetOnOpen: true });
const formRef = ref();
const confirmLoading = ref(false);
const formData = ref<any>({});
const originalRecord = ref<any>({});
const originalLabels = ref<Record<string, string>>({});
const confirmModalVisible = ref(false);
//
const facilityLoading = ref(false);
const facilityOptions = ref<any[]>([]);
//
const picFileList = ref<any[]>([]);
//
const vdpFileList = ref<any[]>([]);
const formRules = ref<any>({
stcd: [{ required: true, message: '请选择过鱼设施', trigger: 'change' }],
tm: [{ required: true, message: '请选择填报时间', trigger: 'change' }],
ftp: [{ required: true, message: '请输入鱼种类', trigger: 'blur' }],
fcnt: [{ required: true, message: '请输入过鱼数量', trigger: 'blur' }],
strdt: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
direction: [{ required: true, message: '请选择鱼游向', trigger: 'change' }],
isfs: [{ required: true, message: '请选择是否鱼苗', trigger: 'change' }]
});
//
const fieldLabelMap: Record<string, string> = {
stcd: '过鱼设施',
tm: '填报时间',
ftp: '鱼种类',
fsz: '鱼类规格(cm)',
fcnt: '过鱼数量(尾)',
fwet: '平均体重(g)',
strdt: '开始日期',
enddt: '结束日期',
direction: '鱼游向',
rcnt: '当日运行次数',
fq: '引用流量',
wtmp: '水温(℃)',
isfs: '是否鱼苗',
picpth: '图片',
vdpth: '视频'
};
// select
const selectOptionsMap: Record<string, () => any[]> = {
stcd: () => facilityOptions.value,
ftp: () =>
shuJuTianBaoStore.getFishOption().map((item: any) => ({
label: item.name,
value: item.id
})),
direction: () => [
{ label: '上行', value: 0 },
{ label: '下行', value: 1 },
{ label: '上行折返', value: 2 },
{ label: '下行折返', value: 3 }
],
isfs: () => [
{ label: '否', value: 0 },
{ label: '是', value: 1 }
]
};
//
const changeOrder = ref<
{ field: string; label: string; oldValue: string; newValue: string }[]
>([]);
const diffList = changeOrder;
const filterOption = (inputValue: string, option: any) => {
const label = option.label || '';
const keyword = inputValue || '';
return label.includes(keyword);
};
const disabledEndDate = (current: any) => {
if (formData.value?.strdt) {
return current && current < new Date(`${formData.value.strdt} 00:00:00`);
}
return false;
};
const handleBeforePicUpload = (file: any) => {
const isImage =
file.type === 'image/jpeg' ||
file.type === 'image/png' ||
file.type === 'image/gif' ||
file.type === 'image/webp';
if (!isImage) {
message.error('只能上传图片文件JPG/PNG/GIF/WEBP');
return Upload.LIST_IGNORE;
}
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
message.error('图片大小不能超过 10MB');
return Upload.LIST_IGNORE;
}
picFileList.value = [...picFileList.value, file];
return false;
};
const handleBeforeVdpUpload = (file: any) => {
const isVideo =
file.type === 'video/mp4' ||
file.type === 'video/quicktime' ||
file.type === 'video/x-msvideo' ||
file.type === 'video/webm' ||
file.type === 'video/x-matroska';
if (!isVideo) {
message.error('只能上传视频文件MP4/MOV/AVI/WEBM/MKV');
return Upload.LIST_IGNORE;
}
const isLt100M = file.size / 1024 / 1024 < 100;
if (!isLt100M) {
message.error('视频大小不能超过 100MB');
return Upload.LIST_IGNORE;
}
vdpFileList.value = [...vdpFileList.value, file];
return false;
};
const handleRemove = () => {
return true;
};
// / id null/-/undefined
const normalizeIds = (val: any): string[] => {
if (val === null || val === undefined || val === '') return [];
return String(val)
.split(',')
.map(s => s.trim())
.filter(s => s && s !== '-' && s !== 'null' && s !== 'undefined');
};
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 resolveOriginalLabel = (field: string): string => {
return resolveSelectLabel(field, originalRecord.value[field]);
};
// formData
watch(
() => formData.value,
newData => {
const original = originalRecord.value;
for (const key in newData) {
const oldVal = original[key];
const newVal = newData[key];
if (oldVal !== newVal) {
const existingIdx = changeOrder.value.findIndex(c => c.field === key);
const oldNorm =
oldVal === null || oldVal === undefined || oldVal === '-'
? null
: oldVal;
const newNorm = newVal === null || newVal === undefined ? null : newVal;
if (oldNorm === newNorm) continue;
if (
oldNorm !== null &&
newNorm !== null &&
!isNaN(Number(oldNorm)) &&
!isNaN(Number(newNorm)) &&
Number(oldNorm) === Number(newNorm)
)
continue;
const isSelect = !!selectOptionsMap[key];
const oldDisplay = isSelect
? originalLabels.value[key] ?? resolveSelectLabel(key, oldNorm)
: oldNorm === null
? '空'
: String(oldNorm);
const newDisplay = isSelect
? resolveSelectLabel(key, newNorm)
: newNorm === null
? '空'
: String(newNorm);
const entry = {
field: key,
label: fieldLabelMap[key] || key,
oldValue: oldDisplay,
newValue: newDisplay
};
if (existingIdx >= 0) {
changeOrder.value[existingIdx] = entry;
} else {
changeOrder.value.push(entry);
}
} else {
changeOrder.value = changeOrder.value.filter(c => c.field !== key);
}
}
},
{ deep: true }
);
// diff
watch(
() => picFileList.value,
newList => {
const originalIds = normalizeIds(
originalRecord.value.picpth || originalRecord.value.firstimgurl
);
const currentExistingIds = newList
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
const currentNewCount = newList.filter((f: any) => f.originFileObj).length;
const deletedCount = originalIds.filter(
(id: string) => !currentExistingIds.includes(id)
).length;
const addedCount = currentNewCount;
if (deletedCount > 0 || addedCount > 0) {
const existingIdx = changeOrder.value.findIndex(
c => c.field === 'picpth'
);
const oldDisplay = `${originalIds.length}张图片`;
const parts: string[] = [];
if (deletedCount > 0) parts.push(`删除${deletedCount}`);
if (addedCount > 0) parts.push(`新增${addedCount}`);
const entry = {
field: 'picpth',
label: '图片',
oldValue: oldDisplay,
newValue: parts.join('')
};
if (existingIdx >= 0) {
changeOrder.value[existingIdx] = entry;
} else {
changeOrder.value.push(entry);
}
} else {
changeOrder.value = changeOrder.value.filter(c => c.field !== 'picpth');
}
},
{ deep: true }
);
// diff
watch(
() => vdpFileList.value,
newList => {
const originalIds = normalizeIds(
originalRecord.value.vdpth || originalRecord.value.videourl
);
const currentExistingIds = newList
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
const currentNewCount = newList.filter((f: any) => f.originFileObj).length;
const deletedCount = originalIds.filter(
(id: string) => !currentExistingIds.includes(id)
).length;
const addedCount = currentNewCount;
if (deletedCount > 0 || addedCount > 0) {
const existingIdx = changeOrder.value.findIndex(c => c.field === 'vdpth');
const oldDisplay = `${originalIds.length}个视频`;
const parts: string[] = [];
if (deletedCount > 0) parts.push(`删除${deletedCount}`);
if (addedCount > 0) parts.push(`新增${addedCount}`);
const entry = {
field: 'vdpth',
label: '视频',
oldValue: oldDisplay,
newValue: parts.join('')
};
if (existingIdx >= 0) {
changeOrder.value[existingIdx] = entry;
} else {
changeOrder.value.push(entry);
}
} else {
changeOrder.value = changeOrder.value.filter(c => c.field !== 'vdpth');
}
},
{ deep: true }
);
const loadFacilities = async () => {
facilityLoading.value = true;
try {
const res = await getFishReleaseMonitorSectionList({
filter: {
logic: 'and',
filters: [
{
field: 'mway',
operator: 'eq',
dataType: 'string',
value: '1'
}
]
},
select: ['stcd', 'stnm', 'mway']
});
facilityOptions.value = (res.data?.data || []).map((item: any) => ({
label: item.stnm,
value: item.stcd
}));
} catch (error) {
console.error('获取过鱼设施列表失败:', error);
} finally {
facilityLoading.value = false;
}
};
// record
watch(
() => props.record,
newRecord => {
if (newRecord) {
const converted = { ...newRecord };
// "-" null
for (const key in converted) {
if (converted[key] === '-') {
converted[key] = null;
}
}
// select/input-number
['direction', 'isfs', 'fcnt', 'fwet', 'rcnt', 'fq', 'wtmp'].forEach(
key => {
if (
converted[key] !== null &&
converted[key] !== undefined &&
converted[key] !== ''
) {
converted[key] = Number(converted[key]);
}
}
);
// fishSearch fishId(id)
const ftpName = converted.ftp;
if (converted.fishId) {
converted.ftp = converted.fishId;
}
originalRecord.value = { ...converted };
formData.value = { ...converted };
changeOrder.value = [];
// select label
const labels: Record<string, string> = {};
for (const key in converted) {
if (selectOptionsMap[key]) {
labels[key] = resolveOriginalLabel(key);
}
}
// ftp 使 id
if (ftpName && converted.fishId) {
labels.ftp = ftpName;
}
originalLabels.value = labels;
// firstimgurl
const picIds = normalizeIds(converted.picpth || converted.firstimgurl);
if (picIds.length > 0) {
picFileList.value = picIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}&view=jpg`,
isExisting: true
}));
} else {
picFileList.value = [];
}
// videourl
const vdpIds = normalizeIds(converted.vdpth || converted.videourl);
if (vdpIds.length > 0) {
vdpFileList.value = vdpIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}`,
isExisting: true
}));
} else {
vdpFileList.value = [];
}
}
},
{ deep: true }
);
//
watch(facilityOptions, () => {
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);
}
}
// ftp id
if (originalLabels.value.ftp) {
labels.ftp = originalLabels.value.ftp;
}
originalLabels.value = labels;
});
watch(
() => props.open,
val => {
if (val) {
loadFacilities();
if (props.isAdd) {
formData.value = {};
originalRecord.value = {};
changeOrder.value = [];
picFileList.value = [];
vdpFileList.value = [];
} else {
// /
const picIds = normalizeIds(
props.record?.picpth || props.record?.firstimgurl
);
picFileList.value = picIds.length
? picIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}&view=jpg`,
isExisting: true
}))
: [];
const vdpIds = normalizeIds(
props.record?.vdpth || props.record?.videourl
);
vdpFileList.value = vdpIds.length
? vdpIds.map((id: string) => ({
uid: id,
name: id,
status: 'done',
url: `${baseUrl}/?${id}`,
isExisting: true
}))
: [];
}
}
}
);
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 buildFormData = (engInfo: Record<string, any>, source: string) => {
const formData = new FormData();
const data = {
engInfo,
source: source.trim() || (props.isAdd ? '新增' : '编辑')
};
formData.append('data', JSON.stringify(data));
//
picFileList.value.forEach((file: any) => {
if (file.originFileObj) {
formData.append('picFiles', file.originFileObj);
}
});
//
vdpFileList.value.forEach((file: any) => {
if (file.originFileObj) {
formData.append('vdFiles', file.originFileObj);
}
});
return formData;
};
//
const formatDateTime = (val: any): any => {
if (val === null || val === undefined || val === '') return val;
const str = String(val);
return str.length === 10 ? `${str} 00:00:00` : str;
};
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);
} else {
//
engInfo.id = formData.value.id;
changeOrder.value.forEach(item => {
// select undefined/null
let val = formData.value[item.field];
if (val === null || val === undefined) {
val = '';
}
engInfo[item.field] = val;
});
// id
const existingPicIds = picFileList.value
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
if (existingPicIds.length > 0) {
engInfo.picpth = existingPicIds.join(',');
} else {
delete engInfo.picpth;
}
// id
const existingVdpIds = vdpFileList.value
.filter((f: any) => f.isExisting)
.map((f: any) => f.uid);
if (existingVdpIds.length > 0) {
engInfo.vdpth = existingVdpIds.join(',');
} else {
delete engInfo.vdpth;
}
}
//
['tm', 'strdt', 'enddt'].forEach(field => {
if (engInfo[field]) {
engInfo[field] = formatDateTime(engInfo[field]);
}
});
const fd = buildFormData(engInfo, source);
res = props.isAdd ? await addFpssRInfo(fd) : await updateFpssRInfo(fd);
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>

View File

@ -7,6 +7,7 @@
@export-btn="exportBtn"
@search-finish="onSearchFinish"
@reset="onReset"
@seeEdit="handleSeeEdit"
ref="searchRef"
/>
<!-- 表格组件 -->
@ -20,6 +21,18 @@
sort: sort
}"
>
<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>
<!-- 图片预览弹框 -->
@ -49,6 +62,24 @@
></video>
</div>
</a-modal>
<!-- 编辑 Modal -->
<EditFishDataAutoModal
v-model:open="editVisible"
:record="editRecord"
@success="handleEditSuccess"
/>
<!-- 删除确认 Modal -->
<DeleteConfirmModal
ref="deleteModalRef"
:delete-fn="deleteFpssrlFn"
:label="'过鱼自动数据'"
title="删除过鱼自动数据"
@success="handleEditSuccess"
/>
<OperationLogModal v-model:open="operationLogVisible" :table-name="'SD_FPSS_A'" />
</div>
</template>
<script setup lang="ts">
@ -57,9 +88,12 @@ import dayjs from 'dayjs';
import { Button } from 'ant-design-vue';
import FishDataSearch from './FishDataSearch.vue';
import BasicTable from '@/components/BasicTable/index.vue';
import { getFishReleaseMonitorList } from '@/api/DataQueryMenuModule';
import { getFishReleaseMonitorList, deleteFpssrlRInfo } from '@/api/DataQueryMenuModule';
import { calcTableScrollY } from '@/utils/index';
import { useDraggable } from '@/utils/drag';
import EditFishDataAutoModal from './EditFishDataAutoModal.vue';
import DeleteConfirmModal from '@/views/conventionalHydropower/BasicData/DeleteConfirmModal.vue';
import OperationLogModal from '@/components/OperationLogModal/index.vue';
const sort = ref<any>([
{
@ -89,6 +123,12 @@ const tableScrollY = ref<string | number>(0);
const currentSearchParams = ref<any>({});
const exportLoading = ref(false);
// //
const editVisible = ref(false);
const editRecord = ref<any>(null);
const deleteModalRef = ref();
const operationLogVisible = ref(false);
//
const imagePreviewVisible = ref(false);
const previewImageUrl = ref('');
@ -291,6 +331,13 @@ const tableColumns = ref<any[]>([
() => '查看视频'
);
}
},
{
key: 'action',
title: '操作',
dataIndex: 'action',
fixed: 'right',
width: 120
}
]);
@ -394,6 +441,35 @@ const initTable = (values: any) => {
tableRef.value.getList(params);
};
const handleSeeEdit = () => {
operationLogVisible.value = true;
};
//
const handleEdit = (record: any) => {
editRecord.value = { ...record };
editVisible.value = true;
};
//
const handleEditSuccess = () => {
initTable(currentSearchParams.value);
};
//
const deleteFpssrlFn = async (record: any, reason: string) => {
return deleteFpssrlRInfo({
ids: [record.id],
source: reason
});
};
const handleDelete = (record: any) => {
deleteModalRef.value?.open(record, () => {
initTable(currentSearchParams.value);
});
};
onMounted(() => {
nextTick(() => {
tableScrollY.value = calcTableScrollY();

View File

@ -7,6 +7,8 @@
@export-btn="exportBtn"
@search-finish="onSearchFinish"
@reset="onReset"
@add="handleAdd"
@seeEdit="handleSeeEdit"
ref="searchRef"
/>
<!-- 表格组件 -->
@ -20,6 +22,18 @@
sort: sort
}"
>
<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>
<!-- 图片预览弹框 -->
@ -49,6 +63,25 @@
></video>
</div>
</a-modal>
<!-- 编辑/新增 Modal -->
<EditFishDataManualModal
v-model:open="editVisible"
:record="editRecord"
:is-add="isAdd"
@success="handleEditSuccess"
/>
<!-- 删除确认 Modal -->
<DeleteConfirmModal
ref="deleteModalRef"
:delete-fn="deleteFpssFn"
:label="'过鱼人工数据'"
title="删除过鱼人工数据"
@success="handleEditSuccess"
/>
<OperationLogModal v-model:open="operationLogVisible" :table-name="'SD_FPSS_R'" />
</div>
</template>
<script setup lang="ts">
@ -57,9 +90,12 @@ import dayjs from 'dayjs';
import { Button } from 'ant-design-vue';
import FishDataSearch from './FishDataSearch.vue';
import BasicTable from '@/components/BasicTable/index.vue';
import { getFishReleaseMonitorList } from '@/api/DataQueryMenuModule';
import { getFishReleaseMonitorList, deleteFpssRInfo } from '@/api/DataQueryMenuModule';
import { calcTableScrollY } from '@/utils/index';
import { useDraggable } from '@/utils/drag';
import EditFishDataManualModal from './EditFishDataManualModal.vue';
import DeleteConfirmModal from '@/views/conventionalHydropower/BasicData/DeleteConfirmModal.vue';
import OperationLogModal from '@/components/OperationLogModal/index.vue';
const sort = ref<any>([
{
@ -89,6 +125,13 @@ const tableScrollY = ref<string | number>(0);
const currentSearchParams = ref<any>({});
const exportLoading = ref(false);
// /
const editVisible = ref(false);
const editRecord = ref<any>(null);
const isAdd = ref(false);
const deleteModalRef = ref();
const operationLogVisible = ref(false);
//
const imagePreviewVisible = ref(false);
const previewImageUrl = ref('');
@ -256,6 +299,13 @@ const tableColumns = ref<any[]>([
() => '查看视频'
);
}
},
{
key: 'action',
title: '操作',
dataIndex: 'action',
fixed: 'right',
width: 120
}
]);
@ -359,6 +409,43 @@ const initTable = (values: any) => {
tableRef.value.getList(params);
};
//
const handleAdd = () => {
isAdd.value = true;
editRecord.value = null;
editVisible.value = true;
};
const handleSeeEdit = () => {
operationLogVisible.value = true;
};
//
const handleEdit = (record: any) => {
isAdd.value = false;
editRecord.value = { ...record };
editVisible.value = true;
};
//
const handleEditSuccess = () => {
initTable(currentSearchParams.value);
};
//
const deleteFpssFn = async (record: any, reason: string) => {
return deleteFpssRInfo({
ids: [record.id],
source: reason
});
};
const handleDelete = (record: any) => {
deleteModalRef.value?.open(record, () => {
initTable(currentSearchParams.value);
});
};
onMounted(() => {
nextTick(() => {
tableScrollY.value = calcTableScrollY();

View File

@ -57,6 +57,8 @@
</a-form-item-rest>
</template>
<template #actions>
<a-button v-if="props.mway === '1'" type="primary" @click="handleAdd">新增</a-button>
<a-button type="primary" @click="seeEdit">查看修改</a-button>
<a-button :loading="exportLoading" @click="exportBtn">导出</a-button>
</template>
</BasicSearch>
@ -75,6 +77,8 @@ const emit = defineEmits<{
(e: 'export-btn'): void;
(e: 'reset', values: any): void;
(e: 'search-finish', values: any): void;
(e: 'add'): void;
(e: 'seeEdit'): void;
}>();
const basicSearchRef = ref<any>();
@ -153,7 +157,15 @@ const onSearchFinish = (values: any) => {
const exportBtn = () => {
emit('export-btn');
};
const initCrossSectionList = params => {
const handleAdd = () => {
emit('add');
};
const seeEdit = () => {
emit('seeEdit');
};
const initCrossSectionList = (params, setDefault = false) => {
const filters = [];
if (params) {
if (params.rvcd != '' && params.rvcd != 'all') {
@ -173,6 +185,13 @@ const initCrossSectionList = params => {
});
}
}
// /
filters.push({
field: 'mway',
operator: 'eq',
dataType: 'string',
value: props.mway
});
crossSectionListLoading.value = true;
getFishReleaseMonitorSectionList({
filter: {
@ -183,6 +202,15 @@ const initCrossSectionList = params => {
}).then(res => {
if (res.data?.data) {
crossSectionList.value = res.data?.data;
//
if (setDefault && crossSectionList.value.length > 0) {
const firstStcd = crossSectionList.value[0].stcd;
initSearchData.stcd = firstStcd;
if (basicSearchRef.value?.formData) {
basicSearchRef.value.formData.stcd = firstStcd;
}
handleSearchFinish({ ...initSearchData, stcd: firstStcd });
}
}
crossSectionListLoading.value = false;
});
@ -233,9 +261,8 @@ onMounted(() => {
min: `${now.subtract(5, 'year').format('YYYY-MM-DD')} 00:00:00`,
max: `${now.format('YYYY-MM-DD')} 23:59:59`
};
initCrossSectionList();
// 使 handleSearchFinish jcdt
handleSearchFinish({ ...initSearchData });
//
initCrossSectionList(undefined, true);
});
</script>