ol-base-components 2.8.12 → 2.8.13

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.
@@ -0,0 +1,154 @@
1
+ // open-close-loop.js
2
+ // 循环“打开→停留→关闭→间隔”的浏览器控制脚本(Windows)
3
+ // 优先使用指定的 Chrome 路径独立进程(只关闭本次打开窗口);否则使用默认浏览器并通过进程名强关(会关闭该浏览器所有窗口)。
4
+
5
+ const { spawn, exec, execSync } = require("child_process");
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const os = require("os");
9
+
10
+ const COUNT = 0; // 循环次数;0 表示无限循环
11
+ const MODE = process.env.MODE || "headless"; // headless|minimized|default
12
+ // 支持多页面:同一轮“同时打开,同时关闭”
13
+ const URLS = ["https://juejin.cn/post/7496406694357516303"];
14
+ const OPEN_MS = 3000; // 打开停留时间
15
+ const CLOSE_MS = 1000; // 关闭后间隔
16
+ const BROWSER_PROC = "chrome.exe"; // 默认浏览器进程名(默认浏览器模式会强关所有该进程窗口)
17
+ const CHROME_PATH = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
18
+
19
+ const sleep = ms => new Promise(r => setTimeout(r, ms));
20
+
21
+ const isWin = process.platform === "win32";
22
+ if (!isWin) {
23
+ console.error("当前脚本仅适配 Windows。");
24
+ process.exit(1);
25
+ }
26
+
27
+ // 判断文件是否存在
28
+ function fileExists(file) {
29
+ try {
30
+ fs.accessSync(file, fs.constants.X_OK | fs.constants.F_OK);
31
+ return true;
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
36
+
37
+ // 创建临时profile,避免复用已开 Chrome 实例
38
+ function makeTempProfile() {
39
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "chrome-prof-"));
40
+ return dir;
41
+ }
42
+
43
+ // 优雅关闭与清理(单实例变量)
44
+ let currentProc = null;
45
+ let currentProfile = null;
46
+
47
+ async function cleanup() {
48
+ try {
49
+ if (currentProc && !currentProc.killed) {
50
+ try {
51
+ currentProc.kill();
52
+ } catch {}
53
+ try {
54
+ execSync(`taskkill /PID ${currentProc.pid} /T /F`, { stdio: "ignore" });
55
+ } catch {}
56
+ }
57
+ } catch {}
58
+ currentProc = null;
59
+
60
+ if (currentProfile) {
61
+ try {
62
+ fs.rmSync(currentProfile, { recursive: true, force: true });
63
+ } catch {}
64
+ currentProfile = null;
65
+ }
66
+ }
67
+
68
+ process.on("SIGINT", async () => {
69
+ await cleanup();
70
+ process.exit(0);
71
+ });
72
+ process.on("SIGTERM", async () => {
73
+ await cleanup();
74
+ process.exit(0);
75
+ });
76
+
77
+ // Chrome 独立进程:同一轮“并发打开→停留→并发关闭并清理”
78
+ async function openWithChromeLoop() {
79
+ const loops = COUNT > 0 ? COUNT : Infinity;
80
+ for (let i = 0; i < loops; i++) {
81
+ const procs = [];
82
+ const profiles = [];
83
+
84
+ for (const url of URLS) {
85
+ const prof = makeTempProfile();
86
+ profiles.push(prof);
87
+ const args = [
88
+ "--new-window",
89
+ `--user-data-dir=${prof}`,
90
+ "--no-first-run",
91
+ "--no-default-browser-check",
92
+ ...(MODE === "headless" ? ["--headless=new", "--disable-gpu", "--hide-scrollbars"] : []),
93
+ ...(MODE === "minimized" ? ["--start-minimized", "--window-size=1,1"] : []),
94
+ url,
95
+ ];
96
+ const p = spawn(CHROME_PATH, args, { stdio: "ignore" });
97
+ procs.push(p);
98
+ }
99
+
100
+ await sleep(OPEN_MS);
101
+
102
+ // 并发关闭刚打开的所有 Chrome 进程
103
+ for (const p of procs) {
104
+ try {
105
+ p.kill();
106
+ } catch {}
107
+ try {
108
+ execSync(`taskkill /PID ${p.pid} /T /F`, { stdio: "ignore" });
109
+ } catch {}
110
+ }
111
+ // 清理对应临时 profile
112
+ for (const prof of profiles) {
113
+ try {
114
+ fs.rmSync(prof, { recursive: true, force: true });
115
+ } catch {}
116
+ }
117
+
118
+ await sleep(CLOSE_MS);
119
+ }
120
+ await cleanup();
121
+ process.exit(0);
122
+ }
123
+
124
+ // 默认浏览器:同一轮“并发打开→停留→一次性强关该进程所有窗口”
125
+ async function openWithDefaultBrowserLoop() {
126
+ const loops = COUNT > 0 ? COUNT : Infinity;
127
+ for (let i = 0; i < loops; i++) {
128
+ for (const url of URLS) {
129
+ const startArgs =
130
+ MODE === "minimized" ? ["/c", "start", "/min", "", url] : ["/c", "start", "", url];
131
+ spawn("cmd", startArgs, { detached: true, stdio: "ignore" }).unref();
132
+ }
133
+
134
+ await sleep(OPEN_MS);
135
+
136
+ // 一次性结束该浏览器所有窗口(注意:这会关闭同类浏览器的所有窗口)
137
+ exec(`taskkill /IM ${BROWSER_PROC} /F`, () => {});
138
+ await sleep(CLOSE_MS);
139
+ }
140
+ await cleanup();
141
+ process.exit(0);
142
+ }
143
+
144
+ (async function main() {
145
+ const useChrome = fileExists(CHROME_PATH);
146
+ if (useChrome) {
147
+ await openWithChromeLoop();
148
+ } else {
149
+ console.warn(
150
+ `未找到 Chrome:${CHROME_PATH},将使用默认浏览器并通过进程名(${BROWSER_PROC})强制关闭。`
151
+ );
152
+ await openWithDefaultBrowserLoop();
153
+ }
154
+ })();
@@ -0,0 +1,29 @@
1
+ // 驼峰命名法转中文
2
+ export const camelCaseToChinese = async camelCase => {
3
+ if (!camelCase) {
4
+ return "创建时间";
5
+ }
6
+
7
+ // 将驼峰命名法转换为单词数组
8
+ const words = camelCase
9
+ .replace(/([A-Z])/g, " $1")
10
+ .trim()
11
+ .split(" ");
12
+ // 将每个单词翻译为中文
13
+ const chineseWords = await Promise.all(words.map(word => translateWord(word.toLowerCase())));
14
+ return chineseWords.join("");
15
+ };
16
+
17
+ // 翻译单词
18
+ const translateWord = async word => {
19
+ try {
20
+ const response = await fetch(
21
+ `https://api.mymemory.translated.net/get?q=${encodeURIComponent(word)}&langpair=en|zh`
22
+ );
23
+ const data = await response.json();
24
+ return data.responseData.translatedText;
25
+ } catch (error) {
26
+ console.warn(`翻译失败: ${word}`, error);
27
+ return word.charAt(0).toUpperCase() + word.slice(1);
28
+ }
29
+ };
@@ -177,6 +177,7 @@
177
177
  <script>
