@skyfox2000/webui 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@
5
5
  "explorer.fileNesting.patterns": {
6
6
  "*.ts": "$(capture).test.ts, $(capture).test.tsx",
7
7
  "*.tsx": "$(capture).test.ts, $(capture).test.tsx",
8
- "package.json": "index.html,pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitignore,.gitattributes,.gitpod.yml,CNAME,README*,.npmrc,.browserslistrc,.env.*,env.d.ts,.prettierrc,.eslintrc.js,*.md",
8
+ "package.json": "index.html,pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitignore,.gitattributes,.gitpod.yml,CNAME,README*,.npmrc,.browserslistrc,.env.*,env.d.ts,.prettierrc,.eslintrc.js,*.md,.cursorignore",
9
9
  "vite.config.ts": "tsconfig.*.json,postcss.config.ts,tailwind.config.ts,tsconfig.json"
10
10
  },
11
11
  "editor.formatOnSave": true,
@@ -0,0 +1,210 @@
1
+ import { defineComponent as $, ref as k, computed as O, watch as j, createElementBlock as p, openBlock as f, createElementVNode as r, createVNode as v, unref as l, mergeProps as B, withCtx as U, createTextVNode as E, toDisplayString as y, Fragment as M, renderList as R, normalizeClass as T, createCommentVNode as F } from "vue";
2
+ import { _ as V } from "./index-htdsukeW.js";
3
+ import { Upload as A, Tag as K, Progress as D } from "ant-design-vue";
4
+ import { httpPost as I, ResStatus as Q } from "@skyfox2000/fapi";
5
+ import "./hostInfo-DK8lknRe.js";
6
+ import "vue-draggable-next";
7
+ import h from "vue-m-message";
8
+ import "dayjs";
9
+ import { combineParams as q } from "@skyfox2000/microbase";
10
+ import { U as o, p as G } from "./file-upload-CMHnVQty.js";
11
+ import "async-validator";
12
+ const H = { class: "w-full border border-solid border-gray-100 mt-1 rounded-md py-5" }, J = { class: "flex items-center justify-between w-full" }, W = { class: "w-35 mx-3" }, X = { class: "flex-1 text-sm text-gray-500" }, Y = { class: "mt-4 px-3" }, Z = { class: "flex items-center justify-between" }, ee = { class: "flex items-center" }, te = { class: "flex items-center" }, oe = ["onClick"], ne = ["onClick"], se = ["onClick"], ve = /* @__PURE__ */ $({
13
+ __name: "uploadList",
14
+ props: {
15
+ autoUpload: { type: Boolean, default: !1 },
16
+ downloadUrl: {},
17
+ fileList: { default: () => [] },
18
+ placeholder: { default: "" },
19
+ fileExt: {},
20
+ maxFileSize: { default: 20 },
21
+ maxCount: { default: 5 },
22
+ parentPath: {}
23
+ },
24
+ emits: ["update:file-list"],
25
+ setup(i, { emit: u }) {
26
+ const e = i, a = k(e.fileList), c = k(), d = u, b = O(() => {
27
+ var t;
28
+ return (t = e.fileExt) != null && t.length ? e.fileExt.map((s) => `.${s}`).join(",") : "";
29
+ }), g = (t) => {
30
+ var s;
31
+ if (e.fileExt && e.fileExt.length > 0) {
32
+ const n = ((s = t.name.split(".").pop()) == null ? void 0 : s.toLowerCase()) || "";
33
+ if (!e.fileExt.includes(n))
34
+ return h.error("文件类型不支持"), !1;
35
+ }
36
+ return t.size / 1024 / 1024 > e.maxFileSize ? (h.error(`文件大小超过 ${e.maxFileSize}MB 限制`), !1) : e.maxCount > 1 && a.value.length >= e.maxCount ? (h.error(`最多上传 ${e.maxCount} 个文件`), !1) : e.autoUpload;
37
+ }, x = (t) => {
38
+ t.forEach((s) => {
39
+ s.fileName || (s.fileName = s.name), e.parentPath && (s.name = G.join("/", e.parentPath, s.fileName));
40
+ });
41
+ }, _ = O(() => ({
42
+ accept: b.value,
43
+ multiple: !0,
44
+ fileList: a.value,
45
+ "onUpdate:fileList": x,
46
+ beforeUpload: g,
47
+ listType: "text",
48
+ maxCount: e.maxCount,
49
+ showUploadList: !1,
50
+ onChange: (t) => {
51
+ e.autoUpload || (a.value = t.fileList);
52
+ }
53
+ }));
54
+ j(
55
+ () => a.value,
56
+ (t) => {
57
+ d("update:file-list", t);
58
+ },
59
+ { deep: !0 }
60
+ );
61
+ const C = (t) => {
62
+ const s = a.value[t].minioFile, n = {
63
+ api: e.downloadUrl.api,
64
+ authorize: e.downloadUrl.authorize,
65
+ url: e.downloadUrl.url,
66
+ // url: props.pageData.urls.download!.url,
67
+ params: {
68
+ Query: {
69
+ FileKey: s.Key
70
+ }
71
+ }
72
+ };
73
+ re(n);
74
+ }, m = (t) => {
75
+ t.status = t.status === o.Offline ? o.Online : o.Offline, t.minioFile.Status = t.status;
76
+ }, L = (t) => {
77
+ a.value.splice(t, 1);
78
+ }, z = () => {
79
+ const t = e.fileExt && e.fileExt.length ? `文件必须为 ${e.fileExt.join("/")}` : "", s = e.maxFileSize !== 0 ? `单文件最大 ${e.maxFileSize}MB` : "", n = e.maxCount !== 0 ? `最多 ${e.maxCount} 个文件` : "";
80
+ return [s, t, n].filter(Boolean).join(",");
81
+ }, N = (t) => {
82
+ switch (t) {
83
+ case o.Uploading:
84
+ return "blue";
85
+ case o.Success:
86
+ return "green";
87
+ case o.Error:
88
+ return "red";
89
+ case o.Online:
90
+ return "green";
91
+ case o.Offline:
92
+ return "pink";
93
+ default:
94
+ return "cyan";
95
+ }
96
+ }, P = (t) => {
97
+ switch (t) {
98
+ case o.Uploading:
99
+ return "上传中";
100
+ case o.Success:
101
+ return "已完成";
102
+ case o.Error:
103
+ return "上传失败";
104
+ case o.Online:
105
+ return "在线";
106
+ case o.Offline:
107
+ return "已下线";
108
+ default:
109
+ return "待上传";
110
+ }
111
+ };
112
+ return (t, s) => (f(), p("div", H, [
113
+ r("div", J, [
114
+ r("div", W, [
115
+ v(l(A), B({
116
+ ref_key: "fileUploader",
117
+ ref: c
118
+ }, _.value), {
119
+ default: U(() => [
120
+ v(l(V), null, {
121
+ default: U(() => s[0] || (s[0] = [
122
+ E("选择文件")
123
+ ])),
124
+ _: 1,
125
+ __: [0]
126
+ })
127
+ ]),
128
+ _: 1
129
+ }, 16)
130
+ ]),
131
+ r("div", X, y(z()), 1)
132
+ ]),
133
+ r("div", Y, [
134
+ (f(!0), p(M, null, R(a.value, (n, w) => (f(), p("div", {
135
+ key: w,
136
+ class: "mb-2 pb-1"
137
+ }, [
138
+ r("div", Z, [
139
+ r("div", ee, [
140
+ r("span", {
141
+ class: T(["text-gray-700 mr-2", [n.status == l(o).Offline ? "line-through" : ""]])
142
+ }, y(n.fileName ?? n.name), 3),
143
+ r("span", null, [
144
+ v(l(K), {
145
+ color: N(n.status)
146
+ }, {
147
+ default: U(() => [
148
+ E(y(P(n.status)), 1)
149
+ ]),
150
+ _: 2
151
+ }, 1032, ["color"])
152
+ ])
153
+ ]),
154
+ r("div", te, [
155
+ n.status == l(o).Offline || n.status == l(o).Online ? (f(), p("span", {
156
+ key: 0,
157
+ class: "text-blue-500 hover:text-blue-700 mr-4 cursor-pointer",
158
+ onClick: (S) => m(n)
159
+ }, y(n.status == l(o).Offline ? "上线" : "下线"), 9, oe)) : F("", !0),
160
+ n.status == l(o).Offline || n.status == l(o).Online ? (f(), p("span", {
161
+ key: 1,
162
+ class: "text-blue-500 hover:text-blue-700 mr-4 cursor-pointer",
163
+ onClick: (S) => C(w)
164
+ }, "下载", 8, ne)) : F("", !0),
165
+ r("span", {
166
+ class: "text-red-500 hover:text-red-700 cursor-pointer",
167
+ onClick: (S) => L(w)
168
+ }, "删除", 8, se)
169
+ ])
170
+ ]),
171
+ r("div", null, [
172
+ v(l(D), {
173
+ percent: n.percent,
174
+ "stroke-width": 2,
175
+ "show-info": !1,
176
+ style: { height: "2px" }
177
+ }, null, 8, ["percent"])
178
+ ])
179
+ ]))), 128))
180
+ ])
181
+ ]));
182
+ }
183
+ }), ae = (i, u) => {
184
+ const e = document.createElement("a"), a = URL.createObjectURL(i);
185
+ e.href = a, e.download = u, e.style.display = "none", document.body.appendChild(e), e.click(), URL.revokeObjectURL(a), document.body.removeChild(e);
186
+ }, re = (i, u, e) => {
187
+ try {
188
+ e && (i.api || (i.api = e.api), i.authorize === void 0 && (i.authorize = e.authorize));
189
+ const a = q(i.params, u);
190
+ return I(i, a).then((c) => {
191
+ if ((c == null ? void 0 : c.status) === Q.SUCCESS && c.data) {
192
+ const d = c.data, b = d.Content, g = d.FileName, x = atob(b), _ = [];
193
+ for (let m = 0; m < x.length; m++)
194
+ _.push(x.charCodeAt(m));
195
+ const C = new Blob([new Uint8Array(_)], {
196
+ type: d.Type
197
+ });
198
+ ae(C, g);
199
+ } else
200
+ h.error("下载文件失败!");
201
+ });
202
+ } catch (a) {
203
+ console.error("下载失败:", a), h.error("文件下载失败,请稍后重试");
204
+ }
205
+ };
206
+ export {
207
+ ve as _,
208
+ re as a,
209
+ ae as d
210
+ };
@@ -0,0 +1,179 @@
1
+ var v = Object.defineProperty;
2
+ var m = (t, r, o) => r in t ? v(t, r, { enumerable: !0, configurable: !0, writable: !0, value: o }) : t[r] = o;
3
+ var h = (t, r, o) => m(t, typeof r != "symbol" ? r + "" : r, o);
4
+ import { hostUrl as E } from "@skyfox2000/fapi";
5
+ import { aa as S, a9 as I, z as d } from "./hostInfo-DK8lknRe.js";
6
+ import { mainAppApis as s } from "@skyfox2000/microbase";
7
+ import b from "dayjs";
8
+ var l = /* @__PURE__ */ ((t) => (t.Pending = "pending", t.Uploading = "uploading", t.Success = "success", t.Error = "error", t.Online = "online", t.Offline = "offline", t))(l || {});
9
+ const F = () => s.value ? s.value.getHostInfo() : S().hostInfo, H = () => s.value && s.value.getAppInfo ? s.value.getAppInfo() : I().appInfo, x = (t) => s.value && s.value.userLogin ? s.value.userLogin(t) : d().login(t, !0), U = () => s.value && s.value.userLogout ? s.value.userLogout() : d().logout(), w = () => s.value && s.value.getToken ? s.value.getToken() : d().getToken(), L = () => s.value && s.value.getUserInfo ? s.value.getUserInfo() : d().getUserInfo(), z = (t) => {
10
+ I().push(t);
11
+ };
12
+ class M {
13
+ /**
14
+ * 连接路径参数,已判断 undefined 或 null 值
15
+ * @param args 路径参数数组
16
+ * @returns 连接后的路径字符串
17
+ */
18
+ static join(...r) {
19
+ return r.filter((c) => c != null).join("/").replace(/[\/]+/, "/");
20
+ }
21
+ }
22
+ class D {
23
+ /**
24
+ * AsyncUploader 构造函数
25
+ * @param urlInfo 文件上传的 API 配置(IUrlInfo 对象)
26
+ * @param maxConcurrent 最大允许并发上传的文件数量
27
+ */
28
+ constructor(r, o) {
29
+ /**
30
+ * 设置 API 端点和最大并发数,所有上传文件通过该类控制
31
+ */
32
+ h(this, "urlInfo");
33
+ /**
34
+ * 最大并发上传数
35
+ */
36
+ h(this, "maxConcurrent");
37
+ /**
38
+ * 控制上传任务的中断信号
39
+ */
40
+ h(this, "abortController");
41
+ this.urlInfo = r, this.maxConcurrent = o;
42
+ }
43
+ /**
44
+ * 上传多个文件,控制并发数量
45
+ * @param files 文件列表(File[] 或 FileList)
46
+ * @param onProgress 上传进度回调
47
+ * @param onComplete 上传完成回调
48
+ */
49
+ async uploadFiles(r, o, u) {
50
+ if (!r.length) return;
51
+ const c = Math.min(this.maxConcurrent, r.length), n = [];
52
+ for (const e of r)
53
+ switch (e.status) {
54
+ case l.Success:
55
+ case l.Online:
56
+ case l.Offline:
57
+ break;
58
+ default:
59
+ e.status = l.Pending, n.push(e);
60
+ break;
61
+ }
62
+ const f = [];
63
+ this.abortController = new AbortController();
64
+ try {
65
+ for (; f.length < c && n.length > 0; ) {
66
+ const e = n.shift();
67
+ if (!e) break;
68
+ f.push(this.handleFileStatus(e, f, n, o));
69
+ }
70
+ await Promise.all(f), u == null || u(r);
71
+ } catch (e) {
72
+ console.error("上传失败:", e), r.forEach((p) => {
73
+ p.status = l.Error, p.error = e instanceof Error ? e : new Error("上传失败"), o == null || o(p);
74
+ }), u == null || u(r);
75
+ }
76
+ }
77
+ /**
78
+ * 处理单个文件的上传逻辑
79
+ * @param file 当前上传的文件
80
+ * @param activeUploads 当前正在上传的文件列表
81
+ * @param pendingFiles 等待上传的文件列表
82
+ * @param onProgress 上传进度回调
83
+ */
84
+ async handleFileStatus(r, o, u, c) {
85
+ try {
86
+ r.status = l.Uploading, await this.uploadFile(r, this.abortController.signal, (n) => {
87
+ r.percent = n, c == null || c(r);
88
+ }), r.status = l.Success;
89
+ } catch (n) {
90
+ r.status = l.Error, r.error = n instanceof Error ? n : new Error("上传失败"), console.error(r.error);
91
+ } finally {
92
+ if (u.length > 0) {
93
+ const n = u.shift();
94
+ n && o.push(this.handleFileStatus(n, o, u, c));
95
+ }
96
+ }
97
+ }
98
+ /**
99
+ * 使用 XMLHttpRequest 上传文件
100
+ * @param file 文件对象
101
+ * @param signal 中断信号
102
+ * @param onProgress 上传进度回调
103
+ */
104
+ async uploadFile(r, o, u) {
105
+ return new Promise((c, n) => {
106
+ const f = new FormData();
107
+ if (f.append("file", r.originFileObj), r.params)
108
+ for (const a in r.params)
109
+ f.append(a, r.params[a]);
110
+ const e = new XMLHttpRequest(), p = E(this.urlInfo);
111
+ if (p === !1) return Promise.resolve(null);
112
+ if (e.open("POST", p, !0), this.urlInfo.header && typeof this.urlInfo.header == "object" && Object.entries(this.urlInfo.header).forEach(([a, i]) => {
113
+ e.setRequestHeader(a, i);
114
+ }), this.urlInfo.authorize) {
115
+ const a = w();
116
+ if (!a) {
117
+ n(new Error("未授权或授权过期"));
118
+ return;
119
+ }
120
+ e.setRequestHeader("Authorization", "Bearer " + a);
121
+ }
122
+ e.upload.addEventListener("progress", (a) => {
123
+ if (a.lengthComputable && a.total > 0) {
124
+ const i = Math.round(a.loaded / a.total * 100);
125
+ u(i);
126
+ }
127
+ }), e.addEventListener("load", () => {
128
+ if (e.status >= 200 && e.status < 300) {
129
+ const a = e.getResponseHeader("Content-Type");
130
+ if (!a || !a.includes("application/json")) {
131
+ n(new Error("返回的结果不是 JSON 格式"));
132
+ return;
133
+ }
134
+ try {
135
+ const i = JSON.parse(e.response);
136
+ if (i.status === "success")
137
+ i.data && (r.minioFile = {
138
+ ETag: i.data.ETag,
139
+ Bucket: i.data.Bucket,
140
+ Key: i.data.Key,
141
+ Size: i.data.Size,
142
+ UpdateTime: b().format("YYYY-MM-DD HH:mm:ss"),
143
+ Status: l.Online
144
+ }), c(r);
145
+ else {
146
+ const g = i.msg;
147
+ n(new Error(g));
148
+ }
149
+ } catch (i) {
150
+ n(new Error("无法解析返回的 JSON 数据: " + i));
151
+ }
152
+ } else
153
+ n(new Error(`上传失败,状态码:${e.status}`));
154
+ }), e.addEventListener("error", () => {
155
+ n(new Error("上传失败,网络异常"));
156
+ }), e.send(f), o.addEventListener("abort", () => {
157
+ e.abort(), n(new Error("上传已取消"));
158
+ });
159
+ });
160
+ }
161
+ /**
162
+ * 取消当前所有的上传任务
163
+ */
164
+ cancelUpload() {
165
+ this.abortController && this.abortController.abort();
166
+ }
167
+ }
168
+ export {
169
+ D as A,
170
+ l as U,
171
+ H as a,
172
+ U as b,
173
+ w as c,
174
+ L as d,
175
+ F as g,
176
+ z as m,
177
+ M as p,
178
+ x as u
179
+ };
@@ -0,0 +1,211 @@
1
+ import k from "async-validator";
2
+ import { httpPost as J, ResStatus as b } from "@skyfox2000/fapi";
3
+ import { A as C, ac as N } from "./hostInfo-DK8lknRe.js";
4
+ import w from "vue-m-message";
5
+ const E = async (v) => {
6
+ const f = await import("exceljs"), m = new f.Workbook();
7
+ await m.xlsx.load(v);
8
+ const u = m.worksheets[0];
9
+ if (!u)
10
+ return w.error("Excel文件不包含工作表"), null;
11
+ const s = [], h = [];
12
+ return u.getRow(1).eachCell((t) => {
13
+ let a = "";
14
+ if (t.value !== null && t.value !== void 0)
15
+ if (typeof t.value == "object")
16
+ if ("richText" in t.value && Array.isArray(t.value.richText))
17
+ a = t.value.richText.map((r) => r.text || "").join("");
18
+ else if ("text" in t.value && typeof t.value.text == "string")
19
+ a = t.value.text;
20
+ else if (t.value instanceof Date)
21
+ a = t.value.toLocaleDateString();
22
+ else
23
+ try {
24
+ a = JSON.stringify(t.value);
25
+ } catch {
26
+ a = String(t.value);
27
+ }
28
+ else
29
+ a = String(t.value);
30
+ s.push(a);
31
+ }), u.eachRow((t, a) => {
32
+ if (a > 1) {
33
+ const r = {};
34
+ s.forEach((i, n) => {
35
+ if (i) {
36
+ const o = t.getCell(n + 1).value;
37
+ o != null ? typeof o == "object" ? "richText" in o && Array.isArray(o.richText) ? r[i] = o.richText.map((x) => x.text || "").join("") : "text" in o && typeof o.text == "string" ? r[i] = o.text : (o instanceof Date, r[i] = o) : r[i] = o : r[i] = null;
38
+ }
39
+ }), h.push(r);
40
+ }
41
+ }), { workbook: m, worksheet: u, headers: s, excelData: h };
42
+ }, S = async (v, f) => {
43
+ const m = await import("exceljs"), u = await E(v);
44
+ if (!u) return { hasError: !0 };
45
+ const { worksheet: s, headers: h } = u, { markCells: t, markHeaders: a } = f;
46
+ if (t.length === 0 && (!a || a.length === 0))
47
+ return { hasError: !1 };
48
+ const r = [...h];
49
+ a && a.length > 0 && a.forEach((l) => {
50
+ r.includes(l) || r.push(l);
51
+ });
52
+ const i = new m.Workbook(), n = i.addWorksheet("Sheet1"), p = 15, o = /* @__PURE__ */ new Map();
53
+ t.forEach(({ row: l, col: g, color: c }) => {
54
+ const y = `${l}-${g}`;
55
+ o.set(y, c || "FFFF0000");
56
+ });
57
+ for (let l = 0; l < r.length; l++) {
58
+ const g = n.getColumn(l + 1);
59
+ if (l < s.columnCount && l < h.length) {
60
+ const c = s.getColumn(l + 1);
61
+ c && c.width ? g.width = c.width : g.width = p;
62
+ } else
63
+ g.width = p;
64
+ }
65
+ const x = n.getRow(1);
66
+ r.forEach((l, g) => {
67
+ const c = x.getCell(g + 1);
68
+ c.value = l;
69
+ const y = g < h.length;
70
+ if (y && g < s.columnCount) {
71
+ const e = s.getRow(1).getCell(g + 1);
72
+ e.style && (c.style = JSON.parse(JSON.stringify(e.style))), e.font && (c.font = JSON.parse(JSON.stringify(e.font))), e.alignment && (c.alignment = JSON.parse(JSON.stringify(e.alignment))), e.border && (c.border = JSON.parse(JSON.stringify(e.border))), e.numFmt && (c.numFmt = e.numFmt), e.fill && (c.fill = JSON.parse(JSON.stringify(e.fill)));
73
+ }
74
+ a && a.includes(l) && !y && (c.fill = {
75
+ type: "pattern",
76
+ pattern: "solid",
77
+ fgColor: { argb: "FFFF0000" }
78
+ // 红色背景
79
+ }, c.font = {
80
+ name: "Arial",
81
+ size: 10,
82
+ bold: !0,
83
+ color: { argb: "FFFFFFFF" }
84
+ // 白色文字
85
+ });
86
+ }), x.commit(), s.eachRow((l, g) => {
87
+ if (g > 1) {
88
+ const c = n.getRow(g);
89
+ for (let y = 0; y < r.length; y++) {
90
+ const e = c.getCell(y + 1);
91
+ if (y < h.length && y < s.columnCount) {
92
+ const d = l.getCell(y + 1);
93
+ if (e.value = d.value, e.value !== null && e.value !== void 0 && typeof e.value == "object" && !("richText" in e.value) && !("formula" in e.value) && !("hyperlink" in e.value) && !(e.value instanceof Date))
94
+ try {
95
+ "text" in e.value && typeof e.value.text == "string" ? e.value = e.value.text : e.value = JSON.stringify(e.value);
96
+ } catch {
97
+ e.value = String(e.value);
98
+ }
99
+ d.style && (e.style = JSON.parse(JSON.stringify(d.style))), d.font && (e.font = JSON.parse(JSON.stringify(d.font))), d.alignment && (e.alignment = JSON.parse(JSON.stringify(d.alignment))), d.border && (e.border = JSON.parse(JSON.stringify(d.border))), d.numFmt && (e.numFmt = d.numFmt), d.fill && (e.fill = JSON.parse(JSON.stringify(d.fill)));
100
+ const F = `${g}-${y + 1}`;
101
+ o.has(F) && (e.fill = {
102
+ type: "pattern",
103
+ pattern: "solid",
104
+ fgColor: { argb: o.get(F) }
105
+ });
106
+ } else
107
+ e.value = null;
108
+ }
109
+ l.height && (c.height = l.height), l.outlineLevel && (c.outlineLevel = l.outlineLevel), c.commit();
110
+ }
111
+ });
112
+ const O = await i.xlsx.writeBuffer();
113
+ return { hasError: !0, errBlob: new Blob([O], {
114
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
115
+ }) };
116
+ }, $ = async (v, f) => {
117
+ if (!f || C(f))
118
+ return { hasError: !1 };
119
+ const m = await E(v);
120
+ if (!m) return { hasError: !0 };
121
+ const { headers: u, excelData: s } = m, h = [];
122
+ if (Object.keys(f).forEach((r) => {
123
+ u.includes(r) || h.push(r);
124
+ }), u.length === 0 || s.length === 0)
125
+ return w.error("Excel文件不包含足够的数据"), { hasError: !0 };
126
+ const t = new k({});
127
+ t.messages(N.messages()), t.define(f);
128
+ const a = await D(u, s, t);
129
+ if (a.length > 0 || h.length > 0) {
130
+ const r = a.map((i) => ({
131
+ row: i.row + 2,
132
+ // 转为Excel行号(+2是因为表头占一行,且是1-based索引)
133
+ col: i.col + 1,
134
+ // 转为Excel列号(+1是因为是1-based索引)
135
+ color: "FFFF0000"
136
+ // 红色
137
+ }));
138
+ return S(v, {
139
+ markCells: r,
140
+ markHeaders: h
141
+ });
142
+ }
143
+ return { hasError: !1 };
144
+ }, D = async (v, f, m) => {
145
+ const u = [];
146
+ for (let s = 0; s < f.length; s++) {
147
+ const h = f[s];
148
+ try {
149
+ await m.validate(h).catch(({ errors: t }) => {
150
+ const a = [];
151
+ t.forEach((r) => {
152
+ const i = v.indexOf(r.field);
153
+ i >= 0 && (a.some((p) => p.row === s && p.col === i) || a.push({
154
+ row: s,
155
+ col: i,
156
+ header: r.field,
157
+ message: r.message.replace("${label}", v[i])
158
+ }));
159
+ }), u.push(...a);
160
+ });
161
+ } catch (t) {
162
+ console.error("验证表格数据时发生错误:", t), w.error("验证表格数据时发生错误:" + t);
163
+ }
164
+ }
165
+ return u;
166
+ }, R = async (v, f, m) => {
167
+ if (!f || f.length === 0)
168
+ return { hasError: !1 };
169
+ const u = await E(v);
170
+ if (!u) return { hasError: !0 };
171
+ const { headers: s, excelData: h } = u, t = [];
172
+ if (f.forEach((n) => {
173
+ s.includes(n) || t.push(n);
174
+ }), t.length > 0)
175
+ return w.error(`表头缺少重复检测所需字段: ${t.join(", ")}`), { hasError: !0 };
176
+ const a = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set(), i = new Array();
177
+ if (h.forEach((n, p) => {
178
+ const o = f.map((x) => n[x]).join("|");
179
+ i.push(o), a.has(o) ? (r.add(p), r.add(a.get(o))) : a.set(o, p);
180
+ }), m) {
181
+ const n = await J(m, {
182
+ Data: i
183
+ });
184
+ if (n != null && n.data && n.data.forEach((p) => {
185
+ r.add(p);
186
+ }), (n == null ? void 0 : n.status) === b.ERROR)
187
+ throw new Error(n.msg);
188
+ }
189
+ if (r.size > 0) {
190
+ const n = [];
191
+ return r.forEach((p) => {
192
+ f.forEach((o) => {
193
+ const x = s.indexOf(o);
194
+ x >= 0 && n.push({
195
+ row: p + 2,
196
+ // Excel行号 = 数组索引 + 2(表头和1-based索引)
197
+ col: x + 1,
198
+ // Excel列号 = 数组索引 + 1(1-based索引)
199
+ color: "FFFF0000"
200
+ // 红色
201
+ });
202
+ });
203
+ }), S(v, { markCells: n, markHeaders: t });
204
+ }
205
+ return { hasError: !1 };
206
+ };
207
+ export {
208
+ R as c,
209
+ E as p,
210
+ $ as v
211
+ };