ant3
parent
1f265d6b85
commit
dbdc655406
12
.eslintrc.js
12
.eslintrc.js
|
|
@ -1,6 +1,4 @@
|
||||||
// @ts-check
|
module.exports = {
|
||||||
const { defineConfig } = require('eslint-define-config');
|
|
||||||
module.exports = defineConfig({
|
|
||||||
root: true,
|
root: true,
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
|
|
@ -20,9 +18,7 @@ module.exports = defineConfig({
|
||||||
extends: [
|
extends: [
|
||||||
'plugin:vue/vue3-recommended',
|
'plugin:vue/vue3-recommended',
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'prettier',
|
|
||||||
'plugin:prettier/recommended',
|
'plugin:prettier/recommended',
|
||||||
'plugin:jest/recommended',
|
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
'vue/script-setup-uses-vars': 'error',
|
'vue/script-setup-uses-vars': 'error',
|
||||||
|
|
@ -55,8 +51,6 @@ module.exports = defineConfig({
|
||||||
'space-before-function-paren': 'off',
|
'space-before-function-paren': 'off',
|
||||||
|
|
||||||
'vue/attributes-order': 'off',
|
'vue/attributes-order': 'off',
|
||||||
'vue/v-on-event-hyphenation': 'off',
|
|
||||||
'vue/multi-word-component-names': 'off',
|
|
||||||
'vue/one-component-per-file': 'off',
|
'vue/one-component-per-file': 'off',
|
||||||
'vue/html-closing-bracket-newline': 'off',
|
'vue/html-closing-bracket-newline': 'off',
|
||||||
'vue/max-attributes-per-line': 'off',
|
'vue/max-attributes-per-line': 'off',
|
||||||
|
|
@ -64,6 +58,7 @@ module.exports = defineConfig({
|
||||||
'vue/singleline-html-element-content-newline': 'off',
|
'vue/singleline-html-element-content-newline': 'off',
|
||||||
'vue/attribute-hyphenation': 'off',
|
'vue/attribute-hyphenation': 'off',
|
||||||
'vue/require-default-prop': 'off',
|
'vue/require-default-prop': 'off',
|
||||||
|
'vue/require-explicit-emits': 'off',
|
||||||
'vue/html-self-closing': [
|
'vue/html-self-closing': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
|
@ -76,5 +71,6 @@ module.exports = defineConfig({
|
||||||
math: 'always',
|
math: 'always',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,7 @@ pnpm-debug.log*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
pnpm-lock.yaml
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@ ports:
|
||||||
- port: 3344
|
- port: 3344
|
||||||
onOpen: open-preview
|
onOpen: open-preview
|
||||||
tasks:
|
tasks:
|
||||||
- init: yarn
|
- init: pnpm install
|
||||||
command: yarn dev
|
command: pnpm run dev
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# shellcheck source=./_/husky.sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
# npx --no-install commitlint --edit "$1"
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
command_exists () {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Workaround for Windows 10, Git Bash and Yarn
|
||||||
|
if command_exists winpty && test -t 1; then
|
||||||
|
exec < /dev/tty
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
. "$(dirname "$0")/common.sh"
|
||||||
|
|
||||||
|
[ -n "$CI" ] && exit 0
|
||||||
|
|
||||||
|
# Format and submit code according to lintstagedrc.js configuration
|
||||||
|
npm run lint:lint-staged
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"octref.vetur",
|
"vue.volar",
|
||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"stylelint.vscode-stylelint",
|
"stylelint.vscode-stylelint",
|
||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
{
|
{
|
||||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
|
||||||
"volar.tsPlugin": true,
|
"volar.tsPlugin": true,
|
||||||
"volar.tsPluginStatus": false,
|
"volar.tsPluginStatus": false,
|
||||||
//===========================================
|
"npm.packageManager": "pnpm",
|
||||||
//============= Editor ======================
|
|
||||||
//===========================================
|
|
||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
//===========================================
|
|
||||||
//============= files =======================
|
|
||||||
//===========================================
|
|
||||||
"files.eol": "\n",
|
"files.eol": "\n",
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"**/node_modules": true,
|
"**/node_modules": true,
|
||||||
|
|
@ -61,7 +55,7 @@
|
||||||
"**/yarn.lock": true
|
"**/yarn.lock": true
|
||||||
},
|
},
|
||||||
"stylelint.enable": true,
|
"stylelint.enable": true,
|
||||||
"stylelint.packageManager": "yarn",
|
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"],
|
||||||
"path-intellisense.mappings": {
|
"path-intellisense.mappings": {
|
||||||
"/@/": "${workspaceRoot}/src"
|
"/@/": "${workspaceRoot}/src"
|
||||||
},
|
},
|
||||||
|
|
@ -94,7 +88,8 @@
|
||||||
},
|
},
|
||||||
"[vue]": {
|
"[vue]": {
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": false
|
"source.fixAll.eslint": true,
|
||||||
|
"source.fixAll.stylelint": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"i18n-ally.localesPaths": ["src/locales/lang"],
|
"i18n-ally.localesPaths": ["src/locales/lang"],
|
||||||
|
|
@ -114,7 +109,6 @@
|
||||||
"esnext",
|
"esnext",
|
||||||
"antv",
|
"antv",
|
||||||
"tinymce",
|
"tinymce",
|
||||||
"qrcode",
|
|
||||||
"sider",
|
"sider",
|
||||||
"pinia",
|
"pinia",
|
||||||
"sider",
|
"sider",
|
||||||
|
|
@ -137,6 +131,11 @@
|
||||||
"lintstagedrc",
|
"lintstagedrc",
|
||||||
"brotli",
|
"brotli",
|
||||||
"tailwindcss",
|
"tailwindcss",
|
||||||
"sider"
|
"sider",
|
||||||
]
|
"pnpm",
|
||||||
|
"antd"
|
||||||
|
],
|
||||||
|
"vetur.format.scriptInitialIndent": true,
|
||||||
|
"vetur.format.styleInitialIndent": true,
|
||||||
|
"vetur.validation.script": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
.yarnclean
48
.yarnclean
|
|
@ -1,48 +0,0 @@
|
||||||
# test directories
|
|
||||||
__tests__
|
|
||||||
test
|
|
||||||
tests
|
|
||||||
powered-test
|
|
||||||
|
|
||||||
# asset directories
|
|
||||||
docs
|
|
||||||
doc
|
|
||||||
website
|
|
||||||
images
|
|
||||||
assets
|
|
||||||
|
|
||||||
# examples
|
|
||||||
example
|
|
||||||
examples
|
|
||||||
|
|
||||||
# code coverage directories
|
|
||||||
coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# build scripts
|
|
||||||
Makefile
|
|
||||||
Gulpfile.js
|
|
||||||
Gruntfile.js
|
|
||||||
|
|
||||||
# configs
|
|
||||||
appveyor.yml
|
|
||||||
circle.yml
|
|
||||||
codeship-services.yml
|
|
||||||
codeship-steps.yml
|
|
||||||
wercker.yml
|
|
||||||
.tern-project
|
|
||||||
.gitattributes
|
|
||||||
.editorconfig
|
|
||||||
.*ignore
|
|
||||||
.eslintrc
|
|
||||||
.jshintrc
|
|
||||||
.flowconfig
|
|
||||||
.documentup.json
|
|
||||||
.yarn-metadata.json
|
|
||||||
.travis.yml
|
|
||||||
|
|
||||||
# misc
|
|
||||||
*.md
|
|
||||||
|
|
||||||
!istanbul-reports/lib/html/assets
|
|
||||||
!istanbul-api/node_modules/istanbul-reports/lib/html/assets
|
|
||||||
102
README.md
102
README.md
|
|
@ -1 +1,101 @@
|
||||||
## 隆昌农业
|
<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="200" height="200" src="https://anncwb.github.io/anncwb/images/logo.png"> </a> <br> <br>
|
||||||
|
|
||||||
|
[](LICENSE)
|
||||||
|
|
||||||
|
<h1>Vue vben admin</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|
精简 Vue Vben Admin。
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
- **最新技术栈**:使用 Vue3/vite2 等前端前沿技术开发
|
||||||
|
- **TypeScript**: 应用程序级 JavaScript 的语言
|
||||||
|
- **主题**:可配置的主题
|
||||||
|
- **国际化**:内置完善的国际化方案
|
||||||
|
- **Mock 数据** 内置 Mock 数据方案
|
||||||
|
- **权限** 内置完善的动态路由权限生成方案
|
||||||
|
- **组件** 二次封装了多个常用的组件
|
||||||
|
|
||||||
|
## 预览
|
||||||
|
|
||||||
|
- [vue-vben-admin](https://vvbin.cn/next/) - 完整版中文站点
|
||||||
|
- [vue-vben-admin-gh-pages](https://anncwb.github.io/vue-vben-admin/) - 完整版 github 站点
|
||||||
|
- [vben-admin-thin-next](https://vvbin.cn/thin/next/) - 简化版中文站点
|
||||||
|
- [vben-admin-thin-gh-pages](https://anncwb.github.io/vben-admin-thin-next/) - 简化版 github 站点
|
||||||
|
|
||||||
|
## 准备
|
||||||
|
|
||||||
|
- [node](http://nodejs.org/) 和 [git](https://git-scm.com/) -项目开发环境
|
||||||
|
- [Vite](https://vitejs.dev/) - 熟悉 vite 特性
|
||||||
|
- [Vue3](https://v3.vuejs.org/) - 熟悉 Vue 基础语法
|
||||||
|
- [TypeScript](https://www.typescriptlang.org/) - 熟悉`TypeScript`基本语法
|
||||||
|
- [Es6+](http://es6.ruanyifeng.com/) - 熟悉 es6 基本语法
|
||||||
|
- [Vue-Router-Next](https://next.router.vuejs.org/) - 熟悉 vue-router 基本使用
|
||||||
|
- [Ant-Design-Vue](https://2x.antdv.com/docs/vue/introduce-cn/) - ui 基本使用
|
||||||
|
- [Mock.js](https://github.com/nuysoft/Mock) - mockjs 基本语法
|
||||||
|
|
||||||
|
## 安装使用
|
||||||
|
|
||||||
|
- 获取项目代码
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/anncwb/vue-vben-admin.git
|
||||||
|
```
|
||||||
|
|
||||||
|
- 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd vue-vben-admin
|
||||||
|
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
- 运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm serve
|
||||||
|
```
|
||||||
|
|
||||||
|
- 打包
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Git 贡献提交规范
|
||||||
|
|
||||||
|
- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 规范 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
|
||||||
|
|
||||||
|
- `feat` 增加新功能
|
||||||
|
- `fix` 修复问题/BUG
|
||||||
|
- `style` 代码风格相关无影响运行结果的
|
||||||
|
- `perf` 优化/性能提升
|
||||||
|
- `refactor` 重构
|
||||||
|
- `revert` 撤销修改
|
||||||
|
- `test` 测试相关
|
||||||
|
- `docs` 文档/注释
|
||||||
|
- `chore` 依赖更新/脚手架配置修改等
|
||||||
|
- `workflow` 工作流改进
|
||||||
|
- `ci` 持续集成
|
||||||
|
- `types` 类型定义文件更改
|
||||||
|
- `wip` 开发中
|
||||||
|
|
||||||
|
## 相关仓库
|
||||||
|
|
||||||
|
如果这些插件对你有帮助,可以给一个 star 支持下
|
||||||
|
|
||||||
|
- [vite-plugin-mock](https://github.com/anncwb/vite-plugin-mock) - 用于本地及开发环境数据 mock
|
||||||
|
- [vite-plugin-html](https://github.com/anncwb/vite-plugin-html) - 用于 html 模版转换及压缩
|
||||||
|
- [vite-plugin-style-import](https://github.com/anncwb/vite-plugin-style-import) - 用于组件库样式按需引入
|
||||||
|
- [vite-plugin-theme](https://github.com/anncwb/vite-plugin-theme) - 用于在线切换主题色等颜色相关配置
|
||||||
|
- [vite-plugin-imagemin](https://github.com/anncwb/vite-plugin-imagemin) - 用于打包压缩图片资源
|
||||||
|
- [vite-plugin-compression](https://github.com/anncwb/vite-plugin-compression) - 用于打包输出.gz|.brotil 文件
|
||||||
|
- [vite-plugin-svg-icons](https://github.com/anncwb/vite-plugin-svg-icons) - 用于快速生成 svg 雪碧图
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT © Vben-2020](./LICENSE)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { generate } from '@ant-design/colors';
|
import { generate } from '@ant-design/colors';
|
||||||
|
|
||||||
export const primaryColor = '#4ba06c';
|
export const primaryColor = '#0960bd';
|
||||||
|
|
||||||
export const darkMode = 'light';
|
export const darkMode = 'light';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import inquirer from 'inquirer';
|
import inquirer from 'inquirer';
|
||||||
import chalk from 'chalk';
|
import colors from 'picocolors';
|
||||||
import pkg from '../../../package.json';
|
import pkg from '../../../package.json';
|
||||||
|
|
||||||
async function generateIcon() {
|
async function generateIcon() {
|
||||||
|
|
@ -64,7 +64,7 @@ async function generateIcon() {
|
||||||
}
|
}
|
||||||
fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite'));
|
fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite'));
|
||||||
console.log(
|
console.log(
|
||||||
`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`,
|
`✨ ${colors.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant';
|
import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant';
|
||||||
import fs, { writeFileSync } from 'fs-extra';
|
import fs, { writeFileSync } from 'fs-extra';
|
||||||
import chalk from 'chalk';
|
import colors from 'picocolors';
|
||||||
|
|
||||||
import { getEnvConfig, getRootPath } from '../utils';
|
import { getEnvConfig, getRootPath } from '../utils';
|
||||||
import { getConfigFileName } from '../getConfigFileName';
|
import { getConfigFileName } from '../getConfigFileName';
|
||||||
|
|
@ -21,20 +21,22 @@ function createConfig(params: CreateConfigParams) {
|
||||||
try {
|
try {
|
||||||
const windowConf = `window.${configName}`;
|
const windowConf = `window.${configName}`;
|
||||||
// Ensure that the variable will not be modified
|
// Ensure that the variable will not be modified
|
||||||
const configStr = `${windowConf}=${JSON.stringify(config)};
|
let configStr = `${windowConf}=${JSON.stringify(config)};`;
|
||||||
|
configStr += `
|
||||||
Object.freeze(${windowConf});
|
Object.freeze(${windowConf});
|
||||||
Object.defineProperty(window, "${configName}", {
|
Object.defineProperty(window, "${configName}", {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
});
|
});
|
||||||
`.replace(/\s/g, '');
|
`.replace(/\s/g, '');
|
||||||
|
|
||||||
fs.mkdirp(getRootPath(OUTPUT_DIR));
|
fs.mkdirp(getRootPath(OUTPUT_DIR));
|
||||||
writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr);
|
writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr);
|
||||||
|
|
||||||
console.log(chalk.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`);
|
console.log(colors.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`);
|
||||||
console.log(chalk.gray(OUTPUT_DIR + '/' + chalk.green(configFileName)) + '\n');
|
console.log(colors.gray(OUTPUT_DIR + '/' + colors.green(configFileName)) + '\n');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(chalk.red('configuration file configuration file failed to package:\n' + error));
|
console.log(colors.red('configuration file configuration file failed to package:\n' + error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// #!/usr/bin/env node
|
// #!/usr/bin/env node
|
||||||
|
|
||||||
import { runBuildConfig } from './buildConf';
|
import { runBuildConfig } from './buildConf';
|
||||||
import chalk from 'chalk';
|
import colors from 'picocolors';
|
||||||
|
|
||||||
import pkg from '../../package.json';
|
import pkg from '../../package.json';
|
||||||
|
|
||||||
|
|
@ -14,9 +14,9 @@ export const runBuild = async () => {
|
||||||
runBuildConfig();
|
runBuildConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!');
|
console.log(`✨ ${colors.cyan(`[${pkg.name}]`)}` + ' - build successfully!');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(chalk.red('vite build error:\n' + error));
|
console.log(colors.red('vite build error:\n' + error));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
// TODO
|
|
||||||
import type { GetManualChunk } from 'rollup';
|
|
||||||
|
|
||||||
//
|
|
||||||
const vendorLibs: { match: string[]; output: string }[] = [
|
|
||||||
// {
|
|
||||||
// match: ['xlsx'],
|
|
||||||
// output: 'xlsx',
|
|
||||||
// },
|
|
||||||
];
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
export const configManualChunk: GetManualChunk = (id: string) => {
|
|
||||||
if (/[\\/]node_modules[\\/]/.test(id)) {
|
|
||||||
const matchItem = vendorLibs.find((item) => {
|
|
||||||
const reg = new RegExp(`[\\/]node_modules[\\/]_?(${item.match.join('|')})(.*)`, 'ig');
|
|
||||||
return reg.test(id);
|
|
||||||
});
|
|
||||||
return matchItem ? matchItem.output : null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated
|
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated
|
||||||
* https://github.com/anncwb/vite-plugin-compression
|
* https://github.com/anncwb/vite-plugin-compression
|
||||||
*/
|
*/
|
||||||
import type { Plugin } from 'vite';
|
import type { PluginOption } from 'vite';
|
||||||
import compressPlugin from 'vite-plugin-compression';
|
import compressPlugin from 'vite-plugin-compression';
|
||||||
|
|
||||||
export function configCompressPlugin(
|
export function configCompressPlugin(
|
||||||
compress: 'gzip' | 'brotli' | 'none',
|
compress: 'gzip' | 'brotli' | 'none',
|
||||||
deleteOriginFile = false,
|
deleteOriginFile = false,
|
||||||
): Plugin | Plugin[] {
|
): PluginOption | PluginOption[] {
|
||||||
const compressList = compress.split(',');
|
const compressList = compress.split(',');
|
||||||
|
|
||||||
const plugins: Plugin[] = [];
|
const plugins: PluginOption[] = [];
|
||||||
|
|
||||||
if (compressList.includes('gzip')) {
|
if (compressList.includes('gzip')) {
|
||||||
plugins.push(
|
plugins.push(
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
import type { Plugin } from 'vite';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* Temporarily solve the Vite circular dependency problem, and wait for a better solution to fix it later. I don't know what problems this writing will bring.
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function configHmrPlugin(): Plugin {
|
|
||||||
return {
|
|
||||||
name: 'singleHMR',
|
|
||||||
handleHotUpdate({ modules, file }) {
|
|
||||||
if (file.match(/xml$/)) return [];
|
|
||||||
|
|
||||||
modules.forEach((m) => {
|
|
||||||
if (!m.url.match(/\.(css|less)/)) {
|
|
||||||
m.importedModules = new Set();
|
|
||||||
m.importers = new Set();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return modules;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
* Plugin to minimize and use ejs template syntax in index.html.
|
* Plugin to minimize and use ejs template syntax in index.html.
|
||||||
* https://github.com/anncwb/vite-plugin-html
|
* https://github.com/anncwb/vite-plugin-html
|
||||||
*/
|
*/
|
||||||
import type { Plugin } from 'vite';
|
import type { PluginOption } from 'vite';
|
||||||
import html from 'vite-plugin-html';
|
import { createHtmlPlugin } from 'vite-plugin-html';
|
||||||
import pkg from '../../../package.json';
|
import pkg from '../../../package.json';
|
||||||
import { GLOB_CONFIG_FILE_NAME } from '../../constant';
|
import { GLOB_CONFIG_FILE_NAME } from '../../constant';
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
|
||||||
return `${path || '/'}${GLOB_CONFIG_FILE_NAME}?v=${pkg.version}-${new Date().getTime()}`;
|
return `${path || '/'}${GLOB_CONFIG_FILE_NAME}?v=${pkg.version}-${new Date().getTime()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const htmlPlugin: Plugin[] = html({
|
const htmlPlugin: PluginOption[] = createHtmlPlugin({
|
||||||
minify: isBuild,
|
minify: isBuild,
|
||||||
inject: {
|
inject: {
|
||||||
// Inject data into ejs template
|
// Inject data into ejs template
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import type { Plugin } from 'vite';
|
import { PluginOption } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue'
|
||||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||||
import legacy from '@vitejs/plugin-legacy';
|
import legacy from '@vitejs/plugin-legacy'
|
||||||
import purgeIcons from 'vite-plugin-purge-icons';
|
import purgeIcons from 'vite-plugin-purge-icons'
|
||||||
import windiCSS from 'vite-plugin-windicss';
|
import windiCSS from 'vite-plugin-windicss'
|
||||||
import vueSetupExtend from 'vite-plugin-vue-setup-extend';
|
import VitePluginCertificate from 'vite-plugin-mkcert'
|
||||||
import { configHtmlPlugin } from './html';
|
//import vueSetupExtend from 'vite-plugin-vue-setup-extend';
|
||||||
import { configPwaConfig } from './pwa';
|
import { configHtmlPlugin } from './html'
|
||||||
import { configMockPlugin } from './mock';
|
import { configPwaConfig } from './pwa'
|
||||||
import { configCompressPlugin } from './compress';
|
import { configMockPlugin } from './mock'
|
||||||
import { configStyleImportPlugin } from './styleImport';
|
import { configCompressPlugin } from './compress'
|
||||||
import { configVisualizerConfig } from './visualizer';
|
import { configStyleImportPlugin } from './styleImport'
|
||||||
import { configThemePlugin } from './theme';
|
import { configVisualizerConfig } from './visualizer'
|
||||||
import { configImageminPlugin } from './imagemin';
|
import { configThemePlugin } from './theme'
|
||||||
import { configSvgIconsPlugin } from './svgSprite';
|
import { configImageminPlugin } from './imagemin'
|
||||||
import { configHmrPlugin } from './hmr';
|
import { configSvgIconsPlugin } from './svgSprite'
|
||||||
|
|
||||||
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
||||||
const {
|
const {
|
||||||
|
|
@ -23,60 +23,60 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
||||||
VITE_LEGACY,
|
VITE_LEGACY,
|
||||||
VITE_BUILD_COMPRESS,
|
VITE_BUILD_COMPRESS,
|
||||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE,
|
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE,
|
||||||
} = viteEnv;
|
} = viteEnv
|
||||||
|
|
||||||
const vitePlugins: (Plugin | Plugin[])[] = [
|
const vitePlugins: (PluginOption | PluginOption[])[] = [
|
||||||
// have to
|
// have to
|
||||||
vue(),
|
vue(),
|
||||||
// have to
|
// have to
|
||||||
vueJsx(),
|
vueJsx(),
|
||||||
// support name
|
// support name
|
||||||
vueSetupExtend(),
|
//vueSetupExtend(),
|
||||||
];
|
VitePluginCertificate({
|
||||||
|
source: 'coding',
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
// vite-plugin-windicss
|
// vite-plugin-windicss
|
||||||
vitePlugins.push(windiCSS());
|
vitePlugins.push(windiCSS())
|
||||||
|
|
||||||
// TODO
|
|
||||||
!isBuild && vitePlugins.push(configHmrPlugin());
|
|
||||||
|
|
||||||
// @vitejs/plugin-legacy
|
// @vitejs/plugin-legacy
|
||||||
VITE_LEGACY && isBuild && vitePlugins.push(legacy());
|
VITE_LEGACY && isBuild && vitePlugins.push(legacy())
|
||||||
|
|
||||||
// vite-plugin-html
|
// vite-plugin-html
|
||||||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
|
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild))
|
||||||
|
|
||||||
// vite-plugin-svg-icons
|
// vite-plugin-svg-icons
|
||||||
vitePlugins.push(configSvgIconsPlugin(isBuild));
|
vitePlugins.push(configSvgIconsPlugin(isBuild))
|
||||||
|
|
||||||
// vite-plugin-mock
|
// vite-plugin-mock
|
||||||
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild));
|
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild))
|
||||||
|
|
||||||
// vite-plugin-purge-icons
|
// vite-plugin-purge-icons
|
||||||
vitePlugins.push(purgeIcons());
|
vitePlugins.push(purgeIcons())
|
||||||
|
|
||||||
// vite-plugin-style-import
|
// vite-plugin-style-import
|
||||||
vitePlugins.push(configStyleImportPlugin(isBuild));
|
vitePlugins.push(configStyleImportPlugin(isBuild))
|
||||||
|
|
||||||
// rollup-plugin-visualizer
|
// rollup-plugin-visualizer
|
||||||
vitePlugins.push(configVisualizerConfig());
|
vitePlugins.push(configVisualizerConfig())
|
||||||
|
|
||||||
//vite-plugin-theme
|
// vite-plugin-theme
|
||||||
vitePlugins.push(configThemePlugin(isBuild));
|
vitePlugins.push(configThemePlugin(isBuild))
|
||||||
|
|
||||||
// The following plugins only work in the production environment
|
// The following plugins only work in the production environment
|
||||||
if (isBuild) {
|
if (isBuild) {
|
||||||
//vite-plugin-imagemin
|
// vite-plugin-imagemin
|
||||||
VITE_USE_IMAGEMIN && vitePlugins.push(configImageminPlugin());
|
VITE_USE_IMAGEMIN && vitePlugins.push(configImageminPlugin())
|
||||||
|
|
||||||
// rollup-plugin-gzip
|
// rollup-plugin-gzip
|
||||||
vitePlugins.push(
|
vitePlugins.push(
|
||||||
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE),
|
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE),
|
||||||
);
|
)
|
||||||
|
|
||||||
// vite-plugin-pwa
|
// vite-plugin-pwa
|
||||||
vitePlugins.push(configPwaConfig(viteEnv));
|
vitePlugins.push(configPwaConfig(viteEnv))
|
||||||
}
|
}
|
||||||
|
|
||||||
return vitePlugins;
|
return vitePlugins
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
* Introduces component library styles on demand.
|
* Introduces component library styles on demand.
|
||||||
* https://github.com/anncwb/vite-plugin-style-import
|
* https://github.com/anncwb/vite-plugin-style-import
|
||||||
*/
|
*/
|
||||||
import styleImport from 'vite-plugin-style-import';
|
import { createStyleImportPlugin } from 'vite-plugin-style-import'
|
||||||
|
|
||||||
export function configStyleImportPlugin(isBuild: boolean) {
|
export function configStyleImportPlugin(_isBuild: boolean) {
|
||||||
if (!isBuild) {
|
if (!_isBuild) {
|
||||||
return [];
|
return []
|
||||||
}
|
}
|
||||||
const styleImportPlugin = styleImport({
|
const styleImportPlugin = createStyleImportPlugin({
|
||||||
libs: [
|
libs: [
|
||||||
{
|
{
|
||||||
libraryName: 'ant-design-vue',
|
libraryName: 'ant-design-vue',
|
||||||
|
|
@ -19,6 +19,7 @@ export function configStyleImportPlugin(isBuild: boolean) {
|
||||||
'anchor-link',
|
'anchor-link',
|
||||||
'sub-menu',
|
'sub-menu',
|
||||||
'menu-item',
|
'menu-item',
|
||||||
|
'menu-divider',
|
||||||
'menu-item-group',
|
'menu-item-group',
|
||||||
'breadcrumb-item',
|
'breadcrumb-item',
|
||||||
'breadcrumb-separator',
|
'breadcrumb-separator',
|
||||||
|
|
@ -44,7 +45,7 @@ export function configStyleImportPlugin(isBuild: boolean) {
|
||||||
'skeleton-paragraph',
|
'skeleton-paragraph',
|
||||||
'skeleton-image',
|
'skeleton-image',
|
||||||
'skeleton-button',
|
'skeleton-button',
|
||||||
];
|
]
|
||||||
// 这里是需要额外引入样式的子组件列表
|
// 这里是需要额外引入样式的子组件列表
|
||||||
// 单独引入子组件时需引入组件样式,否则会在打包后导致子组件样式丢失
|
// 单独引入子组件时需引入组件样式,否则会在打包后导致子组件样式丢失
|
||||||
const replaceList = {
|
const replaceList = {
|
||||||
|
|
@ -63,16 +64,18 @@ export function configStyleImportPlugin(isBuild: boolean) {
|
||||||
'layout-footer': 'layout',
|
'layout-footer': 'layout',
|
||||||
'layout-header': 'layout',
|
'layout-header': 'layout',
|
||||||
'month-picker': 'date-picker',
|
'month-picker': 'date-picker',
|
||||||
};
|
'range-picker': 'date-picker',
|
||||||
|
'image-preview-group': 'image',
|
||||||
|
}
|
||||||
|
|
||||||
return ignoreList.includes(name)
|
return ignoreList.includes(name)
|
||||||
? ''
|
? ''
|
||||||
: replaceList.hasOwnProperty(name)
|
: replaceList.hasOwnProperty(name)
|
||||||
? `ant-design-vue/es/${replaceList[name]}/style/index`
|
? `ant-design-vue/es/${replaceList[name]}/style/index`
|
||||||
: `ant-design-vue/es/${name}/style/index`;
|
: `ant-design-vue/es/${name}/style/index`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
})
|
||||||
return styleImportPlugin;
|
return styleImportPlugin
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@
|
||||||
* https://github.com/anncwb/vite-plugin-svg-icons
|
* https://github.com/anncwb/vite-plugin-svg-icons
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import SvgIconsPlugin from 'vite-plugin-svg-icons';
|
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export function configSvgIconsPlugin(isBuild: boolean) {
|
export function configSvgIconsPlugin(isBuild: boolean) {
|
||||||
const svgIconsPlugin = SvgIconsPlugin({
|
const svgIconsPlugin = createSvgIconsPlugin({
|
||||||
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
|
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
|
||||||
svgoOptions: isBuild,
|
svgoOptions: isBuild,
|
||||||
// default
|
// default
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
* Vite plugin for website theme color switching
|
* Vite plugin for website theme color switching
|
||||||
* https://github.com/anncwb/vite-plugin-theme
|
* https://github.com/anncwb/vite-plugin-theme
|
||||||
*/
|
*/
|
||||||
import type { Plugin } from 'vite';
|
import type { PluginOption } from 'vite';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {
|
import {
|
||||||
viteThemePlugin,
|
viteThemePlugin,
|
||||||
|
|
@ -14,7 +14,7 @@ import {
|
||||||
import { getThemeColors, generateColors } from '../../config/themeConfig';
|
import { getThemeColors, generateColors } from '../../config/themeConfig';
|
||||||
import { generateModifyVars } from '../../generate/generateModifyVars';
|
import { generateModifyVars } from '../../generate/generateModifyVars';
|
||||||
|
|
||||||
export function configThemePlugin(isBuild: boolean): Plugin[] {
|
export function configThemePlugin(isBuild: boolean): PluginOption[] {
|
||||||
const colors = generateColors({
|
const colors = generateColors({
|
||||||
mixDarken,
|
mixDarken,
|
||||||
mixLighten,
|
mixLighten,
|
||||||
|
|
@ -85,5 +85,5 @@ export function configThemePlugin(isBuild: boolean): Plugin[] {
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
return plugin as unknown as Plugin[];
|
return plugin as unknown as PluginOption[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,23 @@
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const { execSync } = require('child_process')
|
||||||
|
|
||||||
|
const scopes = fs
|
||||||
|
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
|
||||||
|
.filter((dirent) => dirent.isDirectory())
|
||||||
|
.map((dirent) => dirent.name.replace(/s$/, ''))
|
||||||
|
|
||||||
|
// precomputed scope
|
||||||
|
const scopeComplete = execSync('git status --porcelain || true')
|
||||||
|
.toString()
|
||||||
|
.trim()
|
||||||
|
.split('\n')
|
||||||
|
.find((r) => ~r.indexOf('M src'))
|
||||||
|
?.replace(/(\/)/g, '%%')
|
||||||
|
?.match(/src%%((\w|-)*)/)?.[1]
|
||||||
|
?.replace(/s$/, '')
|
||||||
|
|
||||||
|
/** @type {import('cz-git').UserConfig} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ignores: [(commit) => commit.includes('init')],
|
ignores: [(commit) => commit.includes('init')],
|
||||||
extends: ['@commitlint/config-conventional'],
|
extends: ['@commitlint/config-conventional'],
|
||||||
|
|
@ -30,4 +50,58 @@ module.exports = {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
prompt: {
|
||||||
|
/** @use `yarn commit :f` */
|
||||||
|
alias: {
|
||||||
|
f: 'docs: fix typos',
|
||||||
|
r: 'docs: update README',
|
||||||
|
s: 'style: update code format',
|
||||||
|
b: 'build: bump dependencies',
|
||||||
|
c: 'chore: update config',
|
||||||
|
},
|
||||||
|
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
|
||||||
|
defaultScope: scopeComplete,
|
||||||
|
scopes: [...scopes, 'mock'],
|
||||||
|
allowEmptyIssuePrefixs: false,
|
||||||
|
allowCustomIssuePrefixs: false,
|
||||||
|
|
||||||
|
// English
|
||||||
|
typesAppend: [
|
||||||
|
{ value: 'wip', name: 'wip: work in process' },
|
||||||
|
{ value: 'workflow', name: 'workflow: workflow improvements' },
|
||||||
|
{ value: 'types', name: 'types: type definition file changes' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// 中英文对照版
|
||||||
|
// messages: {
|
||||||
|
// type: '选择你要提交的类型 :',
|
||||||
|
// scope: '选择一个提交范围 (可选):',
|
||||||
|
// customScope: '请输入自定义的提交范围 :',
|
||||||
|
// subject: '填写简短精炼的变更描述 :\n',
|
||||||
|
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
|
||||||
|
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
|
||||||
|
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
|
||||||
|
// customFooterPrefixs: '输入自定义issue前缀 :',
|
||||||
|
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
|
||||||
|
// confirmCommit: '是否提交或修改commit ?',
|
||||||
|
// },
|
||||||
|
// types: [
|
||||||
|
// { value: 'feat', name: 'feat: 新增功能' },
|
||||||
|
// { value: 'fix', name: 'fix: 修复缺陷' },
|
||||||
|
// { value: 'docs', name: 'docs: 文档变更' },
|
||||||
|
// { value: 'style', name: 'style: 代码格式' },
|
||||||
|
// { value: 'refactor', name: 'refactor: 代码重构' },
|
||||||
|
// { value: 'perf', name: 'perf: 性能优化' },
|
||||||
|
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
|
||||||
|
// { value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
|
||||||
|
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
|
||||||
|
// { value: 'revert', name: 'revert: 回滚 commit' },
|
||||||
|
// { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
|
||||||
|
// { value: 'wip', name: 'wip: 正在开发中' },
|
||||||
|
// { value: 'workflow', name: 'workflow: 工作流程改进' },
|
||||||
|
// { value: 'types', name: 'types: 类型定义文件修改' },
|
||||||
|
// ],
|
||||||
|
// emptyScopesAlias: 'empty: 不填写',
|
||||||
|
// customScopesAlias: 'custom: 自定义',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
||||||
35
index.html
35
index.html
|
|
@ -1,5 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" id="htmlRoot">
|
<html lang="zh-cn" id="htmlRoot">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
|
|
@ -8,20 +8,19 @@
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
|
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
(() => {
|
;(() => {
|
||||||
var htmlRoot = document.getElementById('htmlRoot');
|
var htmlRoot = document.getElementById('htmlRoot')
|
||||||
var theme = window.localStorage.getItem('__APP__DARK__MODE__');
|
var theme = window.localStorage.getItem('__APP__DARK__MODE__')
|
||||||
if (htmlRoot && theme) {
|
if (htmlRoot && theme) {
|
||||||
htmlRoot.setAttribute('data-theme', theme);
|
htmlRoot.setAttribute('data-theme', theme)
|
||||||
theme = htmlRoot = null;
|
theme = htmlRoot = null
|
||||||
}
|
}
|
||||||
})();
|
})()
|
||||||
</script>
|
</script>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -30,7 +29,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme='dark'] .app-loading .app-loading-title {
|
html[data-theme='dark'] .app-loading .app-loading-title {
|
||||||
color: rgba(255, 255, 255, 0.85);
|
color: rgb(255 255 255 / 85%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-loading {
|
.app-loading {
|
||||||
|
|
@ -48,7 +47,6 @@
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-transform: translate3d(-50%, -50%, 0);
|
|
||||||
transform: translate3d(-50%, -50%, 0);
|
transform: translate3d(-50%, -50%, 0);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -66,7 +64,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
color: rgba(0, 0, 0, 0.85);
|
color: rgb(0 0 0 / 85%);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +95,7 @@
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background-color: #0065cc;
|
background-color: #0065cc;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
opacity: 0.3;
|
opacity: 30%;
|
||||||
transform: scale(0.75);
|
transform: scale(0.75);
|
||||||
animation: antSpinMove 1s infinite linear alternate;
|
animation: antSpinMove 1s infinite linear alternate;
|
||||||
transform-origin: 50% 50%;
|
transform-origin: 50% 50%;
|
||||||
|
|
@ -111,43 +109,38 @@
|
||||||
.dot i:nth-child(2) {
|
.dot i:nth-child(2) {
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
-webkit-animation-delay: 0.4s;
|
|
||||||
animation-delay: 0.4s;
|
animation-delay: 0.4s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dot i:nth-child(3) {
|
.dot i:nth-child(3) {
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
-webkit-animation-delay: 0.8s;
|
|
||||||
animation-delay: 0.8s;
|
animation-delay: 0.8s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dot i:nth-child(4) {
|
.dot i:nth-child(4) {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
-webkit-animation-delay: 1.2s;
|
|
||||||
animation-delay: 1.2s;
|
animation-delay: 1.2s;
|
||||||
}
|
}
|
||||||
@keyframes antRotate {
|
@keyframes antRotate {
|
||||||
to {
|
to {
|
||||||
-webkit-transform: rotate(405deg);
|
|
||||||
transform: rotate(405deg);
|
transform: rotate(405deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@-webkit-keyframes antRotate {
|
@keyframes antRotate {
|
||||||
to {
|
to {
|
||||||
-webkit-transform: rotate(405deg);
|
|
||||||
transform: rotate(405deg);
|
transform: rotate(405deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes antSpinMove {
|
@keyframes antSpinMove {
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@-webkit-keyframes antSpinMove {
|
@keyframes antSpinMove {
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
export default {
|
|
||||||
preset: 'ts-jest',
|
|
||||||
roots: ['<rootDir>/tests/'],
|
|
||||||
clearMocks: true,
|
|
||||||
moduleDirectories: ['node_modules', 'src'],
|
|
||||||
moduleFileExtensions: ['js', 'ts', 'vue', 'tsx', 'jsx', 'json', 'node'],
|
|
||||||
modulePaths: ['<rootDir>/src', '<rootDir>/node_modules'],
|
|
||||||
testMatch: [
|
|
||||||
'**/tests/**/*.[jt]s?(x)',
|
|
||||||
'**/?(*.)+(spec|test).[tj]s?(x)',
|
|
||||||
'(/__tests__/.*|(\\.|/)(test|spec))\\.(js|ts)$',
|
|
||||||
],
|
|
||||||
testPathIgnorePatterns: [
|
|
||||||
'<rootDir>/tests/server/',
|
|
||||||
'<rootDir>/tests/__mocks__/',
|
|
||||||
'/node_modules/',
|
|
||||||
],
|
|
||||||
transform: {
|
|
||||||
'^.+\\.tsx?$': 'ts-jest',
|
|
||||||
},
|
|
||||||
transformIgnorePatterns: ['<rootDir>/tests/__mocks__/', '/node_modules/'],
|
|
||||||
// A map from regular expressions to module names that allow to stub out resources with a single module
|
|
||||||
moduleNameMapper: {
|
|
||||||
'\\.(vs|fs|vert|frag|glsl|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
|
||||||
'<rootDir>/tests/__mocks__/fileMock.ts',
|
|
||||||
'\\.(sass|s?css|less)$': '<rootDir>/tests/__mocks__/styleMock.ts',
|
|
||||||
'\\?worker$': '<rootDir>/tests/__mocks__/workerMock.ts',
|
|
||||||
'^/@/(.*)$': '<rootDir>/src/$1',
|
|
||||||
},
|
|
||||||
testEnvironment: 'jsdom',
|
|
||||||
verbose: true,
|
|
||||||
collectCoverage: false,
|
|
||||||
coverageDirectory: 'coverage',
|
|
||||||
collectCoverageFrom: ['src/**/*.{js,ts,vue}'],
|
|
||||||
coveragePathIgnorePatterns: ['^.+\\.d\\.ts$'],
|
|
||||||
};
|
|
||||||
200
package.json
200
package.json
|
|
@ -7,12 +7,13 @@
|
||||||
"url": "https://github.com/anncwb"
|
"url": "https://github.com/anncwb"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bootstrap": "yarn install",
|
"commit": "czg",
|
||||||
|
"bootstrap": "pnpm install",
|
||||||
"serve": "npm run dev",
|
"serve": "npm run dev",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts",
|
"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts",
|
||||||
"build:test": "cross-env vite build --mode test && esno ./build/script/postBuild.ts",
|
"build:test": "cross-env vite build --mode test && esno ./build/script/postBuild.ts",
|
||||||
"build:no-cache": "yarn clean:cache && npm run build",
|
"build:no-cache": "pnpm clean:cache && npm run build",
|
||||||
"report": "cross-env REPORT=true npm run build",
|
"report": "cross-env REPORT=true npm run build",
|
||||||
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
"type:check": "vue-tsc --noEmit --skipLibCheck",
|
||||||
"preview": "npm run build && vite preview",
|
"preview": "npm run build && vite preview",
|
||||||
|
|
@ -23,119 +24,131 @@
|
||||||
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
|
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
|
||||||
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
||||||
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||||
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
|
"lint:lint-staged": "lint-staged",
|
||||||
"test:unit": "jest",
|
"test:unit": "jest",
|
||||||
"test:unit-coverage": "jest --coverage",
|
|
||||||
"test:gzip": "npx http-server dist --cors --gzip -c-1",
|
"test:gzip": "npx http-server dist --cors --gzip -c-1",
|
||||||
"test:br": "npx http-server dist --cors --brotli -c-1",
|
"test:br": "npx http-server dist --cors --brotli -c-1",
|
||||||
"reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap",
|
"reinstall": "rimraf pnpm-lock.yaml && rimraf package.lock.json && rimraf node_modules && npm run bootstrap",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"gen:icon": "esno ./build/generate/icon/index.ts"
|
"gen:icon": "esno ./build/generate/icon/index.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/colors": "^6.0.0",
|
"@ant-design/colors": "^6.0.0",
|
||||||
"@ant-design/icons-vue": "^6.0.1",
|
"@ant-design/icons-vue": "^6.1.0",
|
||||||
"@iconify/iconify": "^2.0.4",
|
"@iconify/iconify": "^2.2.1",
|
||||||
"@vueuse/core": "^6.7.4",
|
"@logicflow/core": "^1.1.13",
|
||||||
"@vueuse/shared": "^6.7.4",
|
"@logicflow/extension": "^1.1.13",
|
||||||
"@zxcvbn-ts/core": "^1.0.0-beta.0",
|
"@vue/runtime-core": "^3.2.33",
|
||||||
"ant-design-vue": "2.2.8",
|
"@vue/shared": "^3.2.33",
|
||||||
"axios": "^0.24.0",
|
"@vueuse/core": "^8.3.0",
|
||||||
|
"@vueuse/shared": "^8.3.0",
|
||||||
|
"@zxcvbn-ts/core": "^2.0.1",
|
||||||
|
"ant-design-vue": "^3.2.0",
|
||||||
|
"axios": "^0.26.1",
|
||||||
|
"codemirror": "^5.65.3",
|
||||||
|
"cropperjs": "^1.5.12",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"echarts": "^5.2.2",
|
"dayjs": "^1.11.1",
|
||||||
|
"echarts": "^5.3.2",
|
||||||
|
"intro.js": "^5.1.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"moment": "^2.29.1",
|
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"path-to-regexp": "^6.2.0",
|
"path-to-regexp": "^6.2.0",
|
||||||
"pinia": "2.0.0",
|
"pinia": "2.0.12",
|
||||||
"qrcode": "^1.4.4",
|
"print-js": "^1.6.0",
|
||||||
"qs": "^6.10.1",
|
"qrcode": "^1.5.0",
|
||||||
|
"qs": "^6.10.3",
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
"sortablejs": "^1.14.0",
|
"showdown": "^2.1.0",
|
||||||
"vue": "^3.2.21",
|
"sortablejs": "^1.15.0",
|
||||||
|
"tinymce": "^5.10.3",
|
||||||
|
"vditor": "^3.8.13",
|
||||||
|
"vue": "^3.2.33",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
"vue-router": "^4.0.12",
|
"vue-json-pretty": "^2.0.6",
|
||||||
"vue-types": "^4.1.1"
|
"vue-router": "^4.0.14",
|
||||||
|
"vue-types": "^4.1.1",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^14.1.0",
|
"@commitlint/cli": "^16.2.3",
|
||||||
"@commitlint/config-conventional": "^14.1.0",
|
"@commitlint/config-conventional": "^16.2.1",
|
||||||
"@iconify/json": "^1.1.422",
|
"@iconify/json": "^2.1.30",
|
||||||
"@purge-icons/generated": "^0.7.0",
|
"@purge-icons/generated": "^0.8.1",
|
||||||
"@types/codemirror": "^5.60.5",
|
"@types/codemirror": "^5.60.5",
|
||||||
"@types/crypto-js": "^4.0.2",
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/fs-extra": "^9.0.13",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@types/inquirer": "^8.1.3",
|
"@types/inquirer": "^8.2.1",
|
||||||
"@types/intro.js": "^3.0.2",
|
"@types/intro.js": "^3.0.2",
|
||||||
"@types/jest": "^27.0.2",
|
"@types/lodash-es": "^4.17.6",
|
||||||
"@types/lodash-es": "^4.17.5",
|
"@types/mockjs": "^1.0.6",
|
||||||
"@types/mockjs": "^1.0.4",
|
"@types/node": "^17.0.25",
|
||||||
"@types/node": "^16.11.6",
|
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@types/qrcode": "^1.4.1",
|
"@types/qrcode": "^1.4.2",
|
||||||
"@types/qs": "^6.9.7",
|
"@types/qs": "^6.9.7",
|
||||||
"@types/showdown": "^1.9.4",
|
"@types/showdown": "^1.9.4",
|
||||||
"@types/sortablejs": "^1.10.7",
|
"@types/sortablejs": "^1.10.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
||||||
"@typescript-eslint/parser": "^5.3.0",
|
"@typescript-eslint/parser": "^5.20.0",
|
||||||
"@vitejs/plugin-legacy": "^1.6.2",
|
"@vitejs/plugin-legacy": "^1.8.1",
|
||||||
"@vitejs/plugin-vue": "^1.9.4",
|
"@vitejs/plugin-vue": "^2.3.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^1.2.0",
|
"@vitejs/plugin-vue-jsx": "^1.3.10",
|
||||||
"@vue/compiler-sfc": "3.2.21",
|
"@vue/compiler-sfc": "^3.2.33",
|
||||||
"@vue/test-utils": "^2.0.0-rc.16",
|
"@vue/test-utils": "^2.0.0-rc.21",
|
||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.4",
|
||||||
"commitizen": "^4.2.4",
|
"conventional-changelog-cli": "^2.2.2",
|
||||||
"conventional-changelog-cli": "^2.1.1",
|
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"dotenv": "^10.0.0",
|
"cz-git": "^1.3.9",
|
||||||
"eslint": "^8.1.0",
|
"czg": "^1.3.9",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"dotenv": "^16.0.0",
|
||||||
"eslint-define-config": "^1.1.2",
|
"eslint": "^8.13.0",
|
||||||
"eslint-plugin-jest": "^25.2.2",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-vue": "^8.0.3",
|
"eslint-plugin-vue": "^8.6.0",
|
||||||
"esno": "^0.10.1",
|
"esno": "^0.14.1",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.1.0",
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"inquirer": "^8.2.0",
|
"inquirer": "^8.2.2",
|
||||||
"jest": "^27.3.1",
|
|
||||||
"less": "^4.1.2",
|
"less": "^4.1.2",
|
||||||
"lint-staged": "11.2.6",
|
"lint-staged": "12.3.7",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss": "^8.3.11",
|
"picocolors": "^1.0.0",
|
||||||
"postcss-html": "^1.2.0",
|
"postcss": "^8.4.12",
|
||||||
"postcss-less": "^5.0.0",
|
"postcss-html": "^1.4.1",
|
||||||
"prettier": "^2.4.1",
|
"postcss-less": "^6.0.0",
|
||||||
|
"prettier": "^2.6.2",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup-plugin-visualizer": "^5.5.2",
|
"rollup": "^2.70.2",
|
||||||
"stylelint": "^14.0.1",
|
"rollup-plugin-visualizer": "^5.6.0",
|
||||||
"stylelint-config-html": "^1.0.0",
|
"stylelint": "^14.7.1",
|
||||||
"stylelint-config-prettier": "^9.0.3",
|
"stylelint-config-prettier": "^9.0.3",
|
||||||
"stylelint-config-standard": "^23.0.0",
|
"stylelint-config-recommended": "^7.0.0",
|
||||||
|
"stylelint-config-recommended-vue": "^1.4.0",
|
||||||
|
"stylelint-config-standard": "^25.0.0",
|
||||||
"stylelint-order": "^5.0.0",
|
"stylelint-order": "^5.0.0",
|
||||||
"ts-jest": "^27.0.7",
|
"ts-node": "^10.7.0",
|
||||||
"ts-node": "^10.4.0",
|
"typescript": "^4.6.3",
|
||||||
"typescript": "^4.4.4",
|
"vite": "^2.9.5",
|
||||||
"vite": "^2.6.13",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-compression": "^0.3.5",
|
"vite-plugin-html": "^3.2.0",
|
||||||
"vite-plugin-html": "^2.1.1",
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
"vite-plugin-imagemin": "^0.4.6",
|
"vite-plugin-mkcert": "^1.6.0",
|
||||||
"vite-plugin-mock": "^2.9.6",
|
"vite-plugin-mock": "^2.9.6",
|
||||||
"vite-plugin-purge-icons": "^0.7.0",
|
"vite-plugin-purge-icons": "^0.8.1",
|
||||||
"vite-plugin-pwa": "^0.11.3",
|
"vite-plugin-pwa": "^0.11.13",
|
||||||
"vite-plugin-style-import": "^1.3.0",
|
"vite-plugin-style-import": "^2.0.0",
|
||||||
"vite-plugin-svg-icons": "^1.0.5",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vite-plugin-theme": "^0.8.1",
|
"vite-plugin-theme": "^0.8.6",
|
||||||
"vite-plugin-vue-setup-extend": "^0.1.0",
|
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||||
"vite-plugin-windicss": "^1.4.12",
|
"vite-plugin-windicss": "^1.8.4",
|
||||||
"vue-eslint-parser": "^8.0.1",
|
"vue-eslint-parser": "^8.3.0",
|
||||||
"vue-tsc": "^0.28.10"
|
"vue-tsc": "^0.33.9"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"//": "Used to install imagemin dependencies, because imagemin may not be installed in China. If it is abroad, you can delete it",
|
|
||||||
"bin-wrapper": "npm:bin-wrapper-china",
|
"bin-wrapper": "npm:bin-wrapper-china",
|
||||||
"rollup": "^2.56.3"
|
"rollup": "^2.56.3",
|
||||||
|
"gifsicle": "5.2.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
@ -148,5 +161,34 @@
|
||||||
"homepage": "https://github.com/anncwb/vue-vben-admin",
|
"homepage": "https://github.com/anncwb/vue-vben-admin",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12 || >=14"
|
"node": "^12 || >=14"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{js,jsx,ts,tsx}": [
|
||||||
|
"eslint --fix",
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
|
||||||
|
"prettier --write--parser json"
|
||||||
|
],
|
||||||
|
"package.json": [
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"*.vue": [
|
||||||
|
"eslint --fix",
|
||||||
|
"prettier --write",
|
||||||
|
"stylelint --fix"
|
||||||
|
],
|
||||||
|
"*.{scss,less,styl,html}": [
|
||||||
|
"stylelint --fix",
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"*.md": [
|
||||||
|
"prettier --write"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"commitizen": {
|
||||||
|
"path": "node_modules/cz-git"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6887
pnpm-lock.yaml
6887
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -1,10 +1,10 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
printWidth: 100,
|
printWidth: 100,
|
||||||
semi: true,
|
semi: false,
|
||||||
vueIndentScriptAndStyle: true,
|
vueIndentScriptAndStyle: true,
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
trailingComma: 'all',
|
trailingComma: 'all',
|
||||||
proseWrap: 'never',
|
proseWrap: 'never',
|
||||||
htmlWhitespaceSensitivity: 'strict',
|
htmlWhitespaceSensitivity: 'strict',
|
||||||
endOfLine: 'auto',
|
endOfLine: 'auto',
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placement="bottomCenter"
|
placement="bottom"
|
||||||
:trigger="['click']"
|
:trigger="['click']"
|
||||||
:dropMenuList="localeList"
|
:dropMenuList="localeList"
|
||||||
:selectedKeys="selectedKeys"
|
:selectedKeys="selectedKeys"
|
||||||
@menuEvent="handleMenuEvent"
|
@menu-event="handleMenuEvent"
|
||||||
overlayClassName="app-locale-picker-overlay"
|
overlayClassName="app-locale-picker-overlay"
|
||||||
>
|
>
|
||||||
<span class="cursor-pointer flex items-center">
|
<span class="cursor-pointer flex items-center">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="prefixCls">
|
<div :class="prefixCls">
|
||||||
<CollapseHeader v-bind="$props" :prefixCls="prefixCls" :show="show" @expand="handleExpand">
|
<CollapseHeader v-bind="props" :prefixCls="prefixCls" :show="show" @expand="handleExpand">
|
||||||
<template #title>
|
<template #title>
|
||||||
<slot name="title"></slot>
|
<slot name="title"></slot>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { isNil } from 'lodash-es';
|
||||||
// component
|
// component
|
||||||
import { Skeleton } from 'ant-design-vue';
|
import { Skeleton } from 'ant-design-vue';
|
||||||
import { CollapseTransition } from '/@/components/Transition';
|
import { CollapseTransition } from '/@/components/Transition';
|
||||||
|
|
@ -66,13 +67,17 @@
|
||||||
/**
|
/**
|
||||||
* @description: Handling development events
|
* @description: Handling development events
|
||||||
*/
|
*/
|
||||||
function handleExpand() {
|
function handleExpand(val: boolean) {
|
||||||
show.value = !show.value;
|
show.value = isNil(val) ? !show.value : val;
|
||||||
if (props.triggerWindowResize) {
|
if (props.triggerWindowResize) {
|
||||||
// 200 milliseconds here is because the expansion has animation,
|
// 200 milliseconds here is because the expansion has animation,
|
||||||
useTimeoutFn(triggerWindowResize, 200);
|
useTimeoutFn(triggerWindowResize, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
handleExpand,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-collapse-container';
|
@prefix-cls: ~'@{namespace}-collapse-container';
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import type { ContextMenuItem, ItemContentProps, Axis } from './typing';
|
import type { ContextMenuItem, ItemContentProps, Axis } from './typing';
|
||||||
import type { FunctionalComponent, CSSProperties } from 'vue';
|
import type { FunctionalComponent, CSSProperties, PropType } from 'vue';
|
||||||
import { defineComponent, nextTick, onMounted, computed, ref, unref, onUnmounted } from 'vue';
|
import { defineComponent, nextTick, onMounted, computed, ref, unref, onUnmounted } from 'vue';
|
||||||
import Icon from '/@/components/Icon';
|
import Icon from '/@/components/Icon';
|
||||||
import { Menu, Divider } from 'ant-design-vue';
|
import { Menu, Divider } from 'ant-design-vue';
|
||||||
|
|
@ -60,9 +60,11 @@
|
||||||
const top = body.clientHeight < y + menuHeight ? y - menuHeight : y;
|
const top = body.clientHeight < y + menuHeight ? y - menuHeight : y;
|
||||||
return {
|
return {
|
||||||
...styles,
|
...styles,
|
||||||
|
position: 'absolute',
|
||||||
width: `${width}px`,
|
width: `${width}px`,
|
||||||
left: `${left + 1}px`,
|
left: `${left + 1}px`,
|
||||||
top: `${top + 1}px`,
|
top: `${top + 1}px`,
|
||||||
|
zIndex: 9999,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -87,7 +89,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMenuItem(items: ContextMenuItem[]) {
|
function renderMenuItem(items: ContextMenuItem[]) {
|
||||||
return items.map((item) => {
|
const visibleItems = items.filter((item) => !item.hidden);
|
||||||
|
return visibleItems.map((item) => {
|
||||||
const { disabled, label, children, divider = false } = item;
|
const { disabled, label, children, divider = false } = item;
|
||||||
|
|
||||||
const contentProps = {
|
const contentProps = {
|
||||||
|
|
@ -124,15 +127,11 @@
|
||||||
}
|
}
|
||||||
const { items } = props;
|
const { items } = props;
|
||||||
return (
|
return (
|
||||||
<Menu
|
<div class={prefixCls}>
|
||||||
inlineIndent={12}
|
<Menu inlineIndent={12} mode="vertical" ref={wrapRef} style={unref(getStyle)}>
|
||||||
mode="vertical"
|
{renderMenuItem(items)}
|
||||||
class={prefixCls}
|
</Menu>
|
||||||
ref={wrapRef}
|
</div>
|
||||||
style={unref(getStyle)}
|
|
||||||
>
|
|
||||||
{renderMenuItem(items)}
|
|
||||||
</Menu>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
@ -185,6 +184,9 @@
|
||||||
background-clip: padding-box;
|
background-clip: padding-box;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
.item-style();
|
.item-style();
|
||||||
|
|
||||||
.ant-divider {
|
.ant-divider {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ export interface Axis {
|
||||||
export interface ContextMenuItem {
|
export interface ContextMenuItem {
|
||||||
label: string;
|
label: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
hidden?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
handler?: Fn;
|
handler?: Fn;
|
||||||
divider?: boolean;
|
divider?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
opt.width = '100%';
|
opt.width = '100%';
|
||||||
}
|
}
|
||||||
const detailCls = `${prefixCls}__detail`;
|
const detailCls = `${prefixCls}__detail`;
|
||||||
opt.wrapClassName = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
|
opt.class = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
|
||||||
|
|
||||||
if (!getContainer) {
|
if (!getContainer) {
|
||||||
// TODO type error?
|
// TODO type error?
|
||||||
|
|
@ -201,10 +201,6 @@
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
.ant-drawer-wrapper-body {
|
.ant-drawer-wrapper-body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-drawer-close {
|
.ant-drawer-close {
|
||||||
|
|
@ -213,19 +209,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-drawer-content {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-drawer-body {
|
.ant-drawer-body {
|
||||||
height: calc(100% - @header-height);
|
height: calc(100% - @header-height);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: @component-background;
|
background-color: @component-background;
|
||||||
flex-grow: 1;
|
|
||||||
overflow: auto;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.5715;
|
|
||||||
word-wrap: break-word;
|
|
||||||
|
|
||||||
.scrollbar__wrap {
|
.scrollbar__wrap {
|
||||||
padding: 16px !important;
|
padding: 16px !important;
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
const heightStr = `${props.height}`;
|
const heightStr = `${props.height}`;
|
||||||
return {
|
return {
|
||||||
height: heightStr,
|
height: heightStr,
|
||||||
lineHeight: heightStr,
|
lineHeight: `calc(${heightStr} - 1px)`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,13 +128,12 @@ export interface DrawerProps extends DrawerFooterProps {
|
||||||
* @type any (string | slot)
|
* @type any (string | slot)
|
||||||
*/
|
*/
|
||||||
title?: VNodeChild | JSX.Element;
|
title?: VNodeChild | JSX.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class name of the container of the Drawer dialog.
|
* The class name of the container of the Drawer dialog.
|
||||||
* @type string
|
* @type string
|
||||||
*/
|
*/
|
||||||
wrapClassName?: string;
|
wrapClassName?: string;
|
||||||
|
class?: string;
|
||||||
/**
|
/**
|
||||||
* Style of wrapper element which **contains mask** compare to `drawerStyle`
|
* Style of wrapper element which **contains mask** compare to `drawerStyle`
|
||||||
* @type object
|
* @type object
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ export { useForm } from './src/hooks/useForm';
|
||||||
export { default as ApiSelect } from './src/components/ApiSelect.vue';
|
export { default as ApiSelect } from './src/components/ApiSelect.vue';
|
||||||
export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
|
export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
|
||||||
export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
|
export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
|
||||||
|
export { default as ApiTree } from './src/components/ApiTree.vue';
|
||||||
export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue';
|
export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue';
|
||||||
export { default as ApiCascader } from './src/components/ApiCascader.vue';
|
export { default as ApiCascader } from './src/components/ApiCascader.vue';
|
||||||
|
export { default as ApiTransfer } from './src/components/ApiTransfer.vue';
|
||||||
|
|
||||||
export { BasicForm };
|
export { BasicForm };
|
||||||
|
|
|
||||||
|
|
@ -58,15 +58,17 @@
|
||||||
import { createFormContext } from './hooks/useFormContext';
|
import { createFormContext } from './hooks/useFormContext';
|
||||||
import { useAutoFocus } from './hooks/useAutoFocus';
|
import { useAutoFocus } from './hooks/useAutoFocus';
|
||||||
import { useModalContext } from '/@/components/Modal';
|
import { useModalContext } from '/@/components/Modal';
|
||||||
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
|
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicForm',
|
name: 'BasicForm',
|
||||||
components: { FormItem, Form, Row, FormAction },
|
components: { FormItem, Form, Row, FormAction },
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
emits: ['advanced-change', 'reset', 'submit', 'register'],
|
emits: ['advanced-change', 'reset', 'submit', 'register', 'field-value-change'],
|
||||||
setup(props, { emit, attrs }) {
|
setup(props, { emit, attrs }) {
|
||||||
const formModel = reactive<Recordable>({});
|
const formModel = reactive<Recordable>({});
|
||||||
const modalFn = useModalContext();
|
const modalFn = useModalContext();
|
||||||
|
|
@ -122,7 +124,7 @@
|
||||||
if (!Array.isArray(defaultValue)) {
|
if (!Array.isArray(defaultValue)) {
|
||||||
schema.defaultValue = dateUtil(defaultValue);
|
schema.defaultValue = dateUtil(defaultValue);
|
||||||
} else {
|
} else {
|
||||||
const def: moment.Moment[] = [];
|
const def: any[] = [];
|
||||||
defaultValue.forEach((item) => {
|
defaultValue.forEach((item) => {
|
||||||
def.push(dateUtil(item));
|
def.push(dateUtil(item));
|
||||||
});
|
});
|
||||||
|
|
@ -131,9 +133,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unref(getProps).showAdvancedButton) {
|
if (unref(getProps).showAdvancedButton) {
|
||||||
return schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[];
|
return cloneDeep(
|
||||||
|
schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[],
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return schemas as FormSchema[];
|
return cloneDeep(schemas as FormSchema[]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -170,7 +174,7 @@
|
||||||
updateSchema,
|
updateSchema,
|
||||||
resetSchema,
|
resetSchema,
|
||||||
appendSchemaByField,
|
appendSchemaByField,
|
||||||
removeSchemaByFiled,
|
removeSchemaByField,
|
||||||
resetFields,
|
resetFields,
|
||||||
scrollToField,
|
scrollToField,
|
||||||
} = useFormEvents({
|
} = useFormEvents({
|
||||||
|
|
@ -225,6 +229,14 @@
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => formModel,
|
||||||
|
useDebounceFn(() => {
|
||||||
|
unref(getProps).submitOnChange && handleSubmit();
|
||||||
|
}, 300),
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
async function setProps(formProps: Partial<FormProps>): Promise<void> {
|
async function setProps(formProps: Partial<FormProps>): Promise<void> {
|
||||||
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
|
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
|
||||||
}
|
}
|
||||||
|
|
@ -235,6 +247,7 @@
|
||||||
if (!validateTrigger || validateTrigger === 'change') {
|
if (!validateTrigger || validateTrigger === 'change') {
|
||||||
validateFields([key]).catch((_) => {});
|
validateFields([key]).catch((_) => {});
|
||||||
}
|
}
|
||||||
|
emit('field-value-change', key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEnterPress(e: KeyboardEvent) {
|
function handleEnterPress(e: KeyboardEvent) {
|
||||||
|
|
@ -255,7 +268,7 @@
|
||||||
updateSchema,
|
updateSchema,
|
||||||
resetSchema,
|
resetSchema,
|
||||||
setProps,
|
setProps,
|
||||||
removeSchemaByFiled,
|
removeSchemaByField,
|
||||||
appendSchemaByField,
|
appendSchemaByField,
|
||||||
clearValidate,
|
clearValidate,
|
||||||
validateFields,
|
validateFields,
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ import {
|
||||||
import ApiRadioGroup from './components/ApiRadioGroup.vue';
|
import ApiRadioGroup from './components/ApiRadioGroup.vue';
|
||||||
import RadioButtonGroup from './components/RadioButtonGroup.vue';
|
import RadioButtonGroup from './components/RadioButtonGroup.vue';
|
||||||
import ApiSelect from './components/ApiSelect.vue';
|
import ApiSelect from './components/ApiSelect.vue';
|
||||||
|
import ApiTree from './components/ApiTree.vue';
|
||||||
import ApiTreeSelect from './components/ApiTreeSelect.vue';
|
import ApiTreeSelect from './components/ApiTreeSelect.vue';
|
||||||
import ApiCascader from './components/ApiCascader.vue';
|
import ApiCascader from './components/ApiCascader.vue';
|
||||||
|
import ApiTransfer from './components/ApiTransfer.vue';
|
||||||
import { BasicUpload } from '/@/components/Upload';
|
import { BasicUpload } from '/@/components/Upload';
|
||||||
import { StrengthMeter } from '/@/components/StrengthMeter';
|
import { StrengthMeter } from '/@/components/StrengthMeter';
|
||||||
import { IconPicker } from '/@/components/Icon';
|
import { IconPicker } from '/@/components/Icon';
|
||||||
|
|
@ -43,6 +45,7 @@ componentMap.set('AutoComplete', AutoComplete);
|
||||||
|
|
||||||
componentMap.set('Select', Select);
|
componentMap.set('Select', Select);
|
||||||
componentMap.set('ApiSelect', ApiSelect);
|
componentMap.set('ApiSelect', ApiSelect);
|
||||||
|
componentMap.set('ApiTree', ApiTree);
|
||||||
componentMap.set('TreeSelect', TreeSelect);
|
componentMap.set('TreeSelect', TreeSelect);
|
||||||
componentMap.set('ApiTreeSelect', ApiTreeSelect);
|
componentMap.set('ApiTreeSelect', ApiTreeSelect);
|
||||||
componentMap.set('ApiRadioGroup', ApiRadioGroup);
|
componentMap.set('ApiRadioGroup', ApiRadioGroup);
|
||||||
|
|
@ -55,6 +58,7 @@ componentMap.set('ApiCascader', ApiCascader);
|
||||||
componentMap.set('Cascader', Cascader);
|
componentMap.set('Cascader', Cascader);
|
||||||
componentMap.set('Slider', Slider);
|
componentMap.set('Slider', Slider);
|
||||||
componentMap.set('Rate', Rate);
|
componentMap.set('Rate', Rate);
|
||||||
|
componentMap.set('ApiTransfer', ApiTransfer);
|
||||||
|
|
||||||
componentMap.set('DatePicker', DatePicker);
|
componentMap.set('DatePicker', DatePicker);
|
||||||
componentMap.set('MonthPicker', DatePicker.MonthPicker);
|
componentMap.set('MonthPicker', DatePicker.MonthPicker);
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
import { get, omit } from 'lodash-es';
|
import { get, omit } from 'lodash-es';
|
||||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
interface Option {
|
interface Option {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
|
@ -76,7 +76,7 @@
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
const emitData = ref<any[]>([]);
|
const emitData = ref<any[]>([]);
|
||||||
const isFirstLoad = ref(true);
|
const isFirstLoad = ref(true);
|
||||||
|
const { t } = useI18n();
|
||||||
// Embedded in the form, just use the hook binding to perform form verification
|
// Embedded in the form, just use the hook binding to perform form verification
|
||||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||||
|
|
||||||
|
|
@ -188,6 +188,7 @@
|
||||||
state,
|
state,
|
||||||
options,
|
options,
|
||||||
loading,
|
loading,
|
||||||
|
t,
|
||||||
handleChange,
|
handleChange,
|
||||||
loadData,
|
loadData,
|
||||||
handleRenderDisplay,
|
handleRenderDisplay,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<Select
|
<Select
|
||||||
@dropdownVisibleChange="handleFetch"
|
@dropdown-visible-change="handleFetch"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
:options="getOptions"
|
:options="getOptions"
|
||||||
|
|
@ -57,6 +57,7 @@
|
||||||
labelField: propTypes.string.def('label'),
|
labelField: propTypes.string.def('label'),
|
||||||
valueField: propTypes.string.def('value'),
|
valueField: propTypes.string.def('value'),
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: propTypes.bool.def(true),
|
||||||
|
alwaysLoad: propTypes.bool.def(false),
|
||||||
},
|
},
|
||||||
emits: ['options-change', 'change'],
|
emits: ['options-change', 'change'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
|
@ -87,7 +88,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
props.immediate && fetch();
|
props.immediate && !props.alwaysLoad && fetch();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
@ -121,10 +122,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFetch() {
|
async function handleFetch(visible) {
|
||||||
if (!props.immediate && unref(isFirstLoad)) {
|
if (visible) {
|
||||||
await fetch();
|
if (props.alwaysLoad) {
|
||||||
isFirstLoad.value = false;
|
await fetch();
|
||||||
|
} else if (!props.immediate && unref(isFirstLoad)) {
|
||||||
|
await fetch();
|
||||||
|
isFirstLoad.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
<template>
|
||||||
|
<Transfer
|
||||||
|
:data-source="getdataSource"
|
||||||
|
:filter-option="filterOption"
|
||||||
|
:render="(item) => item.title"
|
||||||
|
:showSelectAll="showSelectAll"
|
||||||
|
:selectedKeys="selectedKeys"
|
||||||
|
:targetKeys="getTargetKeys"
|
||||||
|
:showSearch="showSearch"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, watch, ref, unref, watchEffect } from 'vue';
|
||||||
|
import { Transfer } from 'ant-design-vue';
|
||||||
|
import { isFunction } from '/@/utils/is';
|
||||||
|
import { get, omit } from 'lodash-es';
|
||||||
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { TransferDirection, TransferItem } from 'ant-design-vue/lib/transfer';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ApiTransfer',
|
||||||
|
components: { Transfer },
|
||||||
|
props: {
|
||||||
|
value: { type: Array as PropType<Array<string>> },
|
||||||
|
api: {
|
||||||
|
type: Function as PropType<(arg?: Recordable) => Promise<TransferItem[]>>,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
params: { type: Object },
|
||||||
|
dataSource: { type: Array as PropType<Array<TransferItem>> },
|
||||||
|
immediate: propTypes.bool.def(true),
|
||||||
|
alwaysLoad: propTypes.bool.def(false),
|
||||||
|
afterFetch: { type: Function as PropType<Fn> },
|
||||||
|
resultField: propTypes.string.def(''),
|
||||||
|
labelField: propTypes.string.def('title'),
|
||||||
|
valueField: propTypes.string.def('key'),
|
||||||
|
showSearch: { type: Boolean, default: false },
|
||||||
|
disabled: { type: Boolean, default: false },
|
||||||
|
filterOption: {
|
||||||
|
type: Function as PropType<(inputValue: string, item: TransferItem) => boolean>,
|
||||||
|
},
|
||||||
|
selectedKeys: { type: Array as PropType<Array<string>> },
|
||||||
|
showSelectAll: { type: Boolean, default: false },
|
||||||
|
targetKeys: { type: Array as PropType<Array<string>> },
|
||||||
|
},
|
||||||
|
emits: ['options-change', 'change'],
|
||||||
|
setup(props, { attrs, emit }) {
|
||||||
|
const _dataSource = ref<TransferItem[]>([]);
|
||||||
|
const _targetKeys = ref<string[]>([]);
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const getAttrs = computed(() => {
|
||||||
|
return {
|
||||||
|
...(!props.api ? { dataSource: unref(_dataSource) } : {}),
|
||||||
|
...attrs,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const getdataSource = computed(() => {
|
||||||
|
const { labelField, valueField } = props;
|
||||||
|
|
||||||
|
return unref(_dataSource).reduce((prev, next: Recordable) => {
|
||||||
|
if (next) {
|
||||||
|
prev.push({
|
||||||
|
...omit(next, [labelField, valueField]),
|
||||||
|
title: next[labelField],
|
||||||
|
key: next[valueField],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}, [] as TransferItem[]);
|
||||||
|
});
|
||||||
|
const getTargetKeys = computed<string[]>(() => {
|
||||||
|
if (unref(_targetKeys).length > 0) {
|
||||||
|
return unref(_targetKeys);
|
||||||
|
}
|
||||||
|
if (Array.isArray(props.value)) {
|
||||||
|
return props.value;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleChange(keys: string[], direction: TransferDirection, moveKeys: string[]) {
|
||||||
|
_targetKeys.value = keys;
|
||||||
|
console.log(direction);
|
||||||
|
console.log(moveKeys);
|
||||||
|
emit('change', keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
props.immediate && !props.alwaysLoad && fetch();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.params,
|
||||||
|
() => {
|
||||||
|
fetch();
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
async function fetch() {
|
||||||
|
const api = props.api;
|
||||||
|
if (!api || !isFunction(api)) {
|
||||||
|
if (Array.isArray(props.dataSource)) {
|
||||||
|
_dataSource.value = props.dataSource;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dataSource.value = [];
|
||||||
|
try {
|
||||||
|
const res = await api(props.params);
|
||||||
|
if (Array.isArray(res)) {
|
||||||
|
_dataSource.value = res;
|
||||||
|
emitChange();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.resultField) {
|
||||||
|
_dataSource.value = get(res, props.resultField) || [];
|
||||||
|
}
|
||||||
|
emitChange();
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function emitChange() {
|
||||||
|
emit('options-change', unref(getdataSource));
|
||||||
|
}
|
||||||
|
return { getTargetKeys, getdataSource, t, getAttrs, handleChange };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
<template>
|
||||||
|
<a-tree v-bind="getAttrs" @change="handleChange">
|
||||||
|
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||||
|
<slot :name="item" v-bind="data || {}"></slot>
|
||||||
|
</template>
|
||||||
|
<template #suffixIcon v-if="loading">
|
||||||
|
<LoadingOutlined spin />
|
||||||
|
</template>
|
||||||
|
</a-tree>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
|
||||||
|
import { Tree } from 'ant-design-vue';
|
||||||
|
import { isArray, isFunction } from '/@/utils/is';
|
||||||
|
import { get } from 'lodash-es';
|
||||||
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
|
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'ApiTree',
|
||||||
|
components: { ATree: Tree, LoadingOutlined },
|
||||||
|
props: {
|
||||||
|
api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
|
||||||
|
params: { type: Object },
|
||||||
|
immediate: { type: Boolean, default: true },
|
||||||
|
resultField: propTypes.string.def(''),
|
||||||
|
afterFetch: { type: Function as PropType<Fn> },
|
||||||
|
},
|
||||||
|
emits: ['options-change', 'change'],
|
||||||
|
setup(props, { attrs, emit }) {
|
||||||
|
const treeData = ref<Recordable[]>([]);
|
||||||
|
const isFirstLoaded = ref<Boolean>(false);
|
||||||
|
const loading = ref(false);
|
||||||
|
const getAttrs = computed(() => {
|
||||||
|
return {
|
||||||
|
...(props.api ? { treeData: unref(treeData) } : {}),
|
||||||
|
...attrs,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleChange(...args) {
|
||||||
|
emit('change', ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.params,
|
||||||
|
() => {
|
||||||
|
!unref(isFirstLoaded) && fetch();
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.immediate,
|
||||||
|
(v) => {
|
||||||
|
v && !isFirstLoaded.value && fetch();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
props.immediate && fetch();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function fetch() {
|
||||||
|
const { api, afterFetch } = props;
|
||||||
|
if (!api || !isFunction(api)) return;
|
||||||
|
loading.value = true;
|
||||||
|
treeData.value = [];
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
result = await api(props.params);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
if (afterFetch && isFunction(afterFetch)) {
|
||||||
|
result = afterFetch(result);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
if (!result) return;
|
||||||
|
if (!isArray(result)) {
|
||||||
|
result = get(result, props.resultField);
|
||||||
|
}
|
||||||
|
treeData.value = (result as Recordable[]) || [];
|
||||||
|
isFirstLoaded.value = true;
|
||||||
|
emit('options-change', treeData.value);
|
||||||
|
}
|
||||||
|
return { getAttrs, loading, handleChange };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import type { PropType, Ref } from 'vue';
|
import type { PropType, Ref } from 'vue';
|
||||||
import type { FormActionType, FormProps } from '../types/form';
|
import { computed, defineComponent, toRefs, unref } from 'vue';
|
||||||
import type { FormSchema } from '../types/form';
|
import type { FormActionType, FormProps, FormSchema } from '../types/form';
|
||||||
import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
|
import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
|
||||||
import type { TableActionType } from '/@/components/Table';
|
import type { TableActionType } from '/@/components/Table';
|
||||||
import { defineComponent, computed, unref, toRefs } from 'vue';
|
import { Col, Divider, Form } from 'ant-design-vue';
|
||||||
import { Form, Col, Divider } from 'ant-design-vue';
|
|
||||||
import { componentMap } from '../componentMap';
|
import { componentMap } from '../componentMap';
|
||||||
import { BasicHelp } from '/@/components/Basic';
|
import { BasicHelp } from '/@/components/Basic';
|
||||||
import { isBoolean, isFunction, isNull } from '/@/utils/is';
|
import { isBoolean, isFunction, isNull } from '/@/utils/is';
|
||||||
import { getSlot } from '/@/utils/helper/tsxHelper';
|
import { getSlot } from '/@/utils/helper/tsxHelper';
|
||||||
import { createPlaceholderMessage, setComponentRuleType } from '../helper';
|
import { createPlaceholderMessage, setComponentRuleType } from '../helper';
|
||||||
import { upperFirst, cloneDeep } from 'lodash-es';
|
import { cloneDeep, upperFirst } from 'lodash-es';
|
||||||
import { useItemLabelWidth } from '../hooks/useLabelWidth';
|
import { useItemLabelWidth } from '../hooks/useLabelWidth';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
|
||||||
|
|
@ -178,8 +177,21 @@
|
||||||
|
|
||||||
const getRequired = isFunction(required) ? required(unref(getValues)) : required;
|
const getRequired = isFunction(required) ? required(unref(getValues)) : required;
|
||||||
|
|
||||||
if ((!rules || rules.length === 0) && getRequired) {
|
/*
|
||||||
rules = [{ required: getRequired, validator }];
|
* 1、若设置了required属性,又没有其他的rules,就创建一个验证规则;
|
||||||
|
* 2、若设置了required属性,又存在其他的rules,则只rules中不存在required属性时,才添加验证required的规则
|
||||||
|
* 也就是说rules中的required,优先级大于required
|
||||||
|
*/
|
||||||
|
if (getRequired) {
|
||||||
|
if (!rules || rules.length === 0) {
|
||||||
|
rules = [{ required: getRequired, validator }];
|
||||||
|
} else {
|
||||||
|
const requiredIndex: number = rules.findIndex((rule) => Reflect.has(rule, 'required'));
|
||||||
|
|
||||||
|
if (requiredIndex === -1) {
|
||||||
|
rules.push({ required: getRequired, validator });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const requiredRuleIndex: number = rules.findIndex(
|
const requiredRuleIndex: number = rules.findIndex(
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,5 @@ export function handleInputNumberValue(component?: ComponentType, val?: any) {
|
||||||
* 时间字段
|
* 时间字段
|
||||||
*/
|
*/
|
||||||
export const dateItemType = genType();
|
export const dateItemType = genType();
|
||||||
|
|
||||||
|
export const defaultValueComponents = ['Input', 'InputPassword', 'InputSearch', 'InputTextArea'];
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { ColEx } from '../types';
|
import type { ColEx } from '../types';
|
||||||
import type { AdvanceState } from '../types/hooks';
|
import type { AdvanceState } from '../types/hooks';
|
||||||
import type { ComputedRef, Ref } from 'vue';
|
import { ComputedRef, getCurrentInstance, Ref } from 'vue';
|
||||||
import type { FormProps, FormSchema } from '../types/form';
|
import type { FormProps, FormSchema } from '../types/form';
|
||||||
import { computed, unref, watch } from 'vue';
|
import { computed, unref, watch } from 'vue';
|
||||||
import { isBoolean, isFunction, isNumber, isObject } from '/@/utils/is';
|
import { isBoolean, isFunction, isNumber, isObject } from '/@/utils/is';
|
||||||
|
|
@ -26,6 +26,8 @@ export default function ({
|
||||||
formModel,
|
formModel,
|
||||||
defaultValueRef,
|
defaultValueRef,
|
||||||
}: UseAdvancedContext) {
|
}: UseAdvancedContext) {
|
||||||
|
const vm = getCurrentInstance();
|
||||||
|
|
||||||
const { realWidthRef, screenEnum, screenRef } = useBreakpoint();
|
const { realWidthRef, screenEnum, screenRef } = useBreakpoint();
|
||||||
|
|
||||||
const getEmptySpan = computed((): number => {
|
const getEmptySpan = computed((): number => {
|
||||||
|
|
@ -150,6 +152,9 @@ export default function ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保页面发送更新
|
||||||
|
vm?.proxy?.$forceUpdate();
|
||||||
|
|
||||||
advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpan);
|
advanceState.actionSpan = (realItemColSum % BASIC_COL_LEN) + unref(getEmptySpan);
|
||||||
|
|
||||||
getAdvanced(unref(getProps).actionColOptions || { span: BASIC_COL_LEN }, itemColSum, true);
|
getAdvanced(unref(getProps).actionColOptions || { span: BASIC_COL_LEN }, itemColSum, true);
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,8 @@ export function useForm(props?: Props): UseFormReturnType {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
removeSchemaByFiled: async (field: string | string[]) => {
|
removeSchemaByField: async (field: string | string[]) => {
|
||||||
unref(formRef)?.removeSchemaByFiled(field);
|
unref(formRef)?.removeSchemaByField(field);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO promisify
|
// TODO promisify
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import type { ComputedRef, Ref } from 'vue';
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
import type { FormProps, FormSchema, FormActionType } from '../types/form';
|
import type { FormProps, FormSchema, FormActionType } from '../types/form';
|
||||||
import type { NamePath } from 'ant-design-vue/lib/form/interface';
|
import type { NamePath } from 'ant-design-vue/lib/form/interface';
|
||||||
import { unref, toRaw } from 'vue';
|
import { unref, toRaw, nextTick } from 'vue';
|
||||||
import { isArray, isFunction, isObject, isString } from '/@/utils/is';
|
import { isArray, isFunction, isObject, isString, isDef, isNullOrUnDef } from '/@/utils/is';
|
||||||
import { deepMerge } from '/@/utils';
|
import { deepMerge } from '/@/utils';
|
||||||
import { dateItemType, handleInputNumberValue } from '../helper';
|
import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper';
|
||||||
import { dateUtil } from '/@/utils/dateUtil';
|
import { dateUtil } from '/@/utils/dateUtil';
|
||||||
import { cloneDeep, uniqBy } from 'lodash-es';
|
import { cloneDeep, uniqBy } from 'lodash-es';
|
||||||
import { error } from '/@/utils/log';
|
import { error } from '/@/utils/log';
|
||||||
|
|
@ -37,9 +37,13 @@ export function useFormEvents({
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
|
|
||||||
Object.keys(formModel).forEach((key) => {
|
Object.keys(formModel).forEach((key) => {
|
||||||
formModel[key] = defaultValueRef.value[key];
|
const schema = unref(getSchema).find((item) => item.field === key);
|
||||||
|
const isInput = schema?.component && defaultValueComponents.includes(schema.component);
|
||||||
|
const defaultValue = cloneDeep(defaultValueRef.value[key]);
|
||||||
|
formModel[key] = isInput ? defaultValue || '' : defaultValue;
|
||||||
});
|
});
|
||||||
clearValidate();
|
nextTick(() => clearValidate());
|
||||||
|
|
||||||
emit('reset', toRaw(formModel));
|
emit('reset', toRaw(formModel));
|
||||||
submitOnReset && handleSubmit();
|
submitOnReset && handleSubmit();
|
||||||
}
|
}
|
||||||
|
|
@ -52,6 +56,10 @@ export function useFormEvents({
|
||||||
.map((item) => item.field)
|
.map((item) => item.field)
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
||||||
|
// key 支持 a.b.c 的嵌套写法
|
||||||
|
const delimiter = '.';
|
||||||
|
const nestKeyArray = fields.filter((item) => item.indexOf(delimiter) >= 0);
|
||||||
|
|
||||||
const validKeys: string[] = [];
|
const validKeys: string[] = [];
|
||||||
Object.keys(values).forEach((key) => {
|
Object.keys(values).forEach((key) => {
|
||||||
const schema = unref(getSchema).find((item) => item.field === key);
|
const schema = unref(getSchema).find((item) => item.field === key);
|
||||||
|
|
@ -82,6 +90,21 @@ export function useFormEvents({
|
||||||
formModel[key] = value;
|
formModel[key] = value;
|
||||||
}
|
}
|
||||||
validKeys.push(key);
|
validKeys.push(key);
|
||||||
|
} else {
|
||||||
|
nestKeyArray.forEach((nestKey: string) => {
|
||||||
|
try {
|
||||||
|
const value = eval('values' + delimiter + nestKey);
|
||||||
|
if (isDef(value)) {
|
||||||
|
formModel[nestKey] = value;
|
||||||
|
validKeys.push(nestKey);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// key not exist
|
||||||
|
if (isDef(defaultValueRef.value[nestKey])) {
|
||||||
|
formModel[nestKey] = cloneDeep(defaultValueRef.value[nestKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
validateFields(validKeys).catch((_) => {});
|
validateFields(validKeys).catch((_) => {});
|
||||||
|
|
@ -89,7 +112,7 @@ export function useFormEvents({
|
||||||
/**
|
/**
|
||||||
* @description: Delete based on field name
|
* @description: Delete based on field name
|
||||||
*/
|
*/
|
||||||
async function removeSchemaByFiled(fields: string | string[]): Promise<void> {
|
async function removeSchemaByField(fields: string | string[]): Promise<void> {
|
||||||
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
||||||
if (!fields) {
|
if (!fields) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -100,7 +123,7 @@ export function useFormEvents({
|
||||||
fieldList = [fields];
|
fieldList = [fields];
|
||||||
}
|
}
|
||||||
for (const field of fieldList) {
|
for (const field of fieldList) {
|
||||||
_removeSchemaByFiled(field, schemaList);
|
_removeSchemaByFeild(field, schemaList);
|
||||||
}
|
}
|
||||||
schemaRef.value = schemaList;
|
schemaRef.value = schemaList;
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +131,7 @@ export function useFormEvents({
|
||||||
/**
|
/**
|
||||||
* @description: Delete based on field name
|
* @description: Delete based on field name
|
||||||
*/
|
*/
|
||||||
function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {
|
function _removeSchemaByFeild(field: string, schemaList: FormSchema[]): void {
|
||||||
if (isString(field)) {
|
if (isString(field)) {
|
||||||
const index = schemaList.findIndex((schema) => schema.field === field);
|
const index = schemaList.findIndex((schema) => schema.field === field);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
|
|
@ -125,18 +148,18 @@ export function useFormEvents({
|
||||||
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
||||||
|
|
||||||
const index = schemaList.findIndex((schema) => schema.field === prefixField);
|
const index = schemaList.findIndex((schema) => schema.field === prefixField);
|
||||||
const hasInList = schemaList.some((item) => item.field === prefixField || schema.field);
|
|
||||||
|
|
||||||
if (!hasInList) return;
|
|
||||||
|
|
||||||
if (!prefixField || index === -1 || first) {
|
if (!prefixField || index === -1 || first) {
|
||||||
first ? schemaList.unshift(schema) : schemaList.push(schema);
|
first ? schemaList.unshift(schema) : schemaList.push(schema);
|
||||||
schemaRef.value = schemaList;
|
schemaRef.value = schemaList;
|
||||||
|
_setDefaultValue(schema);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
schemaList.splice(index + 1, 0, schema);
|
schemaList.splice(index + 1, 0, schema);
|
||||||
}
|
}
|
||||||
|
_setDefaultValue(schema);
|
||||||
|
|
||||||
schemaRef.value = schemaList;
|
schemaRef.value = schemaList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,9 +215,36 @@ export function useFormEvents({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
_setDefaultValue(schema);
|
||||||
|
|
||||||
schemaRef.value = uniqBy(schema, 'field');
|
schemaRef.value = uniqBy(schema, 'field');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _setDefaultValue(data: FormSchema | FormSchema[]) {
|
||||||
|
let schemas: FormSchema[] = [];
|
||||||
|
if (isObject(data)) {
|
||||||
|
schemas.push(data as FormSchema);
|
||||||
|
}
|
||||||
|
if (isArray(data)) {
|
||||||
|
schemas = [...data];
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj: Recordable = {};
|
||||||
|
const currentFieldsValue = getFieldsValue();
|
||||||
|
schemas.forEach((item) => {
|
||||||
|
if (
|
||||||
|
item.component != 'Divider' &&
|
||||||
|
Reflect.has(item, 'field') &&
|
||||||
|
item.field &&
|
||||||
|
!isNullOrUnDef(item.defaultValue) &&
|
||||||
|
!(item.field in currentFieldsValue)
|
||||||
|
) {
|
||||||
|
obj[item.field] = item.defaultValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setFieldsValue(obj);
|
||||||
|
}
|
||||||
|
|
||||||
function getFieldsValue(): Recordable {
|
function getFieldsValue(): Recordable {
|
||||||
const formEl = unref(formElRef);
|
const formEl = unref(formElRef);
|
||||||
if (!formEl) return {};
|
if (!formEl) return {};
|
||||||
|
|
@ -256,7 +306,7 @@ export function useFormEvents({
|
||||||
updateSchema,
|
updateSchema,
|
||||||
resetSchema,
|
resetSchema,
|
||||||
appendSchemaByField,
|
appendSchemaByField,
|
||||||
removeSchemaByFiled,
|
removeSchemaByField,
|
||||||
resetFields,
|
resetFields,
|
||||||
setFieldsValue,
|
setFieldsValue,
|
||||||
scrollToField,
|
scrollToField,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { dateUtil } from '/@/utils/dateUtil';
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
import type { Ref, ComputedRef } from 'vue';
|
import type { Ref, ComputedRef } from 'vue';
|
||||||
import type { FormProps, FormSchema } from '../types/form';
|
import type { FormProps, FormSchema } from '../types/form';
|
||||||
import { set } from 'lodash-es';
|
import { cloneDeep, set } from 'lodash-es';
|
||||||
|
|
||||||
interface UseFormValuesContext {
|
interface UseFormValuesContext {
|
||||||
defaultValueRef: Ref<any>;
|
defaultValueRef: Ref<any>;
|
||||||
|
|
@ -11,6 +11,43 @@ interface UseFormValuesContext {
|
||||||
getProps: ComputedRef<FormProps>;
|
getProps: ComputedRef<FormProps>;
|
||||||
formModel: Recordable;
|
formModel: Recordable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desription deconstruct array-link key. This method will mutate the target.
|
||||||
|
*/
|
||||||
|
function tryDeconstructArray(key: string, value: any, target: Recordable) {
|
||||||
|
const pattern = /^\[(.+)\]$/;
|
||||||
|
if (pattern.test(key)) {
|
||||||
|
const match = key.match(pattern);
|
||||||
|
if (match && match[1]) {
|
||||||
|
const keys = match[1].split(',');
|
||||||
|
value = Array.isArray(value) ? value : [value];
|
||||||
|
keys.forEach((k, index) => {
|
||||||
|
set(target, k.trim(), value[index]);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desription deconstruct object-link key. This method will mutate the target.
|
||||||
|
*/
|
||||||
|
function tryDeconstructObject(key: string, value: any, target: Recordable) {
|
||||||
|
const pattern = /^\{(.+)\}$/;
|
||||||
|
if (pattern.test(key)) {
|
||||||
|
const match = key.match(pattern);
|
||||||
|
if (match && match[1]) {
|
||||||
|
const keys = match[1].split(',');
|
||||||
|
value = isObject(value) ? value : {};
|
||||||
|
keys.forEach((k) => {
|
||||||
|
set(target, k.trim(), value[k.trim()]);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function useFormValues({
|
export function useFormValues({
|
||||||
defaultValueRef,
|
defaultValueRef,
|
||||||
getSchema,
|
getSchema,
|
||||||
|
|
@ -33,14 +70,18 @@ export function useFormValues({
|
||||||
if (isObject(value)) {
|
if (isObject(value)) {
|
||||||
value = transformDateFunc?.(value);
|
value = transformDateFunc?.(value);
|
||||||
}
|
}
|
||||||
if (isArray(value) && value[0]?._isAMomentObject && value[1]?._isAMomentObject) {
|
|
||||||
|
if (isArray(value) && value[0]?.format && value[1]?.format) {
|
||||||
value = value.map((item) => transformDateFunc?.(item));
|
value = value.map((item) => transformDateFunc?.(item));
|
||||||
}
|
}
|
||||||
// Remove spaces
|
// Remove spaces
|
||||||
if (isString(value)) {
|
if (isString(value)) {
|
||||||
value = value.trim();
|
value = value.trim();
|
||||||
}
|
}
|
||||||
set(res, key, value);
|
if (!tryDeconstructArray(key, value, res) && !tryDeconstructObject(key, value, res)) {
|
||||||
|
// 没有解构成功的,按原样赋值
|
||||||
|
set(res, key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return handleRangeTimeValue(res);
|
return handleRangeTimeValue(res);
|
||||||
}
|
}
|
||||||
|
|
@ -77,10 +118,13 @@ export function useFormValues({
|
||||||
const { defaultValue } = item;
|
const { defaultValue } = item;
|
||||||
if (!isNullOrUnDef(defaultValue)) {
|
if (!isNullOrUnDef(defaultValue)) {
|
||||||
obj[item.field] = defaultValue;
|
obj[item.field] = defaultValue;
|
||||||
formModel[item.field] = defaultValue;
|
|
||||||
|
if (formModel[item.field] === undefined) {
|
||||||
|
formModel[item.field] = defaultValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
defaultValueRef.value = obj;
|
defaultValueRef.value = cloneDeep(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { handleFormValues, initDefault };
|
return { handleFormValues, initDefault };
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import type { FormProps, FormSchema } from '../types/form';
|
|
||||||
|
|
||||||
import { computed, unref } from 'vue';
|
import { computed, unref } from 'vue';
|
||||||
|
import type { FormProps, FormSchema } from '../types/form';
|
||||||
import { isNumber } from '/@/utils/is';
|
import { isNumber } from '/@/utils/is';
|
||||||
|
|
||||||
export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<FormProps>) {
|
export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<FormProps>) {
|
||||||
|
|
@ -14,6 +13,7 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
|
||||||
labelWidth: globalLabelWidth,
|
labelWidth: globalLabelWidth,
|
||||||
labelCol: globalLabelCol,
|
labelCol: globalLabelCol,
|
||||||
wrapperCol: globWrapperCol,
|
wrapperCol: globWrapperCol,
|
||||||
|
layout,
|
||||||
} = unref(propsRef);
|
} = unref(propsRef);
|
||||||
|
|
||||||
// If labelWidth is set globally, all items setting
|
// If labelWidth is set globally, all items setting
|
||||||
|
|
@ -33,7 +33,10 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
|
||||||
|
|
||||||
return {
|
return {
|
||||||
labelCol: { style: { width }, ...col },
|
labelCol: { style: { width }, ...col },
|
||||||
wrapperCol: { style: { width: `calc(100% - ${width})` }, ...wrapCol },
|
wrapperCol: {
|
||||||
|
style: { width: layout === 'vertical' ? '100%' : `calc(100% - ${width})` },
|
||||||
|
...wrapCol,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ export const basicProps = {
|
||||||
// 在INPUT组件上单击回车时,是否自动提交
|
// 在INPUT组件上单击回车时,是否自动提交
|
||||||
autoSubmitOnEnter: propTypes.bool.def(false),
|
autoSubmitOnEnter: propTypes.bool.def(false),
|
||||||
submitOnReset: propTypes.bool,
|
submitOnReset: propTypes.bool,
|
||||||
|
submitOnChange: propTypes.bool,
|
||||||
size: propTypes.oneOf(['default', 'small', 'large']).def('default'),
|
size: propTypes.oneOf(['default', 'small', 'large']).def('default'),
|
||||||
// 禁用表单
|
// 禁用表单
|
||||||
disabled: propTypes.bool,
|
disabled: propTypes.bool,
|
||||||
|
|
@ -53,7 +54,7 @@ export const basicProps = {
|
||||||
transformDateFunc: {
|
transformDateFunc: {
|
||||||
type: Function as PropType<Fn>,
|
type: Function as PropType<Fn>,
|
||||||
default: (date: any) => {
|
default: (date: any) => {
|
||||||
return date._isAMomentObject ? date?.format('YYYY-MM-DD HH:mm:ss') : date;
|
return date?.format?.('YYYY-MM-DD HH:mm:ss') ?? date;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
rulesMessageJoinLabel: propTypes.bool.def(true),
|
rulesMessageJoinLabel: propTypes.bool.def(true),
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export interface FormActionType {
|
||||||
updateSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
|
updateSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
|
||||||
resetSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
|
resetSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
|
||||||
setProps: (formProps: Partial<FormProps>) => Promise<void>;
|
setProps: (formProps: Partial<FormProps>) => Promise<void>;
|
||||||
removeSchemaByFiled: (field: string | string[]) => Promise<void>;
|
removeSchemaByField: (field: string | string[]) => Promise<void>;
|
||||||
appendSchemaByField: (
|
appendSchemaByField: (
|
||||||
schema: FormSchema,
|
schema: FormSchema,
|
||||||
prefixField: string | undefined,
|
prefixField: string | undefined,
|
||||||
|
|
@ -49,17 +49,20 @@ export type RegisterFn = (formInstance: FormActionType) => void;
|
||||||
export type UseFormReturnType = [RegisterFn, FormActionType];
|
export type UseFormReturnType = [RegisterFn, FormActionType];
|
||||||
|
|
||||||
export interface FormProps {
|
export interface FormProps {
|
||||||
|
name?: string;
|
||||||
layout?: 'vertical' | 'inline' | 'horizontal';
|
layout?: 'vertical' | 'inline' | 'horizontal';
|
||||||
// Form value
|
// Form value
|
||||||
model?: Recordable;
|
model?: Recordable;
|
||||||
// The width of all items in the entire form
|
// The width of all items in the entire form
|
||||||
labelWidth?: number | string;
|
labelWidth?: number | string;
|
||||||
//alignment
|
// alignment
|
||||||
labelAlign?: 'left' | 'right';
|
labelAlign?: 'left' | 'right';
|
||||||
//Row configuration for the entire form
|
// Row configuration for the entire form
|
||||||
rowProps?: RowProps;
|
rowProps?: RowProps;
|
||||||
// Submit form on reset
|
// Submit form on reset
|
||||||
submitOnReset?: boolean;
|
submitOnReset?: boolean;
|
||||||
|
// Submit form on form changing
|
||||||
|
submitOnChange?: boolean;
|
||||||
// Col configuration for the entire form
|
// Col configuration for the entire form
|
||||||
labelCol?: Partial<ColEx>;
|
labelCol?: Partial<ColEx>;
|
||||||
// Col configuration for the entire form
|
// Col configuration for the entire form
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ export type ComponentType =
|
||||||
| 'Select'
|
| 'Select'
|
||||||
| 'ApiSelect'
|
| 'ApiSelect'
|
||||||
| 'TreeSelect'
|
| 'TreeSelect'
|
||||||
|
| 'ApiTree'
|
||||||
| 'ApiTreeSelect'
|
| 'ApiTreeSelect'
|
||||||
| 'ApiRadioGroup'
|
| 'ApiRadioGroup'
|
||||||
| 'RadioButtonGroup'
|
| 'RadioButtonGroup'
|
||||||
|
|
@ -112,4 +113,5 @@ export type ComponentType =
|
||||||
| 'Render'
|
| 'Render'
|
||||||
| 'Slider'
|
| 'Slider'
|
||||||
| 'Rate'
|
| 'Rate'
|
||||||
| 'Divider';
|
| 'Divider'
|
||||||
|
| 'ApiTransfer';
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
:openKeys="getOpenKeys"
|
:openKeys="getOpenKeys"
|
||||||
:inlineIndent="inlineIndent"
|
:inlineIndent="inlineIndent"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
@openChange="handleOpenChange"
|
@open-change="handleOpenChange"
|
||||||
:class="getMenuClass"
|
:class="getMenuClass"
|
||||||
@click="handleMenuClick"
|
@click="handleMenuClick"
|
||||||
:subMenuOpenDelay="0.2"
|
:subMenuOpenDelay="0.2"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export default defineComponent({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
emits: ['cancel'],
|
emits: ['cancel'],
|
||||||
setup(props, { slots }) {
|
setup(props, { slots, emit }) {
|
||||||
const { visible, draggable, destroyOnClose } = toRefs(props);
|
const { visible, draggable, destroyOnClose } = toRefs(props);
|
||||||
const attrs = useAttrs();
|
const attrs = useAttrs();
|
||||||
useModalDragMove({
|
useModalDragMove({
|
||||||
|
|
@ -19,8 +19,12 @@ export default defineComponent({
|
||||||
draggable,
|
draggable,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const onCancel = (e: Event) => {
|
||||||
|
emit('cancel', e);
|
||||||
|
};
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const propsData = { ...unref(attrs), ...props } as Recordable;
|
const propsData = { ...unref(attrs), ...props, onCancel } as Recordable;
|
||||||
return <Modal {...propsData}>{extendSlots(slots)}</Modal>;
|
return <Modal {...propsData}>{extendSlots(slots)}</Modal>;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
&-title {
|
&-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 16px;
|
|
||||||
|
|
||||||
.base-title {
|
.base-title {
|
||||||
cursor: move !important;
|
cursor: move !important;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
:title="title"
|
:title="title"
|
||||||
v-bind="omit($attrs, 'class')"
|
v-bind="omit($attrs, 'class')"
|
||||||
ref="headerRef"
|
ref="headerRef"
|
||||||
v-if="content || $slots.headerContent || title || getHeaderSlots.length"
|
v-if="getShowHeader"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<template v-if="content">
|
<template v-if="content">
|
||||||
|
|
@ -99,6 +99,10 @@
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getShowHeader = computed(
|
||||||
|
() => props.content || slots?.headerContent || props.title || getHeaderSlots.value.length,
|
||||||
|
);
|
||||||
|
|
||||||
const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
|
const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
|
||||||
|
|
||||||
const getHeaderSlots = computed(() => {
|
const getHeaderSlots = computed(() => {
|
||||||
|
|
@ -150,6 +154,7 @@
|
||||||
getClass,
|
getClass,
|
||||||
getHeaderSlots,
|
getHeaderSlots,
|
||||||
prefixCls,
|
prefixCls,
|
||||||
|
getShowHeader,
|
||||||
getShowFooter,
|
getShowFooter,
|
||||||
omit,
|
omit,
|
||||||
getContentClass,
|
getContentClass,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { toCanvas } from 'qrcode';
|
import { toCanvas } from 'qrcode'
|
||||||
import type { QRCodeRenderersOptions } from 'qrcode';
|
import type { QRCodeRenderersOptions } from 'qrcode'
|
||||||
import { RenderQrCodeParams, ContentType } from './typing';
|
import { RenderQrCodeParams, ContentType } from './typing'
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
export const renderQrCode = ({
|
export const renderQrCode = ({
|
||||||
canvas,
|
canvas,
|
||||||
|
|
@ -9,29 +9,29 @@ export const renderQrCode = ({
|
||||||
width = 0,
|
width = 0,
|
||||||
options: params = {},
|
options: params = {},
|
||||||
}: RenderQrCodeParams) => {
|
}: RenderQrCodeParams) => {
|
||||||
const options = cloneDeep(params);
|
const options = cloneDeep(params)
|
||||||
// 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率
|
// 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率
|
||||||
options.errorCorrectionLevel = options.errorCorrectionLevel || getErrorCorrectionLevel(content);
|
options.errorCorrectionLevel = options.errorCorrectionLevel || getErrorCorrectionLevel(content)
|
||||||
|
|
||||||
return getOriginWidth(content, options).then((_width: number) => {
|
return getOriginWidth(content, options).then((_width: number) => {
|
||||||
options.scale = width === 0 ? undefined : (width / _width) * 4;
|
options.scale = width === 0 ? undefined : (width / _width) * 4
|
||||||
return toCanvas(canvas, content, options);
|
return toCanvas(canvas, content, options)
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
// 得到原QrCode的大小,以便缩放得到正确的QrCode大小
|
// 得到原QrCode的大小,以便缩放得到正确的QrCode大小
|
||||||
function getOriginWidth(content: ContentType, options: QRCodeRenderersOptions) {
|
function getOriginWidth(content: ContentType, options: QRCodeRenderersOptions) {
|
||||||
const _canvas = document.createElement('canvas');
|
const _canvas = document.createElement('canvas')
|
||||||
return toCanvas(_canvas, content, options).then(() => _canvas.width);
|
return toCanvas(_canvas, content, options).then(() => _canvas.width)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对于内容少的QrCode,增大容错率
|
// 对于内容少的QrCode,增大容错率
|
||||||
function getErrorCorrectionLevel(content: ContentType) {
|
function getErrorCorrectionLevel(content: ContentType) {
|
||||||
if (content.length > 36) {
|
if (content.length > 36) {
|
||||||
return 'M';
|
return 'M'
|
||||||
} else if (content.length > 16) {
|
} else if (content.length > 16) {
|
||||||
return 'Q';
|
return 'Q'
|
||||||
} else {
|
} else {
|
||||||
return 'H';
|
return 'H'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,10 @@
|
||||||
</span>
|
</span>
|
||||||
<SimpleMenuTag :item="item" :collapseParent="!!collapse && !!parent" />
|
<SimpleMenuTag :item="item" :collapseParent="!!collapse && !!parent" />
|
||||||
</template>
|
</template>
|
||||||
<template v-for="childrenItem in item.children || []" :key="childrenItem.path">
|
<template
|
||||||
|
v-for="childrenItem in item.children || []"
|
||||||
|
:key="childrenItem.paramPath || childrenItem.path"
|
||||||
|
>
|
||||||
<SimpleSubMenu v-bind="$props" :item="childrenItem" :parent="false" />
|
<SimpleSubMenu v-bind="$props" :item="childrenItem" :parent="false" />
|
||||||
</template>
|
</template>
|
||||||
</SubMenu>
|
</SubMenu>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
:overlayClassName="`${prefixCls}-menu-popover`"
|
:overlayClassName="`${prefixCls}-menu-popover`"
|
||||||
v-else
|
v-else
|
||||||
:visible="getIsOpend"
|
:visible="getIsOpend"
|
||||||
@visibleChange="handleVisibleChange"
|
@visible-change="handleVisibleChange"
|
||||||
:overlayStyle="getOverlayStyle"
|
:overlayStyle="getOverlayStyle"
|
||||||
:align="{ offset: [0, 0] }"
|
:align="{ offset: [0, 0] }"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
display: block;
|
display: block;
|
||||||
width: 2px;
|
width: 2px;
|
||||||
background-color: @primary-color;
|
|
||||||
content: '';
|
content: '';
|
||||||
|
background-color: @primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,8 +45,8 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
right: 18px;
|
right: 18px;
|
||||||
transform: translateY(-50%) rotate(-90deg);
|
|
||||||
transition: transform @transition-time @ease-in-out;
|
transition: transform @transition-time @ease-in-out;
|
||||||
|
transform: translateY(-50%) rotate(-90deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,12 +128,12 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
font-size: @font-size-base;
|
font-size: @font-size-base;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: none;
|
outline: none;
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:active {
|
&:active {
|
||||||
|
|
@ -178,8 +178,8 @@
|
||||||
&-vertical &-submenu-collapse {
|
&-vertical &-submenu-collapse {
|
||||||
.@{submenu-popup-prefix-cls} {
|
.@{submenu-popup-prefix-cls} {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.@{menu-prefix-cls}-submenu-collapsed-show-tit {
|
.@{menu-prefix-cls}-submenu-collapsed-show-tit {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -244,8 +244,8 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: @primary-color;
|
|
||||||
content: '';
|
content: '';
|
||||||
|
background-color: @primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -276,8 +276,8 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: @primary-color;
|
|
||||||
content: '';
|
content: '';
|
||||||
|
background-color: @primary-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{menu-prefix-cls}-submenu-collapse {
|
.@{menu-prefix-cls}-submenu-collapse {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ export { default as BasicTable } from './src/BasicTable.vue';
|
||||||
export { default as TableAction } from './src/components/TableAction.vue';
|
export { default as TableAction } from './src/components/TableAction.vue';
|
||||||
export { default as EditTableHeaderIcon } from './src/components/EditTableHeaderIcon.vue';
|
export { default as EditTableHeaderIcon } from './src/components/EditTableHeaderIcon.vue';
|
||||||
export { default as TableImg } from './src/components/TableImg.vue';
|
export { default as TableImg } from './src/components/TableImg.vue';
|
||||||
|
|
||||||
export * from './src/types/table';
|
export * from './src/types/table';
|
||||||
export * from './src/types/pagination';
|
export * from './src/types/pagination';
|
||||||
export * from './src/types/tableAction';
|
export * from './src/types/tableAction';
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div ref="wrapRef" :class="getWrapperClass">
|
<div ref="wrapRef" :class="getWrapperClass">
|
||||||
<BasicForm
|
<BasicForm
|
||||||
|
ref="formRef"
|
||||||
submitOnReset
|
submitOnReset
|
||||||
v-bind="getFormProps"
|
v-bind="getFormProps"
|
||||||
v-if="getBindValues.useSearchForm"
|
v-if="getBindValues.useSearchForm"
|
||||||
|
|
@ -24,10 +25,16 @@
|
||||||
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
|
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
|
||||||
<slot :name="item" v-bind="data || {}"></slot>
|
<slot :name="item" v-bind="data || {}"></slot>
|
||||||
</template>
|
</template>
|
||||||
|
<template #headerCell="{ column }">
|
||||||
<template #[`header-${column.dataIndex}`] v-for="column in columns" :key="column.dataIndex">
|
|
||||||
<HeaderCell :column="column" />
|
<HeaderCell :column="column" />
|
||||||
</template>
|
</template>
|
||||||
|
<!-- 增加对antdv3.x兼容 -->
|
||||||
|
<template #bodyCell="data">
|
||||||
|
<slot name="bodyCell" v-bind="data || {}"></slot>
|
||||||
|
</template>
|
||||||
|
<!-- <template #[`header-${column.dataIndex}`] v-for="(column, index) in columns" :key="index">-->
|
||||||
|
<!-- <HeaderCell :column="column" />-->
|
||||||
|
<!-- </template>-->
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -43,7 +50,6 @@
|
||||||
import { Table } from 'ant-design-vue';
|
import { Table } from 'ant-design-vue';
|
||||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||||
import { PageWrapperFixedHeightKey } from '/@/components/Page';
|
import { PageWrapperFixedHeightKey } from '/@/components/Page';
|
||||||
import expandIcon from './components/ExpandIcon';
|
|
||||||
import HeaderCell from './components/HeaderCell.vue';
|
import HeaderCell from './components/HeaderCell.vue';
|
||||||
import { InnerHandlers } from './types/table';
|
import { InnerHandlers } from './types/table';
|
||||||
|
|
||||||
|
|
@ -53,6 +59,7 @@
|
||||||
import { useLoading } from './hooks/useLoading';
|
import { useLoading } from './hooks/useLoading';
|
||||||
import { useRowSelection } from './hooks/useRowSelection';
|
import { useRowSelection } from './hooks/useRowSelection';
|
||||||
import { useTableScroll } from './hooks/useTableScroll';
|
import { useTableScroll } from './hooks/useTableScroll';
|
||||||
|
import { useTableScrollTo } from './hooks/useScrollTo';
|
||||||
import { useCustomRow } from './hooks/useCustomRow';
|
import { useCustomRow } from './hooks/useCustomRow';
|
||||||
import { useTableStyle } from './hooks/useTableStyle';
|
import { useTableStyle } from './hooks/useTableStyle';
|
||||||
import { useTableHeader } from './hooks/useTableHeader';
|
import { useTableHeader } from './hooks/useTableHeader';
|
||||||
|
|
@ -97,6 +104,7 @@
|
||||||
const tableData = ref<Recordable[]>([]);
|
const tableData = ref<Recordable[]>([]);
|
||||||
|
|
||||||
const wrapRef = ref(null);
|
const wrapRef = ref(null);
|
||||||
|
const formRef = ref(null);
|
||||||
const innerPropsRef = ref<Partial<BasicTableProps>>();
|
const innerPropsRef = ref<Partial<BasicTableProps>>();
|
||||||
|
|
||||||
const { prefixCls } = useDesign('basic-table');
|
const { prefixCls } = useDesign('basic-table');
|
||||||
|
|
@ -185,8 +193,12 @@
|
||||||
getColumnsRef,
|
getColumnsRef,
|
||||||
getRowSelectionRef,
|
getRowSelectionRef,
|
||||||
getDataSourceRef,
|
getDataSourceRef,
|
||||||
|
wrapRef,
|
||||||
|
formRef,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { scrollTo } = useTableScrollTo(tableElRef, getDataSourceRef);
|
||||||
|
|
||||||
const { customRow } = useCustomRow(getProps, {
|
const { customRow } = useCustomRow(getProps, {
|
||||||
setSelectedRowKeys,
|
setSelectedRowKeys,
|
||||||
getSelectRowKeys,
|
getSelectRowKeys,
|
||||||
|
|
@ -197,7 +209,11 @@
|
||||||
|
|
||||||
const { getRowClassName } = useTableStyle(getProps, prefixCls);
|
const { getRowClassName } = useTableStyle(getProps, prefixCls);
|
||||||
|
|
||||||
const { getExpandOption, expandAll, collapseAll } = useTableExpand(getProps, tableData, emit);
|
const { getExpandOption, expandAll, expandRows, collapseAll } = useTableExpand(
|
||||||
|
getProps,
|
||||||
|
tableData,
|
||||||
|
emit,
|
||||||
|
);
|
||||||
|
|
||||||
const handlers: InnerHandlers = {
|
const handlers: InnerHandlers = {
|
||||||
onColumnsChange: (data: ColumnChangeParam[]) => {
|
onColumnsChange: (data: ColumnChangeParam[]) => {
|
||||||
|
|
@ -222,10 +238,8 @@
|
||||||
const getBindValues = computed(() => {
|
const getBindValues = computed(() => {
|
||||||
const dataSource = unref(getDataSourceRef);
|
const dataSource = unref(getDataSourceRef);
|
||||||
let propsData: Recordable = {
|
let propsData: Recordable = {
|
||||||
// ...(dataSource.length === 0 ? { getPopupContainer: () => document.body } : {}),
|
|
||||||
...attrs,
|
...attrs,
|
||||||
customRow,
|
customRow,
|
||||||
expandIcon: slots.expandIcon ? null : expandIcon(),
|
|
||||||
...unref(getProps),
|
...unref(getProps),
|
||||||
...unref(getHeaderProps),
|
...unref(getHeaderProps),
|
||||||
scroll: unref(getScrollRef),
|
scroll: unref(getScrollRef),
|
||||||
|
|
@ -239,9 +253,9 @@
|
||||||
footer: unref(getFooterProps),
|
footer: unref(getFooterProps),
|
||||||
...unref(getExpandOption),
|
...unref(getExpandOption),
|
||||||
};
|
};
|
||||||
if (slots.expandedRowRender) {
|
// if (slots.expandedRowRender) {
|
||||||
propsData = omit(propsData, 'scroll');
|
// propsData = omit(propsData, 'scroll');
|
||||||
}
|
// }
|
||||||
|
|
||||||
propsData = omit(propsData, ['class', 'onChange']);
|
propsData = omit(propsData, ['class', 'onChange']);
|
||||||
return propsData;
|
return propsData;
|
||||||
|
|
@ -300,7 +314,9 @@
|
||||||
getShowPagination,
|
getShowPagination,
|
||||||
setCacheColumnsByField,
|
setCacheColumnsByField,
|
||||||
expandAll,
|
expandAll,
|
||||||
|
expandRows,
|
||||||
collapseAll,
|
collapseAll,
|
||||||
|
scrollTo,
|
||||||
getSize: () => {
|
getSize: () => {
|
||||||
return unref(getBindValues).size as SizeType;
|
return unref(getBindValues).size as SizeType;
|
||||||
},
|
},
|
||||||
|
|
@ -312,6 +328,7 @@
|
||||||
emit('register', tableAction, formActions);
|
emit('register', tableAction, formActions);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
formRef,
|
||||||
tableElRef,
|
tableElRef,
|
||||||
getBindValues,
|
getBindValues,
|
||||||
getLoading,
|
getLoading,
|
||||||
|
|
@ -346,6 +363,7 @@
|
||||||
|
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
&-row__striped {
|
&-row__striped {
|
||||||
td {
|
td {
|
||||||
|
|
@ -357,6 +375,7 @@
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|
||||||
.ant-form {
|
.ant-form {
|
||||||
|
width: 100%;
|
||||||
padding: 12px 10px 6px;
|
padding: 12px 10px 6px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
background-color: @component-background;
|
background-color: @component-background;
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ import {
|
||||||
Switch,
|
Switch,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
TimePicker,
|
TimePicker,
|
||||||
|
AutoComplete,
|
||||||
|
Radio,
|
||||||
} from 'ant-design-vue';
|
} from 'ant-design-vue';
|
||||||
import type { ComponentType } from './types/componentType';
|
import type { ComponentType } from './types/componentType';
|
||||||
import { ApiSelect, ApiTreeSelect } from '/@/components/Form';
|
import { ApiSelect, ApiTreeSelect, RadioButtonGroup, ApiRadioGroup } from '/@/components/Form';
|
||||||
|
|
||||||
const componentMap = new Map<ComponentType, Component>();
|
const componentMap = new Map<ComponentType, Component>();
|
||||||
|
|
||||||
|
|
@ -17,11 +19,15 @@ componentMap.set('Input', Input);
|
||||||
componentMap.set('InputNumber', InputNumber);
|
componentMap.set('InputNumber', InputNumber);
|
||||||
componentMap.set('Select', Select);
|
componentMap.set('Select', Select);
|
||||||
componentMap.set('ApiSelect', ApiSelect);
|
componentMap.set('ApiSelect', ApiSelect);
|
||||||
|
componentMap.set('AutoComplete', AutoComplete);
|
||||||
componentMap.set('ApiTreeSelect', ApiTreeSelect);
|
componentMap.set('ApiTreeSelect', ApiTreeSelect);
|
||||||
componentMap.set('Switch', Switch);
|
componentMap.set('Switch', Switch);
|
||||||
componentMap.set('Checkbox', Checkbox);
|
componentMap.set('Checkbox', Checkbox);
|
||||||
componentMap.set('DatePicker', DatePicker);
|
componentMap.set('DatePicker', DatePicker);
|
||||||
componentMap.set('TimePicker', TimePicker);
|
componentMap.set('TimePicker', TimePicker);
|
||||||
|
componentMap.set('RadioGroup', Radio.Group);
|
||||||
|
componentMap.set('RadioButtonGroup', RadioButtonGroup);
|
||||||
|
componentMap.set('ApiRadioGroup', ApiRadioGroup);
|
||||||
|
|
||||||
export function add(compName: ComponentType, component: Component) {
|
export function add(compName: ComponentType, component: Component) {
|
||||||
componentMap.set(compName, component);
|
componentMap.set(compName, component);
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { BasicArrow } from '/@/components/Basic';
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
return (props: Recordable) => {
|
|
||||||
if (!props.expandable) {
|
|
||||||
if (props.needIndentSpaced) {
|
|
||||||
return <span class="ant-table-row-expand-icon ant-table-row-spaced" />;
|
|
||||||
} else {
|
|
||||||
return <span />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<BasicArrow
|
|
||||||
style="margin-right: 8px"
|
|
||||||
iconStyle="margin-top: -2px;"
|
|
||||||
onClick={(e: Event) => {
|
|
||||||
props.onExpand(props.record, e);
|
|
||||||
}}
|
|
||||||
expand={props.expanded}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
const { prefixCls } = useDesign('basic-table-header-cell');
|
const { prefixCls } = useDesign('basic-table-header-cell');
|
||||||
|
|
||||||
const getIsEdit = computed(() => !!props.column?.edit);
|
const getIsEdit = computed(() => !!props.column?.edit);
|
||||||
const getTitle = computed(() => props.column?.customTitle);
|
const getTitle = computed(() => props.column?.customTitle || props.column?.title);
|
||||||
const getHelpMessage = computed(() => props.column?.helpMessage);
|
const getHelpMessage = computed(() => props.column?.helpMessage);
|
||||||
|
|
||||||
return { prefixCls, getIsEdit, getTitle, getHelpMessage };
|
return { prefixCls, getIsEdit, getTitle, getHelpMessage };
|
||||||
|
|
|
||||||
|
|
@ -104,21 +104,20 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
const getDropdownList = computed((): any[] => {
|
const getDropdownList = computed((): any[] => {
|
||||||
return (toRaw(props.dropDownActions) || [])
|
const list = (toRaw(props.dropDownActions) || []).filter((action) => {
|
||||||
.filter((action) => {
|
return hasPermission(action.auth) && isIfShow(action);
|
||||||
return hasPermission(action.auth) && isIfShow(action);
|
});
|
||||||
})
|
return list.map((action, index) => {
|
||||||
.map((action, index) => {
|
const { label, popConfirm } = action;
|
||||||
const { label, popConfirm } = action;
|
return {
|
||||||
return {
|
...action,
|
||||||
...action,
|
...popConfirm,
|
||||||
...popConfirm,
|
onConfirm: popConfirm?.confirm,
|
||||||
onConfirm: popConfirm?.confirm,
|
onCancel: popConfirm?.cancel,
|
||||||
onCancel: popConfirm?.cancel,
|
text: label,
|
||||||
text: label,
|
divider: index < list.length - 1 ? props.divider : false,
|
||||||
divider: index < props.dropDownActions.length - 1 ? props.divider : false,
|
};
|
||||||
};
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const getAlign = computed(() => {
|
const getAlign = computed(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,4 @@
|
||||||
<template>
|
<script lang="tsx">
|
||||||
<div :class="prefixCls">
|
|
||||||
<div
|
|
||||||
v-show="!isEdit"
|
|
||||||
:class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }"
|
|
||||||
@click="handleEdit"
|
|
||||||
>
|
|
||||||
<div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">
|
|
||||||
{{ getValues ? getValues : ' ' }}
|
|
||||||
</div>
|
|
||||||
<FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-spin v-if="isEdit" :spinning="spinning">
|
|
||||||
<div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
|
|
||||||
<CellComponent
|
|
||||||
v-bind="getComponentProps"
|
|
||||||
:component="getComponent"
|
|
||||||
:style="getWrapperStyle"
|
|
||||||
:popoverVisible="getRuleVisible"
|
|
||||||
:rule="getRule"
|
|
||||||
:ruleMessage="ruleMessage"
|
|
||||||
:class="getWrapperClass"
|
|
||||||
ref="elRef"
|
|
||||||
@change="handleChange"
|
|
||||||
@options-change="handleOptionsChange"
|
|
||||||
@pressEnter="handleEnter"
|
|
||||||
/>
|
|
||||||
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
|
|
||||||
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
|
|
||||||
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-spin>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts">
|
|
||||||
import type { CSSProperties, PropType } from 'vue';
|
import type { CSSProperties, PropType } from 'vue';
|
||||||
import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue';
|
import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue';
|
||||||
import type { BasicColumn } from '../../types/table';
|
import type { BasicColumn } from '../../types/table';
|
||||||
|
|
@ -50,13 +14,13 @@
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
|
import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
|
||||||
import { createPlaceholderMessage } from './helper';
|
import { createPlaceholderMessage } from './helper';
|
||||||
import { omit, pick, set } from 'lodash-es';
|
import { pick, set } from 'lodash-es';
|
||||||
import { treeToList } from '/@/utils/helper/treeHelper';
|
import { treeToList } from '/@/utils/helper/treeHelper';
|
||||||
import { Spin } from 'ant-design-vue';
|
import { Spin } from 'ant-design-vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'EditableCell',
|
name: 'EditableCell',
|
||||||
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
|
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, Spin },
|
||||||
directives: {
|
directives: {
|
||||||
clickOutside,
|
clickOutside,
|
||||||
},
|
},
|
||||||
|
|
@ -100,13 +64,6 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
const getComponentProps = computed(() => {
|
const getComponentProps = computed(() => {
|
||||||
const compProps = props.column?.editComponentProps ?? {};
|
|
||||||
const component = unref(getComponent);
|
|
||||||
const apiSelectProps: Recordable = {};
|
|
||||||
if (component === 'ApiSelect') {
|
|
||||||
apiSelectProps.cache = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isCheckValue = unref(getIsCheckComp);
|
const isCheckValue = unref(getIsCheckComp);
|
||||||
|
|
||||||
const valueField = isCheckValue ? 'checked' : 'value';
|
const valueField = isCheckValue ? 'checked' : 'value';
|
||||||
|
|
@ -114,19 +71,49 @@
|
||||||
|
|
||||||
const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
|
const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
|
||||||
|
|
||||||
|
let compProps = props.column?.editComponentProps ?? {};
|
||||||
|
const { record, column, index } = props;
|
||||||
|
|
||||||
|
if (isFunction(compProps)) {
|
||||||
|
compProps = compProps({ text: val, record, column, index }) ?? {};
|
||||||
|
}
|
||||||
|
const component = unref(getComponent);
|
||||||
|
const apiSelectProps: Recordable = {};
|
||||||
|
if (component === 'ApiSelect') {
|
||||||
|
apiSelectProps.cache = true;
|
||||||
|
}
|
||||||
|
upEditDynamicDisabled(record, column, value);
|
||||||
return {
|
return {
|
||||||
size: 'small',
|
size: 'small',
|
||||||
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
|
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
|
||||||
getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body,
|
|
||||||
placeholder: createPlaceholderMessage(unref(getComponent)),
|
placeholder: createPlaceholderMessage(unref(getComponent)),
|
||||||
...apiSelectProps,
|
...apiSelectProps,
|
||||||
...omit(compProps, 'onChange'),
|
...compProps,
|
||||||
[valueField]: value,
|
[valueField]: value,
|
||||||
};
|
disabled: unref(getDisable),
|
||||||
|
} as any;
|
||||||
|
});
|
||||||
|
function upEditDynamicDisabled(record, column, value) {
|
||||||
|
if (!record) return false;
|
||||||
|
const { key, dataIndex } = column;
|
||||||
|
if (!key && !dataIndex) return;
|
||||||
|
const dataKey = (dataIndex || key) as string;
|
||||||
|
set(record, dataKey, value);
|
||||||
|
}
|
||||||
|
const getDisable = computed(() => {
|
||||||
|
const { editDynamicDisabled } = props.column;
|
||||||
|
let disabled = false;
|
||||||
|
if (isBoolean(editDynamicDisabled)) {
|
||||||
|
disabled = editDynamicDisabled;
|
||||||
|
}
|
||||||
|
if (isFunction(editDynamicDisabled)) {
|
||||||
|
const { record } = props;
|
||||||
|
disabled = editDynamicDisabled({ record });
|
||||||
|
}
|
||||||
|
return disabled;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getValues = computed(() => {
|
const getValues = computed(() => {
|
||||||
const { editComponentProps, editValueMap } = props.column;
|
const { editValueMap } = props.column;
|
||||||
|
|
||||||
const value = unref(currentValueRef);
|
const value = unref(currentValueRef);
|
||||||
|
|
||||||
|
|
@ -135,11 +122,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const component = unref(getComponent);
|
const component = unref(getComponent);
|
||||||
if (!component.includes('Select')) {
|
if (!component.includes('Select') && !component.includes('Radio')) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
|
const options: LabelValueOptions =
|
||||||
|
unref(getComponentProps)?.options ?? (unref(optionsRef) || []);
|
||||||
const option = options.find((item) => `${item.value}` === `${value}`);
|
const option = options.find((item) => `${item.value}` === `${value}`);
|
||||||
|
|
||||||
return option?.label ?? value;
|
return option?.label ?? value;
|
||||||
|
|
@ -190,14 +178,16 @@
|
||||||
const component = unref(getComponent);
|
const component = unref(getComponent);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
currentValueRef.value = e;
|
currentValueRef.value = e;
|
||||||
} else if (e?.target && Reflect.has(e.target, 'value')) {
|
|
||||||
currentValueRef.value = (e as ChangeEvent).target.value;
|
|
||||||
} else if (component === 'Checkbox') {
|
} else if (component === 'Checkbox') {
|
||||||
currentValueRef.value = (e as ChangeEvent).target.checked;
|
currentValueRef.value = (e as ChangeEvent).target.checked;
|
||||||
} else if (isString(e) || isBoolean(e) || isNumber(e)) {
|
} else if (component === 'Switch') {
|
||||||
|
currentValueRef.value = e;
|
||||||
|
} else if (e?.target && Reflect.has(e.target, 'value')) {
|
||||||
|
currentValueRef.value = (e as ChangeEvent).target.value;
|
||||||
|
} else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(e)) {
|
||||||
currentValueRef.value = e;
|
currentValueRef.value = e;
|
||||||
}
|
}
|
||||||
const onChange = props.column?.editComponentProps?.onChange;
|
const onChange = unref(getComponentProps)?.onChange;
|
||||||
if (onChange && isFunction(onChange)) onChange(...arguments);
|
if (onChange && isFunction(onChange)) onChange(...arguments);
|
||||||
|
|
||||||
table.emit?.('edit-change', {
|
table.emit?.('edit-change', {
|
||||||
|
|
@ -265,7 +255,7 @@
|
||||||
result = await beforeEditSubmit({
|
result = await beforeEditSubmit({
|
||||||
record: pick(record, keys),
|
record: pick(record, keys),
|
||||||
index,
|
index,
|
||||||
key: key as string,
|
key: dataKey as string,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -281,7 +271,7 @@
|
||||||
|
|
||||||
set(record, dataKey, value);
|
set(record, dataKey, value);
|
||||||
//const record = await table.updateTableData(index, dataKey, value);
|
//const record = await table.updateTableData(index, dataKey, value);
|
||||||
needEmit && table.emit?.('edit-end', { record, index, key, value });
|
needEmit && table.emit?.('edit-end', { record, index, key: dataKey, value });
|
||||||
isEdit.value = false;
|
isEdit.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,7 +312,7 @@
|
||||||
|
|
||||||
// only ApiSelect or TreeSelect
|
// only ApiSelect or TreeSelect
|
||||||
function handleOptionsChange(options: LabelValueOptions) {
|
function handleOptionsChange(options: LabelValueOptions) {
|
||||||
const { replaceFields } = props.column?.editComponentProps ?? {};
|
const { replaceFields } = unref(getComponentProps);
|
||||||
const component = unref(getComponent);
|
const component = unref(getComponent);
|
||||||
if (component === 'ApiTreeSelect') {
|
if (component === 'ApiTreeSelect') {
|
||||||
const { title = 'title', value = 'value', children = 'children' } = replaceFields || {};
|
const { title = 'title', value = 'value', children = 'children' } = replaceFields || {};
|
||||||
|
|
@ -355,7 +345,7 @@
|
||||||
|
|
||||||
if (props.column.dataIndex) {
|
if (props.column.dataIndex) {
|
||||||
if (!props.record.editValueRefs) props.record.editValueRefs = {};
|
if (!props.record.editValueRefs) props.record.editValueRefs = {};
|
||||||
props.record.editValueRefs[props.column.dataIndex] = currentValueRef;
|
props.record.editValueRefs[props.column.dataIndex as any] = currentValueRef;
|
||||||
}
|
}
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
props.record.onCancelEdit = () => {
|
props.record.onCancelEdit = () => {
|
||||||
|
|
@ -398,6 +388,59 @@
|
||||||
spinning,
|
spinning,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div class={this.prefixCls}>
|
||||||
|
<div
|
||||||
|
v-show={!this.isEdit}
|
||||||
|
class={{ [`${this.prefixCls}__normal`]: true, 'ellipsis-cell': this.column.ellipsis }}
|
||||||
|
onClick={this.handleEdit}
|
||||||
|
>
|
||||||
|
<div class="cell-content" title={this.column.ellipsis ? this.getValues ?? '' : ''}>
|
||||||
|
{this.column.editRender
|
||||||
|
? this.column.editRender({
|
||||||
|
text: this.value,
|
||||||
|
record: this.record as Recordable,
|
||||||
|
column: this.column,
|
||||||
|
index: this.index,
|
||||||
|
})
|
||||||
|
: this.getValues
|
||||||
|
? this.getValues
|
||||||
|
: '\u00A0'}
|
||||||
|
</div>
|
||||||
|
{!this.column.editRow && <FormOutlined class={`${this.prefixCls}__normal-icon`} />}
|
||||||
|
</div>
|
||||||
|
{this.isEdit && (
|
||||||
|
<Spin spinning={this.spinning}>
|
||||||
|
<div class={`${this.prefixCls}__wrapper`} v-click-outside={this.onClickOutside}>
|
||||||
|
<CellComponent
|
||||||
|
{...this.getComponentProps}
|
||||||
|
component={this.getComponent}
|
||||||
|
style={this.getWrapperStyle}
|
||||||
|
popoverVisible={this.getRuleVisible}
|
||||||
|
rule={this.getRule}
|
||||||
|
ruleMessage={this.ruleMessage}
|
||||||
|
class={this.getWrapperClass}
|
||||||
|
ref="elRef"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
onOptionsChange={this.handleOptionsChange}
|
||||||
|
onPressEnter={this.handleEnter}
|
||||||
|
/>
|
||||||
|
{!this.getRowEditable && (
|
||||||
|
<div class={`${this.prefixCls}__action`}>
|
||||||
|
<CheckOutlined
|
||||||
|
class={[`${this.prefixCls}__icon`, 'mx-2']}
|
||||||
|
onClick={this.handleSubmitClick}
|
||||||
|
/>
|
||||||
|
<CloseOutlined class={`${this.prefixCls}__icon `} onClick={this.handleCancel} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const { t } = useI18n();
|
||||||
* @description: 生成placeholder
|
* @description: 生成placeholder
|
||||||
*/
|
*/
|
||||||
export function createPlaceholderMessage(component: ComponentType) {
|
export function createPlaceholderMessage(component: ComponentType) {
|
||||||
if (component.includes('Input')) {
|
if (component.includes('Input') || component.includes('AutoComplete')) {
|
||||||
return t('common.inputText');
|
return t('common.inputText');
|
||||||
}
|
}
|
||||||
if (component.includes('Picker')) {
|
if (component.includes('Picker')) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<Popover
|
<Popover
|
||||||
placement="bottomLeft"
|
placement="bottomLeft"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
@visibleChange="handleVisibleChange"
|
@visible-change="handleVisibleChange"
|
||||||
:overlayClassName="`${prefixCls}__cloumn-list`"
|
:overlayClassName="`${prefixCls}__cloumn-list`"
|
||||||
:getPopupContainer="getPopupContainer"
|
:getPopupContainer="getPopupContainer"
|
||||||
>
|
>
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
<CheckboxGroup v-model:value="checkedList" @change="onChange" ref="columnListRef">
|
<CheckboxGroup v-model:value="checkedList" @change="onChange" ref="columnListRef">
|
||||||
<template v-for="item in plainOptions" :key="item.value">
|
<template v-for="item in plainOptions" :key="item.value">
|
||||||
<div :class="`${prefixCls}__check-item`" v-if="!('ifShow' in item && !item.ifShow)">
|
<div :class="`${prefixCls}__check-item`" v-if="!('ifShow' in item && !item.ifShow)">
|
||||||
<DragOutlined class="table-coulmn-drag-icon" />
|
<DragOutlined class="table-column-drag-icon" />
|
||||||
<Checkbox :value="item.value">
|
<Checkbox :value="item.value">
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
|
|
@ -111,19 +111,23 @@
|
||||||
computed,
|
computed,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { Tooltip, Popover, Checkbox, Divider } from 'ant-design-vue';
|
import { Tooltip, Popover, Checkbox, Divider } from 'ant-design-vue';
|
||||||
|
import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
|
||||||
import { SettingOutlined, DragOutlined } from '@ant-design/icons-vue';
|
import { SettingOutlined, DragOutlined } from '@ant-design/icons-vue';
|
||||||
import { Icon } from '/@/components/Icon';
|
import { Icon } from '/@/components/Icon';
|
||||||
import { ScrollContainer } from '/@/components/Container';
|
import { ScrollContainer } from '/@/components/Container';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
import { useTableContext } from '../../hooks/useTableContext';
|
import { useTableContext } from '../../hooks/useTableContext';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
import { useSortable } from '/@/hooks/web/useSortable';
|
// import { useSortable } from '/@/hooks/web/useSortable';
|
||||||
import { isFunction, isNullAndUnDef } from '/@/utils/is';
|
import { isFunction, isNullAndUnDef } from '/@/utils/is';
|
||||||
import { getPopupContainer as getParentContainer } from '/@/utils';
|
import { getPopupContainer as getParentContainer } from '/@/utils';
|
||||||
import { omit } from 'lodash-es';
|
import { cloneDeep, omit } from 'lodash-es';
|
||||||
|
import Sortablejs from 'sortablejs';
|
||||||
|
import type Sortable from 'sortablejs';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
checkAll: boolean;
|
checkAll: boolean;
|
||||||
|
isInit?: boolean;
|
||||||
checkedList: string[];
|
checkedList: string[];
|
||||||
defaultCheckList: string[];
|
defaultCheckList: string[];
|
||||||
}
|
}
|
||||||
|
|
@ -157,7 +161,7 @@
|
||||||
let inited = false;
|
let inited = false;
|
||||||
|
|
||||||
const cachePlainOptions = ref<Options[]>([]);
|
const cachePlainOptions = ref<Options[]>([]);
|
||||||
const plainOptions = ref<Options[]>([]);
|
const plainOptions = ref<Options[] | any>([]);
|
||||||
|
|
||||||
const plainSortOptions = ref<Options[]>([]);
|
const plainSortOptions = ref<Options[]>([]);
|
||||||
|
|
||||||
|
|
@ -179,10 +183,12 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const columns = table.getColumns();
|
setTimeout(() => {
|
||||||
if (columns.length) {
|
const columns = table.getColumns();
|
||||||
init();
|
if (columns.length && !state.isInit) {
|
||||||
}
|
init();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
|
|
@ -207,7 +213,7 @@
|
||||||
const columns = getColumns();
|
const columns = getColumns();
|
||||||
|
|
||||||
const checkList = table
|
const checkList = table
|
||||||
.getColumns({ ignoreAction: true })
|
.getColumns({ ignoreAction: true, ignoreIndex: true })
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
if (item.defaultHidden) {
|
if (item.defaultHidden) {
|
||||||
return '';
|
return '';
|
||||||
|
|
@ -233,11 +239,12 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
state.isInit = true;
|
||||||
state.checkedList = checkList;
|
state.checkedList = checkList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkAll change
|
// checkAll change
|
||||||
function onCheckAllChange(e: ChangeEvent) {
|
function onCheckAllChange(e: CheckboxChangeEvent) {
|
||||||
const checkList = plainOptions.value.map((item) => item.value);
|
const checkList = plainOptions.value.map((item) => item.value);
|
||||||
if (e.target.checked) {
|
if (e.target.checked) {
|
||||||
state.checkedList = checkList;
|
state.checkedList = checkList;
|
||||||
|
|
@ -250,16 +257,15 @@
|
||||||
|
|
||||||
const indeterminate = computed(() => {
|
const indeterminate = computed(() => {
|
||||||
const len = plainOptions.value.length;
|
const len = plainOptions.value.length;
|
||||||
let checkdedLen = state.checkedList.length;
|
let checkedLen = state.checkedList.length;
|
||||||
unref(checkIndex) && checkdedLen--;
|
// unref(checkIndex) && checkedLen--;
|
||||||
return checkdedLen > 0 && checkdedLen < len;
|
return checkedLen > 0 && checkedLen < len;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Trigger when check/uncheck a column
|
// Trigger when check/uncheck a column
|
||||||
function onChange(checkedList: string[]) {
|
function onChange(checkedList: string[]) {
|
||||||
const len = plainOptions.value.length;
|
const len = plainSortOptions.value.length;
|
||||||
state.checkAll = checkedList.length === len;
|
state.checkAll = checkedList.length === len;
|
||||||
|
|
||||||
const sortList = unref(plainSortOptions).map((item) => item.value);
|
const sortList = unref(plainSortOptions).map((item) => item.value);
|
||||||
checkedList.sort((prev, next) => {
|
checkedList.sort((prev, next) => {
|
||||||
return sortList.indexOf(prev) - sortList.indexOf(next);
|
return sortList.indexOf(prev) - sortList.indexOf(next);
|
||||||
|
|
@ -267,6 +273,8 @@
|
||||||
setColumns(checkedList);
|
setColumns(checkedList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sortable: Sortable;
|
||||||
|
let sortableOrder: string[] = [];
|
||||||
// reset columns
|
// reset columns
|
||||||
function reset() {
|
function reset() {
|
||||||
state.checkedList = [...state.defaultCheckList];
|
state.checkedList = [...state.defaultCheckList];
|
||||||
|
|
@ -274,6 +282,7 @@
|
||||||
plainOptions.value = unref(cachePlainOptions);
|
plainOptions.value = unref(cachePlainOptions);
|
||||||
plainSortOptions.value = unref(cachePlainOptions);
|
plainSortOptions.value = unref(cachePlainOptions);
|
||||||
setColumns(table.getCacheColumns());
|
setColumns(table.getCacheColumns());
|
||||||
|
sortable.sort(sortableOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the pop-up window for drag and drop initialization
|
// Open the pop-up window for drag and drop initialization
|
||||||
|
|
@ -285,15 +294,18 @@
|
||||||
const el = columnListEl.$el as any;
|
const el = columnListEl.$el as any;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
// Drag and drop sort
|
// Drag and drop sort
|
||||||
const { initSortable } = useSortable(el, {
|
sortable = Sortablejs.create(unref(el), {
|
||||||
handle: '.table-coulmn-drag-icon ',
|
animation: 500,
|
||||||
|
delay: 400,
|
||||||
|
delayOnTouchOnly: true,
|
||||||
|
handle: '.table-column-drag-icon ',
|
||||||
onEnd: (evt) => {
|
onEnd: (evt) => {
|
||||||
const { oldIndex, newIndex } = evt;
|
const { oldIndex, newIndex } = evt;
|
||||||
if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
|
if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Sort column
|
// Sort column
|
||||||
const columns = getColumns();
|
const columns = cloneDeep(plainSortOptions.value);
|
||||||
|
|
||||||
if (oldIndex > newIndex) {
|
if (oldIndex > newIndex) {
|
||||||
columns.splice(newIndex, 0, columns[oldIndex]);
|
columns.splice(newIndex, 0, columns[oldIndex]);
|
||||||
|
|
@ -304,24 +316,29 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
plainSortOptions.value = columns;
|
plainSortOptions.value = columns;
|
||||||
plainOptions.value = columns;
|
|
||||||
setColumns(columns);
|
setColumns(
|
||||||
|
columns
|
||||||
|
.map((col: Options) => col.value)
|
||||||
|
.filter((value: string) => state.checkedList.includes(value)),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
initSortable();
|
// 记录原始order 序列
|
||||||
|
sortableOrder = sortable.toArray();
|
||||||
inited = true;
|
inited = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control whether the serial number column is displayed
|
// Control whether the serial number column is displayed
|
||||||
function handleIndexCheckChange(e: ChangeEvent) {
|
function handleIndexCheckChange(e: CheckboxChangeEvent) {
|
||||||
table.setProps({
|
table.setProps({
|
||||||
showIndexColumn: e.target.checked,
|
showIndexColumn: e.target.checked,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control whether the check box is displayed
|
// Control whether the check box is displayed
|
||||||
function handleSelectCheckChange(e: ChangeEvent) {
|
function handleSelectCheckChange(e: CheckboxChangeEvent) {
|
||||||
table.setProps({
|
table.setProps({
|
||||||
rowSelection: e.target.checked ? defaultRowSelection : undefined,
|
rowSelection: e.target.checked ? defaultRowSelection : undefined,
|
||||||
});
|
});
|
||||||
|
|
@ -341,13 +358,13 @@
|
||||||
if (isFixed && !item.width) {
|
if (isFixed && !item.width) {
|
||||||
item.width = 100;
|
item.width = 100;
|
||||||
}
|
}
|
||||||
table.setCacheColumnsByField?.(item.dataIndex, { fixed: isFixed });
|
table.setCacheColumnsByField?.(item.dataIndex as string, { fixed: isFixed });
|
||||||
setColumns(columns);
|
setColumns(columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setColumns(columns: BasicColumn[] | string[]) {
|
function setColumns(columns: BasicColumn[] | string[]) {
|
||||||
table.setColumns(columns);
|
table.setColumns(columns);
|
||||||
const data: ColumnChangeParam[] = unref(plainOptions).map((col) => {
|
const data: ColumnChangeParam[] = unref(plainSortOptions).map((col) => {
|
||||||
const visible =
|
const visible =
|
||||||
columns.findIndex(
|
columns.findIndex(
|
||||||
(c: BasicColumn | string) =>
|
(c: BasicColumn | string) =>
|
||||||
|
|
@ -390,7 +407,7 @@
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@prefix-cls: ~'@{namespace}-basic-column-setting';
|
@prefix-cls: ~'@{namespace}-basic-column-setting';
|
||||||
|
|
||||||
.table-coulmn-drag-icon {
|
.table-column-drag-icon {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<span>{{ t('component.table.settingDens') }}</span>
|
<span>{{ t('component.table.settingDens') }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<Dropdown placement="bottomCenter" :trigger="['click']" :getPopupContainer="getPopupContainer">
|
<Dropdown placement="bottom" :trigger="['click']" :getPopupContainer="getPopupContainer">
|
||||||
<ColumnHeightOutlined />
|
<ColumnHeightOutlined />
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<Menu @click="handleTitleClick" selectable v-model:selectedKeys="selectedKeysRef">
|
<Menu @click="handleTitleClick" selectable v-model:selectedKeys="selectedKeysRef">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table';
|
import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table';
|
||||||
import type { PaginationProps } from '../types/pagination';
|
import type { PaginationProps } from '../types/pagination';
|
||||||
import type { ComputedRef } from 'vue';
|
import type { ComputedRef } from 'vue';
|
||||||
import { computed, Ref, ref, toRaw, unref, watch } from 'vue';
|
import { computed, Ref, ref, reactive, toRaw, unref, watch } from 'vue';
|
||||||
import { renderEditCell } from '../components/editable';
|
import { renderEditCell } from '../components/editable';
|
||||||
import { usePermission } from '/@/hooks/web/usePermission';
|
import { usePermission } from '/@/hooks/web/usePermission';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
|
@ -152,10 +152,10 @@ export function useColumns(
|
||||||
return hasPermission(column.auth) && isIfShow(column);
|
return hasPermission(column.auth) && isIfShow(column);
|
||||||
})
|
})
|
||||||
.map((column) => {
|
.map((column) => {
|
||||||
const { slots, dataIndex, customRender, format, edit, editRow, flag } = column;
|
const { slots, customRender, format, edit, editRow, flag } = column;
|
||||||
|
|
||||||
if (!slots || !slots?.title) {
|
if (!slots || !slots?.title) {
|
||||||
column.slots = { title: `header-${dataIndex}`, ...(slots || {}) };
|
// column.slots = { title: `header-${dataIndex}`, ...(slots || {}) };
|
||||||
column.customTitle = column.title;
|
column.customTitle = column.title;
|
||||||
Reflect.deleteProperty(column, 'title');
|
Reflect.deleteProperty(column, 'title');
|
||||||
}
|
}
|
||||||
|
|
@ -170,7 +170,7 @@ export function useColumns(
|
||||||
if ((edit || editRow) && !isDefaultAction) {
|
if ((edit || editRow) && !isDefaultAction) {
|
||||||
column.customRender = renderEditCell(column);
|
column.customRender = renderEditCell(column);
|
||||||
}
|
}
|
||||||
return column;
|
return reactive(column);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -197,7 +197,7 @@ export function useColumns(
|
||||||
* set columns
|
* set columns
|
||||||
* @param columnList key|column
|
* @param columnList key|column
|
||||||
*/
|
*/
|
||||||
function setColumns(columnList: Partial<BasicColumn>[] | string[]) {
|
function setColumns(columnList: Partial<BasicColumn>[] | (string | string[])[]) {
|
||||||
const columns = cloneDeep(columnList);
|
const columns = cloneDeep(columnList);
|
||||||
if (!isArray(columns)) return;
|
if (!isArray(columns)) return;
|
||||||
|
|
||||||
|
|
@ -210,31 +210,23 @@ export function useColumns(
|
||||||
|
|
||||||
const cacheKeys = cacheColumns.map((item) => item.dataIndex);
|
const cacheKeys = cacheColumns.map((item) => item.dataIndex);
|
||||||
|
|
||||||
if (!isString(firstColumn)) {
|
if (!isString(firstColumn) && !isArray(firstColumn)) {
|
||||||
columnsRef.value = columns as BasicColumn[];
|
columnsRef.value = columns as BasicColumn[];
|
||||||
} else {
|
} else {
|
||||||
const columnKeys = columns as string[];
|
const columnKeys = (columns as (string | string[])[]).map((m) => m.toString());
|
||||||
const newColumns: BasicColumn[] = [];
|
const newColumns: BasicColumn[] = [];
|
||||||
cacheColumns.forEach((item) => {
|
cacheColumns.forEach((item) => {
|
||||||
if (columnKeys.includes(item.dataIndex! || (item.key as string))) {
|
newColumns.push({
|
||||||
newColumns.push({
|
...item,
|
||||||
...item,
|
defaultHidden: !columnKeys.includes(item.dataIndex?.toString() || (item.key as string)),
|
||||||
defaultHidden: false,
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
newColumns.push({
|
|
||||||
...item,
|
|
||||||
defaultHidden: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort according to another array
|
// Sort according to another array
|
||||||
if (!isEqual(cacheKeys, columns)) {
|
if (!isEqual(cacheKeys, columns)) {
|
||||||
newColumns.sort((prev, next) => {
|
newColumns.sort((prev, next) => {
|
||||||
return (
|
return (
|
||||||
cacheKeys.indexOf(prev.dataIndex as string) -
|
columnKeys.indexOf(prev.dataIndex?.toString() as string) -
|
||||||
cacheKeys.indexOf(next.dataIndex as string)
|
columnKeys.indexOf(next.dataIndex?.toString() as string)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -306,7 +298,7 @@ export function formatCell(text: string, format: CellFormat, record: Recordable,
|
||||||
try {
|
try {
|
||||||
// date type
|
// date type
|
||||||
const DATE_FORMAT_PREFIX = 'date|';
|
const DATE_FORMAT_PREFIX = 'date|';
|
||||||
if (isString(format) && format.startsWith(DATE_FORMAT_PREFIX)) {
|
if (isString(format) && format.startsWith(DATE_FORMAT_PREFIX) && text) {
|
||||||
const dateFormat = format.replace(DATE_FORMAT_PREFIX, '');
|
const dateFormat = format.replace(DATE_FORMAT_PREFIX, '');
|
||||||
|
|
||||||
if (!dateFormat) {
|
if (!dateFormat) {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import {
|
||||||
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
|
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
|
||||||
import { buildUUID } from '/@/utils/uuid';
|
import { buildUUID } from '/@/utils/uuid';
|
||||||
import { isFunction, isBoolean } from '/@/utils/is';
|
import { isFunction, isBoolean } from '/@/utils/is';
|
||||||
import { get, cloneDeep } from 'lodash-es';
|
import { get, cloneDeep, merge } from 'lodash-es';
|
||||||
import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
|
import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
|
||||||
|
|
||||||
interface ActionType {
|
interface ActionType {
|
||||||
|
|
@ -196,11 +196,10 @@ export function useDataSource(
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertTableDataRecord(record: Recordable, index: number): Recordable | undefined {
|
function insertTableDataRecord(record: Recordable, index: number): Recordable | undefined {
|
||||||
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
|
// if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
|
||||||
index = index ?? dataSourceRef.value?.length;
|
index = index ?? dataSourceRef.value?.length;
|
||||||
unref(dataSourceRef).splice(index, 0, record);
|
unref(dataSourceRef).splice(index, 0, record);
|
||||||
unref(propsRef).dataSource?.splice(index, 0, record);
|
return unref(dataSourceRef);
|
||||||
return unref(propsRef).dataSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function findTableDataRecord(rowKey: string | number) {
|
function findTableDataRecord(rowKey: string | number) {
|
||||||
|
|
@ -272,17 +271,17 @@ export function useDataSource(
|
||||||
|
|
||||||
const { sortInfo = {}, filterInfo } = searchState;
|
const { sortInfo = {}, filterInfo } = searchState;
|
||||||
|
|
||||||
let params: Recordable = {
|
let params: Recordable = merge(
|
||||||
...pageParams,
|
pageParams,
|
||||||
...(useSearchForm ? getFieldsValue() : {}),
|
useSearchForm ? getFieldsValue() : {},
|
||||||
...searchInfo,
|
searchInfo,
|
||||||
...(opt?.searchInfo ?? {}),
|
opt?.searchInfo ?? {},
|
||||||
...defSort,
|
defSort,
|
||||||
...sortInfo,
|
sortInfo,
|
||||||
...filterInfo,
|
filterInfo,
|
||||||
...(opt?.sortInfo ?? {}),
|
opt?.sortInfo ?? {},
|
||||||
...(opt?.filterInfo ?? {}),
|
opt?.filterInfo ?? {},
|
||||||
};
|
);
|
||||||
if (beforeFetch && isFunction(beforeFetch)) {
|
if (beforeFetch && isFunction(beforeFetch)) {
|
||||||
params = (await beforeFetch(params)) || params;
|
params = (await beforeFetch(params)) || params;
|
||||||
}
|
}
|
||||||
|
|
@ -293,7 +292,7 @@ export function useDataSource(
|
||||||
const isArrayResult = Array.isArray(res);
|
const isArrayResult = Array.isArray(res);
|
||||||
|
|
||||||
let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
|
let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
|
||||||
const resultTotal: number = isArrayResult ? 0 : get(res, totalField);
|
const resultTotal: number = isArrayResult ? res.length : get(res, totalField);
|
||||||
|
|
||||||
// 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
|
// 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
|
||||||
if (resultTotal) {
|
if (resultTotal) {
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,8 @@ export function useRowSelection(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedRowKeys: unref(selectedRowKeysRef),
|
selectedRowKeys: unref(selectedRowKeysRef),
|
||||||
hideDefaultSelections: false,
|
|
||||||
onChange: (selectedRowKeys: string[]) => {
|
onChange: (selectedRowKeys: string[]) => {
|
||||||
setSelectedRowKeys(selectedRowKeys);
|
setSelectedRowKeys(selectedRowKeys);
|
||||||
// selectedRowKeysRef.value = selectedRowKeys;
|
|
||||||
// selectedRowRef.value = selectedRows;
|
|
||||||
},
|
},
|
||||||
...omit(rowSelection, ['onChange']),
|
...omit(rowSelection, ['onChange']),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
|
import { nextTick, unref } from 'vue';
|
||||||
|
import { warn } from '/@/utils/log';
|
||||||
|
|
||||||
|
export function useTableScrollTo(
|
||||||
|
tableElRef: Ref<ComponentRef>,
|
||||||
|
getDataSourceRef: ComputedRef<Recordable[]>,
|
||||||
|
) {
|
||||||
|
let bodyEl: HTMLElement | null;
|
||||||
|
|
||||||
|
async function findTargetRowToScroll(targetRowData: Recordable) {
|
||||||
|
const { id } = targetRowData;
|
||||||
|
const targetRowEl: HTMLElement | null | undefined = bodyEl?.querySelector(
|
||||||
|
`[data-row-key="${id}"]`,
|
||||||
|
);
|
||||||
|
//Add a delay to get new dataSource
|
||||||
|
await nextTick();
|
||||||
|
bodyEl?.scrollTo({
|
||||||
|
top: targetRowEl?.offsetTop ?? 0,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollTo(pos: string): void {
|
||||||
|
const table = unref(tableElRef);
|
||||||
|
if (!table) return;
|
||||||
|
|
||||||
|
const tableEl: Element = table.$el;
|
||||||
|
if (!tableEl) return;
|
||||||
|
|
||||||
|
if (!bodyEl) {
|
||||||
|
bodyEl = tableEl.querySelector('.ant-table-body');
|
||||||
|
if (!bodyEl) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataSource = unref(getDataSourceRef);
|
||||||
|
if (!dataSource) return;
|
||||||
|
|
||||||
|
// judge pos type
|
||||||
|
if (pos === 'top') {
|
||||||
|
findTargetRowToScroll(dataSource[0]);
|
||||||
|
} else if (pos === 'bottom') {
|
||||||
|
findTargetRowToScroll(dataSource[dataSource.length - 1]);
|
||||||
|
} else {
|
||||||
|
const targetRowData = dataSource.find((data) => data.id === pos);
|
||||||
|
if (targetRowData) {
|
||||||
|
findTargetRowToScroll(targetRowData);
|
||||||
|
} else {
|
||||||
|
warn(`id: ${pos} doesn't exist`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { scrollTo };
|
||||||
|
}
|
||||||
|
|
@ -152,9 +152,15 @@ export function useTable(tableProps?: Props): [
|
||||||
expandAll: () => {
|
expandAll: () => {
|
||||||
getTableInstance().expandAll();
|
getTableInstance().expandAll();
|
||||||
},
|
},
|
||||||
|
expandRows: (keys: string[]) => {
|
||||||
|
getTableInstance().expandRows(keys);
|
||||||
|
},
|
||||||
collapseAll: () => {
|
collapseAll: () => {
|
||||||
getTableInstance().collapseAll();
|
getTableInstance().collapseAll();
|
||||||
},
|
},
|
||||||
|
scrollTo: (pos: string) => {
|
||||||
|
getTableInstance().scrollTo(pos);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return [register, methods];
|
return [register, methods];
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,13 @@ export function useTableExpand(
|
||||||
expandedRowKeys.value = keys;
|
expandedRowKeys.value = keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function expandRows(keys: string[]) {
|
||||||
|
// use row ID expands the specified table row
|
||||||
|
const { isTreeTable } = unref(propsRef);
|
||||||
|
if (!isTreeTable) return;
|
||||||
|
expandedRowKeys.value = [...expandedRowKeys.value, ...keys];
|
||||||
|
}
|
||||||
|
|
||||||
function getAllKeys(data?: Recordable[]) {
|
function getAllKeys(data?: Recordable[]) {
|
||||||
const keys: string[] = [];
|
const keys: string[] = [];
|
||||||
const { childrenColumnName } = unref(propsRef);
|
const { childrenColumnName } = unref(propsRef);
|
||||||
|
|
@ -54,5 +61,5 @@ export function useTableExpand(
|
||||||
expandedRowKeys.value = [];
|
expandedRowKeys.value = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return { getExpandOption, expandAll, collapseAll };
|
return { getExpandOption, expandAll, expandRows, collapseAll };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export function useTableFooter(
|
||||||
propsRef: ComputedRef<BasicTableProps>,
|
propsRef: ComputedRef<BasicTableProps>,
|
||||||
scrollRef: ComputedRef<{
|
scrollRef: ComputedRef<{
|
||||||
x: string | number | true;
|
x: string | number | true;
|
||||||
y: Nullable<number>;
|
y: string | number | null;
|
||||||
scrollToFirstRowOnChange: boolean;
|
scrollToFirstRowOnChange: boolean;
|
||||||
}>,
|
}>,
|
||||||
tableElRef: Ref<ComponentRef>,
|
tableElRef: Ref<ComponentRef>,
|
||||||
|
|
@ -36,14 +36,13 @@ export function useTableFooter(
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const tableEl = unref(tableElRef);
|
const tableEl = unref(tableElRef);
|
||||||
if (!tableEl) return;
|
if (!tableEl) return;
|
||||||
const bodyDomList = tableEl.$el.querySelectorAll('.ant-table-body');
|
const bodyDom = tableEl.$el.querySelector('.ant-table-content');
|
||||||
const bodyDom = bodyDomList[0];
|
|
||||||
useEventListener({
|
useEventListener({
|
||||||
el: bodyDom,
|
el: bodyDom,
|
||||||
name: 'scroll',
|
name: 'scroll',
|
||||||
listener: () => {
|
listener: () => {
|
||||||
const footerBodyDom = tableEl.$el.querySelector(
|
const footerBodyDom = tableEl.$el.querySelector(
|
||||||
'.ant-table-footer .ant-table-body',
|
'.ant-table-footer .ant-table-content',
|
||||||
) as HTMLDivElement;
|
) as HTMLDivElement;
|
||||||
if (!footerBodyDom || !bodyDom) return;
|
if (!footerBodyDom || !bodyDom) return;
|
||||||
footerBodyDom.scrollLeft = bodyDom.scrollLeft;
|
footerBodyDom.scrollLeft = bodyDom.scrollLeft;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { BasicTableProps, TableRowSelection, BasicColumn } from '../types/table';
|
import type { BasicTableProps, TableRowSelection, BasicColumn } from '../types/table';
|
||||||
import type { Ref, ComputedRef } from 'vue';
|
import { Ref, ComputedRef, ref } from 'vue';
|
||||||
import { computed, unref, ref, nextTick, watch } from 'vue';
|
import { computed, unref, nextTick, watch } from 'vue';
|
||||||
import { getViewportOffset } from '/@/utils/domUtils';
|
import { getViewportOffset } from '/@/utils/domUtils';
|
||||||
import { isBoolean } from '/@/utils/is';
|
import { isBoolean } from '/@/utils/is';
|
||||||
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
|
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
|
||||||
|
|
@ -12,11 +12,12 @@ export function useTableScroll(
|
||||||
propsRef: ComputedRef<BasicTableProps>,
|
propsRef: ComputedRef<BasicTableProps>,
|
||||||
tableElRef: Ref<ComponentRef>,
|
tableElRef: Ref<ComponentRef>,
|
||||||
columnsRef: ComputedRef<BasicColumn[]>,
|
columnsRef: ComputedRef<BasicColumn[]>,
|
||||||
rowSelectionRef: ComputedRef<TableRowSelection<any> | null>,
|
rowSelectionRef: ComputedRef<TableRowSelection | null>,
|
||||||
getDataSourceRef: ComputedRef<Recordable[]>,
|
getDataSourceRef: ComputedRef<Recordable[]>,
|
||||||
|
wrapRef: Ref<HTMLElement | null>,
|
||||||
|
formRef: Ref<ComponentRef>,
|
||||||
) {
|
) {
|
||||||
const tableHeightRef: Ref<Nullable<number>> = ref(null);
|
const tableHeightRef: Ref<Nullable<number | string>> = ref(167);
|
||||||
|
|
||||||
const modalFn = useModalContext();
|
const modalFn = useModalContext();
|
||||||
|
|
||||||
// Greater than animation time 280
|
// Greater than animation time 280
|
||||||
|
|
@ -43,8 +44,8 @@ export function useTableScroll(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setHeight(heigh: number) {
|
function setHeight(height: number) {
|
||||||
tableHeightRef.value = heigh;
|
tableHeightRef.value = height;
|
||||||
// Solve the problem of modal adaptive height calculation when the form is placed in the modal
|
// Solve the problem of modal adaptive height calculation when the form is placed in the modal
|
||||||
modalFn?.redoModalHeight?.();
|
modalFn?.redoModalHeight?.();
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +56,8 @@ export function useTableScroll(
|
||||||
let bodyEl: HTMLElement | null;
|
let bodyEl: HTMLElement | null;
|
||||||
|
|
||||||
async function calcTableHeight() {
|
async function calcTableHeight() {
|
||||||
const { resizeHeightOffset, pagination, maxHeight } = unref(propsRef);
|
const { resizeHeightOffset, pagination, maxHeight, isCanResizeParent, useSearchForm } =
|
||||||
|
unref(propsRef);
|
||||||
const tableData = unref(getDataSourceRef);
|
const tableData = unref(getDataSourceRef);
|
||||||
|
|
||||||
const table = unref(tableElRef);
|
const table = unref(tableElRef);
|
||||||
|
|
@ -88,20 +90,17 @@ export function useTableScroll(
|
||||||
|
|
||||||
bodyEl!.style.height = 'unset';
|
bodyEl!.style.height = 'unset';
|
||||||
|
|
||||||
if (!unref(getCanResize) || tableData.length === 0) return;
|
if (!unref(getCanResize) || !unref(tableData) || tableData.length === 0) return;
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
//Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight
|
// Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight
|
||||||
|
|
||||||
const headEl = tableEl.querySelector('.ant-table-thead ');
|
const headEl = tableEl.querySelector('.ant-table-thead ');
|
||||||
|
|
||||||
if (!headEl) return;
|
if (!headEl) return;
|
||||||
|
|
||||||
// Table height from bottom
|
|
||||||
const { bottomIncludeBody } = getViewportOffset(headEl);
|
|
||||||
// Table height from bottom height-custom offset
|
// Table height from bottom height-custom offset
|
||||||
|
let paddingHeight = 32;
|
||||||
const paddingHeight = 32;
|
|
||||||
// Pager height
|
// Pager height
|
||||||
let paginationHeight = 2;
|
let paginationHeight = 2;
|
||||||
if (!isBoolean(pagination)) {
|
if (!isBoolean(pagination)) {
|
||||||
|
|
@ -132,6 +131,35 @@ export function useTableScroll(
|
||||||
headerHeight = (headEl as HTMLElement).offsetHeight;
|
headerHeight = (headEl as HTMLElement).offsetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bottomIncludeBody = 0;
|
||||||
|
if (unref(wrapRef) && isCanResizeParent) {
|
||||||
|
const tablePadding = 12;
|
||||||
|
const formMargin = 16;
|
||||||
|
let paginationMargin = 10;
|
||||||
|
const wrapHeight = unref(wrapRef)?.offsetHeight ?? 0;
|
||||||
|
|
||||||
|
let formHeight = unref(formRef)?.$el.offsetHeight ?? 0;
|
||||||
|
if (formHeight) {
|
||||||
|
formHeight += formMargin;
|
||||||
|
}
|
||||||
|
if (isBoolean(pagination) && !pagination) {
|
||||||
|
paginationMargin = 0;
|
||||||
|
}
|
||||||
|
if (isBoolean(useSearchForm) && !useSearchForm) {
|
||||||
|
paddingHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerCellHeight =
|
||||||
|
(tableEl.querySelector('.ant-table-title') as HTMLElement)?.offsetHeight ?? 0;
|
||||||
|
|
||||||
|
console.log(wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin);
|
||||||
|
bottomIncludeBody =
|
||||||
|
wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin;
|
||||||
|
} else {
|
||||||
|
// Table height from bottom
|
||||||
|
bottomIncludeBody = getViewportOffset(headEl).bottomIncludeBody;
|
||||||
|
}
|
||||||
|
|
||||||
let height =
|
let height =
|
||||||
bottomIncludeBody -
|
bottomIncludeBody -
|
||||||
(resizeHeightOffset || 0) -
|
(resizeHeightOffset || 0) -
|
||||||
|
|
@ -139,7 +167,6 @@ export function useTableScroll(
|
||||||
paginationHeight -
|
paginationHeight -
|
||||||
footerHeight -
|
footerHeight -
|
||||||
headerHeight;
|
headerHeight;
|
||||||
|
|
||||||
height = (height > maxHeight! ? (maxHeight as number) : height) ?? height;
|
height = (height > maxHeight! ? (maxHeight as number) : height) ?? height;
|
||||||
setHeight(height);
|
setHeight(height);
|
||||||
|
|
||||||
|
|
@ -164,7 +191,7 @@ export function useTableScroll(
|
||||||
|
|
||||||
const columns = unref(columnsRef).filter((item) => !item.defaultHidden);
|
const columns = unref(columnsRef).filter((item) => !item.defaultHidden);
|
||||||
columns.forEach((item) => {
|
columns.forEach((item) => {
|
||||||
width += Number.parseInt(item.width as string) || 0;
|
width += Number.parseFloat(item.width as string) || 0;
|
||||||
});
|
});
|
||||||
const unsetWidthColumns = columns.filter((item) => !Reflect.has(item, 'width'));
|
const unsetWidthColumns = columns.filter((item) => !Reflect.has(item, 'width'));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,15 @@ import type {
|
||||||
SizeType,
|
SizeType,
|
||||||
} from './types/table';
|
} from './types/table';
|
||||||
import type { FormProps } from '/@/components/Form';
|
import type { FormProps } from '/@/components/Form';
|
||||||
|
|
||||||
import { DEFAULT_FILTER_FN, DEFAULT_SORT_FN, FETCH_SETTING, DEFAULT_SIZE } from './const';
|
import { DEFAULT_FILTER_FN, DEFAULT_SORT_FN, FETCH_SETTING, DEFAULT_SIZE } from './const';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
|
|
||||||
export const basicProps = {
|
export const basicProps = {
|
||||||
clickToRowSelect: propTypes.bool.def(true),
|
clickToRowSelect: { type: Boolean, default: true },
|
||||||
isTreeTable: propTypes.bool.def(false),
|
isTreeTable: Boolean,
|
||||||
tableSetting: propTypes.shape<TableSetting>({}),
|
tableSetting: propTypes.shape<TableSetting>({}),
|
||||||
inset: propTypes.bool,
|
inset: Boolean,
|
||||||
sortFn: {
|
sortFn: {
|
||||||
type: Function as PropType<(sortInfo: SorterResult) => any>,
|
type: Function as PropType<(sortInfo: SorterResult) => any>,
|
||||||
default: DEFAULT_SORT_FN,
|
default: DEFAULT_SORT_FN,
|
||||||
|
|
@ -26,10 +27,10 @@ export const basicProps = {
|
||||||
type: Function as PropType<(data: Partial<Recordable<string[]>>) => any>,
|
type: Function as PropType<(data: Partial<Recordable<string[]>>) => any>,
|
||||||
default: DEFAULT_FILTER_FN,
|
default: DEFAULT_FILTER_FN,
|
||||||
},
|
},
|
||||||
showTableSetting: propTypes.bool,
|
showTableSetting: Boolean,
|
||||||
autoCreateKey: propTypes.bool.def(true),
|
autoCreateKey: { type: Boolean, default: true },
|
||||||
striped: propTypes.bool.def(true),
|
striped: { type: Boolean, default: true },
|
||||||
showSummary: propTypes.bool,
|
showSummary: Boolean,
|
||||||
summaryFunc: {
|
summaryFunc: {
|
||||||
type: [Function, Array] as PropType<(...arg: any[]) => any[]>,
|
type: [Function, Array] as PropType<(...arg: any[]) => any[]>,
|
||||||
default: null,
|
default: null,
|
||||||
|
|
@ -39,7 +40,7 @@ export const basicProps = {
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
indentSize: propTypes.number.def(24),
|
indentSize: propTypes.number.def(24),
|
||||||
canColDrag: propTypes.bool.def(true),
|
canColDrag: { type: Boolean, default: true },
|
||||||
api: {
|
api: {
|
||||||
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
||||||
default: null,
|
default: null,
|
||||||
|
|
@ -63,8 +64,8 @@ export const basicProps = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 立即请求接口
|
// 立即请求接口
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: { type: Boolean, default: true },
|
||||||
emptyDataIsShowTable: propTypes.bool.def(true),
|
emptyDataIsShowTable: { type: Boolean, default: true },
|
||||||
// 额外的请求参数
|
// 额外的请求参数
|
||||||
searchInfo: {
|
searchInfo: {
|
||||||
type: Object as PropType<Recordable>,
|
type: Object as PropType<Recordable>,
|
||||||
|
|
@ -86,7 +87,7 @@ export const basicProps = {
|
||||||
type: [Array] as PropType<BasicColumn[]>,
|
type: [Array] as PropType<BasicColumn[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
showIndexColumn: propTypes.bool.def(true),
|
showIndexColumn: { type: Boolean, default: true },
|
||||||
indexColumnProps: {
|
indexColumnProps: {
|
||||||
type: Object as PropType<BasicColumn>,
|
type: Object as PropType<BasicColumn>,
|
||||||
default: null,
|
default: null,
|
||||||
|
|
@ -95,8 +96,9 @@ export const basicProps = {
|
||||||
type: Object as PropType<BasicColumn>,
|
type: Object as PropType<BasicColumn>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
ellipsis: propTypes.bool.def(true),
|
ellipsis: { type: Boolean, default: true },
|
||||||
canResize: propTypes.bool.def(true),
|
isCanResizeParent: { type: Boolean, default: false },
|
||||||
|
canResize: { type: Boolean, default: true },
|
||||||
clearSelectOnPageChange: propTypes.bool,
|
clearSelectOnPageChange: propTypes.bool,
|
||||||
resizeHeightOffset: propTypes.number.def(0),
|
resizeHeightOffset: propTypes.number.def(0),
|
||||||
rowSelection: {
|
rowSelection: {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,12 @@ export type ComponentType =
|
||||||
| 'InputNumber'
|
| 'InputNumber'
|
||||||
| 'Select'
|
| 'Select'
|
||||||
| 'ApiSelect'
|
| 'ApiSelect'
|
||||||
|
| 'AutoComplete'
|
||||||
| 'ApiTreeSelect'
|
| 'ApiTreeSelect'
|
||||||
| 'Checkbox'
|
| 'Checkbox'
|
||||||
| 'Switch'
|
| 'Switch'
|
||||||
| 'DatePicker'
|
| 'DatePicker'
|
||||||
| 'TimePicker';
|
| 'TimePicker'
|
||||||
|
| 'RadioGroup'
|
||||||
|
| 'RadioButtonGroup'
|
||||||
|
| 'ApiRadioGroup';
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,18 @@ interface PaginationRenderProps {
|
||||||
originalElement: any;
|
originalElement: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PaginationPositon =
|
||||||
|
| 'topLeft'
|
||||||
|
| 'topCenter'
|
||||||
|
| 'topRight'
|
||||||
|
| 'bottomLeft'
|
||||||
|
| 'bottomCenter'
|
||||||
|
| 'bottomRight';
|
||||||
|
|
||||||
export declare class PaginationConfig extends Pagination {
|
export declare class PaginationConfig extends Pagination {
|
||||||
position?: 'top' | 'bottom' | 'both';
|
position?: PaginationPositon[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginationProps {
|
export interface PaginationProps {
|
||||||
/**
|
/**
|
||||||
* total number of data items
|
* total number of data items
|
||||||
|
|
@ -96,4 +105,11 @@ export interface PaginationProps {
|
||||||
* @type Function
|
* @type Function
|
||||||
*/
|
*/
|
||||||
itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element;
|
itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* specify the position of Pagination
|
||||||
|
* @default ['bottomRight']
|
||||||
|
* @type string[]
|
||||||
|
*/
|
||||||
|
position?: PaginationPositon[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import type { VNodeChild } from 'vue';
|
import type { VNodeChild } from 'vue';
|
||||||
import type { PaginationProps } from './pagination';
|
import type { PaginationProps } from './pagination';
|
||||||
import type { FormProps } from '/@/components/Form';
|
import type { FormProps } from '/@/components/Form';
|
||||||
import type {
|
import type { TableRowSelection as ITableRowSelection } from 'ant-design-vue/lib/table/interface';
|
||||||
ColumnProps,
|
import type { ColumnProps } from 'ant-design-vue/lib/table';
|
||||||
TableRowSelection as ITableRowSelection,
|
|
||||||
} from 'ant-design-vue/lib/table/interface';
|
|
||||||
|
|
||||||
import { ComponentType } from './componentType';
|
import { ComponentType } from './componentType';
|
||||||
import { VueNode } from '/@/utils/propTypes';
|
import { VueNode } from '/@/utils/propTypes';
|
||||||
|
|
@ -89,7 +87,9 @@ export interface TableActionType {
|
||||||
getSelectRows: <T = Recordable>() => T[];
|
getSelectRows: <T = Recordable>() => T[];
|
||||||
clearSelectedRowKeys: () => void;
|
clearSelectedRowKeys: () => void;
|
||||||
expandAll: () => void;
|
expandAll: () => void;
|
||||||
|
expandRows: (keys: string[] | number[]) => void;
|
||||||
collapseAll: () => void;
|
collapseAll: () => void;
|
||||||
|
scrollTo: (pos: string) => void; // pos: id | "top" | "bottom"
|
||||||
getSelectRowKeys: () => string[];
|
getSelectRowKeys: () => string[];
|
||||||
deleteSelectRowByKey: (key: string) => void;
|
deleteSelectRowByKey: (key: string) => void;
|
||||||
setPagination: (info: Partial<PaginationProps>) => void;
|
setPagination: (info: Partial<PaginationProps>) => void;
|
||||||
|
|
@ -191,6 +191,8 @@ export interface BasicTableProps<T = any> {
|
||||||
actionColumn?: BasicColumn;
|
actionColumn?: BasicColumn;
|
||||||
// 文本超过宽度是否显示。。。
|
// 文本超过宽度是否显示。。。
|
||||||
ellipsis?: boolean;
|
ellipsis?: boolean;
|
||||||
|
// 是否继承父级高度(父级高度-表单高度-padding高度)
|
||||||
|
isCanResizeParent?: boolean;
|
||||||
// 是否可以自适应高度
|
// 是否可以自适应高度
|
||||||
canResize?: boolean;
|
canResize?: boolean;
|
||||||
// 自适应高度偏移, 计算结果-偏移量
|
// 自适应高度偏移, 计算结果-偏移量
|
||||||
|
|
@ -410,7 +412,7 @@ export type CellFormat =
|
||||||
| Map<string | number, any>;
|
| Map<string | number, any>;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export interface BasicColumn extends ColumnProps {
|
export interface BasicColumn extends ColumnProps<Recordable> {
|
||||||
children?: BasicColumn[];
|
children?: BasicColumn[];
|
||||||
filters?: {
|
filters?: {
|
||||||
text: string;
|
text: string;
|
||||||
|
|
@ -439,7 +441,14 @@ export interface BasicColumn extends ColumnProps {
|
||||||
editRow?: boolean;
|
editRow?: boolean;
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
editComponent?: ComponentType;
|
editComponent?: ComponentType;
|
||||||
editComponentProps?: Recordable;
|
editComponentProps?:
|
||||||
|
| ((opt: {
|
||||||
|
text: string | number | boolean | Recordable;
|
||||||
|
record: Recordable;
|
||||||
|
column: BasicColumn;
|
||||||
|
index: number;
|
||||||
|
}) => Recordable)
|
||||||
|
| Recordable;
|
||||||
editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
|
editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
|
||||||
editValueMap?: (value: any) => string;
|
editValueMap?: (value: any) => string;
|
||||||
onEditRow?: () => void;
|
onEditRow?: () => void;
|
||||||
|
|
@ -447,6 +456,15 @@ export interface BasicColumn extends ColumnProps {
|
||||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
auth?: RoleEnum | RoleEnum[] | string | string[];
|
||||||
// 业务控制是否显示
|
// 业务控制是否显示
|
||||||
ifShow?: boolean | ((column: BasicColumn) => boolean);
|
ifShow?: boolean | ((column: BasicColumn) => boolean);
|
||||||
|
// 自定义修改后显示的内容
|
||||||
|
editRender?: (opt: {
|
||||||
|
text: string | number | boolean | Recordable;
|
||||||
|
record: Recordable;
|
||||||
|
column: BasicColumn;
|
||||||
|
index: number;
|
||||||
|
}) => VNodeChild | JSX.Element;
|
||||||
|
// 动态 Disabled
|
||||||
|
editDynamicDisabled?: boolean | ((record: Recordable) => boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ColumnChangeParam = {
|
export type ColumnChangeParam = {
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,17 @@ export interface PopConfirm {
|
||||||
confirm: Fn;
|
confirm: Fn;
|
||||||
cancel?: Fn;
|
cancel?: Fn;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
placement?:
|
||||||
|
| 'top'
|
||||||
|
| 'left'
|
||||||
|
| 'right'
|
||||||
|
| 'bottom'
|
||||||
|
| 'topLeft'
|
||||||
|
| 'topRight'
|
||||||
|
| 'leftTop'
|
||||||
|
| 'leftBottom'
|
||||||
|
| 'rightTop'
|
||||||
|
| 'rightBottom'
|
||||||
|
| 'bottomLeft'
|
||||||
|
| 'bottomRight';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a-button-group>
|
<Space>
|
||||||
<a-button type="primary" @click="openUploadModal" preIcon="carbon:cloud-upload">
|
<a-button type="primary" @click="openUploadModal" preIcon="carbon:cloud-upload">
|
||||||
{{ t('component.upload.upload') }}
|
{{ t('component.upload.upload') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|
@ -18,8 +18,7 @@
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</a-button-group>
|
</Space>
|
||||||
|
|
||||||
<UploadModal
|
<UploadModal
|
||||||
v-bind="bindValue"
|
v-bind="bindValue"
|
||||||
:previewFileList="fileList"
|
:previewFileList="fileList"
|
||||||
|
|
@ -38,19 +37,19 @@
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, watch, unref, computed } from 'vue';
|
import { defineComponent, ref, watch, unref, computed } from 'vue';
|
||||||
import UploadModal from './UploadModal.vue';
|
|
||||||
import UploadPreviewModal from './UploadPreviewModal.vue';
|
|
||||||
import { Icon } from '/@/components/Icon';
|
import { Icon } from '/@/components/Icon';
|
||||||
import { Tooltip } from 'ant-design-vue';
|
import { Tooltip, Space } from 'ant-design-vue';
|
||||||
import { useModal } from '/@/components/Modal';
|
import { useModal } from '/@/components/Modal';
|
||||||
import { uploadContainerProps } from './props';
|
import { uploadContainerProps } from './props';
|
||||||
import { omit } from 'lodash-es';
|
import { omit } from 'lodash-es';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
import { isArray } from '/@/utils/is';
|
import { isArray } from '/@/utils/is';
|
||||||
|
import UploadModal from './UploadModal.vue';
|
||||||
|
import UploadPreviewModal from './UploadPreviewModal.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicUpload',
|
name: 'BasicUpload',
|
||||||
components: { UploadModal, UploadPreviewModal, Icon, Tooltip },
|
components: { UploadModal, Space, UploadPreviewModal, Icon, Tooltip },
|
||||||
props: uploadContainerProps,
|
props: uploadContainerProps,
|
||||||
emits: ['change', 'delete', 'preview-delete', 'update:value'],
|
emits: ['change', 'delete', 'preview-delete', 'update:value'],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
:closeFunc="handleCloseFunc"
|
:closeFunc="handleCloseFunc"
|
||||||
:maskClosable="false"
|
:maskClosable="false"
|
||||||
:keyboard="false"
|
:keyboard="false"
|
||||||
wrapClassName="upload-modal"
|
class="upload-modal"
|
||||||
:okButtonProps="getOkButtonProps"
|
:okButtonProps="getOkButtonProps"
|
||||||
:cancelButtonProps="{ disabled: isUploadingRef }"
|
:cancelButtonProps="{ disabled: isUploadingRef }"
|
||||||
>
|
>
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
:accept="getStringAccept"
|
:accept="getStringAccept"
|
||||||
:multiple="multiple"
|
:multiple="multiple"
|
||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
|
:show-upload-list="false"
|
||||||
class="upload-modal-toolbar__btn"
|
class="upload-modal-toolbar__btn"
|
||||||
>
|
>
|
||||||
<a-button type="primary">
|
<a-button type="primary">
|
||||||
|
|
@ -54,7 +55,7 @@
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import { createTableColumns, createActionColumn } from './data';
|
import { createTableColumns, createActionColumn } from './data';
|
||||||
// utils
|
// utils
|
||||||
import { checkFileType, checkImgType, getBase64WithFile } from './helper';
|
import { checkImgType, getBase64WithFile } from './helper';
|
||||||
import { buildUUID } from '/@/utils/uuid';
|
import { buildUUID } from '/@/utils/uuid';
|
||||||
import { isFunction } from '/@/utils/is';
|
import { isFunction } from '/@/utils/is';
|
||||||
import { warn } from '/@/utils/log';
|
import { warn } from '/@/utils/log';
|
||||||
|
|
@ -84,7 +85,7 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const [register, { closeModal }] = useModalInner();
|
const [register, { closeModal }] = useModalInner();
|
||||||
|
|
||||||
const { getAccept, getStringAccept, getHelpText } = useUploadType({
|
const { getStringAccept, getHelpText } = useUploadType({
|
||||||
acceptRef: accept,
|
acceptRef: accept,
|
||||||
helpTextRef: helpText,
|
helpTextRef: helpText,
|
||||||
maxNumberRef: maxNumber,
|
maxNumberRef: maxNumber,
|
||||||
|
|
@ -124,18 +125,12 @@
|
||||||
function beforeUpload(file: File) {
|
function beforeUpload(file: File) {
|
||||||
const { size, name } = file;
|
const { size, name } = file;
|
||||||
const { maxSize } = props;
|
const { maxSize } = props;
|
||||||
const accept = unref(getAccept);
|
|
||||||
// 设置最大值,则判断
|
// 设置最大值,则判断
|
||||||
if (maxSize && file.size / 1024 / 1024 >= maxSize) {
|
if (maxSize && file.size / 1024 / 1024 >= maxSize) {
|
||||||
createMessage.error(t('component.upload.maxSizeMultiple', [maxSize]));
|
createMessage.error(t('component.upload.maxSizeMultiple', [maxSize]));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置类型,则判断
|
|
||||||
if (accept.length > 0 && !checkFileType(file, accept)) {
|
|
||||||
createMessage.error!(t('component.upload.acceptUpload', [accept.join(',')]));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const commonItem = {
|
const commonItem = {
|
||||||
uuid: buildUUID(),
|
uuid: buildUUID(),
|
||||||
file,
|
file,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<BasicModal
|
<BasicModal
|
||||||
width="800px"
|
width="800px"
|
||||||
:title="t('component.upload.preview')"
|
:title="t('component.upload.preview')"
|
||||||
wrapClassName="upload-preview-modal"
|
class="upload-preview-modal"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@register="register"
|
@register="register"
|
||||||
:showOkBtn="false"
|
:showOkBtn="false"
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,7 @@
|
||||||
import type { App } from 'vue';
|
import type { App } from 'vue';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
import {
|
import { Input, Layout } from 'ant-design-vue';
|
||||||
// Need
|
|
||||||
Button as AntButton,
|
|
||||||
Input,
|
|
||||||
Layout,
|
|
||||||
} from 'ant-design-vue';
|
|
||||||
|
|
||||||
const compList = [AntButton.Group];
|
|
||||||
|
|
||||||
export function registerGlobComp(app: App) {
|
export function registerGlobComp(app: App) {
|
||||||
compList.forEach((comp) => {
|
|
||||||
app.component(comp.name || comp.displayName, comp);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(Input).use(Button).use(Layout);
|
app.use(Input).use(Button).use(Layout);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,5 @@
|
||||||
// button reset
|
// button reset
|
||||||
.ant-btn {
|
.ant-btn {
|
||||||
// display: inline-flex;
|
|
||||||
// justify-content: center;
|
|
||||||
// align-items: center;
|
|
||||||
// &.ant-btn-success:not(.ant-btn-link),
|
|
||||||
// &.ant-btn-error:not(.ant-btn-link),
|
|
||||||
// &.ant-btn-warning:not(.ant-btn-link),
|
|
||||||
// &.ant-btn-primary:not(.ant-btn-link) {
|
|
||||||
// box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.08) !important;
|
|
||||||
// }
|
|
||||||
// &-group {
|
|
||||||
// .ant-btn:not(:first-child) {
|
|
||||||
// bottom: 1px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
&-link:hover,
|
&-link:hover,
|
||||||
&-link:focus,
|
&-link:focus,
|
||||||
&-link:active {
|
&-link:active {
|
||||||
|
|
@ -29,23 +15,12 @@
|
||||||
color: @white;
|
color: @white;
|
||||||
background-color: @button-primary-hover-color;
|
background-color: @button-primary-hover-color;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
//&[disabled],
|
|
||||||
//&[disabled]:hover {
|
|
||||||
// color: fade(@button-cancel-color, 40%) !important;
|
|
||||||
// background-color: fade(@button-cancel-bg-color, 40%) !important;
|
|
||||||
// border-color: fade(@button-cancel-border-color, 40%) !important;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&-primary:not(&-background-ghost):not([disabled]) {
|
&-primary:not(&-background-ghost):not([disabled]) {
|
||||||
color: @white;
|
color: @white;
|
||||||
}
|
}
|
||||||
|
|
||||||
//&-primary:not(&-background-ghost) {
|
|
||||||
// border-width: 0;
|
|
||||||
//}
|
|
||||||
|
|
||||||
&-default {
|
&-default {
|
||||||
color: @button-cancel-color;
|
color: @button-cancel-color;
|
||||||
background-color: @button-cancel-bg-color;
|
background-color: @button-cancel-bg-color;
|
||||||
|
|
@ -127,13 +102,6 @@
|
||||||
background-color: @button-success-active-color;
|
background-color: @button-success-active-color;
|
||||||
border-color: @button-success-active-color;
|
border-color: @button-success-active-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
//&[disabled],
|
|
||||||
//&[disabled]:hover {
|
|
||||||
// color: @white;
|
|
||||||
// background-color: fade(@button-success-color, 40%);
|
|
||||||
// border-color: fade(@button-success-color, 40%);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&-warning.ant-btn-link:not([disabled='disabled']) {
|
&-warning.ant-btn-link:not([disabled='disabled']) {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,6 @@
|
||||||
@import './pagination.less';
|
@import './pagination.less';
|
||||||
@import './input.less';
|
@import './input.less';
|
||||||
@import './btn.less';
|
@import './btn.less';
|
||||||
// @import './table.less';
|
|
||||||
|
|
||||||
// TODO beta.11 fix
|
|
||||||
.ant-col {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-image-preview-root {
|
.ant-image-preview-root {
|
||||||
img {
|
img {
|
||||||
|
|
@ -63,3 +57,11 @@ span.anticon:not(.app-iconify) {
|
||||||
border-top: 0 !important;
|
border-top: 0 !important;
|
||||||
border-left: 0 !important;
|
border-left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-form-item-control-input-content {
|
||||||
|
> div {
|
||||||
|
> div {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,3 +22,10 @@
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-input-number {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ html,
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: visible !important;
|
overflow: visible;
|
||||||
overflow-x: hidden !important;
|
overflow-x: hidden;
|
||||||
|
|
||||||
&.color-weak {
|
&.color-weak {
|
||||||
filter: invert(80%);
|
filter: invert(80%);
|
||||||
|
|
@ -40,5 +40,5 @@ button,
|
||||||
div,
|
div,
|
||||||
svg,
|
svg,
|
||||||
span {
|
span {
|
||||||
outline: none !important;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background-color: @primary-color;
|
background-color: @primary-color;
|
||||||
opacity: 75%;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,15 @@
|
||||||
|
.fade-transition {
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
transition: opacity 0.2s ease-in-out;
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
|
@ -5,7 +17,7 @@
|
||||||
|
|
||||||
.fade-enter-from,
|
.fade-enter-from,
|
||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fade-slide */
|
/* fade-slide */
|
||||||
|
|
@ -15,12 +27,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-slide-enter-from {
|
.fade-slide-enter-from {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateX(-30px);
|
transform: translateX(-30px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-slide-leave-to {
|
.fade-slide-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateX(30px);
|
transform: translateX(30px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,12 +47,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-bottom-enter-from {
|
.fade-bottom-enter-from {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateY(-10%);
|
transform: translateY(-10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-bottom-leave-to {
|
.fade-bottom-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateY(10%);
|
transform: translateY(10%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,12 +63,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-scale-enter-from {
|
.fade-scale-enter-from {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-scale-leave-to {
|
.fade-scale-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,11 +83,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-top-enter-from {
|
.fade-top-enter-from {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateY(8%);
|
transform: translateY(8%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-top-leave-to {
|
.fade-top-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateY(-8%);
|
transform: translateY(-8%);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave,
|
&-leave,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave,
|
&-leave,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: scale(0) rotate(-45deg);
|
transform: scale(0) rotate(-45deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-enter-from {
|
&-enter-from {
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-enter-from {
|
&-enter-from {
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-enter-from {
|
&-enter-from {
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-enter-from {
|
&-enter-from {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateY(-15px);
|
transform: translateY(-15px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateY(15px);
|
transform: translateY(15px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateX(-15px);
|
transform: translateX(-15px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: translateX(15px);
|
transform: translateX(15px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
.zoom-out-enter-from,
|
.zoom-out-enter-from,
|
||||||
.zoom-out-leave-to {
|
.zoom-out-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,11 +17,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoom-fade-enter-from {
|
.zoom-fade-enter-from {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: scale(0.92);
|
transform: scale(0.92);
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoom-fade-leave-to {
|
.zoom-fade-leave-to {
|
||||||
opacity: 0%;
|
opacity: 0;
|
||||||
transform: scale(1.06);
|
transform: scale(1.06);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,56 @@
|
||||||
import { on } from '/@/utils/domUtils';
|
import { on } from '/@/utils/domUtils'
|
||||||
import { isServer } from '/@/utils/is';
|
import { isServer } from '/@/utils/is'
|
||||||
import type { ComponentPublicInstance, DirectiveBinding, ObjectDirective } from 'vue';
|
import type { ComponentPublicInstance, DirectiveBinding, ObjectDirective } from 'vue'
|
||||||
|
|
||||||
type DocumentHandler = <T extends MouseEvent>(mouseup: T, mousedown: T) => void;
|
type DocumentHandler = <T extends MouseEvent>(mouseup: T, mousedown: T) => void
|
||||||
|
|
||||||
type FlushList = Map<
|
type FlushList = Map<
|
||||||
HTMLElement,
|
HTMLElement,
|
||||||
{
|
{
|
||||||
documentHandler: DocumentHandler;
|
documentHandler: DocumentHandler
|
||||||
bindingFn: (...args: unknown[]) => unknown;
|
bindingFn: (...args: unknown[]) => unknown
|
||||||
}
|
}
|
||||||
>;
|
>
|
||||||
|
|
||||||
const nodeList: FlushList = new Map();
|
const nodeList: FlushList = new Map()
|
||||||
|
|
||||||
let startClick: MouseEvent;
|
let startClick: MouseEvent
|
||||||
|
|
||||||
if (!isServer) {
|
if (!isServer) {
|
||||||
on(document, 'mousedown', (e: MouseEvent) => (startClick = e));
|
on(document, 'mousedown', (e: MouseEvent) => (startClick = e))
|
||||||
on(document, 'mouseup', (e: MouseEvent) => {
|
on(document, 'mouseup', (e: MouseEvent) => {
|
||||||
for (const { documentHandler } of nodeList.values()) {
|
for (const { documentHandler } of nodeList.values()) {
|
||||||
documentHandler(e, startClick);
|
documentHandler(e, startClick)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDocumentHandler(el: HTMLElement, binding: DirectiveBinding): DocumentHandler {
|
function createDocumentHandler(el: HTMLElement, binding: DirectiveBinding): DocumentHandler {
|
||||||
let excludes: HTMLElement[] = [];
|
let excludes: HTMLElement[] = []
|
||||||
if (Array.isArray(binding.arg)) {
|
if (Array.isArray(binding.arg)) {
|
||||||
excludes = binding.arg;
|
excludes = binding.arg
|
||||||
} else {
|
} else {
|
||||||
// due to current implementation on binding type is wrong the type casting is necessary here
|
// due to current implementation on binding type is wrong the type casting is necessary here
|
||||||
excludes.push(binding.arg as unknown as HTMLElement);
|
excludes.push(binding.arg as unknown as HTMLElement)
|
||||||
}
|
}
|
||||||
return function (mouseup, mousedown) {
|
return function (mouseup, mousedown) {
|
||||||
const popperRef = (
|
const popperRef = (
|
||||||
binding.instance as ComponentPublicInstance<{
|
binding.instance as ComponentPublicInstance<{
|
||||||
popperRef: Nullable<HTMLElement>;
|
popperRef: Nullable<HTMLElement>
|
||||||
}>
|
}>
|
||||||
).popperRef;
|
).popperRef
|
||||||
const mouseUpTarget = mouseup.target as Node;
|
const mouseUpTarget = mouseup.target as Node
|
||||||
const mouseDownTarget = mousedown.target as Node;
|
const mouseDownTarget = mousedown.target as Node
|
||||||
const isBound = !binding || !binding.instance;
|
const isBound = !binding || !binding.instance
|
||||||
const isTargetExists = !mouseUpTarget || !mouseDownTarget;
|
const isTargetExists = !mouseUpTarget || !mouseDownTarget
|
||||||
const isContainedByEl = el.contains(mouseUpTarget) || el.contains(mouseDownTarget);
|
const isContainedByEl = el.contains(mouseUpTarget) || el.contains(mouseDownTarget)
|
||||||
const isSelf = el === mouseUpTarget;
|
const isSelf = el === mouseUpTarget
|
||||||
|
|
||||||
const isTargetExcluded =
|
const isTargetExcluded =
|
||||||
(excludes.length && excludes.some((item) => item?.contains(mouseUpTarget))) ||
|
(excludes.length && excludes.some((item) => item?.contains(mouseUpTarget))) ||
|
||||||
(excludes.length && excludes.includes(mouseDownTarget as HTMLElement));
|
(excludes.length && excludes.includes(mouseDownTarget as HTMLElement))
|
||||||
const isContainedByPopper =
|
const isContainedByPopper =
|
||||||
popperRef && (popperRef.contains(mouseUpTarget) || popperRef.contains(mouseDownTarget));
|
popperRef && (popperRef.contains(mouseUpTarget) || popperRef.contains(mouseDownTarget))
|
||||||
if (
|
if (
|
||||||
isBound ||
|
isBound ||
|
||||||
isTargetExists ||
|
isTargetExists ||
|
||||||
|
|
@ -59,10 +59,10 @@ function createDocumentHandler(el: HTMLElement, binding: DirectiveBinding): Docu
|
||||||
isTargetExcluded ||
|
isTargetExcluded ||
|
||||||
isContainedByPopper
|
isContainedByPopper
|
||||||
) {
|
) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
binding.value();
|
binding.value()
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClickOutside: ObjectDirective = {
|
const ClickOutside: ObjectDirective = {
|
||||||
|
|
@ -70,17 +70,17 @@ const ClickOutside: ObjectDirective = {
|
||||||
nodeList.set(el, {
|
nodeList.set(el, {
|
||||||
documentHandler: createDocumentHandler(el, binding),
|
documentHandler: createDocumentHandler(el, binding),
|
||||||
bindingFn: binding.value,
|
bindingFn: binding.value,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
updated(el, binding) {
|
updated(el, binding) {
|
||||||
nodeList.set(el, {
|
nodeList.set(el, {
|
||||||
documentHandler: createDocumentHandler(el, binding),
|
documentHandler: createDocumentHandler(el, binding),
|
||||||
bindingFn: binding.value,
|
bindingFn: binding.value,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
unmounted(el) {
|
unmounted(el) {
|
||||||
nodeList.delete(el);
|
nodeList.delete(el)
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export default ClickOutside;
|
export default ClickOutside
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* Configure and register global directives
|
* Configure and register global directives
|
||||||
*/
|
*/
|
||||||
import type { App } from 'vue';
|
import type { App } from 'vue'
|
||||||
import { setupPermissionDirective } from './permission';
|
import { setupPermissionDirective } from './permission'
|
||||||
import { setupLoadingDirective } from './loading';
|
import { setupLoadingDirective } from './loading'
|
||||||
|
|
||||||
export function setupGlobDirectives(app: App) {
|
export function setupGlobDirectives(app: App) {
|
||||||
setupPermissionDirective(app);
|
setupPermissionDirective(app)
|
||||||
setupLoadingDirective(app);
|
setupLoadingDirective(app)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue