@gindow/vue 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.
@@ -0,0 +1,59 @@
1
+ import fileTypeChecker from 'file-type-checker'
2
+ import heic2any from 'heic2any'
3
+ import Compressor from 'compressorjs'
4
+
5
+ export const useUpload = () => {
6
+
7
+ const HEIC = (file: File): Promise<File> => {
8
+ return new Promise(async resolve => {
9
+ const blob = (await heic2any({ blob: file, toType: 'image/jpeg', quality: 0.9 }) as Blob)
10
+ const newFile = new File([blob], file.name, { type: blob.type, lastModified: Date.now() })
11
+ return resolve(newFile)
12
+ })
13
+ }
14
+
15
+ const compressor = (file: File): Promise<File> => {
16
+ return new Promise(resolve => {
17
+ new Compressor(file, { quality: 0.9, success: (file: File) => resolve(file) })
18
+ })
19
+ }
20
+
21
+ const handler = (
22
+ file: File,
23
+ para: { compressor: boolean } = { compressor: true }
24
+ ): Promise<File> => {
25
+ return new Promise(resolve => {
26
+ const reader = new FileReader()
27
+ reader.readAsArrayBuffer(file)
28
+ reader.onload = () => {
29
+ const isHeic = fileTypeChecker.validateFileType(reader.result as ArrayBuffer, ['heic'])
30
+ const isCompressor = fileTypeChecker.validateFileType(reader.result as ArrayBuffer, ['jpeg', 'png', 'gif', 'bmp'])
31
+ if (isHeic) resolve(HEIC(file))
32
+ else if (isCompressor && para.compressor) resolve(compressor(file))
33
+ else resolve(file)
34
+ }
35
+ })
36
+ }
37
+
38
+ const getDimension = async (blob: Blob): Promise<{ width: number; height: number }> => {
39
+ return new Promise((resolve, reject) => {
40
+ const img = new Image()
41
+ img.src = URL.createObjectURL(blob)
42
+ img.onload = () => resolve({ width: img.naturalWidth, height: img.naturalHeight })
43
+ img.onerror = (err) => reject(err)
44
+ })
45
+ }
46
+
47
+ const getFileType = (file: File): Promise<{ mimeType: string }> => {
48
+ return new Promise(resolve => {
49
+ const reader = new FileReader()
50
+ reader.readAsArrayBuffer(file)
51
+ reader.onload = () => {
52
+ const detectedFile = fileTypeChecker.detectFile(reader.result as ArrayBuffer)
53
+ resolve({ mimeType: detectedFile?.mimeType! })
54
+ }
55
+ })
56
+ }
57
+
58
+ return { handler, getDimension, getFileType }
59
+ }
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ import type { App, Plugin } from 'vue'
2
+ import { provider, setLocale, getLocale, useLocale } from './locale'
3
+ import './style.css'
4
+
5
+ const VueGo: Plugin = {
6
+ install(app, options?: { locale?: string; messages?: Record<string, any> }) {
7
+ provider(options)
8
+ app.config.globalProperties.$setLocale = setLocale
9
+ app.config.globalProperties.$getLocale = getLocale
10
+ },
11
+ }
12
+
13
+ export * from './types'
14
+ export * from './types/chat'
15
+ export * from './utils'
16
+ export { useBreak } from './hooks/useBreak'
17
+ export { useNanoid } from './hooks/useNanoid'
18
+ export { useCaptcha } from './hooks/useCaptcha'
19
+ export { useUpload } from './hooks/useUpload'
20
+ export { useChat } from './hooks/useChat'
21
+ export type { IChatMessage, IMessageEvent, IUsageEvent, IErrorEvent, ISendMessageParams } from './hooks/useChat'
22
+
23
+ export default VueGo
24
+
25
+ export {
26
+ setLocale,
27
+ getLocale,
28
+ useLocale,
29
+ }
@@ -0,0 +1,11 @@
1
+ export default {
2
+ cancel: 'Cancel',
3
+ confirm: 'Confirm',
4
+ empty: {
5
+ noData: 'No data',
6
+ },
7
+ dialog: {
8
+ tip: 'Tip',
9
+ confirm: 'Confirm',
10
+ },
11
+ }
@@ -0,0 +1,55 @@
1
+ import { 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('vue-go-locale')
18
+ const locale = ref<string>(getStoredLocale())
19
+ const messages: Messages = reactive({ 'en': enUS, 'zh-CN': zhCN })
20
+
21
+ export const provider = (opts?: { locale?: string; messages?: Messages }) => {
22
+ if (opts?.locale) locale.value = opts.locale
23
+ if (opts?.messages) {
24
+ for (const [key, value] of Object.entries(opts.messages)) {
25
+ messages[key] = value
26
+ }
27
+ }
28
+ provide(LOCALE_INJECTION_KEY, { locale, messages })
29
+ return { locale, messages }
30
+ }
31
+
32
+ export const useLocale = () => {
33
+ const injected = inject<{ locale: typeof locale; messages: typeof messages } | undefined>(LOCALE_INJECTION_KEY, undefined)
34
+ const currentLocale = injected?.locale ?? locale
35
+ const currentMessages = injected?.messages ?? messages
36
+
37
+ const t = (path: string, params?: Record<string, string | number>): string => {
38
+ const msg = currentMessages[currentLocale.value]
39
+ const keys = path.replace(/\[(\d+)]/g, '.$1').split('.')
40
+ let result: any = msg
41
+ for (const key of keys) {
42
+ result = result?.[key]
43
+ if (result === undefined) return path
44
+ }
45
+ let text = (result ?? path) as string
46
+ if (params && typeof text === 'string') text = text.replace(/\{(\w+)\}/g, (_, k) => params[k] !== undefined ? String(params[k]) : `{${k}}`)
47
+ return text
48
+ }
49
+
50
+ return { locale: currentLocale, t }
51
+ }
52
+
53
+ export const setLocale = (lang: string) => locale.value = lang
54
+
55
+ export const getLocale = () => locale.value
@@ -0,0 +1,11 @@
1
+ export default {
2
+ cancel: '取消',
3
+ confirm: '确认',
4
+ empty: {
5
+ noData: '暂无数据',
6
+ },
7
+ dialog: {
8
+ tip: '操作提示',
9
+ confirm: '操作确认',
10
+ },
11
+ }
package/src/style.css ADDED
@@ -0,0 +1,24 @@
1
+ /*
2
+ * vue-go 样式占位文件。
3
+ *
4
+ * vue-go 本身不包含 UI 组件,只提供基础样式工具类:
5
+ * - TailwindCSS 基础配置
6
+ * - 通用 flex 布局工具类
7
+ * - 通用文本颜色工具类(含暗黑模式)
8
+ *
9
+ * 实际组件样式以 SFC <style> 块的形式写在各 .vue 文件中:
10
+ * - npm 包模式:构建时由 Vite 提取并聚合到 dist/style.css
11
+ * - submodule 源码模式:消费者 import .vue 时由 vue 插件自动注入
12
+ */
13
+ @import "tailwindcss";
14
+
15
+ @source ".";
16
+
17
+ .flex-center { display: flex !important; align-items: center; justify-content: center; }
18
+ .flex-center-end { display: flex !important; align-items: center; justify-content: end; }
19
+ .flex-center-between { display: flex !important; align-items: center; justify-content: space-between; }
20
+ .flex-center-items { display: flex !important; align-items: center; }
21
+
22
+ .text-light { color: #ccc; }
23
+
24
+ .dark .text-light { color: #333; }
@@ -0,0 +1,62 @@
1
+ export type MessageRole = 'user' | 'assistant' | 'system'
2
+
3
+ export type MessageContentType = 'text' | 'image' | 'code' | 'file'
4
+
5
+ export interface IChatFile {
6
+ id: string
7
+ name: string
8
+ type: string
9
+ size: number
10
+ url?: string
11
+ thumbnail?: string
12
+ }
13
+
14
+ export interface IChatMessageItem {
15
+ id: string
16
+ role: MessageRole
17
+ content: string
18
+ contentType?: MessageContentType
19
+ timestamp: number
20
+ isLoading?: boolean
21
+ isError?: boolean
22
+ files?: IChatFile[]
23
+ metadata?: Record<string, any>
24
+ }
25
+
26
+ export interface IChatSession {
27
+ id: string
28
+ title: string
29
+ messages: IChatMessageItem[]
30
+ createdAt: number
31
+ updatedAt: number
32
+ isPinned?: boolean
33
+ isArchived?: boolean
34
+ }
35
+
36
+ export interface ISendChatParams {
37
+ content: string
38
+ contentType?: MessageContentType
39
+ files?: IChatFile[]
40
+ sessionId?: string
41
+ }
42
+
43
+ export interface IAIResponse {
44
+ message: IChatMessageItem
45
+ sessionId: string
46
+ suggestions?: string[]
47
+ }
48
+
49
+ export interface IChatConfig {
50
+ placeholder?: string
51
+ maxFileSize?: number
52
+ allowedFileTypes?: string[]
53
+ enableStreaming?: boolean
54
+ showTimestamp?: boolean
55
+ showSuggestions?: boolean
56
+ }
57
+
58
+ export interface ICodeBlock {
59
+ language: string
60
+ code: string
61
+ filename?: string
62
+ }
@@ -0,0 +1,74 @@
1
+ export interface IModel {
2
+ id?: string | any
3
+ created_at?: string
4
+ updated_at?: string
5
+ deleted_at?: string
6
+ [property: string]: any
7
+ }
8
+
9
+ export interface IAsset extends IModel {
10
+ id: string
11
+ type: string
12
+ title: string
13
+ url: string
14
+ shrink: string
15
+ }
16
+
17
+ export interface IField extends IModel {
18
+ name: string
19
+ type: string
20
+ readonly?: boolean
21
+ multiple?: boolean
22
+ required?: boolean
23
+ options?: { label: string; value: string }[] | any[]
24
+ }
25
+
26
+ export type IFilter = Omit<IField, 'name'> & { label?: string, rules?: any[] }
27
+
28
+ export interface IParams extends IModel {
29
+ filter?: Object
30
+ search?: string
31
+ include?: string
32
+ page?: number
33
+ size?: number
34
+ }
35
+
36
+ export interface IPagination {
37
+ current_page: number
38
+ per_page: number
39
+ count: number
40
+ total: number
41
+ total_pages: number
42
+ }
43
+
44
+ export interface IResult {
45
+ code: number
46
+ message: string
47
+ data?: IModel | IModel[] | null
48
+ meta?: { pagination?: IPagination }
49
+ }
50
+
51
+ export interface IUploadUserFile {
52
+ id?: string
53
+ percentage?: number
54
+ asset?: IAsset
55
+ title?: string
56
+ width?: number
57
+ height?: number
58
+ type?: string
59
+ mimeType?: string
60
+ }
61
+
62
+ export interface IMenu {
63
+ key?: string
64
+ title: string
65
+ path: string
66
+ name?: string
67
+ icon?: string
68
+ depend?: string
69
+ hidden?: boolean
70
+ divider?: boolean
71
+ disabled?: boolean
72
+ children?: IMenu[]
73
+ isGroup?: boolean
74
+ }
@@ -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,9 @@
1
+ export { request } from './request'
2
+ export { resource } from './request'
3
+ export { $params } from './request'
4
+ export { get } from './get'
5
+ export { download } from './download'
6
+ export { Formatter } from './formatter'
7
+ export { Validate } from './validate'
8
+ export { DateTime } from './datetime'
9
+ export { Platform } from './platform'
@@ -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
+ }
@@ -0,0 +1,146 @@
1
+ import type { AxiosInstance, AxiosResponse } from 'axios'
2
+ import type { IModel } from '../types'
3
+ import { Platform } from './platform'
4
+ import cookie from 'js-cookie'
5
+ import axios from 'axios'
6
+
7
+ const $params = (params: IModel) => {
8
+ const para = { ...params }
9
+ if (typeof para?.search === 'string') return para
10
+ if (para?.search)
11
+ para.search = Object.keys(para.search)
12
+ .filter(item => para.search[item] !== null && para.search[item] !== '')
13
+ .map(item => item + ':' + para.search[item])
14
+ .join(';')
15
+ if (para?.searchFields)
16
+ para.searchFields = Object.keys(para.searchFields)
17
+ .filter(item => para.searchFields[item])
18
+ .map(item => item + ':' + para.searchFields[item])
19
+ .join(';')
20
+ return para
21
+ }
22
+
23
+ export const request = {
24
+
25
+ baseURL: '',
26
+ publicKey: '',
27
+ headers: { Accept: 'application/json' } as Record<string, string>,
28
+ instance: null as AxiosInstance|null,
29
+ accessToken: 'accessToken',
30
+
31
+ init (config: { baseURL?: string, publicKey?: string } = {}) {
32
+ this.baseURL = config.baseURL ?? ''
33
+ this.publicKey = config.publicKey ?? ''
34
+
35
+ const reload = () => {
36
+ this.delToken()
37
+ location.reload()
38
+ }
39
+
40
+ this.instance = axios.create({ baseURL: this.baseURL })
41
+
42
+ this.instance.interceptors.request.use(config => {
43
+ const language = localStorage.getItem('locale')
44
+ if (language) config.headers['Accept-Language'] = language
45
+ return config
46
+ })
47
+
48
+ this.instance.interceptors.response.use((response: AxiosResponse) => {
49
+ if (response.config.responseType === 'blob') return response
50
+ else if (response.data.code === 401) return reload()
51
+ else if (response.data.code === 200) return response.data
52
+ else return Promise.reject(response.data)
53
+ }, ({ response }) => Promise.reject(response.data))
54
+ },
55
+
56
+ setToken (token: string, options: { expires?: number, domain?: string } = {}) {
57
+ options = { ...options, domain: '.' + location.hostname }
58
+ cookie.set(this.accessToken, token, options)
59
+ },
60
+
61
+ getToken () {
62
+ return cookie.get(this.accessToken) || ''
63
+ },
64
+
65
+ delToken () {
66
+ cookie.remove(this.accessToken, { domain: '.' + location.hostname })
67
+ },
68
+
69
+ get (url: string, params?: {}, auth = false) { return this.request({ method: 'GET', url, params }, auth) },
70
+ put (url: string, data?: {}, auth = false) { return this.request({ method: 'PUT', url, data }, auth) },
71
+ patch (url: string, data?: {}, auth = false) { return this.request({ method: 'PATCH', url, data }, auth) },
72
+ delete (url: string, params?: {}, auth = false) { return this.request({ method: 'DELETE', url, params }, auth) },
73
+ post (url: string, data?: {}, auth = false) { return this.request({ method: 'POST', url, data }, auth) },
74
+ blob (url: string, params?: {}, auth = false) { return this.request({ method: 'GET', url, params, responseType: 'blob' }, auth) },
75
+
76
+ request(para: any, auth: boolean = false) {
77
+ const headers = para.headers ?? this.headers
78
+ if (auth) headers.Authorization = 'Bearer ' + this.getToken()
79
+ if (para.params) para.params = $params(para.params)
80
+ return (this.instance as any)({ ...para, headers })
81
+ },
82
+
83
+ async download(url: string, params?: {}, filename?: string, auth = false) {
84
+ const ret = await this.blob(url, params, auth)
85
+ if (Platform.isFlutter) return ret
86
+ const getResponseFileName = () => {
87
+ const disposition = ret.headers['content-disposition']
88
+ const parts = disposition.split("filename*=")
89
+ const val = parts[1].split(";")[0].trim()
90
+ return decodeURIComponent(val.replace(/^UTF-8''/i, ''))
91
+ }
92
+ let link = document.createElement('a')
93
+ link.href = window.URL.createObjectURL(ret.data)
94
+ link.download = filename ?? getResponseFileName()
95
+ link.click()
96
+ return ret
97
+ },
98
+
99
+ async upload(url: string, data = {}) {
100
+ const headers = { ...this.headers, 'Content-Type': 'multipart/form-data' }
101
+ return this.instance!.post(url, data, { headers })
102
+ },
103
+
104
+ sse (url: string, para?: {[key: string]: string | number | undefined | null | void} | null) {
105
+ const params = para ? Object.keys(para).map(key => key +'='+ para[key]).join('&') : ''
106
+ return new EventSource(this.baseURL + '/' + url + '?' + params)
107
+ },
108
+
109
+ setHeader(key: string, value: string) {
110
+ this.headers[key] = value
111
+ },
112
+
113
+ delHeader(key: string) {
114
+ delete this.headers[key]
115
+ }
116
+ }
117
+
118
+ export class resource {
119
+
120
+ url: string
121
+ auth: boolean
122
+
123
+ constructor(url: string, auth = false) {
124
+ this.url = url
125
+ this.auth = auth
126
+ }
127
+
128
+ select = (para?: {}) => request.get(this.url, para, this.auth)
129
+
130
+ create = (para?: {}) => request.post(this.url, para, this.auth)
131
+
132
+ find = (id: string, para?: {}) => request.get(this.url + '/' + id, para, this.auth)
133
+
134
+ update = (id: string, para?: {}) => request.patch(this.url + '/' + id, para, this.auth)
135
+
136
+ delete = (id: string, para?: {}) => request.delete(this.url + '/' + id, para, this.auth)
137
+
138
+ async get(para: any) {
139
+ para.size = 1
140
+ const ret = await this.select(para)
141
+ ret.data = ret.data[0] || {}
142
+ return ret
143
+ }
144
+ }
145
+
146
+ export { $params }
@@ -0,0 +1,22 @@
1
+ export class Validate {
2
+
3
+ static country: string = ''
4
+
5
+ static set = (country: string) => this.country = country
6
+
7
+ static get phone_pattern () {
8
+ return this.country.toUpperCase() === 'CN'
9
+ ? /([1][3,4,5,6,7,8,9][0-9]{9})$/
10
+ : /^(?:\+?[1-9]\d{7,14}|\d{6,11})$/
11
+ }
12
+
13
+ static email_pattern = /^([a-zA-Z0-9_\.-]+)@([\da-zA-Z\.-]+)\.([a-zA-Z\.]{2,6})$/
14
+ static idcard_pattern = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
15
+ static cname_pattern = /^(?:[\u4e00-\u9fa5·]{2,16})$/
16
+ static password_pattern = /^(?![A-Za-z]+$)(?![0-9]+$)(?![^A-Za-z0-9]+$).{8,20}$/
17
+
18
+ static phone = (str: string) => Validate.phone_pattern.test(str)
19
+ static email = (str: string) => Validate.email_pattern.test(str)
20
+ static idcard = (str: string) => Validate.idcard_pattern.test(str)
21
+ static cname = (str: string) => Validate.cname_pattern.test(str)
22
+ }