178
178
  import { getData } from "../../index.js";
179
179
  import { getEnum } from "../../../utils/getEnum.js";
180
+ import { camelCaseToChinese } from "./index.js";
180
181
 
181
182
  export default {
182
183
  name: "search",
@@ -340,17 +341,55 @@ export default {
340
341
  }
341
342
  });
342
343
 
344
+ // 自动识别范围时间字段,以Begin和End结尾的字段,和"BeginTime", "EndTime",这样的时间范围字段
345
+ const rangeTimeCloumns = await this.autoDetectRangeTimeFields(swaggersearchColumns);
346
+ this.formSearchData.tableSearch = [...this.formSearchData.tableSearch, ...rangeTimeCloumns];
347
+
348
+ // const tableHasCreatedTime = this.formSearchData.tableSearch.some(
349
+ // e => e.value === "createdTime"
350
+ // );
351
+ // if (!tableHasCreatedTime) {
352
+ // // 单独处理创建时间 就是BeginTime,EndTime
353
+ // const requiredNames = ["BeginTime", "EndTime"];
354
+ // const hseCreatedTime = requiredNames.every(name =>
355
+ // swaggersearchColumns.some(item => item.name === name)
356
+ // );
357
+ // if (hseCreatedTime) {
358
+ // this.formSearchData.tableSearch.push({
359
+ // label: "创建时间",
360
+ // value: "createdTime",
361
+ // inputType: "picker",
362
+ // props: {
363
+ // type: "datetimerange",
364
+ // startPlaceholder: "开始时间",
365
+ // endPlaceholder: "结束时间",
366
+ // placeholder: "选择时间范围",
367
+ // valueFormat: "yyyy-MM-dd HH:mm:ss",
368
+ // format: "yyyy/MM/dd HH:mm:ss",
369
+ // },
370
+ // });
371
+ // }
372
+ // }
373
+ this.findTableSearch =
374
+ this.formSearchData.tableSearch.length > this.tableSearchSlice
375
+ ? this.formSearchData.tableSearch.slice(0, this.tableSearchSlice)
376
+ : this.formSearchData.tableSearch;
377
+ console.log(`\x1b[36m\x1b[4mol插件-搜索框渲染`, this.formSearchData.tableSearch);
378
+ },
379
+ // 统一的自动识别范围时间字段方法
380
+ async autoDetectRangeTimeFields(swaggersearchColumns) {
381
+ const tableSearch = [];
382
+ // 1. 处理 BeginTime, EndTime 特殊情况
343
383
  const tableHasCreatedTime = this.formSearchData.tableSearch.some(
344
384
  e => e.value === "createdTime"
345
385
  );
346
386
  if (!tableHasCreatedTime) {
347
- // 单独处理创建时间 就是BeginTime,EndTime
348
387
  const requiredNames = ["BeginTime", "EndTime"];
349
388
  const hseCreatedTime = requiredNames.every(name =>
350
389
  swaggersearchColumns.some(item => item.name === name)
351
390
  );
352
391
  if (hseCreatedTime) {
353
- this.formSearchData.tableSearch.push({
392
+ tableSearch.push({
354
393
  label: "创建时间",
355
394
  value: "createdTime",
356
395
  inputType: "picker",
@@ -362,14 +401,83 @@ export default {
362
401
  valueFormat: "yyyy-MM-dd HH:mm:ss",
363
402
  format: "yyyy/MM/dd HH:mm:ss",
364
403
  },
404
+ originalFields: {
405
+ begin: "BeginTime",
406
+ end: "EndTime",
407
+ },
365
408
  });
366
409
  }
367
410
  }
368
- this.findTableSearch =
369
- this.formSearchData.tableSearch.length > this.tableSearchSlice
370
- ? this.formSearchData.tableSearch.slice(0, this.tableSearchSlice)
371
- : this.formSearchData.tableSearch;
372
- console.log(`\x1b[36m\x1b[4mol插件-搜索框渲染`, this.formSearchData.tableSearch);
411
+
412
+ // 2. 自动识别 xxxxBegin 和 xxxxEnd 格式的范围时间字段
413
+ const beginFields = swaggersearchColumns
414
+ .filter(item => item.name.endsWith("Begin"))
415
+ .map(item => item.name);
416
+
417
+ const endFields = swaggersearchColumns
418
+ .filter(item => item.name.endsWith("End"))
419
+ .map(item => item.name);
420
+
421
+ // 找出匹配的 Begin 和 End 字段对
422
+ const rangeTimePairs = [];
423
+ beginFields.forEach(beginField => {
424
+ const prefix = beginField.replace("Begin", "");
425
+ const correspondingEndField = prefix + "End";
426
+
427
+ if (endFields.includes(correspondingEndField)) {
428
+ rangeTimePairs.push({
429
+ beginField,
430
+ endField: correspondingEndField,
431
+ timeField: prefix + "Time",
432
+ label: prefix,
433
+ });
434
+ }
435
+ });
436
+
437
+ // 使用 for...of 循环等待所有异步操作完成
438
+ for (const pair of rangeTimePairs) {
439
+ const { beginField, endField, timeField, label } = pair;
440
+
441
+ // 检查是否已经存在该时间字段
442
+ const timeFieldExists = this.formSearchData.tableSearch.some(
443
+ item => item.value === timeField
444
+ );
445
+
446
+ if (!timeFieldExists) {
447
+ const labelCHN = await camelCaseToChinese(label);
448
+
449
+ // 从 formSearchData.value 中移除原始字段
450
+ this.removeOriginalFieldsFromValue([beginField, endField]);
451
+
452
+ tableSearch.push({
453
+ label: labelCHN,
454
+ value: timeField,
455
+ inputType: "picker",
456
+ props: {
457
+ type: "datetimerange",
458
+ startPlaceholder: "开始时间",
459
+ endPlaceholder: "结束时间",
460
+ placeholder: `选择${labelCHN}范围`,
461
+ valueFormat: "yyyy-MM-dd HH:mm:ss",
462
+ format: "yyyy/MM/dd HH:mm:ss",
463
+ },
464
+ originalFields: {
465
+ begin: beginField,
466
+ end: endField,
467
+ },
468
+ });
469
+ }
470
+ }
471
+ return tableSearch;
472
+ },
473
+ // 新增方法:从 formSearchData.value 中移除原始字段
474
+ removeOriginalFieldsFromValue(removeKeys) {
475
+ removeKeys.forEach(key => {
476
+ const index = this.formSearchData.tableSearch.findIndex(item => item.value === key);
477
+ if (index !== -1) {
478
+ this.formSearchData.tableSearch.splice(index, 1);
479
+ }
480
+ });
373
481
  },
374
482
  // 树形下拉
375
483
  getValue(val) {