<script setup lang="ts">
import { onMounted, reactive, ref, watch } from "vue";
import { $t } from "@/locales";
import { UploadFileInfo, UploadInst } from "naive-ui";
import { exportXlsx, SheetData } from "@/utils/export-excel";
import { fetchAddInterlock, fetchUpdateInterlock, fetchUploadInterlockLedger} from "@/service/api";
import { useEquipment } from "@/hooks/common/useEquipment";
defineOptions({
name: "LedgerUploadDrawer",
});
interface Props {
/** the type of operation */
}
// 引入设备钩子
const {
loading: equipLoading,
filteredequipOptions,
handleequipSearch,
loadEquipMap,
getequip,
nameToequipMap,
resetEquipSearch
} = useEquipment();
onMounted(() => {
loadEquipMap();
});
const props = defineProps<Props>();
const fileListLengthRef = ref(0);
const uploadRef = ref<UploadInst | null>(null);
// 定义符合实际接口返回的数据结构
interface UploadResult {
total_files: number; // 总文件数(数字类型)
success_files: number; // 成功文件数(数字类型)
total_records: number; // 导入记录数(数字类型)
details: FileDetail[]; // 文件详情
}
interface FileDetail {
filename: string; // 文件名
status: "success" | "partial" | "fail"; // 状态
imported: number; // 导入记录数(数字类型)
errors: string[]; // 错误信息
}
const uploadResult = ref<UploadResult | null>(null);
const loading = ref(false);
const fileList = ref<UploadFileInfo[]>([]); // 使用单独的ref管理文件列表
const fileDetail = ref<FileDetail | null>(null);
interface Emits {
(e: "submitted"): void;
}
const emit = defineEmits<Emits>();
const visible = defineModel<boolean>("visible", {
default: false,
});
//const model: any = reactive(createDefaultModel());
const model = reactive({
// 不再需要file属性
});
function createDefaultModel(): any {
return {
file: null,
};
}
function handleInitModel() {
Object.assign(model, createDefaultModel());
}
function closeDrawer() {
visible.value = false;
}
async function handleSubmit() {
// request
if (fileList.value.length === 0) {
window.$message?.error("没有待上传文件");
return;
}
loading.value = true;
uploadResult.value = null; // 重置结果
try {
const formData = new FormData();
// 添加所有文件到FormData
fileList.value.forEach((fileInfo) => {
if (fileInfo.file) {
formData.append("files", fileInfo.file);
}
});
const { data, error } = await fetchUploadInterlockLedger(formData);
console.log(data)
if (!error && data) {
// 使用实际接口返回的数据结构
uploadResult.value = {
total_files: data.total_files || fileList.value.length,
success_files: data.success_files || 0,
total_records: data.total_records || 0,
details: data.details
};
// 显示详细上传结果
// if (uploadResult.value?.success_files <= uploadResult.value?.total_files){
// window.$message?.warning(
// `${uploadResult.value?.success_files}/${uploadResult.value?.total_files}个文件上传成功`
// );
// }
let allErrors: any[] = []; // 存储所有错误信息
if (uploadResult.value.details.length > 0) {
for (var val in uploadResult.value.details) {
if (uploadResult.value.details[val].errors.length > 0) {
// 将当前元素的errors数组拼接到总错误列表
allErrors = allErrors.concat(uploadResult.value.details[val].errors);
window.$message?.error(`${uploadResult.value.details[val].filename}:${allErrors.join('\n')}`);
}
}
// 统一显示所有错误(用换行符分隔)
// if (allErrors.length > 0) {
// window.$message?.warning(allErrors.join('\n'));
// }
}
console.log(allErrors)
if (allErrors.length == 0) {
window.$message?.success("上传成功");
}
}
}
catch (err) {
window.$message?.error("网络错误");
} finally {
loading.value = false;
}
closeDrawer();
emit("submitted");
}
function handleChange(data: { fileList: UploadFileInfo[] }) {
fileList.value = data.fileList; // 更新文件列表
uploadResult.value = null; // 重置结果
}
//sheet={}
function downloadTemplate() {
const equipList = Object.keys(nameToequipMap.value);
// 创建主工作表
const mainSheet: SheetData = {
sheetName: "互锁台账列表",
data: [
// 表头行
[
"报警名称", "触发器", "满足条件", "渠道号", "报警级别",
"报警描述", "触发器渠道", "报警动作", "报警动作Data通道",
"报警动作描述", "互锁类型", "所属模块", "模块类型",
"所属产品", // 需要设置下拉选择的列
"所属部门", "备注"
],
],
// 优化数据验证:使用动态范围引用
dataValidations: [{
type: 'list',
formula1: `设备选项说明!$A$2:$A$${equipList.length + 1}`, // 引用另一工作表的数据
ref: "N2:N1000" // 应用范围:N列第2行到1000行
}]
};
// 创建设备选项说明表
const helpSheet: SheetData = {
sheetName: "设备选项说明",
data: [
["设备选项列表"],
...equipList.map(item => [item])
],
dataValidations:[]
};
exportXlsx([mainSheet, helpSheet], "互锁台账导入模板");
}
// watch(visible, () => {
// if (visible.value) {
// handleInitModel();
// }
// });
function clearFiles() {
fileList.value = [];
if (uploadRef.value) {
uploadRef.value.clear();
}
uploadResult.value = null;
}
watch(visible, (newVal) => {
if (newVal) {
clearFiles(); // 每次打开时清空文件
}
});
</script>
<template>
<NModal v-model:show="visible" preset="dialog" :title="$t('common.upload')">
<NPopover trigger="hover">
<template #trigger>
<NButton @click="downloadTemplate" text type="primary">{{
$t("common.templateDownload")
}}</NButton>
</template>
<span>点此下载导入模板</span>
</NPopover>
<NUpload
accept=".csv,.xls,.xlsx"
ref="uploadRef"
:default-upload="false"
:max="10"
multiple
:file-list="fileList"
@change="handleChange"
>
<NUploadDragger @click="clearFiles">
<div style="margin-bottom: 12px">
<icon-mdi-tray-upload class="text-icon" />
</div>
<NText style="font-size: 16px"> 点击或者拖动文件到该区域来上传 </NText>
<NP depth="3" style="margin: 8px 0 0 0">
请参考上传模板来提供数据,支持csv,xls,xlsx格式,单次最多上传10个文件
</NP>
</NUploadDragger>
</NUpload>
<template #action>
<NSpace :size="16">
<NButton @click="closeDrawer">{{ $t("common.cancel") }}</NButton>
<NButton type="primary"
@click="handleSubmit"
:loading="loading"
:disabled="fileList.length === 0"
>
{{
$t("common.confirm")
}}</NButton>
</NSpace>
</template>
</NModal>
</template>
<style scoped></style>
用户打开模板后,"所属产品"列会有下拉箭头
点击下拉箭头会显示设备选项列表
用户只能选择列表中的设备,不能手动输入
最新发布