@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.
- package/README.md +260 -0
- package/dist/element-go.cjs +1 -0
- package/dist/element-go.d.ts +1 -0
- package/dist/element-go.mjs +2994 -0
- package/dist/resolver.cjs +1 -0
- package/dist/resolver.d.ts +1 -0
- package/dist/resolver.mjs +16 -0
- package/dist/styles/index.css +2 -0
- package/package.json +133 -0
- package/src/assets/avatar.png +0 -0
- package/src/assets/icon.png +0 -0
- package/src/components/ExAssetPreview.vue +55 -0
- package/src/components/ExButton.vue +47 -0
- package/src/components/ExEmpty.vue +26 -0
- package/src/components/ExForm.vue +95 -0
- package/src/components/ExFormField.vue +49 -0
- package/src/components/ExFormSearch.vue +50 -0
- package/src/components/ExFormViewer.vue +51 -0
- package/src/components/ExIcon.vue +33 -0
- package/src/components/ExInputPercentage.vue +36 -0
- package/src/components/ExLayout/account.vue +33 -0
- package/src/components/ExLayout/aside.vue +58 -0
- package/src/components/ExLayout/lang.vue +27 -0
- package/src/components/ExLayout.vue +91 -0
- package/src/components/ExLoading.vue +18 -0
- package/src/components/ExMenu.vue +80 -0
- package/src/components/ExPage.vue +66 -0
- package/src/components/ExPageHeader.vue +34 -0
- package/src/components/ExPagination.vue +34 -0
- package/src/components/ExSelect.vue +28 -0
- package/src/components/ExTable.vue +237 -0
- package/src/components/ExTableColumn.vue +160 -0
- package/src/components/ExUpload.vue +91 -0
- package/src/components/ExUploadAsset.vue +299 -0
- package/src/components/vIcon.vue +23 -0
- package/src/env.d.ts +7 -0
- package/src/hooks/useBreak.ts +23 -0
- package/src/hooks/useChat.ts +135 -0
- package/src/hooks/useIcon.ts +8 -0
- package/src/hooks/useMessage.ts +22 -0
- package/src/hooks/useNanoid.ts +9 -0
- package/src/hooks/useUpload.ts +60 -0
- package/src/index.ts +94 -0
- package/src/libs/auto-imports.d.ts +94 -0
- package/src/libs/components.d.ts +171 -0
- package/src/locale/en-US.ts +49 -0
- package/src/locale/index.ts +73 -0
- package/src/locale/zh-CN.ts +49 -0
- package/src/resolver.ts +26 -0
- package/src/styles/arco.css +179 -0
- package/src/styles/index.css +53 -0
- package/src/types/index.ts +77 -0
- package/src/utils/datetime.ts +42 -0
- package/src/utils/download.ts +11 -0
- package/src/utils/formatter.ts +42 -0
- package/src/utils/get.ts +10 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/params.ts +18 -0
- package/src/utils/platform.ts +38 -0
- package/src/utils/request.ts +144 -0
- 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
|
+
}
|
package/src/resolver.ts
ADDED
|
@@ -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
|
+
}
|
package/src/utils/get.ts
ADDED
|
@@ -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
|
+
}
|