diff --git a/frontend/src/api/guoYuSheShiShuJuTianBao/index.ts b/frontend/src/api/guoYuSheShiShuJuTianBao/index.ts index ef96df2..bd5eb6d 100644 --- a/frontend/src/api/guoYuSheShiShuJuTianBao/index.ts +++ b/frontend/src/api/guoYuSheShiShuJuTianBao/index.ts @@ -81,13 +81,6 @@ export function cancelImportTask(data:any) { data }); } -// 查询导入任务 -export function getImportTask() { - return request({ - url: '/data/importTask/list', - method: 'get' - }); -} //检测用户导入状态 export function checkImportStatus() { return request({ @@ -95,3 +88,20 @@ export function checkImportStatus() { method: 'get' }); } + +// 查询用户导入导入结果 +export function getLastImportResult() { + return request({ + url: '/data/fishDraft/getLastImportResult', + method: 'get' + }); +} + +// 批量保存草稿 +export function batchSaveDraft(data:any) { + return request({ + url: '/data/fishDraft/batchSaveDraft', + method: 'post', + data + }); +} diff --git a/frontend/src/components/BasicSearch/index.vue b/frontend/src/components/BasicSearch/index.vue index a0bd480..1775b01 100644 --- a/frontend/src/components/BasicSearch/index.vue +++ b/frontend/src/components/BasicSearch/index.vue @@ -78,12 +78,15 @@ :value="formData.baseId" placeholder="请选择" @change="dataDimensionDataChange" + show-search + :filter-option="filterOption" style="width: 135px" > {{ opt.basename }} @@ -92,12 +95,15 @@ :value="formData.rstcd" placeholder="请选择电站" @change="stcdIdChange" + show-search + :filter-option="filterOption" style="width: 135px" > {{ opt.ennm }} @@ -113,11 +119,14 @@ :allow-clear="item.fieldProps?.allowClear" :style="{ width: item.width ? item.width + 'px' : '200px' }" @change="(val) => triggerManualValuesChange(item.name, val)" + show-search + :filter-option="filterOption" > {{ opt[item.values?.name] || opt.label || opt.dictName }} @@ -207,6 +216,10 @@ const formRef = ref(); const formData = reactive({}); const rules = reactive>({}); +const filterOption = (inputValue: string, option: any) => { + if (!option.label) return false; + return option.label.indexOf(inputValue) !== -1; +}; // 2. 创建计算属性,自动过滤掉 false/null/undefined 的项 const validSearchList = computed(() => { return props.searchList.filter((item) => item); diff --git a/frontend/src/components/fishSearch/index.vue b/frontend/src/components/fishSearch/index.vue index 9fa697d..2f78425 100644 --- a/frontend/src/components/fishSearch/index.vue +++ b/frontend/src/components/fishSearch/index.vue @@ -70,6 +70,9 @@ diff --git a/frontend/src/store/modules/shuJuTianBao.ts b/frontend/src/store/modules/shuJuTianBao.ts index fb3b513..d437d6c 100644 --- a/frontend/src/store/modules/shuJuTianBao.ts +++ b/frontend/src/store/modules/shuJuTianBao.ts @@ -1,12 +1,14 @@ import { defineStore } from 'pinia'; import { ref } from 'vue'; // 使用 ref 更简单直观 import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from '@/api/select'; +import { set } from 'lodash'; export const useShuJuTianBaoStore = defineStore('shuJuTianBao', () => { // 1. 直接使用 ref 定义状态,确保响应式 const fpssOption = ref([]); const baseOption = ref([]); const engOption = ref([]); + const fishOption = ref([]); // 2. 业务逻辑方法 const getBaseOption = async () => { @@ -48,14 +50,23 @@ export const useShuJuTianBaoStore = defineStore('shuJuTianBao', () => { console.log(error); } }; + const getFishOption = () => { + return fishOption.value; + }; + const setFishOption = (data: any[]) => { + fishOption.value = data; + }; // 3. 直接返回 ref 和方法 // 在组件中使用时:store.baseOption 会自动解包为数组 return { fpssOption, baseOption, engOption, + fishOption, getBaseOption, getEngOption, getFpssOption, + getFishOption, + setFishOption }; }); \ No newline at end of file diff --git a/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBaoForm.vue b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoForm.vue similarity index 90% rename from frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBaoForm.vue rename to frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoForm.vue index 98f360f..f456c8e 100644 --- a/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBaoForm.vue +++ b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoForm.vue @@ -18,18 +18,21 @@ > - + {{ opt.basename }} @@ -43,9 +46,16 @@ :loading="engLoading" placeholder="请选择电站名称" :disabled="isView" + show-search + :filter-option="filterOption" @change="engChange" > - + {{ opt.ennm }} @@ -61,11 +71,14 @@ :loading="fpssLoading" placeholder="请选择过鱼设施" :disabled="isView" + show-search + :filter-option="filterOption" > {{ opt.stnm }} @@ -76,8 +89,9 @@ (), { initialValues: null, loading: false, }); -// 1. 在表单内部定义独立的电站列表状态 - const getBaseDropdownSelect = async () => { try { baseLoading.value = true; const res = await getBaseDropdown({}); baseOption.value = res.data; } catch (error) { - console.error("获取水电基地列表失败:", error); + console.error("获取流域列表失败:", error); } finally { baseLoading.value = false; } @@ -291,7 +303,6 @@ const getFpssDropdownSelect = async (rstcd: string, baseId: string) => { fpssLoading.value = false; } }; -// --- 核心修复:创建计算属性处理 v-model --- const modalVisible = computed({ get: () => props.visible, set: (val) => emit("update:visible", val), @@ -331,16 +342,19 @@ const defaultFormData = reactive({ weightMax: undefined, }); const formData: any = reactive({ ...defaultFormData }); - +const filterOption = (inputValue: string, option: any) => { + if (!option.label) return false; + return option.label.indexOf(inputValue) !== -1; +}; // 验证规则 const rules: Record = { - // baseId: [{ required: true, message: "请选择水电基地", trigger: "change" }], - // rstcd: [{ required: true, message: "请选择电站", trigger: "change" }], - // stcd: [{ required: true, message: "请选择过鱼设施", trigger: "change" }], - // strdt: [{ required: true, message: "请选择过鱼时间", trigger: "change" }], - // ftp: [{ required: true, message: "请选择鱼种类", trigger: "change" }], - // direction: [{ required: true, message: "请选择游向", trigger: "change" }], - // fcnt: [{ required: true, message: "请输入过鱼数量", trigger: "change" }], + baseId: [{ required: true, message: "请选择流域", trigger: "change" }], + rstcd: [{ required: true, message: "请选择电站", trigger: "change" }], + stcd: [{ required: true, message: "请选择过鱼设施", trigger: "change" }], + strdt: [{ required: true, message: "请选择过鱼时间", trigger: "change" }], + ftp: [{ required: true, message: "请选择鱼种类", trigger: "change" }], + direction: [{ required: true, message: "请选择游向", trigger: "change" }], + fcnt: [{ required: true, message: "请输入过鱼数量", trigger: "change" }], }; // 计算是否为编辑模式 @@ -409,8 +423,6 @@ const initForm = () => { if (props.initialValues) { // --- 编辑模式:回填数据 --- const values = props.initialValues; - - // 处理特殊字段拆分 if (values.fwet) { const weights = values.fwet.split("~"); if (weights.length === 2) { @@ -456,12 +468,10 @@ const initForm = () => { } }); } else { - // --- 新增模式:重置表单 --- resetForm(); } }; -// 2. 修改 watch,只监听 visible 的变化 watch( () => props.visible, (newVisible) => { @@ -471,20 +481,11 @@ watch( getEngInfoDropdownSelect(formData.baseId); getFpssDropdownSelect(formData.rstcd, formData.baseId); initForm(); - } else { - // 弹窗关闭时,可以选择是否重置,或者留给下次打开时处理 - // 通常建议在关闭时重置,或者在下次打开时根据 initialValues 判断 } }, { immediate: false } // 不需要 immediate,因为初始状态通常是 false ); -// 3. 删除原来的复杂 watch -// 删除这段代码: -// watch( -// () => [props.visible, props.initialValues], -// ... -// ); // 重置表单 const resetForm = () => { if (formRef.value) { @@ -549,7 +550,7 @@ const handleOk = async () => { fwet: fwet, fsz: fsz, }; - if (!formData.id) submitValues.tm = dayjs().format("YYYY-MM-DD HH:mm:ss") + if (!formData.id) submitValues.tm = dayjs().format("YYYY-MM-DD HH:mm:ss"); console.log(submitValues); emit("ok", submitValues); } catch (error) { @@ -560,5 +561,4 @@ const handleOk = async () => { diff --git a/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBaoSearch.vue b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoSearch.vue similarity index 79% rename from frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBaoSearch.vue rename to frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoSearch.vue index 281fb72..f3fa471 100644 --- a/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBaoSearch.vue +++ b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoSearch.vue @@ -11,7 +11,6 @@ - 新增 @@ -21,7 +20,7 @@ 导入zip - + 批量删除 @@ -65,11 +64,10 @@ import { checkPerm } from "@/directive/permission"; import fishSearch from "@/components/fishSearch/index.vue"; import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao"; -// --- Props & Emits --- interface Props { direction: any[]; guoyuStatus: any[]; - importBtn: (file: File) => void; + importBtn: () => void; batchDelBtn: () => void; submitBtn: () => void; successBtn: () => void; @@ -85,11 +83,8 @@ const emit = defineEmits<{ (e: "searchFinish", values: any): void; }>(); const localTypeDate = ref(null); -// --- State --- -const basicSearchRef = ref(); // 1. 定义 ref -const fileInputRef = ref(); +const basicSearchRef = ref(); -// 模拟 initSearchData const initSearchData = { baseId: "all", stcd: null, @@ -104,14 +99,11 @@ const initSearchData = { }; const searchData = ref({ ...initSearchData }); - -// --- Search List Configuration --- -// 电站(下拉框)、STCD:过鱼设施编码(下拉框)、STRDT:开始时间、ENDDT:结束时间、鱼名称(字符串模糊查询)、DIRECTION:游向(0:上行、1:下行、2:上下行) const searchList: any = computed(() => [ { type: "waterStation", name: "baseId", - label: "水电基地", + label: "流域", fieldProps: { allowClear: true, }, @@ -166,33 +158,18 @@ const searchList: any = computed(() => [ format: "YYYY-MM-DD", valueFormat: "YYYY-MM-DD", allowClear: false, - // disabledDate: disabledDateFn, // 如果需要禁用日期,在此传入函数 }, presets: DateSetting.RangeButton.days, }, ]); // --- Methods --- -const triggerFileInput = () => { - fileInputRef.value?.click(); -}; // 2. 搜索表单逻辑 const onSearchFinish = (values: any) => { - console.log(values); - // 模拟获取 label,实际可能需要根据 dmStcd 查找名称 - // 在原 React 代码中,label 来自 options.find(...) - // 这里简化处理,直接传递 ID 或固定名称,或者你需要维护一个电站列表映射 - // const params: any = {}; - // if (values.strdt) { - // params.startDate = values.strdt[0].format("YYYY-MM-DD"); - // params.endDate = values.strdt[1].format("YYYY-MM-DD"); - // } - emit("searchFinish", values); }; const onValuesChange = (changedValues: any, allValues: any) => { - console.log(changedValues, allValues); searchData.value = { ...searchData.value, ...allValues }; // 同步更新本地 searchData,以便其他逻辑使用 if (changedValues.rstcd || changedValues.baseId) { @@ -207,7 +184,7 @@ const onValuesChange = (changedValues: any, allValues: any) => { const handleReset = () => { localTypeDate.value = null; - emit("reset", searchData.value); + emit("reset", initSearchData); }; watch( () => initSearchData.ftp, @@ -216,9 +193,7 @@ watch( }, { immediate: true } ); -// --- Lifecycle --- onMounted(() => { - // 初始请求 emit("searchFinish", initSearchData); shuJuTianBaoStore.getFpssOption("", ""); diff --git a/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoTable.vue b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoTable.vue new file mode 100644 index 0000000..b58f824 --- /dev/null +++ b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/guoYuSheShiShuJuTianBaoTable.vue @@ -0,0 +1,502 @@ + + + + + + + + 保存 + 取消 + + + 编辑 + 删除 + + + + + + + + {{ getDisplayValue(column.dataIndex, record) }} + + + + + + + + handleBaseChange(val, index)" + > + + {{ opt.basename }} + + + + + + + handleEngChange(val, index)" + > + + {{ opt.ennm }} + + + + + + + handleFpssChange(val, index)" + > + + {{ opt.stnm }} + + + + + + + + + + + + + + + + + + + {{ item.dictName }} + + + + + + + + + + + + + 是 + 否 + + + + + + + + ~ + + + + + + + + + ~ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao.vue b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/index.vue similarity index 74% rename from frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao.vue rename to frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/index.vue index 547cc64..24f60ae 100644 --- a/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao.vue +++ b/frontend/src/views/shuJuTianBao/guoYuSheShiShuJuTianBao/index.vue @@ -1,6 +1,5 @@ - - 编辑 - - - - + fileTableData = val" + /> + + + + + 取消导入 + + 提交导入 + + @@ -142,10 +154,11 @@