@peng_kai/kit 0.3.0-beta.3 → 0.3.0-beta.30

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 (60) hide show
  1. package/.vscode/settings.json +2 -2
  2. package/admin/components/currency/src/CurrencyIcon.vue +37 -33
  3. package/admin/components/date/PeriodPicker.vue +122 -0
  4. package/admin/components/date/TimeFieldSelectForLabel.vue +24 -0
  5. package/admin/components/date/TtaTimeZone.vue +516 -0
  6. package/admin/components/date/TtaTimeZoneSimple.vue +104 -0
  7. package/admin/components/date/helpers.ts +250 -0
  8. package/admin/components/date/index.ts +6 -0
  9. package/admin/components/date/presetProps.ts +19 -0
  10. package/admin/components/filter/src/FilterReset.vue +52 -8
  11. package/admin/components/filter/src/more/TableSetting.vue +95 -0
  12. package/admin/components/provider/Admin.vue +17 -0
  13. package/admin/components/provider/admin-permission.ts +48 -0
  14. package/admin/components/provider/admin-router.ts +361 -0
  15. package/admin/components/provider/index.ts +3 -0
  16. package/admin/components/rich-text/src/RichText.new.vue +19 -6
  17. package/admin/components/rich-text/src/editorConfig.ts +76 -1
  18. package/admin/components/settings/src/SchemaForm.vue +5 -4
  19. package/admin/components/settings/src/Settings.vue +1 -1
  20. package/admin/components/text/index.ts +2 -0
  21. package/admin/components/text/src/Amount.v2.vue +131 -0
  22. package/admin/components/text/src/Datetime.vue +17 -12
  23. package/admin/components/text/src/Num.vue +192 -0
  24. package/admin/layout/large/Breadcrumb.vue +10 -23
  25. package/admin/layout/large/Content.vue +9 -6
  26. package/admin/layout/large/Layout.vue +129 -0
  27. package/admin/layout/large/Menu.vue +24 -17
  28. package/admin/layout/large/Notice.vue +152 -0
  29. package/admin/layout/large/Tabs.vue +183 -0
  30. package/admin/layout/large/index.ts +61 -1
  31. package/admin/layout/large/y682.mp3 +0 -0
  32. package/admin/permission/routerGuard.ts +24 -11
  33. package/admin/permission/vuePlugin.ts +5 -10
  34. package/admin/route-guards/index.ts +0 -1
  35. package/admin/stores/index.ts +1 -0
  36. package/admin/styles/classCover.scss +1 -1
  37. package/admin/styles/index.scss +2 -2
  38. package/antd/hooks/useAntdModal.ts +27 -13
  39. package/antd/hooks/useAntdTable.ts +10 -7
  40. package/antd/hooks/useAntdTheme.ts +7 -0
  41. package/antd/hooks/useTableColumns.ts +83 -0
  42. package/antd/index.ts +1 -1
  43. package/libs/bignumber.ts +1 -1
  44. package/libs/dayjs.ts +16 -2
  45. package/libs/fingerprintjs.ts +1 -0
  46. package/package.json +64 -95
  47. package/request/interceptors/getDeviceInfo.ts +14 -0
  48. package/utils/LocaleManager.ts +1 -1
  49. package/utils/index.ts +1 -4
  50. package/utils/locale/LocaleManager.ts +2 -1
  51. package/utils/locale/helpers.ts +9 -0
  52. package/utils/number.ts +8 -10
  53. package/utils/storage.ts +31 -0
  54. package/utils/string.ts +1 -2
  55. package/utils/upload/AwsS3.ts +11 -4
  56. package/admin/layout/large/PageTab.vue +0 -70
  57. package/admin/route-guards/collapseMenu.ts +0 -11
  58. package/libs/a-calc.ts +0 -1
  59. package/vue/components/test/KitTest.vue +0 -9
  60. package/vue/components/test/testStore.ts +0 -11
