数据管理子系统-问题bug修改
This commit is contained in:
parent
678caccbd7
commit
ac5d153924
@ -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) {
|
export function getFishReleaseList(data) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@ -131,21 +131,13 @@ const searchList: any = [
|
|||||||
// 表格列配置
|
// 表格列配置
|
||||||
const columns = ref<any[]>([
|
const columns = ref<any[]>([
|
||||||
{
|
{
|
||||||
key: "recordId",
|
key: "recordName",
|
||||||
title: "电站",
|
title: "电站",
|
||||||
dataIndex: "recordId",
|
dataIndex: "recordName",
|
||||||
visible: true,
|
visible: true,
|
||||||
width: 120,
|
width: 120,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "tableName",
|
|
||||||
title: "数据类型/所属表名",
|
|
||||||
dataIndex: "tableName",
|
|
||||||
visible: true,
|
|
||||||
width: 160,
|
|
||||||
ellipsis: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "operator",
|
key: "operator",
|
||||||
title: "修改人",
|
title: "修改人",
|
||||||
|
|||||||
729
frontend-sjgl/src/components/fishSearch/index.vue
Normal file
729
frontend-sjgl/src/components/fishSearch/index.vue
Normal 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>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<!-- ===== 概述 ===== -->
|
<!-- ===== 概述 ===== -->
|
||||||
<a-col :span="24"><div class="form-group-title">概述</div></a-col>
|
<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-form-item label="电站编码" name="stcd">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.stcd"
|
v-model:value="formData.stcd"
|
||||||
@ -29,7 +29,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="电站名称" name="ennm">
|
<a-form-item label="电站名称" name="ennm">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.ennm"
|
v-model:value="formData.ennm"
|
||||||
@ -38,7 +38,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="基地" name="baseId">
|
<a-form-item label="基地" name="baseId">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.baseId"
|
v-model:value="formData.baseId"
|
||||||
@ -58,7 +58,7 @@
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="所在位置" name="addvcd">
|
<a-form-item label="所在位置" name="addvcd">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.addvcd"
|
v-model:value="formData.addvcd"
|
||||||
@ -77,7 +77,7 @@
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="详细地址" name="stlc">
|
<a-form-item label="详细地址" name="stlc">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.stlc"
|
v-model:value="formData.stlc"
|
||||||
@ -85,7 +85,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="所在河段" name="reachcd">
|
<a-form-item label="所在河段" name="reachcd">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.reachcd"
|
v-model:value="formData.reachcd"
|
||||||
@ -105,7 +105,7 @@
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="所属公司" name="hycd">
|
<a-form-item label="所属公司" name="hycd">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.hycd"
|
v-model:value="formData.hycd"
|
||||||
@ -124,7 +124,7 @@
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="所属集团" name="topHycd">
|
<a-form-item label="所属集团" name="topHycd">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.topHycd"
|
v-model:value="formData.topHycd"
|
||||||
@ -143,7 +143,7 @@
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="建设状态" name="bldsttCode">
|
<a-form-item label="建设状态" name="bldsttCode">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.bldsttCode"
|
v-model:value="formData.bldsttCode"
|
||||||
@ -159,7 +159,7 @@
|
|||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="建设时间" name="jcdt">
|
<a-form-item label="建设时间" name="jcdt">
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
v-model:value="formData.jcdt"
|
v-model:value="formData.jcdt"
|
||||||
@ -170,7 +170,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="第一台机组投产时间" name="piodt">
|
<a-form-item label="第一台机组投产时间" name="piodt">
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
v-model:value="formData.piodt"
|
v-model:value="formData.piodt"
|
||||||
@ -181,7 +181,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="全部机组投产时间" name="aiodt">
|
<a-form-item label="全部机组投产时间" name="aiodt">
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
v-model:value="formData.aiodt"
|
v-model:value="formData.aiodt"
|
||||||
@ -196,7 +196,7 @@
|
|||||||
<!-- ===== 水文 ===== -->
|
<!-- ===== 水文 ===== -->
|
||||||
<a-col :span="24"><div class="form-group-title">水文</div></a-col>
|
<a-col :span="24"><div class="form-group-title">水文</div></a-col>
|
||||||
|
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="坝址以上流域面积(km²)"
|
label="坝址以上流域面积(km²)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -210,7 +210,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="距河源距离(km)"
|
label="距河源距离(km)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -224,7 +224,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="多年平均降雨量(mm)"
|
label="多年平均降雨量(mm)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -238,7 +238,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="多年平均年径流量(亿m³)"
|
label="多年平均年径流量(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -251,7 +251,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="多年平均流量(m³/s)"
|
label="多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -264,7 +264,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="1月多年平均流量(m³/s)"
|
label="1月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -278,7 +278,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="2月多年平均流量(m³/s)"
|
label="2月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -292,7 +292,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="3月多年平均流量(m³/s)"
|
label="3月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -306,7 +306,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="4月多年平均流量(m³/s)"
|
label="4月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -320,7 +320,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="5月多年平均流量(m³/s)"
|
label="5月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -334,7 +334,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="6月多年平均流量(m³/s)"
|
label="6月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -348,7 +348,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="7月多年平均流量(m³/s)"
|
label="7月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -362,7 +362,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="8月多年平均流量(m³/s)"
|
label="8月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -376,7 +376,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="9月多年平均流量(m³/s)"
|
label="9月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -390,7 +390,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="10月多年平均流量(m³/s)"
|
label="10月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -404,7 +404,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="11月多年平均流量(m³/s)"
|
label="11月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -418,7 +418,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="12月多年平均流量(m³/s)"
|
label="12月多年平均流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -432,7 +432,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="实测最大流量(m³/s)"
|
label="实测最大流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -445,7 +445,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="实测最小流量(m³/s)"
|
label="实测最小流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -458,7 +458,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="调查历史最大流量(m³/s)"
|
label="调查历史最大流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -471,7 +471,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="设计入库洪水流量(m³/s)"
|
label="设计入库洪水流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -484,7 +484,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="设计洪水重现期(年)"
|
label="设计洪水重现期(年)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -493,7 +493,7 @@
|
|||||||
<a-input v-model:value="formData.dsrcin" placeholder="请输入" />
|
<a-input v-model:value="formData.dsrcin" placeholder="请输入" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="校核入库洪水流量(m³/s)"
|
label="校核入库洪水流量(m³/s)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -506,7 +506,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="校核洪水重现期(年)"
|
label="校核洪水重现期(年)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -515,7 +515,7 @@
|
|||||||
<a-input v-model:value="formData.chrcin" placeholder="请输入" />
|
<a-input v-model:value="formData.chrcin" placeholder="请输入" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="实测最大洪量(三天)(亿m³)"
|
label="实测最大洪量(三天)(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -528,7 +528,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="设计洪量(三天)(亿m³)"
|
label="设计洪量(三天)(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -541,7 +541,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="校核洪量(三天)(亿m³)"
|
label="校核洪量(三天)(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -554,7 +554,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="多年平均输沙量(万t)"
|
label="多年平均输沙量(万t)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -567,7 +567,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="多年平均含沙量(kg/m³)"
|
label="多年平均含沙量(kg/m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -580,7 +580,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="实测最大含沙量(kg/m³)"
|
label="实测最大含沙量(kg/m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -597,7 +597,7 @@
|
|||||||
<!-- ===== 水库 ===== -->
|
<!-- ===== 水库 ===== -->
|
||||||
<a-col :span="24"><div class="form-group-title">水库</div></a-col>
|
<a-col :span="24"><div class="form-group-title">水库</div></a-col>
|
||||||
|
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="校核洪水位(m)"
|
label="校核洪水位(m)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -611,7 +611,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="设计洪水位(m)"
|
label="设计洪水位(m)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -625,7 +625,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="正常蓄水位(m)"
|
label="正常蓄水位(m)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -639,7 +639,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="防洪高水位(m)"
|
label="防洪高水位(m)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -653,7 +653,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="防洪限制水位(m)"
|
label="防洪限制水位(m)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -667,7 +667,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="年消落水位(m)"
|
label="年消落水位(m)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -681,7 +681,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="死水位(m)" :labelCol="{ span: 10 }" name="ddz">
|
<a-form-item label="死水位(m)" :labelCol="{ span: 10 }" name="ddz">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.ddz"
|
v-model:value="formData.ddz"
|
||||||
@ -691,7 +691,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="正常蓄水位水库面积(km²)"
|
label="正常蓄水位水库面积(km²)"
|
||||||
name="nrzar"
|
name="nrzar"
|
||||||
@ -705,7 +705,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="回水长度(km)"
|
label="回水长度(km)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -719,7 +719,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="总库容(亿m³)"
|
label="总库容(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -733,7 +733,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="正常蓄水位以下库容(亿m³)"
|
label="正常蓄水位以下库容(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -746,7 +746,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="防洪库容(亿m³)"
|
label="防洪库容(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -759,7 +759,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="调节库容(亿m³)"
|
label="调节库容(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -772,7 +772,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="死库容(亿m³)"
|
label="死库容(亿m³)"
|
||||||
:labelCol="{ span: 10 }"
|
:labelCol="{ span: 10 }"
|
||||||
@ -785,7 +785,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="库容系数(%)" :labelCol="{ span: 10 }" name="cpsc">
|
<a-form-item label="库容系数(%)" :labelCol="{ span: 10 }" name="cpsc">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.cpsc"
|
v-model:value="formData.cpsc"
|
||||||
@ -794,7 +794,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="调节性能" :labelCol="{ span: 10 }" name="rgcp">
|
<a-form-item label="调节性能" :labelCol="{ span: 10 }" name="rgcp">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.rgcp"
|
v-model:value="formData.rgcp"
|
||||||
@ -816,7 +816,7 @@
|
|||||||
><div class="form-group-title">下泄流量及相应下游水位</div></a-col
|
><div class="form-group-title">下泄流量及相应下游水位</div></a-col
|
||||||
>
|
>
|
||||||
|
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="设计洪水位时最大下泄流量(m³/s)"
|
label="设计洪水位时最大下泄流量(m³/s)"
|
||||||
:labelCol="{ span: 12 }"
|
:labelCol="{ span: 12 }"
|
||||||
@ -829,7 +829,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="设计洪水位时最大下泄流量相应下游水位(m)"
|
label="设计洪水位时最大下泄流量相应下游水位(m)"
|
||||||
:labelCol="{ span: 14 }"
|
:labelCol="{ span: 14 }"
|
||||||
@ -842,7 +842,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="校核洪水位时最大下泄流量(m³/s)"
|
label="校核洪水位时最大下泄流量(m³/s)"
|
||||||
:labelCol="{ span: 12 }"
|
:labelCol="{ span: 12 }"
|
||||||
@ -855,7 +855,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="校核洪水位时最大下泄流量相应下游水位(m)"
|
label="校核洪水位时最大下泄流量相应下游水位(m)"
|
||||||
:labelCol="{ span: 14 }"
|
:labelCol="{ span: 14 }"
|
||||||
@ -868,7 +868,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="枯水期调节流量(m³/s)"
|
label="枯水期调节流量(m³/s)"
|
||||||
:labelCol="{ span: 12 }"
|
:labelCol="{ span: 12 }"
|
||||||
@ -881,7 +881,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="枯水期调节流量相应下游水位(m)"
|
label="枯水期调节流量相应下游水位(m)"
|
||||||
:labelCol="{ span: 12 }"
|
:labelCol="{ span: 12 }"
|
||||||
@ -894,7 +894,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="发电最大引用流量(m³/s)"
|
label="发电最大引用流量(m³/s)"
|
||||||
:labelCol="{ span: 12 }"
|
:labelCol="{ span: 12 }"
|
||||||
@ -907,7 +907,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="发电最大引用流量相应下游水位(m)"
|
label="发电最大引用流量相应下游水位(m)"
|
||||||
:labelCol="{ span: 12 }"
|
:labelCol="{ span: 12 }"
|
||||||
@ -926,7 +926,7 @@
|
|||||||
><div class="form-group-title">工程效益指标</div></a-col
|
><div class="form-group-title">工程效益指标</div></a-col
|
||||||
>
|
>
|
||||||
|
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="装机容量(万kW)" name="ttpwr">
|
<a-form-item label="装机容量(万kW)" name="ttpwr">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.ttpwr"
|
v-model:value="formData.ttpwr"
|
||||||
@ -936,7 +936,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="装机台数(台)" name="gncnt">
|
<a-form-item label="装机台数(台)" name="gncnt">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.gncnt"
|
v-model:value="formData.gncnt"
|
||||||
@ -945,12 +945,12 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="容量构成(台*MW)" name="gntp">
|
<a-form-item label="容量构成(台*MW)" name="gntp">
|
||||||
<a-input v-model:value="formData.gntp" placeholder="请输入" />
|
<a-input v-model:value="formData.gntp" placeholder="请输入" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="保证出力(MW)" name="grntpwr">
|
<a-form-item label="保证出力(MW)" name="grntpwr">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.grntpwr"
|
v-model:value="formData.grntpwr"
|
||||||
@ -960,7 +960,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="多年平均年发电量(亿kW·h)" name="yrge">
|
<a-form-item label="多年平均年发电量(亿kW·h)" name="yrge">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.yrge"
|
v-model:value="formData.yrge"
|
||||||
@ -969,7 +969,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="年利用小时数(h)" name="ushr">
|
<a-form-item label="年利用小时数(h)" name="ushr">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.ushr"
|
v-model:value="formData.ushr"
|
||||||
@ -978,7 +978,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="机组综合出力系数" name="k">
|
<a-form-item label="机组综合出力系数" name="k">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.k"
|
v-model:value="formData.k"
|
||||||
@ -991,7 +991,7 @@
|
|||||||
<!-- ===== 大坝 ===== -->
|
<!-- ===== 大坝 ===== -->
|
||||||
<a-col :span="24"><div class="form-group-title">大坝</div></a-col>
|
<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-form-item label="坝型" name="dmtp">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.dmtp"
|
v-model:value="formData.dmtp"
|
||||||
@ -1000,7 +1000,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="坝顶高程(m)" name="dmcrel">
|
<a-form-item label="坝顶高程(m)" name="dmcrel">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.dmcrel"
|
v-model:value="formData.dmcrel"
|
||||||
@ -1010,7 +1010,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="最大坝高(m)" name="mxdmhg">
|
<a-form-item label="最大坝高(m)" name="mxdmhg">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.mxdmhg"
|
v-model:value="formData.mxdmhg"
|
||||||
@ -1020,7 +1020,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="坝顶长度(m)" name="dmlen">
|
<a-form-item label="坝顶长度(m)" name="dmlen">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.dmlen"
|
v-model:value="formData.dmlen"
|
||||||
@ -1034,7 +1034,7 @@
|
|||||||
<!-- ===== 其他 ===== -->
|
<!-- ===== 其他 ===== -->
|
||||||
<a-col :span="24"><div class="form-group-title">其他</div></a-col>
|
<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-form-item label="单独年发电量(亿kW·h)" name="sgyge">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.sgyge"
|
v-model:value="formData.sgyge"
|
||||||
@ -1043,7 +1043,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="联合年发电量(亿kW·h)" name="unyge">
|
<a-form-item label="联合年发电量(亿kW·h)" name="unyge">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.unyge"
|
v-model:value="formData.unyge"
|
||||||
@ -1052,7 +1052,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="利用落差(m)" name="gap">
|
<a-form-item label="利用落差(m)" name="gap">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-model:value="formData.gap"
|
v-model:value="formData.gap"
|
||||||
@ -1061,7 +1061,7 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8">
|
<a-col :span="12">
|
||||||
<a-form-item label="开发方式" name="dvtp">
|
<a-form-item label="开发方式" name="dvtp">
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formData.dvtp"
|
v-model:value="formData.dvtp"
|
||||||
@ -1417,7 +1417,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
stcd: formData.value.stcd
|
stcd: formData.value.stcd
|
||||||
};
|
};
|
||||||
changeOrder.value.forEach(item => {
|
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));
|
appendSelectLabels(engInfo, changeOrder.value.map(c => c.field));
|
||||||
res = await updatePowerInfo({
|
res = await updatePowerInfo({
|
||||||
|
|||||||
@ -718,7 +718,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
// 编辑时只传修改过的字段
|
// 编辑时只传修改过的字段
|
||||||
engInfo.id = formData.value.id;
|
engInfo.id = formData.value.id;
|
||||||
changeOrder.value.forEach(item => {
|
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
|
// 保留剩余的已有图片 inffile
|
||||||
const existingIds = fileList.value
|
const existingIds = fileList.value
|
||||||
|
|||||||
@ -539,7 +539,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateAiboxInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -527,7 +527,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateOtweInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -572,7 +572,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateAiInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -403,7 +403,14 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
res = await addFpInfo({ engInfo, source: source.trim() || '新增' });
|
res = await addFpInfo({ engInfo, source: source.trim() || '新增' });
|
||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
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 多选:数组 → 逗号分隔字符串
|
// 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() || '编辑' });
|
res = await updateFpInfo({ engInfo, source: source.trim() || '编辑' });
|
||||||
|
|||||||
@ -450,7 +450,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
// 编辑时只传 stcd + 修改过的字段
|
// 编辑时只传 stcd + 修改过的字段
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateTeInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -44,6 +44,15 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</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-col :span="8">
|
||||||
<a-form-item label="经度(°)" name="lgtd">
|
<a-form-item label="经度(°)" name="lgtd">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
@ -246,6 +255,7 @@ const fieldLabelMap: Record<string, string> = {
|
|||||||
stcd: '栖息地站码',
|
stcd: '栖息地站码',
|
||||||
stnm: '栖息地名称',
|
stnm: '栖息地名称',
|
||||||
stlc: '站址',
|
stlc: '站址',
|
||||||
|
layerCode: '图层编码',
|
||||||
baseId: '水电基地',
|
baseId: '水电基地',
|
||||||
rstcd: '所属电站',
|
rstcd: '所属电站',
|
||||||
bhdx: '保护对象',
|
bhdx: '保护对象',
|
||||||
@ -518,7 +528,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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 多选:数组 → 逗号分隔字符串
|
// bhdx 多选:数组 → 逗号分隔字符串
|
||||||
if (Array.isArray(engInfo.bhdx)) engInfo.bhdx = engInfo.bhdx.join(',');
|
if (Array.isArray(engInfo.bhdx)) engInfo.bhdx = engInfo.bhdx.join(',');
|
||||||
|
|||||||
@ -64,7 +64,7 @@ const operationLogVisible = ref(false);
|
|||||||
|
|
||||||
const columns = ref<any[]>([
|
const columns = ref<any[]>([
|
||||||
{ key: 'stnm', title: '栖息地名称', dataIndex: 'stnm', visible: true, width: 260, ellipsis: true },
|
{ 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: 'baseName', title: '水电基地', dataIndex: 'baseName', visible: true, width: 120, ellipsis: true },
|
||||||
{ key: 'ennm', title: '所属电站', dataIndex: 'ennm', visible: true, width: 150, 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: '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: 'bhfs', title: '保护方式', dataIndex: 'bhfs', visible: true, width: 120, ellipsis: true },
|
||||||
{ key: 'inv', title: '投资(亿元)', dataIndex: 'inv', visible: true, width: 120 },
|
{ key: 'inv', title: '投资(亿元)', dataIndex: 'inv', visible: true, width: 120 },
|
||||||
{ key: 'stlc', title: '站址', dataIndex: 'stlc', visible: true, ellipsis: true,width: 220 },
|
{ 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 },
|
{ key: 'action', title: '操作', dataIndex: 'action', fixed: 'right', width: 120 },
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -486,7 +486,14 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
res = await addVaInfo({ engInfo, source: source.trim() || '新增' });
|
res = await addVaInfo({ engInfo, source: source.trim() || '新增' });
|
||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
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() || '编辑' });
|
res = await updateVaInfo({ engInfo, source: source.trim() || '编辑' });
|
||||||
}
|
}
|
||||||
if (res?.code == 0 || res?.success) {
|
if (res?.code == 0 || res?.success) {
|
||||||
|
|||||||
@ -344,7 +344,14 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
res = await addEqInfo({ engInfo, source: source.trim() || '新增' });
|
res = await addEqInfo({ engInfo, source: source.trim() || '新增' });
|
||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
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() || '编辑' });
|
res = await updateEqInfo({ engInfo, source: source.trim() || '编辑' });
|
||||||
}
|
}
|
||||||
if (res?.code == 0 || res?.success) {
|
if (res?.code == 0 || res?.success) {
|
||||||
|
|||||||
@ -265,7 +265,14 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
res = await addVdInfo({ engInfo, source: source.trim() || '新增' });
|
res = await addVdInfo({ engInfo, source: source.trim() || '新增' });
|
||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
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() || '编辑' });
|
res = await updateVdInfo({ engInfo, source: source.trim() || '编辑' });
|
||||||
}
|
}
|
||||||
if (res?.code == 0 || res?.success) {
|
if (res?.code == 0 || res?.success) {
|
||||||
|
|||||||
@ -461,7 +461,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
// 编辑时只传 stcd + 修改过的字段
|
// 编辑时只传 stcd + 修改过的字段
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateWeInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -454,7 +454,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
// 编辑时只传 stcd + 修改过的字段
|
// 编辑时只传 stcd + 修改过的字段
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateWtInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -502,7 +502,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateWqInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -513,7 +513,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateSonarInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -525,7 +525,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateDwInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -534,7 +534,12 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
engInfo.stcd = formData.value.stcd;
|
||||||
changeOrder.value.forEach(item => {
|
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({
|
res = await updateOtteInfo({
|
||||||
engInfo,
|
engInfo,
|
||||||
|
|||||||
@ -350,7 +350,14 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
res = await addFbInfo({ engInfo, source: source.trim() || '新增' });
|
res = await addFbInfo({ engInfo, source: source.trim() || '新增' });
|
||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
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() || '编辑' });
|
res = await updateFbInfo({ engInfo, source: source.trim() || '编辑' });
|
||||||
}
|
}
|
||||||
if (res?.code == 0 || res?.success) {
|
if (res?.code == 0 || res?.success) {
|
||||||
|
|||||||
@ -305,7 +305,14 @@ const handleConfirmSubmit = async (source: string) => {
|
|||||||
res = await addVpInfo({ engInfo, source: source.trim() || '新增' });
|
res = await addVpInfo({ engInfo, source: source.trim() || '新增' });
|
||||||
} else {
|
} else {
|
||||||
engInfo.stcd = formData.value.stcd;
|
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() || '编辑' });
|
res = await updateVpInfo({ engInfo, source: source.trim() || '编辑' });
|
||||||
}
|
}
|
||||||
if (res?.code == 0 || res?.success) {
|
if (res?.code == 0 || res?.success) {
|
||||||
|
|||||||
@ -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>
|
||||||
@ -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>
|
||||||
@ -7,6 +7,7 @@
|
|||||||
@export-btn="exportBtn"
|
@export-btn="exportBtn"
|
||||||
@search-finish="onSearchFinish"
|
@search-finish="onSearchFinish"
|
||||||
@reset="onReset"
|
@reset="onReset"
|
||||||
|
@seeEdit="handleSeeEdit"
|
||||||
ref="searchRef"
|
ref="searchRef"
|
||||||
/>
|
/>
|
||||||
<!-- 表格组件 -->
|
<!-- 表格组件 -->
|
||||||
@ -20,6 +21,18 @@
|
|||||||
sort: sort
|
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>
|
</BasicTable>
|
||||||
|
|
||||||
<!-- 图片预览弹框 -->
|
<!-- 图片预览弹框 -->
|
||||||
@ -49,6 +62,24 @@
|
|||||||
></video>
|
></video>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -57,9 +88,12 @@ import dayjs from 'dayjs';
|
|||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
import FishDataSearch from './FishDataSearch.vue';
|
import FishDataSearch from './FishDataSearch.vue';
|
||||||
import BasicTable from '@/components/BasicTable/index.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 { calcTableScrollY } from '@/utils/index';
|
||||||
import { useDraggable } from '@/utils/drag';
|
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>([
|
const sort = ref<any>([
|
||||||
{
|
{
|
||||||
@ -89,6 +123,12 @@ const tableScrollY = ref<string | number>(0);
|
|||||||
const currentSearchParams = ref<any>({});
|
const currentSearchParams = ref<any>({});
|
||||||
const exportLoading = ref(false);
|
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 imagePreviewVisible = ref(false);
|
||||||
const previewImageUrl = ref('');
|
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);
|
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(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
tableScrollY.value = calcTableScrollY();
|
tableScrollY.value = calcTableScrollY();
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
@export-btn="exportBtn"
|
@export-btn="exportBtn"
|
||||||
@search-finish="onSearchFinish"
|
@search-finish="onSearchFinish"
|
||||||
@reset="onReset"
|
@reset="onReset"
|
||||||
|
@add="handleAdd"
|
||||||
|
@seeEdit="handleSeeEdit"
|
||||||
ref="searchRef"
|
ref="searchRef"
|
||||||
/>
|
/>
|
||||||
<!-- 表格组件 -->
|
<!-- 表格组件 -->
|
||||||
@ -20,6 +22,18 @@
|
|||||||
sort: sort
|
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>
|
</BasicTable>
|
||||||
|
|
||||||
<!-- 图片预览弹框 -->
|
<!-- 图片预览弹框 -->
|
||||||
@ -49,6 +63,25 @@
|
|||||||
></video>
|
></video>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -57,9 +90,12 @@ import dayjs from 'dayjs';
|
|||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
import FishDataSearch from './FishDataSearch.vue';
|
import FishDataSearch from './FishDataSearch.vue';
|
||||||
import BasicTable from '@/components/BasicTable/index.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 { calcTableScrollY } from '@/utils/index';
|
||||||
import { useDraggable } from '@/utils/drag';
|
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>([
|
const sort = ref<any>([
|
||||||
{
|
{
|
||||||
@ -89,6 +125,13 @@ const tableScrollY = ref<string | number>(0);
|
|||||||
const currentSearchParams = ref<any>({});
|
const currentSearchParams = ref<any>({});
|
||||||
const exportLoading = ref(false);
|
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 imagePreviewVisible = ref(false);
|
||||||
const previewImageUrl = ref('');
|
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);
|
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(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
tableScrollY.value = calcTableScrollY();
|
tableScrollY.value = calcTableScrollY();
|
||||||
|
|||||||
@ -57,6 +57,8 @@
|
|||||||
</a-form-item-rest>
|
</a-form-item-rest>
|
||||||
</template>
|
</template>
|
||||||
<template #actions>
|
<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>
|
<a-button :loading="exportLoading" @click="exportBtn">导出</a-button>
|
||||||
</template>
|
</template>
|
||||||
</BasicSearch>
|
</BasicSearch>
|
||||||
@ -75,6 +77,8 @@ const emit = defineEmits<{
|
|||||||
(e: 'export-btn'): void;
|
(e: 'export-btn'): void;
|
||||||
(e: 'reset', values: any): void;
|
(e: 'reset', values: any): void;
|
||||||
(e: 'search-finish', values: any): void;
|
(e: 'search-finish', values: any): void;
|
||||||
|
(e: 'add'): void;
|
||||||
|
(e: 'seeEdit'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const basicSearchRef = ref<any>();
|
const basicSearchRef = ref<any>();
|
||||||
@ -153,7 +157,15 @@ const onSearchFinish = (values: any) => {
|
|||||||
const exportBtn = () => {
|
const exportBtn = () => {
|
||||||
emit('export-btn');
|
emit('export-btn');
|
||||||
};
|
};
|
||||||
const initCrossSectionList = params => {
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
emit('add');
|
||||||
|
};
|
||||||
|
|
||||||
|
const seeEdit = () => {
|
||||||
|
emit('seeEdit');
|
||||||
|
};
|
||||||
|
const initCrossSectionList = (params, setDefault = false) => {
|
||||||
const filters = [];
|
const filters = [];
|
||||||
if (params) {
|
if (params) {
|
||||||
if (params.rvcd != '' && params.rvcd != 'all') {
|
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;
|
crossSectionListLoading.value = true;
|
||||||
getFishReleaseMonitorSectionList({
|
getFishReleaseMonitorSectionList({
|
||||||
filter: {
|
filter: {
|
||||||
@ -183,6 +202,15 @@ const initCrossSectionList = params => {
|
|||||||
}).then(res => {
|
}).then(res => {
|
||||||
if (res.data?.data) {
|
if (res.data?.data) {
|
||||||
crossSectionList.value = 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;
|
crossSectionListLoading.value = false;
|
||||||
});
|
});
|
||||||
@ -233,9 +261,8 @@ onMounted(() => {
|
|||||||
min: `${now.subtract(5, 'year').format('YYYY-MM-DD')} 00:00:00`,
|
min: `${now.subtract(5, 'year').format('YYYY-MM-DD')} 00:00:00`,
|
||||||
max: `${now.format('YYYY-MM-DD')} 23:59:59`
|
max: `${now.format('YYYY-MM-DD')} 23:59:59`
|
||||||
};
|
};
|
||||||
initCrossSectionList();
|
// 首次加载:请求设施列表后默认选中第一条并触发搜索
|
||||||
// 使用 handleSearchFinish 确保包含 jcdt 等完整参数
|
initCrossSectionList(undefined, true);
|
||||||
handleSearchFinish({ ...initSearchData });
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user