create-ssnode-cli 0.2.0 → 0.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.
Files changed (99) hide show
  1. package/index.js +10 -3
  2. package/package.json +1 -1
  3. package/secrets.js +10 -7
  4. package/templates/backend/Dockerfile +4 -0
  5. package/templates/backend/config/config.develop.yaml +10 -0
  6. package/templates/backend/config/config.prod.yaml +10 -0
  7. package/templates/backend/dist/config/configuration.js +1 -1
  8. package/templates/backend/dist/config/configuration.js.map +1 -1
  9. package/templates/backend/dist/modules/auth/auth.service.js +1 -1
  10. package/templates/backend/dist/modules/auth/auth.service.js.map +1 -1
  11. package/templates/backend/dist/modules/page-data/page-data.controller.js +1 -1
  12. package/templates/backend/dist/modules/page-data/page-data.controller.js.map +1 -1
  13. package/templates/backend/dist/modules/screen-config/screen-config.controller.js +1 -1
  14. package/templates/backend/dist/modules/screen-config/screen-config.controller.js.map +1 -1
  15. package/templates/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  16. package/templates/backend/node_modules/.bin/js-yaml +2 -2
  17. package/templates/backend/node_modules/.bin/typeorm +2 -2
  18. package/templates/backend/node_modules/.bin/typeorm-ts-node-commonjs +2 -2
  19. package/templates/backend/node_modules/.bin/typeorm-ts-node-esm +2 -2
  20. package/templates/backend/ops/docker/.env.example +4 -0
  21. package/templates/backend/ops/docker/config.sh +2 -0
  22. package/templates/backend/ops/docker/install.sh +35 -0
  23. package/templates/backend/ops/install.sh +17 -3
  24. package/templates/backend/ops/pm2/config.sh +2 -0
  25. package/templates/backend/ops/systemd/config.sh +2 -0
  26. package/templates/backend/package.json +13 -6
  27. package/templates/backend/src/config/config.interface.ts +9 -0
  28. package/templates/backend/src/config/configuration.ts +11 -0
  29. package/templates/backend/src/modules/auth/auth.service.ts +57 -12
  30. package/templates/backend/src/modules/page-data/page-data.controller.ts +33 -10
  31. package/templates/backend/src/modules/screen-config/screen-config.controller.ts +33 -5
  32. package/templates/root/README.md +3 -0
  33. package/templates/root/package.json +9 -1
  34. package/templates/web/dist/assets/{404-63aa5037.js → 404-e6edada0.js} +1 -1
  35. package/templates/web/dist/assets/{404-legacy-494c4093.js → 404-legacy-f6ca5b91.js} +1 -1
  36. package/templates/web/dist/assets/AuthLayout-bcf98efb.js +1 -0
  37. package/templates/web/dist/assets/AuthLayout-legacy-6e7a8ae1.js +1 -0
  38. package/templates/web/dist/assets/{Background-13406ae6.js → Background-eb77ef54.js} +1 -1
  39. package/templates/web/dist/assets/{Background-legacy-35ca5eef.js → Background-legacy-50457007.js} +1 -1
  40. package/templates/web/dist/assets/{Screen-4310b270.js → Screen-318c3fc2.js} +1 -1
  41. package/templates/web/dist/assets/{Screen-legacy-d5f1a31f.js → Screen-legacy-af123b0f.js} +1 -1
  42. package/templates/web/dist/assets/{ScreenChartOption-a6927065.js → ScreenChartOption-953b9157.js} +1 -1
  43. package/templates/web/dist/assets/{ScreenChartOption-legacy-b4c04ce9.js → ScreenChartOption-legacy-2e8fcfd8.js} +1 -1
  44. package/templates/web/dist/assets/api-beff4a3e.js +1 -0
  45. package/templates/web/dist/assets/api-legacy-9fe41d4b.js +1 -0
  46. package/templates/web/dist/assets/{base-5bf689c3.js → base-a14309c8.js} +1 -1
  47. package/templates/web/dist/assets/{base-legacy-d3323277.js → base-legacy-2bc6e427.js} +1 -1
  48. package/templates/web/dist/assets/{child-87a05c88.js → child-2a48ca65.js} +1 -1
  49. package/templates/web/dist/assets/{child-legacy-d4d0277d.js → child-legacy-7665b5f8.js} +1 -1
  50. package/templates/web/dist/assets/{component-1fcd971d.js → component-89b5253e.js} +1 -1
  51. package/templates/web/dist/assets/{component-legacy-943364e8.js → component-legacy-8c5a28ef.js} +1 -1
  52. package/templates/web/dist/assets/{demo-14e7532b.js → demo-d7272cf4.js} +1 -1
  53. package/templates/web/dist/assets/{demo-legacy-da0d2bfa.js → demo-legacy-f7bbfe55.js} +1 -1
  54. package/templates/web/dist/assets/echarts-vendor-50090982.js +9 -0
  55. package/templates/web/dist/assets/echarts-vendor-legacy-50b58722.js +10 -0
  56. package/templates/web/dist/assets/{grandson-4f840b4d.js → grandson-05f8bb58.js} +1 -1
  57. package/templates/web/dist/assets/{grandson-legacy-527ae016.js → grandson-legacy-3e10990b.js} +1 -1
  58. package/templates/web/dist/assets/{index-268d1ac1.js → index-466a1ec1.js} +1 -1
  59. package/templates/web/dist/assets/{index-c1ee2fb3.js → index-5b5a8146.js} +1 -1
  60. package/templates/web/dist/assets/{index-3a2983ce.js → index-7277cbfb.js} +1 -1
  61. package/templates/web/dist/assets/{index-e03d0352.js → index-777ef781.js} +1 -1
  62. package/templates/web/dist/assets/{index-e4c9d42a.js → index-86214b19.js} +1 -1
  63. package/templates/web/dist/assets/{index-f57c9694.js → index-9cd5622a.js} +1 -1
  64. package/templates/web/dist/assets/{index-71f600d4.js → index-a79e448b.js} +1 -1
  65. package/templates/web/dist/assets/{index-af61b79b.js → index-b60badf7.js} +1 -1
  66. package/templates/web/dist/assets/{index-b75948c0.js → index-bd4ed808.js} +1 -1
  67. package/templates/web/dist/assets/{index-9120f091.js → index-cba19800.js} +1 -1
  68. package/templates/web/dist/assets/{index-3448ef35.js → index-d70eb540.js} +1 -1
  69. package/templates/web/dist/assets/{index-5e7dfdb5.js → index-e6071630.js} +1 -1
  70. package/templates/web/dist/assets/{index-legacy-081b881d.js → index-legacy-028ed5d5.js} +1 -1
  71. package/templates/web/dist/assets/{index-legacy-aebba3cb.js → index-legacy-06483318.js} +1 -1
  72. package/templates/web/dist/assets/{index-legacy-548904e6.js → index-legacy-0da8de82.js} +1 -1
  73. package/templates/web/dist/assets/{index-legacy-376a4633.js → index-legacy-3965dcaf.js} +1 -1
  74. package/templates/web/dist/assets/{index-legacy-5f22daba.js → index-legacy-4a13dddc.js} +1 -1
  75. package/templates/web/dist/assets/{index-legacy-0983aa0f.js → index-legacy-783129a7.js} +1 -1
  76. package/templates/web/dist/assets/{index-legacy-06643c96.js → index-legacy-8a2cfb9d.js} +1 -1
  77. package/templates/web/dist/assets/{index-legacy-8bba1715.js → index-legacy-993ef005.js} +1 -1
  78. package/templates/web/dist/assets/{index-legacy-19a8ac10.js → index-legacy-b075295d.js} +1 -1
  79. package/templates/web/dist/assets/{index-legacy-b03d819e.js → index-legacy-b3bd40c1.js} +1 -1
  80. package/templates/web/dist/assets/{index-legacy-35c1de97.js → index-legacy-d510e318.js} +1 -1
  81. package/templates/web/dist/assets/{index-legacy-3a393896.js → index-legacy-feb54578.js} +1 -1
  82. package/templates/web/dist/assets/{parent-ad02830b.js → parent-bba709aa.js} +1 -1
  83. package/templates/web/dist/assets/{parent-legacy-163f567f.js → parent-legacy-48111978.js} +1 -1
  84. package/templates/web/dist/assets/vendor-affac96c.js +124 -0
  85. package/templates/web/dist/assets/vendor-legacy-55fa76eb.js +122 -0
  86. package/templates/web/dist/index.html +3 -3
  87. package/templates/web/package.json +7 -7
  88. package/templates/web/src/js/xlsl.ts +110 -59
  89. package/templates/web/src/layouts/AuthLayout.tsx +16 -11
  90. package/templates/web/src/services/api/admin/user.ts +9 -2
  91. package/templates/web/dist/assets/AuthLayout-07e9f5d2.js +0 -1
  92. package/templates/web/dist/assets/AuthLayout-legacy-1b94749f.js +0 -1
  93. package/templates/web/dist/assets/api-83561db2.js +0 -1
  94. package/templates/web/dist/assets/api-legacy-8e15c853.js +0 -1
  95. package/templates/web/dist/assets/echarts-vendor-d6ce4b9c.js +0 -9
  96. package/templates/web/dist/assets/echarts-vendor-legacy-79597af6.js +0 -10
  97. package/templates/web/dist/assets/vendor-2663c204.js +0 -96
  98. package/templates/web/dist/assets/vendor-legacy-2df23db3.js +0 -87
  99. package/templates/web/node_modules/.bin/xlsx +0 -17