@@ -0,0 +1,83 @@
1
+ import { computed, reactive, ref, toValue, watch, provide } from 'vue';
2
+ import { extendRef } from '@vueuse/core';
3
+
4
+ export type ColumnConfig = { dataIndex: string, visible: boolean, compact: boolean }
5
+ interface TableConfig {
6
+ columns: ColumnConfig[];
7
+ }
8
+
9
+ const tableConfigStore = {
10
+ key: 'TABLE_CONFIG',
11
+ genTableId(columns: { dataIndex: string }[], extra = '') {
12
+ const indexsStr = columns.map((col: any) => col.dataIndex).join(',') + extra;
13
+ let hash = 0;
14
+ let len = 12;
15
+
16
+ for (let i = 0; i < indexsStr.length; i++) {
17
+ const ch = indexsStr.charCodeAt(i);
18
+ hash = (hash << 5) - hash + ch;
19
+ hash |= 0;
20
+ }
21
+
22
+ const base36 = (hash >>> 0).toString(36);
23
+ return base36.length >= len ? base36.slice(0, len) : base36.padStart(len, '0');
24
+ },
25
+ getTableConfig(tableId: string): TableConfig | null {
26
+ const configStr = localStorage.getItem(this.key);
27
+ const allConfig = configStr ? JSON.parse(configStr) : {};
28
+ return allConfig[tableId] || null;
29
+ },
30
+ setTableConfig(tableId: string, config: Partial<TableConfig>) {
31
+ const configStr = localStorage.getItem(this.key);
32
+ const allConfig = configStr ? JSON.parse(configStr) : {};
33
+ allConfig[tableId] = Object.assign({}, allConfig[tableId] || {}, config);
34
+ localStorage.setItem(this.key, JSON.stringify(allConfig));
35
+ }
36
+ }
37
+
38
+ export function useTableColumns<LCT extends any[]>() {
39
+ const columnsConfig = ref<Array<ColumnConfig> | null | undefined>();
40
+ let originalColumns: LCT | null = null;
41
+ let tableId = ''
42
+
43
+ const defineColumns = (columnsGetter: () => LCT) => {
44
+ originalColumns = toValue(columnsGetter) || [] as unknown as LCT;
45
+ tableId = tableConfigStore.genTableId(originalColumns);
46
+ columnsConfig.value = tableConfigStore.getTableConfig(tableId)?.columns;
47
+
48
+ provide('tableColumns', originalColumns);
49
+ provide('tableColumnsConfig', columnsConfig);
50
+
51
+ const columns = computed(() => {
52
+ const config = columnsConfig.value;
53
+ let columns = columnsGetter();
54
+
55
+ if (config?.length) {
56
+ columns = columns.filter((col: any) => config.find(c => c.dataIndex === col.dataIndex)?.visible !== false) as LCT;
57
+ columns = columns.map((col: any) => {
58
+ const cf = config.find(c => c.dataIndex === col.dataIndex);
59
+ return { ...col, compact: cf?.compact };
60
+ }) as LCT;
61
+ const dataIndexOrderMap = new Map(config.map((c, i) => [c.dataIndex, i]));
62
+ columns.sort((a, b) => {
63
+ const indexA = dataIndexOrderMap.get(a.dataIndex);
64
+ const indexB = dataIndexOrderMap.get(b.dataIndex);
65
+ return (indexA ?? Infinity) - (indexB ?? Infinity);
66
+ });
67
+ }
68
+
69
+ return columns;
70
+ })
71
+
72
+ return extendRef(columns, {});
73
+ };
74
+
75
+ watch(columnsConfig, (newConfig) => {
76
+ newConfig && tableConfigStore.setTableConfig(tableId, { columns: newConfig });
77
+ });
78
+
79
+ return {
80
+ defineColumns,
81
+ tableColumnsConfig: columnsConfig,
82
+ };
83
+ }
package/antd/index.ts CHANGED
@@ -5,4 +5,4 @@ export { useAntdForm } from './hooks/useAntdForm';
5
5
  export { useAntdTheme } from './hooks/useAntdTheme';
6
6
  export { createAntdModal } from './hooks/createAntdModal';
7
7
  export { default as InputNumberRange } from './components/InputNumberRange.vue';
8
- export type { SchemaConfig, ItemSchema } from './hooks/useAntdForm.ts';
8
+ export type { SchemaConfig, ItemSchema } from './hooks/useAntdForm.ts';
package/libs/bignumber.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export { default } from 'bignumber.js';
2
- export { BigNumber } from 'bignumber.js';
2
+ export { type BigNumber } from 'bignumber.js';
package/libs/dayjs.ts CHANGED
@@ -5,15 +5,29 @@ import weekday from 'dayjs/esm/plugin/weekday';
5
5
  import localeData from 'dayjs/esm/plugin/localeData';
