|
|
@@ -1,5 +1,5 @@
|
|
|
<template>
|
|
|
- <div class="content" v-loading="loading">
|
|
|
+ <div class="content">
|
|
|
<el-tabs
|
|
|
ref="tabs"
|
|
|
tab-position="left"
|
|
|
@@ -14,6 +14,7 @@
|
|
|
<el-upload
|
|
|
action=""
|
|
|
class="upload-demo"
|
|
|
+ multiple
|
|
|
:http-request="customUpload"
|
|
|
:on-change="validateAndHandleChange"
|
|
|
:before-upload="checkFileType"
|
|
|
@@ -102,7 +103,6 @@
|
|
|
</span>
|
|
|
</el-tooltip>
|
|
|
</span>
|
|
|
- 计算器弹出框
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane name="associatedFields">
|
|
|
<span slot="label" class="iconFont">
|
|
|
@@ -126,7 +126,9 @@
|
|
|
<el-dialog
|
|
|
title="数据列表特征计算函数"
|
|
|
:visible.sync="dialogVisible"
|
|
|
+ element-loading-background="rgba(0, 0, 0, 0.8)"
|
|
|
width="600px"
|
|
|
+ v-loading="loading"
|
|
|
:before-close="handleClose"
|
|
|
>
|
|
|
<el-form
|
|
|
@@ -293,7 +295,6 @@ export default {
|
|
|
"setTriggerGetData",
|
|
|
"setUpdateTriggerGetData",
|
|
|
]),
|
|
|
-
|
|
|
async initDB() {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const request = indexedDB.open("FileDataDB", 2); // 使用较高版本
|
|
|
@@ -333,38 +334,64 @@ export default {
|
|
|
console.log(this.options, "调用数据");
|
|
|
},
|
|
|
async submitComputedFn(formName) {
|
|
|
+ this.loading = true;
|
|
|
try {
|
|
|
// 1. 验证表单
|
|
|
- if (!(await this.validateForm(formName))) return;
|
|
|
+ if (!(await this.validateForm(formName))) {
|
|
|
+ this.loading = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (Number(this.ruleForm.max) < Number(this.ruleForm.min)) {
|
|
|
this.$message.error("开始行不可以大于结束行");
|
|
|
+ this.loading = false;
|
|
|
return;
|
|
|
}
|
|
|
// 2. 获取 IndexedDB 数据
|
|
|
const indexeddbData = await getDataFromIndexedDB();
|
|
|
const region = this.getRegionData(indexeddbData);
|
|
|
-
|
|
|
if (!region.length) {
|
|
|
console.warn("当前选择的列未找到数据");
|
|
|
+ this.loading = false;
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+ let newDatas = [];
|
|
|
+ if (region[0].length > 500) {
|
|
|
+ if (!Number(this.ruleForm.min) || !Number(this.ruleForm.max)) {
|
|
|
+ this.$message.warning("每次最多选择范围在500条内。请输入数据范围");
|
|
|
+ this.loading = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ newDatas = region[0].slice(
|
|
|
+ Number(this.ruleForm.min) - 1,
|
|
|
+ Number(this.ruleForm.max) - 1
|
|
|
+ );
|
|
|
+ if (newDatas.length > 500) {
|
|
|
+ this.$message.warning(
|
|
|
+ "由于列数据过长,为了保证页面操作流畅,每次最多选择范围在500条内。请分批次选择。"
|
|
|
+ );
|
|
|
+ this.loading = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ newDatas = region[0];
|
|
|
+ this.loading = false;
|
|
|
+ }
|
|
|
// 3. 调用算法接口
|
|
|
- const resData = await this.fetchAlgorithmData(region[0]);
|
|
|
-
|
|
|
+ const resData = await this.fetchAlgorithmData(newDatas);
|
|
|
// 4. 筛选和处理数据
|
|
|
const filteredData = this.filterResponseData(resData);
|
|
|
-
|
|
|
// 5. 构建导出数据
|
|
|
const resObj = this.buildExportData(indexeddbData, filteredData);
|
|
|
this.storeData(resObj);
|
|
|
this.resetForm();
|
|
|
- console.log(resObj, "resObj");
|
|
|
+ this.loading = false;
|
|
|
+ this.$message.success("成功");
|
|
|
} catch (error) {
|
|
|
console.error("提交过程中发生错误:", error);
|
|
|
+ this.$message.error(error);
|
|
|
+ this.loading = false;
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
async validateForm(formName) {
|
|
|
try {
|
|
|
const valid = await this.$refs[formName].validate();
|
|
|
@@ -446,7 +473,7 @@ export default {
|
|
|
}
|
|
|
resObj.filename =
|
|
|
format(new Date(), "yyyyMMdd-HH:mm:ss") + resObj.fileOldName;
|
|
|
- resObj.fileId = new Date().getTime();
|
|
|
+ resObj.fileId = new Date().getTime() + "";
|
|
|
resObj.fileData = resData.map((item) => {
|
|
|
const dynamicKeys = this.ruleForm.type.reduce((acc, label) => {
|
|
|
const fieldName = this.selectedNames.find(
|
|
|
@@ -466,7 +493,6 @@ export default {
|
|
|
|
|
|
return resObj;
|
|
|
},
|
|
|
-
|
|
|
resetForm() {
|
|
|
this.ruleForm = {
|
|
|
max: "",
|
|
|
@@ -476,7 +502,6 @@ export default {
|
|
|
};
|
|
|
this.dialogVisible = false; // 重置表单状态
|
|
|
},
|
|
|
-
|
|
|
async storeData(newFileData) {
|
|
|
await storeSetData(this.db, "files", "fileDataArray", newFileData, () => {
|
|
|
this.setTriggerGetData(true);
|
|
|
@@ -508,46 +533,98 @@ export default {
|
|
|
const formData = new FormData();
|
|
|
formData.append("file", file);
|
|
|
// 使用 axios 自定义上传逻辑
|
|
|
+ console.log("自定义上传", file.name);
|
|
|
},
|
|
|
// 验证并处理文件变化
|
|
|
- validateAndHandleChange(file) {
|
|
|
- if (this.checkFileType(file)) {
|
|
|
- this.handleChange(file); // 仅当验证通过时调用 handleChange
|
|
|
+ validateAndHandleChange(fileList) {
|
|
|
+ // 判断 fileList 是否为数组(多个文件)还是单个文件
|
|
|
+ if (Array.isArray(fileList)) {
|
|
|
+ // 如果是数组(多个文件),遍历每个文件进行处理
|
|
|
+ fileList.forEach((file) => {
|
|
|
+ if (this.checkFileType(file)) {
|
|
|
+ this.handleChange(file); // 验证通过后逐一处理
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 如果是单个文件,直接处理
|
|
|
+ if (this.checkFileType(fileList)) {
|
|
|
+ this.handleChange(fileList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 检查文件类型&多个文件选择,但多个文件总数大小不能超过50KB
|
|
|
+ checkFileType(file) {
|
|
|
+ // 判断文件类型
|
|
|
+ const isValidType =
|
|
|
+ file.type === "text/csv" ||
|
|
|
+ file.name.endsWith(".csv") ||
|
|
|
+ file.type ===
|
|
|
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
|
|
|
+ file.name.endsWith(".xlsx") ||
|
|
|
+ file.name.endsWith(".xls");
|
|
|
+
|
|
|
+ if (!isValidType) {
|
|
|
+ this.$message.error("只能上传csv文件或xlsx或xls文件");
|
|
|
+ return false; // 返回false,阻止上传
|
|
|
}
|
|
|
+ // 判断文件大小(以字节为单位,50KB = 51200字节)
|
|
|
+ const maxSize = 50 * 1024; // 50KB
|
|
|
+ if (file.size > maxSize) {
|
|
|
+ this.$message.error("文件大小不能超过50KB");
|
|
|
+ return false; // 返回false,阻止上传
|
|
|
+ }
|
|
|
+ return true; // 如果验证通过,允许上传
|
|
|
},
|
|
|
- // 文件变化时的处理
|
|
|
+
|
|
|
+ // 处理文件
|
|
|
handleChange(file) {
|
|
|
- this.checkFileType(file);
|
|
|
- //csv 本身不支持多个sheet 页 ,所有以这里不需要循环处理
|
|
|
- if (file && file.name.endsWith(".csv")) {
|
|
|
- Papa.parse(file.raw, {
|
|
|
- header: true,
|
|
|
- complete: (results) => {
|
|
|
- // 可以进一步处理解析后的数据
|
|
|
- const fileData = {
|
|
|
- filename: format(new Date(), "yyyyMMdd-HH:mm:ss") + file.name,
|
|
|
- fileOldName: file.name,
|
|
|
- fileData: results.data,
|
|
|
- fileId: new Date().getTime(),
|
|
|
- };
|
|
|
- if (results.data.length > 0) {
|
|
|
- this.storeData(fileData);
|
|
|
+ // 如果是 CSV 文件
|
|
|
+ if (file.name.endsWith(".csv")) {
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = (e) => {
|
|
|
+ const encoding = this.detectFileEncoding(e.target.result);
|
|
|
+ const text = new TextDecoder(encoding).decode(
|
|
|
+ new Uint8Array(e.target.result)
|
|
|
+ );
|
|
|
+
|
|
|
+ // 使用 Papa.parse 解析 CSV 数据
|
|
|
+ Papa.parse(text, {
|
|
|
+ header: true, // 第一行作为表头
|
|
|
+ complete: (results) => {
|
|
|
+ const newData = results.data.slice(0, results.data.length - 1);
|
|
|
+ const fileData = {
|
|
|
+ filename: format(new Date(), "yyyyMMdd-HH:mm:ss") + file.name,
|
|
|
+ fileOldName: file.name,
|
|
|
+ fileData: newData,
|
|
|
+ fileId:
|
|
|
+ new Date().getTime() + "_" + Math.floor(Math.random() * 1000),
|
|
|
+ };
|
|
|
+ if (results.data.length > 0) {
|
|
|
+ this.storeData(fileData);
|
|
|
+ this.loading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error: (error) => {
|
|
|
+ console.error("Error parsing CSV:", error);
|
|
|
this.loading = false;
|
|
|
- }
|
|
|
- },
|
|
|
- error: (error) => {
|
|
|
- console.error("Error parsing CSV:", error);
|
|
|
- this.loading = false;
|
|
|
- },
|
|
|
- });
|
|
|
+ },
|
|
|
+ });
|
|
|
+ };
|
|
|
+ reader.readAsArrayBuffer(file.raw);
|
|
|
} else {
|
|
|
+ // 如果是 Excel 文件
|
|
|
const reader = new FileReader();
|
|
|
reader.onload = (e) => {
|
|
|
const data = new Uint8Array(e.target.result);
|
|
|
+ // 读取 Excel 文件
|
|
|
const workbook = XLSX.read(data, { type: "array" });
|
|
|
+
|
|
|
workbook.SheetNames.forEach((sheetName, ind) => {
|
|
|
const sheetData = XLSX.utils.sheet_to_json(
|
|
|
- workbook.Sheets[sheetName]
|
|
|
+ workbook.Sheets[sheetName],
|
|
|
+ {
|
|
|
+ defval: "", // 确保空值不会导致错误
|
|
|
+ }
|
|
|
);
|
|
|
const fileData = {
|
|
|
filename:
|
|
|
@@ -560,34 +637,18 @@ export default {
|
|
|
this.storeData(fileData);
|
|
|
this.loading = false;
|
|
|
}
|
|
|
- // console.log("Parsed Excel Sheet Data:", sheetData);
|
|
|
- // 可以进一步处理解析后的数据
|
|
|
});
|
|
|
};
|
|
|
reader.readAsArrayBuffer(file.raw);
|
|
|
}
|
|
|
},
|
|
|
- //判断上传文件类型
|
|
|
- checkFileType(file) {
|
|
|
- const isPdf =
|
|
|
- file.type === "text/csv" ||
|
|
|
- file.name.endsWith(".csv") ||
|
|
|
- file.type ===
|
|
|
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
|
|
|
- file.name.endsWith(".xlsx") ||
|
|
|
- file.name.endsWith(".xls");
|
|
|
- if (!isPdf) {
|
|
|
- this.$message.error("只能上传csv文件或xlsx或xls文件");
|
|
|
- return false;
|
|
|
- }
|
|
|
- // 判断文件大小(以字节为单位,100kB = 102400字节)
|
|
|
- const maxSize = 50 * 1024; // 100kB
|
|
|
- if (file.size > maxSize) {
|
|
|
- this.$message.error("文件大小不能超过50kB");
|
|
|
- return false;
|
|
|
+ // 检测文件编码的方法
|
|
|
+ detectFileEncoding(arrayBuffer) {
|
|
|
+ const text = new TextDecoder("utf-8").decode(new Uint8Array(arrayBuffer));
|
|
|
+ if (text.includes("�")) {
|
|
|
+ return "gbk"; // 如果有乱码字符,可能是 GBK 编码
|
|
|
}
|
|
|
- this.loading = true;
|
|
|
- return true;
|
|
|
+ return "utf-8";
|
|
|
},
|
|
|
},
|
|
|
async mounted() {
|
|
|
@@ -614,8 +675,11 @@ export default {
|
|
|
.popover-footer {
|
|
|
text-align: right;
|
|
|
}
|
|
|
- .iconFont {
|
|
|
+ ::v-deep .iconFont {
|
|
|
padding: 0 20px;
|
|
|
+ width: 100% !important;
|
|
|
+ height: 100% !important;
|
|
|
+ display: inline-block;
|
|
|
}
|
|
|
|
|
|
::v-deep .el-tabs__content {
|