@infly/libs 2.0.43 → 2.0.45

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.
Files changed (67) hide show
  1. package/README.md +104 -67
  2. package/{module → adapters/vue2/module}/Permission.js +2 -2
  3. package/{module → adapters/vue2/module}/REST.js +32 -20
  4. package/{module → adapters/vue2/module}/TokenService.js +10 -1
  5. package/adapters/vue2/module/file-export.js +18 -0
  6. package/adapters/vue2/postinstall.js +46 -0
  7. package/adapters/vue2/project-preview.js +152 -0
  8. package/adapters/vue2/script-config.js +26 -0
  9. package/adapters/vue2/store/index.js +1 -0
  10. package/{store → adapters/vue2/store}/modules/user.js +1 -1
  11. package/adapters/vue2/vite/index.js +95 -0
  12. package/adapters/vue2/vite/jest.config.js +11 -0
  13. package/{build → adapters/vue2}/webpack5/webpack.base.js +26 -79
  14. package/bin/cli.js +71 -71
  15. package/build/build-dist/index.js +863 -863
  16. package/build/build-dist/script-management.js +5 -5
  17. package/{script/build → build/build-utils}/command.js +13 -4
  18. package/{script/build → build/build-utils}/deps.js +1 -1
  19. package/{script/build → build/build-utils}/git.js +6 -4
  20. package/{script/build → build/build-utils}/preview.js +4 -1
  21. package/{script/webhook/webhook.js → build/build-utils/webhook-single.js} +7 -2
  22. package/{script/build → build/build-utils}/webhook.js +3 -2
  23. package/build/docker/compose-command.js +74 -74
  24. package/build/docker/compose-release.js +91 -91
  25. package/compat/init.js +9 -0
  26. package/index.js +8 -20
  27. package/module/Uts.js +77 -7265
  28. package/module/cjs/{request-url-rules.cjs → request-url-rules.js} +6 -0
  29. package/module/cjs/rest-error-rules.js +33 -0
  30. package/package.json +124 -92
  31. package/script/git-automation/git-clone.js +3 -4
  32. package/script/git-automation/git-configure.js +29 -0
  33. package/script/git-automation/index.js +0 -14
  34. package/script/git-automation/submodule-status.js +113 -0
  35. package/script/git-automation/submodule-utils.js +18 -0
  36. package/script/index.js +1 -26
  37. package/tools/auto-export.js +1 -2
  38. package/tools/concurrency.js +30 -0
  39. package/tools/progress.js +63 -0
  40. package/tools/project-command.js +198 -194
  41. package/tools/project-preview.js +1 -148
  42. package/tools/select-option.js +60 -60
  43. package/tools/workspace-config.js +145 -0
  44. package/.prettierrc +0 -5
  45. package/build/build-dist/script-management.test.js +0 -16
  46. package/build/docker/compose-command.test.js +0 -148
  47. package/build/docker/compose-release.test.js +0 -101
  48. package/build/docker/docker-build-push.test.js +0 -124
  49. package/build/webpack5/remove-legacy-assets-plugin.js +0 -84
  50. package/build/webpack5/webpack.base.test.js +0 -59
  51. package/lib/index.js +0 -6
  52. package/lib/server/connect.js +0 -3011
  53. package/lib/server/serve-static.js +0 -4848
  54. package/module/cjs/deep-merge.cjs +0 -38
  55. package/script/pts/cloud-scenes.mjs +0 -65
  56. package/script/pts/cloud.js +0 -151
  57. package/script/pts/generate-cloud-params.mjs +0 -210
  58. package/script/pts/generate-cloud-params.test.mjs +0 -67
  59. package/store/index.js +0 -0
  60. package/tools/file-export.js +0 -165
  61. package/tools/project-command.test.js +0 -267
  62. package/tools/select-option.test.js +0 -52
  63. package/webpack.config.js +0 -38
  64. /package/{module → adapters/vue2/module}/Router.js +0 -0
  65. /package/{build → adapters/vue2}/webpack5/inline-runtime-plugin.js +0 -0
  66. /package/{script/build → build/build-utils}/env.js +0 -0
  67. /package/module/cjs/{page-config.cjs → page-config.js} +0 -0