6
6
  import utc from 'dayjs/esm/plugin/utc';
7
7
  import tz from 'dayjs/esm/plugin/timezone';
8
- import 'dayjs/esm/locale/zh';
8
+ import weekOfYear from 'dayjs/esm/plugin/weekOfYear';
9
+ import weekYear from 'dayjs/esm/plugin/weekYear';
10
+ import quarterOfYear from 'dayjs/esm/plugin/quarterOfYear';
11
+ import advancedFormat from 'dayjs/esm/plugin/advancedFormat';
12
+ import customParseFormat from 'dayjs/esm/plugin/customParseFormat';
13
+ import updateLocale from 'dayjs/esm/plugin/updateLocale';
14
+ import isBetween from 'dayjs/esm/plugin/isBetween';
15
+ import 'dayjs/esm/locale/zh-cn';
9
16
  import 'dayjs/esm/locale/en';
10
17
 
11
18
  export type { Dayjs, PluginFunc, UnitType, UnitTypeLong, UnitTypeLongPlural, UnitTypeShort, QUnitType, ConfigType, ConfigTypeMap, OpUnitType, OptionType, ManipulateType } from 'dayjs';
12
19
  export default dayjs;
13
20
 
14
- dayjs.locale('zh');
15
21
  dayjs.extend(relativeTime);
16
22
  dayjs.extend(weekday);
17
23
  dayjs.extend(localeData);
18
24
  dayjs.extend(utc);
19
25
  dayjs.extend(tz);