@@ -9,8 +9,8 @@
9
9
  />
10
10
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11
11
  <title>-</title>
12
- <script type="module" crossorigin src="/assets/index-e4c9d42a.js"></script>
13
- <link rel="modulepreload" crossorigin href="/assets/vendor-2663c204.js">
12
+ <script type="module" crossorigin src="/assets/index-86214b19.js"></script>
13
+ <link rel="modulepreload" crossorigin href="/assets/vendor-affac96c.js">
14
14
  <link rel="stylesheet" href="/assets/index-ec1f790a.css">
15
15
  <script type="module">import.meta.url;import("_").catch(()=>1);async function* g(){};if(location.protocol!="file:"){window.__vite_is_modern_browser=true}</script>
16
16
  <script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
@@ -21,7 +21,7 @@
21
21
  <script src="/env.config.js"></script>
22
22
  <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
23
23
  <script nomodule crossorigin id="vite-legacy-polyfill" src="/assets/polyfills-legacy-b0716348.js"></script>
24
- <script nomodule crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-aebba3cb.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
24
+ <script nomodule crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-06483318.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
25
25
  </body>
26
26
 
27
27
  </html>
@@ -28,18 +28,18 @@
28
28
  "dependencies": {
29
29
  "@ant-design/icons": "5.3.0",
30
30
  "antd": "5.14.2",
31
- "axios": "1.6.2",
31
+ "axios": "1.20.0",
32
32
  "dayjs": "1.11.10",
33
- "echarts": "5.5.0",
33
+ "echarts": "6.1.0",
34
+ "exceljs": "4.4.0",
34
35
  "js-sha256": "^1.0.0",
35
- "lodash": "4.17.21",
36
- "qs": "6.11.0",
36
+ "lodash": "4.18.1",
37
+ "qs": "6.16.0",
37
38
  "react": "18.2.0",
38
39
  "react-dom": "18.2.0",
39
- "react-router-dom": "6.4.5",
40
+ "react-router-dom": "6.30.6",
40
41
  "react-svg": "15.1.7",
41
- "recoil": "0.7.7",
42
- "xlsx": "0.18.5"
42
+ "recoil": "0.7.7"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/react": "18.2.67",
@@ -1,4 +1,4 @@
1
- import * as XLSX from 'xlsx';
1
+ import ExcelJS from 'exceljs';
2
2
  import request from 'axios';
3
3
 
4
4
  interface ExportTableColumns {
@@ -9,31 +9,74 @@ interface ExportTableColumns {
9
9
  }
10
10
 
11
11
  /**
12
- * 获取excel数据信息
12
+ * exceljs 单元格值归一化:
13
+ * 公式单元格取 result,富文本/超链接取 text,其余原样返回
14
+ */
15
+ const normalizeCell = (value: any): any => {
16
+ if (value === null || value === undefined) {
17
+ return null;
18
+ }
19
+ if (typeof value === 'object') {
20
+ if (value instanceof Date) {
21
+ return value;
22
+ }
23
+ if (value.result !== undefined) {
24
+ return normalizeCell(value.result);
25
+ }
26
+ if (Array.isArray(value.richText)) {
27
+ return value.richText.map((t: { text: string }) => t.text).join('');
28
+ }
29
+ if (value.text !== undefined) {
30
+ return value.text;
31
+ }
32
+ if (value.error !== undefined) {
33
+ return value.error;
34
+ }
35
+ }
36
+ return value;
37
+ };
38
+
39
+ /**
40
+ * 获取excel数据信息(首行为表头,与原 xlsx sheet_to_json 行为一致)
13
41
  * @returns
14
42
  */
15
- const importExcelData = (
43
+ const importExcelData = async (
16
44
  data: ArrayBuffer,
17
45
  aWorkSheets: string[] = []
18
- ): Promise<{ [key: string]: any[] }> =>
19
- new Promise((reslove) => {
20
- const webbook = XLSX.read(data, {
21
- type: 'array',
22
- sheets: aWorkSheets.length === 0 ? null : aWorkSheets
23
- });
24
- let workSheets = aWorkSheets;
25
- if (workSheets.length === 0) {
26
- workSheets = webbook.SheetNames;
27
- }
28
- const dict = {};
29
- for (let index = 0; index < workSheets.length; index += 1) {
30
- const sheetName = workSheets[index];
31
- const workSheet = webbook.Sheets[sheetName];
32
- const json = XLSX.utils.sheet_to_json(workSheet);
33
- dict[sheetName] = json;
46
+ ): Promise<{ [key: string]: any[] }> => {
47
+ const workbook = new ExcelJS.Workbook();
48
+ await workbook.xlsx.load(data);
49
+ const workSheets =
50
+ aWorkSheets.length > 0 ? aWorkSheets : workbook.worksheets.map((ws) => ws.name);
51
+ const dict: { [key: string]: any[] } = {};
52
+ for (let index = 0; index < workSheets.length; index += 1) {
53
+ const sheetName = workSheets[index];
54
+ const workSheet = workbook.getWorksheet(sheetName);
55
+ if (!workSheet) {
56
+ continue;
34
57
  }
35
- reslove(dict);
36
- });
58
+ const aoa: any[][] = [];
59
+ workSheet.eachRow({ includeEmpty: true }, (row) => {
60
+ const values = new Array(workSheet.columnCount).fill(null);
61
+ row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
62
+ values[colNumber - 1] = normalizeCell(cell.value);
63
+ });
64
+ aoa.push(values);
65
+ });
66
+ const headers = aoa[0] || [];
67
+ const json = aoa.slice(1).map((row) => {
68
+ const item: { [key: string]: any } = {};
69
+ headers.forEach((header, i) => {
70
+ if (header !== null && header !== '') {
71
+ item[String(header)] = row[i];
72
+ }
73
+ });
74
+ return item;
75
+ });
76
+ dict[sheetName] = json;
77
+ }
78
+ return dict;
79
+ };
37
80
 
38
81
  /**
39
82
  * 获取excel数据信息 <无权限校验>
@@ -74,25 +117,31 @@ function download(url: string | Blob | ArrayBuffer, fileName?: string) {
74
117
  alink.dispatchEvent(event);
75
118
  }
76
119
 
120
+ /**
121
+ * 工作簿写为 xlsx 并触发下载
122
+ */
123
+ async function writeWorkbookToFile(workbook: ExcelJS.Workbook, fileName?: string) {
124
+ const buffer = await workbook.xlsx.writeBuffer();
125
+ download(new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), fileName);
126
+ }
127
+
77
128
  /**
78
129
  * 将数据导出为excel文件
79
130
  * @param sheets 数据
80
131
  * @param aFileName 文件名称
81
132
  */
