@gindow/element-go 1.0.0

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 (61) hide show
  1. package/README.md +260 -0
  2. package/dist/element-go.cjs +1 -0
  3. package/dist/element-go.d.ts +1 -0
  4. package/dist/element-go.mjs +2994 -0
  5. package/dist/resolver.cjs +1 -0
  6. package/dist/resolver.d.ts +1 -0
  7. package/dist/resolver.mjs +16 -0
  8. package/dist/styles/index.css +2 -0
  9. package/package.json +133 -0
  10. package/src/assets/avatar.png +0 -0
  11. package/src/assets/icon.png +0 -0
  12. package/src/components/ExAssetPreview.vue +55 -0
  13. package/src/components/ExButton.vue +47 -0
  14. package/src/components/ExEmpty.vue +26 -0
  15. package/src/components/ExForm.vue +95 -0
  16. package/src/components/ExFormField.vue +49 -0
  17. package/src/components/ExFormSearch.vue +50 -0
  18. package/src/components/ExFormViewer.vue +51 -0
  19. package/src/components/ExIcon.vue +33 -0
  20. package/src/components/ExInputPercentage.vue +36 -0
  21. package/src/components/ExLayout/account.vue +33 -0
  22. package/src/components/ExLayout/aside.vue +58 -0
  23. package/src/components/ExLayout/lang.vue +27 -0
  24. package/src/components/ExLayout.vue +91 -0
  25. package/src/components/ExLoading.vue +18 -0
  26. package/src/components/ExMenu.vue +80 -0
  27. package/src/components/ExPage.vue +66 -0
  28. package/src/components/ExPageHeader.vue +34 -0
  29. package/src/components/ExPagination.vue +34 -0
  30. package/src/components/ExSelect.vue +28 -0
  31. package/src/components/ExTable.vue +237 -0
  32. package/src/components/ExTableColumn.vue +160 -0
  33. package/src/components/ExUpload.vue +91 -0
  34. package/src/components/ExUploadAsset.vue +299 -0
  35. package/src/components/vIcon.vue +23 -0
  36. package/src/env.d.ts +7 -0
  37. package/src/hooks/useBreak.ts +23 -0
  38. package/src/hooks/useChat.ts +135 -0
  39. package/src/hooks/useIcon.ts +8 -0
  40. package/src/hooks/useMessage.ts +22 -0
  41. package/src/hooks/useNanoid.ts +9 -0
  42. package/src/hooks/useUpload.ts +60 -0
  43. package/src/index.ts +94 -0
  44. package/src/libs/auto-imports.d.ts +94 -0
  45. package/src/libs/components.d.ts +171 -0
  46. package/src/locale/en-US.ts +49 -0
  47. package/src/locale/index.ts +73 -0
  48. package/src/locale/zh-CN.ts +49 -0
  49. package/src/resolver.ts +26 -0
  50. package/src/styles/arco.css +179 -0
  51. package/src/styles/index.css +53 -0
  52. package/src/types/index.ts +77 -0
  53. package/src/utils/datetime.ts +42 -0
  54. package/src/utils/download.ts +11 -0
  55. package/src/utils/formatter.ts +42 -0
  56. package/src/utils/get.ts +10 -0
  57. package/src/utils/index.ts +8 -0
  58. package/src/utils/params.ts +18 -0
  59. package/src/utils/platform.ts +38 -0
  60. package/src/utils/request.ts +144 -0
  61. package/src/utils/validate.ts +23 -0