26
+ dayjs.extend(weekOfYear);
27
+ dayjs.extend(weekYear);
28
+ dayjs.extend(quarterOfYear);
29
+ dayjs.extend(advancedFormat);
30
+ dayjs.extend(customParseFormat);
31
+ dayjs.extend(updateLocale);
32
+ dayjs.extend(isBetween);
33
+ dayjs.locale('zh-cn');
@@ -0,0 +1 @@
1
+ export * from '@fingerprintjs/fingerprintjs';
package/package.json CHANGED
@@ -1,95 +1,64 @@
1
- {
2
- "name": "@peng_kai/kit",
3
- "type": "module",
4
- "version": "0.3.0-beta.3",
5
- "description": "",
6
- "author": "",
7
- "license": "ISC",
8
- "keywords": [],
9
- "main": "index.js",
10
- "scripts": {
11
- "dev:js": "tsx ./admin/scripts/deploy.ts",
12
- "lint": "eslint .",
13
- "lint:fix": "eslint . --fix"
14
- },
15
- "peerDependencies": {
16
- "ant-design-vue": "4.2.5",
17
- "vue": "3.5.11",
18
- "vue-router": "4.4.5"
19
- },
20
- "dependencies": {
21
- "@aws-sdk/client-s3": "^3.667.0",
22
- "@aws-sdk/lib-storage": "^3.667.0",
23
- "@babel/generator": "^7.25.7",
24
- "@babel/parser": "^7.25.7",
25
- "@babel/traverse": "^7.25.7",
26
- "@babel/types": "^7.25.7",
27
- "@ckeditor/ckeditor5-vue": "^5.1.0",
28
- "@fingerprintjs/fingerprintjs": "^4.5.0",
29
- "@tanstack/vue-query": "^5.59.1",
30
- "@vueuse/components": "^11.1.0",
31
- "@vueuse/core": "^11.1.0",
32
- "@vueuse/router": "^11.1.0",
33
- "a-calc": "^2.2.10",
34
- "archiver": "^7.0.1",
35
- "axios": "^1.7.7",
36
- "bignumber.js": "^9.1.2",
37
- "chokidar": "^3.6.0",
38
- "crypto-es": "^2.1.0",
39
- "dayjs": "^1.11.13",
40
- "echarts": "^5.5.1",
41
- "execa": "^9.4.0",
42
- "fast-glob": "^3.3.2",
43
- "localstorage-slim": "^2.7.1",
44
- "lodash-es": "^4.17.21",
45
- "nprogress": "^0.2.0",
46
- "pinia": "^2.2.4",
47
- "tsx": "^4.16.00",
48
- "vue": "^3.5.11",
49
- "vue-i18n": "^10.0.4",
50
- "vue-router": "^4.4.5"
51
- },
52
- "devDependencies": {
53
- "@ckeditor/ckeditor5-adapter-ckfinder": "^41.1.0",
54
- "@ckeditor/ckeditor5-alignment": "^41.1.0",
55
- "@ckeditor/ckeditor5-autoformat": "^41.1.0",
56
- "@ckeditor/ckeditor5-basic-styles": "^41.1.0",
57
- "@ckeditor/ckeditor5-block-quote": "^41.1.0",
58
- "@ckeditor/ckeditor5-build-classic": "^41.1.0",
59
- "@ckeditor/ckeditor5-code-block": "^41.1.0",
60
- "@ckeditor/ckeditor5-document-outline": "^41.1.0",
61
- "@ckeditor/ckeditor5-editor-classic": "^41.1.0",
62
- "@ckeditor/ckeditor5-essentials": "^41.1.0",
63
- "@ckeditor/ckeditor5-font": "^41.1.0",
64
- "@ckeditor/ckeditor5-heading": "^41.1.0",
65
- "@ckeditor/ckeditor5-highlight": "^41.1.0",
66
- "@ckeditor/ckeditor5-horizontal-line": "^41.1.0",
67
- "@ckeditor/ckeditor5-html-embed": "^41.1.0",
68
- "@ckeditor/ckeditor5-html-support": "^41.1.0",
69
- "@ckeditor/ckeditor5-image": "^41.1.0",
70
- "@ckeditor/ckeditor5-import-word": "^41.1.0",
71
- "@ckeditor/ckeditor5-indent": "^41.1.0",
72
- "@ckeditor/ckeditor5-link": "^41.1.0",
73
- "@ckeditor/ckeditor5-list": "^41.1.0",
74
- "@ckeditor/ckeditor5-media-embed": "^41.1.0",
75
- "@ckeditor/ckeditor5-paragraph": "^41.1.0",
76
- "@ckeditor/ckeditor5-remove-format": "^41.1.0",
77
- "@ckeditor/ckeditor5-show-blocks": "^41.1.0",
78
- "@ckeditor/ckeditor5-source-editing": "^41.1.0",
79
- "@ckeditor/ckeditor5-table": "^41.1.0",
80
- "@ckeditor/ckeditor5-theme-lark": "^41.1.0",
81
- "@ckeditor/ckeditor5-typing": "^41.1.0",
82
- "@ckeditor/ckeditor5-upload": "^41.1.0",
83
- "@ckeditor/ckeditor5-word-count": "^41.1.0",
84
- "@peng_kai/lint": "^0.1.0",
85
- "@types/archiver": "^6.0.2",
86
- "@types/crypto-js": "^4.2.2",
87
- "@types/lodash-es": "^4.17.12",
88
- "@types/node": "^20.16.11",
89
- "@types/nprogress": "^0.2.3",
90
- "ant-design-vue": "^4.2.5",
91
- "type-fest": "^4.26.1",
92
- "typescript": "^5.6.3",
93
- "vue-component-type-helpers": "^2.1.6"
94
- }
95
- }
1
+ {
2
+ "name": "@peng_kai/kit",
3
+ "type": "module",
4
+ "version": "0.3.0-beta.30",
5
+ "description": "",
6
+ "author": "",
7
+ "license": "ISC",
8
+ "keywords": [],
9
+ "main": "index.js",
10
+ "scripts": {
11
+ "dev:js": "tsx ./admin/scripts/deploy.ts",
12
+ "lint": "eslint .",
13
+ "lint:fix": "eslint . --fix"
14
+ },
15
+ "peerDependencies": {
16
+ "ant-design-vue": "4.2.6",
17
+ "vue": "3.5.26",
18
+ "vue-router": "4.6.4"
19
+ },
20
+ "dependencies": {
21
+ "@aws-sdk/client-s3": "^3.891.0",
22
+ "@aws-sdk/lib-storage": "^3.891.0",
23
+ "@babel/generator": "^7.28.3",
24
+ "@babel/parser": "^7.28.4",
25
+ "@babel/traverse": "^7.28.4",
26
+ "@babel/types": "^7.28.4",
27
+ "@ckeditor/ckeditor5-vue": "^7.3.0",
28
+ "@fingerprintjs/fingerprintjs": "^5.0.1",
29
+ "@tanstack/vue-query": "^5.92.5",
30
+ "@vueuse/components": "^14.1.0",
31
+ "@vueuse/core": "^14.1.0",
32
+ "@vueuse/router": "^14.1.0",
33
+ "archiver": "^7.0.1",
34
+ "axios": "^1.13.2",
35
+ "bignumber.js": "^9.3.1",
36
+ "chokidar": "^4.0.3",
37
+ "crypto-es": "^3.1.2",
38
+ "dayjs": "^1.11.19",
39
+ "echarts": "^5.5.1",
40
+ "execa": "^9.6.0",
41
+ "fast-glob": "^3.3.3",
42
+ "fluid-dnd": "^2.6.2",
43
+ "localstorage-slim": "^2.7.1",
44
+ "lodash-es": "^4.17.21",
45
+ "nprogress": "^0.2.0",
46
+ "pinia": "^3.0.3",
47
+ "tsx": "^4.16.00",
48
+ "vue": "^3.5.21",
49
+ "vue-i18n": "^11.1.12",
50
+ "vue-router": "^4.5.1"
51
+ },
52
+ "devDependencies": {
53
+ "@peng_kai/lint": "^0.1.0",
54
+ "@types/archiver": "^7.0.0",
55
+ "@types/crypto-js": "^4.2.2",
56
+ "@types/lodash-es": "^4.17.12",
57
+ "@types/node": "^22.18.5",
58
+ "@types/nprogress": "^0.2.3",
59
+ "ant-design-vue": "^4.2.6",
60
+ "type-fest": "^5.0.0",
61
+ "typescript": "^5.9.2",
62
+ "vue-component-type-helpers": "^3.0.7"
63
+ }
64
+ }
@@ -25,6 +25,7 @@ export function getDeviceInfo(callback: (base: Record<string, any>, all: GetResu
25
25
  };
26
26
 
27
27
  req.headers.set('Device', callback(base, result));
28
+ req.headers.set('Device-Id', getDeviceID(base.visitor_id));
28
29
  req.headers.set('Accept-Date', getCurrentTimeZone());
29
30
 
30
31
  return req;
@@ -32,6 +33,19 @@ export function getDeviceInfo(callback: (base: Record<string, any>, all: GetResu
32
33
  ];
33
34
  }
34
35
 
36
+ function getDeviceID(visitorId: string) {
37
+ const key = 'backend_device_id';
38
+ let id = localStorage.getItem(key);
39
+ if (!id) {
40
+ id = visitorId
41
+ if (!id) {
42
+ id = crypto.randomUUID();
43
+ }
44
+ localStorage.setItem(key, id);
45
+ }
46
+ return id;
47
+ }
48
+
35
49
  function getCurrentTimeZone() {
36
50
  const now = new Date();
37
51
  const [_, time, tz, describe] = now.toString().match(/(\w{3} \w{3} \d{2} \d{4} \d{2}:\d{2}:\d{2})? (GMT[+-]\d{4}) \((.*?)\)/) ?? [];
@@ -63,7 +63,7 @@ export class LocaleManager {
63
63
 
64
64
  for (const target of localeTargets) {
65
65
  for (const codes of codeMatrix) {
66
- const matched = codes.some(code => code.toUpperCase().startsWith(target.toUpperCase()));
66
+ const matched = codes.some(code => target.toUpperCase().startsWith(code.toUpperCase()));
67
67
 
68
68
  if (matched) {
69
69
  localeFinal = codes[0];
package/utils/index.ts CHANGED
@@ -1,7 +1,4 @@
1
- import { Utf8 as cryptUtf8 } from 'crypto-es/lib/core';
2
- import { AES as cryptoAES } from 'crypto-es/lib/aes';
3
- import { ECB as cryptoModeECB } from 'crypto-es/lib/mode-ecb';
4
- import { Pkcs7 as cryptoPkcs7 } from 'crypto-es/lib/cipher-core';
1
+ import { Utf8 as cryptUtf8, AES as cryptoAES, ECB as cryptoModeECB, Pkcs7 as cryptoPkcs7 } from 'crypto-es';
5
2
  import { at as objAt } from 'lodash-es';
6
3
 
7
4
  export { desensitize, randomString } from './string';
@@ -65,7 +65,7 @@ export class LocaleManager {
65
65
 
66
66
  for (const target of localeTargets) {
67
67
  for (const codes of codeMatrix) {
68
- const matched = codes.some(code => code.toUpperCase().startsWith(target.toUpperCase()));
68
+ const matched = codes.some(code => target.toUpperCase().startsWith(code.toUpperCase()));
69
69
 
70
70
  if (matched) {
71
71
  localeFinal = codes[0];
@@ -92,6 +92,7 @@ export class LocaleManager {
92
92
  if (!this.localesAvailable.includes(locale))
93
93
  return;
94
94
 
95
+ // TODO: 这样可能无法支持code中的语言
95
96
  const message = await this.messageLoaders[locale]?.().catch(() => undefined);
96
97
 
97
98
  // 由于是异步加载,所以需要再判断是否已经加载过
@@ -1,3 +1,4 @@
1
+ import type { I18nOptions } from 'vue-i18n';
1
2
  import { omitBy } from '../../libs/lodash-es';
2
3
 
3
4
  /**
@@ -32,6 +33,14 @@ export function omitLocale(modules: Record<string, any>, excludes: string[] = []
32
33
  return omitBy(modules, (_, path) => excludes.some(locale => path.includes(locale)));
33
34
  }
34
35
 
36
+ /** 添加语言格式 */
37
+ export function addDatetimeFormat<T extends string>(name: T, config: NonNullable<I18nOptions['datetimeFormats']>[string][string]) {
38
+ return {
39
+ [name]: config,
40
+ [`${name}-utc`]: { ...config, timeZone: 'UTC' },
41
+ } as Record<T | `${T}-utc`, typeof config>;
42
+ }
43
+
35
44
  /**
36
45
  * 加密 JSON 消息
37
46
  */
package/utils/number.ts CHANGED
@@ -1,8 +1,6 @@
1
- import type { BigNumber } from 'bignumber.js';
2
1
  import bn from 'bignumber.js';
3
2
 
4
3
  export { default as bn } from 'bignumber.js';
5
- export { calc } from 'a-calc';
6
4
 
7
5
  /**
8
6
  * 常用的数值格式化规则
@@ -23,42 +21,42 @@ export const numFmt = {
23
21
  /** 舍去小数,四舍五入,千位符 */
24
22
  d0r5t: (num: any, fallback: any = 'NaN') => {
25
23
  const result = bn(num);
26
- return result.isNaN() ? fallback : result.decimalPlaces(0, bn.ROUND_HALF_UP).toFormat(0);
24
+ return result.isNaN() ? fallback : result.decimalPlaces(0, bn.ROUND_HALF_UP).toFormat();
27
25
  },
28
26
  /** 舍去小数,向下取整,千位符 */
29
27
  d0r0t: (num: any, fallback: any = 'NaN') => {
30
28
  const result = bn(num);
31
- return result.isNaN() ? fallback : result.decimalPlaces(0, bn.ROUND_DOWN).toFormat(0);
29
+ return result.isNaN() ? fallback : result.decimalPlaces(0, bn.ROUND_DOWN).toFormat();
32
30
  },
33
31
  /** 保留2位小数,四舍五入,千位符 */
34
32
  d2r5t: (num: any, fallback: any = 'NaN') => {
35
33
  const result = bn(num);
36
- return result.isNaN() ? fallback : result.decimalPlaces(2, bn.ROUND_HALF_UP).toFormat(2);
34
+ return result.isNaN() ? fallback : result.decimalPlaces(2, bn.ROUND_HALF_UP).toFormat();
37
35
  },
38
36
  /** 保留2位小数,向下取整,千位符 */
39
37
  d2r0t: (num: any, fallback: any = 'NaN') => {
40
38
  const result = bn(num);
41
- return result.isNaN() ? fallback : result.decimalPlaces(2, bn.ROUND_DOWN).toFormat(2);
39
+ return result.isNaN() ? fallback : result.decimalPlaces(2, bn.ROUND_DOWN).toFormat();
42
40
  },
43
41
  /** 保留6位小数,四舍五入,千位符 */
44
42
  d6r5t: (num: any, fallback: any = 'NaN') => {
45
43
  const result = bn(num);
46
- return result.isNaN() ? fallback : result.decimalPlaces(6, bn.ROUND_HALF_UP).toFormat(6);
44
+ return result.isNaN() ? fallback : result.decimalPlaces(6, bn.ROUND_HALF_UP).toFormat();
47
45
  },
48
46
  /** 保留6位小数,向下取整,千位符 */
49
47
  d6r0t: (num: any, fallback: any = 'NaN') => {
50
48
  const result = bn(num);
51
- return result.isNaN() ? fallback : result.decimalPlaces(6, bn.ROUND_DOWN).toFormat(6);
49
+ return result.isNaN() ? fallback : result.decimalPlaces(6, bn.ROUND_DOWN).toFormat();
52
50
  },
53
51
  /** 保留8位小数,四舍五入,千位符 */
54
52
  d8r5t: (num: any, fallback: any = 'NaN') => {
55
53
  const result = bn(num);
56
- return result.isNaN() ? fallback : result.decimalPlaces(8, bn.ROUND_HALF_UP).toFormat(8);
54
+ return result.isNaN() ? fallback : result.decimalPlaces(8, bn.ROUND_HALF_UP).toFormat();
57
55
  },
58
56
  /** 保留8位小数,向下取整,千位符 */
59
57
  d8r0t: (num: any, fallback: any = 'NaN') => {
60
58
  const result = bn(num);
61
- return result.isNaN() ? fallback : result.decimalPlaces(8, bn.ROUND_DOWN).toFormat(8);
59
+ return result.isNaN() ? fallback : result.decimalPlaces(8, bn.ROUND_DOWN).toFormat();
62
60
  },
63
61
  };
64
62
 
@@ -0,0 +1,31 @@
1
+ import { type MaybeRefOrGetter, computed, isReactive, reactive, toValue } from 'vue';
2
+
3
+ export class StorageKey<F extends Record<string, string | number>> {
4
+ public factors: F;
5
+ private split = '_';
6
+
7
+ public constructor(factors: F, private order: Array<keyof F>) {
8
+ this.factors = isReactive(factors) ? factors : reactive(factors) as F;
9
+ }
10
+
11
+ /**
12
+ * 构建存储键
13
+ * @param parts 键的部分
14
+ * @param excludeFactors 排除键的因素
15
+ */
16
+ public build(parts: Array<MaybeRefOrGetter<F[string]>>, excludeFactors: Array<keyof F> | boolean = false) {
17
+ const finalKey = computed(() => {
18
+ const thisKeys = parts.map(k => String(toValue(k)));
19
+ const factorKeys = Array.isArray(excludeFactors)
20
+ ? this.order.filter(k => !excludeFactors?.includes(k)).map(k => this.factors[k])
21
+ : excludeFactors
22
+ ? []
23
+ : this.order.map(k => this.factors[k]);
24
+ const thisStr = thisKeys.join(this.split);
25
+ const factorStr = factorKeys.join(this.split);
26
+ return `${factorStr}${factorStr ? this.split : ''}${thisStr}`;
27
+ });
28
+
29
+ return finalKey;
30
+ }
31
+ }
package/utils/string.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { Base64 } from 'crypto-es/lib/enc-base64';
2
- import { Utf8 } from 'crypto-es/lib/core';
1
+ import { Base64, Utf8 } from 'crypto-es';
3
2
 
4
3
  /**
5
4
  * 字符串脱敏,省略中间字符串
@@ -1,4 +1,4 @@
1
- import { S3Client } from '@aws-sdk/client-s3';
1
+ import { S3Client, ChecksumAlgorithm } from '@aws-sdk/client-s3';
2
2
  import { Upload } from '@aws-sdk/lib-storage';
3
3
  import type { FileHandler } from './fileHandlers';
4
4
 
@@ -20,16 +20,21 @@ export class AwsS3 {
20
20
  public constructor(private getParams: TGetParams, private fileHandler?: FileHandler) {
21
21
  }
22
22
 
23
- public async upload(file: File, root?: string) {
23
+ public async upload(file: File, root = 'unclassified') {
24
24
  const s3Client = await this.refreshClient();
25
- const filePath = await this.genFilePath(root || 'unclassified');
25
+ const filePath = root.includes('/') ? root : await this.genFilePath(root);
26
26
  const fileName = await (this.fileHandler?.genFileName?.(file) ?? this.genFileName(file));
27
27
  const fullPath = `${filePath}/${fileName}`;
28
28
 
29
29
  const uploader = new Upload({
30
30
  client: s3Client!,
31
- params: { Bucket: this.bucket, Key: fullPath, Body: file },
31
+ params: {
32
+ Bucket: this.bucket, Key: fullPath, Body: file,
33
+ ChecksumAlgorithm: ChecksumAlgorithm.CRC32,
34
+ },
32
35
  leavePartsOnError: false,
36
+ queueSize: 4,
37
+ partSize: 5 * 1024 * 1024,
33
38
  });
34
39
 
35
40
  return { uploader, fileURL: `${this.domain}/${fullPath}` };
@@ -61,6 +66,8 @@ export class AwsS3 {
61
66
  secretAccessKey: params.secretAccessKey,
62
67
  sessionToken: params.sessionToken,
63
68
  },
69
+ requestChecksumCalculation: 'WHEN_REQUIRED',
70
+ responseChecksumValidation: 'WHEN_REQUIRED',
64
71
  });
65
72
 
66
73
  return this.s3Client;
@@ -1,70 +0,0 @@
1
- <script setup lang="ts">
2
- import { TabPane as ATabPane, Tabs as ATabs } from 'ant-design-vue';
3
- import { injectTTAdmin } from '../../adminPlugin';
4
-
5
- const pageTabStore = injectTTAdmin()!.deps.usePageTabStore();
6
- </script>
7
-
8
- <template>
9
- <ATabs
10
- class="app-page-tabs"
11
- :activeKey="pageTabStore.activeTab"
12
- type="editable-card"
13
- size="small"
14
- :animated="false"
15
- :hideAdd="true"
16
- :tabBarGutter="4"
17
- @tabClick="(pageTabStore.openTab as any)"
18
- @edit="(pageTabStore.closeTab as any)"
19
- >
20
- <ATabPane v-for="tab of pageTabStore.tabList" :key="tab.key" :tab="tab.title">
21
- <template #closeIcon>
22
- <i class="i-icon-park-outline:close" />
23
- </template>
24
- </ATabPane>
25
- </ATabs>
26
- </template>
27
-
28
- <style scoped lang="scss">
29
- .app-page-tabs {
30
- :deep(.ant-tabs-nav) {
31
- margin: 0;
32
- }
33
-
34
- :deep(.ant-tabs-nav::before) {
35
- display: none;
36
- }
37
-
38
- :deep(.ant-tabs-tab) {
39
- --uno: 'border-rd-3px! text-14px p-[3px_1px_3px_8px]! select-none';
40
- }
41
-
42
- :deep(.ant-tabs-tab .ant-tabs-tab-btn) {
43
- transform: translateX(8px);
44
- }
45
-
46
- :deep(.ant-tabs-tab-active) {
47
- --uno: 'border-[currentColor]!';
48
- }
49
-
50
- :deep(.ant-tabs-tab-remove) {
51
- display: flex;
52
- height: 100%;
53
- align-items: center;
54
- margin: 0;
55
- opacity: 0;
56
- transition: all 150ms;
57
- }
58
-
59
- :deep(.ant-tabs-tab:hover .ant-tabs-tab-btn),
60
- :deep(.ant-tabs-tab-active .ant-tabs-tab-btn) {
61
- transform: translateX(0);
62
- }
63
-
64
- :deep(.ant-tabs-tab:hover .ant-tabs-tab-remove),
65
- :deep(.ant-tabs-tab-active .ant-tabs-tab-remove) {
66
- margin-left: 0;
67
- opacity: 1;
68
- }
69
- }
70
- </style>
@@ -1,11 +0,0 @@
1
- import type { Router } from 'vue-router';
2
- import { adminPlugin } from '../adminPlugin';
3
-
4
- export function setupCollapseMenu(router: Router) {
5
- const menuStore = adminPlugin.deps.useMenuStore();
6
-
7
- router.beforeEach(() => {
8
- menuStore.collapsed = false;
9
- return true;
10
- });
11
- }
package/libs/a-calc.ts DELETED
@@ -1 +0,0 @@
1
- export * from 'a-calc';
@@ -1,9 +0,0 @@
1
- <script setup lang="ts">
2
- import { useTestStore } from './testStore';
3
-
4
- useTestStore();
5
- </script>
6
-
7
- <template>
8
- <div>123</div>
9
- </template>
@@ -1,11 +0,0 @@
1
- import { useQueryClient } from '@tanstack/vue-query';
2
- import { defineStore } from 'pinia';
3
- import { useRouter } from 'vue-router';
4
-
5
- export const useTestStore = defineStore('test-store', () => {
6
- const router = useRouter();
7
- const queryClient = useQueryClient();
8
- console.log('🤡 / router:', router);
9
- console.log('🤡 / queryClient:', queryClient);
10
- return {};
11
- });