过鱼设施数据填报导入修改
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
9d0fbd2cb0
commit
875f674f60
@ -81,13 +81,6 @@ export function cancelImportTask(data:any) {
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 查询导入任务
|
|
||||||
export function getImportTask() {
|
|
||||||
return request({
|
|
||||||
url: '/data/importTask/list',
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//检测用户导入状态
|
//检测用户导入状态
|
||||||
export function checkImportStatus() {
|
export function checkImportStatus() {
|
||||||
return request({
|
return request({
|
||||||
@ -95,3 +88,20 @@ export function checkImportStatus() {
|
|||||||
method: 'get'
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -78,12 +78,15 @@
|
|||||||
:value="formData.baseId"
|
:value="formData.baseId"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@change="dataDimensionDataChange"
|
@change="dataDimensionDataChange"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
style="width: 135px"
|
style="width: 135px"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="opt in shuJuTianBaoStore.baseOption"
|
v-for="opt in shuJuTianBaoStore.baseOption"
|
||||||
:key="opt.baseid"
|
:key="opt.baseid"
|
||||||
:value="opt.baseid"
|
:value="opt.baseid"
|
||||||
|
:label="opt.basename"
|
||||||
>
|
>
|
||||||
{{ opt.basename }}
|
{{ opt.basename }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@ -92,12 +95,15 @@
|
|||||||
:value="formData.rstcd"
|
:value="formData.rstcd"
|
||||||
placeholder="请选择电站"
|
placeholder="请选择电站"
|
||||||
@change="stcdIdChange"
|
@change="stcdIdChange"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
style="width: 135px"
|
style="width: 135px"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="opt in shuJuTianBaoStore.engOption"
|
v-for="opt in shuJuTianBaoStore.engOption"
|
||||||
:key="opt.stcd"
|
:key="opt.stcd"
|
||||||
:value="opt.stcd"
|
:value="opt.stcd"
|
||||||
|
:label="opt.ennm"
|
||||||
>
|
>
|
||||||
{{ opt.ennm }}
|
{{ opt.ennm }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@ -113,11 +119,14 @@
|
|||||||
:allow-clear="item.fieldProps?.allowClear"
|
:allow-clear="item.fieldProps?.allowClear"
|
||||||
:style="{ width: item.width ? item.width + 'px' : '200px' }"
|
:style="{ width: item.width ? item.width + 'px' : '200px' }"
|
||||||
@change="(val) => triggerManualValuesChange(item.name, val)"
|
@change="(val) => triggerManualValuesChange(item.name, val)"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="opt in item.options"
|
v-for="opt in item.options"
|
||||||
:key="opt[item.values?.value] || opt.value || opt.itemCode"
|
:key="opt[item.values?.value] || opt.value || opt.itemCode"
|
||||||
:value="opt[item.values?.value] || opt.value || opt.itemCode"
|
:value="opt[item.values?.value] || opt.value || opt.itemCode"
|
||||||
|
:label="opt[item.values?.name] || opt.label || opt.dictName"
|
||||||
>
|
>
|
||||||
{{ opt[item.values?.name] || opt.label || opt.dictName }}
|
{{ opt[item.values?.name] || opt.label || opt.dictName }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@ -207,6 +216,10 @@ const formRef = ref<any>();
|
|||||||
const formData = reactive<any>({});
|
const formData = reactive<any>({});
|
||||||
const rules = reactive<Record<string, any>>({});
|
const rules = reactive<Record<string, any>>({});
|
||||||
|
|
||||||
|
const filterOption = (inputValue: string, option: any) => {
|
||||||
|
if (!option.label) return false;
|
||||||
|
return option.label.indexOf(inputValue) !== -1;
|
||||||
|
};
|
||||||
// 2. 创建计算属性,自动过滤掉 false/null/undefined 的项
|
// 2. 创建计算属性,自动过滤掉 false/null/undefined 的项
|
||||||
const validSearchList = computed(() => {
|
const validSearchList = computed(() => {
|
||||||
return props.searchList.filter((item) => item);
|
return props.searchList.filter((item) => item);
|
||||||
|
|||||||
@ -70,6 +70,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, computed, watch } from "vue";
|
import { ref, onMounted, computed, watch } from "vue";
|
||||||
import { getFishDictoryDropdown } from "@/api/select";
|
import { getFishDictoryDropdown } from "@/api/select";
|
||||||
|
import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao";
|
||||||
|
import { init } from "echarts";
|
||||||
|
const shuJuTianBaoStore = useShuJuTianBaoStore();
|
||||||
|
|
||||||
// --- Props & Emits ---
|
// --- Props & Emits ---
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -83,7 +86,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: "update:modelValue", value: string | string[]): void;
|
(e: "update:modelValue", value: string | string[], opt: any): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// --- State ---
|
// --- State ---
|
||||||
@ -149,15 +152,15 @@ const handleSelectOption = (opt: any) => {
|
|||||||
} else {
|
} else {
|
||||||
newValues.push(opt.id); // 选中
|
newValues.push(opt.id); // 选中
|
||||||
}
|
}
|
||||||
emit("update:modelValue", newValues);
|
emit("update:modelValue", newValues, opt);
|
||||||
} else {
|
} else {
|
||||||
// --- 单选逻辑 ---
|
// --- 单选逻辑 ---
|
||||||
// 关键:单选模式下,直接发射当前 ID,覆盖旧值
|
// 关键:单选模式下,直接发射当前 ID,覆盖旧值
|
||||||
// 如果点击的是已选中的项,则清空(可选行为,视需求而定)
|
// 如果点击的是已选中的项,则清空(可选行为,视需求而定)
|
||||||
if (props.modelValue === opt.id) {
|
if (props.modelValue === opt.id) {
|
||||||
emit("update:modelValue", ""); // 取消选中
|
emit("update:modelValue", "", opt); // 取消选中
|
||||||
} else {
|
} else {
|
||||||
emit("update:modelValue", opt.id); // 选中新项
|
emit("update:modelValue", opt.id, opt); // 选中新项
|
||||||
// 单选模式下,选择后通常希望关闭下拉框
|
// 单选模式下,选择后通常希望关闭下拉框
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
@ -167,7 +170,7 @@ const handleSelectOption = (opt: any) => {
|
|||||||
const handleChange = (val: any) => {
|
const handleChange = (val: any) => {
|
||||||
// 当 a-select 内部触发 change 时(例如删除 Tag)
|
// 当 a-select 内部触发 change 时(例如删除 Tag)
|
||||||
// 在单选模式下,如果用户通过键盘或删除操作改变了值,这里也会捕获
|
// 在单选模式下,如果用户通过键盘或删除操作改变了值,这里也会捕获
|
||||||
emit("update:modelValue", val);
|
emit("update:modelValue", val, opt);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFishNameById = (id: string) => {
|
const getFishNameById = (id: string) => {
|
||||||
@ -182,25 +185,34 @@ watch(
|
|||||||
(newVal) => {
|
(newVal) => {
|
||||||
// 如果从多选变为单选,且 modelValue 是数组,取第一个值或清空
|
// 如果从多选变为单选,且 modelValue 是数组,取第一个值或清空
|
||||||
if (!newVal && Array.isArray(props.modelValue)) {
|
if (!newVal && Array.isArray(props.modelValue)) {
|
||||||
emit("update:modelValue", props.modelValue || null);
|
emit("update:modelValue", props.modelValue || null, options.value);
|
||||||
}
|
}
|
||||||
// 如果从单选变为多选,且 modelValue 是字符串,转为数组
|
// 如果从单选变为多选,且 modelValue 是字符串,转为数组
|
||||||
if (newVal && typeof props.modelValue === "string") {
|
if (newVal && typeof props.modelValue === "string") {
|
||||||
emit("update:modelValue", props.modelValue ? [props.modelValue] : []);
|
emit("update:modelValue", props.modelValue ? [props.modelValue] : [], {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const init = () => {
|
||||||
onMounted(() => {
|
let data = shuJuTianBaoStore.getFishOption();
|
||||||
|
if (data.length === 0) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
getFishDictoryDropdown()
|
getFishDictoryDropdown()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
options.value = res.data || [];
|
options.value = res.data || [];
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
shuJuTianBaoStore.setFishOption(options.value);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
options.value = data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { ref } from 'vue'; // 使用 ref 更简单直观
|
import { ref } from 'vue'; // 使用 ref 更简单直观
|
||||||
import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from '@/api/select';
|
import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from '@/api/select';
|
||||||
|
import { set } from 'lodash';
|
||||||
|
|
||||||
export const useShuJuTianBaoStore = defineStore('shuJuTianBao', () => {
|
export const useShuJuTianBaoStore = defineStore('shuJuTianBao', () => {
|
||||||
// 1. 直接使用 ref 定义状态,确保响应式
|
// 1. 直接使用 ref 定义状态,确保响应式
|
||||||
const fpssOption = ref<any[]>([]);
|
const fpssOption = ref<any[]>([]);
|
||||||
const baseOption = ref<any[]>([]);
|
const baseOption = ref<any[]>([]);
|
||||||
const engOption = ref<any[]>([]);
|
const engOption = ref<any[]>([]);
|
||||||
|
const fishOption = ref([]);
|
||||||
|
|
||||||
// 2. 业务逻辑方法
|
// 2. 业务逻辑方法
|
||||||
const getBaseOption = async () => {
|
const getBaseOption = async () => {
|
||||||
@ -48,14 +50,23 @@ export const useShuJuTianBaoStore = defineStore('shuJuTianBao', () => {
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const getFishOption = () => {
|
||||||
|
return fishOption.value;
|
||||||
|
};
|
||||||
|
const setFishOption = (data: any[]) => {
|
||||||
|
fishOption.value = data;
|
||||||
|
};
|
||||||
// 3. 直接返回 ref 和方法
|
// 3. 直接返回 ref 和方法
|
||||||
// 在组件中使用时:store.baseOption 会自动解包为数组
|
// 在组件中使用时:store.baseOption 会自动解包为数组
|
||||||
return {
|
return {
|
||||||
fpssOption,
|
fpssOption,
|
||||||
baseOption,
|
baseOption,
|
||||||
engOption,
|
engOption,
|
||||||
|
fishOption,
|
||||||
getBaseOption,
|
getBaseOption,
|
||||||
getEngOption,
|
getEngOption,
|
||||||
getFpssOption,
|
getFpssOption,
|
||||||
|
getFishOption,
|
||||||
|
setFishOption
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -18,18 +18,21 @@
|
|||||||
>
|
>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :span="12">
|
<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"
|
||||||
:loading="baseLoading"
|
:loading="baseLoading"
|
||||||
placeholder="请选择水电基地"
|
placeholder="请选择流域"
|
||||||
:disabled="isView"
|
:disabled="isView"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
@change="baseChange"
|
@change="baseChange"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="opt in baseOption"
|
v-for="opt in baseOption"
|
||||||
:key="opt.baseid"
|
:key="opt.baseid"
|
||||||
:value="opt.baseid"
|
:value="opt.baseid"
|
||||||
|
:label="opt.basename"
|
||||||
>
|
>
|
||||||
{{ opt.basename }}
|
{{ opt.basename }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@ -43,9 +46,16 @@
|
|||||||
:loading="engLoading"
|
:loading="engLoading"
|
||||||
placeholder="请选择电站名称"
|
placeholder="请选择电站名称"
|
||||||
:disabled="isView"
|
:disabled="isView"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
@change="engChange"
|
@change="engChange"
|
||||||
>
|
>
|
||||||
<a-select-option v-for="opt in engOption" :key="opt.stcd" :value="opt.stcd">
|
<a-select-option
|
||||||
|
v-for="opt in engOption"
|
||||||
|
:key="opt.stcd"
|
||||||
|
:value="opt.stcd"
|
||||||
|
:label="opt.ennm"
|
||||||
|
>
|
||||||
{{ opt.ennm }}
|
{{ opt.ennm }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
@ -61,11 +71,14 @@
|
|||||||
:loading="fpssLoading"
|
:loading="fpssLoading"
|
||||||
placeholder="请选择过鱼设施"
|
placeholder="请选择过鱼设施"
|
||||||
:disabled="isView"
|
:disabled="isView"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="opt in fpssOption"
|
v-for="opt in fpssOption"
|
||||||
:key="opt.stcd"
|
:key="opt.stcd"
|
||||||
:value="opt.stcd"
|
:value="opt.stcd"
|
||||||
|
:label="opt.stnm"
|
||||||
>
|
>
|
||||||
{{ opt.stnm }}
|
{{ opt.stnm }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@ -76,8 +89,9 @@
|
|||||||
<a-form-item label="过鱼时间" name="strdt">
|
<a-form-item label="过鱼时间" name="strdt">
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
v-model:value="formData.strdt"
|
v-model:value="formData.strdt"
|
||||||
|
show-time
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
format="YYYY-MM-DD"
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
placeholder="选择日期"
|
placeholder="选择日期"
|
||||||
:disabled="isView"
|
:disabled="isView"
|
||||||
@ -246,15 +260,13 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
initialValues: null,
|
initialValues: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
});
|
});
|
||||||
// 1. 在表单内部定义独立的电站列表状态
|
|
||||||
|
|
||||||
const getBaseDropdownSelect = async () => {
|
const getBaseDropdownSelect = async () => {
|
||||||
try {
|
try {
|
||||||
baseLoading.value = true;
|
baseLoading.value = true;
|
||||||
const res = await getBaseDropdown({});
|
const res = await getBaseDropdown({});
|
||||||
baseOption.value = res.data;
|
baseOption.value = res.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("获取水电基地列表失败:", error);
|
console.error("获取流域列表失败:", error);
|
||||||
} finally {
|
} finally {
|
||||||
baseLoading.value = false;
|
baseLoading.value = false;
|
||||||
}
|
}
|
||||||
@ -291,7 +303,6 @@ const getFpssDropdownSelect = async (rstcd: string, baseId: string) => {
|
|||||||
fpssLoading.value = false;
|
fpssLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// --- 核心修复:创建计算属性处理 v-model ---
|
|
||||||
const modalVisible = computed({
|
const modalVisible = computed({
|
||||||
get: () => props.visible,
|
get: () => props.visible,
|
||||||
set: (val) => emit("update:visible", val),
|
set: (val) => emit("update:visible", val),
|
||||||
@ -331,16 +342,19 @@ const defaultFormData = reactive({
|
|||||||
weightMax: undefined,
|
weightMax: undefined,
|
||||||
});
|
});
|
||||||
const formData: any = reactive({ ...defaultFormData });
|
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<string, Rule[]> = {
|
const rules: Record<string, Rule[]> = {
|
||||||
// baseId: [{ required: true, message: "请选择水电基地", trigger: "change" }],
|
baseId: [{ required: true, message: "请选择流域", trigger: "change" }],
|
||||||
// rstcd: [{ required: true, message: "请选择电站", trigger: "change" }],
|
rstcd: [{ required: true, message: "请选择电站", trigger: "change" }],
|
||||||
// stcd: [{ required: true, message: "请选择过鱼设施", trigger: "change" }],
|
stcd: [{ required: true, message: "请选择过鱼设施", trigger: "change" }],
|
||||||
// strdt: [{ required: true, message: "请选择过鱼时间", trigger: "change" }],
|
strdt: [{ required: true, message: "请选择过鱼时间", trigger: "change" }],
|
||||||
// ftp: [{ required: true, message: "请选择鱼种类", trigger: "change" }],
|
ftp: [{ required: true, message: "请选择鱼种类", trigger: "change" }],
|
||||||
// direction: [{ required: true, message: "请选择游向", trigger: "change" }],
|
direction: [{ required: true, message: "请选择游向", trigger: "change" }],
|
||||||
// fcnt: [{ required: true, message: "请输入过鱼数量", trigger: "change" }],
|
fcnt: [{ required: true, message: "请输入过鱼数量", trigger: "change" }],
|
||||||
};
|
};
|
||||||
|
|
||||||
// 计算是否为编辑模式
|
// 计算是否为编辑模式
|
||||||
@ -409,8 +423,6 @@ const initForm = () => {
|
|||||||
if (props.initialValues) {
|
if (props.initialValues) {
|
||||||
// --- 编辑模式:回填数据 ---
|
// --- 编辑模式:回填数据 ---
|
||||||
const values = props.initialValues;
|
const values = props.initialValues;
|
||||||
|
|
||||||
// 处理特殊字段拆分
|
|
||||||
if (values.fwet) {
|
if (values.fwet) {
|
||||||
const weights = values.fwet.split("~");
|
const weights = values.fwet.split("~");
|
||||||
if (weights.length === 2) {
|
if (weights.length === 2) {
|
||||||
@ -456,12 +468,10 @@ const initForm = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// --- 新增模式:重置表单 ---
|
|
||||||
resetForm();
|
resetForm();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2. 修改 watch,只监听 visible 的变化
|
|
||||||
watch(
|
watch(
|
||||||
() => props.visible,
|
() => props.visible,
|
||||||
(newVisible) => {
|
(newVisible) => {
|
||||||
@ -471,20 +481,11 @@ watch(
|
|||||||
getEngInfoDropdownSelect(formData.baseId);
|
getEngInfoDropdownSelect(formData.baseId);
|
||||||
getFpssDropdownSelect(formData.rstcd, formData.baseId);
|
getFpssDropdownSelect(formData.rstcd, formData.baseId);
|
||||||
initForm();
|
initForm();
|
||||||
} else {
|
|
||||||
// 弹窗关闭时,可以选择是否重置,或者留给下次打开时处理
|
|
||||||
// 通常建议在关闭时重置,或者在下次打开时根据 initialValues 判断
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: false } // 不需要 immediate,因为初始状态通常是 false
|
{ immediate: false } // 不需要 immediate,因为初始状态通常是 false
|
||||||
);
|
);
|
||||||
|
|
||||||
// 3. 删除原来的复杂 watch
|
|
||||||
// 删除这段代码:
|
|
||||||
// watch(
|
|
||||||
// () => [props.visible, props.initialValues],
|
|
||||||
// ...
|
|
||||||
// );
|
|
||||||
// 重置表单
|
// 重置表单
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
if (formRef.value) {
|
if (formRef.value) {
|
||||||
@ -549,7 +550,7 @@ const handleOk = async () => {
|
|||||||
fwet: fwet,
|
fwet: fwet,
|
||||||
fsz: fsz,
|
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);
|
console.log(submitValues);
|
||||||
emit("ok", submitValues);
|
emit("ok", submitValues);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -560,5 +561,4 @@ const handleOk = async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 如有需要,添加局部样式 */
|
|
||||||
</style>
|
</style>
|
||||||
@ -11,7 +11,6 @@
|
|||||||
<template #ftp="{ onChange }">
|
<template #ftp="{ onChange }">
|
||||||
<fishSearch v-model="localTypeDate" width="280px" @update:modelValue="onChange" />
|
<fishSearch v-model="localTypeDate" width="280px" @update:modelValue="onChange" />
|
||||||
</template>
|
</template>
|
||||||
<!-- 自定义重置及操作按钮区域 -->
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<a-tooltip title="新增">
|
<a-tooltip title="新增">
|
||||||
<a-button @click="props.handleAdd"> 新增 </a-button>
|
<a-button @click="props.handleAdd"> 新增 </a-button>
|
||||||
@ -21,7 +20,7 @@
|
|||||||
导入zip
|
导入zip
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-button @click="props.batchDelBtn" :disabled="batchData.length === 0">
|
<a-button @click="props.batchDelBtn" :disabled="batchData.length === 0">
|
||||||
批量删除
|
批量删除
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-tooltip title="提交数据">
|
<a-tooltip title="提交数据">
|
||||||
@ -65,11 +64,10 @@ import { checkPerm } from "@/directive/permission";
|
|||||||
import fishSearch from "@/components/fishSearch/index.vue";
|
import fishSearch from "@/components/fishSearch/index.vue";
|
||||||
import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao";
|
import { useShuJuTianBaoStore } from "@/store/modules/shuJuTianBao";
|
||||||
|
|
||||||
// --- Props & Emits ---
|
|
||||||
interface Props {
|
interface Props {
|
||||||
direction: any[];
|
direction: any[];
|
||||||
guoyuStatus: any[];
|
guoyuStatus: any[];
|
||||||
importBtn: (file: File) => void;
|
importBtn: () => void;
|
||||||
batchDelBtn: () => void;
|
batchDelBtn: () => void;
|
||||||
submitBtn: () => void;
|
submitBtn: () => void;
|
||||||
successBtn: () => void;
|
successBtn: () => void;
|
||||||
@ -85,11 +83,8 @@ const emit = defineEmits<{
|
|||||||
(e: "searchFinish", values: any): void;
|
(e: "searchFinish", values: any): void;
|
||||||
}>();
|
}>();
|
||||||
const localTypeDate = ref<string>(null);
|
const localTypeDate = ref<string>(null);
|
||||||
// --- State ---
|
const basicSearchRef = ref<any>();
|
||||||
const basicSearchRef = ref<any>(); // 1. 定义 ref
|
|
||||||
const fileInputRef = ref<HTMLInputElement>();
|
|
||||||
|
|
||||||
// 模拟 initSearchData
|
|
||||||
const initSearchData = {
|
const initSearchData = {
|
||||||
baseId: "all",
|
baseId: "all",
|
||||||
stcd: null,
|
stcd: null,
|
||||||
@ -104,14 +99,11 @@ const initSearchData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const searchData = ref<any>({ ...initSearchData });
|
const searchData = ref<any>({ ...initSearchData });
|
||||||
|
|
||||||
// --- Search List Configuration ---
|
|
||||||
// 电站(下拉框)、STCD:过鱼设施编码(下拉框)、STRDT:开始时间、ENDDT:结束时间、鱼名称(字符串模糊查询)、DIRECTION:游向(0:上行、1:下行、2:上下行)
|
|
||||||
const searchList: any = computed(() => [
|
const searchList: any = computed(() => [
|
||||||
{
|
{
|
||||||
type: "waterStation",
|
type: "waterStation",
|
||||||
name: "baseId",
|
name: "baseId",
|
||||||
label: "水电基地",
|
label: "流域",
|
||||||
fieldProps: {
|
fieldProps: {
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
},
|
},
|
||||||
@ -166,33 +158,18 @@ const searchList: any = computed(() => [
|
|||||||
format: "YYYY-MM-DD",
|
format: "YYYY-MM-DD",
|
||||||
valueFormat: "YYYY-MM-DD",
|
valueFormat: "YYYY-MM-DD",
|
||||||
allowClear: false,
|
allowClear: false,
|
||||||
// disabledDate: disabledDateFn, // 如果需要禁用日期,在此传入函数
|
|
||||||
},
|
},
|
||||||
presets: DateSetting.RangeButton.days,
|
presets: DateSetting.RangeButton.days,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
// --- Methods ---
|
// --- Methods ---
|
||||||
const triggerFileInput = () => {
|
|
||||||
fileInputRef.value?.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. 搜索表单逻辑
|
// 2. 搜索表单逻辑
|
||||||
const onSearchFinish = (values: any) => {
|
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);
|
emit("searchFinish", values);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onValuesChange = (changedValues: any, allValues: any) => {
|
const onValuesChange = (changedValues: any, allValues: any) => {
|
||||||
console.log(changedValues, allValues);
|
|
||||||
searchData.value = { ...searchData.value, ...allValues };
|
searchData.value = { ...searchData.value, ...allValues };
|
||||||
// 同步更新本地 searchData,以便其他逻辑使用
|
// 同步更新本地 searchData,以便其他逻辑使用
|
||||||
if (changedValues.rstcd || changedValues.baseId) {
|
if (changedValues.rstcd || changedValues.baseId) {
|
||||||
@ -207,7 +184,7 @@ const onValuesChange = (changedValues: any, allValues: any) => {
|
|||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
localTypeDate.value = null;
|
localTypeDate.value = null;
|
||||||
emit("reset", searchData.value);
|
emit("reset", initSearchData);
|
||||||
};
|
};
|
||||||
watch(
|
watch(
|
||||||
() => initSearchData.ftp,
|
() => initSearchData.ftp,
|
||||||
@ -216,9 +193,7 @@ watch(
|
|||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
// --- Lifecycle ---
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 初始请求
|
|
||||||
emit("searchFinish", initSearchData);
|
emit("searchFinish", initSearchData);
|
||||||
|
|
||||||
shuJuTianBaoStore.getFpssOption("", "");
|
shuJuTianBaoStore.getFpssOption("", "");
|
||||||
@ -0,0 +1,502 @@
|
|||||||
|
<template>
|
||||||
|
<a-table
|
||||||
|
size="small"
|
||||||
|
:loading="fileLoading"
|
||||||
|
:data-source="fileTableData"
|
||||||
|
:columns="modalColumns"
|
||||||
|
height="500"
|
||||||
|
:scroll="{ y: 500, x: '100%' }"
|
||||||
|
:row-key="(record, index) => index"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record, index }">
|
||||||
|
<!-- 1. 操作列 -->
|
||||||
|
<template v-if="column.key === 'action' || column.dataIndex === 'action'">
|
||||||
|
<div class="flex">
|
||||||
|
<template v-if="editingRowIndex === index">
|
||||||
|
<a-button type="link" size="small" @click="saveEdit(index)">保存</a-button>
|
||||||
|
<a-button type="link" size="small" @click="cancelEdit">取消</a-button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-button type="link" size="small" @click="startEdit(index)">编辑</a-button>
|
||||||
|
<a-button type="link" danger size="small" @click="handlePreviewDelete(index)"
|
||||||
|
>删除</a-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 2. 警告提示列 (非编辑状态) -->
|
||||||
|
<template
|
||||||
|
v-else-if="
|
||||||
|
!isEditing(index) &&
|
||||||
|
column.dataIndex &&
|
||||||
|
record._warnings &&
|
||||||
|
record._warnings.includes(column.dataIndex)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div style="color: red; display: flex; align-items: center">
|
||||||
|
<span>{{ getDisplayValue(column.dataIndex, record) }}</span>
|
||||||
|
<exclamation-circle-outlined style="margin-left: 4px" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 3. 编辑状态下的单元格 (绑定到 editingData) -->
|
||||||
|
<template v-else-if="isEditing(index)">
|
||||||
|
<template v-if="column.dataIndex === 'baseName'">
|
||||||
|
<a-select
|
||||||
|
v-model:value="editingData.baseId"
|
||||||
|
placeholder="请选择"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
|
:loading="rowStates[index]?.baseLoading"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="(val) => handleBaseChange(val, index)"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="opt in baseOptions"
|
||||||
|
:key="opt.baseid"
|
||||||
|
:value="opt.baseid"
|
||||||
|
:label="opt.basename"
|
||||||
|
>
|
||||||
|
{{ opt.basename }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 电站名称 -->
|
||||||
|
<template v-else-if="column.dataIndex === 'ennm'">
|
||||||
|
<a-select
|
||||||
|
v-model:value="editingData.rstcd"
|
||||||
|
placeholder="请选择"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
|
:loading="rowStates[index]?.engLoading"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="!editingData.baseId"
|
||||||
|
@change="(val) => handleEngChange(val, index)"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="opt in rowStates[index]?.engOptions || []"
|
||||||
|
:key="opt.stcd"
|
||||||
|
:value="opt.stcd"
|
||||||
|
:label="opt.ennm"
|
||||||
|
>
|
||||||
|
{{ opt.ennm }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 过鱼设施 -->
|
||||||
|
<template v-else-if="column.dataIndex === 'stnm'">
|
||||||
|
<a-select
|
||||||
|
v-model:value="editingData.stcd"
|
||||||
|
placeholder="请选择"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterOption"
|
||||||
|
:loading="rowStates[index]?.fpssLoading"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="!editingData.rstcd"
|
||||||
|
@change="(val) => handleFpssChange(val, index)"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="opt in rowStates[index]?.fpssOptions || []"
|
||||||
|
:key="opt.stcd"
|
||||||
|
:value="opt.stcd"
|
||||||
|
:label="opt.stnm"
|
||||||
|
>
|
||||||
|
{{ opt.stnm }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 过鱼时间 -->
|
||||||
|
<template v-else-if="column.dataIndex === 'strdt'">
|
||||||
|
<a-date-picker
|
||||||
|
v-model:value="editingData.strdt"
|
||||||
|
show-time
|
||||||
|
style="width: 100%"
|
||||||
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 鱼种类 -->
|
||||||
|
<template v-else-if="column.dataIndex === 'ftpName'">
|
||||||
|
<fishSearch
|
||||||
|
v-model="editingData.ftp"
|
||||||
|
style="width: 100%"
|
||||||
|
@update:modelValue="handleFtpChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 游向 -->
|
||||||
|
<template v-else-if="column.dataIndex === 'direction'">
|
||||||
|
<a-select
|
||||||
|
v-model:value="editingData.direction"
|
||||||
|
placeholder="请选择"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in direction"
|
||||||
|
:key="item.itemCode"
|
||||||
|
:value="item.itemCode"
|
||||||
|
>
|
||||||
|
{{ item.dictName }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 数字输入框 -->
|
||||||
|
<template v-else-if="['fcnt', 'wt'].includes(column.dataIndex)">
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="editingData[column.dataIndex]"
|
||||||
|
style="width: 100%"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 是否鱼苗 -->
|
||||||
|
<template v-else-if="column.dataIndex === 'isfs'">
|
||||||
|
<a-radio-group v-model:value="editingData.isfs">
|
||||||
|
<a-radio :value="1">是</a-radio>
|
||||||
|
<a-radio :value="0">否</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 体长 (编辑态使用 Min/Max) -->
|
||||||
|
<template v-else-if="column.dataIndex === 'fsz'">
|
||||||
|
<div class="flex">
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="editingData.bodyLengthMin"
|
||||||
|
style="width: 50%"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
<span class="px-[2px]">~</span>
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="editingData.bodyLengthMax"
|
||||||
|
style="width: 50%"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 体重 (编辑态使用 Min/Max) -->
|
||||||
|
<template v-else-if="column.dataIndex === 'fwet'">
|
||||||
|
<div class="flex align-center">
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="editingData.weightMin"
|
||||||
|
style="width: 50%"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
<span class="px-[2px]">~</span>
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="editingData.weightMax"
|
||||||
|
style="width: 50%"
|
||||||
|
:min="0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 其他默认文本输入 -->
|
||||||
|
<template v-else>
|
||||||
|
<a-input v-model:value="editingData[column.dataIndex]" size="small" />
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 4. 普通展示状态 (直接显示 record) -->
|
||||||
|
<!-- <template v-else>
|
||||||
|
{{ getDisplayValue(column.dataIndex, record) }}
|
||||||
|
</template> -->
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, onMounted, h } from "vue";
|
||||||
|
import { message, Tag } from "ant-design-vue";
|
||||||
|
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
|
||||||
|
import fishSearch from "@/components/fishSearch/index.vue";
|
||||||
|
import { getBaseDropdown, getEngInfoDropdown, getFpssDropdown } from "@/api/select";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
const props: any = defineProps({
|
||||||
|
fileTableData: { type: Array, default: () => [] },
|
||||||
|
fileLoading: { type: Boolean, default: false },
|
||||||
|
direction: { type: Array, default: () => [] },
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:fileTableData"]);
|
||||||
|
|
||||||
|
// --- 状态管理 ---
|
||||||
|
const editingRowIndex = ref<number | null>(null);
|
||||||
|
const baseOptions = ref<any[]>([]);
|
||||||
|
const rowStates = reactive<Record<number, any>>({});
|
||||||
|
|
||||||
|
// 【核心】临时编辑数据,只在编辑模式下使用
|
||||||
|
const editingData = ref<any>(null);
|
||||||
|
|
||||||
|
const modalColumns = ref([
|
||||||
|
{ dataIndex: "baseName", key: "baseName", title: "流域", width: 140 },
|
||||||
|
{ dataIndex: "ennm", key: "ennm", title: "电站名称", width: 140 },
|
||||||
|
{ dataIndex: "stnm", key: "stnm", title: "过鱼设施名称", width: 150 },
|
||||||
|
{ dataIndex: "strdt", key: "strdt", title: "过鱼时间", width: 190 },
|
||||||
|
{ dataIndex: "ftpName", key: "ftpName", title: "鱼种类", width: 120 },
|
||||||
|
{
|
||||||
|
dataIndex: "isfs",
|
||||||
|
key: "isfs",
|
||||||
|
title: "是否鱼苗",
|
||||||
|
width: 130,
|
||||||
|
customRender: ({ text }: any) => {
|
||||||
|
const isYes = text === 1 || text === "1";
|
||||||
|
return h(Tag, { color: isYes ? "success" : "error", style: { margin: 0 } }, () =>
|
||||||
|
isYes ? "是" : "否"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: "direction",
|
||||||
|
key: "direction",
|
||||||
|
title: "游向",
|
||||||
|
width: 120,
|
||||||
|
customRender: ({ text }: any) =>
|
||||||
|
props.direction.find((item: any) => item.itemCode === text)?.dictName || "-",
|
||||||
|
},
|
||||||
|
{ dataIndex: "fcnt", key: "fcnt", title: "过鱼数量(尾)", width: 120 },
|
||||||
|
{ dataIndex: "fsz", key: "fsz", title: "体长(cm)", width: 160 },
|
||||||
|
{ dataIndex: "fwet", key: "fwet", title: "平均体重(g)", width: 160 },
|
||||||
|
{ dataIndex: "wt", key: "wt", title: "水温(℃)", width: 80 },
|
||||||
|
{ dataIndex: "picpth", key: "level5", title: "图片", width: 100 },
|
||||||
|
{ dataIndex: "vdpth", key: "level6", title: "视频", width: 100 },
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
key: "action",
|
||||||
|
dataIndex: "action",
|
||||||
|
fixed: "right",
|
||||||
|
width: 100,
|
||||||
|
align: "center",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// --- 初始化 ---
|
||||||
|
onMounted(() => {
|
||||||
|
loadBaseOptions();
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadBaseOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getBaseDropdown({});
|
||||||
|
baseOptions.value = res.data || [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Load base options failed", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ensureRowState = (index: number) => {
|
||||||
|
if (!rowStates[index]) {
|
||||||
|
rowStates[index] = {
|
||||||
|
engOptions: [],
|
||||||
|
fpssOptions: [],
|
||||||
|
baseLoading: false,
|
||||||
|
engLoading: false,
|
||||||
|
fpssLoading: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return rowStates[index];
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- 级联逻辑 (操作 editingData) ---
|
||||||
|
|
||||||
|
const handleBaseChange = async (baseId: string, index: number) => {
|
||||||
|
console.log(baseId)
|
||||||
|
editingData.value.baseName = baseOptions.value.find(
|
||||||
|
(item: any) => item.baseid == baseId
|
||||||
|
)?.basename;
|
||||||
|
if (baseId && editingData.value._warnings) {
|
||||||
|
editingData.value._warnings = editingData.value._warnings.filter((w: string) => w !== 'baseName');
|
||||||
|
}
|
||||||
|
const state = ensureRowState(index);
|
||||||
|
// 清空后续字段
|
||||||
|
editingData.value.rstcd = undefined;
|
||||||
|
editingData.value.stcd = undefined;
|
||||||
|
state.engOptions = [];
|
||||||
|
state.fpssOptions = [];
|
||||||
|
|
||||||
|
if (!baseId) return;
|
||||||
|
state.engLoading = true;
|
||||||
|
try {
|
||||||
|
const res = await getEngInfoDropdown({ baseId });
|
||||||
|
state.engOptions = res.data || [];
|
||||||
|
} catch (e) {
|
||||||
|
message.error("获取电站列表失败");
|
||||||
|
} finally {
|
||||||
|
state.engLoading = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEngChange = async (rstcd: string, index: number) => {
|
||||||
|
const state = ensureRowState(index);
|
||||||
|
if (rstcd && editingData.value._warnings) {
|
||||||
|
editingData.value._warnings = editingData.value._warnings.filter((w: string) => w !== 'ennm');
|
||||||
|
}
|
||||||
|
editingData.value.ennm = state.engOptions.find(
|
||||||
|
(item: any) => item.stcd === rstcd
|
||||||
|
)?.ennm;
|
||||||
|
editingData.value.stcd = undefined;
|
||||||
|
state.fpssOptions = [];
|
||||||
|
|
||||||
|
if (!rstcd || !editingData.value.baseId) return;
|
||||||
|
state.fpssLoading = true;
|
||||||
|
try {
|
||||||
|
const res = await getFpssDropdown({ rstcd, baseId: editingData.value.baseId });
|
||||||
|
state.fpssOptions = res.data || [];
|
||||||
|
} catch (e) {
|
||||||
|
message.error("获取设施列表失败");
|
||||||
|
} finally {
|
||||||
|
state.fpssLoading = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleFpssChange = (stcd: string, index: number) => {
|
||||||
|
const state = ensureRowState(index);
|
||||||
|
if (stcd && editingData.value._warnings) {
|
||||||
|
editingData.value._warnings = editingData.value._warnings.filter((w: string) => w !== 'stnm');
|
||||||
|
}
|
||||||
|
editingData.value.stnm = state.fpssOptions.find(
|
||||||
|
(item: any) => item.stcd === stcd
|
||||||
|
)?.stnm;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- 编辑控制 ---
|
||||||
|
|
||||||
|
const isEditing = (index: number) => editingRowIndex.value === index;
|
||||||
|
const startEdit = (index: number) => {
|
||||||
|
const originalRecord = props.fileTableData[index];
|
||||||
|
|
||||||
|
// 1. 深拷贝原始数据到临时编辑区
|
||||||
|
editingData.value = JSON.parse(JSON.stringify(originalRecord));
|
||||||
|
|
||||||
|
// 2. 预处理:将 fsz/fwet 字符串拆分为 Min/Max 供输入框使用
|
||||||
|
processStringToMinMax(editingData.value);
|
||||||
|
|
||||||
|
editingRowIndex.value = index;
|
||||||
|
|
||||||
|
// 3. 预加载下拉选项 (基于 editingData 的值)
|
||||||
|
if (editingData.value.baseId && !editingData.value.rstcd) {
|
||||||
|
handleBaseChange(editingData.value.baseId, index);
|
||||||
|
} else if (editingData.value.baseId && editingData.value.rstcd) {
|
||||||
|
handleBaseChange(editingData.value.baseId, index).then(() => {
|
||||||
|
handleEngChange(editingData.value.rstcd, index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 辅助:字符串转 Min/Max
|
||||||
|
const processStringToMinMax = (data: any) => {
|
||||||
|
if (data.fsz) {
|
||||||
|
const sizes = String(data.fsz).split("~");
|
||||||
|
data.bodyLengthMin = sizes[0] || "";
|
||||||
|
data.bodyLengthMax = sizes[1] || sizes[0] || "";
|
||||||
|
} else {
|
||||||
|
data.bodyLengthMin = "";
|
||||||
|
data.bodyLengthMax = "";
|
||||||
|
}
|
||||||
|
if (data.fwet) {
|
||||||
|
const weights = String(data.fwet).split("~");
|
||||||
|
data.weightMin = weights[0] || "";
|
||||||
|
data.weightMax = weights[1] || weights[0] || "";
|
||||||
|
} else {
|
||||||
|
data.weightMin = "";
|
||||||
|
data.weightMax = "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 辅助:Min/Max 转字符串
|
||||||
|
const processMinMaxToString = (data: any) => {
|
||||||
|
// 处理体长
|
||||||
|
if (data.bodyLengthMin !== "" || data.bodyLengthMax !== "") {
|
||||||
|
if (data.bodyLengthMin == data.bodyLengthMax) {
|
||||||
|
data.fsz = data.bodyLengthMin;
|
||||||
|
} else {
|
||||||
|
data.fsz = `${data.bodyLengthMin}~${data.bodyLengthMax}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.fsz = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理体重
|
||||||
|
if (data.weightMin !== "" || data.weightMax !== "") {
|
||||||
|
if (data.weightMin == data.weightMax) {
|
||||||
|
data.fwet = data.weightMin;
|
||||||
|
} else {
|
||||||
|
data.fwet = `${data.weightMin}~${data.weightMax}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.fwet = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理临时字段,避免污染原数据
|
||||||
|
delete data.bodyLengthMin;
|
||||||
|
delete data.bodyLengthMax;
|
||||||
|
delete data.weightMin;
|
||||||
|
delete data.weightMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveEdit = (index: number) => {
|
||||||
|
// 1. 后处理:将 Min/Max 合并回 fsz/fwet
|
||||||
|
processMinMaxToString(editingData.value);
|
||||||
|
|
||||||
|
// 2. 创建新数组,替换对应索引的数据
|
||||||
|
const newData = [...props.fileTableData];
|
||||||
|
newData[index] = { ...editingData.value };
|
||||||
|
|
||||||
|
// 3. 通知父组件更新
|
||||||
|
emit("update:fileTableData", newData);
|
||||||
|
|
||||||
|
// 4. 重置状态
|
||||||
|
editingRowIndex.value = null;
|
||||||
|
editingData.value = null;
|
||||||
|
message.success("保存成功");
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelEdit = () => {
|
||||||
|
editingRowIndex.value = null;
|
||||||
|
editingData.value = null;
|
||||||
|
// 由于我们从未修改过 props.fileTableData,所以不需要恢复操作,直接退出即可
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePreviewDelete = (index: number) => {
|
||||||
|
const newData = [...props.fileTableData];
|
||||||
|
newData.splice(index, 1);
|
||||||
|
emit("update:fileTableData", newData);
|
||||||
|
|
||||||
|
if (editingRowIndex.value === index) {
|
||||||
|
editingRowIndex.value = null;
|
||||||
|
editingData.value = null;
|
||||||
|
} else if (editingRowIndex.value !== null && editingRowIndex.value > index) {
|
||||||
|
editingRowIndex.value--;
|
||||||
|
}
|
||||||
|
message.success("删除成功");
|
||||||
|
};
|
||||||
|
// 鱼种类编辑 修改名称
|
||||||
|
const handleFtpChange = (val: any, opt: any) => {
|
||||||
|
editingData.value.ftpName = opt.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- 辅助函数 ---
|
||||||
|
|
||||||
|
const filterOption = (input: string, option: any) => {
|
||||||
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 统一获取显示值
|
||||||
|
const getDisplayValue = (dataIndex: string, record: any) => {
|
||||||
|
const val = record[dataIndex];
|
||||||
|
if (val === undefined || val === null) return "-";
|
||||||
|
if (dataIndex === "isfs") return val === 1 ? "是" : "否";
|
||||||
|
if (dataIndex === "strdt") return val ? dayjs(val).format("YYYY-MM-DD HH:mm:ss") : "-";
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
defineExpose({
|
||||||
|
editingRowIndex,
|
||||||
|
editingData,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="guoYuSheShiShuJuTianBao-page">
|
<div class="guoYuSheShiShuJuTianBao-page">
|
||||||
<!-- 搜索区域组件,具体 props 需根据实际子组件调整 -->
|
|
||||||
<GuoYuSheShiShuJuTianBaoSearch
|
<GuoYuSheShiShuJuTianBaoSearch
|
||||||
ref="searchRef"
|
ref="searchRef"
|
||||||
:guoyuStatus="guoyuStatus"
|
:guoyuStatus="guoyuStatus"
|
||||||
@ -14,7 +13,6 @@
|
|||||||
@reset="handleReset"
|
@reset="handleReset"
|
||||||
@search-finish="handleSearchFinish"
|
@search-finish="handleSearchFinish"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 主表格 -->
|
<!-- 主表格 -->
|
||||||
<BasicTable
|
<BasicTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
@ -39,7 +37,11 @@
|
|||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
@click="handleEdit(record, 'edit')"
|
@click="handleEdit(record, 'edit')"
|
||||||
v-if="record.status === 'DRAFT' || record.status === 'REJECTED'|| record.status === 'SUBMITTED'"
|
v-if="
|
||||||
|
record.status === 'DRAFT' ||
|
||||||
|
record.status === 'REJECTED' ||
|
||||||
|
record.status === 'SUBMITTED'
|
||||||
|
"
|
||||||
>编辑</a-button
|
>编辑</a-button
|
||||||
>
|
>
|
||||||
<a-button
|
<a-button
|
||||||
@ -76,7 +78,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</BasicTable>
|
</BasicTable>
|
||||||
<!-- <BasicTable :columns="columns" :listUrl="getFishDraftPage" /> -->
|
|
||||||
<!-- 隐藏的文件输入框 -->
|
<!-- 隐藏的文件输入框 -->
|
||||||
<input
|
<input
|
||||||
ref="fileInputRef"
|
ref="fileInputRef"
|
||||||
@ -92,20 +93,31 @@
|
|||||||
cancel-text="取消导入"
|
cancel-text="取消导入"
|
||||||
:width="1500"
|
:width="1500"
|
||||||
v-model:open="visible"
|
v-model:open="visible"
|
||||||
|
maskClosable="false"
|
||||||
|
@cancel="handleCancel"
|
||||||
:confirm-loading="fileLoading"
|
:confirm-loading="fileLoading"
|
||||||
@cancel="handleModalCancel"
|
|
||||||
@ok="handleModalOk"
|
|
||||||
>
|
>
|
||||||
<a-table
|
<GuoYuSheShiShuJuTianBaoTable
|
||||||
size="small"
|
ref="modalTableRef"
|
||||||
:loading="fileLoading"
|
:fileLoading="fileLoading"
|
||||||
:data-source="fileTableData"
|
:fileTableData="fileTableData"
|
||||||
:columns="modalColumns"
|
:direction="direction"
|
||||||
:scroll="{ y: 500, x: '100%' }"
|
@update:file-table-data="(val) => fileTableData = val"
|
||||||
row-key="index"
|
/>
|
||||||
>
|
|
||||||
<!-- 如果需要复杂的行内编辑插槽,可在此定义,但目前逻辑主要在 column render 中处理 -->
|
|
||||||
</a-table>
|
|
||||||
|
<template #footer>
|
||||||
|
<a-button key="back" @click="handleCustomCancel">取消导入</a-button>
|
||||||
|
<a-button
|
||||||
|
key="submit"
|
||||||
|
type="primary"
|
||||||
|
:loading="fileLoading"
|
||||||
|
@click="handleModalOk"
|
||||||
|
>
|
||||||
|
提交导入
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<!-- 新增/编辑 Modal (对应 React 的 EditModal) -->
|
<!-- 新增/编辑 Modal (对应 React 的 EditModal) -->
|
||||||
@ -142,10 +154,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, onMounted, h } from "vue";
|
import { ref, computed, onMounted, h, nextTick } from "vue";
|
||||||
import { message, Modal } from "ant-design-vue"; // 假设使用 ant-design-vue
|
import { message, Modal } from "ant-design-vue"; // 假设使用 ant-design-vue
|
||||||
import BasicTable from "@/components/BasicTable/index.vue";
|
import BasicTable from "@/components/BasicTable/index.vue";
|
||||||
import GuoYuSheShiShuJuTianBaoSearch from "./guoYuSheShiShuJuTianBaoSearch.vue";
|
import GuoYuSheShiShuJuTianBaoSearch from "./guoYuSheShiShuJuTianBaoSearch.vue";
|
||||||
|
import GuoYuSheShiShuJuTianBaoTable from "./guoYuSheShiShuJuTianBaoTable.vue";
|
||||||
import EditModal from "./guoYuSheShiShuJuTianBaoForm.vue";
|
import EditModal from "./guoYuSheShiShuJuTianBaoForm.vue";
|
||||||
import {
|
import {
|
||||||
getFishDraftPage,
|
getFishDraftPage,
|
||||||
@ -158,11 +171,13 @@ import {
|
|||||||
importFishZip,
|
importFishZip,
|
||||||
submitImportTask,
|
submitImportTask,
|
||||||
cancelImportTask,
|
cancelImportTask,
|
||||||
getImportTask,
|
checkImportStatus,
|
||||||
checkImportStatus
|
batchSaveDraft,
|
||||||
|
getLastImportResult,
|
||||||
} from "@/api/guoYuSheShiShuJuTianBao";
|
} from "@/api/guoYuSheShiShuJuTianBao";
|
||||||
import { Tag } from "ant-design-vue"; // 确保导入 Tag
|
import { Tag } from "ant-design-vue"; // 确保导入 Tag
|
||||||
import { getDictItemsByCode } from "@/api/dict";
|
import { getDictItemsByCode } from "@/api/dict";
|
||||||
|
import { m } from "vue-router/dist/router-CWoNjPRp.mjs";
|
||||||
// import { FileImageOutlined, VideoCameraOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
// import { FileImageOutlined, VideoCameraOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
// --- 类型定义 ---
|
// --- 类型定义 ---
|
||||||
@ -188,7 +203,7 @@ const baseColumnsConfig: ColumnConfig[] = [
|
|||||||
{
|
{
|
||||||
dataIndex: "baseName",
|
dataIndex: "baseName",
|
||||||
key: "baseName",
|
key: "baseName",
|
||||||
title: "水电基地",
|
title: "流域",
|
||||||
width: 120,
|
width: 120,
|
||||||
fixed: "left",
|
fixed: "left",
|
||||||
},
|
},
|
||||||
@ -260,10 +275,12 @@ const videoPreviewVisible = ref(false);
|
|||||||
const currentVideoUrl = ref<string>("");
|
const currentVideoUrl = ref<string>("");
|
||||||
|
|
||||||
// 表格数据
|
// 表格数据
|
||||||
const tableData = ref<any[]>([]);
|
|
||||||
const fileTableData = ref<any[]>([]);
|
const fileTableData = ref<any[]>([]);
|
||||||
|
const orgFileTableData = ref<any[]>([]);
|
||||||
|
const warnings = ref<any[]>([]);
|
||||||
const batchData = ref<any[]>([]);
|
const batchData = ref<any[]>([]);
|
||||||
|
|
||||||
|
const modalTableRef = ref<any>(null);
|
||||||
const fileLoading = ref(false);
|
const fileLoading = ref(false);
|
||||||
|
|
||||||
// 行内编辑 Key (用于导入预览表格)
|
// 行内编辑 Key (用于导入预览表格)
|
||||||
@ -278,25 +295,7 @@ const editingKey = ref<string | number>("");
|
|||||||
// if (!file) return "";
|
// if (!file) return "";
|
||||||
// const blob = await file.async("blob");
|
// const blob = await file.async("blob");
|
||||||
// return URL.createObjectURL(blob);
|
// return URL.createObjectURL(blob);
|
||||||
// } catch (e) {
|
const taskId = ref<string>("");
|
||||||
// console.error("Extract file failed", e);
|
|
||||||
// return "";
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// 渲染媒体单元格 (返回 VNode 或简单结构,实际在 Antdv columns render 中处理)
|
|
||||||
// 在 Vue Antdv 中,render 函数接收 (text, record, index)
|
|
||||||
// const createMediaRender = (type: "image" | "video") => {
|
|
||||||
// return (text: string) => {
|
|
||||||
// if (!text) return "-";
|
|
||||||
// // 这里简化处理,实际项目中可能需要使用 h 函数渲染图标和点击事件
|
|
||||||
// // 由于无法直接在这里绑定 click 事件到简单的字符串返回,建议在 columns 定义中使用 slots 或 h 函数
|
|
||||||
// // 为了保持逻辑清晰,这里仅返回文本提示,实际 UI 需结合 Antdv 的 customRender
|
|
||||||
// return type === "image" ? "查看图片" : "播放视频";
|
|
||||||
// };
|
|
||||||
// };
|
|
||||||
|
|
||||||
// --- Columns 定义 ---
|
|
||||||
|
|
||||||
// 主表格 Columns
|
// 主表格 Columns
|
||||||
const columns = computed(() => {
|
const columns = computed(() => {
|
||||||
@ -334,59 +333,6 @@ const columns = computed(() => {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
// 导入预览表格 Columns (包含行内编辑逻辑)
|
|
||||||
const modalColumns = computed(() => {
|
|
||||||
const isEditing = (_record: any, index: number) => index === editingKey.value;
|
|
||||||
|
|
||||||
// const save = async (index: number) => {
|
|
||||||
// // 保存逻辑:实际上 fileTableData 是响应式的,input change 时已经更新
|
|
||||||
// editingKey.value = "";
|
|
||||||
// message.success("行数据已更新");
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const deleteRow = (index: number) => {
|
|
||||||
// fileTableData.value = fileTableData.value.filter((_, i) => i !== index);
|
|
||||||
// message.success("行数据已删除");
|
|
||||||
// };
|
|
||||||
|
|
||||||
return baseColumnsConfig.map((col) => ({
|
|
||||||
...col,
|
|
||||||
customRender: ({ text, record, index }: any) => {
|
|
||||||
const editing = isEditing(record, index);
|
|
||||||
|
|
||||||
// 如果是媒体列
|
|
||||||
if (col.dataIndex === "level5" || col.dataIndex === "level6") {
|
|
||||||
if (editing) {
|
|
||||||
// 返回 Input 组件的 VNode 或标识,实际需用 slot 或 h 函数
|
|
||||||
return "Input编辑中";
|
|
||||||
}
|
|
||||||
return col.dataIndex === "level5" ? "查看图片" : "播放视频";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 普通列
|
|
||||||
if (editing) {
|
|
||||||
// 返回 Input 组件标识
|
|
||||||
return "Input编辑中";
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
},
|
|
||||||
// Antdv 支持通过 slots 自定义单元格内容以实现交互
|
|
||||||
slots: { customRender: `cell-${col.dataIndex}` },
|
|
||||||
}));
|
|
||||||
// .concat({
|
|
||||||
// title: "操作",
|
|
||||||
// dataIndex: "operation",
|
|
||||||
// fixed: "right",
|
|
||||||
// width: 140,
|
|
||||||
// align: "center",
|
|
||||||
// customRender: ({ record, index }: any) => {
|
|
||||||
// const editable = isEditing(record, index);
|
|
||||||
// return editable ? "保存/取消" : "修改/删除";
|
|
||||||
// },
|
|
||||||
// slots: { customRender: "cell-operation" },
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- 业务逻辑方法 ---
|
// --- 业务逻辑方法 ---
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
@ -563,40 +509,111 @@ const handleEditSubmit = async (values: FormData) => {
|
|||||||
submitLoading.value = false;
|
submitLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const isRowDataEqual = (oldRow: any, newRow: any, fields: string[]): boolean => {
|
||||||
|
for (const field of fields) {
|
||||||
|
// 处理 undefined/null 的情况,确保比较的一致性
|
||||||
|
let oldVal = oldRow?.[field];
|
||||||
|
let newVal = newRow?.[field];
|
||||||
|
|
||||||
const handleModalOk = () => {
|
// 特殊处理:如果都是空值,视为相等
|
||||||
Modal.confirm({
|
if ((oldVal === undefined || oldVal === null || oldVal === '') &&
|
||||||
title: "是否提交导入数据?",
|
(newVal === undefined || newVal === null || newVal === '')) {
|
||||||
onOk: async () => {
|
continue;
|
||||||
// tableData.value = [...fileTableData.value];
|
}
|
||||||
visible.value = false;
|
|
||||||
editingKey.value = "";
|
// 严格不相等
|
||||||
message.success("数据已导入至列表");
|
if (oldVal !== newVal) {
|
||||||
// let res: any = await submitImportTask(ids);
|
return false;
|
||||||
// if (res && res?.code == 0) {
|
}
|
||||||
// message.success("审批成功");
|
}
|
||||||
// tableRef.value?.getList();
|
return true;
|
||||||
// }
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleModalCancel = () => {
|
const checkTableDataChanges = () => {
|
||||||
|
// 1. 定义需要比对的核心字段 (对应 Form 中的字段)
|
||||||
|
const oldData = orgFileTableData.value;
|
||||||
|
const newData = fileTableData.value;
|
||||||
|
|
||||||
|
// 2. 如果行数不同,肯定有变化
|
||||||
|
if (oldData.length !== newData.length) {
|
||||||
|
return { hasChanged: true, changedCount: newData.length };
|
||||||
|
}
|
||||||
|
|
||||||
|
let changedCount = 0;
|
||||||
|
|
||||||
|
// 3. 逐行比对
|
||||||
|
for (let i = 0; i < newData.length; i++) {
|
||||||
|
const oldRow = oldData[i];
|
||||||
|
const newRow = newData[i];
|
||||||
|
|
||||||
|
// 如果某一行数据不一致,计数+1
|
||||||
|
if (!isRowDataEqual(oldRow, newRow, ['baseId'])) {
|
||||||
|
changedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { hasChanged: changedCount > 0, changedCount };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交导入
|
||||||
|
const handleModalOk = () => {
|
||||||
|
console.log(orgFileTableData.value)
|
||||||
|
console.log(fileTableData.value)
|
||||||
|
console.log(
|
||||||
|
modalTableRef.value.editingData)
|
||||||
|
if (modalTableRef.value.editingData != undefined) {
|
||||||
|
message.warning("请点击保存后提交数据!");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { hasChanged, changedCount } = checkTableDataChanges();
|
||||||
|
|
||||||
|
// 3. 如果没有变化,直接返回,不执行后续操作
|
||||||
|
if (!hasChanged) {
|
||||||
|
message.info("数据未发生任何变化,无需提交");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(123)
|
||||||
|
// if (warnings.value.length > 0) {
|
||||||
|
// message.warning("请先修复数据");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// Modal.confirm({
|
||||||
|
// title: "是否提交导入数据?",
|
||||||
|
// onOk: async () => {
|
||||||
|
// // tableData.value = [...fileTableData.value];
|
||||||
|
// let ids = fileTableData.value.map((item: any) => item.id);
|
||||||
|
// visible.value = false;
|
||||||
|
// editingKey.value = "";
|
||||||
|
// let res: any = await submitImportTask(ids);
|
||||||
|
// if (res && res?.code == 0) {
|
||||||
|
// message.success("导入成功");
|
||||||
|
// tableRef.value?.getList();
|
||||||
|
// } else {
|
||||||
|
// message.error("导入失败,请检查数据是否正确");
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭导入弹窗
|
||||||
|
const handleCustomCancel = () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "是否取消导入数据?",
|
title: "是否取消导入数据?",
|
||||||
|
content: "未提交的数据将丢失",
|
||||||
|
okText: "确定",
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
editingKey.value = "";
|
editingKey.value = "";
|
||||||
// let res: any = await cancelImportTask(ids);
|
// 可选:调用取消接口
|
||||||
// if (res && res?.code == 0) {
|
let res: any = await cancelImportTask({taskId: taskId.value});
|
||||||
// message.success("审批成功");
|
if (res && res?.code == 0) {
|
||||||
// tableRef.value?.getList();
|
message.success("取消成功");
|
||||||
// }
|
tableRef.value?.getList();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleFileSelect = (e: Event) => {
|
const handleFileSelect = (e: Event) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const file = target.files?.[0];
|
const file = target.files?.[0];
|
||||||
@ -621,8 +638,7 @@ const handleFileSelect = (e: Event) => {
|
|||||||
resetFileInput();
|
resetFileInput();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
fileChange(file);
|
||||||
// props.importBtn(file);
|
|
||||||
resetFileInput();
|
resetFileInput();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -631,23 +647,66 @@ const resetFileInput = () => {
|
|||||||
fileInputRef.value.value = "";
|
fileInputRef.value.value = "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const importBtn = async (file: File) => {
|
const fileChange = async (file: File) => {
|
||||||
|
try {
|
||||||
|
fileLoading.value = true;
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
let res: any = await importFishZip(formData);
|
||||||
|
const { code } = res.data || {};
|
||||||
|
if (code == 1) {
|
||||||
|
message.error("导入失败");
|
||||||
|
} else {
|
||||||
|
message.success("导入成功");
|
||||||
|
fileTableaAnalysis(res, "file");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 导入-按钮
|
||||||
|
const importBtn = async () => {
|
||||||
let res: any = await checkImportStatus();
|
let res: any = await checkImportStatus();
|
||||||
console.log(res)
|
taskId.value = "";
|
||||||
// fileInputRef.value?.click();
|
if (res?.code == 0) {
|
||||||
// fileLoading.value = true;
|
const { hasImportingTask ,currentTask} = res?.data || {};
|
||||||
|
taskId.value = currentTask.id;
|
||||||
|
if (hasImportingTask) {
|
||||||
|
visible.value = true;
|
||||||
|
nextTick(async () => {
|
||||||
|
fileLoading.value = true;
|
||||||
|
modalTableRef.value.editingRowIndex = null;
|
||||||
|
let res1: any = await getLastImportResult();
|
||||||
|
fileTableaAnalysis(res1, "get");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fileInputRef.value?.click();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error("导入查询失败");
|
||||||
|
}
|
||||||
// editingKey.value = "";
|
// editingKey.value = "";
|
||||||
|
};
|
||||||
// try {
|
const fileTableaAnalysis = (res: any, type: string) => {
|
||||||
// const formData = new FormData();
|
let data = [];
|
||||||
// formData.append("file", file);
|
// let warningsList = [];
|
||||||
// let res: any = await importFishZip(formData);
|
let list = [];
|
||||||
// console.log(res);
|
if (type == "file") {
|
||||||
// visible.value = true;
|
list = res.data.failedRows;
|
||||||
// } catch (error) {
|
} else {
|
||||||
// } finally {
|
list = res.data.result.failedRowDetails;
|
||||||
// // fileLoading.value = false;
|
}
|
||||||
// }
|
console.log(list);
|
||||||
|
list.forEach((item) => {
|
||||||
|
data.push({
|
||||||
|
...item.data,
|
||||||
|
_warnings: item.warnings,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
fileTableData.value = data || [];
|
||||||
|
orgFileTableData.value = JSON.parse(JSON.stringify(fileTableData.value));
|
||||||
|
// warnings.value = warningsList || [];
|
||||||
|
fileLoading.value = false;
|
||||||
};
|
};
|
||||||
const handleReset = (values) => {
|
const handleReset = (values) => {
|
||||||
handleSearchFinish(values);
|
handleSearchFinish(values);
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": false,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": false,
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export default ({ mode }: ConfigEnv): UserConfig => {
|
|||||||
// 线上API地址
|
// 线上API地址
|
||||||
// target: 'http://localhost:8093/',
|
// target: 'http://localhost:8093/',
|
||||||
// 本地API地址
|
// 本地API地址
|
||||||
target: 'http://10.84.121.21:8093',
|
target: 'http://10.84.121.21:8093',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: path =>
|
rewrite: path =>
|
||||||
path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user