mirror of
https://github.com/XiaoDaiGua-Ray/ray-template.git
synced 2025-10-08 00:05:31 +08:00
Compare commits
No commits in common. "main" and "v4.8.4" have entirely different histories.
18
.eslintignore
Normal file
18
.eslintignore
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
dist/*
|
||||||
|
node_modules/*
|
||||||
|
auto-imports.d.ts
|
||||||
|
components.d.ts
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
public
|
||||||
|
yarn.*
|
||||||
|
vite-env.*
|
||||||
|
.prettierrc.*
|
||||||
|
visualizer.*
|
||||||
|
visualizer.html
|
||||||
|
.env.*
|
||||||
|
src/locales/lang
|
||||||
|
.depcheckrc
|
||||||
|
src/app-config/echart-themes/**/*.json
|
||||||
|
*.md
|
||||||
|
src/icons/*.svg
|
286
.eslintrc.cjs
Normal file
286
.eslintrc.cjs
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
/* eslint-env node */
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
ignorePatterns: ['node_modules/', 'dist/'],
|
||||||
|
extends: [
|
||||||
|
'eslint-config-prettier',
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:vue/vue3-recommended',
|
||||||
|
'plugin:vue/vue3-essential',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
|
'prettier',
|
||||||
|
'./unplugin/.eslintrc-auto-import.json',
|
||||||
|
],
|
||||||
|
parser: 'vue-eslint-parser',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
sourceType: 'module',
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
ecmaFeatures: {
|
||||||
|
jsx: true,
|
||||||
|
tsx: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: ['vue', '@typescript-eslint', 'prettier'],
|
||||||
|
globals: {
|
||||||
|
defineProps: 'readonly',
|
||||||
|
defineEmits: 'readonly',
|
||||||
|
defineExpose: 'readonly',
|
||||||
|
withDefaults: 'readonly',
|
||||||
|
defineOptions: 'readonly',
|
||||||
|
defineModel: 'readonly',
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'no-undefined': ['error'],
|
||||||
|
'linebreak-style': ['error', 'unix'],
|
||||||
|
'@typescript-eslint/no-explicit-any': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignoreRestArgs: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'prettier/prettier': 'error',
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
'@typescript-eslint/no-unused-vars': 'off',
|
||||||
|
'@typescript-eslint/ban-types': 'off',
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
|
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
|
||||||
|
'@typescript-eslint/consistent-type-imports': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
disallowTypeAnnotations: false,
|
||||||
|
},
|
||||||
|
], // 强制导入类型显示标注 `import type xxx from 'xxx'`
|
||||||
|
'@typescript-eslint/no-empty-interface': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowSingleExtends: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'accessor-pairs': 2, // 强制同时存在 `get` 与 `set`
|
||||||
|
'constructor-super': 0, // 强制子类构造函数中使用 `super` 调用父类的构造函数
|
||||||
|
'default-case': 2, // `switch` 中强制含有 `default`
|
||||||
|
eqeqeq: [2, 'allow-null'], // 强制使用严格判断 `===`
|
||||||
|
'no-alert': 0, // 禁止使用 `alert`、`confirm`
|
||||||
|
'no-array-constructor': 2, // 禁止使用数组构造器
|
||||||
|
'no-bitwise': 0, // 禁止使用按位运算符
|
||||||
|
'no-caller': 1, // 禁止使用 `arguments.caller`、`arguments.callee`
|
||||||
|
'no-catch-shadow': 2, // 禁止 `catch` 子句参数与外部作用域变量同名
|
||||||
|
'no-class-assign': 2, // 禁止给类赋值
|
||||||
|
'no-cond-assign': 2, // 禁止在条件表达式中使用赋值语句
|
||||||
|
'no-const-assign': 2, // 禁止修改 `const` 声明的变量
|
||||||
|
'no-constant-condition': 2, // 禁止在条件中使用常量表达式 `if(true)`、`if(1)`
|
||||||
|
'no-dupe-keys': 2, // 在创建对象字面量时不允许 `key` 重复
|
||||||
|
'no-dupe-args': 2, // 函数参数不能重复
|
||||||
|
'no-duplicate-case': 2, // `switch` 中的 `case` 标签不能重复
|
||||||
|
'no-eval': 1, // 禁止使用 `eval`
|
||||||
|
'no-ex-assign': 2, // 禁止给 `catch` 语句中的异常参数赋值
|
||||||
|
'no-extend-native': 2, // 禁止扩展 `native` 对象
|
||||||
|
'no-extra-bind': 2, // 禁止不必要的函数绑定
|
||||||
|
'no-extra-boolean-cast': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
enforceForLogicalOperands: true,
|
||||||
|
},
|
||||||
|
], // 禁止不必要的 `bool` 转换
|
||||||
|
'no-extra-parens': 0, // 禁止非必要的括号
|
||||||
|
semi: [
|
||||||
|
'error',
|
||||||
|
'never',
|
||||||
|
{
|
||||||
|
beforeStatementContinuationChars: 'always',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'no-fallthrough': 1, // 禁止 `switch` 穿透
|
||||||
|
'no-func-assign': 2, // 禁止重复的函数声明
|
||||||
|
'no-implicit-coercion': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allow: ['!!', '~'],
|
||||||
|
},
|
||||||
|
], // 禁止隐式转换
|
||||||
|
'no-implied-eval': 2, // 禁止使用隐式 `eval`
|
||||||
|
'no-invalid-regexp': 2, // 禁止无效的正则表达式
|
||||||
|
'no-invalid-this': 2, // 禁止无效的 `this`
|
||||||
|
'no-irregular-whitespace': 2, // 禁止含有不合法空格
|
||||||
|
'no-iterator': 2, // 禁止使用 `__iterator__ ` 属性
|
||||||
|
'no-label-var': 2, // `label` 名不能与 `var` 声明的变量名相同
|
||||||
|
'no-labels': 2, // 禁止标签声明
|
||||||
|
'no-lone-blocks': 2, // 禁止不必要的嵌套块
|
||||||
|
'no-multi-spaces': 1, // 禁止使用多余的空格
|
||||||
|
'no-multiple-empty-lines': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
max: 2,
|
||||||
|
},
|
||||||
|
], // 空行最多不能超过 `2` 行
|
||||||
|
'no-new-func': 2, // 禁止使用 `new Function`
|
||||||
|
'no-new-object': 2, // 禁止使用 `new Object`
|
||||||
|
'no-new-require': 2, // 禁止使用 `new require`
|
||||||
|
'no-sparse-arrays': 2, // 禁止稀疏数组
|
||||||
|
'no-trailing-spaces': 1, // 一行结束后面不要有空格
|
||||||
|
'no-unreachable': 2, // 禁止有无法执行的代码
|
||||||
|
'no-unused-expressions': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowShortCircuit: true,
|
||||||
|
allowTernary: true,
|
||||||
|
allowTaggedTemplates: true,
|
||||||
|
enforceForJSX: true,
|
||||||
|
},
|
||||||
|
], // 禁止无用的表达式
|
||||||
|
'no-useless-call': 2, // 禁止不必要的 `call` 和 `apply`
|
||||||
|
'no-var': 'error', // 禁用 `var`
|
||||||
|
'no-with': 2, // 禁用 `with`
|
||||||
|
'use-isnan': 2, // 强制使用 isNaN 判断 NaN
|
||||||
|
'no-multi-assign': 2, // 禁止连续声明变量
|
||||||
|
'prefer-arrow-callback': 2, // 强制使用箭头函数作为回调
|
||||||
|
curly: ['error', 'all'],
|
||||||
|
'vue/multi-word-component-names': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignores: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'vue/no-use-v-if-with-v-for': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowUsingIterationVar: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'vue/require-v-for-key': ['error'],
|
||||||
|
'vue/require-valid-default-prop': ['error'],
|
||||||
|
'vue/component-definition-name-casing': ['error', 'PascalCase'],
|
||||||
|
'vue/html-closing-bracket-newline': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
singleline: 'never',
|
||||||
|
multiline: 'always',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'vue/v-on-event-hyphenation': ['error', 'never'],
|
||||||
|
'vue/component-tags-order': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
order: ['template', 'script', 'style'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'vue/no-v-html': ['error'],
|
||||||
|
'vue/no-v-text': ['error'],
|
||||||
|
'vue/component-api-style': [
|
||||||
|
'error',
|
||||||
|
['script-setup', 'composition', 'composition-vue2'],
|
||||||
|
],
|
||||||
|
'vue/component-name-in-template-casing': [
|
||||||
|
'error',
|
||||||
|
'PascalCase',
|
||||||
|
{
|
||||||
|
registeredComponentsOnly: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'vue/no-unused-refs': ['error'],
|
||||||
|
'vue/prop-name-casing': ['error', 'camelCase'],
|
||||||
|
'vue/component-options-name-casing': ['error', 'PascalCase'],
|
||||||
|
'vue/attribute-hyphenation': [
|
||||||
|
'error',
|
||||||
|
'never',
|
||||||
|
{
|
||||||
|
ignore: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'vue/no-restricted-static-attribute': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
key: 'key',
|
||||||
|
message: 'Disallow using key as a custom attribute',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'no-restricted-syntax': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
selector: "CallExpression[callee.property.name='deprecated']",
|
||||||
|
message: 'Using deprecated API is not allowed.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'padding-line-between-statements': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: '*',
|
||||||
|
next: 'return',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: '*',
|
||||||
|
next: 'function',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: ['const', 'let', 'var'],
|
||||||
|
next: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'any',
|
||||||
|
prev: ['const', 'let', 'var'],
|
||||||
|
next: ['const', 'let', 'var'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: 'directive',
|
||||||
|
next: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'any',
|
||||||
|
prev: 'directive',
|
||||||
|
next: 'directive',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: ['case', 'default'],
|
||||||
|
next: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: ['break'],
|
||||||
|
next: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: ['import'],
|
||||||
|
next: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'any',
|
||||||
|
prev: 'import',
|
||||||
|
next: 'import',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: '*',
|
||||||
|
next: 'export',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'any',
|
||||||
|
prev: 'export',
|
||||||
|
next: 'export',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: ['function'],
|
||||||
|
next: '*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blankLine: 'always',
|
||||||
|
prev: ['class'],
|
||||||
|
next: '*',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
12
.gitattributes
vendored
12
.gitattributes
vendored
@ -1,14 +1,2 @@
|
|||||||
# 将换行符设置为lf
|
# 将换行符设置为lf
|
||||||
* text eol=lf
|
* text eol=lf
|
||||||
# 将静态资源文件以二进制形式处理
|
|
||||||
*.png binary
|
|
||||||
*.jpg binary
|
|
||||||
*.jpeg binary
|
|
||||||
*.gif binary
|
|
||||||
*.svg binary
|
|
||||||
*.webp binary
|
|
||||||
*.mp4 binary
|
|
||||||
*.mov binary
|
|
||||||
*.avi binary
|
|
||||||
*.mp3 binary
|
|
||||||
*.wav binary
|
|
8
.github/workflows/docs-deploy.yaml
vendored
8
.github/workflows/docs-deploy.yaml
vendored
@ -14,15 +14,15 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install Node.js 22.x
|
- name: Install Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 22.x
|
node-version: 20.x
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
with:
|
with:
|
||||||
version: 9
|
version: 8
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@ -35,4 +35,4 @@ jobs:
|
|||||||
uses: JamesIves/github-pages-deploy-action@4.1.4
|
uses: JamesIves/github-pages-deploy-action@4.1.4
|
||||||
with:
|
with:
|
||||||
branch: dist
|
branch: dist
|
||||||
folder: dist/production
|
folder: dist/production-dist
|
||||||
|
4
.github/workflows/push-build.yaml
vendored
4
.github/workflows/push-build.yaml
vendored
@ -8,7 +8,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [22.x]
|
node-version: [20.x]
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
experimental: [true]
|
experimental: [true]
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ jobs:
|
|||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
with:
|
with:
|
||||||
version: 9
|
version: 8
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Get pnpm store directory
|
- name: Get pnpm store directory
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,7 +15,6 @@ dist/
|
|||||||
*.local
|
*.local
|
||||||
visualizer.*
|
visualizer.*
|
||||||
.eslintcache
|
.eslintcache
|
||||||
.history
|
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.idea
|
.idea
|
||||||
|
@ -8,6 +8,7 @@ module.exports = {
|
|||||||
jsxSingleQuote: false, // `jsx` 不使用单引号, 而使用双引号
|
jsxSingleQuote: false, // `jsx` 不使用单引号, 而使用双引号
|
||||||
trailingComma: 'all', // 尾随逗号
|
trailingComma: 'all', // 尾随逗号
|
||||||
bracketSpacing: true, // 大括号内的首尾需要空格
|
bracketSpacing: true, // 大括号内的首尾需要空格
|
||||||
|
jsxBracketSameLine: false, // `jsx` 标签的反尖括号需要换行
|
||||||
arrowParens: 'always', // 箭头函数, 只有一个参数的时候, 也需要括号
|
arrowParens: 'always', // 箭头函数, 只有一个参数的时候, 也需要括号
|
||||||
rangeStart: 0, // 每个文件格式化的范围是文件的全部内容
|
rangeStart: 0, // 每个文件格式化的范围是文件的全部内容
|
||||||
rangeEnd: Infinity,
|
rangeEnd: Infinity,
|
||||||
@ -16,5 +17,6 @@ module.exports = {
|
|||||||
proseWrap: 'preserve', // 使用默认的折行标准
|
proseWrap: 'preserve', // 使用默认的折行标准
|
||||||
htmlWhitespaceSensitivity: 'css', // 根据显示样式决定 `html` 要不要折行
|
htmlWhitespaceSensitivity: 'css', // 根据显示样式决定 `html` 要不要折行
|
||||||
endOfLine: 'lf', // 换行符使用 `lf`,
|
endOfLine: 'lf', // 换行符使用 `lf`,
|
||||||
|
bracketLine: false,
|
||||||
singleAttributePerLine: false,
|
singleAttributePerLine: false,
|
||||||
}
|
}
|
||||||
|
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"i18n-ally.localesPaths": ["src/locales/lang"],
|
"i18n-ally.localesPaths": ["src/locales/lang"],
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.sortKeys": true,
|
"i18n-ally.sortKeys": true,
|
||||||
@ -20,13 +19,10 @@
|
|||||||
"alias-skip.allowedsuffix": ["ts", "tsx"],
|
"alias-skip.allowedsuffix": ["ts", "tsx"],
|
||||||
"alias-skip.rootpath": "package.json",
|
"alias-skip.rootpath": "package.json",
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"baomitu",
|
|
||||||
"bezier",
|
"bezier",
|
||||||
"Cascader",
|
|
||||||
"Clickoutside",
|
"Clickoutside",
|
||||||
"codabar",
|
"codabar",
|
||||||
"commitmsg",
|
"commitmsg",
|
||||||
"crossorigin",
|
|
||||||
"datetimerange",
|
"datetimerange",
|
||||||
"domtoimage",
|
"domtoimage",
|
||||||
"EDITMSG",
|
"EDITMSG",
|
||||||
@ -34,7 +30,6 @@
|
|||||||
"internalkey",
|
"internalkey",
|
||||||
"jsbarcode",
|
"jsbarcode",
|
||||||
"linebreak",
|
"linebreak",
|
||||||
"logicflow",
|
|
||||||
"macarons",
|
"macarons",
|
||||||
"menutag",
|
"menutag",
|
||||||
"ndata",
|
"ndata",
|
||||||
@ -43,10 +38,9 @@
|
|||||||
"Popselect",
|
"Popselect",
|
||||||
"precommit",
|
"precommit",
|
||||||
"siderbar",
|
"siderbar",
|
||||||
"snapline",
|
|
||||||
"stylelint",
|
"stylelint",
|
||||||
"unocss",
|
|
||||||
"WUJIE",
|
"WUJIE",
|
||||||
"zlevel"
|
"zlevel"
|
||||||
]
|
],
|
||||||
|
"peacock.color": "#007fff"
|
||||||
}
|
}
|
||||||
|
543
CHANGELOG.md
543
CHANGELOG.md
@ -1,545 +1,4 @@
|
|||||||
## 5.2.2
|
# CHANGE LOG
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `RForm` 组件相关
|
|
||||||
- 新增 `submitWhenEnter` 配置项,允许在按下回车键时自动触发表单的校验,如果校验成功则会自动触发 `onFinish` 事件
|
|
||||||
- 新增 `onFinish` 配置项,允许在表单校验成功后自动触发的事件
|
|
||||||
- 新增 `autocomplete` 配置项,允许配置表单的自动完成功能,默认配置为 `off`
|
|
||||||
- 新增 `loading` 配置项,允许配置表单的加载状态
|
|
||||||
- 新增 `loadingDescription` 配置项,允许配置表单的加载状态的描述
|
|
||||||
- `useForm` 相关
|
|
||||||
- 新增 `validateTargetField` 方法,允许验证指定表单项的规则
|
|
||||||
- 初始化方法现在支持传入函数,允许动态获取表单的初始化值与规则
|
|
||||||
- `formModel` 方法现在会默认联合 `Recordable` 类型,获取初始化类型中未获取到的类型时,默认推到为 `any` 类型
|
|
||||||
- 新增了 `formConditionRef` 属性,现在可以在内部解构获取一个 `ref` 包裹的响应式初始化表单对象值
|
|
||||||
- 新增了 `updateFormCondition` 方法,允许更新表单的值,该方法会覆盖初始化值
|
|
||||||
- 更新依赖为主流版本
|
|
||||||
- 新增 `unocss` 原子化样式库,但是不推荐全量使用,仅作为一些简单的样式片段使用,否则在调试的时候将会是灾难
|
|
||||||
> 新增 `unocss` 后,在使用 `ProTable` 组件的流体高度最外层父元素配置时,可以便捷的配置 `h-full` 即可。
|
|
||||||
|
|
||||||
## 5.2.1
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `RTablePro` 组件相关
|
|
||||||
- 新增 `runAsyncTableRequest` 方法,与 `runTableRequest` 方法功能一致,但是返回 `Promise` 对象
|
|
||||||
- 现在不允许使用 `useTemplateRef` 方法注册 `dom` 模板引用,约定强制使用 `useTablePro` 方法的 `register` 方法注册 `hook` 使用相关方法
|
|
||||||
- `useTablePro` 方法新增 `getTableProConfig` 方法,与 `useTable` 方法的 `getTableConfig` 方法功能一致,获取 `RTablePro` 组件额外注入配置
|
|
||||||
- `useTable` 方法新增 `getTableConfig` 方法,获取 `RTable` 组件额外注入配置
|
|
||||||
- 更新包为主流版本
|
|
||||||
- `vue-router` 因为在 [4.4.1](https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#441-2024-07-31) 版本中有破坏性的更新,所以在 `jsx` 函数式组件使用 `this.$route`, `this.$router` 会提示类型报错,所以现在强制约定需要使用 `useRoute`, `useRouter` 方法显示的声明与使用
|
|
||||||
- 更新 `naive-ui` 版本至 `2.42.0`
|
|
||||||
- 更新 `vue` 版本至 `3.5.17`
|
|
||||||
- `useForm` 方法新增 `reset` 方法,允许重置表单值,该方法依赖 `useForm` 方法的初始化 `formModel` 参数,所以请确保初始化 `formModel` 参数
|
|
||||||
|
|
||||||
## 5.2.0
|
|
||||||
|
|
||||||
一些破坏性更新,请谨慎更新。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vue` 版本至 `3.5.16`
|
|
||||||
- 更新 `vite` 版本至 `6.3.5`
|
|
||||||
- `RTablePro` 组件相关
|
|
||||||
- `runTableRequest` 方法现在支持传递 `reset` 参数,配置是否重置分页请求
|
|
||||||
- `runTableRequest` 方法新增 `excludeParams` 配置项,允许排除指定的请求参数
|
|
||||||
- `onTablePaginationUpdate` 方法参数返回值由返回函数改为直接返回值
|
|
||||||
- 新增 `paginationPrefix` 配置项,允许自定义分页器前缀,在国际化需求可能会有用
|
|
||||||
- 新增 `flexAutoHeight` 配置项,默认关闭,允许配置表格是否自动继承高度,但是要结合 `css flex` 属性使用
|
|
||||||
|
|
||||||
> 如果你是使用 `NFlex` 组件结合 `RTablePro` 或者 `RTable` 组件使用,需要配置 `Flex` 组件的 `vertical` 属性,并且设置 `class` 为 `flex-vertical`,即可便捷实现该效果。否则你需要设置 `css flex` 相关属性(可以参考 Demo2)的示例。
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { RTablePro } from '@/components'
|
|
||||||
import { NFlex } from 'naive-ui'
|
|
||||||
|
|
||||||
const Demo1 = () => {
|
|
||||||
return (
|
|
||||||
<NFlex vertical class="flex-vertical">
|
|
||||||
<RTablePro flexAutoHeight />
|
|
||||||
</NFlex>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const Demo2 = () => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
class="flex-vertical"
|
|
||||||
style="height: 100%; display: flex; flex-direction: column;"
|
|
||||||
>
|
|
||||||
<RTablePro flexAutoHeight />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- 新增 `getDateByNaiveDatePicker` 方法,便捷获取 `naive-ui` 的 `DatePicker` 组件的日期值
|
|
||||||
- `Recordable` 类型新增 `symbol`, `number` 类型作为 `key` 支持
|
|
||||||
- `RCollapse` 组件相关
|
|
||||||
- 默认配置 `responsive` 配置项为 `screen` 响应模式
|
|
||||||
- 默认配置 `cols` 配置项为 `4 xs:1 s:2 m:2 l:4 xl:4 2xl:6`,虽然目前的预设已经足够使用,但你也可以高度自定义需求
|
|
||||||
- `types` 包
|
|
||||||
- 新增 `GlobalDataTableColumns` 类型,用于声明全局 `DataTableColumns` 类型
|
|
||||||
- 新增 `GlobalRecordable` 类型,用于声明全局 `Recordable` 类型
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `RTablePro` 组件 `print` 方法打印内容错误的问题
|
|
||||||
|
|
||||||
## 5.1.0
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vite` 版本至 `5.3.3`
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `chunksCopilot` 方法判断不准确导致 `node_modules` 库被拆分到 `hooks` 分包重复的问题
|
|
||||||
|
|
||||||
## 5.0.10
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `RDraggableCard` 组件现在不会在抛出获取 `dom` 失败的异常,因为可能存在异步组件加载的可能
|
|
||||||
- `RModal`, `useModal` 方法,移除 `dad` 相关所有配置,使用 `draggable` 配置项替代
|
|
||||||
- 刷新的样式现在会跟随主题变化
|
|
||||||
- 锁屏密码现在会进行加密存储,并且会进行校验处理了
|
|
||||||
- 新增 `decrypt`, `decrypt` 方法,放置于 `utils/c` 包中
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复因为错误的注册全局事件,导致事件污染的问题,但是默认的 `ctrl + k`, `cmd + k` 快捷键依旧保留为全局按键
|
|
||||||
|
|
||||||
## 5.0.9
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `RDraggableCard` 组件
|
|
||||||
- 新增 `restrictionElement` 配置项,允许设置拖拽限制元素
|
|
||||||
- 新增 `padding` 配置项,允许配置元素初始化位置的间隔值
|
|
||||||
- `defaultPosition` 配置项新增 `top-left`, `top-right`, `bottom-left`, `bottom-right` 配置项,允许配置元素初始化位置
|
|
||||||
- `RTablePro` 组件
|
|
||||||
- 现在会自动删除重复的请求参数
|
|
||||||
- 暴露 `resetTablePagination` 方法,允许手动重置表格分页
|
|
||||||
- `logout` 方法现在会在执行的时候,清空所有的 `router-route`
|
|
||||||
- 更新依赖为主流版本
|
|
||||||
|
|
||||||
## 5.0.8
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 修改 `menuTagOptions` 的缓存方式,现在会缓存至 `sessionStorage` 中,兼容可能多系统版本部署与多开系统页面标签页冲突的问题
|
|
||||||
- 新增 `RDraggableCard` 组件
|
|
||||||
- 更新 `vite` 版本至 `6.0.4`
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `updateObjectValue` 方法对于对象值判断不准确的问题
|
|
||||||
- 修复 `SettingDrawer` 组件初始化时,没有正确初始化 `settingStore` 的问题
|
|
||||||
- 修复 `RTable` 组件在未设置 `title` 与 `tool` 为 `false` 时,导致 `headerStyle` 样式会高一些的问题
|
|
||||||
|
|
||||||
## 5.0.7
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vue` 版本至 `3.5.13`
|
|
||||||
- 更新 `vite` 版本至 `6.0.3`
|
|
||||||
- 更新 `naive-ui` 版本至 `2.40.3`
|
|
||||||
- 更新包依赖为主流依赖
|
|
||||||
- 更新 `eslint` 版本至 `9.11.0`,并且同步修改 `eslint` 相关配置方式,使用 `eslint.config.mjs` 文件替代
|
|
||||||
- 更新默认 `node` 版本至 `22.11.0`
|
|
||||||
- `RCollapseGrid` 组件新增 `actionSpan` 配置项,配置操作区域列数
|
|
||||||
- `usePagination` 方法新增 `pageChange`, `pageSizeChange` 回调函数,允许在更新分页页码与每页条数的时候,执行自定义回调;用于取代被移除的 `onUpdatePage`, `onUpdatePageSize` 方法
|
|
||||||
- 移除 `appNaiveUIThemeOverridesCommon` 配置项,现在统一使用 `appNaiveUIThemeOverrides` 配置项
|
|
||||||
- 优化整体风格样式
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `useDomToImage` 方法的类型推导问题
|
|
||||||
- 修复主题切换时,`naive-ui` 主题色覆盖不生效的问题
|
|
||||||
|
|
||||||
## 5.0.6
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 新增 `useChartProvider` 方法,允许注入 `RCharts` 组件配置
|
|
||||||
- 更新 `echarts` 版本至 `5.5.1`
|
|
||||||
- 更新 `vue` 版本至 `3.5.13`
|
|
||||||
- 更新 `@vueuse/core` 版本至 `11.2.0`
|
|
||||||
- 修改 `SettingDrawer` 组件的 `defaultOptions` 配置项管理方式,现在迁移至 `store.setting` 包中
|
|
||||||
- 重构 `cache` 工具模块,更有好的类型推导、更少的代码量
|
|
||||||
- 重构 `precision` 工具模块,更好的类型推导、更少的代码量
|
|
||||||
- 重写 `updateObjectValue` 方法,现在类型提示更加准确
|
|
||||||
- 全局使用 `useTemplateRef`, `shallowRef` 方法替代 `ref` 注册模板引用,减少不必要的响应式代理
|
|
||||||
- 优化 `MenuTag` 组件的关闭按钮样式
|
|
||||||
- `LockScreen` 组件新增头像展示
|
|
||||||
- `AppAvatar` 组件现在默认获取 `avatar` 字段为空的时候,展示名字的首字
|
|
||||||
- 优化 `UnlockScreen` 组件样式,现在会根据主题自动调整背景颜色
|
|
||||||
- 优化内容区域过度动画效果
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `404` 页面【返回】按钮不能准确返回的问题
|
|
||||||
- 修复 `usePagination.getCallback` 方法类型丢失问题;修复该方法获取实时回调不准确的问题
|
|
||||||
- 修复初始化时,菜单滚动条不能准确滚动到当前激活项的问题
|
|
||||||
- 修复 `UnlockScreen` 组件在白色主题下,导致样式显示差异问题,现在统一为黑色主题配置覆盖
|
|
||||||
- 修复 `LockScreen` 组件在退出锁屏时,没有及时更新 `localStorage` 缓存的问题
|
|
||||||
- 修复 `setupDayjs` 初始化不准确的问题
|
|
||||||
|
|
||||||
## 5.0.5
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 新增 `GLOBAL_CLASS_NAMES` 配置项
|
|
||||||
- 新增 `canSkipRoute` 方法,用于初始化系统菜单时,自动获取可跳转的路由,避免权限系统列表中无权限路由跳转导致异常的问题
|
|
||||||
- 优化 `useElementFullscreen` 方法的过渡效果
|
|
||||||
- `useElementFullscreen` 新增 `isFullscreen` 属性,标识当前元素是否处于网页全屏状态
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复锁屏逻辑问题
|
|
||||||
- 修复菜单有时候不能正常的展开被激活项的问题
|
|
||||||
- 修复 `useSiderBar` 的 `close` 问题
|
|
||||||
|
|
||||||
## 5.0.4
|
|
||||||
|
|
||||||
将 `ts` 版本与 `eslint` 解析插件版本更新至最新版,并且同步解决了以前历史遗留的一些问题。
|
|
||||||
|
|
||||||
并且,在该版本做了一些全局注入方式调整,请谨慎更新。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 移除 `vite-plugin-compression` 插件,使用 `rollup-plugin-gzip` 代替
|
|
||||||
- 更新 `@vitejs/plugin-vue-jsx` 版本至 `4.0.1`
|
|
||||||
- 优化注释
|
|
||||||
- 默认设置 `ContentWrapper` 的 `content-wrapper` 内容展示区域的宽高为 `100%`,继承父容器的宽高;该样式会自动的计算,也就是说会自动的适配不同尺寸的屏幕输出与判断是否显示 `FeatureWrapper`, `FooterWrapper`
|
|
||||||
- 更新 `@typescript-eslint/eslint-plugin`, `@typescript-eslint/parser` 版本至 `8.13.0`
|
|
||||||
- 更新 `typescript` 版本至 `5.6.3`
|
|
||||||
- 更新 `vue-tsc` 版本至 `2.1.10`
|
|
||||||
- 更新 `pnpm` 包管理器版本至 `9.12.3`
|
|
||||||
- 新增 `RFlow` 基础流程图组件(后期有时间会逐步加强该组件)
|
|
||||||
- 移除 `useElementFullscreen` 方法 `currentWindowSize` 返回值
|
|
||||||
- 新增 `--html-height`, `--html-width` 的全局 `css var` 属性,实时获取浏览器的尺寸
|
|
||||||
- 样式注入现在由注入至 `body` 改为注入至 `html`,避免 `teleport` 传送至 `body` 外的元素不能使用全局样式的问题
|
|
||||||
- `useBadge.show` 方法新增 `extraOption` 配置项,允许在显示 `badge` 到时候,传入额外的 `options` 配置项
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复菜单折叠后,`SiderBarLogo` 标题样式丢失问题
|
|
||||||
- 修复 `useModal` 因为 `Omit` 原因导致类型丢失问题,现在直接使用 `ModalProps` 作为类型
|
|
||||||
- 修复 `useModal` 创建全屏 `card` 的时候,内容区域边距样式被覆盖的问题,现在会尊重原有的 `card` 样式
|
|
||||||
|
|
||||||
## 5.0.3
|
|
||||||
|
|
||||||
个性化配置能力再次提升。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `SettingDrawer` 组件重构
|
|
||||||
|
|
||||||
## 5.0.2
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 暴露 `setupAppMenu` 方法,提供自定义菜单渲染时机能力
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `MenuTag` 右键菜单不能被选中的问题
|
|
||||||
- 修复 `Menu` 设置 `iconSize`, `iconCollapseSize` 等属性,不能及时刷新渲染的问题,现在新增手动刷新操作按钮
|
|
||||||
|
|
||||||
> 菜单渲染是很复杂、很耗时的操作,所以在权衡以后还是考虑使用手动刷新操作方式更新菜单状态。
|
|
||||||
|
|
||||||
## 5.0.1
|
|
||||||
|
|
||||||
本次更新灵感来自于 `vben admin 5` 项目。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新了 `Menu`, `MenuTag`, `SiderBar` 样式细节
|
|
||||||
- 调整 `components`, `components-pro` 分包,现在都统一到 `components` 下,以 `base`, `pro` 进行区分,避免导出导入麻烦
|
|
||||||
- `MenuTag` 新增了一些操作方式
|
|
||||||
- `SiderBarLogo` 样式调整
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 新增 `tableFlexHeight` 配置项属性修复 `RTable` 组件因为不再透传至 `Table` 导致设置 `flexHeight` 进行动态高度设置失败的问题
|
|
||||||
- 修复 `RTable` 错误的 `title` 属性注入问题
|
|
||||||
- 修复 `MenuTag` 频繁右键会导致闪烁出现右键菜单的问题
|
|
||||||
|
|
||||||
## 5.0.0
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `RTable` 组件现在默认 `attrs` 透传不会再透传至 `Table` 而是透传至容器 `Card`
|
|
||||||
- `AppAvatar` 组件获取用户信息由 `localStorage` 缓存获取变更为 `getSigningCallback` 响应式获取
|
|
||||||
- 移除 `SUPER_ADMIN` 默认值
|
|
||||||
- 移除 `APP_KEEP_ALIVE` 配置项,迁移至 `settingStore`
|
|
||||||
- 移除 `SIDE_BAR_LOGO_DEFAULT` 配置项,迁移至 `settingStore`
|
|
||||||
- 移除 `APP_MENU_CONFIG` 配置项,迁移至 `settingStore`
|
|
||||||
- 移除所有的 `ray-template` 相关注释信息
|
|
||||||
- `SettingDrawer` 新增更多配置项,允许通过配置入口配置更多的配置项
|
|
||||||
- 新增 `DatePicker`, `InputNumber` 样式,默认设置 `width` 为 `100%`
|
|
||||||
- 新增 `updateObjectValue` 方法,并且全局替换重复类似方法
|
|
||||||
- `useTheme` 新增 `syncSystemTheme` 方法,允许同步系统主题
|
|
||||||
- 新增 `ThemeSegment` 主题切换组件
|
|
||||||
- 移除 `watchOnce` 方法引入,使用原生 `watch` 方法替代
|
|
||||||
- 取消 `SettingDrawer` 自动聚焦可选中元素
|
|
||||||
|
|
||||||
## 4.9.7
|
|
||||||
|
|
||||||
从该版本开始,默认关闭了 `cdn` 构建生产环境;因为国内厂商真心不给力。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vue` 版本至 `3.5.12`
|
|
||||||
- 更新 `@vueuse/core` 版本至 `11.1.0`
|
|
||||||
- 更新 `naive-ui` 版本至 `2.40.1`
|
|
||||||
- 更新 `MenuTag` 一些东西,移除了无用的 `ref` 注册,简化了代码;现在允许出现 `rootPath` 标签的关闭按钮了
|
|
||||||
- `useElementFullscreen` 新增 `currentWindowSize` 返回项,获取当前的窗口尺寸
|
|
||||||
- `RCollapseGrid` 组件默认开启 `bordered`
|
|
||||||
- `RCollapseGrid onUpdateValue` 方法更名为 `onUpdateOpen`
|
|
||||||
- `RTable` 组件默认开启 `wrapperBordered`
|
|
||||||
- `RTable` 组件默认开启 `bordered`
|
|
||||||
- 新增 `clearSigningCallback` 方法
|
|
||||||
- `vite.custom.config` 新增 `cdn` 配置项,是否启用 `cdn` 构建项目
|
|
||||||
- 配置 `cdn` 为 `false`,因为国内厂商更新资源速度有点慢,导致预览失败
|
|
||||||
- `Layout` 层注入 `--window-width`, `--window-height`, `css var` 属性
|
|
||||||
- 稳定 `Layout` 层的 `css var` 属性
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `MenuTag` 鼠标移入并且加右键菜单操作时,会导致关闭按钮图标消失的问题
|
|
||||||
- 修复 `useElementFullscreen` 方法在窗口尺寸更新时,全屏元素失败的问题
|
|
||||||
- 修复 `MenuTag` 注入 `MENU_TAG_DATA` 错误的问题
|
|
||||||
- 修复 `Layout Content` 默认高度获取失败问题
|
|
||||||
- 修复 `RCollapseGrid` 组件自定义 `collapse` 插槽折叠失败的问题
|
|
||||||
|
|
||||||
## 4.9.6
|
|
||||||
|
|
||||||
由于 `cdn` 厂商更新 `cdn` 资源太慢的缘故,所以目前 `vue` 的版本只有 `3.5.3` 会导致构建线上生产环境报错的问题。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vue` 版本至 `3.5.8`
|
|
||||||
- `useDomToImage` 相关
|
|
||||||
- 使用 `html-to-image` 替换 `dom-to-image` 底层依赖库
|
|
||||||
- 同步补全 `html-to-image` 所有新特性至该方法
|
|
||||||
- 同步修改 `printDom` 方法
|
|
||||||
- 类型提示现在会更加友好,`create` 方法会根据 `imageType` 自动推导转换结果的类型
|
|
||||||
- 移除 `DomToImageResult` 类型
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `RCollapseGrid` 组件折叠失败的问题
|
|
||||||
|
|
||||||
## 4.9.5
|
|
||||||
|
|
||||||
天元突破,红莲螺岩。
|
|
||||||
|
|
||||||
兼容 `vue3.5` 版本的更新。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新脚手架依赖为主流依赖
|
|
||||||
- 更新 `vue` 版本至 `3.5.6`
|
|
||||||
- 更新 `vite` 版本至 `5.4.3`
|
|
||||||
- 更新 `pinia-plugin-persistedstate` 版本至 `4.0.1`,并且兼容破坏性更新改动
|
|
||||||
- `RChart` 组件相关
|
|
||||||
- 小重构该组件,移除多个 `echart` 缓存,现在有且仅有一个
|
|
||||||
- 减少 `watch` 监听项
|
|
||||||
- 使用 `useTemplateRef` 方法替代 `ref` 注册 `dom`
|
|
||||||
- 现在预设 `card` 时,`chart` 图会更加的醒目一些
|
|
||||||
- 优化 `demo` 展示
|
|
||||||
- 现在会拦截 `aria` 属性,现在仅允许通过 `showAria` 配置项管理无障碍模式
|
|
||||||
- 优化无障碍模式渲染,现在不会重新渲染整个图表,而是通过 `setOptions` 方式更新图表
|
|
||||||
- `useChart` 方法相关
|
|
||||||
- `isDispose` 方法更名为 `isDisposed`
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `useChart` 方法相关方法中 `dispose` 方法执行不生效的问题
|
|
||||||
- 修复 `RChart` 的 `loading` 不能跟随主题变化的问题
|
|
||||||
|
|
||||||
## 4.9.4
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `cdn` 相关的一些配置
|
|
||||||
- 将 `cdn` 源更新为 `baomitu`,为了避免因为墙的影响导致加载缓慢的问题
|
|
||||||
- 新增一些插件的 `cdn` 配置
|
|
||||||
- `useTable`, `useTablePro` 中的 `print` 方法新增传递 `options` 配置项,配置打印,允许配置 `dom-to-image` 与 `print-js`,详情可以查看 `PrintDomOptions` 类型说明。
|
|
||||||
- `RCollapse` 组件新增 `collapse` 插槽,允许自定义【展开】与【收起】状态
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `useTablePro` 中 `print` 方法丢失的问题
|
|
||||||
|
|
||||||
## 4.9.3
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vue` 版本至 `3.4.38`
|
|
||||||
- 更新 `vite` 版本至 `5.4.1`
|
|
||||||
- 调整 `RCollapseGrid` 支持 `actionAlign` 配置型,配置按钮垂直方向,默认为 `end`
|
|
||||||
- `MenuTag` 组件
|
|
||||||
- 调整 `MenuTag` 滚动条样式,现在将它隐藏了
|
|
||||||
- 优化关闭按钮样式
|
|
||||||
- `RTable` 新增 `renderWrapperHeader` 配置项,配置外层容器 `header` 是否渲染
|
|
||||||
- `postcss` 配置 `not dead`,忽略兼容已经无需兼容的浏览器
|
|
||||||
- `RChart` 组件 `setOptions` 方法配置项默认不启用 `merge` 模式
|
|
||||||
- 调整 `header` 的样式,增加了一点点间隙
|
|
||||||
- `useDevice` 新增 `observer` 配置项,可以自定义观察回调
|
|
||||||
- 新增 `components` 包,助力简化业务开发
|
|
||||||
- 新增 `RTablePro` 组件,大幅简化中后台带有过滤请求条件的表格显示业务
|
|
||||||
- 新增 `RCollapse` 组件,允许折叠过滤条件
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 移除 `postcss-px-to-viewport-8-plugin` 插件,使用 `postcss-px-to-viewport-8-with-include` 替换,修复 `include` 失效问题
|
|
||||||
- 修复 `useElementFullscreen` 在退出时,没有正确的回滚 `zIndex` 的问题
|
|
||||||
- 修复 `RChart` 配置 `setChartOptions` 不生效的问题
|
|
||||||
|
|
||||||
## 4.9.2
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- `useDevice` 支持 `observer` 配置项
|
|
||||||
- `postcss` 自动尺寸转换插件配置更新
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复菜单在小尺寸屏幕并且处于折叠状态,导致显示不完整的问题
|
|
||||||
|
|
||||||
## 4.9.1
|
|
||||||
|
|
||||||
更新核心依赖版本为主流版本。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `axios` 版本至 `1.7.2`
|
|
||||||
- 更新 `vue-hooks-plus` 版本至 `2.2.1`
|
|
||||||
- 更新 `naive-ui` 版本至 `2.39.0`
|
|
||||||
- 更新 `vue` 版本至 `3.4.34`
|
|
||||||
- 更新 `vite` 版本至 `5.3.5`
|
|
||||||
- 更新 `@vitejs/plugin-vue` 版本至 `5.1.0`
|
|
||||||
- 更新 `@vitejs/plugin-vue-jsx` 版本至 `4.0.0`
|
|
||||||
- 调整解锁锁屏头像样式
|
|
||||||
- `RModal` 在设置为拖拽时,如果未设置头(也就是 `title`)属性,则会失效
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `__APP_CFG__` 类型丢失问题
|
|
||||||
- 修复 `RTable` 设置 `tool` 为 `false` 时,单独设置 `striped`, `bordered` 时不生效的问题
|
|
||||||
|
|
||||||
## 4.9.0
|
|
||||||
|
|
||||||
主要修复了一个歧义问题,就是新开页面输入 `url`,或者是 `window.open` 打开当前系统的页面时,会导致初始化异常的问题。这是因为以前的 `appMenu`, `appSigning` 相关的缓存都是防止与 `sessionStorage`,但是该缓存并不能共享,所以导致了这个问题。在该版本中将该缓存调整为了 `localStorage`。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 移除 `vite-plugin-imp` 插件
|
|
||||||
- 更新 `vue` 版本至 `3.4.31`
|
|
||||||
- 更新 `vite` 版本至 `5.3.3`
|
|
||||||
- 将 `appPiniaMenuStore`, `appPiniaSigningStore` 缓存由 `sessionStorage` 更改为 `localStorage` 缓存
|
|
||||||
- 现在在模拟退出的时候,会清理 `appPiniaMenuStore`, `appPiniaSigningStore` 的 `localStorage` 缓存
|
|
||||||
- 将 `route` 待提取字段单独抽离,统一维护为 `pickRouteRecordNormalizedConstant`
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `RTable` 自定义 `tool` 时抛出的优化警告问题
|
|
||||||
- 修复在复制 `url` 打开新标签页输入网址后(包括新开页面),会导致项目初始化异常的问题
|
|
||||||
|
|
||||||
## 4.8.9
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `useCheckedRowKeys` 的 `getRows` 方法在异步分页获取数据的时候,会导致切换页面后勾选项丢失问题
|
|
||||||
|
|
||||||
## 4.8.8
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vite` 版本至 `5.3.1`
|
|
||||||
- 更新 `vue` 版本至 `3.4.30`
|
|
||||||
- `FetchErrorFunction` 类型在你自定义请求拦截器插件处理错误请求的时候,可能会用上
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `useCheckedRowKeys` 的 `getRows` 方法类型丢失问题
|
|
||||||
|
|
||||||
## 4.8.7
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vite` 版本至 `5.2.12`
|
|
||||||
- 更新 `vue` 版本至 `3.4.27`
|
|
||||||
- 更新 `vue-hooks-plus` 版本至 `2.2.0`
|
|
||||||
- 更新 `@types/lodash-es` 版本至 `4.17.12`
|
|
||||||
- `FetchFunction` 移除,使用 `AxiosResponseInterceptor`, `AxiosRequestInterceptor` 替代插件类型推导
|
|
||||||
- `echarts macarons theme` 优化
|
|
||||||
- `RChart` 组件的默认 `loading` 效果支持自动跟随主题切换
|
|
||||||
- `SIDE_BAR_LOGO` 更名为 `SIDE_BAR_LOGO_DEFAULT`,现在支持在 `setting store` 中动态更新,以满足更广泛的需求
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `primaryColorOverride` 配置项不生效问题
|
|
||||||
- 修复面包屑在 `sameLevel` 的情况下,可能会被覆盖问题
|
|
||||||
|
|
||||||
## 4.8.6
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复动态路由的情况下,始终会被跳转到 `404` 页面的问题
|
|
||||||
- 修复 `RIcon` 组件 `color` 配置项无效的问题
|
|
||||||
- 修复 `svg-icon` 页面可能会在更新 `icon` 后出现报错的问题
|
|
||||||
- 修复 `updateDocumentTitle` 方法可能会更新标题出错的问题
|
|
||||||
- 修复菜单的折叠问题
|
|
||||||
|
|
||||||
## 4.8.5
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 更新 `vue-router` 版本至 `4.3.2`
|
|
||||||
- 更新 `vue-hooks-plus` 版本至 `2.0.3`
|
|
||||||
- `usePagination` 方法
|
|
||||||
- 新增 `resetPagination` 方法,用于重置分页器
|
|
||||||
- `RBarcode` 组件,默认启用 `watchText` 配置项,用于监听 `text` 内容变化
|
|
||||||
- `RMoreDropdown` 组件,新增 `icon` 自定义配置图标,依赖 `RIcon` 组件实现
|
|
||||||
- `buildOptions` 方法现在会自动根据 `mode` 进行自动构建生成包了
|
|
||||||
- `RTable hooks`
|
|
||||||
- `UseCheckedRowKeysOptions`
|
|
||||||
- 新增 `table column` 参数,自动获取当前表格列配置是否启用了选项模式(单选、多选)
|
|
||||||
- `selectKey` 方法现在在单选模式下,只会选择一条数据,最后一次选择的会覆盖上次的
|
|
||||||
- `useTable`
|
|
||||||
- 新增 `print` 方法
|
|
||||||
- `useTheme` 方法
|
|
||||||
- `changeDarkTheme` 更名为 `darkTheme`
|
|
||||||
- `changeLightTheme` 更名为 `lightTheme`
|
|
||||||
- `getAppTheme` 方法返回值做了准确的 `ts` 签名,并且新增 `themeLabelI18n` 字段
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- 修复 `vitest` 设置 `threads` 导致报错 `Module did not self-register...` 的问题
|
|
||||||
- 修复 `vue-router warning` 抛出 `can no longer be used directly inside...` 的警告问题
|
|
||||||
- 修复 `pre-commit` 错误的 `vue-tsc` 检查报错
|
|
||||||
- `signing logout` 方法现在会正确的清理 `menuTagOptions`
|
|
||||||
|
|
||||||
## 4.8.4
|
|
||||||
|
|
||||||
由于 `node canvas` 本身的特性(环境问题很多),故在 `v4.8.4` 版本予以移除 `RQRCode` 组件,使用 `vue3-next-qrcode` 替代。所有的使用方法保持一致。
|
|
||||||
|
|
||||||
## Feats
|
|
||||||
|
|
||||||
- 新增 `package.json` 的 `lint` 命令,用于自动修复 `eslint, prettier` 问题
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pnpm lint
|
|
||||||
```
|
|
||||||
|
|
||||||
- `useModal` 方法在 `preset = card` 并且设置了 `fullscreen` 时,现在会自动启用滚动条
|
|
||||||
- `pre-commit` 新增 `vue-tsc` 检查
|
|
||||||
|
|
||||||
## 4.8.3
|
## 4.8.3
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import { callWithAsyncErrorHandling } from '../../src/utils/basic'
|
|||||||
describe('callWithAsyncErrorHandling', () => {
|
describe('callWithAsyncErrorHandling', () => {
|
||||||
it('should call the function and return the result', () => {
|
it('should call the function and return the result', () => {
|
||||||
const fn = (x: number) => x
|
const fn = (x: number) => x
|
||||||
|
|
||||||
const callbackFn = () => {}
|
const callbackFn = () => {}
|
||||||
|
|
||||||
expect(callWithAsyncErrorHandling(fn, callbackFn, [1])).resolves.toBe(1)
|
expect(callWithAsyncErrorHandling(fn, callbackFn, [1])).resolves.toBe(1)
|
||||||
@ -15,7 +14,6 @@ describe('callWithAsyncErrorHandling', () => {
|
|||||||
const fn = () => {
|
const fn = () => {
|
||||||
throw new Error('test error')
|
throw new Error('test error')
|
||||||
}
|
}
|
||||||
|
|
||||||
const callbackFn = () => {
|
const callbackFn = () => {
|
||||||
callbackFnExecuted = 2
|
callbackFnExecuted = 2
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import { callWithErrorHandling } from '../../src/utils/basic'
|
|||||||
describe('callWithErrorHandling', () => {
|
describe('callWithErrorHandling', () => {
|
||||||
it('should call the function and return the result', () => {
|
it('should call the function and return the result', () => {
|
||||||
const fn = (x: number) => x
|
const fn = (x: number) => x
|
||||||
|
|
||||||
const callbackFn = () => {}
|
const callbackFn = () => {}
|
||||||
|
|
||||||
expect(callWithErrorHandling(fn, callbackFn, [1])).toBe(1)
|
expect(callWithErrorHandling(fn, callbackFn, [1])).toBe(1)
|
||||||
@ -15,7 +14,6 @@ describe('callWithErrorHandling', () => {
|
|||||||
const fn = () => {
|
const fn = () => {
|
||||||
throw new Error('test error')
|
throw new Error('test error')
|
||||||
}
|
}
|
||||||
|
|
||||||
const callbackFn = () => {
|
const callbackFn = () => {
|
||||||
callbackFnExecuted = 2
|
callbackFnExecuted = 2
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ describe('isValueType', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should return false for Function', () => {
|
it('should return false for Function', () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
||||||
expect(isValueType<Function>(/a/i, 'Function')).toBe(false)
|
expect(isValueType<Function>(/a/i, 'Function')).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -14,7 +14,6 @@ describe('uuid', () => {
|
|||||||
|
|
||||||
it('should return a string with length 36', () => {
|
it('should return a string with length 36', () => {
|
||||||
const uid = uuid(36)
|
const uid = uuid(36)
|
||||||
|
|
||||||
expect(uid.length).toBe(36)
|
expect(uid.length).toBe(36)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { RModal } from '../../src/components/base/RModal/index'
|
import { RModal } from '../../src/components/RModal/index'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
|
|
||||||
describe('RModal', () => {
|
describe('RModal', () => {
|
||||||
|
61
__test__/components/qr-code.spec.ts
Normal file
61
__test__/components/qr-code.spec.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { RQRCode } from '../../src/components/RQRCode/index'
|
||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
|
||||||
|
describe('RQRCode', () => {
|
||||||
|
it('should render a qr code', () => {
|
||||||
|
const wrapper = mount(RQRCode, {
|
||||||
|
props: {
|
||||||
|
text: 'hi',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('img').exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should execute the callback', () => {
|
||||||
|
let successValue: 1
|
||||||
|
let errorValue: -1
|
||||||
|
|
||||||
|
const _success = vitest.fn()
|
||||||
|
const _error = vitest.fn()
|
||||||
|
|
||||||
|
_success.mockReturnValue(1)
|
||||||
|
_error.mockReturnValue(-1)
|
||||||
|
|
||||||
|
mount(RQRCode, {
|
||||||
|
props: {
|
||||||
|
text: 'hi',
|
||||||
|
onSuccess: () => {
|
||||||
|
successValue = _success()
|
||||||
|
|
||||||
|
expect(successValue).toBe(1)
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
errorValue = _error()
|
||||||
|
|
||||||
|
expect(errorValue).toBe(-1)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should execute the onReload function', async () => {
|
||||||
|
let count = 0
|
||||||
|
|
||||||
|
const wrapper = mount(RQRCode, {
|
||||||
|
props: {
|
||||||
|
text: 'hi',
|
||||||
|
status: 'error',
|
||||||
|
onReload: () => {
|
||||||
|
count = 1
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const btn = wrapper.find('.n-button')
|
||||||
|
|
||||||
|
btn.trigger('click')
|
||||||
|
|
||||||
|
expect(count).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
@ -39,7 +39,6 @@ describe('useContextmenuCoordinate', () => {
|
|||||||
clientX: 100,
|
clientX: 100,
|
||||||
clientY: 200,
|
clientY: 200,
|
||||||
})
|
})
|
||||||
|
|
||||||
wrapperRef.element.dispatchEvent(event)
|
wrapperRef.element.dispatchEvent(event)
|
||||||
|
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
@ -17,8 +17,8 @@ describe('useDayjs', () => {
|
|||||||
}
|
}
|
||||||
const localSpy = vi.spyOn(m, 'locale')
|
const localSpy = vi.spyOn(m, 'locale')
|
||||||
|
|
||||||
m.locale('en-US')
|
m.locale('en')
|
||||||
m.locale('zh-CN')
|
m.locale('zh-cn')
|
||||||
|
|
||||||
expect(localSpy).toHaveBeenCalledTimes(2)
|
expect(localSpy).toHaveBeenCalledTimes(2)
|
||||||
})
|
})
|
||||||
|
@ -4,22 +4,23 @@ import { useTheme } from '../../src/hooks/template/useTheme'
|
|||||||
describe('useTheme', async () => {
|
describe('useTheme', async () => {
|
||||||
await setupMiniApp()
|
await setupMiniApp()
|
||||||
|
|
||||||
const { darkTheme, lightTheme, toggleTheme, getAppTheme } = useTheme()
|
const { changeDarkTheme, changeLightTheme, toggleTheme, getAppTheme } =
|
||||||
|
useTheme()
|
||||||
|
|
||||||
it('should change to dark theme', () => {
|
it('should change to dark theme', () => {
|
||||||
darkTheme()
|
changeDarkTheme()
|
||||||
|
|
||||||
expect(getAppTheme().theme).toBe(true)
|
expect(getAppTheme().theme).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should change to light theme', () => {
|
it('should change to light theme', () => {
|
||||||
lightTheme()
|
changeLightTheme()
|
||||||
|
|
||||||
expect(getAppTheme().theme).toBe(false)
|
expect(getAppTheme().theme).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should toggle theme', () => {
|
it('should toggle theme', () => {
|
||||||
lightTheme()
|
changeLightTheme()
|
||||||
|
|
||||||
expect(getAppTheme().theme).toBe(false)
|
expect(getAppTheme().theme).toBe(false)
|
||||||
|
|
||||||
@ -29,18 +30,18 @@ describe('useTheme', async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should return current theme', () => {
|
it('should return current theme', () => {
|
||||||
darkTheme()
|
changeDarkTheme()
|
||||||
|
|
||||||
const { theme: _darkTheme, themeLabel: _darkThemeLabel } = getAppTheme()
|
const { theme: darkTheme, themeLabel: darkThemeLabel } = getAppTheme()
|
||||||
|
|
||||||
expect(_darkTheme).toBe(true)
|
expect(darkTheme).toBe(true)
|
||||||
expect(_darkThemeLabel).toBe('Dark')
|
expect(darkThemeLabel).toBe('暗色')
|
||||||
|
|
||||||
lightTheme()
|
changeLightTheme()
|
||||||
|
|
||||||
const { theme: __lightTheme, themeLabel: __lightThemeLabel } = getAppTheme()
|
const { theme: lightTheme, themeLabel: lightThemeLabel } = getAppTheme()
|
||||||
|
|
||||||
expect(__lightTheme).toBe(false)
|
expect(lightTheme).toBe(false)
|
||||||
expect(__lightThemeLabel).toBe('Light')
|
expect(lightThemeLabel).toBe('明亮')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -13,7 +13,6 @@ import { mount } from '@vue/test-utils'
|
|||||||
*
|
*
|
||||||
* const text = wrapper.find('div').text() // hello
|
* const text = wrapper.find('div').text() // hello
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
||||||
const createRefElement = (slots?: Record<string, Function>) => {
|
const createRefElement = (slots?: Record<string, Function>) => {
|
||||||
const wrapper = mount(
|
const wrapper = mount(
|
||||||
defineComponent({
|
defineComponent({
|
||||||
|
@ -3,7 +3,6 @@ import { call } from '../../src/utils/vue/call'
|
|||||||
describe('call', () => {
|
describe('call', () => {
|
||||||
it('should be executed once', () => {
|
it('should be executed once', () => {
|
||||||
const fn = vi.fn()
|
const fn = vi.fn()
|
||||||
|
|
||||||
call(() => fn())
|
call(() => fn())
|
||||||
|
|
||||||
expect(fn).toHaveBeenCalledTimes(1)
|
expect(fn).toHaveBeenCalledTimes(1)
|
||||||
@ -11,7 +10,6 @@ describe('call', () => {
|
|||||||
|
|
||||||
it('should be executed with an argument', () => {
|
it('should be executed with an argument', () => {
|
||||||
const fn = vi.fn()
|
const fn = vi.fn()
|
||||||
|
|
||||||
call((a: number) => fn(a), 1)
|
call((a: number) => fn(a), 1)
|
||||||
|
|
||||||
expect(fn).toHaveBeenCalledWith(1)
|
expect(fn).toHaveBeenCalledWith(1)
|
||||||
|
@ -4,7 +4,6 @@ import createRefElement from '../utils/createRefElement'
|
|||||||
describe('renderNode', () => {
|
describe('renderNode', () => {
|
||||||
it('should render string', () => {
|
it('should render string', () => {
|
||||||
const wrapper = createRefElement({
|
const wrapper = createRefElement({
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
||||||
default: renderNode('hello world') as Function,
|
default: renderNode('hello world') as Function,
|
||||||
})
|
})
|
||||||
const text = wrapper.text()
|
const text = wrapper.text()
|
||||||
|
@ -1,365 +0,0 @@
|
|||||||
import vue from 'eslint-plugin-vue'
|
|
||||||
import typescriptEslint from '@typescript-eslint/eslint-plugin'
|
|
||||||
import prettier from 'eslint-plugin-prettier'
|
|
||||||
import globals from 'globals'
|
|
||||||
import parser from 'vue-eslint-parser'
|
|
||||||
import path from 'node:path'
|
|
||||||
import { fileURLToPath } from 'node:url'
|
|
||||||
import js from '@eslint/js'
|
|
||||||
import { FlatCompat } from '@eslint/eslintrc'
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url)
|
|
||||||
const __dirname = path.dirname(__filename)
|
|
||||||
const compat = new FlatCompat({
|
|
||||||
baseDirectory: __dirname,
|
|
||||||
recommendedConfig: js.configs.recommended,
|
|
||||||
allConfig: js.configs.all,
|
|
||||||
})
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
'**/node_modules/',
|
|
||||||
'**/dist/',
|
|
||||||
'dist/*',
|
|
||||||
'node_modules/*',
|
|
||||||
'**/auto-imports.d.ts',
|
|
||||||
'**/components.d.ts',
|
|
||||||
'**/.gitignore',
|
|
||||||
'**/.vscode',
|
|
||||||
'**/public',
|
|
||||||
'**/yarn.*',
|
|
||||||
'**/vite-env.*',
|
|
||||||
'**/.prettierrc.*',
|
|
||||||
'**/visualizer.*',
|
|
||||||
'**/visualizer.html',
|
|
||||||
'**/.env.*',
|
|
||||||
'src/locales/lang',
|
|
||||||
'**/.depcheckrc',
|
|
||||||
'src/app-config/echart-themes/**/*.json',
|
|
||||||
'**/*.md',
|
|
||||||
'src/icons/*.svg',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['**/*.js', '**/*.ts', '**/*.jsx', '**/*.tsx', '**/*.vue'],
|
|
||||||
},
|
|
||||||
...compat.extends(
|
|
||||||
'eslint-config-prettier',
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'plugin:vue/vue3-recommended',
|
|
||||||
'plugin:vue/vue3-essential',
|
|
||||||
'plugin:prettier/recommended',
|
|
||||||
'prettier',
|
|
||||||
'./unplugin/.eslintrc-auto-import.json',
|
|
||||||
),
|
|
||||||
{
|
|
||||||
plugins: {
|
|
||||||
vue,
|
|
||||||
'@typescript-eslint': typescriptEslint,
|
|
||||||
prettier,
|
|
||||||
},
|
|
||||||
languageOptions: {
|
|
||||||
globals: {
|
|
||||||
...globals.browser,
|
|
||||||
...globals.node,
|
|
||||||
defineProps: 'readonly',
|
|
||||||
defineEmits: 'readonly',
|
|
||||||
defineExpose: 'readonly',
|
|
||||||
withDefaults: 'readonly',
|
|
||||||
defineOptions: 'readonly',
|
|
||||||
defineModel: 'readonly',
|
|
||||||
},
|
|
||||||
parser: parser,
|
|
||||||
ecmaVersion: 2020,
|
|
||||||
sourceType: 'module',
|
|
||||||
parserOptions: {
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: true,
|
|
||||||
tsx: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'no-undefined': ['error'],
|
|
||||||
'linebreak-style': ['error', 'unix'],
|
|
||||||
'@typescript-eslint/no-explicit-any': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
ignoreRestArgs: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'prettier/prettier': 'error',
|
|
||||||
'no-unused-vars': 'off',
|
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
|
||||||
'@typescript-eslint/ban-types': 'off',
|
|
||||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
||||||
'@typescript-eslint/no-var-requires': 'off',
|
|
||||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
||||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
|
|
||||||
'@typescript-eslint/consistent-type-imports': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
disallowTypeAnnotations: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@typescript-eslint/no-empty-interface': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allowSingleExtends: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'accessor-pairs': 2,
|
|
||||||
'constructor-super': 0,
|
|
||||||
'default-case': 2,
|
|
||||||
eqeqeq: [2, 'allow-null'],
|
|
||||||
'no-alert': 0,
|
|
||||||
'no-array-constructor': 2,
|
|
||||||
'no-bitwise': 0,
|
|
||||||
'no-caller': 1,
|
|
||||||
'no-catch-shadow': 2,
|
|
||||||
'no-class-assign': 2,
|
|
||||||
'no-cond-assign': 2,
|
|
||||||
'no-const-assign': 2,
|
|
||||||
'no-constant-condition': 2,
|
|
||||||
'no-dupe-keys': 2,
|
|
||||||
'no-dupe-args': 2,
|
|
||||||
'no-duplicate-case': 2,
|
|
||||||
'no-eval': 1,
|
|
||||||
'no-ex-assign': 2,
|
|
||||||
'no-extend-native': 2,
|
|
||||||
'no-extra-bind': 2,
|
|
||||||
'no-extra-boolean-cast': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
enforceForLogicalOperands: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-extra-parens': 0,
|
|
||||||
semi: [
|
|
||||||
'error',
|
|
||||||
'never',
|
|
||||||
{
|
|
||||||
beforeStatementContinuationChars: 'always',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-fallthrough': 1,
|
|
||||||
'no-func-assign': 2,
|
|
||||||
'no-implicit-coercion': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allow: ['!!', '~'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-implied-eval': 2,
|
|
||||||
'no-invalid-regexp': 2,
|
|
||||||
'no-invalid-this': 2,
|
|
||||||
'no-irregular-whitespace': 2,
|
|
||||||
'no-iterator': 2,
|
|
||||||
'no-label-var': 2,
|
|
||||||
'no-labels': 2,
|
|
||||||
'no-lone-blocks': 2,
|
|
||||||
'no-multi-spaces': 1,
|
|
||||||
'no-multiple-empty-lines': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
max: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-new-func': 2,
|
|
||||||
'no-new-object': 2,
|
|
||||||
'no-new-require': 2,
|
|
||||||
'no-sparse-arrays': 2,
|
|
||||||
'no-trailing-spaces': 1,
|
|
||||||
'no-unreachable': 2,
|
|
||||||
'no-unused-expressions': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allowShortCircuit: true,
|
|
||||||
allowTernary: true,
|
|
||||||
allowTaggedTemplates: true,
|
|
||||||
enforceForJSX: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-useless-call': 2,
|
|
||||||
'no-var': 'error',
|
|
||||||
'no-with': 2,
|
|
||||||
'use-isnan': 2,
|
|
||||||
'no-multi-assign': 2,
|
|
||||||
'prefer-arrow-callback': 2,
|
|
||||||
curly: ['error', 'all'],
|
|
||||||
'vue/multi-word-component-names': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
ignores: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'vue/no-use-v-if-with-v-for': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allowUsingIterationVar: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'vue/require-v-for-key': ['error'],
|
|
||||||
'vue/require-valid-default-prop': ['error'],
|
|
||||||
'vue/component-definition-name-casing': ['error', 'PascalCase'],
|
|
||||||
'vue/html-closing-bracket-newline': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
singleline: 'never',
|
|
||||||
multiline: 'always',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'vue/v-on-event-hyphenation': ['error', 'never'],
|
|
||||||
'vue/component-tags-order': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
order: ['template', 'script', 'style'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'vue/no-v-html': ['error'],
|
|
||||||
'vue/no-v-text': ['error'],
|
|
||||||
'vue/component-api-style': [
|
|
||||||
'error',
|
|
||||||
['script-setup', 'composition', 'composition-vue2'],
|
|
||||||
],
|
|
||||||
'vue/component-name-in-template-casing': [
|
|
||||||
'error',
|
|
||||||
'PascalCase',
|
|
||||||
{
|
|
||||||
registeredComponentsOnly: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'vue/no-unused-refs': ['error'],
|
|
||||||
'vue/prop-name-casing': ['error', 'camelCase'],
|
|
||||||
'vue/component-options-name-casing': ['error', 'PascalCase'],
|
|
||||||
'vue/attribute-hyphenation': [
|
|
||||||
'error',
|
|
||||||
'never',
|
|
||||||
{
|
|
||||||
ignore: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'vue/no-restricted-static-attribute': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
key: 'key',
|
|
||||||
message: 'Disallow using key as a custom attribute',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-restricted-syntax': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
selector: "CallExpression[callee.property.name='deprecated']",
|
|
||||||
message: 'Using deprecated API is not allowed.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'padding-line-between-statements': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
blankLine: 'always',
|
|
||||||
prev: ['import'],
|
|
||||||
next: '*',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'any',
|
|
||||||
prev: 'import',
|
|
||||||
next: 'import',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'always',
|
|
||||||
prev: '*',
|
|
||||||
next: 'export',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'any',
|
|
||||||
prev: 'export',
|
|
||||||
next: 'export',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'always',
|
|
||||||
prev: ['const', 'let', 'var'],
|
|
||||||
next: '*',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'any',
|
|
||||||
prev: ['const', 'let', 'var'],
|
|
||||||
next: ['const', 'let', 'var'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'always',
|
|
||||||
prev: 'directive',
|
|
||||||
next: '*',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'any',
|
|
||||||
prev: 'directive',
|
|
||||||
next: 'directive',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'always',
|
|
||||||
prev: '*',
|
|
||||||
next: [
|
|
||||||
'if',
|
|
||||||
'class',
|
|
||||||
'for',
|
|
||||||
'do',
|
|
||||||
'while',
|
|
||||||
'switch',
|
|
||||||
'try',
|
|
||||||
'with',
|
|
||||||
'function',
|
|
||||||
'block',
|
|
||||||
'block-like',
|
|
||||||
'break',
|
|
||||||
'case',
|
|
||||||
'continue',
|
|
||||||
'return',
|
|
||||||
'throw',
|
|
||||||
'debugger',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blankLine: 'always',
|
|
||||||
prev: [
|
|
||||||
'if',
|
|
||||||
'class',
|
|
||||||
'for',
|
|
||||||
'do',
|
|
||||||
'while',
|
|
||||||
'switch',
|
|
||||||
'try',
|
|
||||||
'with',
|
|
||||||
'function',
|
|
||||||
'block',
|
|
||||||
'block-like',
|
|
||||||
'break',
|
|
||||||
'case',
|
|
||||||
'continue',
|
|
||||||
'return',
|
|
||||||
'throw',
|
|
||||||
'debugger',
|
|
||||||
],
|
|
||||||
next: '*',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@typescript-eslint/no-unused-expressions': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allowShortCircuit: true,
|
|
||||||
allowTernary: true,
|
|
||||||
allowTaggedTemplates: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@typescript-eslint/no-empty-object-type': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allowInterfaces: 'with-single-extends',
|
|
||||||
allowObjectTypes: 'always',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
41
index.html
41
index.html
@ -1,4 +1,4 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
@ -15,27 +15,6 @@
|
|||||||
--preloading-title-color: <%= preloadingConfig.titleColor %>;
|
--preloading-title-color: <%= preloadingConfig.titleColor %>;
|
||||||
--ray-theme-primary-fade-color: <%= appPrimaryColor.primaryFadeColor %>;
|
--ray-theme-primary-fade-color: <%= appPrimaryColor.primaryFadeColor %>;
|
||||||
--ray-theme-primary-color: <%= appPrimaryColor.primaryColor %>;
|
--ray-theme-primary-color: <%= appPrimaryColor.primaryColor %>;
|
||||||
--global-loading-bg-color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
#pre-loading-animation {
|
|
||||||
background-color: var(--global-loading-bg-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
#pre-loading-animation {
|
|
||||||
background-color: var(--global-loading-bg-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html.dark #pre-loading-animation {
|
|
||||||
background-color: var(--global-loading-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
html.light #pre-loading-animation {
|
|
||||||
background-color: var(--global-loading-bg-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pre-loading-animation {
|
#pre-loading-animation {
|
||||||
@ -44,9 +23,13 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
background-color: #ffffff;
|
||||||
color: var(--preloading-title-color);
|
color: var(--preloading-title-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: var(--global-loading-bg-color);
|
}
|
||||||
|
|
||||||
|
.ray-template--dark #pre-loading-animation {
|
||||||
|
background-color: #2a3146;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pre-loading-animation .pre-loading-animation__wrapper {
|
#pre-loading-animation .pre-loading-animation__wrapper {
|
||||||
@ -112,18 +95,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
|
||||||
;(function () {
|
|
||||||
const html = document.documentElement
|
|
||||||
const store = window.localStorage.getItem('piniaSettingStore')
|
|
||||||
const { _appTheme = false } = store ? JSON.parse(store) : {}
|
|
||||||
const loadingBgColor = _appTheme ? '#1c1e23' : '#ffffff'
|
|
||||||
|
|
||||||
html.classList.add(_appTheme ? 'dark' : 'light')
|
|
||||||
html.style.setProperty('--global-loading-bg-color', loadingBgColor)
|
|
||||||
html.style.setProperty('background-color', loadingBgColor)
|
|
||||||
})()
|
|
||||||
</script>
|
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<div id="pre-loading-animation">
|
<div id="pre-loading-animation">
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-08-11
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import Mock from 'mockjs'
|
import Mock from 'mockjs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-08-11
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
export function array(length: number) {
|
export function array(length: number) {
|
||||||
|
138
package.json
138
package.json
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "ray-template",
|
"name": "ray-template",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "5.2.2",
|
"version": "4.8.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
"node": "^18.0.0 || >=20.0.0",
|
||||||
"pnpm": ">=9.0.0"
|
"pnpm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@ -15,8 +15,7 @@
|
|||||||
"report": "vite build --mode report",
|
"report": "vite build --mode report",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:ui": "vitest --ui",
|
"test:ui": "vitest --ui"
|
||||||
"lint": "vue-tsc --noEmit && eslint --fix && prettier --write \"**/*.{ts,tsx,json,.vue}\""
|
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
@ -25,89 +24,88 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{ts,tsx,json}": [
|
"*.{js,json}": [
|
||||||
"prettier --write"
|
"prettier --write"
|
||||||
],
|
],
|
||||||
"*.{ts,tsx,vue}": [
|
"*.ts?(x)": [
|
||||||
"eslint --fix"
|
"eslint src",
|
||||||
|
"prettier --parser=typescript --write"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@logicflow/core": "2.0.10",
|
"@vueuse/core": "^10.9.0",
|
||||||
"@logicflow/extension": "2.0.14",
|
"awesome-qr": "2.1.5-rc.0",
|
||||||
"@vueuse/core": "^13.1.0",
|
"axios": "^1.6.7",
|
||||||
"axios": "^1.9.0",
|
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"crypto-js": "4.2.0",
|
|
||||||
"currency.js": "^2.0.4",
|
"currency.js": "^2.0.4",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.10",
|
||||||
"echarts": "^5.6.0",
|
"dom-to-image": "2.6.0",
|
||||||
"html-to-image": "1.11.13",
|
"echarts": "^5.5.0",
|
||||||
"interactjs": "1.10.27",
|
"interactjs": "1.10.26",
|
||||||
"jsbarcode": "3.11.6",
|
"jsbarcode": "3.11.6",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mockjs": "1.1.0",
|
"mockjs": "1.1.0",
|
||||||
"naive-ui": "^2.42.0",
|
"naive-ui": "^2.38.2",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^4.4.1",
|
"pinia-plugin-persistedstate": "^3.2.0",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"vue": "^3.5.17",
|
"vue": "^3.4.26",
|
||||||
"vue-demi": "0.14.10",
|
"vue-demi": "0.14.6",
|
||||||
"vue-hooks-plus": "2.4.0",
|
"vue-hooks-plus": "1.9.0",
|
||||||
"vue-i18n": "^9.13.1",
|
"vue-i18n": "^9.13.1",
|
||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.3.0"
|
||||||
"vue3-next-qrcode": "3.0.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "19.7.1",
|
"@commitlint/cli": "^17.7.1",
|
||||||
"@commitlint/config-conventional": "19.7.1",
|
"@commitlint/config-conventional": "^17.7.0",
|
||||||
"@eslint/js": "9.28.0",
|
"@interactjs/types": "1.10.21",
|
||||||
"@interactjs/types": "1.10.27",
|
"@intlify/unplugin-vue-i18n": "^2.0.0",
|
||||||
"@intlify/unplugin-vue-i18n": "4.0.0",
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/crypto-js": "4.2.2",
|
"@types/dom-to-image": "2.6.7",
|
||||||
"@types/jsbarcode": "3.11.4",
|
"@types/jsbarcode": "3.11.4",
|
||||||
"@types/lodash-es": "4.17.12",
|
"@types/lodash-es": "^4.17.11",
|
||||||
"@types/mockjs": "1.0.10",
|
"@types/mockjs": "1.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "8.24.0",
|
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
||||||
"@typescript-eslint/parser": "8.24.0",
|
"@typescript-eslint/parser": "^6.5.0",
|
||||||
"@vitejs/plugin-vue": "5.2.3",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"@vitejs/plugin-vue-jsx": "4.1.2",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"@vitest/ui": "2.1.8",
|
"@vitest/ui": "1.4.0",
|
||||||
"@vue/eslint-config-prettier": "10.1.0",
|
"@vue/eslint-config-prettier": "^9.0.0",
|
||||||
"@vue/eslint-config-typescript": "14.2.0",
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
"@vue/test-utils": "2.4.6",
|
"@vue/test-utils": "2.4.3",
|
||||||
"autoprefixer": "10.4.21",
|
"autoprefixer": "^10.4.15",
|
||||||
"depcheck": "1.4.7",
|
"depcheck": "^1.4.5",
|
||||||
"eslint": "9.20.1",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "10.1.2",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "5.2.6",
|
"eslint-config-standard-with-typescript": "^43.0.0",
|
||||||
"eslint-plugin-vue": "9.32.0",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"globals": "16.0.0",
|
"eslint-plugin-promise": "^6.1.1",
|
||||||
"happy-dom": "17.1.0",
|
"eslint-plugin-vue": "^9.25.0",
|
||||||
|
"happy-dom": "14.3.1",
|
||||||
"husky": "8.0.3",
|
"husky": "8.0.3",
|
||||||
"lint-staged": "15.4.3",
|
"lint-staged": "^15.1.0",
|
||||||
"postcss": "8.5.4",
|
"postcss": "^8.4.31",
|
||||||
"postcss-px-to-viewport-8-with-include": "1.2.2",
|
"postcss-px-to-viewport-8-plugin": "1.2.3",
|
||||||
"prettier": "3.5.3",
|
"prettier": "^3.2.5",
|
||||||
"rollup-plugin-gzip": "4.0.1",
|
"sass": "1.71.1",
|
||||||
"sass": "1.86.3",
|
"svg-sprite-loader": "^6.0.11",
|
||||||
"svg-sprite-loader": "6.0.11",
|
"typescript": "^5.2.2",
|
||||||
"typescript": "5.8.3",
|
"unplugin-auto-import": "^0.17.5",
|
||||||
"unocss": "66.3.3",
|
"unplugin-vue-components": "^0.26.0",
|
||||||
"unplugin-auto-import": "19.1.2",
|
"vite": "^5.2.11",
|
||||||
"unplugin-vue-components": "0.28.0",
|
"vite-bundle-analyzer": "0.9.4",
|
||||||
"vite": "6.3.5",
|
|
||||||
"vite-bundle-analyzer": "0.16.0",
|
|
||||||
"vite-plugin-cdn2": "1.1.0",
|
"vite-plugin-cdn2": "1.1.0",
|
||||||
"vite-plugin-ejs": "1.7.0",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
|
"vite-plugin-ejs": "^1.7.0",
|
||||||
"vite-plugin-eslint": "1.8.1",
|
"vite-plugin-eslint": "1.8.1",
|
||||||
"vite-plugin-inspect": "0.8.4",
|
"vite-plugin-imp": "^2.4.0",
|
||||||
"vite-plugin-mock-dev-server": "1.8.3",
|
"vite-plugin-inspect": "^0.8.3",
|
||||||
"vite-plugin-svg-icons": "2.0.1",
|
"vite-plugin-mock-dev-server": "1.4.7",
|
||||||
"vite-svg-loader": "5.1.0",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vitest": "2.1.8",
|
"vite-svg-loader": "^4.0.0",
|
||||||
"vue-eslint-parser": "9.4.3",
|
"vite-tsconfig-paths": "4.3.2",
|
||||||
"vue-tsc": "2.2.8"
|
"vitest": "1.5.2",
|
||||||
|
"vue-tsc": "^2.0.11"
|
||||||
},
|
},
|
||||||
"description": "<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->",
|
"description": "<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
|
14024
pnpm-lock.yaml
generated
14024
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -8,32 +8,31 @@ module.exports = {
|
|||||||
'ff > 31',
|
'ff > 31',
|
||||||
'ie >= 8',
|
'ie >= 8',
|
||||||
'last 10 versions',
|
'last 10 versions',
|
||||||
'not dead',
|
|
||||||
],
|
],
|
||||||
grid: true,
|
grid: true,
|
||||||
},
|
},
|
||||||
// 为了适配 postcss8.x 版本的转换库
|
// 为了适配 postcss8.x 版本的转换库
|
||||||
'postcss-px-to-viewport-8-with-include': {
|
'postcss-px-to-viewport-8-plugin': {
|
||||||
// 横屏时使用的视口宽度
|
inlinePxToViewport: true,
|
||||||
landscapeWidth: 1920,
|
/** 视窗的宽度(设计稿的宽度) */
|
||||||
// 视窗的宽度(设计稿的宽度)
|
|
||||||
viewportWidth: 1920,
|
viewportWidth: 1920,
|
||||||
// 指定 px 转换为视窗单位值的小数位数
|
/** 视窗的高度(设计稿高度, 一般无需指定) */
|
||||||
|
viewportHeight: 1080,
|
||||||
|
/** 指定 px 转换为视窗单位值的小数位数 */
|
||||||
unitPrecision: 3,
|
unitPrecision: 3,
|
||||||
// 指定需要转换成的视窗单位
|
/** 指定需要转换成的视窗单位 */
|
||||||
viewportUnit: 'vw',
|
viewportUnit: 'rem',
|
||||||
// 制定字体转换单位
|
/** 制定字体转换单位 */
|
||||||
fontViewportUnit: 'vw',
|
fontViewportUnit: 'rem',
|
||||||
// 指定不转换为视窗单位的类
|
/** 指定不转换为视窗单位的类 */
|
||||||
selectorBlackList: ['.ignore'],
|
selectorBlackList: ['.ignore'],
|
||||||
// 小于或等于 1px 不转换为视窗单位
|
/** 小于或等于 1px 不转换为视窗单位 */
|
||||||
minPixelValue: 1,
|
minPixelValue: 1,
|
||||||
// 允许在媒体查询中转换 px
|
/** 允许在媒体查询中转换 px */
|
||||||
mediaQuery: false,
|
mediaQuery: false,
|
||||||
// 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
|
// exclude: /(\/|\\)(node_modules)(\/|\\)/, // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
|
||||||
exclude: /node_modules/,
|
include: [/^src[/\\].*\.(vue|tsx|jsx|ts(?!d))$/],
|
||||||
// 指定一个空的文件夹,避免影响到无需转换的文件
|
preserve: true,
|
||||||
include: [],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-03-31
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 该方法演示如何封装一个通用请求方法
|
* 该方法演示如何封装一个通用请求方法
|
||||||
@ -28,7 +39,7 @@ interface JSONPlaceholder {
|
|||||||
*
|
*
|
||||||
* @returns 测试
|
* @returns 测试
|
||||||
*
|
*
|
||||||
* @method get
|
* @medthod get
|
||||||
*/
|
*/
|
||||||
export const getWeather = (city: string) => {
|
export const getWeather = (city: string) => {
|
||||||
return request<AxiosTestResponse>({
|
return request<AxiosTestResponse>({
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-05-31
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 系统管理员头像与名称
|
* 系统管理员头像与名称
|
||||||
@ -6,13 +17,17 @@
|
|||||||
* 默认读取本地 session catch 缓存
|
* 默认读取本地 session catch 缓存
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
import { NAvatar, NButton, NFlex } from 'naive-ui'
|
import { NAvatar, NButton, NFlex } from 'naive-ui'
|
||||||
|
|
||||||
import { avatarProps } from 'naive-ui'
|
import { avatarProps } from 'naive-ui'
|
||||||
import { useSigningGetters } from '@/store'
|
import { APP_CATCH_KEY } from '@/app-config'
|
||||||
|
import { getStorage } from '@/utils'
|
||||||
|
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import type { AvatarProps, FlexProps } from 'naive-ui'
|
import type { AvatarProps, FlexProps } from 'naive-ui'
|
||||||
|
import type { SigningCallback } from '@/store/modules/signing/types'
|
||||||
|
|
||||||
const AppAvatar = defineComponent({
|
const AppAvatar = defineComponent({
|
||||||
name: 'AppAvatar',
|
name: 'AppAvatar',
|
||||||
@ -30,39 +45,28 @@ const AppAvatar = defineComponent({
|
|||||||
type: [String, Number] as PropType<AvatarProps['size']>,
|
type: [String, Number] as PropType<AvatarProps['size']>,
|
||||||
default: 'medium',
|
default: 'medium',
|
||||||
},
|
},
|
||||||
vertical: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props) {
|
||||||
const { getSigningCallback } = useSigningGetters()
|
const signing = getStorage<SigningCallback>(APP_CATCH_KEY.signing)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getSigningCallback,
|
signing,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const { getSigningCallback, avatarSize, spaceSize, $props, vertical } = this
|
const { signing, avatarSize, spaceSize, $props } = this
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NButton quaternary strong focusable={false}>
|
<NButton quaternary strong>
|
||||||
<NFlex align="center" size={spaceSize} vertical={vertical}>
|
<NFlex align="center" size={spaceSize}>
|
||||||
<NAvatar
|
<NAvatar
|
||||||
{...($props as AvatarProps)}
|
{...($props as AvatarProps)}
|
||||||
src={getSigningCallback?.avatar}
|
src={signing?.avatar}
|
||||||
objectFit="cover"
|
objectFit="cover"
|
||||||
round
|
round
|
||||||
size={avatarSize}
|
size={avatarSize}
|
||||||
>
|
/>
|
||||||
{{
|
{signing?.name}
|
||||||
default: () =>
|
|
||||||
getSigningCallback.avatar
|
|
||||||
? null
|
|
||||||
: getSigningCallback?.name?.[0],
|
|
||||||
}}
|
|
||||||
</NAvatar>
|
|
||||||
{getSigningCallback?.name}
|
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NButton>
|
</NButton>
|
||||||
)
|
)
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-01-18
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 全屏加载效果
|
* 全屏加载效果
|
||||||
@ -20,8 +31,6 @@ import { NSpin } from 'naive-ui'
|
|||||||
import { spinProps } from 'naive-ui'
|
import { spinProps } from 'naive-ui'
|
||||||
import { getVariableToRefs } from '@/global-variable'
|
import { getVariableToRefs } from '@/global-variable'
|
||||||
|
|
||||||
import type { SpinProps } from 'naive-ui'
|
|
||||||
|
|
||||||
const GlobalSpin = defineComponent({
|
const GlobalSpin = defineComponent({
|
||||||
name: 'GlobalSpin',
|
name: 'GlobalSpin',
|
||||||
props: {
|
props: {
|
||||||
@ -41,10 +50,9 @@ const GlobalSpin = defineComponent({
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<NSpin
|
<NSpin
|
||||||
{...(this.$props as SpinProps)}
|
{...this.$props}
|
||||||
show={this.spinValue}
|
show={this.spinValue}
|
||||||
themeOverrides={this.overrides}
|
themeOverrides={this.overrides}
|
||||||
style="height: var(--html-height)"
|
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
...this.$slots,
|
...this.$slots,
|
||||||
|
@ -1,10 +1,28 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-20
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 统一管理是否处于锁屏状态
|
||||||
|
*
|
||||||
|
* 可以根据后台接口进行替换该变量, 只要是一个响应式的变量值即可
|
||||||
|
*/
|
||||||
|
|
||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage } from '@vueuse/core'
|
||||||
import { APP_CATCH_KEY } from '@/app-config'
|
import { APP_CATCH_KEY } from '@/app-config'
|
||||||
|
|
||||||
const appLockScreen = useStorage(
|
const appLockScreen = useStorage(
|
||||||
APP_CATCH_KEY.isAppLockScreen,
|
APP_CATCH_KEY.isAppLockScreen,
|
||||||
false,
|
false,
|
||||||
window.localStorage,
|
sessionStorage,
|
||||||
{
|
{
|
||||||
mergeDefaults: true,
|
mergeDefaults: true,
|
||||||
},
|
},
|
||||||
|
@ -1,22 +1,29 @@
|
|||||||
import { NInput, NFormItem, NButton } from 'naive-ui'
|
/**
|
||||||
import AppAvatar from '@/app-components/app/AppAvatar'
|
*
|
||||||
import { RForm } from '@/components'
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-20
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 锁屏界面 */
|
||||||
|
|
||||||
|
import { NInput, NForm, NFormItem, NButton } from 'naive-ui'
|
||||||
|
|
||||||
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
|
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
|
||||||
import { rules, useCondition } from '@/app-components/app/AppLockScreen/shared'
|
import { rules, useCondition } from '@/app-components/app/AppLockScreen/shared'
|
||||||
import { useSettingActions } from '@/store'
|
import { useSettingGetters, useSettingActions } from '@/store'
|
||||||
import { useTemplateRef } from 'vue'
|
|
||||||
import { useForm } from '@/components'
|
|
||||||
import { APP_CATCH_KEY } from '@/app-config'
|
|
||||||
import { setStorage, encrypt } from '@/utils'
|
|
||||||
|
|
||||||
import type { InputInst } from 'naive-ui'
|
import type { FormInst, InputInst } from 'naive-ui'
|
||||||
|
|
||||||
const LockScreen = defineComponent({
|
const LockScreen = defineComponent({
|
||||||
name: 'LockScreen',
|
name: 'LockScreen',
|
||||||
setup() {
|
setup() {
|
||||||
const [register, { validate }] = useForm()
|
const formInstRef = ref<FormInst | null>(null)
|
||||||
const inputInstRef = useTemplateRef<InputInst | null>('inputInstRef')
|
const inputInstRef = ref<InputInst | null>(null)
|
||||||
|
|
||||||
const { setLockAppScreen } = useAppLockScreen()
|
const { setLockAppScreen } = useAppLockScreen()
|
||||||
const { updateSettingState } = useSettingActions()
|
const { updateSettingState } = useSettingActions()
|
||||||
@ -25,17 +32,15 @@ const LockScreen = defineComponent({
|
|||||||
lockCondition: useCondition(),
|
lockCondition: useCondition(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 锁屏 */
|
||||||
const lockScreen = () => {
|
const lockScreen = () => {
|
||||||
validate().then(() => {
|
formInstRef.value?.validate((error) => {
|
||||||
setLockAppScreen(true)
|
if (!error) {
|
||||||
updateSettingState('lockScreenSwitch', false)
|
setLockAppScreen(true)
|
||||||
setStorage(
|
updateSettingState('lockScreenSwitch', true)
|
||||||
APP_CATCH_KEY.appLockScreenPasswordKey,
|
|
||||||
encrypt(state.lockCondition.lockPassword),
|
|
||||||
'localStorage',
|
|
||||||
)
|
|
||||||
|
|
||||||
state.lockCondition = useCondition()
|
state.lockCondition = useCondition()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,51 +53,40 @@ const LockScreen = defineComponent({
|
|||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
lockScreen,
|
lockScreen,
|
||||||
register,
|
formInstRef,
|
||||||
inputInstRef,
|
inputInstRef,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const { register } = this
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="app-lock-screen__content">
|
<div class="app-lock-screen__input">
|
||||||
<div class="app-lock-screen__input">
|
<NForm
|
||||||
<AppAvatar
|
ref="formInstRef"
|
||||||
avatarSize={52}
|
model={this.lockCondition}
|
||||||
style="pointer-events: none;margin: 24px 0;"
|
rules={rules}
|
||||||
vertical
|
labelPlacement="left"
|
||||||
/>
|
>
|
||||||
<RForm
|
<NFormItem path="lockPassword">
|
||||||
ref="formInstRef"
|
<NInput
|
||||||
model={this.lockCondition}
|
ref="inputInstRef"
|
||||||
rules={rules}
|
v-model:value={this.lockCondition.lockPassword}
|
||||||
labelPlacement="left"
|
type="password"
|
||||||
onRegister={register}
|
placeholder="请输入锁屏密码"
|
||||||
>
|
clearable
|
||||||
<NFormItem path="lockPassword">
|
showPasswordOn="click"
|
||||||
<NInput
|
minlength={6}
|
||||||
ref="inputInstRef"
|
maxlength={12}
|
||||||
v-model:value={this.lockCondition.lockPassword}
|
onKeydown={(e: KeyboardEvent) => {
|
||||||
type="password"
|
if (e.code === 'Enter') {
|
||||||
placeholder="请输入锁屏密码"
|
this.lockScreen()
|
||||||
clearable
|
}
|
||||||
showPasswordOn="click"
|
}}
|
||||||
minlength={6}
|
/>
|
||||||
maxlength={12}
|
</NFormItem>
|
||||||
onKeydown={(e: KeyboardEvent) => {
|
<NButton type="primary" onClick={this.lockScreen.bind(this)}>
|
||||||
if (e.code === 'Enter') {
|
锁屏
|
||||||
this.lockScreen()
|
</NButton>
|
||||||
}
|
</NForm>
|
||||||
}}
|
|
||||||
autofocus
|
|
||||||
/>
|
|
||||||
</NFormItem>
|
|
||||||
<NButton type="primary" onClick={this.lockScreen.bind(this)}>
|
|
||||||
锁屏
|
|
||||||
</NButton>
|
|
||||||
</RForm>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
import '../../index.scss'
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-20
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import { NInput, NFormItem, NButton, NFlex } from 'naive-ui'
|
/** 解锁界面 */
|
||||||
|
|
||||||
|
import { NInput, NForm, NFormItem, NButton, NFlex } from 'naive-ui'
|
||||||
import AppAvatar from '@/app-components/app/AppAvatar'
|
import AppAvatar from '@/app-components/app/AppAvatar'
|
||||||
import { RForm } from '@/components'
|
|
||||||
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useSigningActions, useSettingActions } from '@/store'
|
import { useSigningActions, useSettingActions } from '@/store'
|
||||||
import { rules, useCondition } from '@/app-components/app/AppLockScreen/shared'
|
import { rules, useCondition } from '@/app-components/app/AppLockScreen/shared'
|
||||||
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
|
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
|
||||||
import { useDevice } from '@/hooks'
|
import { useDevice } from '@/hooks'
|
||||||
import { useForm } from '@/components'
|
|
||||||
import { APP_CATCH_KEY } from '@/app-config'
|
import type { FormInst, InputInst } from 'naive-ui'
|
||||||
import { removeStorage, decrypt, getStorage } from '@/utils'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'UnlockScreen',
|
name: 'UnlockScreen',
|
||||||
setup() {
|
setup() {
|
||||||
const [register, { validate }] = useForm()
|
const formRef = ref<FormInst | null>(null)
|
||||||
|
const inputInstRef = ref<InputInst | null>(null)
|
||||||
|
|
||||||
const { logout } = useSigningActions()
|
const { logout } = useSigningActions()
|
||||||
const { updateSettingState } = useSettingActions()
|
const { updateSettingState } = useSettingActions()
|
||||||
@ -25,13 +35,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
const HH_MM_FORMAT = 'HH:mm'
|
const HH_MM_FORMAT = 'HH:mm'
|
||||||
const AM_PM_FORMAT = 'A'
|
const AM_PM_FORMAT = 'A'
|
||||||
const YY_MM_DD_FORMAT = 'YYYY-MM-DD'
|
const YY_MM_DD_FORMAT = 'YY年MM月DD日'
|
||||||
const DDD_FORMAT = 'ddd'
|
const DDD_FORMAT = 'ddd'
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
lockCondition: useCondition(),
|
lockCondition: useCondition(),
|
||||||
HH_MM: dayjs().format(HH_MM_FORMAT),
|
HH_MM: dayjs().format(HH_MM_FORMAT),
|
||||||
AM_PM: dayjs().format(AM_PM_FORMAT),
|
AM_PM: dayjs().locale('en').format(AM_PM_FORMAT),
|
||||||
YY_MM_DD: dayjs().format(YY_MM_DD_FORMAT),
|
YY_MM_DD: dayjs().format(YY_MM_DD_FORMAT),
|
||||||
DDD: dayjs().format(DDD_FORMAT),
|
DDD: dayjs().format(DDD_FORMAT),
|
||||||
})
|
})
|
||||||
@ -44,55 +54,30 @@ export default defineComponent({
|
|||||||
state.DDD = dayjs().format(DDD_FORMAT)
|
state.DDD = dayjs().format(DDD_FORMAT)
|
||||||
}, 86_400_000)
|
}, 86_400_000)
|
||||||
|
|
||||||
const toSigningFn = () => {
|
/** 退出登陆并且回到登陆页 */
|
||||||
removeStorage(APP_CATCH_KEY.appLockScreenPasswordKey, 'localStorage')
|
|
||||||
updateSettingState('lockScreenSwitch', false)
|
|
||||||
setTimeout(() => {
|
|
||||||
logout()
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
const backToSigning = () => {
|
const backToSigning = () => {
|
||||||
window.$dialog.warning({
|
window.$dialog.warning({
|
||||||
title: '警告',
|
title: '警告',
|
||||||
content: '是否返回到登陆页并且重新登录',
|
content: '是否返回到登陆页?',
|
||||||
positiveText: '确定',
|
positiveText: '确定',
|
||||||
negativeText: '重新登录',
|
negativeText: '取消',
|
||||||
onPositiveClick: toSigningFn,
|
onPositiveClick: () => {
|
||||||
|
logout()
|
||||||
|
setTimeout(() => {
|
||||||
|
updateSettingState('lockScreenSwitch', false)
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 解锁 */
|
||||||
const unlockScreen = () => {
|
const unlockScreen = () => {
|
||||||
const catchPassword = getStorage<string>(
|
formRef.value?.validate((error) => {
|
||||||
APP_CATCH_KEY.appLockScreenPasswordKey,
|
if (!error) {
|
||||||
'localStorage',
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!catchPassword) {
|
|
||||||
window.$dialog.warning({
|
|
||||||
title: '警告',
|
|
||||||
content: () => '检测到锁屏密码被修改,请重新登录',
|
|
||||||
closable: false,
|
|
||||||
maskClosable: false,
|
|
||||||
closeOnEsc: false,
|
|
||||||
positiveText: '重新登录',
|
|
||||||
onPositiveClick: toSigningFn,
|
|
||||||
})
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const dCatchPassword = decrypt(catchPassword)
|
|
||||||
|
|
||||||
validate().then(() => {
|
|
||||||
if (dCatchPassword === state.lockCondition.lockPassword) {
|
|
||||||
setLockAppScreen(false)
|
setLockAppScreen(false)
|
||||||
updateSettingState('lockScreenSwitch', false)
|
updateSettingState('lockScreenSwitch', false)
|
||||||
removeStorage(APP_CATCH_KEY.appLockScreenPasswordKey, 'localStorage')
|
|
||||||
|
|
||||||
state.lockCondition = useCondition()
|
state.lockCondition = useCondition()
|
||||||
} else {
|
|
||||||
window.$message.warning('密码错误,请重新输入')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -106,84 +91,71 @@ export default defineComponent({
|
|||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
backToSigning,
|
backToSigning,
|
||||||
unlockScreen,
|
unlockScreen,
|
||||||
|
formRef,
|
||||||
|
inputInstRef,
|
||||||
isTabletOrSmaller,
|
isTabletOrSmaller,
|
||||||
register,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const { isTabletOrSmaller } = this
|
const { isTabletOrSmaller } = this
|
||||||
const { HH_MM, AM_PM, YY_MM_DD, DDD } = this
|
const { HH_MM, AM_PM, YY_MM_DD, DDD } = this
|
||||||
const hmSplit = HH_MM.split(':')
|
const hmSplit = HH_MM.split(':')
|
||||||
const { unlockScreen, backToSigning, register } = this
|
const { unlockScreen, backToSigning } = this
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="app-lock-screen__content app-lock-screen__content--full">
|
<div class="app-lock-screen__unlock">
|
||||||
<div class="app-lock-screen__unlock">
|
<div class="app-lock-screen__unlock__content">
|
||||||
<div class="app-lock-screen__unlock__content">
|
<div class="app-lock-screen__unlock__content-wrapper">
|
||||||
<div class="app-lock-screen__unlock__content-wrapper">
|
<div
|
||||||
<div
|
class={[
|
||||||
class={[
|
'app-lock-screen__unlock__content-bg__wrapper',
|
||||||
'app-lock-screen__unlock__content-bg__wrapper',
|
'app-lock-screen__unlock__content-bg',
|
||||||
'app-lock-screen__unlock__content-bg',
|
isTabletOrSmaller
|
||||||
isTabletOrSmaller
|
? 'app-lock-screen__unlock__content-bg--smaller'
|
||||||
? 'app-lock-screen__unlock__content-bg--smaller'
|
: '',
|
||||||
: '',
|
]}
|
||||||
]}
|
>
|
||||||
>
|
<div class="left">{hmSplit[0]}</div>
|
||||||
<div class="left">{hmSplit[0]}</div>
|
<div class="right">{hmSplit[1]}</div>
|
||||||
<div class="right">{hmSplit[1]}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="app-lock-screen__unlock__content-avatar">
|
</div>
|
||||||
<AppAvatar
|
<div class="app-lock-screen__unlock__content-avatar">
|
||||||
avatarSize={52}
|
<AppAvatar avatarSize={52} style="pointer-events: none;" />
|
||||||
style="pointer-events: none;"
|
</div>
|
||||||
vertical
|
<div class="app-lock-screen__unlock__content-input">
|
||||||
/>
|
<NForm ref="formRef" model={this.lockCondition} rules={rules}>
|
||||||
|
<NFormItem path="lockPassword">
|
||||||
|
<NInput
|
||||||
|
ref="inputInstRef"
|
||||||
|
v-model:value={this.lockCondition.lockPassword}
|
||||||
|
type="password"
|
||||||
|
placeholder="请输入解锁密码"
|
||||||
|
clearable
|
||||||
|
minlength={6}
|
||||||
|
maxlength={12}
|
||||||
|
onKeydown={(e: KeyboardEvent) => {
|
||||||
|
if (e.code === 'Enter') {
|
||||||
|
unlockScreen()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</NFormItem>
|
||||||
|
<NFlex justify="space-between">
|
||||||
|
<NButton type="primary" text onClick={backToSigning.bind(this)}>
|
||||||
|
返回登陆
|
||||||
|
</NButton>
|
||||||
|
<NButton type="primary" text onClick={unlockScreen.bind(this)}>
|
||||||
|
进入系统
|
||||||
|
</NButton>
|
||||||
|
</NFlex>
|
||||||
|
</NForm>
|
||||||
|
</div>
|
||||||
|
<div class="app-lock-screen__unlock__content-date">
|
||||||
|
<div class="current-date">
|
||||||
|
{HH_MM} <span>{AM_PM}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-lock-screen__unlock__content-input">
|
<div class="current-year">
|
||||||
<RForm
|
{YY_MM_DD} <span>{DDD}</span>
|
||||||
onRegister={register}
|
|
||||||
model={this.lockCondition}
|
|
||||||
rules={rules}
|
|
||||||
>
|
|
||||||
<NFormItem path="lockPassword">
|
|
||||||
<NInput
|
|
||||||
autofocus
|
|
||||||
v-model:value={this.lockCondition.lockPassword}
|
|
||||||
type="password"
|
|
||||||
placeholder="请输入解锁密码"
|
|
||||||
clearable
|
|
||||||
minlength={6}
|
|
||||||
onKeydown={(e: KeyboardEvent) => {
|
|
||||||
if (e.code === 'Enter') {
|
|
||||||
unlockScreen()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</NFormItem>
|
|
||||||
<NFlex justify="space-between">
|
|
||||||
<NButton
|
|
||||||
type="primary"
|
|
||||||
text
|
|
||||||
onClick={backToSigning.bind(this)}
|
|
||||||
>
|
|
||||||
返回登陆
|
|
||||||
</NButton>
|
|
||||||
<NButton
|
|
||||||
type="primary"
|
|
||||||
text
|
|
||||||
onClick={unlockScreen.bind(this)}
|
|
||||||
>
|
|
||||||
进入系统
|
|
||||||
</NButton>
|
|
||||||
</NFlex>
|
|
||||||
</RForm>
|
|
||||||
</div>
|
|
||||||
<div class="app-lock-screen__unlock__content-date">
|
|
||||||
<div class="current-year">
|
|
||||||
{YY_MM_DD} <span>{DDD}</span> <span>{AM_PM}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
.app-lock-screen__content {
|
.app-lock-screen__content {
|
||||||
&.app-lock-screen__content--full {
|
|
||||||
width: 100%;
|
|
||||||
height: var(--html-height);
|
|
||||||
@include flexCenter;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .app-lock-screen__input {
|
& .app-lock-screen__input {
|
||||||
& button[class*='n-button'] {
|
& button[class*='n-button'] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -36,7 +30,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
font-size: 16.67rem;
|
font-size: 320px;
|
||||||
gap: 80px;
|
gap: 80px;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
|
||||||
@ -85,23 +79,9 @@
|
|||||||
|
|
||||||
& .current-year,
|
& .current-year,
|
||||||
& .current-date span {
|
& .current-date span {
|
||||||
font-size: 1.875rem;
|
font-size: 1.5rem;
|
||||||
line-height: 2.25rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ray-template--light {
|
|
||||||
.app-lock-screen__unlock__content-bg__wrapper {
|
|
||||||
background-color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-lock-screen__unlock__content-bg {
|
|
||||||
& .left,
|
|
||||||
& .right {
|
|
||||||
background-color: rgba(244, 244, 245, 1) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,11 +1,33 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-05-13
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 这里没有做解锁密码校验, 只要符合校验规则值皆可
|
||||||
|
* 可以根据需求自行更改
|
||||||
|
*/
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
import { RModal } from '@/components'
|
import { RModal } from '@/components'
|
||||||
import LockScreen from './components/LockScreen'
|
import LockScreen from './components/LockScreen'
|
||||||
|
import UnlockScreen from './components/UnlockScreen'
|
||||||
|
|
||||||
|
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
|
||||||
import { useSettingGetters, useSettingActions } from '@/store'
|
import { useSettingGetters, useSettingActions } from '@/store'
|
||||||
|
|
||||||
const AppLockScreen = defineComponent({
|
const AppLockScreen = defineComponent({
|
||||||
name: 'AppLockScreen',
|
name: 'AppLockScreen',
|
||||||
setup() {
|
setup() {
|
||||||
|
const { getLockAppScreen } = useAppLockScreen()
|
||||||
const { updateSettingState } = useSettingActions()
|
const { updateSettingState } = useSettingActions()
|
||||||
const { getLockScreenSwitch } = useSettingGetters()
|
const { getLockScreenSwitch } = useSettingGetters()
|
||||||
const lockScreenSwitchRef = computed({
|
const lockScreenSwitchRef = computed({
|
||||||
@ -17,9 +39,12 @@ const AppLockScreen = defineComponent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
lockScreenSwitchRef,
|
lockScreenSwitchRef,
|
||||||
|
getLockAppScreen,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
|
const { getLockAppScreen } = this
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RModal
|
<RModal
|
||||||
v-model:show={this.lockScreenSwitchRef}
|
v-model:show={this.lockScreenSwitchRef}
|
||||||
@ -28,10 +53,12 @@ const AppLockScreen = defineComponent({
|
|||||||
autoFocus={false}
|
autoFocus={false}
|
||||||
maskClosable={false}
|
maskClosable={false}
|
||||||
closeOnEsc={false}
|
closeOnEsc={false}
|
||||||
preset="dialog"
|
preset={!getLockAppScreen() ? 'dialog' : void 0}
|
||||||
title="锁定屏幕"
|
title="锁定屏幕"
|
||||||
>
|
>
|
||||||
<LockScreen />
|
<div class="app-lock-screen__content">
|
||||||
|
{!getLockAppScreen() ? <LockScreen /> : <UnlockScreen />}
|
||||||
|
</div>
|
||||||
</RModal>
|
</RModal>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-20
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import type { InputInst } from 'naive-ui'
|
import type { InputInst } from 'naive-ui'
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
|
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* 友情链接组件,无实际项目意义
|
||||||
|
*/
|
||||||
|
|
||||||
import { NAvatar, NTooltip, NFlex } from 'naive-ui'
|
import { NAvatar, NTooltip, NFlex } from 'naive-ui'
|
||||||
|
|
||||||
interface AvatarOptions {
|
interface AvatarOptions {
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-14
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 全局注入 naive ui 提示性组件
|
* 全局注入 naive ui 提示性组件
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-07-21
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 路由更新前,取消上一路由所有请求
|
* 路由更新前,取消上一路由所有请求
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-07-08
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import { get } from 'lodash-es'
|
import { get } from 'lodash-es'
|
||||||
import {
|
import {
|
||||||
setClass,
|
setClass,
|
||||||
@ -7,8 +18,7 @@ import {
|
|||||||
getStorage,
|
getStorage,
|
||||||
} from '@/utils'
|
} from '@/utils'
|
||||||
import { useSettingGetters } from '@/store'
|
import { useSettingGetters } from '@/store'
|
||||||
import { APP_CATCH_KEY, GLOBAL_CLASS_NAMES, APP_THEME } from '@/app-config'
|
import { APP_CATCH_KEY } from '@/app-config'
|
||||||
import { useWindowSize } from '@vueuse/core'
|
|
||||||
|
|
||||||
import type { SettingState } from '@/store/modules/setting/types'
|
import type { SettingState } from '@/store/modules/setting/types'
|
||||||
|
|
||||||
@ -16,50 +26,40 @@ export default defineComponent({
|
|||||||
name: 'AppStyleProvider',
|
name: 'AppStyleProvider',
|
||||||
setup(_, { expose }) {
|
setup(_, { expose }) {
|
||||||
const { getAppTheme } = useSettingGetters()
|
const { getAppTheme } = useSettingGetters()
|
||||||
const { height, width } = useWindowSize()
|
|
||||||
|
|
||||||
// 同步主题色变量至 html,如果未获取到缓存值则已默认值填充
|
/** 同步主题色变量至 body, 如果未获取到缓存值则已默认值填充 */
|
||||||
const syncPrimaryColorToBody = () => {
|
const syncPrimaryColorToBody = () => {
|
||||||
// 默认主题色
|
|
||||||
const {
|
const {
|
||||||
appPrimaryColor: { primaryColor, primaryFadeColor },
|
appPrimaryColor: { primaryColor, primaryFadeColor },
|
||||||
} = APP_THEME
|
} = __APP_CFG__ // 默认主题色
|
||||||
// 主题色配置 class 名
|
const body = document.body
|
||||||
const { rayTemplateThemePrimaryColor, rayTemplateThemePrimaryFadeColor } =
|
|
||||||
GLOBAL_CLASS_NAMES
|
|
||||||
|
|
||||||
const html = document.documentElement
|
|
||||||
|
|
||||||
// 获取缓存 naive ui 配置项
|
|
||||||
const primaryColorOverride = getStorage<SettingState>(
|
const primaryColorOverride = getStorage<SettingState>(
|
||||||
APP_CATCH_KEY.appPiniaSettingStore,
|
APP_CATCH_KEY.appPiniaSettingStore,
|
||||||
'localStorage',
|
'localStorage',
|
||||||
)
|
) // 获取缓存 naive ui 配置项
|
||||||
|
|
||||||
if (primaryColorOverride) {
|
if (primaryColorOverride) {
|
||||||
// 获取主色调
|
|
||||||
const p = get(
|
const p = get(
|
||||||
primaryColorOverride,
|
primaryColorOverride,
|
||||||
'primaryColorOverride.common.primaryColor',
|
'primaryColorOverride.common.primaryColor',
|
||||||
primaryColor,
|
primaryColor,
|
||||||
)
|
) // 获取主色调
|
||||||
// 将主色调任意颜色转换为 rgba 格式
|
const fp = colorToRgba(p, 0.38) // 将主色调任意颜色转换为 rgba 格式
|
||||||
const fp = colorToRgba(p, 0.85)
|
|
||||||
|
|
||||||
// 设置全局主题色 css 变量
|
/** 设置全局主题色 css 变量 */
|
||||||
html.style.setProperty(rayTemplateThemePrimaryColor, p) // 主色调
|
body.style.setProperty('--ray-theme-primary-color', p) // 主色调
|
||||||
// 降低透明度后的主色调
|
body.style.setProperty(
|
||||||
html.style.setProperty(
|
'--ray-theme-primary-fade-color',
|
||||||
rayTemplateThemePrimaryFadeColor,
|
|
||||||
fp || primaryFadeColor,
|
fp || primaryFadeColor,
|
||||||
)
|
) // 降低透明度后的主色调
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 隐藏加载动画
|
/** 隐藏加载动画 */
|
||||||
const hiddenLoadingAnimation = () => {
|
const hiddenLoadingAnimation = () => {
|
||||||
// pre-loading-animation 是默认 id
|
/** pre-loading-animation 是默认 id */
|
||||||
const el = document.getElementById(GLOBAL_CLASS_NAMES.preLoadingAnimation)
|
const el = document.getElementById('pre-loading-animation')
|
||||||
|
|
||||||
if (el) {
|
if (el) {
|
||||||
setStyle(el, {
|
setStyle(el, {
|
||||||
@ -68,30 +68,38 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换主题时,同步更新 html class 以便于进行自定义 css 配置
|
/** 切换主题时, 同步更新 body class 以便于进行自定义 css 配置 */
|
||||||
const updateGlobalThemeClass = (bool: boolean) => {
|
const updateGlobalThemeClass = (bool: boolean) => {
|
||||||
const html = document.documentElement
|
/**
|
||||||
const { darkClassName, lightClassName } = GLOBAL_CLASS_NAMES
|
*
|
||||||
|
* 初始化时根据当前主题色进行初始化 body 的 class 属性
|
||||||
|
*
|
||||||
|
* 根据 getAppTheme 进行初始化
|
||||||
|
*/
|
||||||
|
const body = document.body
|
||||||
|
const darkClassName = 'ray-template--dark' // 暗色类名
|
||||||
|
const lightClassName = 'ray-template--light' // 明亮色类名
|
||||||
|
|
||||||
bool
|
bool
|
||||||
? removeClass(html, lightClassName)
|
? removeClass(body, lightClassName)
|
||||||
: removeClass(html, darkClassName)
|
: removeClass(body, darkClassName)
|
||||||
|
|
||||||
setClass(html, bool ? darkClassName : lightClassName)
|
setClass(body, bool ? darkClassName : lightClassName)
|
||||||
}
|
}
|
||||||
|
|
||||||
syncPrimaryColorToBody()
|
syncPrimaryColorToBody()
|
||||||
hiddenLoadingAnimation()
|
hiddenLoadingAnimation()
|
||||||
|
|
||||||
watchEffect(() => {
|
// 当切换主题时,更新 body 当前的注入 class
|
||||||
// 当切换主题时,更新 html 当前的注入 class
|
watch(
|
||||||
updateGlobalThemeClass(getAppTheme.value)
|
() => getAppTheme.value,
|
||||||
// 注入全局宽高尺寸
|
(ndata) => {
|
||||||
setStyle(document.documentElement, {
|
updateGlobalThemeClass(ndata)
|
||||||
[GLOBAL_CLASS_NAMES.htmlHeight]: `${height.value}px`,
|
},
|
||||||
[GLOBAL_CLASS_NAMES.htmlWidth]: `${width.value}px`,
|
{
|
||||||
})
|
immediate: true,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
expose()
|
expose()
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2024-01-01
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 检测当前版本是否为最新版本
|
* 检测当前版本是否为最新版本
|
||||||
@ -28,10 +39,18 @@ export default defineComponent({
|
|||||||
if (version !== cacheVersion) {
|
if (version !== cacheVersion) {
|
||||||
modalShow.value = true
|
modalShow.value = true
|
||||||
|
|
||||||
setStorage(APP_CATCH_KEY.appVersionProvider, version, 'localStorage')
|
setStorage<string>(
|
||||||
|
APP_CATCH_KEY.appVersionProvider,
|
||||||
|
version,
|
||||||
|
'localStorage',
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setStorage(APP_CATCH_KEY.appVersionProvider, version, 'localStorage')
|
setStorage<string>(
|
||||||
|
APP_CATCH_KEY.appVersionProvider,
|
||||||
|
version,
|
||||||
|
'localStorage',
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -53,7 +72,7 @@ export default defineComponent({
|
|||||||
title="发现新版本"
|
title="发现新版本"
|
||||||
content="当前版本已更新,点击确认加载新版本~"
|
content="当前版本已更新,点击确认加载新版本~"
|
||||||
zIndex={999999999}
|
zIndex={999999999}
|
||||||
draggable
|
dad
|
||||||
positiveText="确认"
|
positiveText="确认"
|
||||||
negativeText="取消"
|
negativeText="取消"
|
||||||
onPositiveClick={logout}
|
onPositiveClick={logout}
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-10-21
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 全局水印注入
|
* 全局水印注入
|
||||||
@ -26,7 +37,7 @@ export default defineComponent({
|
|||||||
const { getWatermarkConfig, getWatermarkSwitch } = this
|
const { getWatermarkConfig, getWatermarkSwitch } = this
|
||||||
|
|
||||||
return getWatermarkSwitch ? (
|
return getWatermarkSwitch ? (
|
||||||
<NWatermark {...getWatermarkConfig} fullscreen />
|
<NWatermark cross fullscreen {...getWatermarkConfig} />
|
||||||
) : null
|
) : null
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
import type { AppMenuConfig, PreloadingConfig } from '@/types'
|
|
||||||
import type { MessageProviderProps } from 'naive-ui'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
* 全局注入到 html 的样式类名。
|
|
||||||
*
|
*
|
||||||
* 如果涉及到全局主题色的 class name,需要修改的时候记得全局替换;
|
* @date 2023-05-23
|
||||||
* 避免样式出现奇奇怪怪的问题。
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
*/
|
*/
|
||||||
export const GLOBAL_CLASS_NAMES = {
|
|
||||||
darkClassName: 'ray-template--dark',
|
/** 系统配置 */
|
||||||
lightClassName: 'ray-template--light',
|
|
||||||
rayTemplateThemePrimaryColor: '--ray-theme-primary-color',
|
import type { LayoutSideBarLogo, PreloadingConfig } from '@/types'
|
||||||
rayTemplateThemePrimaryFadeColor: '--ray-theme-primary-fade-color',
|
import type { AppMenuConfig, AppKeepAlive } from '@/types'
|
||||||
preLoadingAnimation: 'pre-loading-animation',
|
import type { MessageProviderProps } from 'naive-ui'
|
||||||
htmlHeight: '--html-height',
|
|
||||||
htmlWidth: '--html-width',
|
|
||||||
} as const
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -34,9 +30,8 @@ export const MESSAGE_PROVIDER: MessageProviderProps = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
|
||||||
* 是否启用路由切换 spin 加载;
|
* 是否启用路由切换 spin 加载;
|
||||||
* 如果启用该配置项,则会在路由更新时触发内容区域的加载状态,直到路由加载完成。
|
* 如果启用该配置项,啧会在路由更新时触发内容区域的加载状态,直到路由加载完成。
|
||||||
*
|
*
|
||||||
* 在 v4.7.5 版本后,默认关闭了该配置项。
|
* 在 v4.7.5 版本后,默认关闭了该配置项。
|
||||||
*/
|
*/
|
||||||
@ -44,11 +39,25 @@ export const LAYOUT_CONTENT_SPIN_WHEN_ROUTE_CHANGE = false
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 全局 Spin 加载内容
|
||||||
* 全局 Spin 加载内容。
|
|
||||||
*/
|
*/
|
||||||
export const APP_GLOBAL_LOADING = 'loading'
|
export const APP_GLOBAL_LOADING = 'loading'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 系统缓存
|
||||||
|
*
|
||||||
|
* 说明:
|
||||||
|
* - setupKeepAlive: 是否启用系统页面缓存, 设置为 false 则关闭系统页面缓存
|
||||||
|
* - keepAliveExclude: 排除哪些页面不缓存
|
||||||
|
* - maxKeepAliveLength: 最大缓存页面数量
|
||||||
|
*/
|
||||||
|
export const APP_KEEP_ALIVE: Readonly<AppKeepAlive> = {
|
||||||
|
setupKeepAlive: true,
|
||||||
|
keepAliveExclude: [],
|
||||||
|
maxKeepAliveLength: 5,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 首屏加载信息配置
|
* 首屏加载信息配置
|
||||||
@ -62,26 +71,61 @@ export const PRE_LOADING_CONFIG: PreloadingConfig = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* icon: LOGO 图标, 依赖 `RIcon` 实现(如果为空则不会渲染图标);4.8.2 版本后支持 VNode
|
||||||
* 系统缓存 key 前缀。
|
* title: LOGO 标题
|
||||||
* 可以选择自定义缓存 key 前缀,在使用 getStorage 和 setStorage 时可以考虑是否启用前缀的方式来避免缓存 key 冲突。
|
* url: 点击跳转地址, 如果不配置该属性, 则不会触发跳转
|
||||||
* 该配置项也可以结合 APP_CATCH_KEY 使用。
|
* jumpType: 跳转类型(station: 项目内跳转, outsideStation: 新页面打开)
|
||||||
*
|
*
|
||||||
* 值得注意的是,该方法整合进了 cache.ts 方法包中。也就是说只要该配置项不为空字符串则会自动启用缓存前缀。
|
* 如果不设置该属性或者为空, 则不会渲染 LOGO
|
||||||
|
*/
|
||||||
|
export const SIDE_BAR_LOGO: LayoutSideBarLogo | undefined = {
|
||||||
|
icon: 'ray',
|
||||||
|
title: 'Ray Template',
|
||||||
|
url: '/dashboard',
|
||||||
|
jumpType: 'station',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
*
|
*
|
||||||
* 默认不启用。
|
* 系统菜单折叠配置
|
||||||
|
*
|
||||||
|
* menuCollapsedWidth 配置仅当 menuCollapsedMode 为 width 风格时才有效
|
||||||
|
*
|
||||||
|
* menuCollapsedMode:
|
||||||
|
* - transform: 边栏将只会移动它的位置而不会改变宽度
|
||||||
|
* - width: Sider 的内容宽度将会被实际改变
|
||||||
|
* menuCollapsedIconSize 配置菜单未折叠时图标的大小
|
||||||
|
* menuCollapsedIndent 配置菜单每级的缩进
|
||||||
|
* menuAccordion 手风琴模式
|
||||||
|
*/
|
||||||
|
export const APP_MENU_CONFIG: Readonly<AppMenuConfig> = {
|
||||||
|
menuCollapsedWidth: 64,
|
||||||
|
menuCollapsedMode: 'width',
|
||||||
|
menuCollapsedIconSize: 22,
|
||||||
|
menuCollapsedIndent: 24,
|
||||||
|
menuAccordion: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 系统缓存 key 前缀
|
||||||
|
* 可以选择自定义缓存 key 前缀,在使用 getStorage 和 setStorage 时可以考虑是否启用前缀的方式来避免缓存 key 冲突
|
||||||
|
* 该配置项也可以结合 APP_CATCH_KEY 使用
|
||||||
|
*
|
||||||
|
* 值得注意的是,该方法整合进了 cache.ts 方法包中。也就是说只要该配置项不为空字符串则会自动启用缓存前缀
|
||||||
|
*
|
||||||
|
* 默认不启用
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* export const APP_CATCH_KEY_PREFIX = 'ray-template:'
|
* export const APP_CATCH_KEY_PREFIX = 'ray-template:'
|
||||||
*
|
*
|
||||||
* 转换后的缓存 key: ray-template:signing。
|
* 'ray-template:signing' // 会自动拼接为
|
||||||
*/
|
*/
|
||||||
export const APP_CATCH_KEY_PREFIX = ''
|
export const APP_CATCH_KEY_PREFIX = ''
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 系统默认缓存 key 配置
|
||||||
* 系统默认缓存 key 配置。
|
|
||||||
*
|
*
|
||||||
* 说明:
|
* 说明:
|
||||||
* - signing: 登陆信息缓存 key
|
* - signing: 登陆信息缓存 key
|
||||||
@ -93,8 +137,6 @@ export const APP_CATCH_KEY_PREFIX = ''
|
|||||||
* - appPiniaMenuStore: pinia menu store key
|
* - appPiniaMenuStore: pinia menu store key
|
||||||
* - appPiniaSigningStore: pinia signing store key
|
* - appPiniaSigningStore: pinia signing store key
|
||||||
* - appVersionProvider: 版本信息缓存 key
|
* - appVersionProvider: 版本信息缓存 key
|
||||||
* - appMenuTagOptions: 标签页菜单列表
|
|
||||||
* - appLockScreenPasswordKey: 锁屏密码缓存 key
|
|
||||||
*/
|
*/
|
||||||
export const APP_CATCH_KEY = {
|
export const APP_CATCH_KEY = {
|
||||||
signing: 'signing',
|
signing: 'signing',
|
||||||
@ -108,16 +150,13 @@ export const APP_CATCH_KEY = {
|
|||||||
appVersionProvider: 'appVersionProvider',
|
appVersionProvider: 'appVersionProvider',
|
||||||
isAppLockScreen: 'isAppLockScreen',
|
isAppLockScreen: 'isAppLockScreen',
|
||||||
appGlobalSearchOptions: 'appGlobalSearchOptions',
|
appGlobalSearchOptions: 'appGlobalSearchOptions',
|
||||||
appMenuTagOptions: 'appMenuTagOptions',
|
|
||||||
appLockScreenPasswordKey: 'appLockScreenPasswordKey',
|
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 系统内容切换动画配置
|
||||||
* 系统内容切换动画配置。
|
* 但是在配置的时候,会自动拼接一个 `transform` 前缀
|
||||||
* 但是在配置的时候,会自动拼接一个 transform 前缀。
|
* 例如: `transform-fade-bottom`
|
||||||
* 例如: transform-fade-bottom。
|
|
||||||
*/
|
*/
|
||||||
export const CONTENT_TRANSITION_OPTIONS = [
|
export const CONTENT_TRANSITION_OPTIONS = [
|
||||||
{
|
{
|
||||||
|
@ -1,38 +1,50 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-05-19
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 系统颜色风格配置入口 */
|
||||||
|
|
||||||
import type { AppTheme } from '@/types'
|
import type { AppTheme } from '@/types'
|
||||||
|
|
||||||
export const APP_THEME: AppTheme = {
|
export const APP_THEME: AppTheme = {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 系统主题颜色预设色盘
|
||||||
* 系统主题颜色预设色盘。
|
* 支持 RGBA、RGB、十六进制
|
||||||
* 支持 RGBA、RGB、十六进制。
|
|
||||||
*/
|
*/
|
||||||
appThemeColors: [
|
appThemeColors: [
|
||||||
'#2d8cf0',
|
'#2d8cf0',
|
||||||
'#3f9eff',
|
'#3f9eff',
|
||||||
'#ff42bc',
|
'#ff42bc',
|
||||||
'#ee4f12',
|
'#ee4f12',
|
||||||
|
'#a6e4f7',
|
||||||
'#dbcb02',
|
'#dbcb02',
|
||||||
'#18a058',
|
'#18A058',
|
||||||
],
|
],
|
||||||
// 系统主题色
|
/** 系统主题色 */
|
||||||
appPrimaryColor: {
|
appPrimaryColor: {
|
||||||
// 主题色
|
/** 主题色 */
|
||||||
primaryColor: '#2d8cf0',
|
primaryColor: '#2d8cf0',
|
||||||
// 主题辅助色(用于整体 hover、active 等之类颜色)
|
/** 主题辅助色(用于整体 hover、active 等之类颜色) */
|
||||||
primaryFadeColor: 'rgba(45, 140, 240, 0.85)',
|
primaryFadeColor: 'rgba(45, 140, 240, 0.3)',
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 配置系统 naive-ui 主题色
|
||||||
* 配置系统 naive-ui 主题色。
|
* 官网文档地址: <https://www.naiveui.com/zh-CN/dark/docs/customize-theme>
|
||||||
* 官网文档地址: <https://www.naiveui.com/zh-CN/dark/docs/customize-theme>。
|
|
||||||
*
|
*
|
||||||
* 注意:
|
* 注意:
|
||||||
* - appPrimaryColor common 配置优先级大于该配置
|
* - appPrimaryColor common 配置优先级大于该配置
|
||||||
*
|
*
|
||||||
* 如果需要定制化整体组件样式,配置示例。
|
* 如果需要定制化整体组件样式, 配置示例
|
||||||
* 具体自行查看官网,还有模式更佳丰富的 peers 主题变量配置。
|
* 具体自行查看官网, 还有模式更佳丰富的 peers 主题变量配置
|
||||||
* 地址: <https://www.naiveui.com/zh-CN/dark/docs/customize-theme#%E4%BD%BF%E7%94%A8-peers-%E4%B8%BB%E9%A2%98%E5%8F%98%E9%87%8F>
|
* 地址: <https://www.naiveui.com/zh-CN/dark/docs/customize-theme#%E4%BD%BF%E7%94%A8-peers-%E4%B8%BB%E9%A2%98%E5%8F%98%E9%87%8F>
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
@ -48,24 +60,17 @@ export const APP_THEME: AppTheme = {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
appNaiveUIThemeOverrides: {
|
appNaiveUIThemeOverrides: {
|
||||||
dark: {
|
dark: {},
|
||||||
common: {
|
light: {},
|
||||||
borderRadius: '4px',
|
},
|
||||||
baseColor: 'rgb(18, 18, 18)',
|
appNaiveUIThemeOverridesCommon: {
|
||||||
},
|
dark: {},
|
||||||
},
|
light: {},
|
||||||
light: {
|
|
||||||
common: {
|
|
||||||
borderRadius: '4px',
|
|
||||||
baseColor: 'rgb(255, 255, 255)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 配置 echart 主题颜色
|
||||||
* 配置 echart 主题颜色。
|
* 约定配置时以:主题名称为文件名,其文件夹下两个主题风格的 json 文件。并且暗色主题必须为 xxx-dark.json
|
||||||
* 约定配置时以:主题名称为文件名,其文件夹下两个主题风格的 json 文件。并且暗色主题必须为 xxx-dark.json。
|
|
||||||
*
|
*
|
||||||
* [文档地址](https://xiaodaigua-ray.github.io/ray-template-doc/ray-template-docs/advanced/echart-themes.html)
|
* [文档地址](https://xiaodaigua-ray.github.io/ray-template-doc/ray-template-docs/advanced/echart-themes.html)
|
||||||
*/
|
*/
|
||||||
|
@ -7,24 +7,7 @@
|
|||||||
"#f7c5a0",
|
"#f7c5a0",
|
||||||
"#d4a4eb",
|
"#d4a4eb",
|
||||||
"#d2f5a6",
|
"#d2f5a6",
|
||||||
"#76f2f2",
|
"#76f2f2"
|
||||||
"#9b8bba",
|
|
||||||
"#e098c7",
|
|
||||||
"#8fd3e8",
|
|
||||||
"#71669e",
|
|
||||||
"#cc70af",
|
|
||||||
"#7cb4cc",
|
|
||||||
"#7EC4FF",
|
|
||||||
"#5FCBB0",
|
|
||||||
"#49C4BF",
|
|
||||||
"#F0C9CA",
|
|
||||||
"#34DC90",
|
|
||||||
"#3295E0",
|
|
||||||
"#EAB62E",
|
|
||||||
"#76C3F3",
|
|
||||||
"#2DC2C0",
|
|
||||||
"#FCC43F",
|
|
||||||
"#84CFFF"
|
|
||||||
],
|
],
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"textStyle": {},
|
"textStyle": {},
|
||||||
@ -314,9 +297,6 @@
|
|||||||
"legend": {
|
"legend": {
|
||||||
"textStyle": {
|
"textStyle": {
|
||||||
"color": "#999999"
|
"color": "#999999"
|
||||||
},
|
|
||||||
"pageTextStyle": {
|
|
||||||
"color": "#999999"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tooltip": {
|
"tooltip": {
|
||||||
|
@ -19,13 +19,7 @@
|
|||||||
"#c9ab00",
|
"#c9ab00",
|
||||||
"#7eb00a",
|
"#7eb00a",
|
||||||
"#6f5553",
|
"#6f5553",
|
||||||
"#c14089",
|
"#c14089"
|
||||||
"#516b91",
|
|
||||||
"#59c4e6",
|
|
||||||
"#edafda",
|
|
||||||
"#93b7e3",
|
|
||||||
"#a5e7f0",
|
|
||||||
"#cbb0e3"
|
|
||||||
],
|
],
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
"textStyle": {},
|
"textStyle": {},
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-05-19
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 国际化相关配置 */
|
||||||
|
|
||||||
import type { TemplateLocale, LocalOptions, DayjsLocalMap } from '@/types'
|
import type { TemplateLocale, LocalOptions, DayjsLocalMap } from '@/types'
|
||||||
import type { ValueOf } from '@/types'
|
import type { ValueOf } from '@/types'
|
||||||
|
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-12
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 正则入口
|
* 正则入口
|
||||||
@ -8,12 +19,4 @@ export const APP_REGEX: Record<string, RegExp> = {
|
|||||||
/** css 尺寸单位匹配 */
|
/** css 尺寸单位匹配 */
|
||||||
cssUnit:
|
cssUnit:
|
||||||
/^\d+(\.\d+)?(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ch|ex|q|s|ms|deg|rad|turn|grad|hz|khz|dpi|dpcm|dppx|fr|auto)$/,
|
/^\d+(\.\d+)?(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ch|ex|q|s|ms|deg|rad|turn|grad|hz|khz|dpi|dpcm|dppx|fr|auto)$/,
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* 匹配 css 单位是否为 auto, unset, fit-content, max-content, min-content, initial, inherit, revert, revert-layer, -webkit-fill-available,
|
|
||||||
* -webkit-max-content, -webkit-min-content, -webkit-revert, -webkit-revert-layer, -webkit-fill-available。
|
|
||||||
*/
|
|
||||||
cssSize:
|
|
||||||
/^auto|unset|fit-content|max-content|min-content|initial|inherit|revert|revert-layer|[-\w]+-webkit-fill-available$/,
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-02
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import type { AxiosConfig } from '@/types'
|
import type { AxiosConfig } from '@/types'
|
||||||
|
|
||||||
/** axios 相关配置 */
|
/** axios 相关配置 */
|
||||||
|
@ -1,10 +1,23 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-05-19
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** vue-router 相关配置入口 */
|
||||||
|
|
||||||
import type { LayoutInst } from 'naive-ui'
|
import type { LayoutInst } from 'naive-ui'
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* 内容区域 shallowRef 注册
|
* 内容区域 ref 注册
|
||||||
* 可以控制内容区域当前滚动位置
|
* 可以控制内容区域当前滚动位置
|
||||||
* 如果你需要在切换路由时候配置自定义滚动到某个视图区域时, 可以使用该属性提供的方法(scrollTo)
|
* 如果你需要在切换路由时候配置自定义滚动到某个视图区域时, 可以使用该属性提供的方法(scrollTo)
|
||||||
*
|
*
|
||||||
@ -16,12 +29,12 @@ import type { Ref } from 'vue'
|
|||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
export const LAYOUT_CONTENT_REF: Readonly<Ref<LayoutInst | null>> =
|
export const LAYOUT_CONTENT_REF: Readonly<Ref<LayoutInst | null>> =
|
||||||
shallowRef<LayoutInst | null>(null)
|
ref<LayoutInst | null>(null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* 侧边滚动栏滚动 shallowRef 注册。
|
* 侧边滚动栏滚动 ref 注册。
|
||||||
* 可以控制侧边滚动栏滚动位置。
|
* 可以控制侧边滚动栏滚动位置。
|
||||||
*
|
*
|
||||||
* 请注意使用时机。建议使用 nextTick() 等待 dom 挂载后再执行该方法。
|
* 请注意使用时机。建议使用 nextTick() 等待 dom 挂载后再执行该方法。
|
||||||
@ -31,7 +44,7 @@ export const LAYOUT_CONTENT_REF: Readonly<Ref<LayoutInst | null>> =
|
|||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
export const LAYOUT_SIDER_REF: Readonly<Ref<LayoutInst | null>> =
|
export const LAYOUT_SIDER_REF: Readonly<Ref<LayoutInst | null>> =
|
||||||
shallowRef<LayoutInst | null>(null)
|
ref<LayoutInst | null>(null)
|
||||||
|
|
||||||
export const SETUP_ROUTER_ACTION = {
|
export const SETUP_ROUTER_ACTION = {
|
||||||
/** 是否启用路由切换时顶部加载条 */
|
/** 是否启用路由切换时顶部加载条 */
|
||||||
@ -58,4 +71,4 @@ export const WHITE_ROUTES: string[] = ['RLogin', 'ErrorPage', 'RayTemplateDoc']
|
|||||||
* 超级管理员
|
* 超级管理员
|
||||||
* 配置默认超级管理员, 默认拥有全部最高权限
|
* 配置默认超级管理员, 默认拥有全部最高权限
|
||||||
*/
|
*/
|
||||||
export const SUPER_ADMIN: (string | number)[] = []
|
export const SUPER_ADMIN: (string | number)[] = ['admin']
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-10-23
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import { useAxiosInterceptor } from '@/axios/utils/interceptor'
|
import { useAxiosInterceptor } from '@/axios/utils/interceptor'
|
||||||
import implement from './provider'
|
import implement from './provider'
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { axiosCanceler } from '@/axios/utils/interceptor'
|
import { axiosCanceler } from '@/axios/utils/interceptor'
|
||||||
|
|
||||||
import type { AxiosRequestInterceptor, FetchErrorFunction } from '@/axios/types'
|
import type { FetchFunction, FetchErrorFunction } from '@/axios/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -10,7 +10,7 @@ import type { AxiosRequestInterceptor, FetchErrorFunction } from '@/axios/types'
|
|||||||
* @description
|
* @description
|
||||||
* 移除请求拦截器与注入请求拦截器。
|
* 移除请求拦截器与注入请求拦截器。
|
||||||
*/
|
*/
|
||||||
const injectRequestCanceler: AxiosRequestInterceptor = (ins, mode) => {
|
const injectRequestCanceler: FetchFunction = (ins, mode) => {
|
||||||
axiosCanceler.removePendingRequest(ins) // 检查是否存在重复请求, 若存在则取消已发的请求
|
axiosCanceler.removePendingRequest(ins) // 检查是否存在重复请求, 若存在则取消已发的请求
|
||||||
axiosCanceler.addPendingRequest(ins) // 把当前的请求信息添加到 pendingRequest 表中
|
axiosCanceler.addPendingRequest(ins) // 把当前的请求信息添加到 pendingRequest 表中
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,7 @@ import { appendRequestHeaders } from '@/axios/utils/append-request-headers'
|
|||||||
import { APP_CATCH_KEY } from '@/app-config'
|
import { APP_CATCH_KEY } from '@/app-config'
|
||||||
import { getStorage } from '@/utils'
|
import { getStorage } from '@/utils'
|
||||||
|
|
||||||
import type {
|
import type { RequestInterceptorConfig, FetchFunction } from '@/axios/types'
|
||||||
RequestInterceptorConfig,
|
|
||||||
AxiosRequestInterceptor,
|
|
||||||
} from '@/axios/types'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -16,7 +13,7 @@ import type {
|
|||||||
* 当然你也可以根据 request instance 来特殊处理, 这里暂时不做演示
|
* 当然你也可以根据 request instance 来特殊处理, 这里暂时不做演示
|
||||||
*/
|
*/
|
||||||
const requestHeaderToken = (ins: RequestInterceptorConfig, mode: string) => {
|
const requestHeaderToken = (ins: RequestInterceptorConfig, mode: string) => {
|
||||||
const token = getStorage<string | null>(APP_CATCH_KEY.token, 'localStorage')
|
const token = getStorage<string>(APP_CATCH_KEY.token)
|
||||||
|
|
||||||
if (ins.url) {
|
if (ins.url) {
|
||||||
// TODO: 根据 url 不同是否设置 token
|
// TODO: 根据 url 不同是否设置 token
|
||||||
@ -29,7 +26,7 @@ const requestHeaderToken = (ins: RequestInterceptorConfig, mode: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 注入请求头信息 */
|
/** 注入请求头信息 */
|
||||||
const injectRequestHeaders: AxiosRequestInterceptor = (ins, mode) => {
|
const injectRequestHeaders: FetchFunction = (ins, mode) => {
|
||||||
appendRequestHeaders(ins, [
|
appendRequestHeaders(ins, [
|
||||||
requestHeaderToken(ins, mode),
|
requestHeaderToken(ins, mode),
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-06
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 请求拦截器入口
|
* 请求拦截器入口
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-10-23
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import { useAxiosInterceptor } from '@/axios/utils/interceptor'
|
import { useAxiosInterceptor } from '@/axios/utils/interceptor'
|
||||||
import implement from './provider'
|
import implement from './provider'
|
||||||
|
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import { axiosCanceler } from '@/axios/utils/interceptor'
|
import { axiosCanceler } from '@/axios/utils/interceptor'
|
||||||
|
|
||||||
import type {
|
import type { FetchFunction, FetchErrorFunction } from '@/axios/types'
|
||||||
AxiosResponseInterceptor,
|
|
||||||
FetchErrorFunction,
|
|
||||||
} from '@/axios/types'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -13,7 +10,7 @@ import type {
|
|||||||
* @description
|
* @description
|
||||||
* 响应成功后注销请求取消器。
|
* 响应成功后注销请求取消器。
|
||||||
*/
|
*/
|
||||||
const injectResponseCanceler: AxiosResponseInterceptor = (ins, mode) => {
|
const injectResponseCanceler: FetchFunction = (ins, mode) => {
|
||||||
axiosCanceler.removePendingRequest(ins)
|
axiosCanceler.removePendingRequest(ins)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-06
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 响应拦截器入口
|
* 响应拦截器入口
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-07-11
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 基于 vue-hook-plus 与 axios 封装
|
* 基于 vue-hook-plus 与 axios 封装
|
||||||
@ -40,14 +51,14 @@ function useRequest<
|
|||||||
fetchOptions: AppRawRequestConfig<Response>,
|
fetchOptions: AppRawRequestConfig<Response>,
|
||||||
option?: UseRequestOptions<Response, HookPlusParams, HookPlusPlugin>,
|
option?: UseRequestOptions<Response, HookPlusParams, HookPlusPlugin>,
|
||||||
) {
|
) {
|
||||||
const fn = () => {
|
const fc = () => {
|
||||||
const cb = request<Response>(fetchOptions)
|
const cb = request<Response>(fetchOptions)
|
||||||
|
|
||||||
return cb
|
return cb
|
||||||
}
|
}
|
||||||
|
|
||||||
const hooks = useHookPlusRequest<Response, HookPlusParams>(
|
const hooks = useHookPlusRequest<Response, HookPlusParams>(
|
||||||
fn,
|
fc,
|
||||||
Object.assign({}, option),
|
Object.assign({}, option),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2022-11-18
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 请求拦截器与响应拦截器
|
||||||
|
* 如果有需要拓展拦截器, 请在 inject 目录下参照示例方法继续拓展
|
||||||
|
* 该页面不应该做过多的改动与配置
|
||||||
|
*/
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { AXIOS_CONFIG } from '@/app-config'
|
import { AXIOS_CONFIG } from '@/app-config'
|
||||||
import { useAxiosInterceptor } from '@/axios/utils/interceptor'
|
import { useAxiosInterceptor } from '@/axios/utils/interceptor'
|
||||||
@ -10,33 +28,23 @@ import {
|
|||||||
setupRequestErrorInterceptor,
|
setupRequestErrorInterceptor,
|
||||||
} from '@/axios/axios-interceptor/request'
|
} from '@/axios/axios-interceptor/request'
|
||||||
|
|
||||||
import type { AxiosInstanceExpand, RequestInterceptorConfig } from './types'
|
import type { AxiosInstanceExpand } from './types'
|
||||||
|
|
||||||
// 创建 axios 实例
|
|
||||||
const server: AxiosInstanceExpand = axios.create(AXIOS_CONFIG)
|
const server: AxiosInstanceExpand = axios.create(AXIOS_CONFIG)
|
||||||
// 获取拦截器实例
|
|
||||||
const { createAxiosInstance, beforeFetch, fetchError } = useAxiosInterceptor()
|
const { createAxiosInstance, beforeFetch, fetchError } = useAxiosInterceptor()
|
||||||
|
|
||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
server.interceptors.request.use(
|
server.interceptors.request.use(
|
||||||
(request) => {
|
(request) => {
|
||||||
// 生成 request instance
|
createAxiosInstance(request, 'requestInstance') // 生成 request instance
|
||||||
createAxiosInstance(
|
setupRequestInterceptor() // 初始化拦截器所有已注入方法
|
||||||
request as RequestInterceptorConfig<unknown>,
|
beforeFetch('requestInstance', 'implementRequestInterceptorArray', 'ok') // 执行拦截器所有已注入方法
|
||||||
'requestInstance',
|
|
||||||
)
|
|
||||||
// 初始化拦截器所有已注入方法
|
|
||||||
setupRequestInterceptor()
|
|
||||||
// 执行拦截器所有已注入方法
|
|
||||||
beforeFetch('requestInstance', 'implementRequestInterceptorArray', 'ok')
|
|
||||||
|
|
||||||
return request
|
return request
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// 初始化拦截器所有已注入方法(错误状态)
|
setupRequestErrorInterceptor() // 初始化拦截器所有已注入方法(错误状态)
|
||||||
setupRequestErrorInterceptor()
|
fetchError('requestError', error, 'implementRequestInterceptorErrorArray') // 执行所有已注入方法
|
||||||
// 执行所有已注入方法
|
|
||||||
fetchError('requestError', error, 'implementRequestInterceptorErrorArray')
|
|
||||||
|
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
},
|
},
|
||||||
@ -45,22 +53,17 @@ server.interceptors.request.use(
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
server.interceptors.response.use(
|
server.interceptors.response.use(
|
||||||
(response) => {
|
(response) => {
|
||||||
// 创建响应实例
|
createAxiosInstance(response, 'responseInstance') // 创建响应实例
|
||||||
createAxiosInstance(response, 'responseInstance')
|
setupResponseInterceptor() // 注入响应成功待执行队列
|
||||||
// 注入响应成功待执行队列
|
beforeFetch('responseInstance', 'implementResponseInterceptorArray', 'ok') // 执行响应成功拦截器
|
||||||
setupResponseInterceptor()
|
|
||||||
// 执行响应成功拦截器
|
|
||||||
beforeFetch('responseInstance', 'implementResponseInterceptorArray', 'ok')
|
|
||||||
|
|
||||||
const { data } = response
|
const { data } = response
|
||||||
|
|
||||||
return Promise.resolve(data)
|
return Promise.resolve(data)
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// 注入响应失败待执行队列
|
setupResponseErrorInterceptor() // 注入响应失败待执行队列
|
||||||
setupResponseErrorInterceptor()
|
fetchError('responseError', error, 'implementResponseInterceptorErrorArray') // 执行响应失败后拦截器
|
||||||
// 执行响应失败后拦截器
|
|
||||||
fetchError('responseError', error, 'implementResponseInterceptorErrorArray')
|
|
||||||
|
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
},
|
},
|
||||||
|
@ -7,8 +7,6 @@ import type {
|
|||||||
Axios,
|
Axios,
|
||||||
AxiosResponse,
|
AxiosResponse,
|
||||||
AxiosError,
|
AxiosError,
|
||||||
InternalAxiosRequestConfig,
|
|
||||||
AxiosRequestHeaders,
|
|
||||||
} from 'axios'
|
} from 'axios'
|
||||||
import type { AnyFC } from '@/types'
|
import type { AnyFC } from '@/types'
|
||||||
|
|
||||||
@ -47,24 +45,6 @@ export interface AppRawRequestConfig<T = any> extends AxiosRequestConfig<T> {
|
|||||||
* 标记该请求的配置项是否被标记了取消。
|
* 标记该请求的配置项是否被标记了取消。
|
||||||
*/
|
*/
|
||||||
__CANCELER_TAG_RAY_TEMPLATE__?: '__CANCELER_TAG_RAY_TEMPLATE__'
|
__CANCELER_TAG_RAY_TEMPLATE__?: '__CANCELER_TAG_RAY_TEMPLATE__'
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* 该接口是否需要自动弹出请求状态提示。
|
|
||||||
* 统一显示后端返回的提示信息。
|
|
||||||
*
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
responseErrorMessage?: boolean
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* 该接口是否需要自动弹出请求状态提示。
|
|
||||||
* 统一显示后端返回的提示信息。
|
|
||||||
*
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
responseSuccessMessage?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CancelerParams<T = any, D = any>
|
export interface CancelerParams<T = any, D = any>
|
||||||
@ -145,8 +125,18 @@ export interface ErrorImplementQueue {
|
|||||||
implementResponseInterceptorErrorArray: AnyFC[]
|
implementResponseInterceptorErrorArray: AnyFC[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FetchFunction = <T = any, K = any>(
|
||||||
|
ins: RequestInterceptorConfig<T> & ResponseInterceptorConfig<T, K>,
|
||||||
|
mode: string,
|
||||||
|
) => void
|
||||||
|
|
||||||
export type FetchType = 'ok' | 'error'
|
export type FetchType = 'ok' | 'error'
|
||||||
|
|
||||||
|
export type FetchErrorFunction<T = any, D = any> = (
|
||||||
|
error: AxiosError<T, D>,
|
||||||
|
mode: string,
|
||||||
|
) => void
|
||||||
|
|
||||||
export interface AxiosFetchInstance {
|
export interface AxiosFetchInstance {
|
||||||
requestInstance: RequestInterceptorConfig | null
|
requestInstance: RequestInterceptorConfig | null
|
||||||
responseInstance: ResponseInterceptorConfig | null
|
responseInstance: ResponseInterceptorConfig | null
|
||||||
@ -156,54 +146,3 @@ export interface AxiosFetchError<T = any> {
|
|||||||
requestError: T | null
|
requestError: T | null
|
||||||
responseError: T | null
|
responseError: T | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AxiosResponseConfigInterceptor<T = any>
|
|
||||||
extends AppRawRequestConfig<T> {
|
|
||||||
headers: AxiosRequestHeaders
|
|
||||||
}
|
|
||||||
|
|
||||||
type AxiosResponseOmit<T = any, D = any> = Omit<AxiosResponse<T, D>, 'config'>
|
|
||||||
|
|
||||||
type AxiosResponseInterceptorIns<T = any, D = any> = AxiosResponseOmit<T, D> & {
|
|
||||||
config: AxiosResponseConfigInterceptor<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param ins current response instance
|
|
||||||
* @param mode current environment mode
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* axios response interceptor.
|
|
||||||
*/
|
|
||||||
export type AxiosResponseInterceptor<T = any, K = any> = (
|
|
||||||
ins: AxiosResponseInterceptorIns<T, K>,
|
|
||||||
mode: string,
|
|
||||||
) => void
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param ins current request instance
|
|
||||||
* @param mode current environment mode
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* axios request interceptor.
|
|
||||||
*/
|
|
||||||
export type AxiosRequestInterceptor<T = any> = (
|
|
||||||
ins: RequestInterceptorConfig<T>,
|
|
||||||
mode: string,
|
|
||||||
) => void
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param error current request error instance
|
|
||||||
* @param mode current environment mode
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* axios request and response error interceptor.
|
|
||||||
* if you need create plugin with error interceptor, you can use this function type.
|
|
||||||
*/
|
|
||||||
export type FetchErrorFunction<T = any, D = any> = (
|
|
||||||
error: AxiosError<T, D>,
|
|
||||||
mode: string,
|
|
||||||
) => void
|
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-02-27
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 自动取消重复请求
|
* 自动取消重复请求
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-02
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** axios 拦截器工具 */
|
||||||
|
|
||||||
import type { RawAxiosRequestHeaders, AxiosRequestConfig } from 'axios'
|
import type { RawAxiosRequestHeaders, AxiosRequestConfig } from 'axios'
|
||||||
import type { RequestHeaderOptions } from '../types'
|
import type { RequestHeaderOptions } from '../types'
|
||||||
|
|
||||||
|
@ -1,3 +1,25 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-05
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* axios 拦截器注入
|
||||||
|
*
|
||||||
|
* 请求拦截器、响应拦截器
|
||||||
|
* 暴露启动方法调用所有已注册方法
|
||||||
|
*
|
||||||
|
* 该拦截器仅适合放置公共的 axios 拦截器操作, 并且采用队列形式管理请求拦截器的注入
|
||||||
|
* 所以在使用的时候, 需要按照约定格式进行参数传递
|
||||||
|
*/
|
||||||
|
|
||||||
import RequestCanceler from '@/axios/utils/RequestCanceler'
|
import RequestCanceler from '@/axios/utils/RequestCanceler'
|
||||||
import { getAppEnvironment } from '@/utils'
|
import { getAppEnvironment } from '@/utils'
|
||||||
|
|
||||||
@ -13,36 +35,31 @@ import type {
|
|||||||
import type { AnyFC } from '@/types'
|
import type { AnyFC } from '@/types'
|
||||||
import type { AxiosError } from 'axios'
|
import type { AxiosError } from 'axios'
|
||||||
|
|
||||||
// 当前请求的实例
|
/** 当前请求的实例 */
|
||||||
const axiosFetchInstance: AxiosFetchInstance = {
|
const axiosFetchInstance: AxiosFetchInstance = {
|
||||||
requestInstance: null,
|
requestInstance: null,
|
||||||
responseInstance: null,
|
responseInstance: null,
|
||||||
}
|
}
|
||||||
// 请求失败返回值
|
/** 请求失败返回值 */
|
||||||
const axiosFetchError: AxiosFetchError<AxiosError<unknown, unknown>> = {
|
const axiosFetchError: AxiosFetchError<AxiosError<unknown, unknown>> = {
|
||||||
requestError: null,
|
requestError: null,
|
||||||
responseError: null,
|
responseError: null,
|
||||||
}
|
}
|
||||||
// 请求队列(区分 resolve 与 reject 状态)
|
/** 请求队列(区分 resolve 与 reject 状态) */
|
||||||
const implement: ImplementQueue = {
|
const implement: ImplementQueue = {
|
||||||
implementRequestInterceptorArray: [],
|
implementRequestInterceptorArray: [],
|
||||||
implementResponseInterceptorArray: [],
|
implementResponseInterceptorArray: [],
|
||||||
}
|
}
|
||||||
// 请求失败队列
|
|
||||||
const errorImplement: ErrorImplementQueue = {
|
const errorImplement: ErrorImplementQueue = {
|
||||||
implementRequestInterceptorErrorArray: [],
|
implementRequestInterceptorErrorArray: [],
|
||||||
implementResponseInterceptorErrorArray: [],
|
implementResponseInterceptorErrorArray: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImplementKeys = keyof ImplementQueue
|
/** 取消器实例 */
|
||||||
|
|
||||||
type ErrorImplementKeys = keyof ErrorImplementQueue
|
|
||||||
|
|
||||||
// 取消器实例
|
|
||||||
export const axiosCanceler = new RequestCanceler()
|
export const axiosCanceler = new RequestCanceler()
|
||||||
|
|
||||||
export const useAxiosInterceptor = () => {
|
export const useAxiosInterceptor = () => {
|
||||||
// 创建拦截器实例
|
/** 创建拦截器实例 */
|
||||||
const createAxiosInstance = (
|
const createAxiosInstance = (
|
||||||
instance: RequestInterceptorConfig | ResponseInterceptorConfig,
|
instance: RequestInterceptorConfig | ResponseInterceptorConfig,
|
||||||
instanceKey: keyof AxiosFetchInstance,
|
instanceKey: keyof AxiosFetchInstance,
|
||||||
@ -54,33 +71,29 @@ export const useAxiosInterceptor = () => {
|
|||||||
instance as ResponseInterceptorConfig)
|
instance as ResponseInterceptorConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取当前实例
|
/** 获取当前实例 */
|
||||||
const getAxiosInstance = (instanceKey: keyof AxiosFetchInstance) => {
|
const getAxiosInstance = (instanceKey: keyof AxiosFetchInstance) => {
|
||||||
return axiosFetchInstance[instanceKey]
|
return axiosFetchInstance[instanceKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置注入方法队列
|
/** 设置注入方法队列 */
|
||||||
const setImplement = (
|
const setImplement = (
|
||||||
key: ImplementKeys | ErrorImplementKeys,
|
key: keyof ImplementQueue | keyof ErrorImplementQueue,
|
||||||
func: AnyFC[],
|
func: AnyFC[],
|
||||||
fetchType: FetchType,
|
fetchType: FetchType,
|
||||||
) => {
|
) => {
|
||||||
fetchType === 'ok'
|
fetchType === 'ok' ? (implement[key] = func) : (errorImplement[key] = func)
|
||||||
? (implement[key as ImplementKeys] = func)
|
|
||||||
: (errorImplement[key as ErrorImplementKeys] = func)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取队列中所有的所有拦截器方法
|
/** 获取队列中所有的所有拦截器方法 */
|
||||||
const getImplement = (
|
const getImplement = (
|
||||||
key: ImplementKeys | ErrorImplementKeys,
|
key: keyof ImplementQueue | keyof ErrorImplementQueue,
|
||||||
fetchType: FetchType,
|
fetchType: FetchType,
|
||||||
): AnyFC[] => {
|
): AnyFC[] => {
|
||||||
return fetchType === 'ok'
|
return fetchType === 'ok' ? implement[key] : errorImplement[key]
|
||||||
? implement[key as ImplementKeys]
|
|
||||||
: errorImplement[key as ErrorImplementKeys]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 队列执行器
|
/** 队列执行器 */
|
||||||
const implementer = (funcs: AnyFC[], ...args: any[]) => {
|
const implementer = (funcs: AnyFC[], ...args: any[]) => {
|
||||||
if (Array.isArray(funcs)) {
|
if (Array.isArray(funcs)) {
|
||||||
funcs.forEach((curr) => {
|
funcs.forEach((curr) => {
|
||||||
@ -91,16 +104,16 @@ export const useAxiosInterceptor = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求、响应前执行拦截器队列中的所有方法
|
/** 请求、响应前执行拦截器队列中的所有方法 */
|
||||||
const beforeFetch = (
|
const beforeFetch = (
|
||||||
key: keyof AxiosFetchInstance,
|
key: keyof AxiosFetchInstance,
|
||||||
implementKey: ImplementKeys | ErrorImplementKeys,
|
implementKey: keyof ImplementQueue | keyof ErrorImplementQueue,
|
||||||
fetchType: FetchType,
|
fetchType: FetchType,
|
||||||
) => {
|
) => {
|
||||||
const funcArr =
|
const funcArr =
|
||||||
fetchType === 'ok'
|
fetchType === 'ok'
|
||||||
? implement[implementKey as ImplementKeys]
|
? implement[implementKey]
|
||||||
: errorImplement[implementKey as ErrorImplementKeys]
|
: errorImplement[implementKey]
|
||||||
const instance = getAxiosInstance(key)
|
const instance = getAxiosInstance(key)
|
||||||
const { MODE } = getAppEnvironment()
|
const { MODE } = getAppEnvironment()
|
||||||
|
|
||||||
@ -109,11 +122,11 @@ export const useAxiosInterceptor = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求、响应错误时执行队列中所有方法
|
/** 请求、响应错误时执行队列中所有方法 */
|
||||||
const fetchError = (
|
const fetchError = (
|
||||||
key: keyof AxiosFetchError,
|
key: keyof AxiosFetchError,
|
||||||
error: AxiosError<unknown, unknown>,
|
error: AxiosError<unknown, unknown>,
|
||||||
errorImplementKey: ErrorImplementKeys,
|
errorImplementKey: keyof ErrorImplementQueue,
|
||||||
) => {
|
) => {
|
||||||
axiosFetchError[key] = error
|
axiosFetchError[key] = error
|
||||||
|
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2024-04-14
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
import { NSpin } from 'naive-ui'
|
import { NSpin } from 'naive-ui'
|
||||||
@ -5,7 +16,6 @@ import { NSpin } from 'naive-ui'
|
|||||||
import barcode from 'jsbarcode'
|
import barcode from 'jsbarcode'
|
||||||
import props from './props'
|
import props from './props'
|
||||||
import { completeSize, call } from '@/utils'
|
import { completeSize, call } from '@/utils'
|
||||||
import { useTemplateRef } from 'vue'
|
|
||||||
|
|
||||||
import type { WatchStopHandle } from 'vue'
|
import type { WatchStopHandle } from 'vue'
|
||||||
|
|
||||||
@ -13,9 +23,7 @@ export default defineComponent({
|
|||||||
name: 'RBarcode',
|
name: 'RBarcode',
|
||||||
props,
|
props,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const barcodeRef = useTemplateRef<HTMLCanvasElement | HTMLOrSVGElement>(
|
const barcodeRef = ref<HTMLCanvasElement | HTMLOrSVGElement>()
|
||||||
'barcodeRef',
|
|
||||||
)
|
|
||||||
const cssVars = computed(() => {
|
const cssVars = computed(() => {
|
||||||
const cssVar = {
|
const cssVar = {
|
||||||
'--r-barcode-width': completeSize(props.width),
|
'--r-barcode-width': completeSize(props.width),
|
@ -88,11 +88,13 @@ const props = {
|
|||||||
* @description
|
* @description
|
||||||
* 是否监听 text 变化,当 text 变化时,会重新生成条形码。
|
* 是否监听 text 变化,当 text 变化时,会重新生成条形码。
|
||||||
*
|
*
|
||||||
* @default true
|
* 但是,在条形码的使用场景中,text 变化的频率应该是比较低的,所以默认不开启。如果有需要,可以手动开启。
|
||||||
|
*
|
||||||
|
* @default false
|
||||||
*/
|
*/
|
||||||
watchText: {
|
watchText: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: false,
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
@ -79,9 +79,10 @@ const useChart = () => {
|
|||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* chart 是否已经销毁。
|
* chart 是否已经销毁。
|
||||||
* 如果销毁则返回 true,否则返回 false。
|
* 如果销毁则返回 true, 否则返回 false。
|
||||||
*/
|
*/
|
||||||
const isDisposed = () => !!getChartInstance().echartInst?.isDisposed()
|
const isDispose = () =>
|
||||||
|
!(echartInst && getChartInstance().echartInst.getDom())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -101,7 +102,7 @@ const useChart = () => {
|
|||||||
register,
|
register,
|
||||||
{
|
{
|
||||||
getChartInstance,
|
getChartInstance,
|
||||||
isDisposed,
|
isDispose,
|
||||||
dispose,
|
dispose,
|
||||||
render,
|
render,
|
||||||
},
|
},
|
@ -26,7 +26,7 @@ import { NCard } from 'naive-ui'
|
|||||||
import props from './props'
|
import props from './props'
|
||||||
import { throttle } from 'lodash-es'
|
import { throttle } from 'lodash-es'
|
||||||
import { completeSize, downloadBase64File, call, renderNode } from '@/utils'
|
import { completeSize, downloadBase64File, call, renderNode } from '@/utils'
|
||||||
import { getCustomEchartTheme, loadingOptions, setEchartOptions } from './utils'
|
import { setupChartTheme } from './utils'
|
||||||
import { APP_THEME } from '@/app-config'
|
import { APP_THEME } from '@/app-config'
|
||||||
import {
|
import {
|
||||||
useResizeObserver,
|
useResizeObserver,
|
||||||
@ -35,8 +35,6 @@ import {
|
|||||||
} from '@vueuse/core'
|
} from '@vueuse/core'
|
||||||
import { RMoreDropdown } from '@/components'
|
import { RMoreDropdown } from '@/components'
|
||||||
import { useSettingGetters } from '@/store'
|
import { useSettingGetters } from '@/store'
|
||||||
import { useTemplateRef } from 'vue'
|
|
||||||
import { USE_CHART_PROVIDER_KEY } from './config'
|
|
||||||
|
|
||||||
import type { WatchStopHandle } from 'vue'
|
import type { WatchStopHandle } from 'vue'
|
||||||
import type { AnyFC } from '@/types'
|
import type { AnyFC } from '@/types'
|
||||||
@ -48,8 +46,15 @@ import type {
|
|||||||
import type { ECharts, EChartsCoreOption } from 'echarts/core'
|
import type { ECharts, EChartsCoreOption } from 'echarts/core'
|
||||||
import type { DropdownProps, DropdownOption } from 'naive-ui'
|
import type { DropdownProps, DropdownOption } from 'naive-ui'
|
||||||
|
|
||||||
|
// setOption 默认配置项
|
||||||
|
const defaultChartOptions = {
|
||||||
|
notMerge: false,
|
||||||
|
lazyUpdate: true,
|
||||||
|
silent: false,
|
||||||
|
replaceMerge: [],
|
||||||
|
}
|
||||||
// 获取 chart 主题
|
// 获取 chart 主题
|
||||||
const echartThemes = getCustomEchartTheme()
|
const echartThemes = setupChartTheme()
|
||||||
// download 下载功能 key
|
// download 下载功能 key
|
||||||
const __CHART_DOWN_LOAD_CHART__ = '__R_CHART_DOWN_LOAD_CHART__'
|
const __CHART_DOWN_LOAD_CHART__ = '__R_CHART_DOWN_LOAD_CHART__'
|
||||||
|
|
||||||
@ -87,21 +92,14 @@ export default defineComponent({
|
|||||||
props,
|
props,
|
||||||
setup(props, { expose }) {
|
setup(props, { expose }) {
|
||||||
const { getAppTheme } = useSettingGetters()
|
const { getAppTheme } = useSettingGetters()
|
||||||
// echart 容器实例
|
const rayChartRef = ref<HTMLElement>() // echart 容器实例
|
||||||
const rayChartRef = useTemplateRef<HTMLElement>('rayChartRef')
|
const rayChartWrapperRef = ref<HTMLElement>() // echart 父容器实例
|
||||||
// echart 父容器实例
|
const echartInstanceRef = ref<ECharts>() // echart 实例
|
||||||
const rayChartWrapperRef = useTemplateRef<HTMLElement>('rayChartWrapperRef')
|
let resizeThrottleReturn: DebouncedFunc<AnyFC> | null // resize 防抖方法实例
|
||||||
// echart 实例
|
let resizeObserverReturn: UseResizeObserverReturn | null // resize observer 实例
|
||||||
const echartInstanceRef = shallowRef<ECharts>()
|
const { echartTheme } = APP_THEME // 当前配置主题
|
||||||
// resize 防抖方法实例
|
let watchThrottledCallback: WatchStopHandle | null // watch props 回调
|
||||||
let resizeThrottleReturn: DebouncedFunc<AnyFC> | null
|
let echartInst: ECharts | null // 无代理响应式代理缓存 echart inst
|
||||||
// resize observer 实例
|
|
||||||
let resizeObserverReturn: UseResizeObserverReturn | null
|
|
||||||
// 当前配置主题
|
|
||||||
const { echartTheme } = APP_THEME
|
|
||||||
// watch props 回调
|
|
||||||
let watchThrottledCallback: WatchStopHandle | null
|
|
||||||
// 下拉框配置项
|
|
||||||
const moreDropDownOptions = computed<DropdownProps['options']>(() => [
|
const moreDropDownOptions = computed<DropdownProps['options']>(() => [
|
||||||
{
|
{
|
||||||
label: '下载图片',
|
label: '下载图片',
|
||||||
@ -110,30 +108,22 @@ export default defineComponent({
|
|||||||
echartInstanceRef.value && echartInstanceRef.value.getDom()
|
echartInstanceRef.value && echartInstanceRef.value.getDom()
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
])
|
]) // 下拉框配置项
|
||||||
const cssVarsRef = computed(() => {
|
const cssVarsRef = computed(() => {
|
||||||
return {
|
return {
|
||||||
'--ray-chart-width': completeSize(props.width),
|
'--ray-chart-width': completeSize(props.width),
|
||||||
'--ray-chart-height': completeSize(props.height),
|
'--ray-chart-height': completeSize(props.height),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// 目标是否可见
|
const targetIsVisible = ref(false) // 目标是否可见
|
||||||
const targetIsVisible = ref(false)
|
let intersectionObserverReturn: UseIntersectionObserverReturn | null // intersectionObserver 实例
|
||||||
// intersectionObserver 实例
|
|
||||||
let intersectionObserverReturn: UseIntersectionObserverReturn | null
|
|
||||||
// 缓存一些配置信息
|
|
||||||
const __catch = {
|
|
||||||
aria: props.showAria,
|
|
||||||
}
|
|
||||||
const chartProvideOptions = inject(USE_CHART_PROVIDER_KEY, {})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 注册 `echart` 组件, 图利, 渲染器等
|
||||||
* 注册 echart 组件、图利、渲染器等。
|
|
||||||
*
|
*
|
||||||
* 会自动合并拓展 echart 组件。
|
* 会自动合并拓展 `echart` 组件
|
||||||
* 该方法必须在注册图表之前调用。
|
* 该方法必须在注册图表之前调用
|
||||||
*/
|
*/
|
||||||
const registerChartCore = async () => {
|
const registerChartCore = async () => {
|
||||||
use([
|
use([
|
||||||
@ -166,29 +156,19 @@ export default defineComponent({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 更具当前主题渲染 chart
|
||||||
* 更具当前主题渲染 chart。
|
|
||||||
*
|
*
|
||||||
* 如果手动配置了 theme 属性,autoChangeTheme 属性则会失效;
|
* 如果手动配置了 theme 属性,autoChangeTheme 属性则会失效
|
||||||
* 但是,如果配置 theme 属性为 default,则会根据当前主题色渲染 chart 默认主题。
|
* 但是,如果配置 theme 属性为 default,则会根据当前主题色渲染 chart 默认主题
|
||||||
*
|
*
|
||||||
* 当 Boolean(theme) 为 false,则会尝试获取 echartTheme 属性;
|
* 当 Boolean(theme) 为 false,则会尝试获取 echartTheme 属性
|
||||||
* 但是,如果未获取到 echartTheme 属性,则会使用默认样式。
|
* 但是,如果未获取到 echartTheme 属性,则会使用默认样式
|
||||||
*/
|
*/
|
||||||
const updateChartTheme = () => {
|
const updateChartTheme = () => {
|
||||||
const { theme: providerTheme } = chartProvideOptions || {}
|
if (echartInst?.getDom()) {
|
||||||
|
|
||||||
if (echartInstanceRef.value) {
|
|
||||||
destroyChart()
|
destroyChart()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果配置了全局配置主题,则忽略后面所有逻辑
|
|
||||||
if (providerTheme) {
|
|
||||||
renderChart(providerTheme)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.theme === 'default') {
|
if (props.theme === 'default') {
|
||||||
props.autoChangeTheme ? renderChart('dark') : renderChart('')
|
props.autoChangeTheme ? renderChart('dark') : renderChart('')
|
||||||
|
|
||||||
@ -219,61 +199,66 @@ export default defineComponent({
|
|||||||
*/
|
*/
|
||||||
const combineChartOptions = (ops: EChartsCoreOption) => {
|
const combineChartOptions = (ops: EChartsCoreOption) => {
|
||||||
let options = unref(ops)
|
let options = unref(ops)
|
||||||
|
|
||||||
const assign = (opts: object) => Object.assign({}, options, opts)
|
const assign = (opts: object) => Object.assign({}, options, opts)
|
||||||
|
|
||||||
// 拦截 aria 配置项
|
if (props.showAria) {
|
||||||
options = assign({
|
options = assign({
|
||||||
aria: {
|
aria: {
|
||||||
enabled: props.showAria,
|
enabled: true,
|
||||||
decal: {
|
decal: {
|
||||||
show: props.showAria,
|
show: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 渲染 `echart`
|
||||||
* 渲染 echart。
|
*
|
||||||
|
* 缓存两个实例
|
||||||
|
* 直接使用响应式代理实例会出现诡异的问题, 例如 `legend` 点击时报错
|
||||||
*/
|
*/
|
||||||
const renderChart = (theme: string = echartTheme) => {
|
const renderChart = (theme: string = echartTheme) => {
|
||||||
// 获取 dom 容器
|
/** 获取 dom 容器 */
|
||||||
const element = rayChartRef.value as HTMLElement
|
const element = rayChartRef.value as HTMLElement
|
||||||
// 获取配置项
|
/** 获取配置项 */
|
||||||
const options = combineChartOptions(props.options)
|
const options = combineChartOptions(props.options)
|
||||||
// 获取 dom 容器实际宽高
|
/** 获取 dom 容器实际宽高 */
|
||||||
const { height, width } = element.getBoundingClientRect()
|
const { height, width } = element.getBoundingClientRect()
|
||||||
const { onSuccess, onError } = props
|
const { onSuccess, onError } = props
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 注册 chart
|
/** 注册 chart */
|
||||||
echartInstanceRef.value = init(element, theme, {
|
echartInst = init(element, theme, {
|
||||||
// 如果款度为 0,则以 200px 填充
|
/** 如果款度为 0, 则以 200px 填充 */
|
||||||
width: width === 0 ? 200 : void 0,
|
width: width === 0 ? 200 : void 0,
|
||||||
// 如果高度为 0,则以 200px 填充
|
/** 如果高度为 0, 则以 200px 填充 */
|
||||||
height: height === 0 ? 200 : void 0,
|
height: height === 0 ? 200 : void 0,
|
||||||
})
|
})
|
||||||
|
echartInstanceRef.value = echartInst
|
||||||
|
|
||||||
// 渲染成功回调
|
// 渲染成功回调
|
||||||
if (onSuccess) {
|
if (onSuccess) {
|
||||||
call(onSuccess, echartInstanceRef.value)
|
call(onSuccess, echartInst)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是否强制下一队列渲染图表
|
// 是否强制下一队列渲染图表
|
||||||
if (props.nextTick) {
|
if (props.nextTick) {
|
||||||
echartInstanceRef.value.setOption({})
|
echartInst.setOption({})
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
options && echartInstanceRef.value?.setOption(options)
|
options && echartInst?.setOption(options)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
options && echartInstanceRef.value?.setOption(options)
|
options && echartInst?.setOption(options)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 渲染失败回调
|
/** 渲染失败回调 */
|
||||||
if (onError) {
|
if (onError) {
|
||||||
call(onError)
|
call(onError)
|
||||||
}
|
}
|
||||||
@ -294,29 +279,26 @@ export default defineComponent({
|
|||||||
* chart 是否已经销毁。
|
* chart 是否已经销毁。
|
||||||
* 如果销毁则返回 true, 否则返回 false。
|
* 如果销毁则返回 true, 否则返回 false。
|
||||||
*/
|
*/
|
||||||
const isDisposed = () => {
|
const isDispose = () => !(echartInst && echartInst.getDom())
|
||||||
return !!echartInstanceRef.value?.isDisposed()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* 销毁 chart 实例, 释放资源
|
||||||
* 销毁 chart 实例,释放资源。
|
|
||||||
*/
|
*/
|
||||||
const destroyChart = () => {
|
const destroyChart = () => {
|
||||||
if (!isDisposed()) {
|
if (!isDispose()) {
|
||||||
echartInstanceRef.value?.dispose()
|
echartInst!.clear()
|
||||||
|
echartInst!.dispose()
|
||||||
|
|
||||||
|
echartInstanceRef.value = void 0
|
||||||
|
echartInst = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 重置 echarts 尺寸 */
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* 重置 echarts 尺寸。
|
|
||||||
*/
|
|
||||||
const resizeChart = () => {
|
const resizeChart = () => {
|
||||||
if (echartInstanceRef.value) {
|
if (echartInst) {
|
||||||
echartInstanceRef.value.resize()
|
echartInst.resize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,16 +307,15 @@ export default defineComponent({
|
|||||||
* @param key moreDropDownOptions key
|
* @param key moreDropDownOptions key
|
||||||
* @param option moreDropDownOptions current click option
|
* @param option moreDropDownOptions current click option
|
||||||
*
|
*
|
||||||
* @description
|
* 预设 card 风格下拉框点击
|
||||||
* 预设 card 风格下拉框点击。
|
* 当前仅实现下载图片功能
|
||||||
* 当前仅实现下载图片功能。
|
|
||||||
*/
|
*/
|
||||||
const dropdownSelect = (key: string | number, option: DropdownOption) => {
|
const dropdownSelect = (key: string | number, option: DropdownOption) => {
|
||||||
if (key === __CHART_DOWN_LOAD_CHART__ && !isDisposed()) {
|
if (key === __CHART_DOWN_LOAD_CHART__ && !isDispose()) {
|
||||||
const { filename, ...args } = props.downloadOptions
|
const { filename, ...args } = props.downloadOptions
|
||||||
|
|
||||||
downloadBase64File(
|
downloadBase64File(
|
||||||
echartInstanceRef.value!.getDataURL(args),
|
echartInst!.getDataURL(args),
|
||||||
filename ?? `${new Date().getTime()}`,
|
filename ?? `${new Date().getTime()}`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -346,11 +327,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* 挂载 chart 方法。
|
|
||||||
*/
|
|
||||||
const mount = () => {
|
const mount = () => {
|
||||||
// 注册事件
|
// 注册事件
|
||||||
if (props.autoResize) {
|
if (props.autoResize) {
|
||||||
@ -372,7 +348,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 避免重复渲染
|
// 避免重复渲染
|
||||||
if (echartInstanceRef.value?.getDom()) {
|
if (echartInst?.getDom()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +357,7 @@ export default defineComponent({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据主题渲染 chart
|
// 渲染 chart
|
||||||
updateChartTheme()
|
updateChartTheme()
|
||||||
|
|
||||||
// 初始化完成后移除 intersectionObserver 监听
|
// 初始化完成后移除 intersectionObserver 监听
|
||||||
@ -390,16 +366,21 @@ export default defineComponent({
|
|||||||
// 注册 register,用于 useChart hook
|
// 注册 register,用于 useChart hook
|
||||||
const { onRegister } = props
|
const { onRegister } = props
|
||||||
|
|
||||||
if (onRegister && echartInstanceRef.value) {
|
if (onRegister && echartInst) {
|
||||||
call(onRegister, echartInstanceRef.value, mount, unmount)
|
call(onRegister, echartInst, mount, unmount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
if (props.intersectionObserver) {
|
||||||
*
|
intersectionObserverReturn = useIntersectionObserver(
|
||||||
* @description
|
props.intersectionObserverTarget || rayChartWrapperRef,
|
||||||
* 卸载 chart 方法。
|
([entry]) => {
|
||||||
*/
|
targetIsVisible.value = entry.isIntersecting
|
||||||
|
},
|
||||||
|
props.intersectionOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const unmount = () => {
|
const unmount = () => {
|
||||||
// 卸载 echarts
|
// 卸载 echarts
|
||||||
destroyChart()
|
destroyChart()
|
||||||
@ -414,17 +395,15 @@ export default defineComponent({
|
|||||||
resizeObserverReturn = null
|
resizeObserverReturn = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听全局主题变化,然后重新渲染对应主题 echarts
|
/** 监听全局主题变化, 然后重新渲染对应主题 echarts */
|
||||||
watch(
|
watch(
|
||||||
() => getAppTheme.value,
|
() => getAppTheme.value,
|
||||||
() => {
|
() => {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @description
|
* Q: 为什么需要重新卸载再渲染
|
||||||
* Q: 为什么需要重新卸载再渲染?
|
* A: 因为 echarts 官方文档并未提供动态渲染方法
|
||||||
* A: 因为 echarts 官方文档并未提供动态渲染方法。
|
* A: 虽然原型上有 setTheme 方法, 但是官方标记是仅限于在类 ECharts 中访问
|
||||||
* 虽然原型上有 setTheme 方法,但是官方标记是仅限于在类 ECharts 中访问。
|
|
||||||
* 所以,只能先卸载后重新渲染。
|
|
||||||
*/
|
*/
|
||||||
if (props.autoChangeTheme) {
|
if (props.autoChangeTheme) {
|
||||||
destroyChart()
|
destroyChart()
|
||||||
@ -432,19 +411,21 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 贴花跟随主题渲染
|
||||||
|
*
|
||||||
|
* 自动跟随模板主题或者指定主题皆可
|
||||||
|
*/
|
||||||
|
watch(
|
||||||
|
() => props.showAria,
|
||||||
|
() => {
|
||||||
|
destroyChart()
|
||||||
|
updateChartTheme()
|
||||||
|
},
|
||||||
|
)
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
// 是否启用了可视区域监听
|
/** 监听 options 变化 */
|
||||||
if (props.intersectionObserver) {
|
|
||||||
intersectionObserverReturn = useIntersectionObserver(
|
|
||||||
props.intersectionObserverTarget || rayChartWrapperRef,
|
|
||||||
([entry]) => {
|
|
||||||
targetIsVisible.value = entry.isIntersecting
|
|
||||||
},
|
|
||||||
props.intersectionOptions,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听 options 变化
|
|
||||||
if (props.watchOptions) {
|
if (props.watchOptions) {
|
||||||
watchThrottledCallback = watchThrottled(
|
watchThrottledCallback = watchThrottled(
|
||||||
() => props.options,
|
() => props.options,
|
||||||
@ -453,12 +434,12 @@ export default defineComponent({
|
|||||||
const options = combineChartOptions(ndata)
|
const options = combineChartOptions(ndata)
|
||||||
const setOpt = Object.assign(
|
const setOpt = Object.assign(
|
||||||
{},
|
{},
|
||||||
setEchartOptions(),
|
|
||||||
props.setChartOptions,
|
props.setChartOptions,
|
||||||
|
defaultChartOptions,
|
||||||
)
|
)
|
||||||
|
|
||||||
// 如果 options 发生变动更新 echarts
|
// 如果 options 发生变动更新 echarts
|
||||||
echartInstanceRef.value?.setOption(options, setOpt)
|
echartInst?.setOption(options, setOpt)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 深度监听 options
|
// 深度监听 options
|
||||||
@ -472,20 +453,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
// 监听 loading 变化
|
// 监听 loading 变化
|
||||||
props.loading
|
props.loading
|
||||||
? echartInstanceRef.value?.showLoading(
|
? echartInst?.showLoading(props.loadingOptions)
|
||||||
loadingOptions(props.loadingOptions),
|
: echartInst?.hideLoading()
|
||||||
)
|
|
||||||
: echartInstanceRef.value?.hideLoading()
|
|
||||||
|
|
||||||
// 贴花是否启用
|
|
||||||
if (props.showAria !== __catch.aria && echartInstanceRef.value) {
|
|
||||||
echartInstanceRef.value.setOption(combineChartOptions(props.options))
|
|
||||||
|
|
||||||
__catch.aria = props.showAria
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当前图表容器是否处于可见状态,如果可见则渲染图表
|
// 当前图表容器是否处于可见状态,如果可见则渲染图表
|
||||||
if (targetIsVisible.value && !isDisposed()) {
|
if (targetIsVisible.value) {
|
||||||
mount()
|
mount()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -532,7 +504,6 @@ export default defineComponent({
|
|||||||
style={[this.cssVarsRef]}
|
style={[this.cssVarsRef]}
|
||||||
contentStyle={contentStyle}
|
contentStyle={contentStyle}
|
||||||
bordered={bordered}
|
bordered={bordered}
|
||||||
embedded
|
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
default: renderNode(
|
default: renderNode(
|
||||||
@ -546,7 +517,7 @@ export default defineComponent({
|
|||||||
<RMoreDropdown
|
<RMoreDropdown
|
||||||
iconSize={18}
|
iconSize={18}
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
options={dropdownOptions || moreDropDownOptions}
|
options={dropdownOptions ?? moreDropDownOptions}
|
||||||
trigger="click"
|
trigger="click"
|
||||||
onSelect={dropdownSelect.bind(this)}
|
onSelect={dropdownSelect.bind(this)}
|
||||||
placement="bottom-end"
|
placement="bottom-end"
|
@ -1,4 +1,4 @@
|
|||||||
import { loadingOptions, setEchartOptions } from './utils'
|
import { loadingOptions } from './utils'
|
||||||
|
|
||||||
import type * as echarts from 'echarts/core' // echarts 核心模块
|
import type * as echarts from 'echarts/core' // echarts 核心模块
|
||||||
import type { PropType, VNode } from 'vue'
|
import type { PropType, VNode } from 'vue'
|
||||||
@ -192,8 +192,7 @@ const props = {
|
|||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* 是否启用 chart 无障碍模式。
|
* 是否启用 chart 无障碍模式。
|
||||||
* 该组建默认拦截 aria 配置项的 enabled 属性与 decal.show 属性。
|
* 启用该配置项后会覆盖 options 中的 aria。
|
||||||
* 也就意味着,你不能通过配置 options 管理该组件的无障碍模式,只能通过该配置项统一管理。
|
|
||||||
*
|
*
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
@ -345,7 +344,6 @@ const props = {
|
|||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* 是否将渲染放置下一个队列。
|
* 是否将渲染放置下一个队列。
|
||||||
* 该配置项在渲染很多图表的时候可以有很不错的性能提升。
|
|
||||||
*
|
*
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
@ -358,11 +356,16 @@ const props = {
|
|||||||
* @description
|
* @description
|
||||||
* 设置 setOptions 方法配置项。
|
* 设置 setOptions 方法配置项。
|
||||||
*
|
*
|
||||||
* @default {notMerge:true,lazyUpdate:true,silent:false,replaceMerge:[]}
|
* @default {notMerge:false,lazyUpdate:true,silent:false,replaceMerge:[]}
|
||||||
*/
|
*/
|
||||||
setChartOptions: {
|
setChartOptions: {
|
||||||
type: Object as PropType<SetOptionOpts>,
|
type: Object as PropType<SetOptionOpts>,
|
||||||
default: () => setEchartOptions(),
|
default: () => ({
|
||||||
|
notMerge: false,
|
||||||
|
lazyUpdate: true,
|
||||||
|
silent: false,
|
||||||
|
replaceMerge: [],
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
@ -1,7 +1,19 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-07-22
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ChartThemeRawArray,
|
ChartThemeRawArray,
|
||||||
ChartThemeRawModules,
|
ChartThemeRawModules,
|
||||||
} from '@/components/base/RChart/src/types'
|
LoadingOptions,
|
||||||
|
} from '@/components/RChart/src/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -18,7 +30,7 @@ import type {
|
|||||||
* 3. 选择 json 类型,然后复制
|
* 3. 选择 json 类型,然后复制
|
||||||
* 4. 在 echart-themes 包中创建对应的 json 文件,文件名为主题名称
|
* 4. 在 echart-themes 包中创建对应的 json 文件,文件名为主题名称
|
||||||
*/
|
*/
|
||||||
export const getCustomEchartTheme = () => {
|
export const setupChartTheme = () => {
|
||||||
// 获取所有主题
|
// 获取所有主题
|
||||||
const themeRawModules: Record<string, ChartThemeRawModules> =
|
const themeRawModules: Record<string, ChartThemeRawModules> =
|
||||||
import.meta.glob('@/app-config/echart-themes/**/*.json', {
|
import.meta.glob('@/app-config/echart-themes/**/*.json', {
|
||||||
@ -43,3 +55,35 @@ export const getCustomEchartTheme = () => {
|
|||||||
|
|
||||||
return rawThemes
|
return rawThemes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param options 加载自定义配置项
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* chart 加载配置项。
|
||||||
|
*
|
||||||
|
* @see https://echarts.apache.org/zh/api.html#echartsInstance.showLoading
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const options = loadingOptions({ ...LoadingOptions })
|
||||||
|
*/
|
||||||
|
export const loadingOptions = (options?: LoadingOptions) =>
|
||||||
|
Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
text: 'loading',
|
||||||
|
color: '#c23531',
|
||||||
|
textColor: '#000',
|
||||||
|
maskColor: 'rgba(255, 255, 255, 0.9)',
|
||||||
|
zlevel: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
showSpinner: true,
|
||||||
|
spinnerRadius: 10,
|
||||||
|
lineWidth: 5,
|
||||||
|
fontWeight: 'normal',
|
||||||
|
fontStyle: 'normal',
|
||||||
|
fontFamily: 'sans-serif',
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
)
|
@ -20,8 +20,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ray-collapse-grid__suffix--btn {
|
|
||||||
align-self: var(--r-collapse-grid-action-align);
|
|
||||||
}
|
|
||||||
}
|
}
|
99
src/components/RCollapseGrid/src/index.tsx
Normal file
99
src/components/RCollapseGrid/src/index.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2022-12-27
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* <https://www.naiveui.com/zh-CN/dark/components/grid>
|
||||||
|
*
|
||||||
|
* 可折叠操作栏
|
||||||
|
* 可以结合表单或者表格使用,让你快捷的实现高级搜索功能
|
||||||
|
*
|
||||||
|
* 该组件完全基于 `NGrid` `NGridItem` 实现, 所以需要在使用该组件时使用 `NGridItem` 包裹元素
|
||||||
|
*/
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
import { NCard, NGrid, NGridItem, NFlex } from 'naive-ui'
|
||||||
|
import { RIcon } from '@/components'
|
||||||
|
|
||||||
|
import { call } from '@/utils'
|
||||||
|
import props from './props'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RCollapseGrid',
|
||||||
|
props,
|
||||||
|
setup(props) {
|
||||||
|
const modelCollapsed = ref(!props.open)
|
||||||
|
|
||||||
|
const collapseClick = () => {
|
||||||
|
modelCollapsed.value = !modelCollapsed.value
|
||||||
|
|
||||||
|
const { onUpdateValue, 'onUpdate:value': _onUpdateValue } = props
|
||||||
|
|
||||||
|
if (onUpdateValue) {
|
||||||
|
call(onUpdateValue, modelCollapsed.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_onUpdateValue) {
|
||||||
|
call(_onUpdateValue, modelCollapsed.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CollapseIcon = () => (
|
||||||
|
<div class="collapse-icon" onClick={collapseClick.bind(this)}>
|
||||||
|
<span>
|
||||||
|
{modelCollapsed.value
|
||||||
|
? props.collapseToggleText[0]
|
||||||
|
: props.collapseToggleText[1]}
|
||||||
|
</span>
|
||||||
|
<RIcon
|
||||||
|
customClassName={`collapse-icon--arrow ${
|
||||||
|
modelCollapsed.value ? '' : 'collapse-icon--arrow__expanded'
|
||||||
|
}`}
|
||||||
|
name="expanded"
|
||||||
|
size="14"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
modelCollapsed,
|
||||||
|
collapseClick,
|
||||||
|
CollapseIcon,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<NCard bordered={this.bordered}>
|
||||||
|
{{
|
||||||
|
default: () => (
|
||||||
|
<NGrid
|
||||||
|
class="ray-collapse-grid"
|
||||||
|
{...this.$props}
|
||||||
|
collapsed={this.modelCollapsed}
|
||||||
|
xGap={this.xGap || 12}
|
||||||
|
yGap={this.yGap || 18}
|
||||||
|
collapsedRows={this.collapsedRows}
|
||||||
|
>
|
||||||
|
{this.$slots.default?.()}
|
||||||
|
<NGridItem suffix class="ray-collapse-grid__suffix--btn">
|
||||||
|
<NFlex justify="end" align="center">
|
||||||
|
{this.$slots.action?.()}
|
||||||
|
{this.CollapseIcon()}
|
||||||
|
</NFlex>
|
||||||
|
</NGridItem>
|
||||||
|
</NGrid>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
</NCard>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -1,32 +1,10 @@
|
|||||||
import { gridProps } from 'naive-ui'
|
import { gridProps } from 'naive-ui'
|
||||||
|
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import type { CollapseToggleText, ActionAlignType } from './types'
|
import type { CollapseToggleText } from './types'
|
||||||
import type { AnyFC, MaybeArray } from '@/types'
|
import type { AnyFC, MaybeArray } from '@/types'
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* 操作区域列数。
|
|
||||||
*
|
|
||||||
* @default 1
|
|
||||||
*/
|
|
||||||
actionSpan: {
|
|
||||||
type: Number,
|
|
||||||
default: 1,
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* 自定义操作按钮区域按钮列排列方式。
|
|
||||||
*
|
|
||||||
* @default end
|
|
||||||
*/
|
|
||||||
actionAlign: {
|
|
||||||
type: String as PropType<ActionAlignType>,
|
|
||||||
default: 'end',
|
|
||||||
},
|
|
||||||
open: {
|
open: {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -59,13 +37,13 @@ const props = {
|
|||||||
* 默认 `false`
|
* 默认 `false`
|
||||||
*/
|
*/
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: false,
|
||||||
},
|
},
|
||||||
onUpdateOpen: {
|
onUpdateValue: {
|
||||||
type: [Function, Array] as PropType<MaybeArray<(bool: boolean) => void>>,
|
type: [Function, Array] as PropType<MaybeArray<(bool: boolean) => void>>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
'onUpdate:open': {
|
'onUpdate:value': {
|
||||||
type: [Function, Array] as PropType<MaybeArray<(bool: boolean) => void>>,
|
type: [Function, Array] as PropType<MaybeArray<(bool: boolean) => void>>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
@ -1,3 +1 @@
|
|||||||
export type CollapseToggleText = [string | number, string | number]
|
export type CollapseToggleText = [string | number, string | number]
|
||||||
|
|
||||||
export type ActionAlignType = 'auto' | 'end' | 'center' | 'start'
|
|
51
src/components/RForm/src/Form.tsx
Normal file
51
src/components/RForm/src/Form.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2024-03-27
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NForm } from 'naive-ui'
|
||||||
|
|
||||||
|
import props from './props'
|
||||||
|
import { call } from '@/utils'
|
||||||
|
|
||||||
|
import type { RFormInst } from './types'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RForm',
|
||||||
|
props,
|
||||||
|
setup(props, { expose }) {
|
||||||
|
const formRef = ref<RFormInst>()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 主动调用 register 方法,满足 useForm 方法正常调用
|
||||||
|
const { onRegister } = props
|
||||||
|
|
||||||
|
if (onRegister && formRef.value) {
|
||||||
|
call(onRegister, formRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expose()
|
||||||
|
|
||||||
|
return {
|
||||||
|
formRef,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
const { $attrs, $props, $slots } = this
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NForm {...$attrs} {...$props} ref="formRef">
|
||||||
|
{{
|
||||||
|
...$slots,
|
||||||
|
}}
|
||||||
|
</NForm>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
114
src/components/RForm/src/hooks/useForm.ts
Normal file
114
src/components/RForm/src/hooks/useForm.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
|
import type {
|
||||||
|
RFormInst,
|
||||||
|
FormValidateCallback,
|
||||||
|
ShouldRuleBeApplied,
|
||||||
|
RFormRules,
|
||||||
|
} from '../types'
|
||||||
|
import type { Recordable } from '@/types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* 获取 RForm 实例。
|
||||||
|
* 让你能够便捷的调用相关的一些已封装方法。
|
||||||
|
*
|
||||||
|
* @warning
|
||||||
|
* 值得注意的是,必须手动调用 register 方法,否则不能正常使用。
|
||||||
|
* 在使用 相关 hooks 的时候,需要注意生命周期,确保 register 方法已经被调用与表格实例已经被初始化;
|
||||||
|
* 不要在父组件 create 阶段就去调用 hook,如果需要,请使用 nextTick 包裹。
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* defineComponent({
|
||||||
|
* setup() {
|
||||||
|
* const [register, { ...Hooks }] = useForm()
|
||||||
|
*
|
||||||
|
* return {
|
||||||
|
* register,
|
||||||
|
* ...Hooks,
|
||||||
|
* }
|
||||||
|
* },
|
||||||
|
* render() {
|
||||||
|
* const { register, ...Hooks } = this
|
||||||
|
*
|
||||||
|
* return <RForm onRegister={register} />
|
||||||
|
* },
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
const useForm = <T extends Recordable, R extends RFormRules>(
|
||||||
|
model?: T,
|
||||||
|
rules?: R,
|
||||||
|
) => {
|
||||||
|
const formRef = ref<RFormInst>()
|
||||||
|
|
||||||
|
const register = (inst: RFormInst) => {
|
||||||
|
if (inst) {
|
||||||
|
formRef.value = inst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormInstance = () => {
|
||||||
|
if (!formRef.value) {
|
||||||
|
throw new Error(
|
||||||
|
'[useForm]: form instance is not ready yet. if you are using useForm, please make sure you have called register method in onRegister event.',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return formRef.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* 验证表单,Promise rejection 的返回值类型是 FormValidationError[]。
|
||||||
|
*
|
||||||
|
* @see https://www.naiveui.com/zh-CN/dark/components/form#inline.vue
|
||||||
|
*/
|
||||||
|
const validate = (
|
||||||
|
callback?: FormValidateCallback,
|
||||||
|
shouldRuleBeApplied?: ShouldRuleBeApplied,
|
||||||
|
) => getFormInstance().validate.call(null, callback, shouldRuleBeApplied)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* 还原表单到未验证状态。
|
||||||
|
*
|
||||||
|
* @see https://www.naiveui.com/zh-CN/dark/components/form#Form-Methods
|
||||||
|
*/
|
||||||
|
const restoreValidation = () => getFormInstance().restoreValidation.call(null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* 获取表项中收集到的值的对象。
|
||||||
|
*
|
||||||
|
* 调用该方法时,需要确保初始化 useForm 方法的时候传入了 model,否则可能有意想不到的问题发生。
|
||||||
|
*/
|
||||||
|
const formModel = () => cloneDeep(model) || ({} as T)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* 获取验证表单项的规则。
|
||||||
|
*
|
||||||
|
* 调用该方法时,需要确保初始化 useForm 方法的时候传入了 rules,否则可能有意想不到的问题发生。
|
||||||
|
*/
|
||||||
|
const formRules = () => cloneDeep(rules) || ({} as R)
|
||||||
|
|
||||||
|
return [
|
||||||
|
register,
|
||||||
|
{
|
||||||
|
getFormInstance,
|
||||||
|
validate,
|
||||||
|
restoreValidation,
|
||||||
|
formModel,
|
||||||
|
formRules,
|
||||||
|
},
|
||||||
|
] as const
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseFormReturn = ReturnType<typeof useForm>
|
||||||
|
|
||||||
|
export default useForm
|
24
src/components/RForm/src/props.ts
Normal file
24
src/components/RForm/src/props.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { formProps } from 'naive-ui'
|
||||||
|
|
||||||
|
import type { MaybeArray } from '@/types'
|
||||||
|
import type { RFormInst } from './types'
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
...formProps,
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* RForm 注册挂载成功后触发的事件。
|
||||||
|
* 可以结合 useForm 方法中的 register 方法使用,然后便捷的使用 hooks。
|
||||||
|
*
|
||||||
|
* @default null
|
||||||
|
*/
|
||||||
|
onRegister: {
|
||||||
|
type: [Function, Array] as PropType<
|
||||||
|
MaybeArray<(formInst: RFormInst) => void>
|
||||||
|
>,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export default props
|
@ -8,12 +8,12 @@
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: var(--ray-icon-color);
|
fill: currentColor;
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
opacity: var(--ray-icon-depth);
|
opacity: var(--ray-icon-depth);
|
||||||
cursor: var(--ray-icon-cursor);
|
cursor: var(--ray-icon-cursor);
|
||||||
|
|
||||||
& svg[RayIconAttribute='ray-icon'] {
|
& svg[RayIconAttribute="ray-icon"] {
|
||||||
width: var(--ray-icon-width);
|
width: var(--ray-icon-width);
|
||||||
height: var(--ray-icon-height);
|
height: var(--ray-icon-height);
|
||||||
fill: currentColor;
|
fill: currentColor;
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-01-04
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
import { completeSize, call } from '@/utils'
|
import { completeSize, call } from '@/utils'
|
||||||
@ -18,7 +29,6 @@ export default defineComponent({
|
|||||||
: completeSize(props.size),
|
: completeSize(props.size),
|
||||||
'--ray-icon-depth': props.depth,
|
'--ray-icon-depth': props.depth,
|
||||||
'--ray-icon-cursor': props.cursor,
|
'--ray-icon-cursor': props.cursor,
|
||||||
'--ray-icon-color': props.color,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cssVar
|
return cssVar
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-10-27
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import type { MaybeArray } from '@/types'
|
import type { MaybeArray } from '@/types'
|
||||||
|
|
@ -1,3 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-06-09
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
import { NSpin } from 'naive-ui'
|
import { NSpin } from 'naive-ui'
|
||||||
@ -5,7 +16,6 @@ import { NSpin } from 'naive-ui'
|
|||||||
import { call, completeSize } from '@/utils'
|
import { call, completeSize } from '@/utils'
|
||||||
import props from './props'
|
import props from './props'
|
||||||
import { useEventListener } from '@vueuse/core'
|
import { useEventListener } from '@vueuse/core'
|
||||||
import { useTemplateRef } from 'vue'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'RIframe',
|
name: 'RIframe',
|
||||||
@ -20,7 +30,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return cssVar
|
return cssVar
|
||||||
})
|
})
|
||||||
const iframeRef = useTemplateRef<HTMLIFrameElement>('iframeRef')
|
const iframeRef = ref<HTMLIFrameElement>()
|
||||||
const spinShow = ref(true)
|
const spinShow = ref(true)
|
||||||
|
|
||||||
const iframeLoadSuccess = (e: Event) => {
|
const iframeLoadSuccess = (e: Event) => {
|
||||||
@ -67,13 +77,15 @@ export default defineComponent({
|
|||||||
...this.$slots,
|
...this.$slots,
|
||||||
default: () => (
|
default: () => (
|
||||||
<iframe
|
<iframe
|
||||||
class={['ray-iframe__container', this.iframeClass]}
|
class={['ray-iframe__container', this.wrapperClass]}
|
||||||
ref="iframeRef"
|
ref="iframeRef"
|
||||||
src={this.src}
|
src={this.src}
|
||||||
allow={this.allow}
|
allow={this.allow}
|
||||||
name={this.name}
|
name={this.name}
|
||||||
title={this.title}
|
title={this.title}
|
||||||
loading={typeof this.lazy === 'boolean' ? 'lazy' : this.lazy}
|
{...{
|
||||||
|
loading: this.lazy ? 'lazy' : null,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
@ -1,7 +1,17 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-10-03
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import type { MaybeArray } from '@/types'
|
import type { MaybeArray } from '@/types'
|
||||||
import type { SpinProps } from 'naive-ui'
|
import type { SpinProps } from 'naive-ui'
|
||||||
import type { Lazy } from './types'
|
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
src: {
|
src: {
|
||||||
@ -80,10 +90,10 @@ const props = {
|
|||||||
},
|
},
|
||||||
lazy: {
|
lazy: {
|
||||||
/** 是否延迟加载 iframe */
|
/** 是否延迟加载 iframe */
|
||||||
type: [Boolean, String] as PropType<boolean | Lazy>,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
iframeClass: {
|
wrapperClass: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
14
src/components/RIframe/src/types.ts
Normal file
14
src/components/RIframe/src/types.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-10-03
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface RIframeInst {
|
||||||
|
iframe: Ref<HTMLIFrameElement>
|
||||||
|
}
|
119
src/components/RModal/src/Modal.tsx
Normal file
119
src/components/RModal/src/Modal.tsx
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Ray <https://github.com/XiaoDaiGua-Ray>
|
||||||
|
*
|
||||||
|
* @date 2023-11-22
|
||||||
|
*
|
||||||
|
* @workspace ray-template
|
||||||
|
*
|
||||||
|
* @remark 今天也是元气满满撸代码的一天
|
||||||
|
*/
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
import { NModal } from 'naive-ui'
|
||||||
|
|
||||||
|
import props from './props'
|
||||||
|
import { completeSize, uuid } from '@/utils'
|
||||||
|
import { setupInteract } from './utils'
|
||||||
|
import {
|
||||||
|
FULLSCREEN_CARD_TYPE_CLASS,
|
||||||
|
R_MODAL_CLASS,
|
||||||
|
CSS_VARS_KEYS,
|
||||||
|
} from './constant'
|
||||||
|
|
||||||
|
import type interact from 'interactjs'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RModal',
|
||||||
|
props,
|
||||||
|
setup(props) {
|
||||||
|
const cssVars = computed(() => ({
|
||||||
|
[CSS_VARS_KEYS['width']]: completeSize(props.width ?? 600),
|
||||||
|
[CSS_VARS_KEYS['cardWidth']]: completeSize(props.cardWidth ?? 600),
|
||||||
|
[CSS_VARS_KEYS['dialogWidth']]: completeSize(props.dialogWidth ?? 446),
|
||||||
|
}))
|
||||||
|
const uuidEl = uuid()
|
||||||
|
let intractable: null | ReturnType<typeof interact>
|
||||||
|
// 记录拖拽的位置
|
||||||
|
const position = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
}
|
||||||
|
// 当前是否为预设 card 类型并且设置了 fullscreen
|
||||||
|
const isFullscreenCardType = computed(
|
||||||
|
() => props.preset === 'card' && props.fullscreen,
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.show,
|
||||||
|
(ndata) => {
|
||||||
|
if (
|
||||||
|
ndata &&
|
||||||
|
props.dad &&
|
||||||
|
(props.preset === 'card' || props.preset === 'dialog')
|
||||||
|
) {
|
||||||
|
nextTick(() => {
|
||||||
|
const target = document.getElementById(uuidEl)
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
setupInteract(target, {
|
||||||
|
preset: props.preset,
|
||||||
|
x: position.x,
|
||||||
|
y: position.y,
|
||||||
|
dargCallback: (x, y) => {
|
||||||
|
position.x = x
|
||||||
|
position.y = y
|
||||||
|
},
|
||||||
|
}).then((res) => {
|
||||||
|
intractable = res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.memo && target) {
|
||||||
|
target.style.transform = `translate(${position.x}px, ${position.y}px)`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
intractable?.unset()
|
||||||
|
|
||||||
|
intractable = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
cssVars,
|
||||||
|
isFullscreenCardType,
|
||||||
|
uuidEl,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
const { $props, $slots, $attrs } = this
|
||||||
|
const { preset, ...$otherProps } = $props
|
||||||
|
const { cssVars, uuidEl, isFullscreenCardType } = this
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NModal
|
||||||
|
class={[
|
||||||
|
R_MODAL_CLASS,
|
||||||
|
isFullscreenCardType ? FULLSCREEN_CARD_TYPE_CLASS : '',
|
||||||
|
]}
|
||||||
|
style={[cssVars, isFullscreenCardType ? `height: 100vh` : '']}
|
||||||
|
preset={preset}
|
||||||
|
{...{
|
||||||
|
id: uuidEl,
|
||||||
|
}}
|
||||||
|
{...$otherProps}
|
||||||
|
{...$attrs}
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
...$slots,
|
||||||
|
}}
|
||||||
|
</NModal>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -1,44 +1,18 @@
|
|||||||
import { useModal as useNaiveModal, NScrollbar } from 'naive-ui'
|
import { useModal as useNaiveModal } from 'naive-ui'
|
||||||
|
import { setupInteract } from '../utils'
|
||||||
import { queryElements, setStyle, completeSize, setClass } from '@/utils'
|
import { queryElements, setStyle, completeSize, setClass } from '@/utils'
|
||||||
import { R_MODAL_CLASS, CSS_VARS_KEYS } from '../constant'
|
import { R_MODAL_CLASS, CSS_VARS_KEYS } from '../constant'
|
||||||
|
|
||||||
import type { RModalProps } from '../types'
|
import type { RModalProps } from '../types'
|
||||||
|
|
||||||
|
interface UseModalCreateOptions extends Omit<RModalProps, 'memo'> {}
|
||||||
|
|
||||||
const useModal = () => {
|
const useModal = () => {
|
||||||
const { create: naiveCreate, destroyAll: naiveDestroyAll } = useNaiveModal()
|
const { create: naiveCreate, destroyAll: naiveDestroyAll } = useNaiveModal()
|
||||||
|
|
||||||
const create = (options: RModalProps) => {
|
const create = (options: UseModalCreateOptions) => {
|
||||||
const { content, ...rest } = options
|
const { preset, dad, fullscreen, width, cardWidth, dialogWidth } = options
|
||||||
let contentNode = content
|
const modalReactive = naiveCreate(options)
|
||||||
|
|
||||||
if (rest.preset === 'card' && rest.fullscreen) {
|
|
||||||
contentNode = () =>
|
|
||||||
h(
|
|
||||||
NScrollbar,
|
|
||||||
{
|
|
||||||
themeOverrides: {
|
|
||||||
color: 'rgba(0, 0, 0, 0)',
|
|
||||||
colorHover: 'rgba(0, 0, 0, 0)',
|
|
||||||
},
|
|
||||||
trigger: 'hover',
|
|
||||||
style: {
|
|
||||||
width: 'auto',
|
|
||||||
maxHeight:
|
|
||||||
'calc(var(--html-height) - 29px - var(--n-padding-bottom) - var(--n-padding-bottom) - var(--n-padding-top))',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
default: () =>
|
|
||||||
typeof content === 'function' ? content() : content,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { preset, fullscreen, width, cardWidth, dialogWidth } = options
|
|
||||||
const modalReactive = naiveCreate({
|
|
||||||
...rest,
|
|
||||||
content: contentNode,
|
|
||||||
})
|
|
||||||
const { key } = modalReactive
|
const { key } = modalReactive
|
||||||
const cssVars = {
|
const cssVars = {
|
||||||
[CSS_VARS_KEYS['width']]: completeSize(width ?? 600),
|
[CSS_VARS_KEYS['width']]: completeSize(width ?? 600),
|
||||||
@ -54,6 +28,15 @@ const useModal = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否启用拖拽
|
||||||
|
if (dad) {
|
||||||
|
setupInteract(modalElement, {
|
||||||
|
preset,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// preset 为 card,fullscreen 为 true 时,最大化 modal
|
// preset 为 card,fullscreen 为 true 时,最大化 modal
|
||||||
if (fullscreen && preset === 'card') {
|
if (fullscreen && preset === 'card') {
|
||||||
setStyle(modalElement, {
|
setStyle(modalElement, {
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user