82
- function exportExcel(sheets: { [key: string]: any[] }, fileName: string) {
83
- const sheetKeys = Object.keys(sheets);
84
- const Sheets = {};
85
- sheetKeys.forEach((key) => {
86
- const sheet = XLSX.utils.json_to_sheet(sheets[key]);
87
- Sheets[key] = sheet;
133
+ async function exportExcel(sheets: { [key: string]: any[] }, fileName: string) {
134
+ const workbook = new ExcelJS.Workbook();
135
+ Object.keys(sheets).forEach((key) => {
136
+ const rows = sheets[key] || [];
137
+ const sheet = workbook.addWorksheet(key);
138
+ if (rows.length > 0) {
139
+ const headers = Object.keys(rows[0]);
140
+ sheet.columns = headers.map((header) => ({ header, key: header }));
141
+ rows.forEach((row) => sheet.addRow(row));
142
+ }
88
143
  });
89
- XLSX.writeFileXLSX(
90
- {
91
- SheetNames: sheetKeys,
92
- Sheets
93
- },
94
- fileName
95
- );
144
+ await writeWorkbookToFile(workbook, fileName);
96
145
  }
97
146
 
98
147
  /**
@@ -100,12 +149,15 @@ function exportExcel(sheets: { [key: string]: any[] }, fileName: string) {
100
149
  * @param sheets 数据
101
150
  * @param aFileName 文件名称
102
151
  */
103
- function exportExcelFromTable(tablee: HTMLTableElement, fileName?: string) {
104
- const workbook = XLSX.utils.table_to_book(tablee);
105
- // Process Data (add a new row)
106
- // var ws = workbook.Sheets['Sheet1'];
107
- // XLSX.utils.sheet_add_aoa(ws, [['Created ' + new Date().toISOString()]], { origin: -1 });
108
- XLSX.writeFileXLSX(workbook, fileName);
152
+ async function exportExcelFromTable(tablee: HTMLTableElement, fileName?: string) {
153
+ const workbook = new ExcelJS.Workbook();
154
+ const sheet = workbook.addWorksheet('Sheet1');
155
+ const trList = tablee.querySelectorAll('tr');
156
+ trList.forEach((tr) => {
157
+ const cells = tr.querySelectorAll('th,td');
158
+ sheet.addRow(Array.from(cells).map((cell) => (cell.textContent || '').trim()));
159
+ });
160
+ await writeWorkbookToFile(workbook, fileName);
109
161
  }
110
162
 
111
163
  /**
@@ -114,16 +166,16 @@ function exportExcelFromTable(tablee: HTMLTableElement, fileName?: string) {
114
166
  * @param dataList 表格数据
115
167
  * @param fileName 文件名称
116
168
  */
117
- function exportExcelFromColumns(columns: ExportTableColumns[], dataList: any[], fileName: string) {
169
+ async function exportExcelFromColumns(columns: ExportTableColumns[], dataList: any[], fileName: string) {
118
170
  // 将头部标题数据 拉平
119
- const mergeOptions = [];
171
+ const mergeOptions: Array<{ s: { r: number; c: number }; e: { r: number; c: number } }> = [];
120
172
  let maxHeaderLevel = 1;
121
173
  const flatteHeaders = (
122
174
  columns: ExportTableColumns[],
123
175
  prevHeaders: ExportTableColumns[] = [],
124
176
  level = 1
125
177
  ) => {
126
- const list = [];
178
+ const list: ExportTableColumns[] = [];
127
179
  for (let index = 0; index < columns.length; index++) {
128
180
  const element = columns[index];
129
181
 
@@ -145,7 +197,7 @@ function exportExcelFromColumns(columns: ExportTableColumns[], dataList: any[],
145
197
  list.push({
146
198
  ...element,
147
199
  prevHeaders: [...prevHeaders, element]
148
- });
200
+ } as ExportTableColumns);
149
201
  }
150
202
  }
151
203
  maxHeaderLevel = Math.max(maxHeaderLevel, level);
@@ -154,7 +206,7 @@ function exportExcelFromColumns(columns: ExportTableColumns[], dataList: any[],
154
206
 
155
207
  const flatteColumns = flatteHeaders(columns, []);
156
208
  const headerDatas: string[][] = [];
157
- const dataIndexKeys = [];
209
+ const dataIndexKeys: Array<string | string[] | undefined> = [];
158
210
  for (let index = 0; index < flatteColumns.length; index++) {
159
211
  const element = flatteColumns[index];
160
212
  dataIndexKeys.push(element.dataIndex);
@@ -164,10 +216,10 @@ function exportExcelFromColumns(columns: ExportTableColumns[], dataList: any[],
164
216
  headerDatas[j] = [];
165
217
  }
166
218
  const headerData = headerDatas[j];
167
- const targetElement = element.prevHeaders[j] || {};
219
+ const targetElement = element.prevHeaders?.[j] || {};
168
220
  headerData.push(targetElement.title || '');
169
221
 
170
- if (j === element.prevHeaders.length - 1) {
222
+ if (j === (element.prevHeaders?.length || 0) - 1) {
171
223
  mergeOptions.push({
172
224
  s: {
173
225
  r: j,
@@ -192,7 +244,7 @@ function exportExcelFromColumns(columns: ExportTableColumns[], dataList: any[],
192
244
  return getValueFromProps(keys, target);
193
245
  };
194
246
 
195
- const contentDatas = [];
247
+ const contentDatas: any[][] = [];
196
248
  for (let index = 0; index < dataList.length; index++) {
197
249
  const element = dataList[index];
198
250
  const values = [];
@@ -204,22 +256,21 @@ function exportExcelFromColumns(columns: ExportTableColumns[], dataList: any[],
204
256
  if (dataIndex instanceof Array) {
205
257
  value = getValueFromProps([...dataIndex], element);
206
258
  } else {
207
- value = getValueFromProps([dataIndex], element);
259
+ value = getValueFromProps([dataIndex as string], element);
208
260
  }
209
261
  values.push(value);
210
262
  }
211
263
  contentDatas.push(values);
212
264
  }
213
265
 
214
- // 创建工作簿
215
- const wb = XLSX.utils.book_new();
216
- // 转换数据为工作表
217
- const contentws = XLSX.utils.aoa_to_sheet([...headerDatas, ...contentDatas]);
218
- // 设置单元格合并
219
- contentws['!merges'] = mergeOptions;
220
- // 添加工作表到工作簿
221
- XLSX.utils.book_append_sheet(wb, contentws);
222
- XLSX.writeFile(wb, fileName);
266
+ // 创建工作簿(单元格合并,r/c 从 0 起转为 exceljs 的 1 起行列)
267
+ const workbook = new ExcelJS.Workbook();
268
+ const sheet = workbook.addWorksheet('Sheet1');
269
+ [...headerDatas, ...contentDatas].forEach((row) => sheet.addRow(row));
270
+ mergeOptions.forEach((merge) => {
271
+ sheet.mergeCells(merge.s.r + 1, merge.s.c + 1, merge.e.r + 1, merge.e.c + 1);
272
+ });
273
+ await writeWorkbookToFile(workbook, fileName);
223
274
  }
224
275
 
225
276
  /**
@@ -231,7 +282,7 @@ const createMultiMap = (aList = [], aUniqePropNames: string[]): { [key: string]:
231
282
  const resault = {};
232
283
  for (let index = 0; index < aList.length; index += 1) {
233
284
  const element = aList[index];
234
- for (let j = 0; j < aUniqePropNames.length; j += 1) {
285
+ for (let j = 0; j < aUniqePropNames.length; j++) {
235
286
  const aPropName = aUniqePropNames[j];
236
287
  const dict = resault[aPropName] || {};
237
288
 
@@ -24,20 +24,25 @@ export default function AuthLayout() {
24
24
 
25
25
  // 判断登录 -- 优先判断sso登录 --- 如果不是单点登录情况 --- 未登录
26
26
  setLoading(true);
27
- // 存在单点登录
27
+ // 存在单点登录(接入方跳转 URL 携带 ?user=<用户名>&ts=<unix秒>&sign=<票据>)
28
28
  const query = QueryString.parse(location.search.replace('?', ''));
29
29
  if (query.user) {
30
- // 执行 sso登录
31
- api.admin.user.ssoLogin(query.token as string).then((success) => {
32
- if (success) {
30
+ // 执行 sso登录(票据由接入方用 backend sso.ticketKey 生成,见 docs/api-security.md)
31
+ api.admin.user
32
+ .ssoLogin({
33
+ username: query.user as string,
34
+ ts: query.ts as string,
35
+ sign: query.sign as string
36
+ })
37
+ .then((success) => {
33
38
  setLoading(false);
34
- setSystemAuthorization(true);
35
- } else {
36
- setLoading(false);
37
- setSystemAuthorization(false);
38
- // reLogin();
39
- }
40
- });
39
+ if (success) {
40
+ setSystemAuthorization(true);
41
+ } else {
42
+ setSystemAuthorization(false);
43
+ reLogin();
44
+ }
45
+ });
41
46
  return;
42
47
  }
43
48
  // 非单点登录 --- 普通处理
@@ -58,9 +58,16 @@ export function login(params: {
58
58
 
59
59
  /**
60
60
  * 单点登录 /api/ssologin
61
+ * 票据由接入方(门户/统一认证)用 backend sso.ticketKey 生成:
62
+ * sign = HMAC-SHA256(`${username}\n${ts}`, ticketKey) hex
63
+ * backend 未开启 sso(yaml sso.enabled=false)时该接口返回 404。
61
64
  */
62
- export function ssoLogin(params: { [key: string]: any }): Promise<boolean> {
63
- if (!params || Object.keys(params).length === 0) {
65
+ export function ssoLogin(params: {
66
+ username: string;
67
+ ts: string;
68
+ sign: string;
69
+ }): Promise<boolean> {
70
+ if (!params?.username || !params?.ts || !params?.sign) {
64
71
  return Promise.resolve(false);
65
72
  }
66
73
  return request.get('/api/ssologin', { params }).then((res: ResponseItem) => {
@@ -1 +0,0 @@
1
- import{u as m,e as p,r as s,Q as d,j as f,S as g,O as h}from"./vendor-2663c204.js";import{a as r}from"./api-83561db2.js";import"./index-e4c9d42a.js";function E(){const c=m(),n=p(),[l,t]=s.useState(!0),[o,i]=s.useState(!1);return s.useEffect(()=>{if(!window.ENV.checkToken){t(!1);return}const e=()=>{c("/login?redirect=".concat(encodeURIComponent(n.pathname+n.search)))};t(!0);const u=d.parse(n.search.replace("?",""));if(u.user){r.admin.user.ssoLogin(u.token).then(a=>{a?(t(!1),i(!0)):(t(!1),i(!1))});return}r.admin.user.isLogin().then(a=>{a.login?(t(!1),i(a.permission)):(t(!1),e())})},[]),s.useEffect(()=>{o&&r.admin.user.getInfo().then(e=>{e.status==="SUCCESS"&&(e.data.menu?e.data.menuArray=JSON.parse(e.data.menu):e.data.menuArray=[])})},[o]),l?f.jsx(g,{spinning:!0,tip:"登录中...",size:"large",style:{height:"100vh",width:"100vw",display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"center"}}):f.jsx(h,{})}export{E as default};
@@ -1 +0,0 @@
1
- System.register(["./vendor-legacy-2df23db3.js","./api-legacy-8e15c853.js","./index-legacy-aebba3cb.js"],(function(e,t){"use strict";var n,s,r,a,i,u,o,c;return{setters:[e=>{n=e.u,s=e.e,r=e.r,a=e.Q,i=e.j,u=e.S,o=e.O},e=>{c=e.a},null],execute:function(){e("default",(function(){const e=n(),t=s(),[d,l]=r.useState(!0),[f,g]=r.useState(!1);return r.useEffect((()=>{if(!window.ENV.checkToken)return void l(!1);l(!0);const n=a.parse(t.search.replace("?",""));n.user?c.admin.user.ssoLogin(n.token).then((e=>{e?(l(!1),g(!0)):(l(!1),g(!1))})):c.admin.user.isLogin().then((n=>{n.login?(l(!1),g(n.permission)):(l(!1),e(`/login?redirect=${encodeURIComponent(t.pathname+t.search)}`))}))}),[]),r.useEffect((()=>{f&&c.admin.user.getInfo().then((e=>{"SUCCESS"===e.status&&(e.data.menu?e.data.menuArray=JSON.parse(e.data.menu):e.data.menuArray=[])}))}),[f]),d?i.jsx(u,{spinning:!0,tip:"登录中...",size:"large",style:{height:"100vh",width:"100vw",display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"center"}}):i.jsx(o,{})}))}}}));
@@ -1 +0,0 @@
1
- import{a3 as i,w as s}from"./vendor-2663c204.js";import{P as _}from"./index-e4c9d42a.js";const{CancelToken:y}=i,b=y.source(),u=i.create({baseURL:"",timeoutErrorMessage:"网络出点小差,请稍等重试",withCredentials:!1,responseType:"json",cancelToken:b.token});u.interceptors.request.use(e=>e);u.interceptors.response.use(e=>{const t=_.request.ignoreContentTypes,r=e.headers["content-type"];return t.some(n=>r.includes(n))?e:e.data},e=>Promise.reject(e));const o=u,l=i.create({timeoutErrorMessage:"网络出点小差,请稍等重试",withCredentials:!1,responseType:"json"});l.interceptors.response.use(e=>e.data);const d="login_type",a="storage_usertoken",p=(e,t)=>{localStorage.setItem(d,e),e==="sso"?sessionStorage.setItem(a,t):e==="password"&&localStorage.setItem(a,t),c(t&&"Bearer ".concat(t))},S=()=>{switch(localStorage.getItem(d)){case"password":return localStorage.getItem(a);case"sso":return sessionStorage.getItem(a);default:return""}};function h(e){return o.post("/api/login",e).then(t=>t.code===200&&t.data?(p("password",t.data),!0):!1)}function O(e){return!e||Object.keys(e).length===0?Promise.resolve(!1):o.get("/api/ssologin",{params:e}).then(t=>t.code===200&&t.data?(p("sso",t.data),!0):!1)}function j(){return S()}function T(){return o.get("/api/user/islogin").then(e=>{var t,r;return{login:e.code===200&&((t=e.data)==null?void 0:t.login),permission:e.code===200&&((r=e.data)==null?void 0:r.permission)}})}function I(){return o.get("/api/user/captcha").then(e=>e.data||{captchaId:"",svg:""})}function v(){return o.get("/api/user/info").then(e=>e.code===200?{status:"SUCCESS",data:e.data}:{status:"FAIL"})}function M(){return o.post("/api/user/logout").then(e=>e.code===200).finally(()=>{localStorage.removeItem(a),c(null)})}const P=Object.freeze(Object.defineProperty({__proto__:null,getAuthorization:j,getCaptcha:I,getInfo:v,isLogin:T,login:h,logout:M,ssoLogin:O},Symbol.toStringTag,{value:"Module"}));function L(){return o.get("/api/user/captcha")}const Y=Object.freeze(Object.defineProperty({__proto__:null,getCaptcha:L},Symbol.toStringTag,{value:"Module"})),w=10*1024*1024;function $(e){const t=new FormData;return t.append("file",e),o.post("/api/upload",t,{headers:{"Content-Type":"multipart/form-data"}})}const z=Object.freeze(Object.defineProperty({__proto__:null,UPLOAD_MAX_SIZE:w,upload:$},Symbol.toStringTag,{value:"Module"}));function U(e){return o.post("/api/add",e)}function B(e){return o.get("/api/getList",{params:e})}function C(e){return o.put("/api/edit",e)}function A(e){return o.delete("/api/deleteById",{params:e})}function E(e,t){const r=new FormData;return r.append("file",e),o.post("/api/v1/import",r,t)}const q=Object.freeze(Object.defineProperty({__proto__:null,add:U,deleteById:A,getList:B,update:C,upload:E},Symbol.toStringTag,{value:"Module"}));function N(){return o.get("/api/ops/overview")}function F(e){return o.get("/api/ops/probe/".concat(e))}const R=Object.freeze(Object.defineProperty({__proto__:null,overview:N,probe:F},Symbol.toStringTag,{value:"Module"}));function D(e){return o.get("/api/getList",{params:e})}function x(e){return o.post("/api/add",e)}function k(e){return o.put("/api/edit",e)}function G(e){return o.delete("/api/deleteById",{params:{id:e}})}const K=Object.freeze(Object.defineProperty({__proto__:null,add:x,deleteById:G,edit:k,getList:D},Symbol.toStringTag,{value:"Module"}));function W(e){return o.get("/api/image/getList",{params:e})}function V(e){return o.post("/api/image/add",e)}function X(e){return o.put("/api/image/edit",e)}function Z(e){return o.delete("/api/image/deleteById",{params:{id:e}})}const H=Object.freeze(Object.defineProperty({__proto__:null,add:V,deleteById:Z,edit:X,getList:W},Symbol.toStringTag,{value:"Module"}));function J(e){return o.get("/api/user/list",{params:e})}function Q(e){return o.post("/api/user/create",e)}function ee(e){return o.put("/api/user/update",e)}function te(e){return o.delete("/api/user/delete",{params:{id:e}})}function oe(e){return o.post("/api/user/resetPassword",null,{params:{id:e}})}function re(e){return o.post("/api/user/toggleStatus",null,{params:{id:e}})}const ne=Object.freeze(Object.defineProperty({__proto__:null,createUser:Q,deleteUser:te,listUsers:J,resetUserPassword:oe,toggleUserStatus:re,updateUser:ee},Symbol.toStringTag,{value:"Module"}));function ae(e){return o.get("/api/audit/list",{params:e})}const se=Object.freeze(Object.defineProperty({__proto__:null,listAuditLogs:ae},Symbol.toStringTag,{value:"Module"})),f={user:P,captcha:Y,upload:z,test:q,ops:R,pageData:K,image:H,userManage:ne,auditLog:se},ie=e=>{let t="YYYYMM";switch(e){case 1:t="YYYYMMDD";break;case 2:t="YYYYMM";break;case 3:t="YYYY";break}return t};function ue(e,t=2){return Number.isInteger(e)?e.toString():e.toFixed(t)}const ce=(e,t)=>{let r=e.id?1/e.id:0,n=t.id?1/t.id:0;return e.sort<0?r+=-1e3-e.sort:e.sort>0&&(r+=20*1e3*(e.sort?1/e.sort:1)),t.sort<0?n+=-1e3-t.sort:t.sort>0&&(n+=20*1e3*(t.sort?1/t.sort:1)),n-r},le=e=>{if(e.data instanceof Blob){const t=e.headers["content-disposition"],g=(t==null?void 0:t.split(";")).find(m=>m.trim().startsWith("filename=")).trim().replace("filename=","");return{data:e.data,fileName:decodeURIComponent(g)}}return{}},de=Object.freeze(Object.defineProperty({__proto__:null,exportFile:le,formatNumber:ue,getTimeFormatter:ie,sort:ce},Symbol.toStringTag,{value:"Module"})),pe=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"}));o.defaults.baseURL=window.ENV.requestBaseUrl;o.defaults.validateStatus=e=>(e===401&&s.info("登录失效,请重新登录"),e>=200&&e<300);o.interceptors.response.use(e=>(e&&e.code!==void 0&&e.code!==200&&s.error(e.message||e.msg||"请求失败,请重试"),e),e=>{var t;s.error("".concat(e==null?void 0:e.message,"(").concat(decodeURIComponent((t=e.request)==null?void 0:t.responseURL),")"),5)});const c=e=>{const t=e&&(e.startsWith("Bearer ")?e:"Bearer ".concat(e));o.defaults.headers.Authorization=t,l.defaults.headers.Authorization=t};c(f.user.getAuthorization());const me={admin:f,common:de,mysql:pe};export{w as U,me as a};
@@ -1 +0,0 @@
1
- System.register(["./vendor-legacy-2df23db3.js","./index-legacy-aebba3cb.js"],(function(e,t){"use strict";var r,o,n;return{setters:[e=>{r=e.a3,o=e.w},e=>{n=e.P}],execute:function(){const{CancelToken:t}=r,a=t.source(),s=r.create({baseURL:"",timeoutErrorMessage:"网络出点小差,请稍等重试",withCredentials:!1,responseType:"json",cancelToken:a.token});s.interceptors.request.use((e=>e)),s.interceptors.response.use((e=>{const t=n.request.ignoreContentTypes,r=e.headers["content-type"];return t.some((e=>r.includes(e)))?e:e.data}),(e=>Promise.reject(e)));const i=s,u=r.create({timeoutErrorMessage:"网络出点小差,请稍等重试",withCredentials:!1,responseType:"json"});u.interceptors.response.use((e=>e.data));const d="login_type",l="storage_usertoken",p=(e,t)=>{localStorage.setItem(d,e),"sso"===e?sessionStorage.setItem(l,t):"password"===e&&localStorage.setItem(l,t),y(t?`Bearer ${t}`:t)},c=Object.freeze(Object.defineProperty({__proto__:null,getAuthorization:function(){return(()=>{switch(localStorage.getItem(d)){case"password":return localStorage.getItem(l);case"sso":return sessionStorage.getItem(l);default:return""}})()},getCaptcha:function(){return i.get("/api/user/captcha").then((e=>e.data||{captchaId:"",svg:""}))},getInfo:function(){return i.get("/api/user/info").then((e=>200===e.code?{status:"SUCCESS",data:e.data}:{status:"FAIL"}))},isLogin:function(){return i.get("/api/user/islogin").then((e=>({login:200===e.code&&e.data?.login,permission:200===e.code&&e.data?.permission})))},login:function(e){return i.post("/api/login",e).then((e=>!(200!==e.code||!e.data||(p("password",e.data),0))))},logout:function(){return i.post("/api/user/logout").then((e=>200===e.code)).finally((()=>{localStorage.removeItem(l),y(null)}))},ssoLogin:function(e){return e&&0!==Object.keys(e).length?i.get("/api/ssologin",{params:e}).then((e=>!(200!==e.code||!e.data||(p("sso",e.data),0)))):Promise.resolve(!1)}},Symbol.toStringTag,{value:"Module"})),g=Object.freeze(Object.defineProperty({__proto__:null,getCaptcha:function(){return i.get("/api/user/captcha")}},Symbol.toStringTag,{value:"Module"})),f=e("U",10485760),m={user:c,captcha:g,upload:Object.freeze(Object.defineProperty({__proto__:null,UPLOAD_MAX_SIZE:f,upload:function(e){const t=new FormData;return t.append("file",e),i.post("/api/upload",t,{headers:{"Content-Type":"multipart/form-data"}})}},Symbol.toStringTag,{value:"Module"})),test:Object.freeze(Object.defineProperty({__proto__:null,add:function(e){return i.post("/api/add",e)},deleteById:function(e){return i.delete("/api/deleteById",{params:e})},getList:function(e){return i.get("/api/getList",{params:e})},update:function(e){return i.put("/api/edit",e)},upload:function(e,t){const r=new FormData;return r.append("file",e),i.post("/api/v1/import",r,t)}},Symbol.toStringTag,{value:"Module"})),ops:Object.freeze(Object.defineProperty({__proto__:null,overview:function(){return i.get("/api/ops/overview")},probe:function(e){return i.get(`/api/ops/probe/${e}`)}},Symbol.toStringTag,{value:"Module"})),pageData:Object.freeze(Object.defineProperty({__proto__:null,add:function(e){return i.post("/api/add",e)},deleteById:function(e){return i.delete("/api/deleteById",{params:{id:e}})},edit:function(e){return i.put("/api/edit",e)},getList:function(e){return i.get("/api/getList",{params:e})}},Symbol.toStringTag,{value:"Module"})),image:Object.freeze(Object.defineProperty({__proto__:null,add:function(e){return i.post("/api/image/add",e)},deleteById:function(e){return i.delete("/api/image/deleteById",{params:{id:e}})},edit:function(e){return i.put("/api/image/edit",e)},getList:function(e){return i.get("/api/image/getList",{params:e})}},Symbol.toStringTag,{value:"Module"})),userManage:Object.freeze(Object.defineProperty({__proto__:null,createUser:function(e){return i.post("/api/user/create",e)},deleteUser:function(e){return i.delete("/api/user/delete",{params:{id:e}})},listUsers:function(e){return i.get("/api/user/list",{params:e})},resetUserPassword:function(e){return i.post("/api/user/resetPassword",null,{params:{id:e}})},toggleUserStatus:function(e){return i.post("/api/user/toggleStatus",null,{params:{id:e}})},updateUser:function(e){return i.put("/api/user/update",e)}},Symbol.toStringTag,{value:"Module"})),auditLog:Object.freeze(Object.defineProperty({__proto__:null,listAuditLogs:function(e){return i.get("/api/audit/list",{params:e})}},Symbol.toStringTag,{value:"Module"}))},_=Object.freeze(Object.defineProperty({__proto__:null,exportFile:e=>{if(e.data instanceof Blob){const t=e.headers["content-disposition"],r=t?.split(";"),o=r.find((e=>e.trim().startsWith("filename="))).trim().replace("filename=","");return{data:e.data,fileName:decodeURIComponent(o)}}return{}},formatNumber:function(e,t=2){return Number.isInteger(e)?e.toString():e.toFixed(t)},getTimeFormatter:e=>{let t="YYYYMM";switch(e){case 1:t="YYYYMMDD";break;case 2:t="YYYYMM";break;case 3:t="YYYY"}return t},sort:(e,t)=>{let r=e.id?1/e.id:0,o=t.id?1/t.id:0;return e.sort<0?r+=-1e3-e.sort:e.sort>0&&(r+=2e4*(e.sort?1/e.sort:1)),t.sort<0?o+=-1e3-t.sort:t.sort>0&&(o+=2e4*(t.sort?1/t.sort:1)),o-r}},Symbol.toStringTag,{value:"Module"})),b=Object.freeze(Object.defineProperty({__proto__:null},Symbol.toStringTag,{value:"Module"}));i.defaults.baseURL=window.ENV.requestBaseUrl,i.defaults.validateStatus=e=>(401===e&&o.info("登录失效,请重新登录"),e>=200&&e<300),i.interceptors.response.use((e=>(e&&void 0!==e.code&&200!==e.code&&o.error(e.message||e.msg||"请求失败,请重试"),e)),(e=>{o.error(`${e?.message}(${decodeURIComponent(e.request?.responseURL)})`,5)}));const y=e=>{const t=e?e.startsWith("Bearer ")?e:`Bearer ${e}`:e;i.defaults.headers.Authorization=t,u.defaults.headers.Authorization=t};y(m.user.getAuthorization()),e("a",{admin:m,common:_,mysql:b})}}}));