@ -0,0 +1,19 @@ |
|||
root = true |
|||
|
|||
[*] |
|||
charset=utf-8 |
|||
end_of_line=LF |
|||
insert_final_newline=true |
|||
indent_style=space |
|||
indent_size=2 |
|||
max_line_length = 100 |
|||
|
|||
[*.{yml,yaml,json}] |
|||
indent_style = space |
|||
indent_size = 2 |
|||
|
|||
[*.md] |
|||
trim_trailing_whitespace = false |
|||
|
|||
[Makefile] |
|||
indent_style = tab |
@ -0,0 +1,11 @@ |
|||
# port |
|||
VITE_PORT = 8081 |
|||
|
|||
# spa-title |
|||
VITE_GLOB_APP_TITLE = DcuiPlus |
|||
|
|||
# spa shortname |
|||
VITE_GLOB_APP_SHORT_NAME = DcuiPlus |
|||
|
|||
# 生产环境 开启mock |
|||
VITE_GLOB_PROD_MOCK = false |
@ -0,0 +1,31 @@ |
|||
# 只在开发模式中被载入 |
|||
VITE_PORT = 8081 |
|||
|
|||
# 网站根目录 |
|||
VITE_PUBLIC_PATH = / |
|||
|
|||
# 是否开启mock |
|||
VITE_USE_MOCK = false |
|||
|
|||
# 网站前缀 |
|||
VITE_BASE_URL = / |
|||
|
|||
# 是否删除console |
|||
VITE_DROP_CONSOLE = false |
|||
|
|||
# 跨域代理,可以配置多个,请注意不要换行 |
|||
#VITE_PROXY = [["/appApi","http://localhost:8001"],["/upload","http://localhost:8001/upload"]] |
|||
#VITE_PROXY=[["/api","http://10.10.10.56:9000"]] |
|||
|
|||
# API 接口地址 |
|||
VITE_GLOB_API_URL ="http://10.10.10.56:9000" |
|||
#VITE_GLOB_API_URL ="http://172.1.2.29:9000" |
|||
|
|||
# 图片上传地址 |
|||
VITE_GLOB_UPLOAD_URL= |
|||
|
|||
# 图片前缀地址 |
|||
VITE_GLOB_IMG_URL= |
|||
|
|||
# 接口前缀 |
|||
VITE_GLOB_API_URL_PREFIX = |
@ -0,0 +1,31 @@ |
|||
# 是否开启mock |
|||
VITE_USE_MOCK = false |
|||
|
|||
# 网站根目录 |
|||
VITE_PUBLIC_PATH = / |
|||
|
|||
# 网站前缀 |
|||
VITE_BASE_URL = / |
|||
|
|||
# 是否删除console |
|||
VITE_DROP_CONSOLE = true |
|||
|
|||
# API |
|||
VITE_GLOB_API_URL ="http://10.10.10.56:9000" |
|||
|
|||
# 图片上传地址 |
|||
VITE_GLOB_UPLOAD_URL= |
|||
|
|||
# 图片前缀地址 |
|||
VITE_GLOB_IMG_URL= |
|||
|
|||
# 接口前缀 |
|||
VITE_GLOB_API_URL_PREFIX = |
|||
|
|||
# 是否启用gzip压缩或brotli压缩 |
|||
# 可选: gzip | brotli | none |
|||
# 如果你需要多种形式,你可以用','来分隔 |
|||
VITE_BUILD_COMPRESS = 'none' |
|||
|
|||
# 使用压缩时是否删除原始文件,默认为false |
|||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false |
@ -0,0 +1,16 @@ |
|||
*.sh |
|||
node_modules |
|||
*.md |
|||
*.woff |
|||
*.ttf |
|||
.vscode |
|||
.idea |
|||
dist |
|||
/public |
|||
/docs |
|||
.husky |
|||
.local |
|||
/bin |
|||
Dockerfile |
|||
components.d.ts |
|||
components.d.ts |
@ -0,0 +1,71 @@ |
|||
// @ts-check
|
|||
const { defineConfig } = require('eslint-define-config'); |
|||
module.exports = defineConfig({ |
|||
root: true, |
|||
env: { |
|||
browser: true, |
|||
node: true, |
|||
es6: true, |
|||
}, |
|||
parser: 'vue-eslint-parser', |
|||
parserOptions: { |
|||
parser: '@typescript-eslint/parser', |
|||
ecmaVersion: 2020, |
|||
sourceType: 'module', |
|||
jsxPragma: 'React', |
|||
ecmaFeatures: { |
|||
jsx: true, |
|||
}, |
|||
}, |
|||
extends: [ |
|||
'plugin:vue/vue3-recommended', |
|||
'plugin:@typescript-eslint/recommended', |
|||
'prettier', |
|||
'plugin:prettier/recommended', |
|||
], |
|||
rules: { |
|||
'vue/script-setup-uses-vars': 'error', |
|||
'vue/multi-word-component-names': 'off', |
|||
'@typescript-eslint/ban-ts-ignore': 'off', |
|||
'@typescript-eslint/explicit-function-return-type': 'off', |
|||
'@typescript-eslint/no-explicit-any': 'off', |
|||
'@typescript-eslint/no-var-requires': 'off', |
|||
'@typescript-eslint/no-empty-function': 'off', |
|||
'vue/custom-event-name-casing': 'off', |
|||
'no-use-before-define': 'off', |
|||
'@typescript-eslint/no-use-before-define': 'off', |
|||
'@typescript-eslint/ban-ts-comment': 'off', |
|||
'@typescript-eslint/ban-types': 'off', |
|||
'@typescript-eslint/no-non-null-assertion': 'off', |
|||
'@typescript-eslint/explicit-module-boundary-types': 'off', |
|||
'@typescript-eslint/no-unused-vars': ['error', { varsIgnorePattern: '.*', args: 'none' }], |
|||
'no-unused-vars': [ |
|||
'error', |
|||
// we are only using this rule to check for unused arguments since TS
|
|||
// catches unused variables but not args.
|
|||
{ varsIgnorePattern: '.*', args: 'none' }, |
|||
], |
|||
'space-before-function-paren': 'off', |
|||
|
|||
'vue/attributes-order': 'off', |
|||
'vue/one-component-per-file': 'off', |
|||
'vue/html-closing-bracket-newline': 'off', |
|||
'vue/max-attributes-per-line': 'off', |
|||
'vue/multiline-html-element-content-newline': 'off', |
|||
'vue/singleline-html-element-content-newline': 'off', |
|||
'vue/attribute-hyphenation': 'off', |
|||
'vue/require-default-prop': 'off', |
|||
'vue/html-self-closing': [ |
|||
'error', |
|||
{ |
|||
html: { |
|||
void: 'always', |
|||
normal: 'never', |
|||
component: 'always', |
|||
}, |
|||
svg: 'always', |
|||
math: 'always', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
@ -0,0 +1,27 @@ |
|||
.DS_Store |
|||
node_modules |
|||
/screenshots |
|||
/dist |
|||
dist.zip |
|||
dist_electron |
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
|||
/components.d.ts |
|||
/components.d.ts |
@ -0,0 +1,9 @@ |
|||
/dist/* |
|||
.local |
|||
.output.js |
|||
/node_modules/** |
|||
|
|||
**/*.svg |
|||
**/*.sh |
|||
|
|||
/public/* |
@ -0,0 +1,3 @@ |
|||
/dist/* |
|||
/public/* |
|||
public/* |
@ -1,37 +1,16 @@ |
|||
# dc-ui-plus |
|||
|
|||
#### 介绍 |
|||
naive ui 实现 |
|||
> 联美运营驾驶舱管理系统 |
|||
|
|||
#### 软件架构 |
|||
软件架构说明 |
|||
## Build Setup |
|||
|
|||
``` bash |
|||
# install dependencies |
|||
npm install |
|||
|
|||
#### 安装教程 |
|||
# serve with hot reload at localhost:8081 |
|||
npm run dev |
|||
|
|||
1. xxxx |
|||
2. xxxx |
|||
3. xxxx |
|||
|
|||
#### 使用说明 |
|||
|
|||
1. xxxx |
|||
2. xxxx |
|||
3. xxxx |
|||
|
|||
#### 参与贡献 |
|||
|
|||
1. Fork 本仓库 |
|||
2. 新建 Feat_xxx 分支 |
|||
3. 提交代码 |
|||
4. 新建 Pull Request |
|||
|
|||
|
|||
#### 特技 |
|||
|
|||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md |
|||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) |
|||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 |
|||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 |
|||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) |
|||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) |
|||
# build for production with minification |
|||
npm run build |
|||
``` |
@ -0,0 +1,806 @@ |
|||
/* eslint-disable */ |
|||
/* prettier-ignore */ |
|||
// @ts-nocheck
|
|||
// noinspection JSUnusedGlobalSymbols
|
|||
// Generated by unplugin-auto-import
|
|||
export {} |
|||
declare global { |
|||
const EffectScope: typeof import('vue')['EffectScope'] |
|||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] |
|||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] |
|||
const computed: typeof import('vue')['computed'] |
|||
const computedAsync: typeof import('@vueuse/core')['computedAsync'] |
|||
const computedEager: typeof import('@vueuse/core')['computedEager'] |
|||
const computedInject: typeof import('@vueuse/core')['computedInject'] |
|||
const computedWithControl: typeof import('@vueuse/core')['computedWithControl'] |
|||
const controlledComputed: typeof import('@vueuse/core')['controlledComputed'] |
|||
const controlledRef: typeof import('@vueuse/core')['controlledRef'] |
|||
const createApp: typeof import('vue')['createApp'] |
|||
const createEventHook: typeof import('@vueuse/core')['createEventHook'] |
|||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] |
|||
const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] |
|||
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] |
|||
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] |
|||
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] |
|||
const customRef: typeof import('vue')['customRef'] |
|||
const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] |
|||
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch'] |
|||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] |
|||
const defineComponent: typeof import('vue')['defineComponent'] |
|||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed'] |
|||
const effectScope: typeof import('vue')['effectScope'] |
|||
const extendRef: typeof import('@vueuse/core')['extendRef'] |
|||
const getCurrentInstance: typeof import('vue')['getCurrentInstance'] |
|||
const getCurrentScope: typeof import('vue')['getCurrentScope'] |
|||
const h: typeof import('vue')['h'] |
|||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch'] |
|||
const inject: typeof import('vue')['inject'] |
|||
const isDefined: typeof import('@vueuse/core')['isDefined'] |
|||
const isProxy: typeof import('vue')['isProxy'] |
|||
const isReactive: typeof import('vue')['isReactive'] |
|||
const isReadonly: typeof import('vue')['isReadonly'] |
|||
const isRef: typeof import('vue')['isRef'] |
|||
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] |
|||
const markRaw: typeof import('vue')['markRaw'] |
|||
const nextTick: typeof import('vue')['nextTick'] |
|||
const onActivated: typeof import('vue')['onActivated'] |
|||
const onBeforeMount: typeof import('vue')['onBeforeMount'] |
|||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] |
|||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] |
|||
const onClickOutside: typeof import('@vueuse/core')['onClickOutside'] |
|||
const onDeactivated: typeof import('vue')['onDeactivated'] |
|||
const onErrorCaptured: typeof import('vue')['onErrorCaptured'] |
|||
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke'] |
|||
const onLongPress: typeof import('@vueuse/core')['onLongPress'] |
|||
const onMounted: typeof import('vue')['onMounted'] |
|||
const onRenderTracked: typeof import('vue')['onRenderTracked'] |
|||
const onRenderTriggered: typeof import('vue')['onRenderTriggered'] |
|||
const onScopeDispose: typeof import('vue')['onScopeDispose'] |
|||
const onServerPrefetch: typeof import('vue')['onServerPrefetch'] |
|||
const onStartTyping: typeof import('@vueuse/core')['onStartTyping'] |
|||
const onUnmounted: typeof import('vue')['onUnmounted'] |
|||
const onUpdated: typeof import('vue')['onUpdated'] |
|||
const pausableWatch: typeof import('@vueuse/core')['pausableWatch'] |
|||
const provide: typeof import('vue')['provide'] |
|||
const reactify: typeof import('@vueuse/core')['reactify'] |
|||
const reactifyObject: typeof import('@vueuse/core')['reactifyObject'] |
|||
const reactive: typeof import('vue')['reactive'] |
|||
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed'] |
|||
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit'] |
|||
const reactivePick: typeof import('@vueuse/core')['reactivePick'] |
|||
const readonly: typeof import('vue')['readonly'] |
|||
const ref: typeof import('vue')['ref'] |
|||
const refAutoReset: typeof import('@vueuse/core')['refAutoReset'] |
|||
const refDebounced: typeof import('@vueuse/core')['refDebounced'] |
|||
const refDefault: typeof import('@vueuse/core')['refDefault'] |
|||
const refThrottled: typeof import('@vueuse/core')['refThrottled'] |
|||
const refWithControl: typeof import('@vueuse/core')['refWithControl'] |
|||
const resolveComponent: typeof import('vue')['resolveComponent'] |
|||
const resolveRef: typeof import('@vueuse/core')['resolveRef'] |
|||
const resolveUnref: typeof import('@vueuse/core')['resolveUnref'] |
|||
const shallowReactive: typeof import('vue')['shallowReactive'] |
|||
const shallowReadonly: typeof import('vue')['shallowReadonly'] |
|||
const shallowRef: typeof import('vue')['shallowRef'] |
|||
const syncRef: typeof import('@vueuse/core')['syncRef'] |
|||
const syncRefs: typeof import('@vueuse/core')['syncRefs'] |
|||
const templateRef: typeof import('@vueuse/core')['templateRef'] |
|||
const throttledRef: typeof import('@vueuse/core')['throttledRef'] |
|||
const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] |
|||
const toRaw: typeof import('vue')['toRaw'] |
|||
const toReactive: typeof import('@vueuse/core')['toReactive'] |
|||
const toRef: typeof import('vue')['toRef'] |
|||
const toRefs: typeof import('vue')['toRefs'] |
|||
const toValue: typeof import('vue')['toValue'] |
|||
const triggerRef: typeof import('vue')['triggerRef'] |
|||
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] |
|||
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] |
|||
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted'] |
|||
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose'] |
|||
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted'] |
|||
const unref: typeof import('vue')['unref'] |
|||
const unrefElement: typeof import('@vueuse/core')['unrefElement'] |
|||
const until: typeof import('@vueuse/core')['until'] |
|||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] |
|||
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery'] |
|||
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter'] |
|||
const useArrayFind: typeof import('@vueuse/core')['useArrayFind'] |
|||
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex'] |
|||
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin'] |
|||
const useArrayMap: typeof import('@vueuse/core')['useArrayMap'] |
|||
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce'] |
|||
const useArraySome: typeof import('@vueuse/core')['useArraySome'] |
|||
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] |
|||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] |
|||
const useAttrs: typeof import('vue')['useAttrs'] |
|||
const useBase64: typeof import('@vueuse/core')['useBase64'] |
|||
const useBattery: typeof import('@vueuse/core')['useBattery'] |
|||
const useBluetooth: typeof import('@vueuse/core')['useBluetooth'] |
|||
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints'] |
|||
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] |
|||
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] |
|||
const useCached: typeof import('@vueuse/core')['useCached'] |
|||
const useClipboard: typeof import('@vueuse/core')['useClipboard'] |
|||
const useCloned: typeof import('@vueuse/core')['useCloned'] |
|||
const useColorMode: typeof import('@vueuse/core')['useColorMode'] |
|||
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] |
|||
const useCounter: typeof import('@vueuse/core')['useCounter'] |
|||
const useCssModule: typeof import('vue')['useCssModule'] |
|||
const useCssVar: typeof import('@vueuse/core')['useCssVar'] |
|||
const useCssVars: typeof import('vue')['useCssVars'] |
|||
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement'] |
|||
const useCycleList: typeof import('@vueuse/core')['useCycleList'] |
|||
const useDark: typeof import('@vueuse/core')['useDark'] |
|||
const useDateFormat: typeof import('@vueuse/core')['useDateFormat'] |
|||
const useDebounce: typeof import('@vueuse/core')['useDebounce'] |
|||
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn'] |
|||
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory'] |
|||
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion'] |
|||
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation'] |
|||
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio'] |
|||
const useDevicesList: typeof import('@vueuse/core')['useDevicesList'] |
|||
const useDialog: typeof import('naive-ui')['useDialog'] |
|||
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia'] |
|||
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility'] |
|||
const useDraggable: typeof import('@vueuse/core')['useDraggable'] |
|||
const useDropZone: typeof import('@vueuse/core')['useDropZone'] |
|||
const useElementBounding: typeof import('@vueuse/core')['useElementBounding'] |
|||
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint'] |
|||
const useElementHover: typeof import('@vueuse/core')['useElementHover'] |
|||
const useElementSize: typeof import('@vueuse/core')['useElementSize'] |
|||
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility'] |
|||
const useEventBus: typeof import('@vueuse/core')['useEventBus'] |
|||
const useEventListener: typeof import('@vueuse/core')['useEventListener'] |
|||
const useEventSource: typeof import('@vueuse/core')['useEventSource'] |
|||
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper'] |
|||
const useFavicon: typeof import('@vueuse/core')['useFavicon'] |
|||
const useFetch: typeof import('@vueuse/core')['useFetch'] |
|||
const useFileDialog: typeof import('@vueuse/core')['useFileDialog'] |
|||
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess'] |
|||
const useFocus: typeof import('@vueuse/core')['useFocus'] |
|||
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin'] |
|||
const useFps: typeof import('@vueuse/core')['useFps'] |
|||
const useFullscreen: typeof import('@vueuse/core')['useFullscreen'] |
|||
const useGamepad: typeof import('@vueuse/core')['useGamepad'] |
|||
const useGeolocation: typeof import('@vueuse/core')['useGeolocation'] |
|||
const useIdle: typeof import('@vueuse/core')['useIdle'] |
|||
const useImage: typeof import('@vueuse/core')['useImage'] |
|||
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll'] |
|||
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver'] |
|||
const useInterval: typeof import('@vueuse/core')['useInterval'] |
|||
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn'] |
|||
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier'] |
|||
const useLastChanged: typeof import('@vueuse/core')['useLastChanged'] |
|||
const useLoadingBar: typeof import('naive-ui')['useLoadingBar'] |
|||
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage'] |
|||
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys'] |
|||
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory'] |
|||
const useMediaControls: typeof import('@vueuse/core')['useMediaControls'] |
|||
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery'] |
|||
const useMemoize: typeof import('@vueuse/core')['useMemoize'] |
|||
const useMemory: typeof import('@vueuse/core')['useMemory'] |
|||
const useMessage: typeof import('naive-ui')['useMessage'] |
|||
const useMounted: typeof import('@vueuse/core')['useMounted'] |
|||
const useMouse: typeof import('@vueuse/core')['useMouse'] |
|||
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement'] |
|||
const useMousePressed: typeof import('@vueuse/core')['useMousePressed'] |
|||
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver'] |
|||
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage'] |
|||
const useNetwork: typeof import('@vueuse/core')['useNetwork'] |
|||
const useNotification: typeof import('naive-ui')['useNotification'] |
|||
const useNow: typeof import('@vueuse/core')['useNow'] |
|||
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl'] |
|||
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination'] |
|||
const useOnline: typeof import('@vueuse/core')['useOnline'] |
|||
const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] |
|||
const useParallax: typeof import('@vueuse/core')['useParallax'] |
|||
const usePermission: typeof import('@vueuse/core')['usePermission'] |
|||
const usePointer: typeof import('@vueuse/core')['usePointer'] |
|||
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] |
|||
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] |
|||
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] |
|||
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] |
|||
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] |
|||
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion'] |
|||
const useRafFn: typeof import('@vueuse/core')['useRafFn'] |
|||
const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] |
|||
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] |
|||
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation'] |
|||
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea'] |
|||
const useScriptTag: typeof import('@vueuse/core')['useScriptTag'] |
|||
const useScroll: typeof import('@vueuse/core')['useScroll'] |
|||
const useScrollLock: typeof import('@vueuse/core')['useScrollLock'] |
|||
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] |
|||
const useShare: typeof import('@vueuse/core')['useShare'] |
|||
const useSlots: typeof import('vue')['useSlots'] |
|||
const useSorted: typeof import('@vueuse/core')['useSorted'] |
|||
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] |
|||
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] |
|||
const useStepper: typeof import('@vueuse/core')['useStepper'] |
|||
const useStorage: typeof import('@vueuse/core')['useStorage'] |
|||
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] |
|||
const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] |
|||
const useSupported: typeof import('@vueuse/core')['useSupported'] |
|||
const useSwipe: typeof import('@vueuse/core')['useSwipe'] |
|||
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] |
|||
const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] |
|||
const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] |
|||
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] |
|||
const useThrottle: typeof import('@vueuse/core')['useThrottle'] |
|||
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn'] |
|||
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory'] |
|||
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo'] |
|||
const useTimeout: typeof import('@vueuse/core')['useTimeout'] |
|||
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn'] |
|||
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] |
|||
const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] |
|||
const useTitle: typeof import('@vueuse/core')['useTitle'] |
|||
const useToNumber: typeof import('@vueuse/core')['useToNumber'] |
|||
const useToString: typeof import('@vueuse/core')['useToString'] |
|||
const useToggle: typeof import('@vueuse/core')['useToggle'] |
|||
const useTransition: typeof import('@vueuse/core')['useTransition'] |
|||
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] |
|||
const useUserMedia: typeof import('@vueuse/core')['useUserMedia'] |
|||
const useVModel: typeof import('@vueuse/core')['useVModel'] |
|||
const useVModels: typeof import('@vueuse/core')['useVModels'] |
|||
const useVibrate: typeof import('@vueuse/core')['useVibrate'] |
|||
const useVirtualList: typeof import('@vueuse/core')['useVirtualList'] |
|||
const useWakeLock: typeof import('@vueuse/core')['useWakeLock'] |
|||
const useWebNotification: typeof import('@vueuse/core')['useWebNotification'] |
|||
const useWebSocket: typeof import('@vueuse/core')['useWebSocket'] |
|||
const useWebWorker: typeof import('@vueuse/core')['useWebWorker'] |
|||
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn'] |
|||
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus'] |
|||
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll'] |
|||
const useWindowSize: typeof import('@vueuse/core')['useWindowSize'] |
|||
const watch: typeof import('vue')['watch'] |
|||
const watchArray: typeof import('@vueuse/core')['watchArray'] |
|||
const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] |
|||
const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] |
|||
const watchEffect: typeof import('vue')['watchEffect'] |
|||
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] |
|||
const watchOnce: typeof import('@vueuse/core')['watchOnce'] |
|||
const watchPausable: typeof import('@vueuse/core')['watchPausable'] |
|||
const watchPostEffect: typeof import('vue')['watchPostEffect'] |
|||
const watchSyncEffect: typeof import('vue')['watchSyncEffect'] |
|||
const watchThrottled: typeof import('@vueuse/core')['watchThrottled'] |
|||
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable'] |
|||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter'] |
|||
const whenever: typeof import('@vueuse/core')['whenever'] |
|||
} |
|||
// for type re-export
|
|||
declare global { |
|||
// @ts-ignore
|
|||
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue' |
|||
} |
|||
// for vue template auto import
|
|||
import { UnwrapRef } from 'vue' |
|||
declare module 'vue' { |
|||
interface ComponentCustomProperties { |
|||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> |
|||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> |
|||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']> |
|||
readonly computed: UnwrapRef<typeof import('vue')['computed']> |
|||
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']> |
|||
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']> |
|||
readonly computedInject: UnwrapRef<typeof import('@vueuse/core')['computedInject']> |
|||
readonly computedWithControl: UnwrapRef<typeof import('@vueuse/core')['computedWithControl']> |
|||
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']> |
|||
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']> |
|||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']> |
|||
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']> |
|||
readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']> |
|||
readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']> |
|||
readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']> |
|||
readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']> |
|||
readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']> |
|||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']> |
|||
readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']> |
|||
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']> |
|||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']> |
|||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']> |
|||
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']> |
|||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']> |
|||
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']> |
|||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']> |
|||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']> |
|||
readonly h: UnwrapRef<typeof import('vue')['h']> |
|||
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']> |
|||
readonly inject: UnwrapRef<typeof import('vue')['inject']> |
|||
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']> |
|||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']> |
|||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> |
|||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> |
|||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']> |
|||
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']> |
|||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']> |
|||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> |
|||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']> |
|||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']> |
|||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']> |
|||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']> |
|||
readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']> |
|||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']> |
|||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']> |
|||
readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']> |
|||
readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']> |
|||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']> |
|||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']> |
|||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']> |
|||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']> |
|||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']> |
|||
readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']> |
|||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']> |
|||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']> |
|||
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']> |
|||
readonly provide: UnwrapRef<typeof import('vue')['provide']> |
|||
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']> |
|||
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']> |
|||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']> |
|||
readonly reactiveComputed: UnwrapRef<typeof import('@vueuse/core')['reactiveComputed']> |
|||
readonly reactiveOmit: UnwrapRef<typeof import('@vueuse/core')['reactiveOmit']> |
|||
readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']> |
|||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']> |
|||
readonly ref: UnwrapRef<typeof import('vue')['ref']> |
|||
readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']> |
|||
readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']> |
|||
readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']> |
|||
readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']> |
|||
readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']> |
|||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']> |
|||
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']> |
|||
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']> |
|||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']> |
|||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']> |
|||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']> |
|||
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']> |
|||
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']> |
|||
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']> |
|||
readonly throttledRef: UnwrapRef<typeof import('@vueuse/core')['throttledRef']> |
|||
readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']> |
|||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> |
|||
readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']> |
|||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']> |
|||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> |
|||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']> |
|||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> |
|||
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']> |
|||
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']> |
|||
readonly tryOnMounted: UnwrapRef<typeof import('@vueuse/core')['tryOnMounted']> |
|||
readonly tryOnScopeDispose: UnwrapRef<typeof import('@vueuse/core')['tryOnScopeDispose']> |
|||
readonly tryOnUnmounted: UnwrapRef<typeof import('@vueuse/core')['tryOnUnmounted']> |
|||
readonly unref: UnwrapRef<typeof import('vue')['unref']> |
|||
readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']> |
|||
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']> |
|||
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']> |
|||
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']> |
|||
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']> |
|||
readonly useArrayFind: UnwrapRef<typeof import('@vueuse/core')['useArrayFind']> |
|||
readonly useArrayFindIndex: UnwrapRef<typeof import('@vueuse/core')['useArrayFindIndex']> |
|||
readonly useArrayJoin: UnwrapRef<typeof import('@vueuse/core')['useArrayJoin']> |
|||
readonly useArrayMap: UnwrapRef<typeof import('@vueuse/core')['useArrayMap']> |
|||
readonly useArrayReduce: UnwrapRef<typeof import('@vueuse/core')['useArrayReduce']> |
|||
readonly useArraySome: UnwrapRef<typeof import('@vueuse/core')['useArraySome']> |
|||
readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']> |
|||
readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']> |
|||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> |
|||
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']> |
|||
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']> |
|||
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']> |
|||
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']> |
|||
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']> |
|||
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']> |
|||
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']> |
|||
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']> |
|||
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']> |
|||
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']> |
|||
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']> |
|||
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']> |
|||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']> |
|||
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']> |
|||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']> |
|||
readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']> |
|||
readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']> |
|||
readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']> |
|||
readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']> |
|||
readonly useDebounce: UnwrapRef<typeof import('@vueuse/core')['useDebounce']> |
|||
readonly useDebounceFn: UnwrapRef<typeof import('@vueuse/core')['useDebounceFn']> |
|||
readonly useDebouncedRefHistory: UnwrapRef<typeof import('@vueuse/core')['useDebouncedRefHistory']> |
|||
readonly useDeviceMotion: UnwrapRef<typeof import('@vueuse/core')['useDeviceMotion']> |
|||
readonly useDeviceOrientation: UnwrapRef<typeof import('@vueuse/core')['useDeviceOrientation']> |
|||
readonly useDevicePixelRatio: UnwrapRef<typeof import('@vueuse/core')['useDevicePixelRatio']> |
|||
readonly useDevicesList: UnwrapRef<typeof import('@vueuse/core')['useDevicesList']> |
|||
readonly useDialog: UnwrapRef<typeof import('naive-ui')['useDialog']> |
|||
readonly useDisplayMedia: UnwrapRef<typeof import('@vueuse/core')['useDisplayMedia']> |
|||
readonly useDocumentVisibility: UnwrapRef<typeof import('@vueuse/core')['useDocumentVisibility']> |
|||
readonly useDraggable: UnwrapRef<typeof import('@vueuse/core')['useDraggable']> |
|||
readonly useDropZone: UnwrapRef<typeof import('@vueuse/core')['useDropZone']> |
|||
readonly useElementBounding: UnwrapRef<typeof import('@vueuse/core')['useElementBounding']> |
|||
readonly useElementByPoint: UnwrapRef<typeof import('@vueuse/core')['useElementByPoint']> |
|||
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']> |
|||
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']> |
|||
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']> |
|||
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']> |
|||
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']> |
|||
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']> |
|||
readonly useEyeDropper: UnwrapRef<typeof import('@vueuse/core')['useEyeDropper']> |
|||
readonly useFavicon: UnwrapRef<typeof import('@vueuse/core')['useFavicon']> |
|||
readonly useFetch: UnwrapRef<typeof import('@vueuse/core')['useFetch']> |
|||
readonly useFileDialog: UnwrapRef<typeof import('@vueuse/core')['useFileDialog']> |
|||
readonly useFileSystemAccess: UnwrapRef<typeof import('@vueuse/core')['useFileSystemAccess']> |
|||
readonly useFocus: UnwrapRef<typeof import('@vueuse/core')['useFocus']> |
|||
readonly useFocusWithin: UnwrapRef<typeof import('@vueuse/core')['useFocusWithin']> |
|||
readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']> |
|||
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']> |
|||
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']> |
|||
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']> |
|||
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']> |
|||
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']> |
|||
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']> |
|||
readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']> |
|||
readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']> |
|||
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']> |
|||
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']> |
|||
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']> |
|||
readonly useLoadingBar: UnwrapRef<typeof import('naive-ui')['useLoadingBar']> |
|||
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']> |
|||
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']> |
|||
readonly useManualRefHistory: UnwrapRef<typeof import('@vueuse/core')['useManualRefHistory']> |
|||
readonly useMediaControls: UnwrapRef<typeof import('@vueuse/core')['useMediaControls']> |
|||
readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']> |
|||
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']> |
|||
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']> |
|||
readonly useMessage: UnwrapRef<typeof import('naive-ui')['useMessage']> |
|||
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']> |
|||
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']> |
|||
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']> |
|||
readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']> |
|||
readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']> |
|||
readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']> |
|||
readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']> |
|||
readonly useNotification: UnwrapRef<typeof import('naive-ui')['useNotification']> |
|||
readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']> |
|||
readonly useObjectUrl: UnwrapRef<typeof import('@vueuse/core')['useObjectUrl']> |
|||
readonly useOffsetPagination: UnwrapRef<typeof import('@vueuse/core')['useOffsetPagination']> |
|||
readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']> |
|||
readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']> |
|||
readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']> |
|||
readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']> |
|||
readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']> |
|||
readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']> |
|||
readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']> |
|||
readonly usePreferredContrast: UnwrapRef<typeof import('@vueuse/core')['usePreferredContrast']> |
|||
readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']> |
|||
readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']> |
|||
readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']> |
|||
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']> |
|||
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']> |
|||
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']> |
|||
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']> |
|||
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']> |
|||
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']> |
|||
readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']> |
|||
readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']> |
|||
readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']> |
|||
readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']> |
|||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> |
|||
readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']> |
|||
readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']> |
|||
readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']> |
|||
readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']> |
|||
readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']> |
|||
readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']> |
|||
readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']> |
|||
readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']> |
|||
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']> |
|||
readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']> |
|||
readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']> |
|||
readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']> |
|||
readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']> |
|||
readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']> |
|||
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']> |
|||
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']> |
|||
readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']> |
|||
readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']> |
|||
readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']> |
|||
readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']> |
|||
readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']> |
|||
readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']> |
|||
readonly useToNumber: UnwrapRef<typeof import('@vueuse/core')['useToNumber']> |
|||
readonly useToString: UnwrapRef<typeof import('@vueuse/core')['useToString']> |
|||
readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']> |
|||
readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']> |
|||
readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']> |
|||
readonly useUserMedia: UnwrapRef<typeof import('@vueuse/core')['useUserMedia']> |
|||
readonly useVModel: UnwrapRef<typeof import('@vueuse/core')['useVModel']> |
|||
readonly useVModels: UnwrapRef<typeof import('@vueuse/core')['useVModels']> |
|||
readonly useVibrate: UnwrapRef<typeof import('@vueuse/core')['useVibrate']> |
|||
readonly useVirtualList: UnwrapRef<typeof import('@vueuse/core')['useVirtualList']> |
|||
readonly useWakeLock: UnwrapRef<typeof import('@vueuse/core')['useWakeLock']> |
|||
readonly useWebNotification: UnwrapRef<typeof import('@vueuse/core')['useWebNotification']> |
|||
readonly useWebSocket: UnwrapRef<typeof import('@vueuse/core')['useWebSocket']> |
|||
readonly useWebWorker: UnwrapRef<typeof import('@vueuse/core')['useWebWorker']> |
|||
readonly useWebWorkerFn: UnwrapRef<typeof import('@vueuse/core')['useWebWorkerFn']> |
|||
readonly useWindowFocus: UnwrapRef<typeof import('@vueuse/core')['useWindowFocus']> |
|||
readonly useWindowScroll: UnwrapRef<typeof import('@vueuse/core')['useWindowScroll']> |
|||
readonly useWindowSize: UnwrapRef<typeof import('@vueuse/core')['useWindowSize']> |
|||
readonly watch: UnwrapRef<typeof import('vue')['watch']> |
|||
readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']> |
|||
readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']> |
|||
readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']> |
|||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> |
|||
readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']> |
|||
readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']> |
|||
readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']> |
|||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> |
|||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']> |
|||
readonly watchThrottled: UnwrapRef<typeof import('@vueuse/core')['watchThrottled']> |
|||
readonly watchTriggerable: UnwrapRef<typeof import('@vueuse/core')['watchTriggerable']> |
|||
readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']> |
|||
readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']> |
|||
} |
|||
} |
|||
declare module '@vue/runtime-core' { |
|||
interface ComponentCustomProperties { |
|||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> |
|||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> |
|||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']> |
|||
readonly computed: UnwrapRef<typeof import('vue')['computed']> |
|||
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']> |
|||
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']> |
|||
readonly computedInject: UnwrapRef<typeof import('@vueuse/core')['computedInject']> |
|||
readonly computedWithControl: UnwrapRef<typeof import('@vueuse/core')['computedWithControl']> |
|||
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']> |
|||
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']> |
|||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']> |
|||
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']> |
|||
readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']> |
|||
readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']> |
|||
readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']> |
|||
readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']> |
|||
readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']> |
|||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']> |
|||
readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']> |
|||
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']> |
|||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']> |
|||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']> |
|||
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']> |
|||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']> |
|||
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']> |
|||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']> |
|||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']> |
|||
readonly h: UnwrapRef<typeof import('vue')['h']> |
|||
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']> |
|||
readonly inject: UnwrapRef<typeof import('vue')['inject']> |
|||
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']> |
|||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']> |
|||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> |
|||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> |
|||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']> |
|||
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']> |
|||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']> |
|||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> |
|||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']> |
|||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']> |
|||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']> |
|||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']> |
|||
readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']> |
|||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']> |
|||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']> |
|||
readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']> |
|||
readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']> |
|||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']> |
|||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']> |
|||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']> |
|||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']> |
|||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']> |
|||
readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']> |
|||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']> |
|||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']> |
|||
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']> |
|||
readonly provide: UnwrapRef<typeof import('vue')['provide']> |
|||
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']> |
|||
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']> |
|||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']> |
|||
readonly reactiveComputed: UnwrapRef<typeof import('@vueuse/core')['reactiveComputed']> |
|||
readonly reactiveOmit: UnwrapRef<typeof import('@vueuse/core')['reactiveOmit']> |
|||
readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']> |
|||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']> |
|||
readonly ref: UnwrapRef<typeof import('vue')['ref']> |
|||
readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']> |
|||
readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']> |
|||
readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']> |
|||
readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']> |
|||
readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']> |
|||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']> |
|||
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']> |
|||
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']> |
|||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']> |
|||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']> |
|||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']> |
|||
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']> |
|||
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']> |
|||
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']> |
|||
readonly throttledRef: UnwrapRef<typeof import('@vueuse/core')['throttledRef']> |
|||
readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']> |
|||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> |
|||
readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']> |
|||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']> |
|||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> |
|||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']> |
|||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> |
|||
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']> |
|||
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']> |
|||
readonly tryOnMounted: UnwrapRef<typeof import('@vueuse/core')['tryOnMounted']> |
|||
readonly tryOnScopeDispose: UnwrapRef<typeof import('@vueuse/core')['tryOnScopeDispose']> |
|||
readonly tryOnUnmounted: UnwrapRef<typeof import('@vueuse/core')['tryOnUnmounted']> |
|||
readonly unref: UnwrapRef<typeof import('vue')['unref']> |
|||
readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']> |
|||
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']> |
|||
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']> |
|||
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']> |
|||
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']> |
|||
readonly useArrayFind: UnwrapRef<typeof import('@vueuse/core')['useArrayFind']> |
|||
readonly useArrayFindIndex: UnwrapRef<typeof import('@vueuse/core')['useArrayFindIndex']> |
|||
readonly useArrayJoin: UnwrapRef<typeof import('@vueuse/core')['useArrayJoin']> |
|||
readonly useArrayMap: UnwrapRef<typeof import('@vueuse/core')['useArrayMap']> |
|||
readonly useArrayReduce: UnwrapRef<typeof import('@vueuse/core')['useArrayReduce']> |
|||
readonly useArraySome: UnwrapRef<typeof import('@vueuse/core')['useArraySome']> |
|||
readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']> |
|||
readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']> |
|||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> |
|||
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']> |
|||
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']> |
|||
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']> |
|||
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']> |
|||
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']> |
|||
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']> |
|||
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']> |
|||
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']> |
|||
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']> |
|||
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']> |
|||
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']> |
|||
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']> |
|||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']> |
|||
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']> |
|||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']> |
|||
readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']> |
|||
readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']> |
|||
readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']> |
|||
readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']> |
|||
readonly useDebounce: UnwrapRef<typeof import('@vueuse/core')['useDebounce']> |
|||
readonly useDebounceFn: UnwrapRef<typeof import('@vueuse/core')['useDebounceFn']> |
|||
readonly useDebouncedRefHistory: UnwrapRef<typeof import('@vueuse/core')['useDebouncedRefHistory']> |
|||
readonly useDeviceMotion: UnwrapRef<typeof import('@vueuse/core')['useDeviceMotion']> |
|||
readonly useDeviceOrientation: UnwrapRef<typeof import('@vueuse/core')['useDeviceOrientation']> |
|||
readonly useDevicePixelRatio: UnwrapRef<typeof import('@vueuse/core')['useDevicePixelRatio']> |
|||
readonly useDevicesList: UnwrapRef<typeof import('@vueuse/core')['useDevicesList']> |
|||
readonly useDialog: UnwrapRef<typeof import('naive-ui')['useDialog']> |
|||
readonly useDisplayMedia: UnwrapRef<typeof import('@vueuse/core')['useDisplayMedia']> |
|||
readonly useDocumentVisibility: UnwrapRef<typeof import('@vueuse/core')['useDocumentVisibility']> |
|||
readonly useDraggable: UnwrapRef<typeof import('@vueuse/core')['useDraggable']> |
|||
readonly useDropZone: UnwrapRef<typeof import('@vueuse/core')['useDropZone']> |
|||
readonly useElementBounding: UnwrapRef<typeof import('@vueuse/core')['useElementBounding']> |
|||
readonly useElementByPoint: UnwrapRef<typeof import('@vueuse/core')['useElementByPoint']> |
|||
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']> |
|||
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']> |
|||
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']> |
|||
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']> |
|||
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']> |
|||
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']> |
|||
readonly useEyeDropper: UnwrapRef<typeof import('@vueuse/core')['useEyeDropper']> |
|||
readonly useFavicon: UnwrapRef<typeof import('@vueuse/core')['useFavicon']> |
|||
readonly useFetch: UnwrapRef<typeof import('@vueuse/core')['useFetch']> |
|||
readonly useFileDialog: UnwrapRef<typeof import('@vueuse/core')['useFileDialog']> |
|||
readonly useFileSystemAccess: UnwrapRef<typeof import('@vueuse/core')['useFileSystemAccess']> |
|||
readonly useFocus: UnwrapRef<typeof import('@vueuse/core')['useFocus']> |
|||
readonly useFocusWithin: UnwrapRef<typeof import('@vueuse/core')['useFocusWithin']> |
|||
readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']> |
|||
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']> |
|||
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']> |
|||
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']> |
|||
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']> |
|||
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']> |
|||
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']> |
|||
readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']> |
|||
readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']> |
|||
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']> |
|||
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']> |
|||
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']> |
|||
readonly useLoadingBar: UnwrapRef<typeof import('naive-ui')['useLoadingBar']> |
|||
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']> |
|||
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']> |
|||
readonly useManualRefHistory: UnwrapRef<typeof import('@vueuse/core')['useManualRefHistory']> |
|||
readonly useMediaControls: UnwrapRef<typeof import('@vueuse/core')['useMediaControls']> |
|||
readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']> |
|||
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']> |
|||
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']> |
|||
readonly useMessage: UnwrapRef<typeof import('naive-ui')['useMessage']> |
|||
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']> |
|||
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']> |
|||
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']> |
|||
readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']> |
|||
readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']> |
|||
readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']> |
|||
readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']> |
|||
readonly useNotification: UnwrapRef<typeof import('naive-ui')['useNotification']> |
|||
readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']> |
|||
readonly useObjectUrl: UnwrapRef<typeof import('@vueuse/core')['useObjectUrl']> |
|||
readonly useOffsetPagination: UnwrapRef<typeof import('@vueuse/core')['useOffsetPagination']> |
|||
readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']> |
|||
readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']> |
|||
readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']> |
|||
readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']> |
|||
readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']> |
|||
readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']> |
|||
readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']> |
|||
readonly usePreferredContrast: UnwrapRef<typeof import('@vueuse/core')['usePreferredContrast']> |
|||
readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']> |
|||
readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']> |
|||
readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']> |
|||
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']> |
|||
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']> |
|||
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']> |
|||
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']> |
|||
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']> |
|||
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']> |
|||
readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']> |
|||
readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']> |
|||
readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']> |
|||
readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']> |
|||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> |
|||
readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']> |
|||
readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']> |
|||
readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']> |
|||
readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']> |
|||
readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']> |
|||
readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']> |
|||
readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']> |
|||
readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']> |
|||
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']> |
|||
readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']> |
|||
readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']> |
|||
readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']> |
|||
readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']> |
|||
readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']> |
|||
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']> |
|||
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']> |
|||
readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']> |
|||
readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']> |
|||
readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']> |
|||
readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']> |
|||
readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']> |
|||
readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']> |
|||
readonly useToNumber: UnwrapRef<typeof import('@vueuse/core')['useToNumber']> |
|||
readonly useToString: UnwrapRef<typeof import('@vueuse/core')['useToString']> |
|||
readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']> |
|||
readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']> |
|||
readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']> |
|||
readonly useUserMedia: UnwrapRef<typeof import('@vueuse/core')['useUserMedia']> |
|||
readonly useVModel: UnwrapRef<typeof import('@vueuse/core')['useVModel']> |
|||
readonly useVModels: UnwrapRef<typeof import('@vueuse/core')['useVModels']> |
|||
readonly useVibrate: UnwrapRef<typeof import('@vueuse/core')['useVibrate']> |
|||
readonly useVirtualList: UnwrapRef<typeof import('@vueuse/core')['useVirtualList']> |
|||
readonly useWakeLock: UnwrapRef<typeof import('@vueuse/core')['useWakeLock']> |
|||
readonly useWebNotification: UnwrapRef<typeof import('@vueuse/core')['useWebNotification']> |
|||
readonly useWebSocket: UnwrapRef<typeof import('@vueuse/core')['useWebSocket']> |
|||
readonly useWebWorker: UnwrapRef<typeof import('@vueuse/core')['useWebWorker']> |
|||
readonly useWebWorkerFn: UnwrapRef<typeof import('@vueuse/core')['useWebWorkerFn']> |
|||
readonly useWindowFocus: UnwrapRef<typeof import('@vueuse/core')['useWindowFocus']> |
|||
readonly useWindowScroll: UnwrapRef<typeof import('@vueuse/core')['useWindowScroll']> |
|||
readonly useWindowSize: UnwrapRef<typeof import('@vueuse/core')['useWindowSize']> |
|||
readonly watch: UnwrapRef<typeof import('vue')['watch']> |
|||
readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']> |
|||
readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']> |
|||
readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']> |
|||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> |
|||
readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']> |
|||
readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']> |
|||
readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']> |
|||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> |
|||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']> |
|||
readonly watchThrottled: UnwrapRef<typeof import('@vueuse/core')['watchThrottled']> |
|||
readonly watchTriggerable: UnwrapRef<typeof import('@vueuse/core')['watchTriggerable']> |
|||
readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']> |
|||
readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']> |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
/** |
|||
* The name of the configuration file entered in the production environment |
|||
*/ |
|||
export const GLOB_CONFIG_FILE_NAME = 'app.config.js'; |
|||
|
|||
export const OUTPUT_DIR = 'dist'; |
@ -0,0 +1,9 @@ |
|||
/** |
|||
* Get the configuration file variable name |
|||
* @param env |
|||
*/ |
|||
export const getConfigFileName = (env: Record<string, any>) => { |
|||
return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__` |
|||
.toUpperCase() |
|||
.replace(/\s/g, ''); |
|||
}; |
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Generate additional configuration files when used for packaging. The file can be configured with some global variables, so that it can be changed directly externally without repackaging |
|||
*/ |
|||
import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant'; |
|||
import fs, { writeFileSync } from 'fs-extra'; |
|||
import chalk from 'chalk'; |
|||
|
|||
import { getRootPath, getEnvConfig } from '../utils'; |
|||
import { getConfigFileName } from '../getConfigFileName'; |
|||
|
|||
import pkg from '../../package.json'; |
|||
|
|||
function createConfig( |
|||
{ |
|||
configName, |
|||
config, |
|||
configFileName = GLOB_CONFIG_FILE_NAME, |
|||
}: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} } |
|||
) { |
|||
try { |
|||
const windowConf = `window.${configName}`; |
|||
// Ensure that the variable will not be modified
|
|||
const configStr = `${windowConf}=${JSON.stringify(config)};
|
|||
Object.freeze(${windowConf}); |
|||
Object.defineProperty(window, "${configName}", { |
|||
configurable: false, |
|||
writable: false, |
|||
}); |
|||
`.replace(/\s/g, '');
|
|||
fs.mkdirp(getRootPath(OUTPUT_DIR)); |
|||
writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr); |
|||
|
|||
console.log(chalk.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`); |
|||
console.log(chalk.gray(OUTPUT_DIR + '/' + chalk.green(configFileName)) + '\n'); |
|||
} catch (error) { |
|||
console.log(chalk.red('configuration file configuration file failed to package:\n' + error)); |
|||
} |
|||
} |
|||
|
|||
export function runBuildConfig() { |
|||
const config = getEnvConfig(); |
|||
const configFileName = getConfigFileName(config); |
|||
createConfig({ config, configName: configFileName }); |
|||
} |
@ -0,0 +1,23 @@ |
|||
// #!/usr/bin/env node
|
|||
|
|||
import { runBuildConfig } from './buildConf'; |
|||
import chalk from 'chalk'; |
|||
|
|||
import pkg from '../../package.json'; |
|||
|
|||
export const runBuild = async () => { |
|||
try { |
|||
const argvList = process.argv.splice(2); |
|||
|
|||
// Generate configuration file
|
|||
if (!argvList.includes('disabled-config')) { |
|||
await runBuildConfig(); |
|||
} |
|||
|
|||
console.log(`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!'); |
|||
} catch (error) { |
|||
console.log(chalk.red('vite build error:\n' + error)); |
|||
process.exit(1); |
|||
} |
|||
}; |
|||
runBuild(); |
@ -0,0 +1,71 @@ |
|||
import fs from 'fs'; |
|||
import path from 'path'; |
|||
import dotenv from 'dotenv'; |
|||
|
|||
export function isDevFn(mode: string): boolean { |
|||
return mode === 'development'; |
|||
} |
|||
|
|||
export function isProdFn(mode: string): boolean { |
|||
return mode === 'production'; |
|||
} |
|||
|
|||
/** |
|||
* Whether to generate package preview |
|||
*/ |
|||
export function isReportMode(): boolean { |
|||
return process.env.REPORT === 'true'; |
|||
} |
|||
|
|||
// Read all environment variable configuration files to process.env
|
|||
export function wrapperEnv(envConf: Recordable): ViteEnv { |
|||
const ret: any = {}; |
|||
|
|||
for (const envName of Object.keys(envConf)) { |
|||
let realName = envConf[envName].replace(/\\n/g, '\n'); |
|||
realName = realName === 'true' ? true : realName === 'false' ? false : realName; |
|||
|
|||
if (envName === 'VITE_PORT') { |
|||
realName = Number(realName); |
|||
} |
|||
if (envName === 'VITE_PROXY') { |
|||
try { |
|||
realName = JSON.parse(realName); |
|||
} catch (error) {} |
|||
} |
|||
ret[envName] = realName; |
|||
process.env[envName] = realName; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
/** |
|||
* Get the environment variables starting with the specified prefix |
|||
* @param match prefix |
|||
* @param confFiles ext |
|||
*/ |
|||
export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.production']) { |
|||
let envConfig = {}; |
|||
confFiles.forEach((item) => { |
|||
try { |
|||
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item))); |
|||
envConfig = { ...envConfig, ...env }; |
|||
} catch (error) {} |
|||
}); |
|||
|
|||
Object.keys(envConfig).forEach((key) => { |
|||
const reg = new RegExp(`^(${match})`); |
|||
if (!reg.test(key)) { |
|||
Reflect.deleteProperty(envConfig, key); |
|||
} |
|||
}); |
|||
return envConfig; |
|||
} |
|||
|
|||
/** |
|||
* Get user root directory |
|||
* @param dir file path |
|||
*/ |
|||
export function getRootPath(...dir: string[]) { |
|||
return path.resolve(process.cwd(), ...dir); |
|||
} |
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated |
|||
* https://github.com/anncwb/vite-plugin-compression
|
|||
*/ |
|||
import type { Plugin } from 'vite'; |
|||
|
|||
import compressPlugin from 'vite-plugin-compression'; |
|||
|
|||
export function configCompressPlugin( |
|||
compress: 'gzip' | 'brotli' | 'none', |
|||
deleteOriginFile = false |
|||
): Plugin | Plugin[] { |
|||
const compressList = compress.split(','); |
|||
|
|||
const plugins: Plugin[] = []; |
|||
|
|||
if (compressList.includes('gzip')) { |
|||
plugins.push( |
|||
compressPlugin({ |
|||
ext: '.gz', |
|||
deleteOriginFile, |
|||
}) |
|||
); |
|||
} |
|||
if (compressList.includes('brotli')) { |
|||
plugins.push( |
|||
compressPlugin({ |
|||
ext: '.br', |
|||
algorithm: 'brotliCompress', |
|||
deleteOriginFile, |
|||
}) |
|||
); |
|||
} |
|||
return plugins; |
|||
} |
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Plugin to minimize and use ejs template syntax in index.html. |
|||
* https://github.com/anncwb/vite-plugin-html
|
|||
*/ |
|||
import type { PluginOption } from 'vite'; |
|||
|
|||
import { createHtmlPlugin } from 'vite-plugin-html'; |
|||
|
|||
import pkg from '../../../package.json'; |
|||
import { GLOB_CONFIG_FILE_NAME } from '../../constant'; |
|||
|
|||
export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) { |
|||
const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env; |
|||
|
|||
const path = VITE_PUBLIC_PATH.endsWith('/') ? VITE_PUBLIC_PATH : `${VITE_PUBLIC_PATH}/`; |
|||
|
|||
const getAppConfigSrc = () => { |
|||
return `${path || '/'}${GLOB_CONFIG_FILE_NAME}?v=${pkg.version}-${new Date().getTime()}`; |
|||
}; |
|||
|
|||
const htmlPlugin: PluginOption[] = createHtmlPlugin({ |
|||
minify: isBuild, |
|||
inject: { |
|||
// Inject data into ejs template
|
|||
data: { |
|||
title: VITE_GLOB_APP_TITLE, |
|||
}, |
|||
// Embed the generated app.config.js file
|
|||
tags: isBuild |
|||
? [ |
|||
{ |
|||
tag: 'script', |
|||
attrs: { |
|||
src: getAppConfigSrc(), |
|||
}, |
|||
}, |
|||
] |
|||
: [], |
|||
}, |
|||
}); |
|||
return htmlPlugin; |
|||
} |
@ -0,0 +1,63 @@ |
|||
import type { Plugin, PluginOption } from 'vite'; |
|||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'; |
|||
import AutoImport from 'unplugin-auto-import/vite'; |
|||
import Components from 'unplugin-vue-components/vite'; |
|||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'; |
|||
|
|||
import vue from '@vitejs/plugin-vue'; |
|||
import vueJsx from '@vitejs/plugin-vue-jsx'; |
|||
|
|||
import { configHtmlPlugin } from './html'; |
|||
import { configMockPlugin } from './mock'; |
|||
import { configCompressPlugin } from './compress'; |
|||
|
|||
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean, prodMock) { |
|||
const { VITE_USE_MOCK, VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE } = viteEnv; |
|||
|
|||
const vitePlugins: (Plugin | Plugin[] | PluginOption[])[] = [ |
|||
// have to
|
|||
vue(), |
|||
// have to
|
|||
vueJsx(), |
|||
|
|||
AutoImport({ |
|||
// 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
|
|||
imports: [ |
|||
'vue', |
|||
'@vueuse/core', |
|||
{ |
|||
'naive-ui': ['useDialog', 'useMessage', 'useNotification', 'useLoadingBar'], |
|||
}, |
|||
], |
|||
eslintrc: { |
|||
enabled: false, // Default `false`
|
|||
// filepath: './.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json`
|
|||
globalsPropValue: true, // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')
|
|||
}, |
|||
resolvers: [NaiveUiResolver(), ElementPlusResolver()], |
|||
vueTemplate: true, // 是否在 vue 模板中自动导入
|
|||
dts: true, |
|||
}), |
|||
|
|||
// 按需引入NaiveUi且自动创建组件声明
|
|||
Components({ |
|||
dts: true, |
|||
resolvers: [NaiveUiResolver(), ElementPlusResolver()], |
|||
}), |
|||
]; |
|||
|
|||
// vite-plugin-html
|
|||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild)); |
|||
|
|||
// vite-plugin-mock
|
|||
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild, prodMock)); |
|||
|
|||
if (isBuild) { |
|||
// rollup-plugin-gzip
|
|||
vitePlugins.push( |
|||
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE) |
|||
); |
|||
} |
|||
|
|||
return vitePlugins; |
|||
} |
@ -0,0 +1,19 @@ |
|||
/** |
|||
* Mock plugin for development and production. |
|||
* https://github.com/anncwb/vite-plugin-mock
|
|||
*/ |
|||
import { viteMockServe } from 'vite-plugin-mock'; |
|||
|
|||
export function configMockPlugin(isBuild: boolean, prodMock: boolean) { |
|||
return viteMockServe({ |
|||
ignore: /^\_/, |
|||
mockPath: 'mock', |
|||
localEnabled: !isBuild, |
|||
prodEnabled: isBuild && prodMock, |
|||
injectCode: ` |
|||
import { setupProdMockServer } from '../mock/_createProductionServer'; |
|||
|
|||
setupProdMockServer(); |
|||
`,
|
|||
}); |
|||
} |
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Used to parse the .env.development proxy configuration |
|||
*/ |
|||
import type { ProxyOptions } from 'vite'; |
|||
|
|||
type ProxyItem = [string, string]; |
|||
|
|||
type ProxyList = ProxyItem[]; |
|||
|
|||
type ProxyTargetList = Record<string, ProxyOptions & { rewrite: (path: string) => string }>; |
|||
|
|||
const httpsRE = /^https:\/\//; |
|||
|
|||
/** |
|||
* Generate proxy |
|||
* @param list |
|||
*/ |
|||
export function createProxy(list: ProxyList = []) { |
|||
const ret: ProxyTargetList = {}; |
|||
for (const [prefix, target] of list) { |
|||
const isHttps = httpsRE.test(target); |
|||
|
|||
// https://github.com/http-party/node-http-proxy#options
|
|||
ret[prefix] = { |
|||
target: target, |
|||
changeOrigin: true, |
|||
ws: true, |
|||
rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''), |
|||
// https is require secure=false
|
|||
...(isHttps ? { secure: false } : {}), |
|||
}; |
|||
} |
|||
return ret; |
|||
} |
@ -0,0 +1,57 @@ |
|||
module.exports = { |
|||
ignores: [(commit) => commit.includes('init')], |
|||
extends: ['@commitlint/config-conventional'], |
|||
parserPreset: { |
|||
parserOpts: { |
|||
headerPattern: /^(\w*|[\u4e00-\u9fa5]*)(?:[\(\(](.*)[\)\)])?[\:\:] (.*)/, |
|||
headerCorrespondence: ['type', 'scope', 'subject'], |
|||
referenceActions: [ |
|||
'close', |
|||
'closes', |
|||
'closed', |
|||
'fix', |
|||
'fixes', |
|||
'fixed', |
|||
'resolve', |
|||
'resolves', |
|||
'resolved', |
|||
], |
|||
issuePrefixes: ['#'], |
|||
noteKeywords: ['BREAKING CHANGE'], |
|||
fieldPattern: /^-(.*?)-$/, |
|||
revertPattern: /^Revert\s"([\s\S]*)"\s*This reverts commit (\w*)\./, |
|||
revertCorrespondence: ['header', 'hash'], |
|||
warn() {}, |
|||
mergePattern: null, |
|||
mergeCorrespondence: null, |
|||
}, |
|||
}, |
|||
rules: { |
|||
'body-leading-blank': [2, 'always'], |
|||
'footer-leading-blank': [1, 'always'], |
|||
'header-max-length': [2, 'always', 108], |
|||
'subject-empty': [2, 'never'], |
|||
'type-empty': [2, 'never'], |
|||
'type-enum': [ |
|||
2, |
|||
'always', |
|||
[ |
|||
'feat', |
|||
'fix', |
|||
'perf', |
|||
'style', |
|||
'docs', |
|||
'test', |
|||
'refactor', |
|||
'build', |
|||
'ci', |
|||
'chore', |
|||
'revert', |
|||
'wip', |
|||
'workflow', |
|||
'types', |
|||
'release', |
|||
], |
|||
], |
|||
}, |
|||
}; |
@ -0,0 +1,122 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="zh-cmn-Hans" id="htmlRoot" data-theme="light"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/> |
|||
<meta content="webkit" name="renderer"/> |
|||
<meta |
|||
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" |
|||
name="viewport" |
|||
/> |
|||
<link href="/favicon.ico" rel="icon"/> |
|||
<title><%= title %></title> |
|||
</head> |
|||
<body> |
|||
<div id="appProvider" style="display: none"></div> |
|||
<div id="app"> |
|||
<style> |
|||
.first-loading-wrap { |
|||
display: flex; |
|||
width: 100%; |
|||
height: 100vh; |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.first-loading-wrap > h1 { |
|||
font-size: 128px |
|||
} |
|||
|
|||
.first-loading-wrap .loading-wrap { |
|||
padding: 98px; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center |
|||
} |
|||
|
|||
.dot { |
|||
animation: antRotate 1.2s infinite linear; |
|||
transform: rotate(45deg); |
|||
position: relative; |
|||
display: inline-block; |
|||
font-size: 32px; |
|||
width: 32px; |
|||
height: 32px; |
|||
box-sizing: border-box |
|||
} |
|||
|
|||
.dot i { |
|||
width: 14px; |
|||
height: 14px; |
|||
position: absolute; |
|||
display: block; |
|||
background-color: #1890ff; |
|||
border-radius: 100%; |
|||
transform: scale(.75); |
|||
transform-origin: 50% 50%; |
|||
opacity: .3; |
|||
animation: antSpinMove 1s infinite linear alternate |
|||
} |
|||
|
|||
.dot i:nth-child(1) { |
|||
top: 0; |
|||
left: 0 |
|||
} |
|||
|
|||
.dot i:nth-child(2) { |
|||
top: 0; |
|||
right: 0; |
|||
-webkit-animation-delay: .4s; |
|||
animation-delay: .4s |
|||
} |
|||
|
|||
.dot i:nth-child(3) { |
|||
right: 0; |
|||
bottom: 0; |
|||
-webkit-animation-delay: .8s; |
|||
animation-delay: .8s |
|||
} |
|||
|
|||
.dot i:nth-child(4) { |
|||
bottom: 0; |
|||
left: 0; |
|||
-webkit-animation-delay: 1.2s; |
|||
animation-delay: 1.2s |
|||
} |
|||
|
|||
@keyframes antRotate { |
|||
to { |
|||
-webkit-transform: rotate(405deg); |
|||
transform: rotate(405deg) |
|||
} |
|||
} |
|||
|
|||
@-webkit-keyframes antRotate { |
|||
to { |
|||
-webkit-transform: rotate(405deg); |
|||
transform: rotate(405deg) |
|||
} |
|||
} |
|||
|
|||
@keyframes antSpinMove { |
|||
to { |
|||
opacity: 1 |
|||
} |
|||
} |
|||
|
|||
@-webkit-keyframes antSpinMove { |
|||
to { |
|||
opacity: 1 |
|||
} |
|||
}</style> |
|||
<div class="first-loading-wrap"> |
|||
<div class="loading-wrap"> |
|||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<script>var globalThis = window;</script> |
|||
<script src="/src/main.ts" type="module"></script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,22 @@ |
|||
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'; |
|||
|
|||
interface IModuleType { |
|||
default: any[]; |
|||
} |
|||
|
|||
const modules = import.meta.glob<IModuleType>('./**/*.ts', { eager: true }); |
|||
|
|||
const mockModules: any[] = []; |
|||
Object.keys(modules).forEach((key) => { |
|||
if (key.includes('/_')) { |
|||
return; |
|||
} |
|||
mockModules.push(...modules[key].default); |
|||
}); |
|||
|
|||
/** |
|||
* Used in a production environment. Need to manually import all modules |
|||
*/ |
|||
export function setupProdMockServer() { |
|||
createProdMockServer(mockModules); |
|||
} |
@ -0,0 +1,73 @@ |
|||
import Mock from 'mockjs'; |
|||
|
|||
export function resultSuccess(result, { message = 'ok' } = {}) { |
|||
return Mock.mock({ |
|||
code: 200, |
|||
result, |
|||
message, |
|||
type: 'success', |
|||
}); |
|||
} |
|||
|
|||
export function resultPageSuccess<T = any>( |
|||
page: number, |
|||
pageSize: number, |
|||
list: T[], |
|||
{ message = 'ok' } = {} |
|||
) { |
|||
const pageData = pagination(page, pageSize, list); |
|||
|
|||
return { |
|||
...resultSuccess({ |
|||
page, |
|||
pageSize, |
|||
pageCount: list.length, |
|||
list: pageData, |
|||
}), |
|||
message, |
|||
}; |
|||
} |
|||
|
|||
export function resultError(message = 'Request failed', { code = -1, result = null } = {}) { |
|||
return { |
|||
code, |
|||
result, |
|||
message, |
|||
type: 'error', |
|||
}; |
|||
} |
|||
|
|||
export function pagination<T = any>(pageNo: number, pageSize: number, array: T[]): T[] { |
|||
const offset = (pageNo - 1) * Number(pageSize); |
|||
const ret = |
|||
offset + Number(pageSize) >= array.length |
|||
? array.slice(offset, array.length) |
|||
: array.slice(offset, offset + Number(pageSize)); |
|||
return ret; |
|||
} |
|||
|
|||
/** |
|||
* @param {Number} times 回调函数需要执行的次数 |
|||
* @param {Function} callback 回调函数 |
|||
*/ |
|||
export function doCustomTimes(times: number, callback: any) { |
|||
let i = -1; |
|||
while (++i < times) { |
|||
callback(i); |
|||
} |
|||
} |
|||
|
|||
export interface requestParams { |
|||
method: string; |
|||
body: any; |
|||
headers?: { token?: string }; |
|||
query: any; |
|||
} |
|||
|
|||
/** |
|||
* @description 本函数用于从request数据中获取token,请根据项目的实际情况修改 |
|||
* |
|||
*/ |
|||
export function getRequestToken({ headers }: requestParams): string | undefined { |
|||
return headers?.token; |
|||
} |
@ -0,0 +1,44 @@ |
|||
import { Random } from 'mockjs'; |
|||
import { resultSuccess } from '../_util'; |
|||
|
|||
const consoleInfo = { |
|||
//访问量
|
|||
visits: { |
|||
dayVisits: Random.float(10000, 99999, 2, 2), |
|||
rise: Random.float(10, 99), |
|||
decline: Random.float(10, 99), |
|||
amount: Random.float(99999, 999999, 3, 5), |
|||
}, |
|||
//销售额
|
|||
saleroom: { |
|||
weekSaleroom: Random.float(10000, 99999, 2, 2), |
|||
amount: Random.float(99999, 999999, 2, 2), |
|||
degree: Random.float(10, 99), |
|||
}, |
|||
//订单量
|
|||
orderLarge: { |
|||
weekLarge: Random.float(10000, 99999, 2, 2), |
|||
rise: Random.float(10, 99), |
|||
decline: Random.float(10, 99), |
|||
amount: Random.float(99999, 999999, 2, 2), |
|||
}, |
|||
//成交额度
|
|||
volume: { |
|||
weekLarge: Random.float(10000, 99999, 2, 2), |
|||
rise: Random.float(10, 99), |
|||
decline: Random.float(10, 99), |
|||
amount: Random.float(99999, 999999, 2, 2), |
|||
}, |
|||
}; |
|||
|
|||
export default [ |
|||
//主控台 卡片数据
|
|||
{ |
|||
url: '/api/dashboard/console', |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: () => { |
|||
return resultSuccess(consoleInfo); |
|||
}, |
|||
}, |
|||
]; |
@ -0,0 +1,89 @@ |
|||
import { resultSuccess } from '../_util'; |
|||
|
|||
const menuList = () => { |
|||
const result: any[] = [ |
|||
{ |
|||
label: 'Dashboard', |
|||
key: 'dashboard', |
|||
type: 1, |
|||
subtitle: 'dashboard', |
|||
openType: 1, |
|||
auth: 'dashboard', |
|||
path: '/dashboard', |
|||
children: [ |
|||
{ |
|||
label: '主控台', |
|||
key: 'console', |
|||
type: 1, |
|||
subtitle: 'console', |
|||
openType: 1, |
|||
auth: 'console', |
|||
path: '/dashboard/console', |
|||
}, |
|||
{ |
|||
label: '工作台', |
|||
key: 'workplace', |
|||
type: 1, |
|||
subtitle: 'workplace', |
|||
openType: 1, |
|||
auth: 'workplace', |
|||
path: '/dashboard/workplace', |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
label: '表单管理', |
|||
key: 'form', |
|||
type: 1, |
|||
subtitle: 'form', |
|||
openType: 1, |
|||
auth: 'form', |
|||
path: '/form', |
|||
children: [ |
|||
{ |
|||
label: '基础表单', |
|||
key: 'basic-form', |
|||
type: 1, |
|||
subtitle: 'basic-form', |
|||
openType: 1, |
|||
auth: 'basic-form', |
|||
path: '/form/basic-form', |
|||
}, |
|||
{ |
|||
label: '分步表单', |
|||
key: 'step-form', |
|||
type: 1, |
|||
subtitle: 'step-form', |
|||
openType: 1, |
|||
auth: 'step-form', |
|||
path: '/form/step-form', |
|||
}, |
|||
{ |
|||
label: '表单详情', |
|||
key: 'detail', |
|||
type: 1, |
|||
subtitle: 'detail', |
|||
openType: 1, |
|||
auth: 'detail', |
|||
path: '/form/detail', |
|||
}, |
|||
], |
|||
}, |
|||
]; |
|||
|
|||
return result; |
|||
}; |
|||
|
|||
export default [ |
|||
{ |
|||
url: '/api/menu/list', |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: () => { |
|||
const list = menuList(); |
|||
return resultSuccess({ |
|||
list, |
|||
}); |
|||
}, |
|||
}, |
|||
]; |
@ -0,0 +1,45 @@ |
|||
import { resultSuccess, doCustomTimes } from '../_util'; |
|||
|
|||
function getMenuKeys() { |
|||
const keys = ['dashboard', 'console', 'workplace', 'basic-form', 'step-form', 'detail']; |
|||
const newKeys = []; |
|||
doCustomTimes(parseInt(Math.random() * 6), () => { |
|||
const key = keys[Math.floor(Math.random() * keys.length)]; |
|||
newKeys.push(key); |
|||
}); |
|||
return Array.from(new Set(newKeys)); |
|||
} |
|||
|
|||
const roleList = (pageSize) => { |
|||
const result: any[] = []; |
|||
doCustomTimes(pageSize, () => { |
|||
result.push({ |
|||
id: '@integer(10,100)', |
|||
name: '@cname()', |
|||
explain: '@cname()', |
|||
isDefault: '@boolean()', |
|||
menu_keys: getMenuKeys(), |
|||
create_date: `@date('yyyy-MM-dd hh:mm:ss')`, |
|||
'status|1': ['normal', 'enable', 'disable'], |
|||
}); |
|||
}); |
|||
return result; |
|||
}; |
|||
|
|||
export default [ |
|||
{ |
|||
url: '/api/role/list', |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 10 } = query; |
|||
const list = roleList(Number(pageSize)); |
|||
return resultSuccess({ |
|||
page: Number(page), |
|||
pageSize: Number(pageSize), |
|||
pageCount: 60, |
|||
list, |
|||
}); |
|||
}, |
|||
}, |
|||
]; |
@ -0,0 +1,40 @@ |
|||
import { Random } from 'mockjs'; |
|||
import { resultSuccess, doCustomTimes } from '../_util'; |
|||
|
|||
const tableList = (pageSize) => { |
|||
const result: any[] = []; |
|||
doCustomTimes(pageSize, () => { |
|||
result.push({ |
|||
id: '@integer(10,999999)', |
|||
beginTime: '@datetime', |
|||
endTime: '@datetime', |
|||
address: '@city()', |
|||
name: '@cname()', |
|||
avatar: Random.image('400x400', Random.color(), Random.color(), Random.first()), |
|||
date: `@date('yyyy-MM-dd')`, |
|||
time: `@time('HH:mm')`, |
|||
'no|100000-10000000': 100000, |
|||
'status|1': [true, false], |
|||
}); |
|||
}); |
|||
return result; |
|||
}; |
|||
|
|||
export default [ |
|||
//表格数据列表
|
|||
{ |
|||
url: '/api/table/list', |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: ({ query }) => { |
|||
const { page = 1, pageSize = 10 } = query; |
|||
const list = tableList(Number(pageSize)); |
|||
return resultSuccess({ |
|||
page: Number(page), |
|||
pageSize: Number(pageSize), |
|||
pageCount: 60, |
|||
list, |
|||
}); |
|||
}, |
|||
}, |
|||
]; |
@ -0,0 +1,52 @@ |
|||
import { resultSuccess } from '../_util'; |
|||
|
|||
const menusList = [ |
|||
{ |
|||
path: '/dashboard', |
|||
name: 'Dashboard', |
|||
component: 'LAYOUT', |
|||
redirect: '/dashboard/console', |
|||
meta: { |
|||
icon: 'DashboardOutlined', |
|||
title: 'Dashboard', |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: 'console', |
|||
name: 'dashboard_console', |
|||
component: '/dashboard/console/console', |
|||
meta: { |
|||
title: '主控台', |
|||
}, |
|||
}, |
|||
{ |
|||
path: 'monitor', |
|||
name: 'dashboard_monitor', |
|||
component: '/dashboard/monitor/monitor', |
|||
meta: { |
|||
title: '监控页', |
|||
}, |
|||
}, |
|||
{ |
|||
path: 'workplace', |
|||
name: 'dashboard_workplace', |
|||
component: '/dashboard/workplace/workplace', |
|||
meta: { |
|||
hidden: true, |
|||
title: '工作台', |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
]; |
|||
|
|||
export default [ |
|||
{ |
|||
url: '/api/menus', |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: () => { |
|||
return resultSuccess(menusList); |
|||
}, |
|||
}, |
|||
]; |
@ -0,0 +1,157 @@ |
|||
// import Mock from 'mockjs';
|
|||
import { resultSuccess } from '../_util'; |
|||
|
|||
// const Random = Mock.Random;
|
|||
|
|||
// const token = Random.string('upper', 32, 32);
|
|||
|
|||
// const adminInfo = {
|
|||
// userId: '1',
|
|||
// username: 'admin',
|
|||
// realName: 'Admin',
|
|||
// avatar: Random.image(),
|
|||
// desc: 'manager',
|
|||
// password: Random.string('upper', 4, 16),
|
|||
// token,
|
|||
// permissions: [
|
|||
// {
|
|||
// label: '主控台',
|
|||
// value: 'dashboard_console',
|
|||
// },
|
|||
// {
|
|||
// label: '监控页',
|
|||
// value: 'dashboard_monitor',
|
|||
// },
|
|||
// {
|
|||
// label: '工作台',
|
|||
// value: 'dashboard_workplace',
|
|||
// },
|
|||
// {
|
|||
// label: '基础列表',
|
|||
// value: 'basic_list',
|
|||
// },
|
|||
// {
|
|||
// label: '基础列表删除',
|
|||
// value: 'basic_list_delete',
|
|||
// },
|
|||
// ],
|
|||
// };
|
|||
|
|||
const imgCode = { |
|||
msg: '操作成功', |
|||
img: '/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAA8AKADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDtrW1ga1hZoIySikkoOeKsCztv+feL/vgU2z/484P+ua/yqyKiMY8q0IjGPKtCIWdr/wA+0P8A3wKeLK1/59of+/YqQVXl1OxtrpLWe7ginddyRvIFZh7A9apU09kPlj2JhZWn/PrD/wB+xThY2n/PrB/37FV73WdO0yLzL29gt1xnMkgGfp60zRvEOl6+kr6ZdC4WFtrkIy4P4gZ/CrWHk4Ooo+6uttPvC0di8LCz/wCfWD/v2KcLCz/59IP+/YqYU8Vnyx7Byx7EI0+y/wCfS3/79j/CnDTrL/nzt/8Av0v+FTZAqm+uaXDdLayaharOxwIzKN35VUaXNpFXDlj2LI06x/587f8A79L/AIU4abY/8+Vv/wB+l/wqdSDTxU8sewcsexXGmWH/AD5W3/fpf8KeNMsP+fG2/wC/S/4VYFKWVRkkAD1o5Y9g5Y9iAaXp/wDz423/AH5X/CnjStP/AOfC1/78r/hWJdePfC9le/ZJ9atVmzghSWAPuwBA/E10UE8VxEssTq8bDKspyCPatZ4adNKU4WT2utwSi9iIaVp3/Pha/wDflf8ACnDSdO/6B9r/AN+V/wAKtCnisuWPYOWPYqjSdN/6B9p/35X/AAqtqel6fHpF66WNqrrA5VhCoIO08jitYVV1b/kC3/8A17yf+gmlKMeV6ClGPK9DkrP/AI84P+ua/wAqsiq9n/x5wf8AXNf5VZFOPwocfhQjnC5rzH4h6IdauILhJxHLChTay5DDOevavUCuRisjUdHW6ByK6sLiquFqqtRdpIcoqSsz5/utFksoHknuIzt6KmTk/jivT/hZGLPSCyk7rh97enHArJ8Z+HzBpszxrynzflWl8MLuOfSfLyPMgYqw9uor6LF5hicdlLqVHdqdnpsrafiYxgo1LLsdv4q1O+07w3eXWmeX9riTeoddwwD83HrjNUvAPih/EHhuOa7mD3sbtHOcAZOcg4HsRXJeOn8Rx32dLvm+xSr88R2AxnvgkZwfr6+1eYzWD2lxEtxKEjc8yIN238OKzy/LcNisL7KdWKnJ3VruWid4taeqS3HObjK6Wh7T8S73VzpEcOkPINzkTGJsNtx2ryK90tbTSIbxppRes/zo/GOvTvmu08NWWsxP9mmuRf6dKuUkEuTF6cHsfQZ7e9O8R+GIpljEz+Wd3ynIBPtzVYPM/wCzqkMPGSdO93KK1a7NP/h0KUOdX6nd+AvEL3fg62udQkIeFGEkjf3Vzz+WK07z4geFrCDzZNbtJBjhYH81j+C5ryjS/EGoeDJ47a+JudLl+VJMfNH7H1+n5elZ+q2PhfTXW+ENxcQ3DF4kV/3Y74GMYA9Cax/s+hUruc1Jwm7w5EnfV3WtrNeY+dpWXTuelRfGfwxJciJo7+NCcea8K7R78MT+lZ3xS1rWpLa1sdGE5tpwTNJbqTkdhkdB/OvOU8S6KwEU3hu28noWTAfH1wD+td54b1fRtbjh0uxuZBJHH8kE4O4KOwJ4OB7k4HtW+IwTy+pDE08PL3d1K0lto7ra3n+AlLnXK2cvb+FNKGlgXYm+1Mm5pt5Gw/Tp+db/AMJfGUtpfnw3fTb4mJ+yuT90jqufQ9R/9erXjfR5rfw5P9lz5gAJA6le9eeeB7Yz+KLWQNgwuJPfiunCVJY7LcTVxlTmtql/K+jXZPawpLlmlFH1ZGwZQRUoqhpshkt0J9K0BXxp0DhVXVv+QJf/APXtJ/6Catiqur/8gS//AOvaT/0E1MvhZMvhZyVn/wAeUH/XNf5VZFV7L/jyg/65r/KrIoj8KCPwocKdjIpBTxVFHL+JLITW75XIIwRXlGjzXPhLxSXMUhsHbbI+07Qp759q92u7YTxFSK5waG0d3vUd678Fj3hlODjzQmrNfk/VdCZR5rMmvNJXUYQw5DDIIrj9X8GiRGjZTtbuOo9xXqNjB5cKrgAAYAqSaySYcqK4oTlCSnF2a2K3OA8GaFc6VC0Es4mhBzGSuGT1HuKb458Mw6zGkqTPBdRD5HBO0/Uf1616Db2CRdBUGoaWLlDxXRDG14V/rEZWn30/LbXqS4pqx8+apfana2D6bqsCzKeEnB9Oh9/0NWfBkLahHcWUsSywKQ6h1yFb2r0HWPCjzEjZuU9iM1e8MeGvsRA8pVHoFxXq1M6pzwcsOqSjKTTunpful0foQqbUr3MP/hHZNm0wK0f90qCPyq9onhDS4tShvP7OEdxE4dHjd0wfoDivS49Oi2AFBUkenxI2QorxaderTTUJNX3s7XNGk9zn9b0xryzIA7V5JqkbeDtVh1M6bHcRFiNyuY2VvQkZBB+navoR4FaPbiuS1vQ47rMctvHNEx5SRAyn8DWmErwo1VKpHmjs1dq69UKSutDa8J6va63oVrf2jZjmTO09VPdT7g5FdCK5vw5Yx6fbCC3t4oIwc7IkCjP0FdKvSsajg5tw26ehS8xwqrq//IEv/wDr2k/9BNWxVXV/+QJf/wDXtJ/6Cayl8LJl8LOSsv8Ajyt/+ua/yqyK5mLWrmKJI1SIhFCjIPb8ak/t+6/55w/98n/Gso1o2RnGrGyOlFOFcz/wkN3/AM84P++T/jS/8JFd/wDPOD/vk/41Xtoj9tE6gDNHlKTnFcx/wkl5/wA8oP8Avk/40v8Awkt5/wA8oP8Avk/40e2iHtonVqoFSAVyP/CT3v8Azyt/++W/xpf+Eovf+eVv/wB8t/jR7aIe2ideBTsA1x//AAlV9/zyt/8Avlv8aX/hK77/AJ5W3/fLf40e2iHtonWtbI/VRT4rdI+gFch/wlt//wA8bb/vlv8AGl/4S/UP+eNt/wB8t/8AFUe2iHtonbAU8Vw//CYah/zxtf8Avlv/AIql/wCEy1H/AJ42v/fLf/FUe2iHtondAU1oFfqK4j/hM9R/542v/fDf/FUv/Ca6l/zwtP8Avhv/AIqj20Q9tE7mOFU6CpxXAf8ACbal/wA8LT/vhv8A4ql/4TjU/wDnhaf98N/8VR7aIe2iegiqur/8gPUP+vaT/wBBNcV/wnOp/wDPC0/74b/4qo7nxnqN1azW7w2oSVGRiqtkAjHHzVMq0bMUqsbM/9k=', |
|||
code: 200, |
|||
captchaEnabled: true, |
|||
uuid: 'e0f32b7395a44b67b71f8b2c1a590476', |
|||
}; |
|||
|
|||
const loginData = { |
|||
msg: '操作成功', |
|||
code: 200, |
|||
token: |
|||
'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImMyNWQ3ZTBiLWZiZjMtNDAwNy1hNzk2LWM0ZWM5NjI4ZDI2NSJ9.N7U3awYhe6bNedmYRE0ZXO7cvqjqbF7Zd94LMAVZwR866mOvngJ2dRMSx2vcTqjqk25CBafZgIdoZk5ETooyAA', |
|||
}; |
|||
|
|||
const userData = { |
|||
msg: '操作成功', |
|||
code: 200, |
|||
permissions: ['*:*:*'], |
|||
roles: ['admin'], |
|||
user: { |
|||
createBy: 'admin', |
|||
createTime: '2021-05-26 18:56:28', |
|||
updateBy: null, |
|||
updateTime: null, |
|||
remark: '管理员', |
|||
userId: 1, |
|||
deptId: 100, |
|||
userName: 'admin', |
|||
nickName: '系统管理员', |
|||
email: 'ry@163.com', |
|||
phonenumber: '15888888888', |
|||
sex: '1', |
|||
avatar: '', |
|||
password: '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', |
|||
status: '0', |
|||
delFlag: '0', |
|||
loginIp: '127.0.0.1', |
|||
loginDate: '2023-08-16T08:33:10.356+08:00', |
|||
dept: { |
|||
createBy: null, |
|||
createTime: null, |
|||
updateBy: null, |
|||
updateTime: null, |
|||
remark: null, |
|||
deptId: 100, |
|||
parentId: 0, |
|||
ancestors: '0', |
|||
deptName: '联美节能环保集团', |
|||
orderNum: 0, |
|||
leader: '联美', |
|||
phone: null, |
|||
email: null, |
|||
status: '0', |
|||
delFlag: null, |
|||
parentName: null, |
|||
children: [], |
|||
}, |
|||
roles: [ |
|||
{ |
|||
createBy: null, |
|||
createTime: null, |
|||
updateBy: null, |
|||
updateTime: null, |
|||
remark: null, |
|||
roleId: 1, |
|||
roleName: '超级管理员', |
|||
roleKey: 'admin', |
|||
roleSort: 1, |
|||
dataScope: '1', |
|||
menuCheckStrictly: false, |
|||
deptCheckStrictly: false, |
|||
status: '0', |
|||
delFlag: null, |
|||
flag: false, |
|||
menuIds: null, |
|||
deptIds: null, |
|||
permissions: null, |
|||
admin: true, |
|||
}, |
|||
], |
|||
roleIds: null, |
|||
postIds: null, |
|||
roleId: null, |
|||
admin: true, |
|||
}, |
|||
}; |
|||
|
|||
export default [ |
|||
{ |
|||
url: '/api/captchaImage', |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: () => { |
|||
// const token = getRequestToken(request);
|
|||
// if (!token) return resultError('Invalid token');
|
|||
return resultSuccess(imgCode); |
|||
}, |
|||
}, |
|||
{ |
|||
url: '/api/login', |
|||
timeout: 1000, |
|||
method: 'post', |
|||
response: () => { |
|||
return resultSuccess(loginData); |
|||
}, |
|||
}, |
|||
{ |
|||
url: '/api/getInfo', |
|||
timeout: 1000, |
|||
method: 'get', |
|||
response: () => { |
|||
// const token = getRequestToken(request);
|
|||
// if (!token) return resultError('Invalid token');
|
|||
return resultSuccess(userData); |
|||
}, |
|||
}, |
|||
]; |
@ -0,0 +1,135 @@ |
|||
{ |
|||
"name": "dc-ui-plus", |
|||
"version": "1.0.2", |
|||
"author": { |
|||
"name": "Daniel" |
|||
}, |
|||
"private": true, |
|||
"scripts": { |
|||
"bootstrap": "yarn install", |
|||
"serve": "npm run dev", |
|||
"dev": "vite", |
|||
"build": "vite build && esno ./build/script/postBuild.ts", |
|||
"build:no-cache": "yarn clean:cache && npm run build", |
|||
"report": "cross-env REPORT=true npm run build", |
|||
"preview": "npm run build && vite preview", |
|||
"preview:dist": "vite preview", |
|||
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite", |
|||
"clean:lib": "rimraf node_modules", |
|||
"build typecheck": "vuedx-typecheck . && vite build", |
|||
"deploy": "gh-pages -d dist", |
|||
"lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix", |
|||
"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"", |
|||
"lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/", |
|||
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js", |
|||
"lint:pretty": "pretty-quick --staged", |
|||
"test prod gzip": "http-server dist --cors --gzip -c-1" |
|||
}, |
|||
"dependencies": { |
|||
"@vicons/antd": "^0.12.0", |
|||
"@vicons/ionicons5": "^0.12.0", |
|||
"@vueup/vue-quill": "^1.0.0", |
|||
"@vueuse/core": "^9.5.0", |
|||
"animate.css": "^4.1.1", |
|||
"axios": "^1.1.3", |
|||
"blueimp-md5": "^2.19.0", |
|||
"date-fns": "^2.29.3", |
|||
"echarts": "^5.4.0", |
|||
"element-plus": "^2.3.8", |
|||
"element-resize-detector": "^1.2.4", |
|||
"lodash": "^4.17.21", |
|||
"lodash-es": "^4.17.21", |
|||
"mitt": "^3.0.1", |
|||
"mockjs": "^1.1.0", |
|||
"naive-ui": "^2.34.2", |
|||
"pinia": "^2.0.23", |
|||
"qs": "^6.11.0", |
|||
"vfonts": "^0.0.3", |
|||
"vue": "^3.2.45", |
|||
"vue-router": "^4.1.6", |
|||
"vue-types": "^4.2.1", |
|||
"vxe-table": "^4.4.2", |
|||
"xe-utils": "^3.5.11" |
|||
}, |
|||
"devDependencies": { |
|||
"@commitlint/cli": "^17.2.0", |
|||
"@commitlint/config-conventional": "^17.2.0", |
|||
"@types/lodash": "^4.14.188", |
|||
"@types/node": "^18.11.9", |
|||
"@typescript-eslint/eslint-plugin": "^5.42.1", |
|||
"@typescript-eslint/parser": "^5.42.1", |
|||
"@vicons/tabler": "^0.12.0", |
|||
"@vitejs/plugin-vue": "^3.2.0", |
|||
"@vitejs/plugin-vue-jsx": "^2.1.1", |
|||
"@vue/compiler-sfc": "^3.2.45", |
|||
"@vue/eslint-config-typescript": "^11.0.2", |
|||
"autoprefixer": "^10.4.13", |
|||
"commitizen": "^4.2.5", |
|||
"core-js": "^3.26.0", |
|||
"dotenv": "^16.0.3", |
|||
"eslint": "^8.27.0", |
|||
"eslint-config-prettier": "^8.5.0", |
|||
"eslint-define-config": "1.12.0", |
|||
"eslint-plugin-jest": "^27.1.5", |
|||
"eslint-plugin-prettier": "^4.2.1", |
|||
"eslint-plugin-vue": "^9.7.0", |
|||
"esno": "^0.16.3", |
|||
"gh-pages": "^4.0.0", |
|||
"husky": "^8.0.2", |
|||
"jest": "^29.3.1", |
|||
"less": "^4.1.3", |
|||
"less-loader": "^11.1.0", |
|||
"lint-staged": "^13.0.3", |
|||
"postcss": "^8.4.19", |
|||
"prettier": "^2.7.1", |
|||
"pretty-quick": "^3.1.3", |
|||
"rimraf": "^3.0.2", |
|||
"stylelint": "^14.14.1", |
|||
"stylelint-config-prettier": "^9.0.4", |
|||
"stylelint-config-standard": "^29.0.0", |
|||
"stylelint-order": "^5.0.0", |
|||
"stylelint-scss": "^4.3.0", |
|||
"tailwindcss": "^3.2.3", |
|||
"typescript": "^4.8.4", |
|||
"unplugin-auto-import": "^0.16.6", |
|||
"unplugin-vue-components": "^0.22.12", |
|||
"vite": "^3.2.3", |
|||
"vite-plugin-compression": "^0.5.1", |
|||
"vite-plugin-html": "^3.2.0", |
|||
"vite-plugin-mock": "^2.9.6", |
|||
"vite-plugin-style-import": "^2.0.0", |
|||
"vue-demi": "^0.13.11", |
|||
"vue-draggable-next": "^2.1.1", |
|||
"vue-eslint-parser": "^9.1.0", |
|||
"vuedraggable": "^4.1.0" |
|||
}, |
|||
"lint-staged": { |
|||
"*.{vue,js,ts,tsx}": "eslint --fix" |
|||
}, |
|||
"config": { |
|||
"commitizen": { |
|||
"path": "./node_modules/cz-customizable" |
|||
} |
|||
}, |
|||
"keywords": [ |
|||
"vue", |
|||
"naive-ui", |
|||
"naive-ui-admin", |
|||
"vue3", |
|||
"ts", |
|||
"tsx", |
|||
"admin", |
|||
"typescript" |
|||
], |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://github.com/jekip/naive-ui-admin.git" |
|||
}, |
|||
"license": "MIT", |
|||
"bugs": { |
|||
"url": "https://github.com/jekip/naive-ui-admin/issues" |
|||
}, |
|||
"engines": { |
|||
"node": "^12 || >=14" |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
module.exports = { |
|||
plugins: { |
|||
tailwindcss: {}, |
|||
autoprefixer: {}, |
|||
}, |
|||
}; |
@ -0,0 +1,20 @@ |
|||
module.exports = { |
|||
printWidth: 100, |
|||
tabWidth: 2, |
|||
useTabs: false, |
|||
semi: true, |
|||
vueIndentScriptAndStyle: true, |
|||
singleQuote: true, |
|||
quoteProps: 'as-needed', |
|||
bracketSpacing: true, |
|||
trailingComma: 'es5', |
|||
jsxBracketSameLine: false, |
|||
jsxSingleQuote: false, |
|||
arrowParens: 'always', |
|||
insertPragma: false, |
|||
requirePragma: false, |
|||
proseWrap: 'never', |
|||
htmlWhitespaceSensitivity: 'strict', |
|||
endOfLine: 'auto', |
|||
rangeStart: 0, |
|||
}; |
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,87 @@ |
|||
<template> |
|||
<NConfigProvider |
|||
v-if="!isLock" |
|||
:locale="zhCN" |
|||
:theme="getDarkTheme" |
|||
:theme-overrides="getThemeOverrides" |
|||
:date-locale="dateZhCN" |
|||
> |
|||
<AppProvider> |
|||
<RouterView /> |
|||
</AppProvider> |
|||
</NConfigProvider> |
|||
|
|||
<transition v-if="isLock && $route.name !== 'login'" name="slide-up"> |
|||
<LockScreen /> |
|||
</transition> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { computed, onMounted, onUnmounted } from 'vue'; |
|||
import { zhCN, dateZhCN, darkTheme } from 'naive-ui'; |
|||
import { LockScreen } from '@/components/Lockscreen'; |
|||
import { AppProvider } from '@/components/Application'; |
|||
import { useScreenLockStore } from '@/store/modules/screenLock.js'; |
|||
import { useRoute } from 'vue-router'; |
|||
import { useDesignSettingStore } from '@/store/modules/designSetting'; |
|||
import { lighten } from '@/utils/index'; |
|||
|
|||
const route = useRoute(); |
|||
const useScreenLock = useScreenLockStore(); |
|||
const designStore = useDesignSettingStore(); |
|||
const isLock = computed(() => useScreenLock.isLocked); |
|||
const lockTime = computed(() => useScreenLock.lockTime); |
|||
|
|||
/** |
|||
* @type import('naive-ui').GlobalThemeOverrides |
|||
*/ |
|||
const getThemeOverrides = computed(() => { |
|||
const appTheme = designStore.appTheme; |
|||
const lightenStr = lighten(designStore.appTheme, 6); |
|||
return { |
|||
common: { |
|||
primaryColor: appTheme, |
|||
primaryColorHover: lightenStr, |
|||
primaryColorPressed: lightenStr, |
|||
primaryColorSuppl: appTheme, |
|||
}, |
|||
LoadingBar: { |
|||
colorLoading: appTheme, |
|||
}, |
|||
}; |
|||
}); |
|||
|
|||
const getDarkTheme = computed(() => (designStore.darkTheme ? darkTheme : undefined)); |
|||
|
|||
let timer: NodeJS.Timer; |
|||
|
|||
const timekeeping = () => { |
|||
clearInterval(timer); |
|||
if (route.name == 'login' || isLock.value) return; |
|||
// 设置不锁屏 |
|||
useScreenLock.setLock(false); |
|||
// 重置锁屏时间 |
|||
useScreenLock.setLockTime(); |
|||
timer = setInterval(() => { |
|||
// 锁屏倒计时递减 |
|||
useScreenLock.setLockTime(lockTime.value - 1); |
|||
if (lockTime.value <= 0) { |
|||
// 设置锁屏 |
|||
useScreenLock.setLock(true); |
|||
return clearInterval(timer); |
|||
} |
|||
}, 1000); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
document.addEventListener('mousedown', timekeeping); |
|||
}); |
|||
|
|||
onUnmounted(() => { |
|||
document.removeEventListener('mousedown', timekeeping); |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less"> |
|||
@import 'styles/index.less'; |
|||
</style> |
@ -0,0 +1,9 @@ |
|||
import { http } from '@/utils/http/axios'; |
|||
|
|||
//获取主控台信息
|
|||
export function getConsoleInfo() { |
|||
return http.request({ |
|||
url: '/dashboard/console', |
|||
method: 'get', |
|||
}); |
|||
} |
@ -0,0 +1,23 @@ |
|||
import { http } from '@/utils/http/axios'; |
|||
|
|||
/** |
|||
* @description: 根据用户id获取用户菜单 |
|||
*/ |
|||
export function adminMenus() { |
|||
return http.request({ |
|||
url: '/menus', |
|||
method: 'GET', |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 获取tree菜单列表 |
|||
* @param params |
|||
*/ |
|||
export function getMenuList(params?) { |
|||
return http.request({ |
|||
url: '/menu/list', |
|||
method: 'GET', |
|||
params, |
|||
}); |
|||
} |
@ -0,0 +1,11 @@ |
|||
import { http } from '@/utils/http/axios'; |
|||
|
|||
/** |
|||
* @description: 角色列表 |
|||
*/ |
|||
export function getRoleList() { |
|||
return http.request({ |
|||
url: '/role/list', |
|||
method: 'GET', |
|||
}); |
|||
} |
@ -0,0 +1,87 @@ |
|||
import { http } from '@/utils/http/axios'; |
|||
|
|||
export interface BasicResponseModel<T = any> { |
|||
code: number; |
|||
message: string; |
|||
result: T; |
|||
} |
|||
|
|||
export interface BasicPageParams { |
|||
pageNumber: number; |
|||
pageSize: number; |
|||
total: number; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @returns 获取验证码 |
|||
*/ |
|||
export function getCodeImg() { |
|||
return http.request( |
|||
{ |
|||
url: '/captchaImage', |
|||
method: 'get', |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @description: 获取用户信息 |
|||
*/ |
|||
export function getUserInfo() { |
|||
return http.request( |
|||
{ |
|||
url: '/getInfo', |
|||
method: 'get', |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @description: 用户登录 |
|||
*/ |
|||
export function login(params) { |
|||
return http.request<BasicResponseModel>( |
|||
{ |
|||
url: '/login', |
|||
method: 'POST', |
|||
params, |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @description: 用户修改密码 |
|||
*/ |
|||
export function changePassword(params, uid) { |
|||
return http.request( |
|||
{ |
|||
url: `/user/u${uid}/changepw`, |
|||
method: 'POST', |
|||
params, |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @description: 用户登出 |
|||
*/ |
|||
export function logout(params) { |
|||
return http.request({ |
|||
url: '/login/logout', |
|||
method: 'POST', |
|||
params, |
|||
}); |
|||
} |
@ -0,0 +1,90 @@ |
|||
import { http } from '@/utils/http/axios'; |
|||
|
|||
/** |
|||
* 获取左侧菜单 |
|||
* @returns |
|||
*/ |
|||
export function getMenu() { |
|||
return http.request( |
|||
{ |
|||
url: '/bi/opt/getMenu', |
|||
method: 'get', |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 获取热源信息 |
|||
* @returns |
|||
*/ |
|||
export function getStationInfo() { |
|||
return http.request( |
|||
{ |
|||
url: '/bi/opt/getStationInfo', |
|||
method: 'get', |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 获取表格header |
|||
* @returns |
|||
*/ |
|||
export function getTableHeader() { |
|||
return http.request( |
|||
{ |
|||
url: '/bi/opt/getTableHeader', |
|||
method: 'get', |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 获取表格数据 |
|||
* @returns |
|||
*/ |
|||
export function getTableData(params) { |
|||
return http.request( |
|||
{ |
|||
url: '/bi/opt/getTableData/'+params, |
|||
method: 'get', |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
|||
|
|||
//获取table
|
|||
export function getTableList(params) { |
|||
return http.request({ |
|||
url: '/table/list', |
|||
method: 'get', |
|||
params, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @description: 配置项修改 |
|||
*/ |
|||
export function editConfig(params) { |
|||
return http.request( |
|||
{ |
|||
url: '/dc/dcUserMonitorConfig/A', |
|||
method: 'POST', |
|||
params, |
|||
}, |
|||
{ |
|||
isTransformResponse: false, |
|||
} |
|||
); |
|||
} |
@ -0,0 +1,58 @@ |
|||
/** |
|||
* 表格参数 |
|||
*/ |
|||
export interface TableVo { |
|||
id: string; |
|||
deviceuuid: string; |
|||
areaid: string; |
|||
C018: object; |
|||
C019: object; |
|||
C020: object; |
|||
C021: object; |
|||
C022: object; |
|||
C023: object; |
|||
C024: object; |
|||
C025: object; |
|||
source: string; |
|||
data: string; |
|||
C007: object; |
|||
C026: object; |
|||
C027: object; |
|||
C028: object; |
|||
C029: object; |
|||
C005: object; |
|||
C006: object; |
|||
C001: object; |
|||
C002: object; |
|||
C003: object; |
|||
C004: object; |
|||
C008: object; |
|||
C009: object; |
|||
C010: object; |
|||
C011: object; |
|||
C012: object; |
|||
C013: object; |
|||
C014: object; |
|||
C015: object; |
|||
C016: boolean; |
|||
C017: object; |
|||
C030: object; |
|||
C031: object; |
|||
C032: object; |
|||
C033: object; |
|||
C034: object; |
|||
C035: object; |
|||
C036: object; |
|||
C037: object; |
|||
C038: object; |
|||
C039: object; |
|||
C040: object; |
|||
C041: object; |
|||
C042: object; |
|||
C043: object; |
|||
C044: object; |
|||
C045: object; |
|||
C046: object; |
|||
C047: object; |
|||
C048: object; |
|||
} |
@ -0,0 +1,539 @@ |
|||
/* Logo 字体 */ |
|||
@font-face { |
|||
font-family: "iconfont logo"; |
|||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); |
|||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), |
|||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), |
|||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), |
|||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); |
|||
} |
|||
|
|||
.logo { |
|||
font-family: "iconfont logo"; |
|||
font-size: 160px; |
|||
font-style: normal; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
|
|||
/* tabs */ |
|||
.nav-tabs { |
|||
position: relative; |
|||
} |
|||
|
|||
.nav-tabs .nav-more { |
|||
position: absolute; |
|||
right: 0; |
|||
bottom: 0; |
|||
height: 42px; |
|||
line-height: 42px; |
|||
color: #666; |
|||
} |
|||
|
|||
#tabs { |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
#tabs li { |
|||
cursor: pointer; |
|||
width: 100px; |
|||
height: 40px; |
|||
line-height: 40px; |
|||
text-align: center; |
|||
font-size: 16px; |
|||
border-bottom: 2px solid transparent; |
|||
position: relative; |
|||
z-index: 1; |
|||
margin-bottom: -1px; |
|||
color: #666; |
|||
} |
|||
|
|||
|
|||
#tabs .active { |
|||
border-bottom-color: #f00; |
|||
color: #222; |
|||
} |
|||
|
|||
.tab-container .content { |
|||
display: none; |
|||
} |
|||
|
|||
/* 页面布局 */ |
|||
.main { |
|||
padding: 30px 100px; |
|||
width: 960px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.main .logo { |
|||
color: #333; |
|||
text-align: left; |
|||
margin-bottom: 30px; |
|||
line-height: 1; |
|||
height: 110px; |
|||
margin-top: -50px; |
|||
overflow: hidden; |
|||
*zoom: 1; |
|||
} |
|||
|
|||
.main .logo a { |
|||
font-size: 160px; |
|||
color: #333; |
|||
} |
|||
|
|||
.helps { |
|||
margin-top: 40px; |
|||
} |
|||
|
|||
.helps pre { |
|||
padding: 20px; |
|||
margin: 10px 0; |
|||
border: solid 1px #e7e1cd; |
|||
background-color: #fffdef; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.icon_lists { |
|||
width: 100% !important; |
|||
overflow: hidden; |
|||
*zoom: 1; |
|||
} |
|||
|
|||
.icon_lists li { |
|||
width: 100px; |
|||
margin-bottom: 10px; |
|||
margin-right: 20px; |
|||
text-align: center; |
|||
list-style: none !important; |
|||
cursor: default; |
|||
} |
|||
|
|||
.icon_lists li .code-name { |
|||
line-height: 1.2; |
|||
} |
|||
|
|||
.icon_lists .icon { |
|||
display: block; |
|||
height: 100px; |
|||
line-height: 100px; |
|||
font-size: 42px; |
|||
margin: 10px auto; |
|||
color: #333; |
|||
-webkit-transition: font-size 0.25s linear, width 0.25s linear; |
|||
-moz-transition: font-size 0.25s linear, width 0.25s linear; |
|||
transition: font-size 0.25s linear, width 0.25s linear; |
|||
} |
|||
|
|||
.icon_lists .icon:hover { |
|||
font-size: 100px; |
|||
} |
|||
|
|||
.icon_lists .svg-icon { |
|||
/* 通过设置 font-size 来改变图标大小 */ |
|||
width: 1em; |
|||
/* 图标和文字相邻时,垂直对齐 */ |
|||
vertical-align: -0.15em; |
|||
/* 通过设置 color 来改变 SVG 的颜色/fill */ |
|||
fill: currentColor; |
|||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 |
|||
normalize.css 中也包含这行 */ |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.icon_lists li .name, |
|||
.icon_lists li .code-name { |
|||
color: #666; |
|||
} |
|||
|
|||
/* markdown 样式 */ |
|||
.markdown { |
|||
color: #666; |
|||
font-size: 14px; |
|||
line-height: 1.8; |
|||
} |
|||
|
|||
.highlight { |
|||
line-height: 1.5; |
|||
} |
|||
|
|||
.markdown img { |
|||
vertical-align: middle; |
|||
max-width: 100%; |
|||
} |
|||
|
|||
.markdown h1 { |
|||
color: #404040; |
|||
font-weight: 500; |
|||
line-height: 40px; |
|||
margin-bottom: 24px; |
|||
} |
|||
|
|||
.markdown h2, |
|||
.markdown h3, |
|||
.markdown h4, |
|||
.markdown h5, |
|||
.markdown h6 { |
|||
color: #404040; |
|||
margin: 1.6em 0 0.6em 0; |
|||
font-weight: 500; |
|||
clear: both; |
|||
} |
|||
|
|||
.markdown h1 { |
|||
font-size: 28px; |
|||
} |
|||
|
|||
.markdown h2 { |
|||
font-size: 22px; |
|||
} |
|||
|
|||
.markdown h3 { |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.markdown h4 { |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.markdown h5 { |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.markdown h6 { |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.markdown hr { |
|||
height: 1px; |
|||
border: 0; |
|||
background: #e9e9e9; |
|||
margin: 16px 0; |
|||
clear: both; |
|||
} |
|||
|
|||
.markdown p { |
|||
margin: 1em 0; |
|||
} |
|||
|
|||
.markdown>p, |
|||
.markdown>blockquote, |
|||
.markdown>.highlight, |
|||
.markdown>ol, |
|||
.markdown>ul { |
|||
width: 80%; |
|||
} |
|||
|
|||
.markdown ul>li { |
|||
list-style: circle; |
|||
} |
|||
|
|||
.markdown>ul li, |
|||
.markdown blockquote ul>li { |
|||
margin-left: 20px; |
|||
padding-left: 4px; |
|||
} |
|||
|
|||
.markdown>ul li p, |
|||
.markdown>ol li p { |
|||
margin: 0.6em 0; |
|||
} |
|||
|
|||
.markdown ol>li { |
|||
list-style: decimal; |
|||
} |
|||
|
|||
.markdown>ol li, |
|||
.markdown blockquote ol>li { |
|||
margin-left: 20px; |
|||
padding-left: 4px; |
|||
} |
|||
|
|||
.markdown code { |
|||
margin: 0 3px; |
|||
padding: 0 5px; |
|||
background: #eee; |
|||
border-radius: 3px; |
|||
} |
|||
|
|||
.markdown strong, |
|||
.markdown b { |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.markdown>table { |
|||
border-collapse: collapse; |
|||
border-spacing: 0px; |
|||
empty-cells: show; |
|||
border: 1px solid #e9e9e9; |
|||
width: 95%; |
|||
margin-bottom: 24px; |
|||
} |
|||
|
|||
.markdown>table th { |
|||
white-space: nowrap; |
|||
color: #333; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.markdown>table th, |
|||
.markdown>table td { |
|||
border: 1px solid #e9e9e9; |
|||
padding: 8px 16px; |
|||
text-align: left; |
|||
} |
|||
|
|||
.markdown>table th { |
|||
background: #F7F7F7; |
|||
} |
|||
|
|||
.markdown blockquote { |
|||
font-size: 90%; |
|||
color: #999; |
|||
border-left: 4px solid #e9e9e9; |
|||
padding-left: 0.8em; |
|||
margin: 1em 0; |
|||
} |
|||
|
|||
.markdown blockquote p { |
|||
margin: 0; |
|||
} |
|||
|
|||
.markdown .anchor { |
|||
opacity: 0; |
|||
transition: opacity 0.3s ease; |
|||
margin-left: 8px; |
|||
} |
|||
|
|||
.markdown .waiting { |
|||
color: #ccc; |
|||
} |
|||
|
|||
.markdown h1:hover .anchor, |
|||
.markdown h2:hover .anchor, |
|||
.markdown h3:hover .anchor, |
|||
.markdown h4:hover .anchor, |
|||
.markdown h5:hover .anchor, |
|||
.markdown h6:hover .anchor { |
|||
opacity: 1; |
|||
display: inline-block; |
|||
} |
|||
|
|||
.markdown>br, |
|||
.markdown>p>br { |
|||
clear: both; |
|||
} |
|||
|
|||
|
|||
.hljs { |
|||
display: block; |
|||
background: white; |
|||
padding: 0.5em; |
|||
color: #333333; |
|||
overflow-x: auto; |
|||
} |
|||
|
|||
.hljs-comment, |
|||
.hljs-meta { |
|||
color: #969896; |
|||
} |
|||
|
|||
.hljs-string, |
|||
.hljs-variable, |
|||
.hljs-template-variable, |
|||
.hljs-strong, |
|||
.hljs-emphasis, |
|||
.hljs-quote { |
|||
color: #df5000; |
|||
} |
|||
|
|||
.hljs-keyword, |
|||
.hljs-selector-tag, |
|||
.hljs-type { |
|||
color: #a71d5d; |
|||
} |
|||
|
|||
.hljs-literal, |
|||
.hljs-symbol, |
|||
.hljs-bullet, |
|||
.hljs-attribute { |
|||
color: #0086b3; |
|||
} |
|||
|
|||
.hljs-section, |
|||
.hljs-name { |
|||
color: #63a35c; |
|||
} |
|||
|
|||
.hljs-tag { |
|||
color: #333333; |
|||
} |
|||
|
|||
.hljs-title, |
|||
.hljs-attr, |
|||
.hljs-selector-id, |
|||
.hljs-selector-class, |
|||
.hljs-selector-attr, |
|||
.hljs-selector-pseudo { |
|||
color: #795da3; |
|||
} |
|||
|
|||
.hljs-addition { |
|||
color: #55a532; |
|||
background-color: #eaffea; |
|||
} |
|||
|
|||
.hljs-deletion { |
|||
color: #bd2c00; |
|||
background-color: #ffecec; |
|||
} |
|||
|
|||
.hljs-link { |
|||
text-decoration: underline; |
|||
} |
|||
|
|||
/* 代码高亮 */ |
|||
/* PrismJS 1.15.0 |
|||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ |
|||
/** |
|||
* prism.js default theme for JavaScript, CSS and HTML |
|||
* Based on dabblet (http://dabblet.com) |
|||
* @author Lea Verou |
|||
*/ |
|||
code[class*="language-"], |
|||
pre[class*="language-"] { |
|||
color: black; |
|||
background: none; |
|||
text-shadow: 0 1px white; |
|||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; |
|||
text-align: left; |
|||
white-space: pre; |
|||
word-spacing: normal; |
|||
word-break: normal; |
|||
word-wrap: normal; |
|||
line-height: 1.5; |
|||
|
|||
-moz-tab-size: 4; |
|||
-o-tab-size: 4; |
|||
tab-size: 4; |
|||
|
|||
-webkit-hyphens: none; |
|||
-moz-hyphens: none; |
|||
-ms-hyphens: none; |
|||
hyphens: none; |
|||
} |
|||
|
|||
pre[class*="language-"]::-moz-selection, |
|||
pre[class*="language-"] ::-moz-selection, |
|||
code[class*="language-"]::-moz-selection, |
|||
code[class*="language-"] ::-moz-selection { |
|||
text-shadow: none; |
|||
background: #b3d4fc; |
|||
} |
|||
|
|||
pre[class*="language-"]::selection, |
|||
pre[class*="language-"] ::selection, |
|||
code[class*="language-"]::selection, |
|||
code[class*="language-"] ::selection { |
|||
text-shadow: none; |
|||
background: #b3d4fc; |
|||
} |
|||
|
|||
@media print { |
|||
|
|||
code[class*="language-"], |
|||
pre[class*="language-"] { |
|||
text-shadow: none; |
|||
} |
|||
} |
|||
|
|||
/* Code blocks */ |
|||
pre[class*="language-"] { |
|||
padding: 1em; |
|||
margin: .5em 0; |
|||
overflow: auto; |
|||
} |
|||
|
|||
:not(pre)>code[class*="language-"], |
|||
pre[class*="language-"] { |
|||
background: #f5f2f0; |
|||
} |
|||
|
|||
/* Inline code */ |
|||
:not(pre)>code[class*="language-"] { |
|||
padding: .1em; |
|||
border-radius: .3em; |
|||
white-space: normal; |
|||
} |
|||
|
|||
.token.comment, |
|||
.token.prolog, |
|||
.token.doctype, |
|||
.token.cdata { |
|||
color: slategray; |
|||
} |
|||
|
|||
.token.punctuation { |
|||
color: #999; |
|||
} |
|||
|
|||
.namespace { |
|||
opacity: .7; |
|||
} |
|||
|
|||
.token.property, |
|||
.token.tag, |
|||
.token.boolean, |
|||
.token.number, |
|||
.token.constant, |
|||
.token.symbol, |
|||
.token.deleted { |
|||
color: #905; |
|||
} |
|||
|
|||
.token.selector, |
|||
.token.attr-name, |
|||
.token.string, |
|||
.token.char, |
|||
.token.builtin, |
|||
.token.inserted { |
|||
color: #690; |
|||
} |
|||
|
|||
.token.operator, |
|||
.token.entity, |
|||
.token.url, |
|||
.language-css .token.string, |
|||
.style .token.string { |
|||
color: #9a6e3a; |
|||
background: hsla(0, 0%, 100%, .5); |
|||
} |
|||
|
|||
.token.atrule, |
|||
.token.attr-value, |
|||
.token.keyword { |
|||
color: #07a; |
|||
} |
|||
|
|||
.token.function, |
|||
.token.class-name { |
|||
color: #DD4A68; |
|||
} |
|||
|
|||
.token.regex, |
|||
.token.important, |
|||
.token.variable { |
|||
color: #e90; |
|||
} |
|||
|
|||
.token.important, |
|||
.token.bold { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.token.italic { |
|||
font-style: italic; |
|||
} |
|||
|
|||
.token.entity { |
|||
cursor: help; |
|||
} |
@ -0,0 +1,230 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"/> |
|||
<title>iconfont Demo</title> |
|||
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/> |
|||
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/> |
|||
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css"> |
|||
<link rel="stylesheet" href="demo.css"> |
|||
<link rel="stylesheet" href="iconfont.css"> |
|||
<script src="iconfont.js"></script> |
|||
<!-- jQuery --> |
|||
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script> |
|||
<!-- 代码高亮 --> |
|||
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script> |
|||
<style> |
|||
.main .logo { |
|||
margin-top: 0; |
|||
height: auto; |
|||
} |
|||
|
|||
.main .logo a { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.main .logo .sub-title { |
|||
margin-left: 0.5em; |
|||
font-size: 22px; |
|||
color: #fff; |
|||
background: linear-gradient(-45deg, #3967FF, #B500FE); |
|||
-webkit-background-clip: text; |
|||
-webkit-text-fill-color: transparent; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<div class="main"> |
|||
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank"> |
|||
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg"> |
|||
|
|||
</a></h1> |
|||
<div class="nav-tabs"> |
|||
<ul id="tabs" class="dib-box"> |
|||
<li class="dib active"><span>Unicode</span></li> |
|||
<li class="dib"><span>Font class</span></li> |
|||
<li class="dib"><span>Symbol</span></li> |
|||
</ul> |
|||
|
|||
</div> |
|||
<div class="tab-container"> |
|||
<div class="content unicode" style="display: block;"> |
|||
<ul class="icon_lists dib-box"> |
|||
|
|||
<li class="dib"> |
|||
<span class="icon iconfont"></span> |
|||
<div class="name">箭头_切换向下</div> |
|||
<div class="code-name">&#xeb04;</div> |
|||
</li> |
|||
|
|||
<li class="dib"> |
|||
<span class="icon iconfont"></span> |
|||
<div class="name">箭头_切换向上</div> |
|||
<div class="code-name">&#xeb05;</div> |
|||
</li> |
|||
|
|||
</ul> |
|||
<div class="article markdown"> |
|||
<h2 id="unicode-">Unicode 引用</h2> |
|||
<hr> |
|||
|
|||
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p> |
|||
<ul> |
|||
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li> |
|||
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li> |
|||
</ul> |
|||
<blockquote> |
|||
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p> |
|||
</blockquote> |
|||
<p>Unicode 使用步骤如下:</p> |
|||
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3> |
|||
<pre><code class="language-css" |
|||
>@font-face { |
|||
font-family: 'iconfont'; |
|||
src: url('iconfont.ttf?t=1692926138640') format('truetype'); |
|||
} |
|||
</code></pre> |
|||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3> |
|||
<pre><code class="language-css" |
|||
>.iconfont { |
|||
font-family: "iconfont" !important; |
|||
font-size: 16px; |
|||
font-style: normal; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
</code></pre> |
|||
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3> |
|||
<pre> |
|||
<code class="language-html" |
|||
><span class="iconfont">&#x33;</span> |
|||
</code></pre> |
|||
<blockquote> |
|||
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p> |
|||
</blockquote> |
|||
</div> |
|||
</div> |
|||
<div class="content font-class"> |
|||
<ul class="icon_lists dib-box"> |
|||
|
|||
<li class="dib"> |
|||
<span class="icon iconfont icon-decline"></span> |
|||
<div class="name"> |
|||
箭头_切换向下 |
|||
</div> |
|||
<div class="code-name">.icon-decline |
|||
</div> |
|||
</li> |
|||
|
|||
<li class="dib"> |
|||
<span class="icon iconfont icon-rise"></span> |
|||
<div class="name"> |
|||
箭头_切换向上 |
|||
</div> |
|||
<div class="code-name">.icon-rise |
|||
</div> |
|||
</li> |
|||
|
|||
</ul> |
|||
<div class="article markdown"> |
|||
<h2 id="font-class-">font-class 引用</h2> |
|||
<hr> |
|||
|
|||
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p> |
|||
<p>与 Unicode 使用方式相比,具有如下特点:</p> |
|||
<ul> |
|||
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li> |
|||
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li> |
|||
</ul> |
|||
<p>使用步骤如下:</p> |
|||
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3> |
|||
<pre><code class="language-html"><link rel="stylesheet" href="./iconfont.css"> |
|||
</code></pre> |
|||
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3> |
|||
<pre><code class="language-html"><span class="iconfont icon-xxx"></span> |
|||
</code></pre> |
|||
<blockquote> |
|||
<p>" |
|||
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p> |
|||
</blockquote> |
|||
</div> |
|||
</div> |
|||
<div class="content symbol"> |
|||
<ul class="icon_lists dib-box"> |
|||
|
|||
<li class="dib"> |
|||
<svg class="icon svg-icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-decline"></use> |
|||
</svg> |
|||
<div class="name">箭头_切换向下</div> |
|||
<div class="code-name">#icon-decline</div> |
|||
</li> |
|||
|
|||
<li class="dib"> |
|||
<svg class="icon svg-icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-rise"></use> |
|||
</svg> |
|||
<div class="name">箭头_切换向上</div> |
|||
<div class="code-name">#icon-rise</div> |
|||
</li> |
|||
|
|||
</ul> |
|||
<div class="article markdown"> |
|||
<h2 id="symbol-">Symbol 引用</h2> |
|||
<hr> |
|||
|
|||
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a> |
|||
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p> |
|||
<ul> |
|||
<li>支持多色图标了,不再受单色限制。</li> |
|||
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li> |
|||
<li>兼容性较差,支持 IE9+,及现代浏览器。</li> |
|||
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li> |
|||
</ul> |
|||
<p>使用步骤如下:</p> |
|||
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3> |
|||
<pre><code class="language-html"><script src="./iconfont.js"></script> |
|||
</code></pre> |
|||
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3> |
|||
<pre><code class="language-html"><style> |
|||
.icon { |
|||
width: 1em; |
|||
height: 1em; |
|||
vertical-align: -0.15em; |
|||
fill: currentColor; |
|||
overflow: hidden; |
|||
} |
|||
</style> |
|||
</code></pre> |
|||
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3> |
|||
<pre><code class="language-html"><svg class="icon" aria-hidden="true"> |
|||
<use xlink:href="#icon-xxx"></use> |
|||
</svg> |
|||
</code></pre> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<script> |
|||
$(document).ready(function () { |
|||
$('.tab-container .content:first').show() |
|||
|
|||
$('#tabs li').click(function (e) { |
|||
var tabContent = $('.tab-container .content') |
|||
var index = $(this).index() |
|||
|
|||
if ($(this).hasClass('active')) { |
|||
return |
|||
} else { |
|||
$('#tabs li').removeClass('active') |
|||
$(this).addClass('active') |
|||
|
|||
tabContent.hide().eq(index).fadeIn() |
|||
} |
|||
}) |
|||
}) |
|||
</script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,21 @@ |
|||
@font-face { |
|||
font-family: "iconfont"; /* Project id */ |
|||
src: url('iconfont.ttf?t=1692926138640') format('truetype'); |
|||
} |
|||
|
|||
.iconfont { |
|||
font-family: "iconfont" !important; |
|||
font-size: 16px; |
|||
font-style: normal; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
|
|||
.icon-decline:before { |
|||
content: "\eb04"; |
|||
} |
|||
|
|||
.icon-rise:before { |
|||
content: "\eb05"; |
|||
} |
|||
|
@ -0,0 +1 @@ |
|||
window._iconfont_svg_string_='<svg><symbol id="icon-decline" viewBox="0 0 1024 1024"><path d="M538.51148682 873.04849423L326.20720947 660.74421688l62.13783703-62.13783704 150.16644032 150.16644032V44.544H636.89639465v932.06755556l-98.38490783-103.56306133z" fill="#444444" ></path></symbol><symbol id="icon-rise" viewBox="0 0 1024 1024"><path d="M484.06629095 154.70743703l212.30427736 207.12612387-62.13783704 62.13783704-150.16644032-150.16644032V978.03377778H385.68138313V45.96622222l98.38490782 108.74121481z" fill="#444444" ></path></symbol></svg>',function(n){var e=(e=document.getElementsByTagName("script"))[e.length-1],t=e.getAttribute("data-injectcss"),e=e.getAttribute("data-disable-injectsvg");if(!e){var i,o,d,c,l,s=function(e,t){t.parentNode.insertBefore(e,t)};if(t&&!n.__iconfont__svg__cssinject__){n.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(e){console&&console.log(e)}}i=function(){var e,t=document.createElement("div");t.innerHTML=n._iconfont_svg_string_,(t=t.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",t=t,(e=document.body).firstChild?s(t,e.firstChild):e.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(i,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),i()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(d=i,c=n.document,l=!1,r(),c.onreadystatechange=function(){"complete"==c.readyState&&(c.onreadystatechange=null,a())})}function a(){l||(l=!0,d())}function r(){try{c.documentElement.doScroll("left")}catch(e){return void setTimeout(r,50)}a()}}(window); |
@ -0,0 +1,23 @@ |
|||
{ |
|||
"id": "", |
|||
"name": "", |
|||
"font_family": "iconfont", |
|||
"css_prefix_text": "icon-", |
|||
"description": "", |
|||
"glyphs": [ |
|||
{ |
|||
"icon_id": "122793502", |
|||
"name": "箭头_切换向下", |
|||
"font_class": "decline", |
|||
"unicode": "eb04", |
|||
"unicode_decimal": 60164 |
|||
}, |
|||
{ |
|||
"icon_id": "122793503", |
|||
"name": "箭头_切换向上", |
|||
"font_class": "rise", |
|||
"unicode": "eb05", |
|||
"unicode_decimal": 60165 |
|||
} |
|||
] |
|||
} |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 123 KiB |
After Width: | Height: | Size: 177 KiB |
After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1,26 @@ |
|||
<template> |
|||
<n-dialog-provider> |
|||
<n-notification-provider> |
|||
<n-message-provider> |
|||
<slot name="default"></slot> |
|||
</n-message-provider> |
|||
</n-notification-provider> |
|||
</n-dialog-provider> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent } from 'vue'; |
|||
import { NDialogProvider, NNotificationProvider, NMessageProvider } from 'naive-ui'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'Application', |
|||
components: { |
|||
NDialogProvider, |
|||
NNotificationProvider, |
|||
NMessageProvider, |
|||
}, |
|||
setup() { |
|||
return {}; |
|||
}, |
|||
}); |
|||
</script> |
@ -0,0 +1,3 @@ |
|||
import AppProvider from './Application.vue'; |
|||
|
|||
export { AppProvider }; |
@ -0,0 +1,110 @@ |
|||
<template> |
|||
<span :style="{ color }"> |
|||
{{ value }} |
|||
</span> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent, ref, computed, watchEffect, unref, onMounted, watch } from 'vue'; |
|||
import { useTransition, TransitionPresets } from '@vueuse/core'; |
|||
import { isNumber } from '@/utils/is'; |
|||
|
|||
const props = { |
|||
startVal: { type: Number, default: 0 }, |
|||
endVal: { type: Number, default: 2021 }, |
|||
duration: { type: Number, default: 1500 }, |
|||
autoplay: { type: Boolean, default: true }, |
|||
decimals: { |
|||
type: Number, |
|||
default: 0, |
|||
validator(value: number) { |
|||
return value >= 0; |
|||
}, |
|||
}, |
|||
prefix: { type: String, default: '' }, |
|||
suffix: { type: String, default: '' }, |
|||
separator: { type: String, default: ',' }, |
|||
decimal: { type: String, default: '.' }, |
|||
/** |
|||
* font color |
|||
*/ |
|||
color: { type: String }, |
|||
/** |
|||
* Turn on digital animation |
|||
*/ |
|||
useEasing: { type: Boolean, default: true }, |
|||
/** |
|||
* Digital animation |
|||
*/ |
|||
transition: { type: String, default: 'linear' }, |
|||
}; |
|||
|
|||
export default defineComponent({ |
|||
name: 'CountTo', |
|||
props, |
|||
emits: ['onStarted', 'onFinished'], |
|||
setup(props, { emit }) { |
|||
const source = ref(props.startVal); |
|||
const disabled = ref(false); |
|||
let outputValue = useTransition(source); |
|||
|
|||
const value = computed(() => formatNumber(unref(outputValue))); |
|||
|
|||
watchEffect(() => { |
|||
source.value = props.startVal; |
|||
}); |
|||
|
|||
watch([() => props.startVal, () => props.endVal], () => { |
|||
if (props.autoplay) { |
|||
start(); |
|||
} |
|||
}); |
|||
|
|||
onMounted(() => { |
|||
props.autoplay && start(); |
|||
}); |
|||
|
|||
function start() { |
|||
run(); |
|||
source.value = props.endVal; |
|||
} |
|||
|
|||
function reset() { |
|||
source.value = props.startVal; |
|||
run(); |
|||
} |
|||
|
|||
function run() { |
|||
outputValue = useTransition(source, { |
|||
disabled, |
|||
duration: props.duration, |
|||
onFinished: () => emit('onFinished'), |
|||
onStarted: () => emit('onStarted'), |
|||
...(props.useEasing ? { transition: TransitionPresets[props.transition] } : {}), |
|||
}); |
|||
} |
|||
|
|||
function formatNumber(num: number | string) { |
|||
if (!num) { |
|||
return ''; |
|||
} |
|||
const { decimals, decimal, separator, suffix, prefix } = props; |
|||
num = Number(num).toFixed(decimals); |
|||
num += ''; |
|||
|
|||
const x = num.split('.'); |
|||
let x1 = x[0]; |
|||
const x2 = x.length > 1 ? decimal + x[1] : ''; |
|||
|
|||
const rgx = /(\d+)(\d{3})/; |
|||
if (separator && !isNumber(separator)) { |
|||
while (rgx.test(x1)) { |
|||
x1 = x1.replace(rgx, '$1' + separator + '$2'); |
|||
} |
|||
} |
|||
return prefix + x1 + x2 + suffix; |
|||
} |
|||
|
|||
return { value, start, reset }; |
|||
}, |
|||
}); |
|||
</script> |
@ -0,0 +1,4 @@ |
|||
import { withInstall } from '@/utils'; |
|||
import countTo from './CountTo.vue'; |
|||
|
|||
export const CountTo = withInstall(countTo); |
@ -0,0 +1,4 @@ |
|||
export { default as BasicForm } from './src/BasicForm.vue'; |
|||
export { useForm } from './src/hooks/useForm'; |
|||
export * from './src/types/form'; |
|||
export * from './src/types/index'; |
@ -0,0 +1,318 @@ |
|||
<template> |
|||
<n-form v-bind="getBindValue" :model="formModel" ref="formElRef"> |
|||
<n-grid v-bind="getGrid"> |
|||
<n-gi v-bind="schema.giProps" v-for="schema in getSchema" :key="schema.field"> |
|||
<n-form-item :label="schema.label" :path="schema.field"> |
|||
<!--标签名右侧温馨提示--> |
|||
<template #label v-if="schema.labelMessage"> |
|||
{{ schema.label }} |
|||
<n-tooltip trigger="hover" :style="schema.labelMessageStyle"> |
|||
<template #trigger> |
|||
<n-icon size="18" class="cursor-pointer text-gray-400"> |
|||
<QuestionCircleOutlined /> |
|||
</n-icon> |
|||
</template> |
|||
{{ schema.labelMessage }} |
|||
</n-tooltip> |
|||
</template> |
|||
|
|||
<!--判断插槽--> |
|||
<template v-if="schema.slot"> |
|||
<slot |
|||
:name="schema.slot" |
|||
:model="formModel" |
|||
:field="schema.field" |
|||
:value="formModel[schema.field]" |
|||
></slot> |
|||
</template> |
|||
|
|||
<!--NCheckbox--> |
|||
<template v-else-if="schema.component === 'NCheckbox'"> |
|||
<n-checkbox-group v-model:value="formModel[schema.field]"> |
|||
<n-space> |
|||
<n-checkbox |
|||
v-for="item in schema.componentProps.options" |
|||
:key="item.value" |
|||
:value="item.value" |
|||
:label="item.label" |
|||
/> |
|||
</n-space> |
|||
</n-checkbox-group> |
|||
</template> |
|||
|
|||
<!--NRadioGroup--> |
|||
<template v-else-if="schema.component === 'NRadioGroup'"> |
|||
<n-radio-group v-model:value="formModel[schema.field]"> |
|||
<n-space> |
|||
<n-radio |
|||
v-for="item in schema.componentProps.options" |
|||
:key="item.value" |
|||
:value="item.value" |
|||
> |
|||
{{ item.label }} |
|||
</n-radio> |
|||
</n-space> |
|||
</n-radio-group> |
|||
</template> |
|||
<!--动态渲染表单组件--> |
|||
<component |
|||
v-else |
|||
v-bind="getComponentProps(schema)" |
|||
:is="schema.component" |
|||
v-model:value="formModel[schema.field]" |
|||
:class="{ isFull: schema.isFull != false && getProps.isFull }" |
|||
/> |
|||
<!--组件后面的内容--> |
|||
<template v-if="schema.suffix"> |
|||
<slot |
|||
:name="schema.suffix" |
|||
:model="formModel" |
|||
:field="schema.field" |
|||
:value="formModel[schema.field]" |
|||
></slot> |
|||
</template> |
|||
</n-form-item> |
|||
</n-gi> |
|||
<!--提交 重置 展开 收起 按钮--> |
|||
<n-gi |
|||
:span="isInline ? '' : 24" |
|||
:suffix="isInline ? true : false" |
|||
#="{ overflow }" |
|||
v-if="getProps.showActionButtonGroup" |
|||
> |
|||
<n-space |
|||
align="center" |
|||
:justify="isInline ? 'end' : 'start'" |
|||
:style="{ 'margin-left': `${isInline ? 12 : getProps.labelWidth}px` }" |
|||
> |
|||
<n-button |
|||
v-if="getProps.showSubmitButton" |
|||
v-bind="getSubmitBtnOptions" |
|||
@click="handleSubmit" |
|||
:loading="loadingSub" |
|||
>{{ getProps.submitButtonText }}</n-button |
|||
> |
|||
<n-button |
|||
v-if="getProps.showResetButton" |
|||
v-bind="getResetBtnOptions" |
|||
@click="resetFields" |
|||
>{{ getProps.resetButtonText }}</n-button |
|||
> |
|||
<n-button |
|||
type="primary" |
|||
text |
|||
icon-placement="right" |
|||
v-if="isInline && getProps.showAdvancedButton" |
|||
@click="unfoldToggle" |
|||
> |
|||
<template #icon> |
|||
<n-icon size="14" class="unfold-icon" v-if="overflow"> |
|||
<DownOutlined /> |
|||
</n-icon> |
|||
<n-icon size="14" class="unfold-icon" v-else> |
|||
<UpOutlined /> |
|||
</n-icon> |
|||
</template> |
|||
{{ overflow ? '展开' : '收起' }} |
|||
</n-button> |
|||
</n-space> |
|||
</n-gi> |
|||
</n-grid> |
|||
</n-form> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, reactive, ref, computed, unref, onMounted, watch } from 'vue'; |
|||
import { createPlaceholderMessage } from './helper'; |
|||
import { useFormEvents } from './hooks/useFormEvents'; |
|||
import { useFormValues } from './hooks/useFormValues'; |
|||
|
|||
import { basicProps } from './props'; |
|||
import { DownOutlined, UpOutlined, QuestionCircleOutlined } from '@vicons/antd'; |
|||
|
|||
import type { Ref } from 'vue'; |
|||
import type { GridProps } from 'naive-ui/lib/grid'; |
|||
import type { FormSchema, FormProps, FormActionType } from './types/form'; |
|||
|
|||
import { isArray } from '@/utils/is/index'; |
|||
import { deepMerge } from '@/utils'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'BasicForm', |
|||
components: { DownOutlined, UpOutlined, QuestionCircleOutlined }, |
|||
props: { |
|||
...basicProps, |
|||
}, |
|||
emits: ['reset', 'submit', 'register'], |
|||
setup(props, { emit, attrs }) { |
|||
const defaultFormModel = ref<Recordable>({}); |
|||
const formModel = reactive<Recordable>({}); |
|||
const propsRef = ref<Partial<FormProps>>({}); |
|||
const schemaRef = ref<Nullable<FormSchema[]>>(null); |
|||
const formElRef = ref<Nullable<FormActionType>>(null); |
|||
const gridCollapsed = ref(true); |
|||
const loadingSub = ref(false); |
|||
const isUpdateDefaultRef = ref(false); |
|||
|
|||
const getSubmitBtnOptions = computed(() => { |
|||
return Object.assign( |
|||
{ |
|||
size: props.size, |
|||
type: 'primary', |
|||
}, |
|||
props.submitButtonOptions |
|||
); |
|||
}); |
|||
|
|||
const getResetBtnOptions = computed(() => { |
|||
return Object.assign( |
|||
{ |
|||
size: props.size, |
|||
type: 'default', |
|||
}, |
|||
props.resetButtonOptions |
|||
); |
|||
}); |
|||
|
|||
function getComponentProps(schema) { |
|||
const compProps = schema.componentProps ?? {}; |
|||
const component = schema.component; |
|||
return { |
|||
clearable: true, |
|||
placeholder: createPlaceholderMessage(unref(component)), |
|||
...compProps, |
|||
}; |
|||
} |
|||
|
|||
const getProps = computed((): FormProps => { |
|||
const formProps = { ...props, ...unref(propsRef) } as FormProps; |
|||
const rulesObj: any = { |
|||
rules: {}, |
|||
}; |
|||
const schemas: any = formProps.schemas || []; |
|||
schemas.forEach((item) => { |
|||
if (item.rules && isArray(item.rules)) { |
|||
rulesObj.rules[item.field] = item.rules; |
|||
} |
|||
}); |
|||
return { ...formProps, ...unref(rulesObj) }; |
|||
}); |
|||
|
|||
const isInline = computed(() => { |
|||
const { layout } = unref(getProps); |
|||
return layout === 'inline'; |
|||
}); |
|||
|
|||
const getGrid = computed((): GridProps => { |
|||
const { gridProps } = unref(getProps); |
|||
return { |
|||
...gridProps, |
|||
collapsed: isInline.value ? gridCollapsed.value : false, |
|||
responsive: 'screen', |
|||
}; |
|||
}); |
|||
|
|||
const getBindValue = computed( |
|||
() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable) |
|||
); |
|||
|
|||
const getSchema = computed((): FormSchema[] => { |
|||
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any); |
|||
for (const schema of schemas) { |
|||
const { defaultValue } = schema; |
|||
// handle date type |
|||
// dateItemType.includes(component as string) |
|||
if (defaultValue) { |
|||
schema.defaultValue = defaultValue; |
|||
} |
|||
} |
|||
return schemas as FormSchema[]; |
|||
}); |
|||
|
|||
const { handleFormValues, initDefault } = useFormValues({ |
|||
defaultFormModel, |
|||
getSchema, |
|||
formModel, |
|||
}); |
|||
|
|||
const { handleSubmit, validate, resetFields, getFieldsValue, clearValidate, setFieldsValue } = |
|||
useFormEvents({ |
|||
emit, |
|||
getProps, |
|||
formModel, |
|||
getSchema, |
|||
formElRef: formElRef as Ref<FormActionType>, |
|||
defaultFormModel, |
|||
loadingSub, |
|||
handleFormValues, |
|||
}); |
|||
|
|||
function unfoldToggle() { |
|||
gridCollapsed.value = !gridCollapsed.value; |
|||
} |
|||
|
|||
async function setProps(formProps: Partial<FormProps>): Promise<void> { |
|||
propsRef.value = deepMerge(unref(propsRef) || {}, formProps); |
|||
} |
|||
|
|||
const formActionType: Partial<FormActionType> = { |
|||
getFieldsValue, |
|||
setFieldsValue, |
|||
resetFields, |
|||
validate, |
|||
clearValidate, |
|||
setProps, |
|||
submit: handleSubmit, |
|||
}; |
|||
|
|||
watch( |
|||
() => getSchema.value, |
|||
(schema) => { |
|||
if (unref(isUpdateDefaultRef)) { |
|||
return; |
|||
} |
|||
if (schema?.length) { |
|||
initDefault(); |
|||
isUpdateDefaultRef.value = true; |
|||
} |
|||
} |
|||
); |
|||
|
|||
onMounted(() => { |
|||
initDefault(); |
|||
emit('register', formActionType); |
|||
}); |
|||
|
|||
return { |
|||
formElRef, |
|||
formModel, |
|||
getGrid, |
|||
getProps, |
|||
getBindValue, |
|||
getSchema, |
|||
getSubmitBtnOptions, |
|||
getResetBtnOptions, |
|||
handleSubmit, |
|||
resetFields, |
|||
loadingSub, |
|||
isInline, |
|||
getComponentProps, |
|||
unfoldToggle, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.isFull { |
|||
width: 100%; |
|||
justify-content: flex-start; |
|||
} |
|||
|
|||
.unfold-icon { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 100%; |
|||
margin-left: -3px; |
|||
} |
|||
</style> |
@ -0,0 +1,42 @@ |
|||
import { ComponentType } from './types/index'; |
|||
|
|||
/** |
|||
* @description: 生成placeholder |
|||
*/ |
|||
export function createPlaceholderMessage(component: ComponentType) { |
|||
if (component === 'NInput') return '请输入'; |
|||
if ( |
|||
['NPicker', 'NSelect', 'NCheckbox', 'NRadio', 'NSwitch', 'NDatePicker', 'NTimePicker'].includes( |
|||
component |
|||
) |
|||
) |
|||
return '请选择'; |
|||
return ''; |
|||
} |
|||
|
|||
const DATE_TYPE = ['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker']; |
|||
|
|||
function genType() { |
|||
return [...DATE_TYPE, 'RangePicker']; |
|||
} |
|||
|
|||
/** |
|||
* 时间字段 |
|||
*/ |
|||
export const dateItemType = genType(); |
|||
|
|||
export function defaultType(component) { |
|||
if (component === 'NInput') return ''; |
|||
if (component === 'NInputNumber') return null; |
|||
return [ |
|||
'NPicker', |
|||
'NSelect', |
|||
'NCheckbox', |
|||
'NRadio', |
|||
'NSwitch', |
|||
'NDatePicker', |
|||
'NTimePicker', |
|||
].includes(component) |
|||
? '' |
|||
: undefined; |
|||
} |
@ -0,0 +1,86 @@ |
|||
import type { FormProps, FormActionType, UseFormReturnType } from '../types/form'; |
|||
import type { DynamicProps } from '/#/utils'; |
|||
|
|||
import { ref, onUnmounted, unref, nextTick, watch } from 'vue'; |
|||
import { isProdMode } from '@/utils/env'; |
|||
import { getDynamicProps } from '@/utils'; |
|||
|
|||
type Props = Partial<DynamicProps<FormProps>>; |
|||
|
|||
export function useForm(props?: Props): UseFormReturnType { |
|||
const formRef = ref<Nullable<FormActionType>>(null); |
|||
const loadedRef = ref<Nullable<boolean>>(false); |
|||
|
|||
async function getForm() { |
|||
const form = unref(formRef); |
|||
if (!form) { |
|||
console.error( |
|||
'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!' |
|||
); |
|||
} |
|||
await nextTick(); |
|||
return form as FormActionType; |
|||
} |
|||
|
|||
function register(instance: FormActionType) { |
|||
isProdMode() && |
|||
onUnmounted(() => { |
|||
formRef.value = null; |
|||
loadedRef.value = null; |
|||
}); |
|||
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return; |
|||
|
|||
formRef.value = instance; |
|||
loadedRef.value = true; |
|||
|
|||
watch( |
|||
() => props, |
|||
() => { |
|||
props && instance.setProps(getDynamicProps(props)); |
|||
}, |
|||
{ |
|||
immediate: true, |
|||
deep: true, |
|||
} |
|||
); |
|||
} |
|||
|
|||
const methods: FormActionType = { |
|||
setProps: async (formProps: Partial<FormProps>) => { |
|||
const form = await getForm(); |
|||
await form.setProps(formProps); |
|||
}, |
|||
|
|||
resetFields: async () => { |
|||
getForm().then(async (form) => { |
|||
await form.resetFields(); |
|||
}); |
|||
}, |
|||
|
|||
clearValidate: async (name?: string | string[]) => { |
|||
const form = await getForm(); |
|||
await form.clearValidate(name); |
|||
}, |
|||
|
|||
getFieldsValue: <T>() => { |
|||
return unref(formRef)?.getFieldsValue() as T; |
|||
}, |
|||
|
|||
setFieldsValue: async <T>(values: T) => { |
|||
const form = await getForm(); |
|||
await form.setFieldsValue<T>(values); |
|||
}, |
|||
|
|||
submit: async (): Promise<any> => { |
|||
const form = await getForm(); |
|||
return form.submit(); |
|||
}, |
|||
|
|||
validate: async (nameList?: any[]): Promise<Recordable> => { |
|||
const form = await getForm(); |
|||
return form.validate(nameList); |
|||
}, |
|||
}; |
|||
|
|||
return [register, methods]; |
|||
} |
@ -0,0 +1,11 @@ |
|||
import { provide, inject } from 'vue'; |
|||
|
|||
const key = Symbol('formElRef'); |
|||
|
|||
export function createFormContext(instance) { |
|||
provide(key, instance); |
|||
} |
|||
|
|||
export function useFormContext() { |
|||
return inject(key); |
|||
} |
@ -0,0 +1,107 @@ |
|||
import type { ComputedRef, Ref } from 'vue'; |
|||
import type { FormProps, FormSchema, FormActionType } from '../types/form'; |
|||
import { unref, toRaw } from 'vue'; |
|||
import { isFunction } from '@/utils/is'; |
|||
|
|||
declare type EmitType = (event: string, ...args: any[]) => void; |
|||
|
|||
interface UseFormActionContext { |
|||
emit: EmitType; |
|||
getProps: ComputedRef<FormProps>; |
|||
getSchema: ComputedRef<FormSchema[]>; |
|||
formModel: Recordable; |
|||
formElRef: Ref<FormActionType>; |
|||
defaultFormModel: Recordable; |
|||
loadingSub: Ref<boolean>; |
|||
handleFormValues: Function; |
|||
} |
|||
|
|||
export function useFormEvents({ |
|||
emit, |
|||
getProps, |
|||
formModel, |
|||
getSchema, |
|||
formElRef, |
|||
defaultFormModel, |
|||
loadingSub, |
|||
handleFormValues, |
|||
}: UseFormActionContext) { |
|||
// 验证
|
|||
async function validate() { |
|||
return unref(formElRef)?.validate(); |
|||
} |
|||
|
|||
// 提交
|
|||
async function handleSubmit(e?: Event): Promise<void> { |
|||
e && e.preventDefault(); |
|||
loadingSub.value = true; |
|||
const { submitFunc } = unref(getProps); |
|||
if (submitFunc && isFunction(submitFunc)) { |
|||
await submitFunc(); |
|||
return; |
|||
} |
|||
const formEl = unref(formElRef); |
|||
if (!formEl) return; |
|||
try { |
|||
await validate(); |
|||
loadingSub.value = false; |
|||
emit('submit', formModel); |
|||
return; |
|||
} catch (error) { |
|||
loadingSub.value = false; |
|||
return; |
|||
} |
|||
} |
|||
|
|||
//清空校验
|
|||
async function clearValidate() { |
|||
// @ts-ignore
|
|||
await unref(formElRef)?.restoreValidation(); |
|||
} |
|||
|
|||
//重置
|
|||
async function resetFields(): Promise<void> { |
|||
const { resetFunc, submitOnReset } = unref(getProps); |
|||
resetFunc && isFunction(resetFunc) && (await resetFunc()); |
|||
|
|||
const formEl = unref(formElRef); |
|||
if (!formEl) return; |
|||
Object.keys(formModel).forEach((key) => { |
|||
formModel[key] = unref(defaultFormModel)[key] || null; |
|||
}); |
|||
await clearValidate(); |
|||
const fromValues = handleFormValues(toRaw(unref(formModel))); |
|||
emit('reset', fromValues); |
|||
submitOnReset && (await handleSubmit()); |
|||
} |
|||
|
|||
//获取表单值
|
|||
function getFieldsValue(): Recordable { |
|||
const formEl = unref(formElRef); |
|||
if (!formEl) return {}; |
|||
return handleFormValues(toRaw(unref(formModel))); |
|||
} |
|||
|
|||
//设置表单字段值
|
|||
async function setFieldsValue(values: Recordable): Promise<void> { |
|||
const fields = unref(getSchema) |
|||
.map((item) => item.field) |
|||
.filter(Boolean); |
|||
|
|||
Object.keys(values).forEach((key) => { |
|||
const value = values[key]; |
|||
if (fields.includes(key)) { |
|||
formModel[key] = value; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
return { |
|||
handleSubmit, |
|||
validate, |
|||
resetFields, |
|||
getFieldsValue, |
|||
clearValidate, |
|||
setFieldsValue, |
|||
}; |
|||
} |
@ -0,0 +1,54 @@ |
|||
import { isArray, isFunction, isObject, isString, isNullOrUnDef } from '@/utils/is'; |
|||
import { unref } from 'vue'; |
|||
import type { Ref, ComputedRef } from 'vue'; |
|||
import type { FormSchema } from '../types/form'; |
|||
import { set } from 'lodash-es'; |
|||
|
|||
interface UseFormValuesContext { |
|||
defaultFormModel: Ref<any>; |
|||
getSchema: ComputedRef<FormSchema[]>; |
|||
formModel: Recordable; |
|||
} |
|||
export function useFormValues({ defaultFormModel, getSchema, formModel }: UseFormValuesContext) { |
|||
// 加工 form values
|
|||
function handleFormValues(values: Recordable) { |
|||
if (!isObject(values)) { |
|||
return {}; |
|||
} |
|||
const res: Recordable = {}; |
|||
for (const item of Object.entries(values)) { |
|||
let [, value] = item; |
|||
const [key] = item; |
|||
if ( |
|||
!key || |
|||
(isArray(value) && value.length === 0) || |
|||
isFunction(value) || |
|||
isNullOrUnDef(value) |
|||
) { |
|||
continue; |
|||
} |
|||
// 删除空格
|
|||
if (isString(value)) { |
|||
value = value.trim(); |
|||
} |
|||
set(res, key, value); |
|||
} |
|||
return res; |
|||
} |
|||
|
|||
//初始化默认值
|
|||
function initDefault() { |
|||
const schemas = unref(getSchema); |
|||
const obj: Recordable = {}; |
|||
schemas.forEach((item) => { |
|||
const { defaultValue } = item; |
|||
if (!isNullOrUnDef(defaultValue)) { |
|||
obj[item.field] = defaultValue; |
|||
formModel[item.field] = defaultValue; |
|||
} |
|||
}); |
|||
defaultFormModel.value = obj; |
|||
} |
|||
|
|||
return { handleFormValues, initDefault }; |
|||
} |
@ -0,0 +1,82 @@ |
|||
import type { CSSProperties, PropType } from 'vue'; |
|||
import { FormSchema } from './types/form'; |
|||
import type { GridProps, GridItemProps } from 'naive-ui/lib/grid'; |
|||
import type { ButtonProps } from 'naive-ui/lib/button'; |
|||
import { propTypes } from '@/utils/propTypes'; |
|||
export const basicProps = { |
|||
// 标签宽度 固定宽度
|
|||
labelWidth: { |
|||
type: [Number, String] as PropType<number | string>, |
|||
default: 80, |
|||
}, |
|||
// 表单配置规则
|
|||
schemas: { |
|||
type: [Array] as PropType<FormSchema[]>, |
|||
default: () => [], |
|||
}, |
|||
//布局方式
|
|||
layout: { |
|||
type: String, |
|||
default: 'inline', |
|||
}, |
|||
//是否展示为行内表单
|
|||
inline: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
//大小
|
|||
size: { |
|||
type: String, |
|||
default: 'medium', |
|||
}, |
|||
//标签位置
|
|||
labelPlacement: { |
|||
type: String, |
|||
default: 'left', |
|||
}, |
|||
//组件是否width 100%
|
|||
isFull: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
//是否显示操作按钮(查询/重置)
|
|||
showActionButtonGroup: propTypes.bool.def(true), |
|||
// 显示重置按钮
|
|||
showResetButton: propTypes.bool.def(true), |
|||
//重置按钮配置
|
|||
resetButtonOptions: Object as PropType<Partial<ButtonProps>>, |
|||
// 显示确认按钮
|
|||
showSubmitButton: propTypes.bool.def(true), |
|||
// 确认按钮配置
|
|||
submitButtonOptions: Object as PropType<Partial<ButtonProps>>, |
|||
//展开收起按钮
|
|||
showAdvancedButton: propTypes.bool.def(true), |
|||
// 确认按钮文字
|
|||
submitButtonText: { |
|||
type: String, |
|||
default: '查询', |
|||
}, |
|||
//重置按钮文字
|
|||
resetButtonText: { |
|||
type: String, |
|||
default: '重置', |
|||
}, |
|||
//grid 配置
|
|||
gridProps: Object as PropType<GridProps>, |
|||
//gi配置
|
|||
giProps: Object as PropType<GridItemProps>, |
|||
//grid 样式
|
|||
baseGridStyle: { |
|||
type: Object as PropType<CSSProperties>, |
|||
}, |
|||
//是否折叠
|
|||
collapsed: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
//默认展示的行数
|
|||
collapsedRows: { |
|||
type: Number, |
|||
default: 1, |
|||
}, |
|||
}; |
@ -0,0 +1,59 @@ |
|||
import { ComponentType } from './index'; |
|||
import type { CSSProperties } from 'vue'; |
|||
import type { GridProps, GridItemProps } from 'naive-ui/lib/grid'; |
|||
import type { ButtonProps } from 'naive-ui/lib/button'; |
|||
|
|||
export interface FormSchema { |
|||
field: string; |
|||
label: string; |
|||
labelMessage?: string; |
|||
labelMessageStyle?: object | string; |
|||
defaultValue?: any; |
|||
component?: ComponentType; |
|||
componentProps?: object; |
|||
slot?: string; |
|||
rules?: object | object[]; |
|||
giProps?: GridItemProps; |
|||
isFull?: boolean; |
|||
suffix?: string; |
|||
} |
|||
|
|||
export interface FormProps { |
|||
model?: Recordable; |
|||
labelWidth?: number | string; |
|||
schemas?: FormSchema[]; |
|||
inline: boolean; |
|||
layout?: string; |
|||
size: string; |
|||
labelPlacement: string; |
|||
isFull: boolean; |
|||
showActionButtonGroup?: boolean; |
|||
showResetButton?: boolean; |
|||
resetButtonOptions?: Partial<ButtonProps>; |
|||
showSubmitButton?: boolean; |
|||
showAdvancedButton?: boolean; |
|||
submitButtonOptions?: Partial<ButtonProps>; |
|||
submitButtonText?: string; |
|||
resetButtonText?: string; |
|||
gridProps?: GridProps; |
|||
giProps?: GridItemProps; |
|||
resetFunc?: () => Promise<void>; |
|||
submitFunc?: () => Promise<void>; |
|||
submitOnReset?: boolean; |
|||
baseGridStyle?: CSSProperties; |
|||
collapsedRows?: number; |
|||
} |
|||
|
|||
export interface FormActionType { |
|||
submit: () => Promise<any>; |
|||
setProps: (formProps: Partial<FormProps>) => Promise<void>; |
|||
setFieldsValue: (values: Recordable) => Promise<void>; |
|||
clearValidate: (name?: string | string[]) => Promise<void>; |
|||
getFieldsValue: () => Recordable; |
|||
resetFields: () => Promise<void>; |
|||
validate: (nameList?: any[]) => Promise<any>; |
|||
} |
|||
|
|||
export type RegisterFn = (formInstance: FormActionType) => void; |
|||
|
|||
export type UseFormReturnType = [RegisterFn, FormActionType]; |
@ -0,0 +1,28 @@ |
|||
export type ComponentType = |
|||
| 'NInput' |
|||
| 'NInputGroup' |
|||
| 'NInputPassword' |
|||
| 'NInputSearch' |
|||
| 'NInputTextArea' |
|||
| 'NInputNumber' |
|||
| 'NInputCountDown' |
|||
| 'NSelect' |
|||
| 'NTreeSelect' |
|||
| 'NRadioButtonGroup' |
|||
| 'NRadioGroup' |
|||
| 'NCheckbox' |
|||
| 'NCheckboxGroup' |
|||
| 'NAutoComplete' |
|||
| 'NCascader' |
|||
| 'NDatePicker' |
|||
| 'NMonthPicker' |
|||
| 'NRangePicker' |
|||
| 'NWeekPicker' |
|||
| 'NTimePicker' |
|||
| 'NSwitch' |
|||
| 'NStrengthMeter' |
|||
| 'NUpload' |
|||
| 'NIconPicker' |
|||
| 'NRender' |
|||
| 'NSlider' |
|||
| 'NRate'; |
@ -0,0 +1,304 @@ |
|||
<template> |
|||
<div |
|||
:class="{ onLockLogin: showLogin }" |
|||
class="lockscreen" |
|||
@keyup="onLockLogin(true)" |
|||
@mousedown.stop |
|||
@contextmenu.prevent |
|||
> |
|||
<template v-if="!showLogin"> |
|||
<div class="lock-box"> |
|||
<div class="lock"> |
|||
<span class="lock-icon" title="解锁屏幕" @click="onLockLogin(true)"> |
|||
<n-icon> |
|||
<lock-outlined /> |
|||
</n-icon> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<!--充电--> |
|||
<recharge |
|||
:battery="battery" |
|||
:battery-status="batteryStatus" |
|||
:calc-discharging-time="calcDischargingTime" |
|||
:calc-charging-time="calcChargingTime" |
|||
/> |
|||
|
|||
<div class="local-time"> |
|||
<div class="time">{{ hour }}:{{ minute }}</div> |
|||
<div class="date">{{ month }}月{{ day }}号,星期{{ week }}</div> |
|||
</div> |
|||
<div class="computer-status"> |
|||
<span :class="{ offline: !online }" class="network"> |
|||
<wifi-outlined class="network" /> |
|||
</span> |
|||
<api-outlined /> |
|||
</div> |
|||
</template> |
|||
|
|||
<!--登录--> |
|||
<template v-if="showLogin"> |
|||
<div class="login-box"> |
|||
<n-avatar :size="128"> |
|||
<n-icon> |
|||
<user-outlined /> |
|||
</n-icon> |
|||
</n-avatar> |
|||
<div class="username">{{ loginParams.username }}</div> |
|||
<n-input |
|||
type="password" |
|||
autofocus |
|||
v-model:value="loginParams.password" |
|||
@keyup.enter="onLogin" |
|||
placeholder="请输入登录密码" |
|||
> |
|||
<template #suffix> |
|||
<n-icon @click="onLogin" style="cursor: pointer"> |
|||
<LoadingOutlined v-if="loginLoading" /> |
|||
<arrow-right-outlined v-else /> |
|||
</n-icon> |
|||
</template> |
|||
</n-input> |
|||
|
|||
<div class="flex w-full" v-if="isLoginError"> |
|||
<span class="text-red-500">{{ errorMsg }}</span> |
|||
</div> |
|||
|
|||
<div class="flex justify-around w-full mt-1"> |
|||
<div><a @click="showLogin = false">返回</a></div> |
|||
<div><a @click="goLogin">重新登录</a></div> |
|||
<div><a @click="onLogin">进入系统</a></div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, reactive, toRefs } from 'vue'; |
|||
import { ResultEnum } from '@/enums/httpEnum'; |
|||
import recharge from './Recharge.vue'; |
|||
import { |
|||
LockOutlined, |
|||
LoadingOutlined, |
|||
UserOutlined, |
|||
ApiOutlined, |
|||
ArrowRightOutlined, |
|||
WifiOutlined, |
|||
} from '@vicons/antd'; |
|||
|
|||
import { useRouter, useRoute } from 'vue-router'; |
|||
import { useOnline } from '@/hooks/useOnline'; |
|||
import { useTime } from '@/hooks/useTime'; |
|||
import { useBattery } from '@/hooks/useBattery'; |
|||
import { useScreenLockStore } from '@/store/modules/screenLock'; |
|||
import { UserInfoType, useUserStore } from '@/store/modules/user'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'ScreenLock', |
|||
components: { |
|||
LockOutlined, |
|||
LoadingOutlined, |
|||
UserOutlined, |
|||
ArrowRightOutlined, |
|||
ApiOutlined, |
|||
WifiOutlined, |
|||
recharge, |
|||
}, |
|||
setup() { |
|||
const useScreenLock = useScreenLockStore(); |
|||
const userStore = useUserStore(); |
|||
|
|||
// 获取时间 |
|||
const { month, day, hour, minute, second, week } = useTime(); |
|||
const { online } = useOnline(); |
|||
|
|||
const router = useRouter(); |
|||
const route = useRoute(); |
|||
|
|||
const { battery, batteryStatus, calcDischargingTime, calcChargingTime } = useBattery(); |
|||
const userInfo: UserInfoType = userStore.getUserInfo || {}; |
|||
const username = userInfo['username'] || ''; |
|||
const state = reactive({ |
|||
showLogin: false, |
|||
loginLoading: false, // 正在登录 |
|||
isLoginError: false, //密码错误 |
|||
errorMsg: '密码错误', |
|||
loginParams: { |
|||
username: username || '', |
|||
password: '', |
|||
}, |
|||
}); |
|||
|
|||
// 解锁登录 |
|||
const onLockLogin = (value: boolean) => (state.showLogin = value); |
|||
|
|||
// 登录 |
|||
const onLogin = async () => { |
|||
if (!state.loginParams.password.trim()) { |
|||
return; |
|||
} |
|||
const params = { |
|||
isLock: true, |
|||
...state.loginParams, |
|||
}; |
|||
state.loginLoading = true; |
|||
const { code, message } = await userStore.login(params); |
|||
if (code === ResultEnum.SUCCESS) { |
|||
onLockLogin(false); |
|||
useScreenLock.setLock(false); |
|||
} else { |
|||
state.errorMsg = message; |
|||
state.isLoginError = true; |
|||
} |
|||
state.loginLoading = false; |
|||
}; |
|||
|
|||
//重新登录 |
|||
const goLogin = () => { |
|||
onLockLogin(false); |
|||
useScreenLock.setLock(false); |
|||
router.replace({ |
|||
path: '/login', |
|||
query: { |
|||
redirect: route.fullPath, |
|||
}, |
|||
}); |
|||
}; |
|||
|
|||
return { |
|||
...toRefs(state), |
|||
online, |
|||
month, |
|||
day, |
|||
hour, |
|||
minute, |
|||
second, |
|||
week, |
|||
battery, |
|||
batteryStatus, |
|||
calcDischargingTime, |
|||
calcChargingTime, |
|||
onLockLogin, |
|||
onLogin, |
|||
goLogin, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.lockscreen { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
bottom: 0; |
|||
right: 0; |
|||
display: flex; |
|||
background: #000; |
|||
color: white; |
|||
overflow: hidden; |
|||
z-index: 9999; |
|||
|
|||
&.onLockLogin { |
|||
background-color: rgba(25, 28, 34, 0.88); |
|||
backdrop-filter: blur(7px); |
|||
} |
|||
|
|||
.login-box { |
|||
position: absolute; |
|||
top: 45%; |
|||
left: 50%; |
|||
transform: translate(-50%, -50%); |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
> * { |
|||
margin-bottom: 14px; |
|||
} |
|||
|
|||
.username { |
|||
font-size: 30px; |
|||
} |
|||
} |
|||
|
|||
.lock-box { |
|||
position: absolute; |
|||
top: 20px; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
font-size: 34px; |
|||
z-index: 100; |
|||
|
|||
.tips { |
|||
color: white; |
|||
cursor: text; |
|||
} |
|||
|
|||
.lock { |
|||
display: flex; |
|||
justify-content: center; |
|||
|
|||
.lock-icon { |
|||
cursor: pointer; |
|||
|
|||
.anticon-unlock { |
|||
display: none; |
|||
} |
|||
|
|||
&:hover .anticon-unlock { |
|||
display: initial; |
|||
} |
|||
|
|||
&:hover .anticon-lock { |
|||
display: none; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.local-time { |
|||
position: absolute; |
|||
bottom: 60px; |
|||
left: 60px; |
|||
font-family: helvetica; |
|||
|
|||
.time { |
|||
font-size: 70px; |
|||
} |
|||
|
|||
.date { |
|||
font-size: 40px; |
|||
} |
|||
} |
|||
|
|||
.computer-status { |
|||
position: absolute; |
|||
bottom: 60px; |
|||
right: 60px; |
|||
font-size: 24px; |
|||
|
|||
> * { |
|||
margin-left: 14px; |
|||
} |
|||
|
|||
.network { |
|||
position: relative; |
|||
|
|||
&.offline::before { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 50%; |
|||
top: 50%; |
|||
width: 2px; |
|||
height: 28px; |
|||
transform: translate(-50%, -50%) rotate(45deg); |
|||
background-color: red; |
|||
z-index: 10; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,164 @@ |
|||
<template> |
|||
<div class="container"> |
|||
<div class="number">{{ battery.level }}%</div> |
|||
<div class="contrast"> |
|||
<div class="circle"></div> |
|||
<ul class="bubbles"> |
|||
<li v-for="i in 15" :key="i"></li> |
|||
</ul> |
|||
</div> |
|||
<div class="charging"> |
|||
<div>{{ batteryStatus }}</div> |
|||
<div v-show="Number.isFinite(battery.dischargingTime) && battery.dischargingTime != 0"> |
|||
剩余可使用时间:{{ calcDischargingTime }} |
|||
</div> |
|||
<span v-show="Number.isFinite(battery.chargingTime) && battery.chargingTime != 0"> |
|||
距离电池充满需要:{{ calcChargingTime }} |
|||
</span> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent } from 'vue'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'HuaweiCharge', |
|||
// props: ['batteryStatus', 'battery', 'calcDischargingTime'], |
|||
props: { |
|||
battery: { |
|||
// 电池对象 |
|||
type: Object, |
|||
default: () => ({}), |
|||
}, |
|||
calcDischargingTime: { |
|||
// 电池剩余时间可用时间 |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
calcChargingTime: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
batteryStatus: { |
|||
// 电池状态 |
|||
type: String, |
|||
validator: (val: string) => ['充电中', '已充满', '已断开电源'].includes(val), |
|||
}, |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.container { |
|||
position: absolute; |
|||
bottom: 20vh; |
|||
left: 50vw; |
|||
width: 300px; |
|||
height: 500px; |
|||
transform: translateX(-50%); |
|||
|
|||
.number { |
|||
position: absolute; |
|||
top: 20%; |
|||
z-index: 10; |
|||
width: 300px; |
|||
font-size: 32px; |
|||
color: #fff; |
|||
text-align: center; |
|||
} |
|||
|
|||
.contrast { |
|||
width: 300px; |
|||
height: 400px; |
|||
overflow: hidden; |
|||
background-color: #000; |
|||
filter: contrast(15) hue-rotate(0); |
|||
animation: hueRotate 10s infinite linear; |
|||
|
|||
.circle { |
|||
position: relative; |
|||
width: 300px; |
|||
height: 300px; |
|||
filter: blur(8px); |
|||
box-sizing: border-box; |
|||
|
|||
&::after { |
|||
position: absolute; |
|||
top: 40%; |
|||
left: 50%; |
|||
width: 200px; |
|||
height: 200px; |
|||
background-color: #00ff6f; |
|||
border-radius: 42% 38% 62% 49% / 45%; |
|||
content: ''; |
|||
transform: translate(-50%, -50%) rotate(0); |
|||
animation: rotate 10s infinite linear; |
|||
} |
|||
|
|||
&::before { |
|||
position: absolute; |
|||
top: 40%; |
|||
left: 50%; |
|||
z-index: 10; |
|||
width: 176px; |
|||
height: 176px; |
|||
background-color: #000; |
|||
border-radius: 50%; |
|||
content: ''; |
|||
transform: translate(-50%, -50%); |
|||
} |
|||
} |
|||
|
|||
.bubbles { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 50%; |
|||
width: 100px; |
|||
height: 40px; |
|||
background-color: #00ff6f; |
|||
border-radius: 100px 100px 0 0; |
|||
filter: blur(5px); |
|||
transform: translate(-50%, 0); |
|||
|
|||
li { |
|||
position: absolute; |
|||
background: #00ff6f; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.charging { |
|||
font-size: 20px; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
@keyframes rotate { |
|||
50% { |
|||
border-radius: 45% / 42% 38% 58% 49%; |
|||
} |
|||
|
|||
100% { |
|||
transform: translate(-50%, -50%) rotate(720deg); |
|||
} |
|||
} |
|||
|
|||
@keyframes moveToTop { |
|||
90% { |
|||
opacity: 1; |
|||
} |
|||
|
|||
100% { |
|||
opacity: 0.1; |
|||
transform: translate(-50%, -180px); |
|||
} |
|||
} |
|||
|
|||
@keyframes hueRotate { |
|||
100% { |
|||
filter: contrast(15) hue-rotate(360deg); |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,3 @@ |
|||
import LockScreen from './Lockscreen.vue'; |
|||
|
|||
export { LockScreen }; |
@ -0,0 +1,3 @@ |
|||
export { default as basicModal } from './src/basicModal.vue'; |
|||
export { useModal } from './src/hooks/useModal'; |
|||
export * from './src/type'; |
@ -0,0 +1,117 @@ |
|||
<template> |
|||
<n-modal id="basic-modal" v-bind="getBindValue" v-model:show="isModal" @close="onCloseModal"> |
|||
<template #header> |
|||
<div class="w-full cursor-move" id="basic-modal-bar">{{ getBindValue.title }}</div> |
|||
</template> |
|||
<template #default> |
|||
<slot name="default"></slot> |
|||
</template> |
|||
<template #action v-if="!$slots.action"> |
|||
<n-space> |
|||
<n-button @click="closeModal">取消</n-button> |
|||
<n-button type="primary" :loading="subLoading" @click="handleSubmit">{{ |
|||
subBtuText |
|||
}}</n-button> |
|||
</n-space> |
|||
</template> |
|||
<template v-else #action> |
|||
<slot name="action"></slot> |
|||
</template> |
|||
</n-modal> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { |
|||
getCurrentInstance, |
|||
ref, |
|||
nextTick, |
|||
unref, |
|||
computed, |
|||
useAttrs, |
|||
defineEmits, |
|||
defineProps, |
|||
} from 'vue'; |
|||
import { basicProps } from './props'; |
|||
import startDrag from '@/utils/Drag'; |
|||
import { deepMerge } from '@/utils'; |
|||
import { FormProps } from '@/components/Form'; |
|||
import { ModalProps, ModalMethods } from './type'; |
|||
|
|||
const attrs = useAttrs(); |
|||
const props = defineProps({ ...basicProps }); |
|||
const emit = defineEmits(['on-close', 'on-ok', 'register']); |
|||
|
|||
const propsRef = ref<Partial<ModalProps> | null>(null); |
|||
|
|||
const isModal = ref(false); |
|||
const subLoading = ref(false); |
|||
|
|||
const getProps = computed((): FormProps => { |
|||
return { ...props, ...(unref(propsRef) as any) }; |
|||
}); |
|||
|
|||
const subBtuText = computed(() => { |
|||
const { subBtuText } = propsRef.value as any; |
|||
return subBtuText || props.subBtuText; |
|||
}); |
|||
|
|||
async function setProps(modalProps: Partial<ModalProps>): Promise<void> { |
|||
propsRef.value = deepMerge(unref(propsRef) || ({} as any), modalProps); |
|||
} |
|||
|
|||
const getBindValue = computed(() => { |
|||
return { |
|||
...attrs, |
|||
...unref(getProps), |
|||
...unref(propsRef), |
|||
}; |
|||
}); |
|||
|
|||
function setSubLoading(status: boolean) { |
|||
subLoading.value = status; |
|||
} |
|||
|
|||
function openModal() { |
|||
isModal.value = true; |
|||
nextTick(() => { |
|||
const oBox = document.getElementById('basic-modal'); |
|||
const oBar = document.getElementById('basic-modal-bar'); |
|||
startDrag(oBar, oBox); |
|||
}); |
|||
} |
|||
|
|||
function closeModal() { |
|||
isModal.value = false; |
|||
subLoading.value = false; |
|||
emit('on-close'); |
|||
} |
|||
|
|||
function onCloseModal() { |
|||
isModal.value = false; |
|||
emit('on-close'); |
|||
} |
|||
|
|||
function handleSubmit() { |
|||
subLoading.value = true; |
|||
console.log(subLoading.value); |
|||
emit('on-ok'); |
|||
} |
|||
|
|||
const modalMethods: ModalMethods = { |
|||
setProps, |
|||
openModal, |
|||
closeModal, |
|||
setSubLoading, |
|||
}; |
|||
|
|||
const instance = getCurrentInstance(); |
|||
if (instance) { |
|||
emit('register', modalMethods); |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less"> |
|||
.cursor-move { |
|||
cursor: move; |
|||
} |
|||
</style> |
@ -0,0 +1,54 @@ |
|||
import { ref, unref, getCurrentInstance, watch } from 'vue'; |
|||
import { isProdMode } from '@/utils/env'; |
|||
import { ModalMethods, UseModalReturnType } from '../type'; |
|||
import { getDynamicProps } from '@/utils'; |
|||
import { tryOnUnmounted } from '@vueuse/core'; |
|||
export function useModal(props): UseModalReturnType { |
|||
const modalRef = ref<Nullable<ModalMethods>>(null); |
|||
const currentInstance = getCurrentInstance(); |
|||
|
|||
const getInstance = () => { |
|||
const instance = unref(modalRef.value); |
|||
if (!instance) { |
|||
console.error('useModal instance is undefined!'); |
|||
} |
|||
return instance; |
|||
}; |
|||
|
|||
const register = (modalInstance: ModalMethods) => { |
|||
isProdMode() && |
|||
tryOnUnmounted(() => { |
|||
modalRef.value = null; |
|||
}); |
|||
modalRef.value = modalInstance; |
|||
currentInstance?.emit('register', modalInstance); |
|||
|
|||
watch( |
|||
() => props, |
|||
() => { |
|||
props && modalInstance.setProps(getDynamicProps(props)); |
|||
}, |
|||
{ |
|||
immediate: true, |
|||
deep: true, |
|||
} |
|||
); |
|||
}; |
|||
|
|||
const methods: ModalMethods = { |
|||
setProps: (props): void => { |
|||
getInstance()?.setProps(props); |
|||
}, |
|||
openModal: () => { |
|||
getInstance()?.openModal(); |
|||
}, |
|||
closeModal: () => { |
|||
getInstance()?.closeModal(); |
|||
}, |
|||
setSubLoading: (status) => { |
|||
getInstance()?.setSubLoading(status); |
|||
}, |
|||
}; |
|||
|
|||
return [register, methods]; |
|||
} |
@ -0,0 +1,30 @@ |
|||
import { NModal } from 'naive-ui'; |
|||
|
|||
export const basicProps = { |
|||
...NModal.props, |
|||
// 确认按钮文字
|
|||
subBtuText: { |
|||
type: String, |
|||
default: '确认', |
|||
}, |
|||
showIcon: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
width: { |
|||
type: Number, |
|||
default: 446, |
|||
}, |
|||
title: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
maskClosable: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
preset: { |
|||
type: String, |
|||
default: 'dialog', |
|||
}, |
|||
}; |
@ -0,0 +1,19 @@ |
|||
import type { DialogOptions } from 'naive-ui/lib/dialog'; |
|||
/** |
|||
* @description: 弹窗对外暴露的方法 |
|||
*/ |
|||
export interface ModalMethods { |
|||
setProps: (props) => void; |
|||
openModal: () => void; |
|||
closeModal: () => void; |
|||
setSubLoading: (status) => void; |
|||
} |
|||
|
|||
/** |
|||
* 支持修改,DialogOptions 參數 |
|||
*/ |
|||
export type ModalProps = DialogOptions; |
|||
|
|||
export type RegisterFn = (ModalInstance: ModalMethods) => void; |
|||
|
|||
export type UseModalReturnType = [RegisterFn, ModalMethods]; |
@ -0,0 +1,4 @@ |
|||
export { default as BasicTable } from './src/Table.vue'; |
|||
export { default as TableAction } from './src/components/TableAction.vue'; |
|||
export * from './src/types/table'; |
|||
export * from './src/types/tableAction'; |
@ -0,0 +1,353 @@ |
|||
<template> |
|||
<div class="table-toolbar"> |
|||
<!--顶部左侧区域--> |
|||
<div class="flex items-center table-toolbar-left"> |
|||
<template v-if="title"> |
|||
<div class="table-toolbar-left-title"> |
|||
{{ title }} |
|||
<n-tooltip trigger="hover" v-if="titleTooltip"> |
|||
<template #trigger> |
|||
<n-icon size="18" class="ml-1 text-gray-400 cursor-pointer"> |
|||
<QuestionCircleOutlined /> |
|||
</n-icon> |
|||
</template> |
|||
{{ titleTooltip }} |
|||
</n-tooltip> |
|||
</div> |
|||
</template> |
|||
<slot name="tableTitle"></slot> |
|||
</div> |
|||
|
|||
<div class="flex items-center table-toolbar-right"> |
|||
<!--顶部右侧区域--> |
|||
<slot name="toolbar"></slot> |
|||
|
|||
<!--斑马纹--> |
|||
<n-tooltip trigger="hover"> |
|||
<template #trigger> |
|||
<div class="mr-2 table-toolbar-right-icon"> |
|||
<n-switch v-model:value="isStriped" @update:value="setStriped" /> |
|||
</div> |
|||
</template> |
|||
<span>表格斑马纹</span> |
|||
</n-tooltip> |
|||
<n-divider vertical /> |
|||
|
|||
<!--刷新--> |
|||
<n-tooltip trigger="hover"> |
|||
<template #trigger> |
|||
<div class="table-toolbar-right-icon" @click="reload"> |
|||
<n-icon size="18"> |
|||
<ReloadOutlined /> |
|||
</n-icon> |
|||
</div> |
|||
</template> |
|||
<span>刷新</span> |
|||
</n-tooltip> |
|||
|
|||
<!--密度--> |
|||
<n-tooltip trigger="hover"> |
|||
<template #trigger> |
|||
<div class="table-toolbar-right-icon"> |
|||
<n-dropdown |
|||
@select="densitySelect" |
|||
trigger="click" |
|||
:options="densityOptions" |
|||
v-model:value="tableSize" |
|||
> |
|||
<n-icon size="18"> |
|||
<ColumnHeightOutlined /> |
|||
</n-icon> |
|||
</n-dropdown> |
|||
</div> |
|||
</template> |
|||
<span>密度</span> |
|||
</n-tooltip> |
|||
|
|||
<!--表格设置单独抽离成组件--> |
|||
<ColumnSetting /> |
|||
</div> |
|||
</div> |
|||
<div class="s-table"> |
|||
<n-data-table |
|||
ref="tableElRef" |
|||
v-bind="getBindValues" |
|||
:striped="isStriped" |
|||
:pagination="pagination" |
|||
@update:page="updatePage" |
|||
@update:page-size="updatePageSize" |
|||
> |
|||
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item"> |
|||
<slot :name="item" v-bind="data"></slot> |
|||
</template> |
|||
</n-data-table> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { |
|||
ref, |
|||
defineComponent, |
|||
reactive, |
|||
unref, |
|||
toRaw, |
|||
computed, |
|||
toRefs, |
|||
onMounted, |
|||
nextTick, |
|||
} from 'vue'; |
|||
import { ReloadOutlined, ColumnHeightOutlined, QuestionCircleOutlined } from '@vicons/antd'; |
|||
import { createTableContext } from './hooks/useTableContext'; |
|||
|
|||
import ColumnSetting from './components/settings/ColumnSetting.vue'; |
|||
|
|||
import { useLoading } from './hooks/useLoading'; |
|||
import { useColumns } from './hooks/useColumns'; |
|||
import { useDataSource } from './hooks/useDataSource'; |
|||
import { usePagination } from './hooks/usePagination'; |
|||
|
|||
import { basicProps } from './props'; |
|||
|
|||
import { BasicTableProps } from './types/table'; |
|||
|
|||
import { getViewportOffset } from '@/utils/domUtils'; |
|||
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn'; |
|||
import { isBoolean } from '@/utils/is'; |
|||
|
|||
const densityOptions = [ |
|||
{ |
|||
type: 'menu', |
|||
label: '紧凑', |
|||
key: 'small', |
|||
}, |
|||
{ |
|||
type: 'menu', |
|||
label: '默认', |
|||
key: 'medium', |
|||
}, |
|||
{ |
|||
type: 'menu', |
|||
label: '宽松', |
|||
key: 'large', |
|||
}, |
|||
]; |
|||
|
|||
export default defineComponent({ |
|||
components: { |
|||
ReloadOutlined, |
|||
ColumnHeightOutlined, |
|||
ColumnSetting, |
|||
QuestionCircleOutlined, |
|||
}, |
|||
props: { |
|||
...basicProps, |
|||
}, |
|||
emits: [ |
|||
'fetch-success', |
|||
'fetch-error', |
|||
'update:checked-row-keys', |
|||
'edit-end', |
|||
'edit-cancel', |
|||
'edit-row-end', |
|||
'edit-change', |
|||
], |
|||
setup(props, { emit }) { |
|||
const deviceHeight = ref(150); |
|||
const tableElRef = ref<ComponentRef>(null); |
|||
const wrapRef = ref<Nullable<HTMLDivElement>>(null); |
|||
let paginationEl: HTMLElement | null; |
|||
const isStriped = ref(false); |
|||
const tableData = ref<Recordable[]>([]); |
|||
const innerPropsRef = ref<Partial<BasicTableProps>>(); |
|||
|
|||
const getProps = computed(() => { |
|||
return { ...props, ...unref(innerPropsRef) } as BasicTableProps; |
|||
}); |
|||
|
|||
const { getLoading, setLoading } = useLoading(getProps); |
|||
|
|||
const { getPaginationInfo, setPagination } = usePagination(getProps); |
|||
|
|||
const { getDataSourceRef, getDataSource, getRowKey, reload } = useDataSource( |
|||
getProps, |
|||
{ |
|||
getPaginationInfo, |
|||
setPagination, |
|||
tableData, |
|||
setLoading, |
|||
}, |
|||
emit |
|||
); |
|||
|
|||
const { getPageColumns, setColumns, getColumns, getCacheColumns, setCacheColumnsField } = |
|||
useColumns(getProps); |
|||
|
|||
const state = reactive({ |
|||
tableSize: unref(getProps as any).size || 'medium', |
|||
isColumnSetting: false, |
|||
}); |
|||
|
|||
//页码切换 |
|||
function updatePage(page) { |
|||
setPagination({ page: page }); |
|||
reload(); |
|||
} |
|||
|
|||
//分页数量切换 |
|||
function updatePageSize(size) { |
|||
setPagination({ page: 1, pageSize: size }); |
|||
reload(); |
|||
} |
|||
|
|||
//密度切换 |
|||
function densitySelect(e) { |
|||
state.tableSize = e; |
|||
} |
|||
|
|||
//选中行 |
|||
function updateCheckedRowKeys(rowKeys) { |
|||
emit('update:checked-row-keys', rowKeys); |
|||
} |
|||
|
|||
//获取表格大小 |
|||
const getTableSize = computed(() => state.tableSize); |
|||
|
|||
//组装表格信息 |
|||
const getBindValues = computed(() => { |
|||
const tableData = unref(getDataSourceRef); |
|||
const maxHeight = tableData.length ? `${unref(deviceHeight)}px` : 'auto'; |
|||
return { |
|||
...unref(getProps), |
|||
loading: unref(getLoading), |
|||
columns: toRaw(unref(getPageColumns)), |
|||
rowKey: unref(getRowKey), |
|||
data: tableData, |
|||
size: unref(getTableSize), |
|||
remote: true, |
|||
'max-height': maxHeight, |
|||
}; |
|||
}); |
|||
|
|||
//获取分页信息 |
|||
const pagination = computed(() => toRaw(unref(getPaginationInfo))); |
|||
|
|||
function setProps(props: Partial<BasicTableProps>) { |
|||
innerPropsRef.value = { ...unref(innerPropsRef), ...props }; |
|||
} |
|||
|
|||
const setStriped = (value: boolean) => (isStriped.value = value); |
|||
|
|||
const tableAction = { |
|||
reload, |
|||
setColumns, |
|||
setLoading, |
|||
setProps, |
|||
getColumns, |
|||
getPageColumns, |
|||
getCacheColumns, |
|||
setCacheColumnsField, |
|||
emit, |
|||
}; |
|||
|
|||
const getCanResize = computed(() => { |
|||
const { canResize } = unref(getProps); |
|||
return canResize; |
|||
}); |
|||
|
|||
async function computeTableHeight() { |
|||
const table = unref(tableElRef); |
|||
if (!table) return; |
|||
if (!unref(getCanResize)) return; |
|||
const tableEl: any = table?.$el; |
|||
const headEl = tableEl.querySelector('.n-data-table-thead '); |
|||
const { bottomIncludeBody } = getViewportOffset(headEl); |
|||
const headerH = 64; |
|||
let paginationH = 2; |
|||
let marginH = 24; |
|||
if (!isBoolean(unref(pagination))) { |
|||
paginationEl = tableEl.querySelector('.n-data-table__pagination') as HTMLElement; |
|||
if (paginationEl) { |
|||
const offsetHeight = paginationEl.offsetHeight; |
|||
paginationH += offsetHeight || 0; |
|||
} else { |
|||
paginationH += 28; |
|||
} |
|||
} |
|||
let height = |
|||
bottomIncludeBody - (headerH + paginationH + marginH + (props.resizeHeightOffset || 0)); |
|||
const maxHeight = props.maxHeight; |
|||
height = maxHeight && maxHeight < height ? maxHeight : height; |
|||
deviceHeight.value = height; |
|||
} |
|||
|
|||
useWindowSizeFn(computeTableHeight, 280); |
|||
|
|||
onMounted(() => { |
|||
nextTick(() => { |
|||
computeTableHeight(); |
|||
}); |
|||
}); |
|||
|
|||
createTableContext({ ...tableAction, wrapRef, getBindValues }); |
|||
|
|||
return { |
|||
...toRefs(state), |
|||
tableElRef, |
|||
getBindValues, |
|||
getDataSource, |
|||
densityOptions, |
|||
reload, |
|||
densitySelect, |
|||
updatePage, |
|||
updatePageSize, |
|||
pagination, |
|||
tableAction, |
|||
setStriped, |
|||
isStriped, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
<style lang="less" scoped> |
|||
.table-toolbar { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding: 0 0 16px 0; |
|||
|
|||
&-left { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
flex: 1; |
|||
|
|||
&-title { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: flex-start; |
|||
font-size: 16px; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
|
|||
&-right { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
flex: 1; |
|||
|
|||
&-icon { |
|||
margin-left: 12px; |
|||
font-size: 16px; |
|||
cursor: pointer; |
|||
color: var(--text-color); |
|||
|
|||
:hover { |
|||
color: #1890ff; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.table-toolbar-inner-popover-title { |
|||
padding: 2px 0; |
|||
} |
|||
</style> |
@ -0,0 +1,41 @@ |
|||
import type { Component } from 'vue'; |
|||
import { |
|||
NInput, |
|||
NSelect, |
|||
NCheckbox, |
|||
NInputNumber, |
|||
NSwitch, |
|||
NDatePicker, |
|||
NTimePicker, |
|||
} from 'naive-ui'; |
|||
import type { ComponentType } from './types/componentType'; |
|||
|
|||
export enum EventEnum { |
|||
NInput = 'on-input', |
|||
NInputNumber = 'on-input', |
|||
NSelect = 'on-update:value', |
|||
NSwitch = 'on-update:value', |
|||
NCheckbox = 'on-update:value', |
|||
NDatePicker = 'on-update:value', |
|||
NTimePicker = 'on-update:value', |
|||
} |
|||
|
|||
const componentMap = new Map<ComponentType, Component>(); |
|||
|
|||
componentMap.set('NInput', NInput); |
|||
componentMap.set('NInputNumber', NInputNumber); |
|||
componentMap.set('NSelect', NSelect); |
|||
componentMap.set('NSwitch', NSwitch); |
|||
componentMap.set('NCheckbox', NCheckbox); |
|||
componentMap.set('NDatePicker', NDatePicker); |
|||
componentMap.set('NTimePicker', NTimePicker); |
|||
|
|||
export function add(compName: ComponentType, component: Component) { |
|||
componentMap.set(compName, component); |
|||
} |
|||
|
|||
export function del(compName: ComponentType) { |
|||
componentMap.delete(compName); |
|||
} |
|||
|
|||
export { componentMap }; |
@ -0,0 +1,141 @@ |
|||
<template> |
|||
<div class="tableAction"> |
|||
<div class="flex items-center justify-center"> |
|||
<template v-for="(action, index) in getActions" :key="`${index}-${action.label}`"> |
|||
<n-button v-bind="action" class="mx-2"> |
|||
{{ action.label }} |
|||
<template #icon v-if="action.hasOwnProperty('icon')"> |
|||
<n-icon :component="action.icon" /> |
|||
</template> |
|||
</n-button> |
|||
</template> |
|||
<n-dropdown |
|||
v-if="dropDownActions && getDropdownList.length" |
|||
trigger="hover" |
|||
:options="getDropdownList" |
|||
@select="select" |
|||
> |
|||
<slot name="more"></slot> |
|||
<n-button v-bind="getMoreProps" class="mx-2" v-if="!$slots.more" icon-placement="right"> |
|||
<div class="flex items-center"> |
|||
<span>更多</span> |
|||
<n-icon size="14" class="ml-1"> |
|||
<DownOutlined /> |
|||
</n-icon> |
|||
</div> |
|||
<!-- <template #icon>--> |
|||
<!-- --> |
|||
<!-- </template>--> |
|||
</n-button> |
|||
</n-dropdown> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, PropType, computed, toRaw } from 'vue'; |
|||
import { ActionItem } from '@/components/Table'; |
|||
import { usePermission } from '@/hooks/web/usePermission'; |
|||
import { isBoolean, isFunction } from '@/utils/is'; |
|||
import { DownOutlined } from '@vicons/antd'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'TableAction', |
|||
components: { DownOutlined }, |
|||
props: { |
|||
actions: { |
|||
type: Array as PropType<ActionItem[]>, |
|||
default: null, |
|||
required: true, |
|||
}, |
|||
dropDownActions: { |
|||
type: Array as PropType<ActionItem[]>, |
|||
default: null, |
|||
}, |
|||
style: { |
|||
type: String as PropType<String>, |
|||
default: 'button', |
|||
}, |
|||
select: { |
|||
type: Function as PropType<Function>, |
|||
default: () => {}, |
|||
}, |
|||
}, |
|||
setup(props) { |
|||
const { hasPermission } = usePermission(); |
|||
|
|||
const actionType = |
|||
props.style === 'button' ? 'default' : props.style === 'text' ? 'primary' : 'default'; |
|||
const actionText = |
|||
props.style === 'button' ? undefined : props.style === 'text' ? true : undefined; |
|||
|
|||
const getMoreProps = computed(() => { |
|||
return { |
|||
text: actionText, |
|||
type: actionType, |
|||
size: 'small', |
|||
}; |
|||
}); |
|||
|
|||
const getDropdownList = computed(() => { |
|||
return (toRaw(props.dropDownActions) || []) |
|||
.filter((action) => { |
|||
return hasPermission(action.auth as string[]) && isIfShow(action); |
|||
}) |
|||
.map((action) => { |
|||
const { popConfirm } = action; |
|||
return { |
|||
size: 'small', |
|||
text: actionText, |
|||
type: actionType, |
|||
...action, |
|||
...popConfirm, |
|||
onConfirm: popConfirm?.confirm, |
|||
onCancel: popConfirm?.cancel, |
|||
}; |
|||
}); |
|||
}); |
|||
|
|||
function isIfShow(action: ActionItem): boolean { |
|||
const ifShow = action.ifShow; |
|||
|
|||
let isIfShow = true; |
|||
|
|||
if (isBoolean(ifShow)) { |
|||
isIfShow = ifShow; |
|||
} |
|||
if (isFunction(ifShow)) { |
|||
isIfShow = ifShow(action); |
|||
} |
|||
return isIfShow; |
|||
} |
|||
|
|||
const getActions = computed(() => { |
|||
return (toRaw(props.actions) || []) |
|||
.filter((action) => { |
|||
return hasPermission(action.auth as string[]) && isIfShow(action); |
|||
}) |
|||
.map((action) => { |
|||
const { popConfirm } = action; |
|||
//需要展示什么风格,自己修改一下参数 |
|||
return { |
|||
size: 'small', |
|||
text: actionText, |
|||
type: actionType, |
|||
...action, |
|||
...(popConfirm || {}), |
|||
onConfirm: popConfirm?.confirm, |
|||
onCancel: popConfirm?.cancel, |
|||
enable: !!popConfirm, |
|||
}; |
|||
}); |
|||
}); |
|||
|
|||
return { |
|||
getActions, |
|||
getDropdownList, |
|||
getMoreProps, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
@ -0,0 +1,47 @@ |
|||
import type { FunctionalComponent, defineComponent } from 'vue'; |
|||
import type { ComponentType } from '../../types/componentType'; |
|||
import { componentMap } from '@/components/Table/src/componentMap'; |
|||
|
|||
import { h } from 'vue'; |
|||
|
|||
import { NPopover } from 'naive-ui'; |
|||
|
|||
export interface ComponentProps { |
|||
component: ComponentType; |
|||
rule: boolean; |
|||
popoverVisible: boolean; |
|||
ruleMessage: string; |
|||
} |
|||
|
|||
export const CellComponent: FunctionalComponent = ( |
|||
{ component = 'NInput', rule = true, ruleMessage, popoverVisible }: ComponentProps, |
|||
{ attrs } |
|||
) => { |
|||
const Comp = componentMap.get(component) as typeof defineComponent; |
|||
|
|||
const DefaultComp = h(Comp, attrs); |
|||
if (!rule) { |
|||
return DefaultComp; |
|||
} |
|||
return h( |
|||
NPopover, |
|||
{ 'display-directive': 'show', show: !!popoverVisible, manual: 'manual' }, |
|||
{ |
|||
trigger: () => DefaultComp, |
|||
default: () => |
|||
h( |
|||
'span', |
|||
{ |
|||
style: { |
|||
color: 'red', |
|||
width: '90px', |
|||
display: 'inline-block', |
|||
}, |
|||
}, |
|||
{ |
|||
default: () => ruleMessage, |
|||
} |
|||
), |
|||
} |
|||
); |
|||
}; |
@ -0,0 +1,418 @@ |
|||
<template> |
|||
<div class="editable-cell"> |
|||
<div v-show="!isEdit" class="editable-cell-content" @click="handleEdit"> |
|||
{{ getValues }} |
|||
<n-icon class="edit-icon" v-if="!column.editRow"> |
|||
<FormOutlined /> |
|||
</n-icon> |
|||
</div> |
|||
<div class="flex editable-cell-content" v-show="isEdit" v-click-outside="onClickOutside"> |
|||
<div class="editable-cell-content-comp"> |
|||
<CellComponent |
|||
v-bind="getComponentProps" |
|||
:component="getComponent" |
|||
:popoverVisible="getRuleVisible" |
|||
:ruleMessage="ruleMessage" |
|||
:rule="getRule" |
|||
:class="getWrapperClass" |
|||
ref="elRef" |
|||
@options-change="handleOptionsChange" |
|||
@pressEnter="handleEnter" |
|||
/> |
|||
</div> |
|||
<div class="editable-cell-action" v-if="!getRowEditable"> |
|||
<n-icon class="mx-2 cursor-pointer"> |
|||
<CheckOutlined @click="handleSubmit" /> |
|||
</n-icon> |
|||
<n-icon class="mx-2 cursor-pointer"> |
|||
<CloseOutlined @click="handleCancel" /> |
|||
</n-icon> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script lang="ts"> |
|||
import type { PropType } from 'vue'; |
|||
import type { BasicColumn } from '../../types/table'; |
|||
import type { EditRecordRow } from './index'; |
|||
|
|||
import { defineComponent, ref, unref, nextTick, computed, watchEffect, toRaw } from 'vue'; |
|||
import { FormOutlined, CloseOutlined, CheckOutlined } from '@vicons/antd'; |
|||
import { CellComponent } from './CellComponent'; |
|||
|
|||
import { useTableContext } from '../../hooks/useTableContext'; |
|||
|
|||
import clickOutside from '@/directives/clickOutside'; |
|||
|
|||
import { propTypes } from '@/utils/propTypes'; |
|||
import { isString, isBoolean, isFunction, isNumber, isArray } from '@/utils/is'; |
|||
import { createPlaceholderMessage } from './helper'; |
|||
import { set, omit } from 'lodash-es'; |
|||
import { EventEnum } from '@/components/Table/src/componentMap'; |
|||
|
|||
import { parseISO, format } from 'date-fns'; |
|||
|
|||
export default defineComponent({ |
|||
name: 'EditableCell', |
|||
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent }, |
|||
directives: { |
|||
clickOutside, |
|||
}, |
|||
props: { |
|||
value: { |
|||
type: [String, Number, Boolean, Object] as PropType<string | number | boolean | Recordable>, |
|||
default: '', |
|||
}, |
|||
record: { |
|||
type: Object as PropType<EditRecordRow>, |
|||
}, |
|||
column: { |
|||
type: Object as PropType<BasicColumn>, |
|||
default: () => ({}), |
|||
}, |
|||
index: propTypes.number, |
|||
}, |
|||
setup(props) { |
|||
const table = useTableContext(); |
|||
const isEdit = ref(false); |
|||
const elRef = ref(); |
|||
const ruleVisible = ref(false); |
|||
const ruleMessage = ref(''); |
|||
const optionsRef = ref<LabelValueOptions>([]); |
|||
const currentValueRef = ref<any>(props.value); |
|||
const defaultValueRef = ref<any>(props.value); |
|||
|
|||
// const { prefixCls } = useDesign('editable-cell'); |
|||
|
|||
const getComponent = computed(() => props.column?.editComponent || 'NInput'); |
|||
const getRule = computed(() => props.column?.editRule); |
|||
|
|||
const getRuleVisible = computed(() => { |
|||
return unref(ruleMessage) && unref(ruleVisible); |
|||
}); |
|||
|
|||
const getIsCheckComp = computed(() => { |
|||
const component = unref(getComponent); |
|||
return ['NCheckbox', 'NRadio'].includes(component); |
|||
}); |
|||
|
|||
const getComponentProps = computed(() => { |
|||
const compProps = props.column?.editComponentProps ?? {}; |
|||
const editComponent = props.column?.editComponent ?? null; |
|||
const component = unref(getComponent); |
|||
const apiSelectProps: Recordable = {}; |
|||
|
|||
const isCheckValue = unref(getIsCheckComp); |
|||
|
|||
let valueField = isCheckValue ? 'checked' : 'value'; |
|||
const val = unref(currentValueRef); |
|||
|
|||
let value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val; |
|||
|
|||
//TODO 特殊处理 NDatePicker 可能要根据项目 规范自行调整代码 |
|||
if (component === 'NDatePicker') { |
|||
if (isString(value)) { |
|||
if (compProps.valueFormat) { |
|||
valueField = 'formatted-value'; |
|||
} else { |
|||
value = parseISO(value as any).getTime(); |
|||
} |
|||
} else if (isArray(value)) { |
|||
if (compProps.valueFormat) { |
|||
valueField = 'formatted-value'; |
|||
} else { |
|||
value = value.map((item) => parseISO(item).getTime()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
const onEvent: any = editComponent ? EventEnum[editComponent] : undefined; |
|||
|
|||
return { |
|||
placeholder: createPlaceholderMessage(unref(getComponent)), |
|||
...apiSelectProps, |
|||
...omit(compProps, 'onChange'), |
|||
[onEvent]: handleChange, |
|||
[valueField]: value, |
|||
}; |
|||
}); |
|||
|
|||
const getValues = computed(() => { |
|||
const { editComponentProps, editValueMap } = props.column; |
|||
|
|||
const value = unref(currentValueRef); |
|||
|
|||
if (editValueMap && isFunction(editValueMap)) { |
|||
return editValueMap(value); |
|||
} |
|||
|
|||
const component = unref(getComponent); |
|||
if (!component.includes('NSelect')) { |
|||
return value; |
|||
} |
|||
|
|||
const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []); |
|||
const option = options.find((item) => `${item.value}` === `${value}`); |
|||
|
|||
return option?.label ?? value; |
|||
}); |
|||
|
|||
const getWrapperClass = computed(() => { |
|||
const { align = 'center' } = props.column; |
|||
return `edit-cell-align-${align}`; |
|||
}); |
|||
|
|||
const getRowEditable = computed(() => { |
|||
const { editable } = props.record || {}; |
|||
return !!editable; |
|||
}); |
|||
|
|||
watchEffect(() => { |
|||
defaultValueRef.value = props.value; |
|||
}); |
|||
|
|||
watchEffect(() => { |
|||
const { editable } = props.column; |
|||
if (isBoolean(editable) || isBoolean(unref(getRowEditable))) { |
|||
isEdit.value = !!editable || unref(getRowEditable); |
|||
} |
|||
}); |
|||
|
|||
function handleEdit() { |
|||
if (unref(getRowEditable) || unref(props.column?.editRow)) return; |
|||
ruleMessage.value = ''; |
|||
isEdit.value = true; |
|||
nextTick(() => { |
|||
const el = unref(elRef); |
|||
el?.focus?.(); |
|||
}); |
|||
} |
|||
|
|||
async function handleChange(e: any) { |
|||
const component = unref(getComponent); |
|||
const compProps = props.column?.editComponentProps ?? {}; |
|||
if (!e) { |
|||
currentValueRef.value = e; |
|||
} else if (e?.target && Reflect.has(e.target, 'value')) { |
|||
currentValueRef.value = (e as ChangeEvent).target.value; |
|||
} else if (component === 'NCheckbox') { |
|||
currentValueRef.value = (e as ChangeEvent).target.checked; |
|||
} else if (isString(e) || isBoolean(e) || isNumber(e)) { |
|||
currentValueRef.value = e; |
|||
} |
|||
|
|||
//TODO 特殊处理 NDatePicker 可能要根据项目 规范自行调整代码 |
|||
if (component === 'NDatePicker') { |
|||
if (isNumber(currentValueRef.value)) { |
|||
if (compProps.valueFormat) { |
|||
currentValueRef.value = format(currentValueRef.value, compProps.valueFormat); |
|||
} |
|||
} else if (isArray(currentValueRef.value)) { |
|||
if (compProps.valueFormat) { |
|||
currentValueRef.value = currentValueRef.value.map((item) => { |
|||
format(item, compProps.valueFormat); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
const onChange = props.column?.editComponentProps?.onChange; |
|||
if (onChange && isFunction(onChange)) onChange(...arguments); |
|||
|
|||
table.emit?.('edit-change', { |
|||
column: props.column, |
|||
value: unref(currentValueRef), |
|||
record: toRaw(props.record), |
|||
}); |
|||
await handleSubmiRule(); |
|||
} |
|||
|
|||
async function handleSubmiRule() { |
|||
const { column, record } = props; |
|||
const { editRule } = column; |
|||
const currentValue = unref(currentValueRef); |
|||
|
|||
if (editRule) { |
|||
if (isBoolean(editRule) && !currentValue && !isNumber(currentValue)) { |
|||
ruleVisible.value = true; |
|||
const component = unref(getComponent); |
|||
ruleMessage.value = createPlaceholderMessage(component); |
|||
return false; |
|||
} |
|||
if (isFunction(editRule)) { |
|||
const res = await editRule(currentValue, record as Recordable); |
|||
if (!!res) { |
|||
ruleMessage.value = res; |
|||
ruleVisible.value = true; |
|||
return false; |
|||
} else { |
|||
ruleMessage.value = ''; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
ruleMessage.value = ''; |
|||
return true; |
|||
} |
|||
|
|||
async function handleSubmit(needEmit = true, valid = true) { |
|||
if (valid) { |
|||
const isPass = await handleSubmiRule(); |
|||
if (!isPass) return false; |
|||
} |
|||
|
|||
const { column, index, record } = props; |
|||
if (!record) return false; |
|||
const { key } = column; |
|||
const value = unref(currentValueRef); |
|||
if (!key) return; |
|||
|
|||
const dataKey = key as string; |
|||
|
|||
set(record, dataKey, value); |
|||
//const record = await table.updateTableData(index, dataKey, value); |
|||
needEmit && table.emit?.('edit-end', { record, index, key, value }); |
|||
isEdit.value = false; |
|||
} |
|||
|
|||
async function handleEnter() { |
|||
if (props.column?.editRow) { |
|||
return; |
|||
} |
|||
await handleSubmit(); |
|||
} |
|||
|
|||
function handleCancel() { |
|||
isEdit.value = false; |
|||
currentValueRef.value = defaultValueRef.value; |
|||
const { column, index, record } = props; |
|||
const { key } = column; |
|||
ruleVisible.value = true; |
|||
ruleMessage.value = ''; |
|||
table.emit?.('edit-cancel', { |
|||
record, |
|||
index, |
|||
key: key, |
|||
value: unref(currentValueRef), |
|||
}); |
|||
} |
|||
|
|||
function onClickOutside() { |
|||
if (props.column?.editable || unref(getRowEditable)) { |
|||
return; |
|||
} |
|||
const component = unref(getComponent); |
|||
|
|||
if (component.includes('NInput')) { |
|||
handleCancel(); |
|||
} |
|||
} |
|||
|
|||
// only ApiSelect |
|||
function handleOptionsChange(options: LabelValueOptions) { |
|||
optionsRef.value = options; |
|||
} |
|||
|
|||
function initCbs(cbs: 'submitCbs' | 'validCbs' | 'cancelCbs', handle: Fn) { |
|||
if (props.record) { |
|||
/* eslint-disable */ |
|||
isArray(props.record[cbs]) |
|||
? props.record[cbs]?.push(handle) |
|||
: (props.record[cbs] = [handle]); |
|||
} |
|||
} |
|||
|
|||
if (props.record) { |
|||
initCbs('submitCbs', handleSubmit); |
|||
initCbs('validCbs', handleSubmiRule); |
|||
initCbs('cancelCbs', handleCancel); |
|||
|
|||
if (props.column.key) { |
|||
if (!props.record.editValueRefs) props.record.editValueRefs = {}; |
|||
props.record.editValueRefs[props.column.key] = currentValueRef; |
|||
} |
|||
/* eslint-disable */ |
|||
props.record.onCancelEdit = () => { |
|||
isArray(props.record?.cancelCbs) && props.record?.cancelCbs.forEach((fn) => fn()); |
|||
}; |
|||
/* eslint-disable */ |
|||
props.record.onSubmitEdit = async () => { |
|||
if (isArray(props.record?.submitCbs)) { |
|||
const validFns = (props.record?.validCbs || []).map((fn) => fn()); |
|||
|
|||
const res = await Promise.all(validFns); |
|||
|
|||
const pass = res.every((item) => !!item); |
|||
|
|||
if (!pass) return; |
|||
const submitFns = props.record?.submitCbs || []; |
|||
submitFns.forEach((fn) => fn(false, false)); |
|||
table.emit?.('edit-row-end'); |
|||
return true; |
|||
} |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
isEdit, |
|||
handleEdit, |
|||
currentValueRef, |
|||
handleSubmit, |
|||
handleChange, |
|||
handleCancel, |
|||
elRef, |
|||
getComponent, |
|||
getRule, |
|||
onClickOutside, |
|||
ruleMessage, |
|||
getRuleVisible, |
|||
getComponentProps, |
|||
handleOptionsChange, |
|||
getWrapperClass, |
|||
getRowEditable, |
|||
getValues, |
|||
handleEnter, |
|||
// getSize, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less"> |
|||
.editable-cell { |
|||
&-content { |
|||
position: relative; |
|||
overflow-wrap: break-word; |
|||
word-break: break-word; |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
|
|||
&-comp { |
|||
flex: 1; |
|||
} |
|||
|
|||
.edit-icon { |
|||
font-size: 14px; |
|||
//position: absolute; |
|||
//top: 4px; |
|||
//right: 0; |
|||
display: none; |
|||
width: 20px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
&:hover { |
|||
.edit-icon { |
|||
display: inline-block; |
|||
} |
|||
} |
|||
} |
|||
|
|||
&-action { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,15 @@ |
|||
import { ComponentType } from '../../types/componentType'; |
|||
|
|||
/** |
|||
* @description: 生成placeholder |
|||
*/ |
|||
export function createPlaceholderMessage(component: ComponentType) { |
|||
if (component === 'NInput') return '请输入'; |
|||
if ( |
|||
['NPicker', 'NSelect', 'NCheckbox', 'NRadio', 'NSwitch', 'NDatePicker', 'NTimePicker'].includes( |
|||
component |
|||
) |
|||
) |
|||
return '请选择'; |
|||
return ''; |
|||
} |