@@ -1,38 +0,0 @@
1
- /**
2
- * 深度合并对象
3
- * @param {Object} target - 目标对象
4
- * @param {Object} source - 源对象
5
- * @param {boolean} overwrite - 是否覆盖已存在的属性,默认 false
6
- * @returns {Object} 合并后的目标对象
7
- */
8
- function deepMerge(target, source, overwrite = false) {
9
- if (!source || typeof source !== "object") return target;
10
- if (!target || typeof target !== "object") return source;
11
-
12
- Object.keys(source).forEach((key) => {
13
- const sourceValue = source[key];
14
- const targetValue = target[key];
15
-
16
- if (Array.isArray(sourceValue)) {
17
- if (!overwrite && targetValue !== undefined) {
18
- return;
19
- }
20
- target[key] = [...sourceValue];
21
- } else if (sourceValue && typeof sourceValue === "object") {
22
- if (!target[key] || typeof target[key] !== "object") {
23
- target[key] = {};
24
- }
25
- deepMerge(target[key], sourceValue, overwrite);
26
- } else if (!overwrite && targetValue !== undefined) {
27
- return;
28
- } else {
29
- target[key] = sourceValue;
30
- }
31
- });
32
-
33
- return target;
34
- }
35
-
36
- module.exports = {
37
- deepMerge
38
- };
@@ -1,65 +0,0 @@
1
- export var DEFAULT_BASE_URL = "https://api.sutpay.com";
2
-
3
- export function createScenes(baseUrl) {
4
- var resolvedBaseUrl = baseUrl || DEFAULT_BASE_URL;
5
-
6
- return [
7
- {
8
- name: "coupon_alipay",
9
- generateUrl: resolvedBaseUrl + "/cpay/generate_api_coupon_request_data/",
10
- issueUrl: resolvedBaseUrl + "/voucher/coupons/issue/test",
11
- body: {
12
- activity_id: "ACT735CCV04067449",
13
- mobile: "17875733848",
14
- notify_url: resolvedBaseUrl + "/cpay/test_callback_api_issue_coupons/",
15
- user: "13688851059",
16
- login_id: "17875733848"
17
- }
18
- },
19
- {
20
- name: "coupon_wx",
21
- generateUrl: resolvedBaseUrl + "/cpay/generate_api_coupon_request_data/",
22
- issueUrl: resolvedBaseUrl + "/voucher/coupons/issue/test",
23
- body: {
24
- activity_id: "21978842",
25
- mobile: "17875733848",
26
- notify_url: resolvedBaseUrl + "/cpay/test_callback_api_issue_coupons/",
27
- user: "13688851059",
28
- appid: "wxf68630951d36fd07",
29
- openid: "oxSpZ5WBf_Qx5KN6AYXBgzwVf8mg"
30
- }
31
- },
32
- {
33
- name: "cash_alipay",
34
- generateUrl: resolvedBaseUrl + "/cpay/generate_api_cash_request_data/",
35
- issueUrl: resolvedBaseUrl + "/cpay/funds/transfer/test",
36
- body: {
37
- user: "13688851059",
38
- mobile: "17875733848",
39
- activity_id: "SUT00002382",
40
- pay_type: "alipay",
41
- amount: "1",
42
- desc: "企业付款-开发调试支付宝",
43
- notify_url: resolvedBaseUrl + "/cpay/test_callback_api_transfers/",
44
- login_id: "1108@qq.com",
45
- realname: "曾某某"
46
- }
47
- },
48
- {
49
- name: "cash_wx",
50
- generateUrl: resolvedBaseUrl + "/cpay/generate_api_cash_request_data/",
51
- issueUrl: resolvedBaseUrl + "/cpay/funds/transfer/test",
52
- body: {
53
- user: "13688851059",
54
- mobile: "17875733848",
55
- activity_id: "SUT00002382",
56
- notify_url: resolvedBaseUrl + "/cpay/test_callback_api_transfers/",
57
- appid: "wxf68630951d36fd07",
58
- openid: "oxSpZ5WBf_Qx5KN6AYXBgzwVf8mg",
59
- amount: "1",
60
- pay_type: "wx",
61
- desc: "企业付款-开发调试微信"
62
- }
63
- }
64
- ];
65
- }
@@ -1,151 +0,0 @@
1
- import http from "pts/http";
2
- import { check } from "pts";
3
-
4
- var PAYLOAD_FILE = "cloud-payloads.generated.json";
5
- var CLOUD_PAYLOADS = JSON.parse(readTextFile(PAYLOAD_FILE));
6
-
7
- var payloadIndex = 0;
8
-
9
- function readTextFile(fileName) {
10
- var content = open(fileName);
11
-
12
- if (typeof content === "string") {
13
- return content;
14
- }
15
-
16
- var bytes = new Uint8Array(content);
17
- var chunks = [];
18
- var chunkSize = 8192;
19
-
20
- for (var i = 0; i < bytes.length; i += chunkSize) {
21
- var chunk = bytes.subarray(i, i + chunkSize);
22
- chunks.push(String.fromCharCode.apply(null, chunk));
23
- }
24
-
25
- return chunks.join("");
26
- }
27
-
28
- function getHttpStatus(resp) {
29
- if (resp.statusCode !== undefined && resp.statusCode !== null) {
30
- return Number(resp.statusCode);
31
- }
32
-
33
- return Number(resp.status);
34
- }
35
-
36
- function isHttp200(resp) {
37
- return getHttpStatus(resp) === 200;
38
- }
39
-
40
- function safeJson(resp) {
41
- try {
42
- return resp.json();
43
- } catch (e) {
44
- return null;
45
- }
46
- }
47
-
48
- function getBusinessCode(json) {
49
- if (!json) return undefined;
50
-
51
- if (json.code !== undefined && json.code !== null) {
52
- return Number(json.code);
53
- }
54
-
55
- if (json.meta && json.meta.code !== undefined && json.meta.code !== null) {
56
- return Number(json.meta.code);
57
- }
58
-
59
- if (json.data && json.data.code !== undefined && json.data.code !== null) {
60
- return Number(json.data.code);
61
- }
62
-
63
- return undefined;
64
- }
65
-
66
- function isBusinessSuccess(json) {
67
- var code = getBusinessCode(json);
68
- return code === 0 || code === 200;
69
- }
70
-
71
- function getBusinessMessage(json) {
72
- if (!json) return "";
73
-
74
- if (json.message !== undefined && json.message !== null) {
75
- return String(json.message);
76
- }
77
-
78
- if (json.msg !== undefined && json.msg !== null) {
79
- return String(json.msg);
80
- }
81
-
82
- if (json.error !== undefined && json.error !== null) {
83
- return String(json.error);
84
- }
85
-
86
- if (json.meta && json.meta.message !== undefined && json.meta.message !== null) {
87
- return String(json.meta.message);
88
- }
89
-
90
- return "";
91
- }
92
-
93
- // ── 使用本地预生成的签名参数调用统一派发接口 ────────────────────────────────
94
-
95
- function runPayload(payload) {
96
- payload = payload || { index: 0, sceneName: "", issueUrl: "", signedPayload: {} };
97
-
98
- var headers = { "Content-Type": "application/json" };
99
- var sceneName = payload.sceneName || "unknown";
100
- var signedPayload = payload.signedPayload || {};
101
-
102
- // Step 2:用签名参数调用统一派发接口
103
- var t0 = Date.now();
104
- var issueResp = http.post(payload.issueUrl, signedPayload, { headers: headers });
105
- var duration = Date.now() - t0;
106
- var issueJson = safeJson(issueResp);
107
-
108
- check("[" + sceneName + "] issue: http status 200", function () {
109
- return isHttp200(issueResp);
110
- }, issueResp);
111
-
112
- check("[" + sceneName + "] issue: has result", function () {
113
- return !!issueJson;
114
- }, issueResp);
115
-
116
- check("[" + sceneName + "] issue: biz code 0 or 200", function () {
117
- return isBusinessSuccess(issueJson);
118
- }, issueResp);
119
-
120
- console.log("[" + sceneName + "#" + payload.index + "] issue_resp:", JSON.stringify(issueJson));
121
- if (!isBusinessSuccess(issueJson)) {
122
- console.error(
123
- "[" + sceneName + "#" + payload.index + "] issue_failed:",
124
- "status=" + getHttpStatus(issueResp),
125
- "code=" + getBusinessCode(issueJson),
126
- "message=" + getBusinessMessage(issueJson),
127
- "out_biz_no=" + (signedPayload.out_biz_no || "")
128
- );
129
- }
130
- console.log("[" + sceneName + "#" + payload.index + "] issue_duration_ms:", duration);
131
- }
132
-
133
- // ── 主压测逻辑:每次迭代取一条本地预生成参数并派发 ──────────────────────────
134
-
135
- export default function () {
136
- check("[payloads] has local generated data", function () {
137
- return CLOUD_PAYLOADS.length > 0;
138
- });
139
-
140
- if (CLOUD_PAYLOADS.length === 0) {
141
- console.error("No payloads found. Generate and upload request file: " + PAYLOAD_FILE);
142
- return;
143
- }
144
-
145
- var randomOffset = Math.floor(Math.random() * CLOUD_PAYLOADS.length);
146
- var payloadArrayIndex = (payloadIndex + randomOffset) % CLOUD_PAYLOADS.length;
147
- var payload = CLOUD_PAYLOADS[payloadArrayIndex];
148
- payloadIndex++;
149
-
150
- runPayload(payload);
151
- }
@@ -1,210 +0,0 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- import { createScenes, DEFAULT_BASE_URL } from "./cloud-scenes.mjs";
6
-
7
- var DEFAULT_JSON_OUT = "cloud-payloads.generated.json";
8
- var DEFAULT_COUNT = 3000;
9
- var DEFAULT_CONCURRENCY = 10;
10
- var SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
11
-
12
- export function parseArgs(argv) {
13
- var args = {
14
- count: DEFAULT_COUNT,
15
- concurrency: DEFAULT_CONCURRENCY,
16
- baseUrl: process.env.CLOUD_BASE_URL || DEFAULT_BASE_URL,
17
- jsonOut: DEFAULT_JSON_OUT,
18
- scene: ""
19
- };
20
-
21
- for (var i = 0; i < argv.length; i++) {
22
- var key = argv[i];
23
- var value = argv[i + 1];
24
-
25
- if (key === "--count") {
26
- args.count = parsePositiveInt(value, "--count");
27
- i++;
28
- } else if (key === "--concurrency") {
29
- args.concurrency = parsePositiveInt(value, "--concurrency");
30
- i++;
31
- } else if (key === "--base-url") {
32
- args.baseUrl = requireValue(value, "--base-url");
33
- i++;
34
- } else if (key === "--json-out") {
35
- args.jsonOut = requireValue(value, "--json-out");
36
- i++;
37
- } else if (key === "--scene") {
38
- args.scene = requireValue(value, "--scene");
39
- i++;
40
- } else if (key === "--help" || key === "-h") {
41
- args.help = true;
42
- } else {
43
- throw new Error("Unknown argument: " + key);
44
- }
45
- }
46
-
47
- return args;
48
- }
49
-
50
- export function buildGenerateJobs(scenes, count) {
51
- var jobs = [];
52
-
53
- for (var i = 0; i < count; i++) {
54
- jobs.push({
55
- index: i,
56
- scene: scenes[i % scenes.length]
57
- });
58
- }
59
-
60
- return jobs;
61
- }
62
-
63
- export function createPayloadJsonSource(payloads) {
64
- return JSON.stringify(payloads, null, 2) + "\n";
65
- }
66
-
67
- async function main() {
68
- var args = parseArgs(process.argv.slice(2));
69
-
70
- if (args.help) {
71
- printHelp();
72
- return;
73
- }
74
-
75
- var scenes = createScenes(args.baseUrl);
76
- if (args.scene) {
77
- scenes = scenes.filter(function (scene) {
78
- return scene.name === args.scene;
79
- });
80
- }
81
-
82
- if (scenes.length === 0) {
83
- throw new Error("No scene matched: " + args.scene);
84
- }
85
-
86
- var jobs = buildGenerateJobs(scenes, args.count);
87
- var payloads = await runPool(jobs, args.concurrency, generatePayload);
88
- var jsonOutPath = resolveOutputPath(args.jsonOut);
89
-
90
- await mkdir(path.dirname(jsonOutPath), { recursive: true });
91
- await writeFile(jsonOutPath, createPayloadJsonSource(payloads), "utf8");
92
-
93
- console.log("Generated request-file JSON -> " + jsonOutPath);
94
- }
95
-
96
- async function generatePayload(job) {
97
- var scene = job.scene;
98
- var resp = await fetch(scene.generateUrl, {
99
- method: "POST",
100
- headers: { "Content-Type": "application/json" },
101
- body: JSON.stringify(scene.body)
102
- });
103
- var text = await resp.text();
104
- var json = parseJson(text);
105
-
106
- if (!resp.ok || !json || !json.data || !isBusinessSuccess(json)) {
107
- throw new Error(
108
- "[" + scene.name + "#" + job.index + "] generate failed: http_status=" +
109
- resp.status +
110
- ", body=" +
111
- text
112
- );
113
- }
114
-
115
- return {
116
- index: job.index,
117
- sceneName: scene.name,
118
- issueUrl: scene.issueUrl,
119
- signedPayload: json.data
120
- };
121
- }
122
-
123
- async function runPool(items, concurrency, worker) {
124
- var results = new Array(items.length);
125
- var nextIndex = 0;
126
- var workerCount = Math.min(concurrency, items.length);
127
- var runners = [];
128
-
129
- for (var i = 0; i < workerCount; i++) {
130
- runners.push(
131
- (async function () {
132
- while (nextIndex < items.length) {
133
- var currentIndex = nextIndex;
134
- nextIndex++;
135
- results[currentIndex] = await worker(items[currentIndex]);
136
-
137
- if ((currentIndex + 1) % 100 === 0 || currentIndex + 1 === items.length) {
138
- console.log("Generated " + (currentIndex + 1) + "/" + items.length);
139
- }
140
- }
141
- })()
142
- );
143
- }
144
-
145
- await Promise.all(runners);
146
- return results;
147
- }
148
-
149
- function parseJson(text) {
150
- try {
151
- return JSON.parse(text);
152
- } catch (error) {
153
- return null;
154
- }
155
- }
156
-
157
- function getBusinessCode(json) {
158
- if (!json) return undefined;
159
- if (json.code !== undefined && json.code !== null) return Number(json.code);
160
- if (json.meta && json.meta.code !== undefined && json.meta.code !== null) return Number(json.meta.code);
161
- if (json.data && json.data.code !== undefined && json.data.code !== null) return Number(json.data.code);
162
- return undefined;
163
- }
164
-
165
- function isBusinessSuccess(json) {
166
- var code = getBusinessCode(json);
167
- return code === 0 || code === 200;
168
- }
169
-
170
- function parsePositiveInt(value, flag) {
171
- var parsed = Number(requireValue(value, flag));
172
- if (!Number.isInteger(parsed) || parsed <= 0) {
173
- throw new Error(flag + " must be a positive integer");
174
- }
175
- return parsed;
176
- }
177
-
178
- function requireValue(value, flag) {
179
- if (!value || value.indexOf("--") === 0) {
180
- throw new Error(flag + " requires a value");
181
- }
182
- return value;
183
- }
184
-
185
- function resolveOutputPath(value) {
186
- if (path.isAbsolute(value)) {
187
- return value;
188
- }
189
- return path.resolve(SCRIPT_DIR, value);
190
- }
191
-
192
- function printHelp() {
193
- console.log([
194
- "Usage: node packages/infly-libs/script/pts/generate-cloud-params.mjs [options]",
195
- "",
196
- "Options:",
197
- " --count <n> Number of signed payloads to generate. Default: 3000",
198
- " --concurrency <n> Concurrent generate API requests. Default: 10",
199
- " --base-url <url> API base URL. Default: CLOUD_BASE_URL or " + DEFAULT_BASE_URL,
200
- " --json-out <file> Output PTS request-file JSON in this folder. Default: " + DEFAULT_JSON_OUT,
201
- " --scene <name> Generate only one scene, e.g. coupon_alipay"
202
- ].join("\n"));
203
- }
204
-
205
- if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
206
- main().catch(function (error) {
207
- console.error(error.message || error);
208
- process.exitCode = 1;
209
- });
210
- }
@@ -1,67 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
-
4
- import {
5
- buildGenerateJobs,
6
- createPayloadJsonSource,
7
- parseArgs
8
- } from "./generate-cloud-params.mjs";
9
-
10
- const scenes = [
11
- { name: "coupon_alipay", generateUrl: "https://example.test/gen1", issueUrl: "https://example.test/issue1", body: { a: 1 } },
12
- { name: "coupon_wx", generateUrl: "https://example.test/gen2", issueUrl: "https://example.test/issue2", body: { b: 2 } }
13
- ];
14
-
15
- test("buildGenerateJobs creates the requested count and cycles scenes", () => {
16
- const jobs = buildGenerateJobs(scenes, 5);
17
-
18
- assert.deepEqual(jobs.map((job) => job.scene.name), [
19
- "coupon_alipay",
20
- "coupon_wx",
21
- "coupon_alipay",
22
- "coupon_wx",
23
- "coupon_alipay"
24
- ]);
25
- assert.deepEqual(jobs.map((job) => job.index), [0, 1, 2, 3, 4]);
26
- });
27
-
28
- test("parseArgs keeps defaults and accepts common overrides", () => {
29
- const args = parseArgs([
30
- "--count",
31
- "3000",
32
- "--concurrency",
33
- "20",
34
- "--base-url",
35
- "https://local.test",
36
- "--json-out",
37
- "tmp/generated.json",
38
- "--scene",
39
- "coupon_wx"
40
- ]);
41
-
42
- assert.equal(args.count, 3000);
43
- assert.equal(args.concurrency, 20);
44
- assert.equal(args.baseUrl, "https://local.test");
45
- assert.equal(args.jsonOut, "tmp/generated.json");
46
- assert.equal(args.scene, "coupon_wx");
47
- });
48
-
49
- test("createPayloadJsonSource writes request-file JSON data", () => {
50
- const source = createPayloadJsonSource([
51
- {
52
- index: 0,
53
- sceneName: "coupon_alipay",
54
- issueUrl: "https://example.test/issue",
55
- signedPayload: { sign: "abc" }
56
- }
57
- ]);
58
-
59
- assert.deepEqual(JSON.parse(source), [
60
- {
61
- index: 0,
62
- sceneName: "coupon_alipay",
63
- issueUrl: "https://example.test/issue",
64
- signedPayload: { sign: "abc" }
65
- }
66
- ]);
67
- });
package/store/index.js DELETED
File without changes
@@ -1,165 +0,0 @@
1
- /**
2
- * 统一文件导出函数
3
- * @param {Object} config - 配置对象
4
- * @param {string} config.url - 请求文件的 URL
5
- * @param {string} config.fileName - 导出文件的基础名称
6
- * @param {Object} [config.params={}] - 请求参数
7
- * @param {string} [config.suffix=".csv"] - 文件后缀名
8
- * @param {Object} config.request - 请求封装实例 (如 axios 实例)
9
- * @param {string} [config.reqMethod="get"] - 请求方法 ('get' 或 'post')
10
- * @param {Object} [config.Message={}] - Element UI Message 组件实例
11
- * @param {Object} [config.MessageBox={}] - Element UI MessageBox 组件实例
12
- * @param {Object} [config.Loading={}] - Element UI Loading 组件实例
13
- */
14
- async function exportFile(config) {
15
- // 1. 参数解构与默认值,并进行基本校验
16
- const {
17
- url,
18
- fileName,
19
- params = {},
20
- suffix = ".csv",
21
- request,
22
- reqMethod = "get",
23
- Message = {},
24
- MessageBox = {},
25
- Loading = {},
26
- hideConfirm = false,
27
- confirmConfig = { message: "导出筛选后的所有文件, 是否继续?" }
28
- } = config || {};
29
-
30
- if (!url || !request) {
31
- console.error("exportFile: 缺少必要的参数 (url, fileName, request)");
32
- return;
33
- }
34
-
35
- let loadingInstance = null;
36
-
37
- // 辅助函数:显示消息
38
- const showMessage = (type, msg) => {
39
- if (Message && Uts.isFunction(Message[type])) {
40
- Message[type](msg);
41
- }
42
- };
43
-
44
- // 辅助函数:显示加载
45
- const showLoading = () => {
46
- if (Loading && Uts.isFunction(Loading.service)) {
47
- loadingInstance = Loading.service({
48
- text: "文件正在下载中,请等候...",
49
- spinner: "el-icon-loading",
50
- background: "rgba(0, 0, 0, 0.7)"
51
- });
52
- }
53
- };
54
-
55
- // 辅助函数:隐藏加载
56
- const hideLoading = () => {
57
- if (loadingInstance && Uts.isFunction(loadingInstance.close)) {
58
- loadingInstance.close();
59
- }
60
- };
61
-
62
- // 辅助函数:处理文件下载
63
- const handleDownload = (blob, fullFileName) => {
64
- if ("download" in document.createElement("a")) {
65
- const elink = document.createElement("a");
66
- elink.style.display = "none";
67
- elink.href = URL.createObjectURL(blob);
68
- elink.download = fullFileName;
69
- document.body.appendChild(elink);
70
- elink.click();
71
- URL.revokeObjectURL(elink.href);
72
- document.body.removeChild(elink);
73
- } else {
74
- // IE10+下载
75
- navigator.msSaveBlob(blob, fullFileName);
76
- }
77
- };
78
-
79
- try {
80
- // 2. 确认框
81
- if (MessageBox && Uts.isFunction(MessageBox.confirm) && !hideConfirm) {
82
- await MessageBox.confirm(confirmConfig?.message, "提示", {
83
- confirmButtonText: "确定",
84
- cancelButtonText: "取消",
85
- type: "warning"
86
- });
87
- }
88
-
89
- showLoading(); // 显示加载
90
-
91
- try {
92
- // 3. 请求文件流
93
- const requestConfig = {
94
- responseType: "arraybuffer",
95
- timeout: 0
96
- };
97
-
98
- let res;
99
- if (reqMethod === "get") {
100
- res = await request.get(url, { ...params, ...requestConfig });
101
- } else if (reqMethod === "post") {
102
- res = await request.post(url, params, requestConfig);
103
- } else {
104
- console.warn(`exportFile: 不支持的请求方法 '${reqMethod}'`);
105
- showMessage("error", "导出失败:不支持的请求方法!");
106
- return;
107
- }
108
- const { code, message } = res || {};
109
- if (code && (code != 0 || code != 200)) {
110
- showMessage("error", message || "导出失败!");
111
- return;
112
- }
113
-
114
- const blob = new Blob([res], { type: "application/octet-stream" });
115
- const fullFileName = `${fileName}_${new Date().toISOString().slice(0, 10)}${suffix}`;
116
-
117
- handleDownload(blob, fullFileName); // 处理文件下载
118
- showMessage("success", "文件导出成功!");
119
- } catch (err) {
120
- console.error("导出错误:", err);
121
- const { response, message: errMsg } = err || {};
122
- const { status, statusText, message = errMsg } = response || {};
123
-
124
- if (status === 403 || statusText === "Forbidden") {
125
- showMessage("error", "无操作权限!");
126
- } else if (status === 404) {
127
- showMessage("error", "导出地址未找到!");
128
- } else if (message && message.includes("timeout")) {
129
- showMessage("error", "导出超时,请稍后再试!");
130
- } else {
131
- showMessage("error", message || "导出异常,请稍后再试!");
132
- }
133
- } finally {
134
- hideLoading(); // 隐藏加载
135
- }
136
- } catch (err) {
137
- // 捕获 MessageBox.confirm 的取消操作
138
- if (err === "cancel") {
139
- showMessage("info", "已取消导出");
140
- } else {
141
- console.error("导出流程中断:", err);
142
- showMessage("error", "导出流程异常中断!");
143
- }
144
- }
145
- }
146
-
147
- // 创建 Vue mixin 对象
148
- const fileExportMixin = {
149
- methods: {
150
- async $exportFile(config) {
151
- // 自动注入 ElementUI 组件
152
- const enhancedConfig = {
153
- ...config,
154
- Message: this.$message || Message,
155
- MessageBox: this.$msgbox || MessageBox,
156
- Loading: this.$loading || Loading,
157
- request: config.request || this.$axios
158
- };
159
-
160
- return await exportFile(enhancedConfig);
161
- }
162
- }
163
- };
164
-
165
- export { exportFile, fileExportMixin };