@@ -0,0 +1,73 @@
1
+ import { getCurrentInstance, inject, provide, reactive, ref } from 'vue'
2
+ import zhCN from './zh-CN'
3
+ import enUS from './en-US'
4
+
5
+ type Messages = Record<string, any>
6
+
7
+ const getStoredLocale = (): string => {
8
+ const availableCodes = ['en', 'zh-CN']
9
+ const storageLocale = localStorage.getItem('locale')
10
+ const browserLocale = navigator.language
11
+ if (storageLocale && availableCodes.includes(storageLocale)) return storageLocale
12
+ else if (browserLocale && availableCodes.includes(browserLocale as string)) return browserLocale as string // 完全匹配
13
+ else if (browserLocale && availableCodes.includes(browserLocale.split('-')[0] as string)) return browserLocale.split('-')[0] as string // 部分匹配
14
+ else return availableCodes[0] ?? 'zh-CN' // 未匹配
15
+ }
16
+
17
+ const LOCALE_INJECTION_KEY = Symbol('element-go-locale')
18
+ const locale = ref<string>(getStoredLocale())
19
+
20
+ /**
21
+ * element-go 自带的基础文案底座,**永不被 provider 覆盖**。
22
+ * 业务 app 只需在自己的 messages 里写业务 key;ex-* 组件用到的内置 key
23
+ * 始终能在这里兜底(含 app 自定义 locale 码如 en-KE / sw-KE,会回落到 en)。
24
+ */
25
+ const base: Messages = { 'en': enUS, 'en-US': enUS, 'zh-CN': zhCN }
26
+ const messages: Messages = reactive({ 'en': enUS, 'zh-CN': zhCN })
27
+
28
+ /** 取语言族兜底码:zh* → zh-CN,其余 → en */
29
+ const fallbackCode = (code: string): string => (code.toLowerCase().startsWith('zh') ? 'zh-CN' : 'en')
30
+
31
+ /** 按 a.b.c / a[0].b 路径深取;取不到返回 undefined */
32
+ const deepGet = (obj: Messages | undefined, keys: string[]): unknown => {
33
+ let result: any = obj
34
+ for (const key of keys) {
35
+ result = result?.[key]
36
+ if (result === undefined) return undefined
37
+ }
38
+ return result
39
+ }
40
+
41
+ export const provider = (opts?: { locale?: string; messages?: Messages }) => {
42
+ if (opts?.locale) locale.value = opts.locale
43
+ if (opts?.messages) {
44
+ for (const [key, value] of Object.entries(opts.messages)) {
45
+ messages[key] = value
46
+ }
47
+ }
48
+ if (getCurrentInstance()) provide(LOCALE_INJECTION_KEY, { locale, messages })
49
+ return { locale, messages }
50
+ }
51
+
52
+ export const useLocale = () => {
53
+ const injected = inject<{ locale: typeof locale; messages: typeof messages } | undefined>(LOCALE_INJECTION_KEY, undefined)
54
+ const currentLocale = injected?.locale ?? locale
55
+ const currentMessages = injected?.messages ?? messages
56
+
57
+ const t = (path: string, params?: Record<string, string | number>): string => {
58
+ const keys = path.replace(/\[(\d+)]/g, '.$1').split('.')
59
+ // 1) 先查当前 locale 的 app messages
60
+ let result = deepGet(currentMessages[currentLocale.value], keys)
61
+ // 2) 查不到 → 回落到 element-go 自带 base(按语言族),保证 ex-* 文案永远有值
62
+ if (result === undefined) result = deepGet(base[fallbackCode(currentLocale.value)], keys)
63
+ let text = (result ?? path) as string
64
+ if (params && typeof text === 'string') text = text.replace(/\{(\w+)\}/g, (_, k) => params[k] !== undefined ? String(params[k]) : `{${k}}`)
65
+ return text
66
+ }
67
+
68
+ return { locale: currentLocale, t }
69
+ }
70
+
71
+ export const setLocale = (lang: string) => locale.value = lang
72
+
73
+ export const getLocale = () => locale.value
@@ -0,0 +1,49 @@
1
+ export default {
2
+ core: {
3
+ back: '返回',
4
+ save: '保存',
5
+ cancel: '取消',
6
+ reset: '重置',
7
+ search: '查询',
8
+ keywords: '关键字',
9
+ upload: '上传文件',
10
+ confirm: '确认',
11
+ phoneNumber: '手机号码',
12
+ createdAt: '创建时间',
13
+ noPermission: '暂无权限',
14
+ create: '新建',
15
+ edit: '编辑',
16
+ delete: '删除',
17
+ sort: '排序',
18
+ logout: '退出',
19
+ profile: '个人中心',
20
+ password: '密码',
21
+ datetime: {
22
+ to: '至',
23
+ start: '开始日期',
24
+ end: '结束日期',
25
+ yesterday: '昨天',
26
+ today: '今天',
27
+ thisWeek: '本周',
28
+ thisMonth: '本月',
29
+ thisYear: '本年',
30
+ },
31
+ message: {
32
+ successful: '操作成功',
33
+ downloadFailed: '下载失败',
34
+ tooLarge: '文件超过大小限制',
35
+ fileExceed: '最多只能上传 {limit} 个文件',
36
+ confirm: '确认',
37
+ delConfirm: '确定要删除该条记录吗?',
38
+ },
39
+ },
40
+ empty: {
41
+ noData: '暂无数据',
42
+ },
43
+ dialog: {
44
+ tip: '操作提示',
45
+ confirm: '操作确认',
46
+ prompt: '请输入',
47
+ required: '必填项',
48
+ },
49
+ }
@@ -0,0 +1,26 @@
1
+ export interface ElementGoResolverOptions {
2
+ /**
3
+ * 是否自动导入 element-go 的聚合样式文件。
4
+ * 默认 true:每次解析到 Ex* 组件时附带 `element-go/styles/index.css` 副作用导入
5
+ * (unplugin-vue-components 会去重,不会重复打包)。
6
+ * 设为 false 时需在应用入口手动 `import 'element-go/styles/index.css'`。
7
+ */
8
+ importStyle?: boolean
9
+ /** 自定义前缀,默认 'Ex' */
10
+ prefix?: string
11
+ }
12
+
13
+ export function ElementGoResolver(options: ElementGoResolverOptions = {}) {
14
+ const { importStyle = true, prefix = 'Ex' } = options
15
+ return {
16
+ type: 'component' as const,
17
+ resolve(name: string) {
18
+ if (!name.startsWith(prefix)) return
19
+ return {
20
+ name,
21
+ from: 'element-go',
22
+ sideEffects: importStyle ? 'element-go/styles/index.css' : undefined,
23
+ }
24
+ },
25
+ }
26
+ }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Arco Design 风格主题 —— 把 Arco 设计令牌映射成 Element Plus 支持的 CSS 变量(--el-*)。
3
+ *
4
+ * 用法:在应用入口、element-go 基础样式之后引入即可:
5
+ * import 'element-go/styles/arco.css'
6
+ *
7
+ * 说明:
8
+ * - 选择器用 `html:root` / `html.dark:root` 提升优先级,确保覆盖 element-plus 与
9
+ * element-go 基础变量,且不依赖 import 顺序。
10
+ * - 亮色用 Arco 官方调色板原值;暗色中性色用 Arco 暗色面板原值,语义色的
11
+ * light-* 派生用 color-mix 按 Element Plus 的混色规则从基色推导(向暗背景混合)。
12
+ */
13
+
14
+ /* ============ 亮色 ============ */
15
+ html:root {
16
+ /* 主色 arcoblue(蓝 1~9 取自 Arco 调色板) */
17
+ --el-color-primary: #165dff;
18
+ --el-color-primary-light-3: #4080ff;
19
+ --el-color-primary-light-5: #6aa1ff;
20
+ --el-color-primary-light-7: #94bfff;
21
+ --el-color-primary-light-8: #bedaff;
22
+ --el-color-primary-light-9: #e8f3ff;
23
+ --el-color-primary-dark-2: #0e42d2;
24
+
25
+ /* 成功 green */
26
+ --el-color-success: #00b42a;
27
+ --el-color-success-light-3: #23c343;
28
+ --el-color-success-light-5: #4cd263;
29
+ --el-color-success-light-7: #7be188;
30
+ --el-color-success-light-8: #aff0b5;
31
+ --el-color-success-light-9: #e8ffea;
32
+ --el-color-success-dark-2: #009a29;
33
+
34
+ /* 警告 orange */
35
+ --el-color-warning: #ff7d00;
36
+ --el-color-warning-light-3: #ff9a2e;
37
+ --el-color-warning-light-5: #ffb65d;
38
+ --el-color-warning-light-7: #ffcf8b;
39
+ --el-color-warning-light-8: #ffe4ba;
40
+ --el-color-warning-light-9: #fff7e8;
41
+ --el-color-warning-dark-2: #d25f00;
42
+
43
+ /* 危险 / 错误 red(Element Plus 同时用 danger 与 error 两套变量) */
44
+ --el-color-danger: #f53f3f;
45
+ --el-color-danger-light-3: #f76560;
46
+ --el-color-danger-light-5: #f98981;
47
+ --el-color-danger-light-7: #fbaca3;
48
+ --el-color-danger-light-8: #fdcdc5;
49
+ --el-color-danger-light-9: #ffece8;
50
+ --el-color-danger-dark-2: #cb272d;
51
+ --el-color-error: #f53f3f;
52
+ --el-color-error-light-3: #f76560;
53
+ --el-color-error-light-5: #f98981;
54
+ --el-color-error-light-7: #fbaca3;
55
+ --el-color-error-light-8: #fdcdc5;
56
+ --el-color-error-light-9: #ffece8;
57
+ --el-color-error-dark-2: #cb272d;
58
+
59
+ /* 信息 gray */
60
+ --el-color-info: #86909c;
61
+ --el-color-info-light-3: #a9aeb8;
62
+ --el-color-info-light-5: #c9cdd4;
63
+ --el-color-info-light-7: #e5e6eb;
64
+ --el-color-info-light-8: #f2f3f5;
65
+ --el-color-info-light-9: #f7f8fa;
66
+ --el-color-info-dark-2: #6b7785;
67
+
68
+ /* 文本 text 1~4 */
69
+ --el-text-color-primary: #1d2129;
70
+ --el-text-color-regular: #4e5969;
71
+ --el-text-color-secondary: #86909c;
72
+ --el-text-color-placeholder: #a9aeb8;
73
+ --el-text-color-disabled: #c9cdd4;
74
+
75
+ /* 边框 */
76
+ --el-border-color-darker: #a9aeb8;
77
+ --el-border-color-dark: #c9cdd4;
78
+ --el-border-color: #e5e6eb;
79
+ --el-border-color-light: #e5e6eb;
80
+ --el-border-color-lighter: #f2f3f5;
81
+ --el-border-color-extra-light: #f7f8fa;
82
+
83
+ /* 填充 fill 1~4 */
84
+ --el-fill-color-darker: #c9cdd4;
85
+ --el-fill-color-dark: #e5e6eb;
86
+ --el-fill-color: #f2f3f5;
87
+ --el-fill-color-light: #f2f3f5;
88
+ --el-fill-color-lighter: #f7f8fa;
89
+ --el-fill-color-blank: #ffffff;
90
+
91
+ /* 背景 */
92
+ --el-bg-color: #ffffff;
93
+ --el-bg-color-page: #f7f8fa;
94
+ --el-bg-color-overlay: #ffffff;
95
+
96
+ /* 圆角(Arco:medium 4 / small 2 / round) */
97
+ --el-border-radius-base: 4px;
98
+ --el-border-radius-small: 2px;
99
+ --el-border-radius-round: 20px;
100
+
101
+ /* 字体(Arco 系统字体栈) */
102
+ --el-font-family: -apple-system, blinkmacsystemfont, 'PingFang SC', 'Helvetica Neue', helvetica, 'Microsoft YaHei', arial, sans-serif;
103
+ }
104
+
105
+ /* ============ 暗色(Arco 暗色面板,html.dark 时生效) ============ */
106
+ html.dark:root {
107
+ /* 中性色取自 Arco 暗色 bg/text/border/fill 调色板 */
108
+ --el-bg-color: #232324;
109
+ --el-bg-color-page: #17171a;
110
+ --el-bg-color-overlay: #2a2a2b;
111
+
112
+ --el-text-color-primary: rgba(255, 255, 255, 0.9);
113
+ --el-text-color-regular: rgba(255, 255, 255, 0.7);
114
+ --el-text-color-secondary: rgba(255, 255, 255, 0.5);
115
+ --el-text-color-placeholder: rgba(255, 255, 255, 0.35);
116
+ --el-text-color-disabled: rgba(255, 255, 255, 0.3);
117
+
118
+ --el-border-color-darker: #6b6b6c;
119
+ --el-border-color-dark: #5f5f60;
120
+ --el-border-color: #484849;
121
+ --el-border-color-light: #333335;
122
+ --el-border-color-lighter: #2a2a2b;
123
+ --el-border-color-extra-light: #232324;
124
+
125
+ --el-fill-color-darker: #484849;
126
+ --el-fill-color-dark: #373739;
127
+ --el-fill-color: #313132;
128
+ --el-fill-color-light: #2a2a2b;
129
+ --el-fill-color-lighter: #232324;
130
+ --el-fill-color-blank: transparent;
131
+
132
+ /* 语义色:暗色下基色提亮一档,light-* 用 color-mix 向暗背景(#17171a)混合派生 */
133
+ --el-color-primary: #3c7eff;
134
+ --el-color-primary-light-3: color-mix(in srgb, #3c7eff 70%, #17171a);
135
+ --el-color-primary-light-5: color-mix(in srgb, #3c7eff 50%, #17171a);
136
+ --el-color-primary-light-7: color-mix(in srgb, #3c7eff 30%, #17171a);
137
+ --el-color-primary-light-8: color-mix(in srgb, #3c7eff 20%, #17171a);
138
+ --el-color-primary-light-9: color-mix(in srgb, #3c7eff 10%, #17171a);
139
+ --el-color-primary-dark-2: color-mix(in srgb, #3c7eff 80%, #fff);
140
+
141
+ --el-color-success: #23c343;
142
+ --el-color-success-light-3: color-mix(in srgb, #23c343 70%, #17171a);
143
+ --el-color-success-light-5: color-mix(in srgb, #23c343 50%, #17171a);
144
+ --el-color-success-light-7: color-mix(in srgb, #23c343 30%, #17171a);
145
+ --el-color-success-light-8: color-mix(in srgb, #23c343 20%, #17171a);
146
+ --el-color-success-light-9: color-mix(in srgb, #23c343 10%, #17171a);
147
+ --el-color-success-dark-2: color-mix(in srgb, #23c343 80%, #fff);
148
+
149
+ --el-color-warning: #ff9a2e;
150
+ --el-color-warning-light-3: color-mix(in srgb, #ff9a2e 70%, #17171a);
151
+ --el-color-warning-light-5: color-mix(in srgb, #ff9a2e 50%, #17171a);
152
+ --el-color-warning-light-7: color-mix(in srgb, #ff9a2e 30%, #17171a);
153
+ --el-color-warning-light-8: color-mix(in srgb, #ff9a2e 20%, #17171a);
154
+ --el-color-warning-light-9: color-mix(in srgb, #ff9a2e 10%, #17171a);
155
+ --el-color-warning-dark-2: color-mix(in srgb, #ff9a2e 80%, #fff);
156
+
157
+ --el-color-danger: #f76560;
158
+ --el-color-danger-light-3: color-mix(in srgb, #f76560 70%, #17171a);
159
+ --el-color-danger-light-5: color-mix(in srgb, #f76560 50%, #17171a);
160
+ --el-color-danger-light-7: color-mix(in srgb, #f76560 30%, #17171a);
161
+ --el-color-danger-light-8: color-mix(in srgb, #f76560 20%, #17171a);
162
+ --el-color-danger-light-9: color-mix(in srgb, #f76560 10%, #17171a);
163
+ --el-color-danger-dark-2: color-mix(in srgb, #f76560 80%, #fff);
164
+ --el-color-error: #f76560;
165
+ --el-color-error-light-3: color-mix(in srgb, #f76560 70%, #17171a);
166
+ --el-color-error-light-5: color-mix(in srgb, #f76560 50%, #17171a);
167
+ --el-color-error-light-7: color-mix(in srgb, #f76560 30%, #17171a);
168
+ --el-color-error-light-8: color-mix(in srgb, #f76560 20%, #17171a);
169
+ --el-color-error-light-9: color-mix(in srgb, #f76560 10%, #17171a);
170
+ --el-color-error-dark-2: color-mix(in srgb, #f76560 80%, #fff);
171
+
172
+ --el-color-info: #86909c;
173
+ --el-color-info-light-3: color-mix(in srgb, #86909c 70%, #17171a);
174
+ --el-color-info-light-5: color-mix(in srgb, #86909c 50%, #17171a);
175
+ --el-color-info-light-7: color-mix(in srgb, #86909c 30%, #17171a);
176
+ --el-color-info-light-8: color-mix(in srgb, #86909c 20%, #17171a);
177
+ --el-color-info-light-9: color-mix(in srgb, #86909c 10%, #17171a);
178
+ --el-color-info-dark-2: color-mix(in srgb, #86909c 80%, #fff);
179
+ }
@@ -0,0 +1,53 @@
1
+ @import "tailwindcss";
2
+ @import "element-plus/dist/index.css";
3
+ @import "element-plus/theme-chalk/dark/css-vars.css";
4
+ @import "@gindow/vue/style.css";
5
+
6
+ @source "../";
7
+
8
+ /* @layer theme, base, components, utilities; */
9
+
10
+ /* @import "tailwindcss/theme.css" layer(theme); */
11
+ /* @import "tailwindcss/utilities.css" layer(utilities); */
12
+
13
+ .flex-center { display: flex !important; align-items: center; justify-content: center; }
14
+ .flex-center-end { display: flex !important; align-items: center; justify-content: end; }
15
+ .flex-center-between { display: flex !important; align-items: center; justify-content: space-between; }
16
+ .flex-center-items { display: flex !important; align-items: center; }
17
+
18
+ .text-light { color: #ccc; }
19
+
20
+ /* 暗黑模式 */
21
+ .dark .text-light { color: #333; }
22
+
23
+ /* Common */
24
+ .text-primary { color: var(--el-color-primary); }
25
+ .text-success { color: var(--el-color-success); }
26
+ .text-warning { color: var(--el-color-warning); }
27
+ .text-danger { color: var(--el-color-danger); }
28
+ .text-info { color: var(--el-color-info); }
29
+ .bg-color { background-color: var(--el-bg-color); }
30
+ .bg-color-page { background-color: var(--el-bg-color-page); }
31
+ .bg-color-overlay { background-color: var(--el-bg-color-overlay); }
32
+ .border-color { border-color: var(--el-border-color); }
33
+ .border-color-light { border-color: var(--el-border-color-light); }
34
+ .border-color-lighter { border-color: var(--el-border-color-lighter); }
35
+ .border-color-extra-light { border-color: var(--el-border-color-extra-light); }
36
+
37
+ /* Element Plus */
38
+ :root { --el-border-radius-base: 0; }
39
+ :root .el-button { --el-button-outline-color: transparent; }
40
+ :root .el-tag { --el-tag-border-radius: 0px; }
41
+
42
+ /* ExForm */
43
+ .ex-form .el-form-item { max-width: 500px; }
44
+ .ex-form .el-form-item:last-child { margin-bottom: 0; }
45
+ .ex-form-wide .el-form-item { max-width: 800px; }
46
+ .ex-form .el-input-number,
47
+ .ex-form .el-cascader,
48
+ .ex-form .el-radio-group,
49
+ .ex-form .el-checkbox-group,
50
+ .ex-form .el-date-editor { display: flex; width: 100%; }
51
+ .ex-form .el-radio-button, .ex-form .el-checkbox-button { display: flex; flex: 1; }
52
+ .ex-form .el-radio-button .el-radio-button__inner, .ex-form .el-checkbox-button .el-checkbox-button__inner { flex: 1; display: block; }
53
+ .ex-form .el-radio.is-bordered, .ex-form .el-checkbox.is-bordered { margin-right: 18px; }
@@ -0,0 +1,77 @@
1
+ import type { FormItemRule, UploadUserFile } from 'element-plus'
2
+
3
+ export interface IModel {
4
+ id?: string | any
5
+ created_at?: string
6
+ updated_at?: string
7
+ deleted_at?: string
8
+ [property: string]: any
9
+ }
10
+
11
+ export interface IField extends IModel {
12
+ name: string
13
+ type: string
14
+ readonly?: boolean
15
+ multiple?: boolean
16
+ required?: boolean
17
+ options?: { label: string; value: string }[] | any[]
18
+ component?: any // 自定义组
19
+ }
20
+
21
+ export type IFilter = Omit<IField, 'name'> & { label?: string, rules?: FormItemRule[] }
22
+
23
+ export interface IParams extends IModel {
24
+ filter?: Object
25
+ search?: string
26
+ include?: string
27
+ page?: number
28
+ size?: number
29
+ }
30
+
31
+ export interface IPagination {
32
+ current_page: number
33
+ per_page: number
34
+ count: number
35
+ total: number
36
+ total_pages: number
37
+ }
38
+
39
+ export interface IResult {
40
+ code: number
41
+ message: string
42
+ data?: IModel | IModel[] | null
43
+ meta?: { pagination?: IPagination }
44
+ }
45
+
46
+ export interface IAsset extends IModel {
47
+ id: string
48
+ type: string
49
+ title: string
50
+ url: string
51
+ shrink: string
52
+ }
53
+
54
+ export interface IUploadUserFile extends UploadUserFile {
55
+ id?: string
56
+ percentage?: number
57
+ asset?: IAsset
58
+ title?: string
59
+ width?: number
60
+ height?: number
61
+ type?: string
62
+ mimeType?: string
63
+ }
64
+
65
+ export interface IMenu {
66
+ key?: string
67
+ title: string
68
+ path: string
69
+ name?: string
70
+ icon?: string
71
+ depend?: string
72
+ hidden?: boolean
73
+ divider?: boolean
74
+ disabled?: boolean
75
+ children?: IMenu[]
76
+ isGroup?: boolean
77
+ }
@@ -0,0 +1,42 @@
1
+ import dayjs from 'dayjs'
2
+
3
+ export class DateTime {
4
+
5
+ static dayjs = dayjs
6
+
7
+ static s(date?: dayjs.ConfigType, symbol = '/') {
8
+ return DateTime.dayjs(date).format('YYYY/MM/DD HH:mm:ss'.replace(/\//g, symbol))
9
+ }
10
+
11
+ static m(date?: dayjs.ConfigType, symbol = '/') {
12
+ return DateTime.dayjs(date).format('YYYY/MM/DD HH:mm'.replace(/\//g, symbol))
13
+ }
14
+
15
+ static h(date?: dayjs.ConfigType, symbol = '/') {
16
+ return DateTime.dayjs(date).format('YYYY/MM/DD HH'.replace(/\//g, symbol))
17
+ }
18
+
19
+ static d(date?: dayjs.ConfigType, symbol = '/') {
20
+ return DateTime.dayjs(date).format('YYYY/MM/DD'.replace(/\//g, symbol))
21
+ }
22
+
23
+ static M(date?: dayjs.ConfigType, symbol = '/') {
24
+ return DateTime.dayjs(date).format('YYYY/MM'.replace(/\//g, symbol))
25
+ }
26
+
27
+ static y(date?: dayjs.ConfigType) {
28
+ return DateTime.dayjs(date).format('YYYY')
29
+ }
30
+
31
+ static date(date?: dayjs.ConfigType, symbol = '/') {
32
+ return DateTime.dayjs(date).format('YYYY/MM/DD'.replace(/\//g, symbol))
33
+ }
34
+
35
+ static time(date?: dayjs.ConfigType) {
36
+ return DateTime.dayjs(date).format('HH:mm')
37
+ }
38
+
39
+ static format(date?: dayjs.ConfigType, format = 'YYYY/MM/DD HH:mm:ss') {
40
+ return DateTime.dayjs(date).format(format)
41
+ }
42
+ }
@@ -0,0 +1,11 @@
1
+ export const download = (blob: Blob, filename: string) => {
2
+ const url = URL.createObjectURL(blob)
3
+ const a = document.createElement('a')
4
+ a.href = url
5
+ a.download = filename
6
+ a.style.display = 'none'
7
+ document.body.appendChild(a)
8
+ a.click()
9
+ document.body.removeChild(a)
10
+ URL.revokeObjectURL(url)
11
+ }
@@ -0,0 +1,42 @@
1
+ export class Formatter {
2
+
3
+ static config: {
4
+ locale?: string
5
+ currency?: string
6
+ decimals?: number
7
+ } = {}
8
+
9
+ static set = (config: { locale?: string, currency?: string, decimals?: number }) => this.config = config
10
+
11
+ static id = (str: string = '') => str.slice(-12).toUpperCase()
12
+
13
+ static date = (datestr: string = '') => datestr.substring(0, 10) + ' ' + datestr.substring(11, 19)
14
+
15
+ static idcard = (idcard: string = '') => idcard ? idcard.substring(0, 6) + '****' + idcard.substring(14) : ''
16
+
17
+ static phone = (phone: string = '', naked = false): string => naked || !phone ? phone : phone.substring(0, 3) + '****' + phone.substring(phone.length - 4)
18
+
19
+ static email = (email: string = '') => {
20
+ const [username, domain] = email.split('@')
21
+ if (!username || !domain) return email
22
+ const masked = username.length > 2 ? username[0] + '****' + username[username.length - 1] : username
23
+ return `${masked}@${domain}`
24
+ }
25
+
26
+ static bankcard = (bankcard: string = '') => bankcard.substring(0, 4) + '****' + bankcard.substring(bankcard.length - 4)
27
+
28
+ static url = (url: string = '') => url.replace(/:\/\//g, ':##').replace(/\/+/g, '/').replace(/:##/g, '://')
29
+
30
+ static price = (value: string | number = 0, currency?: string) => {
31
+ const { locale, decimals, currency: defaultCurrency } = this.config
32
+ const number = typeof value === 'string' ? parseFloat(value) : value
33
+ return new Intl.NumberFormat(locale, {
34
+ style: 'currency',
35
+ currency: currency ?? defaultCurrency ?? 'CNY',
36
+ minimumFractionDigits: decimals ?? 2,
37
+ maximumFractionDigits: decimals ?? 2,
38
+ }).format(number / 100)
39
+ }
40
+
41
+ static currency = (value: string | number = 0, currency?: string) => this.price(value, currency)
42
+ }
@@ -0,0 +1,10 @@
1
+ export const get = (object: any, path: string | string[], defaultValue?: any): any => {
2
+ if (object == null) return defaultValue
3
+ const keys = Array.isArray(path) ? path : path.replace(/\[(\d+)]/g, '.$1').split('.').filter(Boolean)
4
+ let result: any = object
5
+ for (const key of keys) {
6
+ result = result?.[key]
7
+ if (result === undefined) return defaultValue
8
+ }
9
+ return result
10
+ }
@@ -0,0 +1,8 @@
1
+ export { request } from './request'
2
+ export { get } from './get'
3
+ export { download } from './download'
4
+ export { Formatter } from './formatter'
5
+ export { Validate } from './validate'
6
+ export { DateTime } from './datetime'
7
+ export { Platform } from './platform'
8
+ export { $params } from './params'
@@ -0,0 +1,18 @@
1
+ import type { IModel } from '../types'
2
+
3
+ // 查询转化
4
+ export const $params = (params: IModel) => {
5
+ const para = { ...params }
6
+ if (typeof para?.search === 'string') return para
7
+ if (para?.search)
8
+ para.search = Object.keys(para.search)
9
+ .filter(item => para.search[item] !== null && para.search[item] !== '')
10
+ .map(item => item + ':' + para.search[item])
11
+ .join(';')
12
+ if (para?.searchFields)
13
+ para.searchFields = Object.keys(para.searchFields)
14
+ .filter(item => para.searchFields[item])
15
+ .map(item => item + ':' + para.searchFields[item])
16
+ .join(';')
17
+ return para
18
+ }
@@ -0,0 +1,38 @@
1
+ export class Platform {
2
+
3
+ static get userAgent() {
4
+ return window.navigator.userAgent.toLowerCase()
5
+ }
6
+
7
+ static get isFlutter() {
8
+ return Platform.userAgent.match(/flutter/i) !== null
9
+ }
10
+
11
+ static get isFlutterIOS() {
12
+ return Platform.isFlutter && Platform.isIOS
13
+ }
14
+
15
+ static get isWeb() {
16
+ return window.matchMedia('(min-width: 992px)').matches
17
+ }
18
+
19
+ static get isMobile() {
20
+ return Platform.userAgent.match(/(phone|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i) !== null
21
+ }
22
+
23
+ static get isIOS() {
24
+ return Platform.userAgent.match(/iphone|ipad|ipod|ios/i) !== null
25
+ }
26
+
27
+ static get isWechat() {
28
+ return Platform.userAgent.match(/MicroMessenger/i) !== null
29
+ }
30
+
31
+ static get isWxwork() {
32
+ return Platform.userAgent.match(/MicroMessenger/i) !== null && Platform.userAgent.match(/wxwork/i) !== null
33
+ }
34
+
35
+ static get isMiniprogram() {
36
+ return Platform.userAgent.match(/MicroMessenger/i) !== null && Platform.userAgent.match(/miniprogram/i) !== null
37
+ }
38
+ }