Browse Source

refactor(全局): 重构升级

升级依赖
Ant-Design-Vue3.x
Vue3.2.x
vite2.9.15
BREAKING CHANGE: 重构到vben最新分支
master
wangxiang 2 years ago
parent
commit
ef868d4f58
  1. 2
      .env
  2. 7
      .eslintrc.js
  3. 52
      .yarnclean
  4. 2
      build/config/themeConfig.ts
  5. 4
      build/generate/icon/index.ts
  6. 8
      build/script/buildConf.ts
  7. 6
      build/script/postBuild.ts
  8. 6
      build/vite/plugin/compress.ts
  9. 27
      build/vite/plugin/hmr.ts
  10. 8
      build/vite/plugin/html.ts
  11. 16
      build/vite/plugin/index.ts
  12. 64
      build/vite/plugin/styleImport.ts
  13. 4
      build/vite/plugin/svgSprite.ts
  14. 41
      build/vite/plugin/theme.ts
  15. 3
      build/vite/plugin/visualizer.ts
  16. 2
      index.html
  17. 237
      package.json
  18. 9674
      pnpm-lock.yaml
  19. BIN
      public/favicon.ico
  20. BIN
      public/resource/img/logo.png
  21. 2
      public/resource/img/logo.svg
  22. BIN
      public/resource/img/pwa-192x192.png
  23. BIN
      public/resource/img/pwa-512x512.png
  24. 1
      src/App.vue
  25. 2
      src/api/platform/core/controller/user.ts
  26. BIN
      src/assets/images/login-ad-mini.jpg
  27. BIN
      src/assets/images/logo.png
  28. 2
      src/assets/images/logo.svg
  29. 148
      src/assets/styles/ant-design/btn.less
  30. 8
      src/assets/styles/ant-design/index.less
  31. 3
      src/assets/styles/ant-design/input.less
  32. 5
      src/assets/styles/color.less
  33. 188
      src/assets/styles/common.less
  34. 6
      src/assets/styles/index.less
  35. 268
      src/assets/styles/kicc.less
  36. 12
      src/assets/styles/transition/fade.less
  37. 7
      src/assets/styles/var/index.less
  38. 13
      src/assets/styles/var/kicc.less
  39. 1
      src/assets/styles/vxe-table/index.less
  40. 110
      src/assets/styles/vxe-table/vxe.dark.less
  41. 10
      src/components/AMap/src/AMapDesigner/index.vue
  42. 20
      src/components/AMap/src/amap.data.tsx
  43. 14
      src/components/AMap/src/components/MapPointModal.vue
  44. 2
      src/components/Application/src/AppLogo.vue
  45. 4
      src/components/Button/src/BasicButton.vue
  46. 9
      src/components/Button/src/props.ts
  47. 17
      src/components/ClickOutSide/src/ClickOutSide.vue
  48. 99
      src/components/Container/src/collapse/CollapseContainer.vue
  49. 60
      src/components/Container/src/collapse/CollapseHeader.vue
  50. 15
      src/components/ContextMenu/src/ContextMenu.vue
  51. 1
      src/components/ContextMenu/src/typing.ts
  52. 3
      src/components/Cropper/src/CopperModal.vue
  53. 6
      src/components/Description/src/Description.vue
  54. 2
      src/components/Description/src/typing.ts
  55. 26
      src/components/Excel/src/Export2Excel.ts
  56. 118
      src/components/Excel/src/ImportExcel.vue
  57. 1
      src/components/Form/index.ts
  58. 31
      src/components/Form/src/BasicForm.vue
  59. 2
      src/components/Form/src/componentMap.ts
  60. 9
      src/components/Form/src/components/ApiCascader.vue
  61. 29
      src/components/Form/src/components/ApiRadioGroup.vue
  62. 16
      src/components/Form/src/components/ApiSelect.vue
  63. 138
      src/components/Form/src/components/ApiTransfer.vue
  64. 19
      src/components/Form/src/components/FormItem.vue
  65. 19
      src/components/Form/src/components/RadioButtonGroup.vue
  66. 4
      src/components/Form/src/helper.ts
  67. 8
      src/components/Form/src/hooks/useAdvanced.ts
  68. 10
      src/components/Form/src/hooks/useForm.ts
  69. 74
      src/components/Form/src/hooks/useFormEvents.ts
  70. 18
      src/components/Form/src/hooks/useFormValues.ts
  71. 10
      src/components/Form/src/props.ts
  72. 12
      src/components/Form/src/types/form.ts
  73. 3
      src/components/Form/src/types/index.ts
  74. 2
      src/components/Icon/src/Icon.vue
  75. 80
      src/components/Icon/src/IconPicker.vue
  76. 21
      src/components/Loading/src/Loading.vue
  77. 4
      src/components/Loading/src/useLoading.ts
  78. 2
      src/components/Markdown/index.ts
  79. 30
      src/components/Markdown/src/Markdown.vue
  80. 62
      src/components/Markdown/src/MarkdownViewer.vue
  81. 19
      src/components/Markdown/src/getTheme.ts
  82. 5
      src/components/Menu/src/BasicMenu.vue
  83. 11
      src/components/Menu/src/components/BasicMenuItem.vue
  84. 3
      src/components/Menu/src/components/MenuItemContent.vue
  85. 9
      src/components/Menu/src/props.ts
  86. 4
      src/components/Menu/src/useOpenKeys.ts
  87. 18
      src/components/Modal/src/BasicModal.vue
  88. 9
      src/components/Modal/src/components/Modal.tsx
  89. 2
      src/components/Modal/src/components/ModalClose.vue
  90. 1
      src/components/Modal/src/components/ModalFooter.vue
  91. 1
      src/components/Modal/src/components/ModalHeader.vue
  92. 11
      src/components/Modal/src/components/ModalWrapper.vue
  93. 5
      src/components/Modal/src/index.less
  94. 2
      src/components/Page/index.ts
  95. 4
      src/components/Page/src/PageFooter.vue
  96. 25
      src/components/Page/src/PageWrapper.vue
  97. 4
      src/components/Qrcode/src/Qrcode.vue
  98. 11
      src/components/Scrollbar/src/Scrollbar.vue
  99. 4
      src/components/Scrollbar/src/bar.ts
  100. 2
      src/components/Scrollbar/src/util.ts
  101. Some files were not shown because too many files have changed in this diff Show More

2
.env

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
VITE_PORT = 3100
# 网站标题
VITE_GLOB_APP_TITLE = Kicc Admin
VITE_GLOB_APP_TITLE = 康来智慧冷链平台
# 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符
VITE_GLOB_APP_SHORT_NAME = kicc_admin

7
.eslintrc.js

@ -56,7 +56,6 @@ module.exports = defineConfig({ @@ -56,7 +56,6 @@ module.exports = defineConfig({
/** ----------vue配置----------- */
'vue/script-setup-uses-vars': 'error',
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
@ -87,10 +86,7 @@ module.exports = defineConfig({ @@ -87,10 +86,7 @@ module.exports = defineConfig({
}],
'vue/max-attributes-per-line': ['error', {
'singleline': 3,
'multiline': {
'max': 1,
'allowFirstLine': true
}
'multiline': 1
}],
'vue/html-closing-bracket-spacing': ['error', {
'startTag': 'never',
@ -118,5 +114,6 @@ module.exports = defineConfig({ @@ -118,5 +114,6 @@ module.exports = defineConfig({
'alphabetical': false
}],
'vue/no-v-html': 'off',
'vue/multi-word-component-names': 'off',
}
});

52
.yarnclean

@ -1,52 +0,0 @@ @@ -1,52 +0,0 @@
# PROJECT: kicc-ui
# DESCRIPTION: 配置yarn install后清除并从软件包依赖关系中删除不必要的文件
# VERSION: 1.0.0
# Author: 康来生物科技有限公司-王翔
# test directories
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

2
build/config/themeConfig.ts

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
import { generate } from '@ant-design/colors';
export const primaryColor = '#0960bd';
export const primaryColor = '#0084f4';
type Fn = (...arg: any) => any;
type GenerateTheme = 'default' | 'dark';

4
build/generate/icon/index.ts

@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
import path from 'path';
import fs from 'fs-extra';
import inquirer from 'inquirer';
import chalk from 'chalk';
import colors from 'picocolors';
import pkg from '../../../package.json';
/** 生成图标集 */
@ -80,7 +80,7 @@ import pkg from '../../../package.json'; @@ -80,7 +80,7 @@ import pkg from '../../../package.json';
}
// 清除vite预构建缓存
fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite'));
console.log(`${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`);
console.log(`${colors.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`);
});
})();

8
build/script/buildConf.ts

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant';
import fs, { writeFileSync } from 'fs-extra';
import chalk from 'chalk';
import colors from 'picocolors';
import { getRootPath, getEnvConfig } from '../utils';
import { getConfigFileName } from '../getConfigFileName';
import pkg from '../../package.json';
@ -32,10 +32,10 @@ function createConfig({ @@ -32,10 +32,10 @@ function createConfig({
// 将配置信息追加到_app.config.js文件中
writeFileSync(getRootPath(`${OUTPUT_DIR}/${configFileName}`), configStr);
console.log(chalk.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`);
console.log(chalk.gray(OUTPUT_DIR + '/' + chalk.green(configFileName)) + '\n');
console.log(colors.cyan(`✨ [${pkg.name}]`) + ` - configuration file is build successfully:`);
console.log(colors.gray(OUTPUT_DIR + '/' + colors.green(configFileName)) + '\n');
} 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));
}
}

6
build/script/postBuild.ts

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
*/
import { runBuildConfig } from './buildConf';
import chalk from 'chalk';
import colors from 'picocolors';
import pkg from '../../package.json';
export const runBuild = async () => {
@ -18,9 +18,9 @@ export const runBuild = async () => { @@ -18,9 +18,9 @@ export const runBuild = async () => {
runBuildConfig();
}
console.log(`${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!');
console.log(`${colors.cyan(`[${pkg.name}]`)}` + ' - build successfully!');
} catch (error) {
console.log(chalk.red('vite build error:\n' + error));
console.log(colors.red('vite build error:\n' + error));
process.exit(1);
}
};

6
build/vite/plugin/compress.ts

@ -7,13 +7,13 @@ @@ -7,13 +7,13 @@
* @create: 2022/4/6
*/
import type { Plugin } from 'vite';
import compressPlugin from 'vite-plugin-compression';
import type { PluginOption } from 'vite';
export function configCompressPlugin(compress: 'gzip' | 'brotli' | 'none', deleteOriginFile = false): Plugin | Plugin[] {
export function configCompressPlugin(compress: 'gzip' | 'brotli' | 'none', deleteOriginFile = false): PluginOption | PluginOption[] {
const compressList = compress.split(',');
const plugins: Plugin[] = [];
const plugins: PluginOption[] = [];
if (compressList.includes('gzip')) {
plugins.push(

27
build/vite/plugin/hmr.ts

@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
/**
* @program: kicc-ui
* @description: HMR()
* todo: 目前解决方案直接清除已经导入的模块然后直接热部署,Vite循环依赖问题,,
* @author: entfrm开发团队-
* @create: 2022/4/5
*/
import type { Plugin } from 'vite';
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;
},
};
}

8
build/vite/plugin/html.ts

@ -7,8 +7,8 @@ @@ -7,8 +7,8 @@
* @create: 2022/4/5
*/
import type { Plugin } from 'vite';
import html from 'vite-plugin-html';
import type { PluginOption } from 'vite';
import { createHtmlPlugin } from 'vite-plugin-html';
import pkg from '../../../package.json';
import { GLOB_CONFIG_FILE_NAME } from '../../constant';
@ -20,11 +20,11 @@ export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) { @@ -20,11 +20,11 @@ export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
return `${path || '/'}${GLOB_CONFIG_FILE_NAME}?v=${pkg.version}-${new Date().getTime()}`;
};
const htmlPlugin: Plugin[] = html({
const htmlPlugin: PluginOption[] = createHtmlPlugin({
minify: isBuild,
inject: {
// 将数据注入ejs模板
injectData: {
data: {
title: VITE_GLOB_APP_TITLE,
},
// 嵌入生成的app.config.js文件

16
build/vite/plugin/index.ts

@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
* @create: 2022/4/5
*/
import type { Plugin } from 'vite';
import type { PluginOption } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy';
@ -19,7 +19,8 @@ import { configVisualizerConfig } from './visualizer'; @@ -19,7 +19,8 @@ import { configVisualizerConfig } from './visualizer';
import { configThemePlugin } from './theme';
import { configImageminPlugin } from './imagemin';
import { configSvgIconsPlugin } from './svgSprite';
import { configHmrPlugin } from './hmr';
import OptimizationPersist from 'vite-plugin-optimize-persist';
import PkgConfig from 'vite-plugin-package-config';
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
const {
@ -29,7 +30,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { @@ -29,7 +30,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE
} = viteEnv;
const vitePlugins: (Plugin | Plugin[])[] = [
const vitePlugins: (PluginOption | PluginOption[])[] = [
// 必须,提供对Vue3单文件组件构建
vue(),
// 必须,提供对Vue3 Jsx构建
@ -45,9 +46,6 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { @@ -45,9 +46,6 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// vite-plugin-purge-icons,提供对Iconify图标框架中的icon以dom节点的方式生成到html中
vitePlugins.push(purgeIcons());
// todo: 解决HMR(模块热部署)循环依赖问题
!isBuild && vitePlugins.push(configHmrPlugin());
// vite-plugin-html,提供压缩和基于ejs模板功能
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
@ -63,6 +61,12 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { @@ -63,6 +61,12 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// vite-plugin-style-import,提供对vite的按需引入组件库样式功能
vitePlugins.push(configStyleImportPlugin());
// vite-plugin-package-config,提供对依赖包的配置文件注入到package.json
vitePlugins.push(PkgConfig());
// vite-plugin-optimize-persist,提供对构建文件的缓存,避免二次预构建
vitePlugins.push(OptimizationPersist());
// 以下插件仅适用于生产环境
if (isBuild) {
// vite-plugin-imagemin,提供压缩图片资源的功能

64
build/vite/plugin/styleImport.ts

@ -7,9 +7,9 @@ @@ -7,9 +7,9 @@
* @create: 2022/4/5
*/
import styleImport from 'vite-plugin-style-import';
import { createStyleImportPlugin } from 'vite-plugin-style-import';
export function configStyleImportPlugin() {
const styleImportPlugin = styleImport({
const styleImportPlugin = createStyleImportPlugin({
libs: [
{
// 需要导入库名
@ -18,13 +18,69 @@ export function configStyleImportPlugin() { @@ -18,13 +18,69 @@ export function configStyleImportPlugin() {
esModule: true,
// 自定义样式文件转换
resolveStyle: (name) => {
return `ant-design-vue/es/${name}/style/index`;
// 这里是无需额外引入样式文件的“子组件”列表
const ignoreList = [
'anchor-link',
'sub-menu',
'menu-item',
'menu-divider',
'menu-item-group',
'breadcrumb-item',
'breadcrumb-separator',
'form-item',
'step',
'select-option',
'select-opt-group',
'card-grid',
'card-meta',
'collapse-panel',
'descriptions-item',
'list-item',
'list-item-meta',
'table-column',
'table-column-group',
'tab-pane',
'tab-content',
'timeline-item',
'tree-node',
'skeleton-input',
'skeleton-avatar',
'skeleton-title',
'skeleton-paragraph',
'skeleton-image',
'skeleton-button',
];
// 这里是需要额外引入样式的子组件列表
// 单独引入子组件时需引入组件样式,否则会在打包后导致子组件样式丢失
const replaceList = {
'typography-text': 'typography',
'typography-title': 'typography',
'typography-paragraph': 'typography',
'typography-link': 'typography',
'dropdown-button': 'dropdown',
'input-password': 'input',
'input-search': 'input',
'input-group': 'input',
'radio-group': 'radio',
'checkbox-group': 'checkbox',
'layout-sider': 'layout',
'layout-content': 'layout',
'layout-footer': 'layout',
'layout-header': 'layout',
'month-picker': 'date-picker',
'range-picker': 'date-picker',
'image-preview-group': 'image',
};
return ignoreList.includes(name)
? ''
: replaceList.hasOwnProperty(name)
? `ant-design-vue/es/${replaceList[name]}/style/index`
: `ant-design-vue/es/${name}/style/index`;
}
},
{ // 按需加载vxe-table组件
libraryName: 'vxe-table',
esModule: true,
resolveComponent: (name) => `vxe-table/es/${name}`,
resolveStyle: (name) => `vxe-table/es/${name}/style.css`
}
]

4
build/vite/plugin/svgSprite.ts

@ -8,11 +8,11 @@ @@ -8,11 +8,11 @@
* @create: 2022/4/5
*/
import SvgIconsPlugin from 'vite-plugin-svg-icons';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import path from 'path';
export function configSvgIconsPlugin(isBuild: boolean) {
const svgIconsPlugin = SvgIconsPlugin({
const svgIconsPlugin = createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
svgoOptions: isBuild,
// default

41
build/vite/plugin/theme.ts

@ -7,28 +7,29 @@ @@ -7,28 +7,29 @@
* @create: 2022/4/5
*/
import type { Plugin } from 'vite';
import type { PluginOption } from 'vite';
import path from 'path';
import {
viteThemePlugin,
antdDarkThemePlugin,
mixLighten,
mixDarken,
tinycolor
tinycolor,
} from 'vite-plugin-theme';
import { getThemeColors, generateColors } from '../../config/themeConfig';
import { generateModifyVars } from '../../generate/generateModifyVars';
export function configThemePlugin(isBuild: boolean): Plugin[] {
export function configThemePlugin(isBuild: boolean): PluginOption[] {
// 生成主题渐变颜色,进行匹配提取css
const colors = generateColors({
mixDarken,
mixLighten,
tinycolor
});
const plugin = [
// 配置vite主题插件,在vite编译时处理
viteThemePlugin({
// fix:修复编译后主题色切换不生效黑屏的问题
// https://github.com/vbenjs/vue-vben-admin/issues/1445
const vite_theme_plugin = viteThemePlugin({
// 自定义选择器转换
resolveSelector: (s) => {
s = s.trim();
@ -43,21 +44,36 @@ export function configThemePlugin(isBuild: boolean): Plugin[] { @@ -43,21 +44,36 @@ export function configThemePlugin(isBuild: boolean): Plugin[] {
return s;
case '.ant-select-item-option-selected:not(.ant-select-item-option-disabled)':
return s;
default:
if (s.indexOf('.ant-btn') >= -1) {
// 按钮被重新定制过,需要过滤掉class防止覆盖
return s;
}
}
// 对于没有data-theme前缀的css选择器,加个[data-theme]标识前缀,目前没什么用,后期可能会用到获取这部分数据
return s.startsWith('[data-theme') ? s : `[data-theme] ${s}`;
},
// 如果css包含数组中的颜色值,则会提取css
colorVariables: [...getThemeColors(), ...colors]
}),
});
vite_theme_plugin.forEach(function (item) {
//对vite:theme插件特殊配置
if ('vite:theme' === item.name) {
// 打包时去除enforce: "post",vite 2.6.x适配,否则生成app-theme-style为空,因为async transform(code, id) {的code没有正确获取
if (isBuild) {
delete item.enforce;
}
}
});
// 配置ant-design暗黑主题插件
antdDarkThemePlugin({
const plugin = [vite_theme_plugin, antdDarkThemePlugin({
// 设置服务器启动预加载antd.less文件
preloadFiles: [
path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.less'),
// path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.dark.less'),
path.resolve(process.cwd(), 'src/assets/styles/index.less'),
path.resolve(process.cwd(), 'node_modules/vxe-table/lib/style.css'),
],
// 过滤less(禁止在生产环境客户端控制台调用transform注入的函数处理css)
filter: (id) => (isBuild ? !id.endsWith('antd.less') : true),
@ -91,10 +107,9 @@ export function configThemePlugin(isBuild: boolean): Plugin[] { @@ -91,10 +107,9 @@ export function configThemePlugin(isBuild: boolean): Plugin[] {
'alert-warning-icon-color': '#d89614',
'alert-error-border-color': '#58181c',
'alert-error-bg-color': '#2a1215',
'alert-error-icon-color': '#a61d24'
'alert-error-icon-color': '#a61d24',
}
})
];
})];
return plugin as unknown as Plugin[];
return plugin as unknown as PluginOption[];
}

3
build/vite/plugin/visualizer.ts

@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
import visualizer from 'rollup-plugin-visualizer';
import { isReportMode } from '../../utils';
import type { PluginOption } from 'vite';
export function configVisualizerConfig() {
if (isReportMode()) {
@ -21,7 +22,7 @@ export function configVisualizerConfig() { @@ -21,7 +22,7 @@ export function configVisualizerConfig() {
gzipSize: true,
// 从源代码中收集brotli大小并将其显示在图表中
brotliSize: true,
}) as Plugin;
}) as PluginOption;
}
return [];
}

2
index.html

@ -152,7 +152,7 @@ @@ -152,7 +152,7 @@
</style>
<div class="app-loading">
<div class="app-loading-wrap">
<img src="/resource/img/logo.svg" alt="Logo"/>
<img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo"/>
<div class="app-loading-dots">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>

237
package.json

@ -12,11 +12,11 @@ @@ -12,11 +12,11 @@
"lint:check": "eslint --max-warnings 0 \"src/**/*.{vue,ts,tsx}\"",
"lint:eslint": "eslint --cache --max-warnings 0 \"src/**/*.{vue,ts,tsx}\" --fix",
"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts",
"build:test": "yarn lint:check && vite build --mode test && esno ./build/script/postBuild.ts",
"build:no-cache": "yarn delete:cache && yarn build",
"preview": "yarn run build && vite preview",
"build:test": "pnpm lint:check && vite build --mode test && esno ./build/script/postBuild.ts",
"build:no-cache": "pnpm delete:cache && pnpm build",
"preview": "pnpm run build && vite preview",
"preview:dist": "vite preview",
"report": "cross-env REPORT=true yarn run build",
"report": "cross-env REPORT=true pnpm run build",
"log": "conventional-changelog -p angular -i CHANGELOG.md -s",
"delete:lib": "rimraf node_modules",
"delete:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
@ -24,83 +24,96 @@ @@ -24,83 +24,96 @@
"type:check": "vue-tsc --noEmit --skipLibCheck"
},
"dependencies": {
"@amap/amap-jsapi-loader": "1.0.1",
"@iconify/iconify": "2.2.1",
"@vueuse/core": "9.1.1",
"@zxcvbn-ts/core": "2.0.1",
"ant-design-vue": "2.2.8",
"axios": "0.21.3",
"cropperjs": "1.5.12",
"crypto-js": "4.1.1",
"echarts": "5.2.0",
"@amap/amap-jsapi-loader": "^1.0.1",
"@iconify/iconify": "^2.1.30",
"@vueuse/core": "^9.1.1",
"@vueuse/shared": "^9.1.1",
"@zxcvbn-ts/core": "^2.0.1",
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.1.0",
"@vue/runtime-core": "^3.2.33",
"@vue/shared": "^3.2.33",
"ant-design-vue": "^3.2.12",
"axios": "^0.26.1",
"cropperjs": "^1.5.12",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.1",
"echarts": "^5.3.2",
"event-source-polyfill": "^1.0.31",
"js-base64": "3.6.1",
"lodash-es": "4.17.21",
"nprogress": "0.2.0",
"path-to-regexp": "6.2.0",
"pinia": "2.0.13",
"print-js": "1.6.0",
"qrcode": "1.4.4",
"qs": "6.10.3",
"resize-observer-polyfill": "1.5.1",
"js-base64": "^3.6.1",
"lodash-es": "^4.17.21",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0",
"pinia": "^2.0.13",
"print-js": "^1.6.0",
"qrcode": "^1.5.0",
"qs": "^6.10.3",
"resize-observer-polyfill": "^1.5.1",
"sortablejs": "^1.15.0",
"tinymce": "5.9.1",
"vditor": "3.8.6",
"vue": "3.2.12",
"vue-i18n": "9.1.7",
"vue-router": "4.0.11",
"vue-types": "4.0.3",
"vxe-table": "^4.2.8",
"tinymce": "^5.10.3",
"vditor": "^3.8.13",
"vue": "^3.2.45",
"vue-i18n": "^9.1.9",
"vue-router": "^4.0.14",
"vue-types": "^4.1.1",
"exceljs": "^4.3.0",
"vxe-table": "^4.3.9",
"vxe-table-plugin-antd": "^3.0.5",
"vxe-table-plugin-export-xlsx": "^3.0.4",
"xe-utils": "^3.5.4",
"xlsx": "0.17.2"
"xlsx": "^0.17.2"
},
"devDependencies": {
"@iconify/json": "2.1.30",
"@types/crypto-js": "4.0.2",
"@types/fs-extra": "9.0.12",
"@types/inquirer": "7.3.3",
"@types/lodash-es": "4.17.4",
"@types/nprogress": "0.2.0",
"@types/qrcode": "1.4.1",
"@types/qs": "6.9.7",
"@types/sortablejs": "1.10.7",
"@typescript-eslint/eslint-plugin": "4.31.1",
"@typescript-eslint/parser": "4.31.1",
"@vitejs/plugin-legacy": "1.5.3",
"@vitejs/plugin-vue": "1.6.2",
"@vitejs/plugin-vue-jsx": "1.1.8",
"@vue/compiler-sfc": "3.2.9",
"autoprefixer": "10.3.4",
"conventional-changelog-cli": "2.1.1",
"cross-env": "7.0.3",
"dotenv": "10.0.0",
"eslint": "7.32.0",
"eslint-define-config": "1.0.9",
"eslint-plugin-vue": "7.17.0",
"esno": "0.9.1",
"fs-extra": "10.0.0",
"inquirer": "8.1.2",
"less": "4.1.1",
"postcss": "8.3.6",
"rimraf": "3.0.2",
"rollup-plugin-visualizer": "5.5.2",
"typescript": "4.4.2",
"vite": "2.5.10",
"vite-plugin-compression": "0.3.5",
"vite-plugin-html": "2.1.0",
"vite-plugin-imagemin": "0.4.5",
"vite-plugin-purge-icons": "0.7.0",
"vite-plugin-pwa": "0.11.2",
"vite-plugin-style-import": "1.2.1",
"vite-plugin-svg-icons": "1.0.4",
"vite-plugin-theme": "0.8.1",
"vite-plugin-windicss": "1.4.3",
"vue-eslint-parser": "7.11.0",
"vue-tsc": "0.3.0"
"@iconify/json": "^2.1.30",
"@purge-icons/generated": "^0.8.1",
"@types/crypto-js": "^4.1.1",
"@types/fs-extra": "^9.0.13",
"@types/inquirer": "^8.2.1",
"@types/lodash-es": "^4.17.6",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.5.0",
"@types/qs": "^6.9.7",
"@types/sortablejs": "^1.10.7",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"@vitejs/plugin-legacy": "^2.0.0",
"@vitejs/plugin-vue": "^2.3.3",
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@vue/compiler-sfc": "^3.2.33",
"picocolors": "^1.0.0",
"autoprefixer": "^10.4.4",
"conventional-changelog-cli": "^2.2.2",
"cross-env": "^7.0.3",
"dotenv": "^16.0.0",
"eslint": "^8.13.0",
"eslint-define-config": "^1.1.1",
"eslint-plugin-vue": "^8.6.0",
"esno": "^0.14.1",
"fs-extra": "^10.1.0",
"inquirer": "^8.2.2",
"less": "^4.1.2",
"postcss": "^8.4.12",
"rimraf": "^3.0.2",
"rollup-plugin-visualizer": "^5.6.0",
"typescript": "^4.6.3",
"vite": "^2.9.15",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.0",
"vite-plugin-imagemin": "^0.6.1",
"vite-plugin-purge-icons": "^0.8.2",
"vite-plugin-pwa": "^0.12.3",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-theme": "^0.8.6",
"vite-plugin-windicss": "^1.8.7",
"vue-eslint-parser": "^8.3.0",
"vue-tsc": "^1.0.9",
"vite-plugin-optimize-persist": "^0.1.2",
"vite-plugin-package-config": "^0.1.1"
},
"resolutions": {
"bin-wrapper": "npm:bin-wrapper-china",
"rollup": "2.56.2"
"rollup": "2.72.0"
},
"engines": {
"node": "12 || >=14"
@ -108,5 +121,83 @@ @@ -108,5 +121,83 @@
"browserslist": [
"> 1%",
"last 2 versions"
],
"vite": {
"optimizeDeps": {
"include": [
"@ant-design/colors",
"@ant-design/icons-vue",
"@vueuse/core",
"@vueuse/shared",
"@zxcvbn-ts/core",
"ant-design-vue",
"axios",
"cropperjs",
"crypto-js/aes",
"crypto-js/enc-base64",
"crypto-js/enc-utf8",
"crypto-js/md5",
"crypto-js/mode-ecb",
"crypto-js/pad-pkcs7",
"echarts",
"echarts/charts",
"echarts/components",
"echarts/core",
"echarts/renderers",
"lodash-es",
"nprogress",
"path-to-regexp",
"pinia",
"print-js",
"qrcode",
"qs",
"resize-observer-polyfill",
"sortablejs",
"tinymce/icons/default/icons",
"tinymce/plugins/advlist",
"tinymce/plugins/anchor",
"tinymce/plugins/autolink",
"tinymce/plugins/autosave",
"tinymce/plugins/code",
"tinymce/plugins/codesample",
"tinymce/plugins/contextmenu",
"tinymce/plugins/directionality",
"tinymce/plugins/fullscreen",
"tinymce/plugins/hr",
"tinymce/plugins/image",
"tinymce/plugins/insertdatetime",
"tinymce/plugins/link",
"tinymce/plugins/lists",
"tinymce/plugins/media",
"tinymce/plugins/nonbreaking",
"tinymce/plugins/noneditable",
"tinymce/plugins/pagebreak",
"tinymce/plugins/paste",
"tinymce/plugins/preview",
"tinymce/plugins/print",
"tinymce/plugins/save",
"tinymce/plugins/searchreplace",
"tinymce/plugins/spellchecker",
"tinymce/plugins/tabfocus",
"tinymce/plugins/table",
"tinymce/plugins/template",
"tinymce/plugins/textcolor",
"tinymce/plugins/textpattern",
"tinymce/plugins/visualblocks",
"tinymce/plugins/visualchars",
"tinymce/plugins/wordcount",
"tinymce/themes/silver",
"tinymce/tinymce",
"vditor",
"vue",
"vue-i18n",
"vue-router",
"vue-types",
"vxe-table",
"vxe-table-plugin-antd",
"vxe-table-plugin-export-xlsx",
"xe-utils"
]
}
}
}

9674
pnpm-lock.yaml

File diff suppressed because it is too large Load Diff

BIN
public/favicon.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 254 KiB

BIN
public/resource/img/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

2
public/resource/img/logo.svg

@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1649230397851" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2943" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M687.3088 801.7664a9.6 9.6 0 0 1-9.6-9.6v-138.3168c0-8.448 4.5568-16.3072 11.8528-20.5568l105.984-61.184a4.5824 4.5824 0 0 0 2.2784-3.9424v-118.1952a9.6 9.6 0 0 1 19.2 0v118.1952a23.7824 23.7824 0 0 1-11.8784 20.5568l-105.9584 61.184a4.5824 4.5824 0 0 0-2.2784 3.9424v138.3168a9.6 9.6 0 0 1-9.6 9.6z" fill="#008CFF" p-id="2944"></path><path d="M704.128 778.1632a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM824.2432 419.8144a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2945"></path><path d="M191.9744 673.92a9.6 9.6 0 0 1-9.6-9.6v-138.3168c0-8.4736 4.5568-16.3328 11.8784-20.5568l105.9584-61.184a4.5824 4.5824 0 0 0 2.2784-3.9424v-118.1952a9.6 9.6 0 0 1 19.2 0V440.32a23.7824 23.7824 0 0 1-11.8784 20.5568l-105.9584 61.184a4.5824 4.5824 0 0 0-2.2784 3.9424v138.3168a9.6 9.6 0 0 1-9.6 9.6z" fill="#008CFF" p-id="2946"></path><path d="M208.7936 650.3168a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM328.9088 291.9424a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2947"></path><path d="M351.1296 763.008a9.6 9.6 0 0 1-9.6-9.5232l-1.7408-226.1248a9.6256 9.6256 0 0 1 9.5232-9.6768c4.736 0.5632 9.6256 4.2496 9.6768 9.5232l1.7408 226.1248a9.6256 9.6256 0 0 1-9.5232 9.6768h-0.0768z" fill="#008CFF" p-id="2948"></path><path d="M366.2336 510.4384a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM367.9744 736.5632a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2949"></path><path d="M813.9264 666.2656a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2950"></path><path d="M640.1536 144.2048a6.4 6.4 0 0 1-3.2-0.8704L512 71.2448 387.0464 143.36a6.4 6.4 0 1 1-6.4-11.0592l128.1536-73.9584a6.3488 6.3488 0 0 1 6.4 0l128.1536 73.9584c3.072 1.7664 4.1216 5.6832 2.3296 8.7296a6.4 6.4 0 0 1-5.5296 3.1744zM512 966.5536a6.272 6.272 0 0 1-3.2-0.8704l-128.1536-73.9584a6.3488 6.3488 0 0 1-2.3296-8.7296 6.4 6.4 0 0 1 8.7296-2.3296L512 952.7552l124.9536-72.1152a6.4 6.4 0 0 1 6.4 11.0592l-128.1536 73.9584a6.0672 6.0672 0 0 1-3.2 0.896zM123.8784 442.2912a6.4 6.4 0 0 1-6.4-6.4l0.0256-147.968a6.4 6.4 0 0 1 3.2-5.5296L248.8064 208.384a6.4 6.4 0 1 1 6.4 11.0592l-124.9024 72.192-0.0256 144.256a6.4 6.4 0 0 1-6.4 6.4zM771.9936 816.4864a6.4 6.4 0 0 1-3.2-11.9296l124.9024-72.1664 0.0256-144.256a6.4 6.4 0 0 1 12.8 0l-0.0256 147.968a6.4 6.4 0 0 1-3.2 5.5296l-128.1024 74.0096a6.656 6.656 0 0 1-3.2 0.8448zM252.0064 816.4864a6.4 6.4 0 0 1-3.2-0.8704l-128.1024-74.0096a6.4 6.4 0 0 1-3.2-5.5296l-0.0256-147.968a6.4 6.4 0 0 1 12.8 0l0.0256 144.256 124.9024 72.1664c3.072 1.7664 4.1216 5.6832 2.3296 8.7296a6.3232 6.3232 0 0 1-5.5296 3.2256zM900.1216 442.2912a6.4 6.4 0 0 1-6.4-6.4l-0.0256-144.256-124.9024-72.1664a6.4 6.4 0 0 1 6.4-11.0592l128.1024 74.0096a6.4 6.4 0 0 1 3.2 5.5296l0.0256 147.968a6.4 6.4 0 0 1-6.4 6.3744z" fill="#00CFFF" p-id="2951"></path><path d="M628.7872 258.176L516.8128 193.536a9.6 9.6 0 0 0-9.6 0l-111.9744 64.64a9.6256 9.6256 0 0 0-4.8128 8.32v129.3056c0 3.4304 1.8176 6.6048 4.8128 8.32l111.9744 64.64a9.8304 9.8304 0 0 0 9.6256 0l111.9744-64.64a9.6256 9.6256 0 0 0 4.8128-8.32V266.496a9.7536 9.7536 0 0 0-4.8384-8.32z m-14.4128 132.096L512 449.3568l-102.3744-59.1104v-118.2208L512 212.9408l102.3744 59.0848v118.2464z" fill="#008CFF" p-id="2952"></path><path d="M512 470.0416a9.6 9.6 0 0 1-9.6-9.6v-123.7504l-107.1872-61.8752a9.6 9.6 0 1 1 9.6-16.6144l111.9744 64.64a9.6256 9.6256 0 0 1 4.8128 8.32v129.3056a9.6 9.6 0 0 1-9.6 9.5744z" fill="#008CFF" p-id="2953"></path><path d="M640.7936 249.6768a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2954"></path><path d="M512 340.7616a9.5744 9.5744 0 0 1-4.8128-17.92l100.352-57.9328a9.5744 9.5744 0 1 1 9.6 16.6144l-100.352 57.9328a9.5488 9.5488 0 0 1-4.7872 1.3056z" fill="#008CFF" p-id="2955"></path><path d="M521.0112 601.6256a9.5744 9.5744 0 0 1-4.8128-17.92l130.048-75.008a9.5744 9.5744 0 1 1 9.6 16.6144l-130.048 75.008a9.2928 9.2928 0 0 1-4.7872 1.3056z" fill="#008CFF" p-id="2956"></path><path d="M523.4688 872.064a9.6 9.6 0 0 1-9.6-9.5232l-2.4576-270.4384a9.6 9.6 0 0 1 9.5232-9.6768c4.8128 0.5888 9.6256 4.224 9.6768 9.5232l2.4576 270.4384a9.6 9.6 0 0 1-9.5232 9.6768h-0.0768z" fill="#008CFF" p-id="2957"></path><path d="M537.8304 575.1808a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM540.1344 845.7984a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM667.8784 500.1728a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2958"></path></svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

BIN
public/resource/img/pwa-192x192.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
public/resource/img/pwa-512x512.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 155 KiB

1
src/App.vue

@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
import { AppProvider } from '/@/components/Application';
import { useTitle } from '/@/hooks/web/useTitle';
import { useLocale } from '/@/locales/useLocale';
import 'dayjs/locale/zh-cn';
//
const { getAntdLocale } = useLocale();

2
src/api/platform/core/controller/user.ts

@ -50,7 +50,7 @@ export const login = (params: LoginParams, options?: boolean | RequestOptions) = @@ -50,7 +50,7 @@ export const login = (params: LoginParams, options?: boolean | RequestOptions) =
export const getUserInfo = () => defHttp.get<User>({ url: Api.getUserInfo });
/** 登出 */
export const logout = () => defHttp.delete({ url: Api.logout });
export const logout = () => defHttp.delete({ url: Api.logout }, { errorMessageMode: 'none'});
/** 获取验证码 */
export const getCaptcha = () => defHttp.get<Captcha>({ url: `${Api.getCaptcha}?key=${Date.now()}` });

BIN
src/assets/images/login-ad-mini.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 KiB

BIN
src/assets/images/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

2
src/assets/images/logo.svg

@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1649230397851" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2943" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M687.3088 801.7664a9.6 9.6 0 0 1-9.6-9.6v-138.3168c0-8.448 4.5568-16.3072 11.8528-20.5568l105.984-61.184a4.5824 4.5824 0 0 0 2.2784-3.9424v-118.1952a9.6 9.6 0 0 1 19.2 0v118.1952a23.7824 23.7824 0 0 1-11.8784 20.5568l-105.9584 61.184a4.5824 4.5824 0 0 0-2.2784 3.9424v138.3168a9.6 9.6 0 0 1-9.6 9.6z" fill="#008CFF" p-id="2944"></path><path d="M704.128 778.1632a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM824.2432 419.8144a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2945"></path><path d="M191.9744 673.92a9.6 9.6 0 0 1-9.6-9.6v-138.3168c0-8.4736 4.5568-16.3328 11.8784-20.5568l105.9584-61.184a4.5824 4.5824 0 0 0 2.2784-3.9424v-118.1952a9.6 9.6 0 0 1 19.2 0V440.32a23.7824 23.7824 0 0 1-11.8784 20.5568l-105.9584 61.184a4.5824 4.5824 0 0 0-2.2784 3.9424v138.3168a9.6 9.6 0 0 1-9.6 9.6z" fill="#008CFF" p-id="2946"></path><path d="M208.7936 650.3168a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM328.9088 291.9424a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2947"></path><path d="M351.1296 763.008a9.6 9.6 0 0 1-9.6-9.5232l-1.7408-226.1248a9.6256 9.6256 0 0 1 9.5232-9.6768c4.736 0.5632 9.6256 4.2496 9.6768 9.5232l1.7408 226.1248a9.6256 9.6256 0 0 1-9.5232 9.6768h-0.0768z" fill="#008CFF" p-id="2948"></path><path d="M366.2336 510.4384a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM367.9744 736.5632a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2949"></path><path d="M813.9264 666.2656a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2950"></path><path d="M640.1536 144.2048a6.4 6.4 0 0 1-3.2-0.8704L512 71.2448 387.0464 143.36a6.4 6.4 0 1 1-6.4-11.0592l128.1536-73.9584a6.3488 6.3488 0 0 1 6.4 0l128.1536 73.9584c3.072 1.7664 4.1216 5.6832 2.3296 8.7296a6.4 6.4 0 0 1-5.5296 3.1744zM512 966.5536a6.272 6.272 0 0 1-3.2-0.8704l-128.1536-73.9584a6.3488 6.3488 0 0 1-2.3296-8.7296 6.4 6.4 0 0 1 8.7296-2.3296L512 952.7552l124.9536-72.1152a6.4 6.4 0 0 1 6.4 11.0592l-128.1536 73.9584a6.0672 6.0672 0 0 1-3.2 0.896zM123.8784 442.2912a6.4 6.4 0 0 1-6.4-6.4l0.0256-147.968a6.4 6.4 0 0 1 3.2-5.5296L248.8064 208.384a6.4 6.4 0 1 1 6.4 11.0592l-124.9024 72.192-0.0256 144.256a6.4 6.4 0 0 1-6.4 6.4zM771.9936 816.4864a6.4 6.4 0 0 1-3.2-11.9296l124.9024-72.1664 0.0256-144.256a6.4 6.4 0 0 1 12.8 0l-0.0256 147.968a6.4 6.4 0 0 1-3.2 5.5296l-128.1024 74.0096a6.656 6.656 0 0 1-3.2 0.8448zM252.0064 816.4864a6.4 6.4 0 0 1-3.2-0.8704l-128.1024-74.0096a6.4 6.4 0 0 1-3.2-5.5296l-0.0256-147.968a6.4 6.4 0 0 1 12.8 0l0.0256 144.256 124.9024 72.1664c3.072 1.7664 4.1216 5.6832 2.3296 8.7296a6.3232 6.3232 0 0 1-5.5296 3.2256zM900.1216 442.2912a6.4 6.4 0 0 1-6.4-6.4l-0.0256-144.256-124.9024-72.1664a6.4 6.4 0 0 1 6.4-11.0592l128.1024 74.0096a6.4 6.4 0 0 1 3.2 5.5296l0.0256 147.968a6.4 6.4 0 0 1-6.4 6.3744z" fill="#00CFFF" p-id="2951"></path><path d="M628.7872 258.176L516.8128 193.536a9.6 9.6 0 0 0-9.6 0l-111.9744 64.64a9.6256 9.6256 0 0 0-4.8128 8.32v129.3056c0 3.4304 1.8176 6.6048 4.8128 8.32l111.9744 64.64a9.8304 9.8304 0 0 0 9.6256 0l111.9744-64.64a9.6256 9.6256 0 0 0 4.8128-8.32V266.496a9.7536 9.7536 0 0 0-4.8384-8.32z m-14.4128 132.096L512 449.3568l-102.3744-59.1104v-118.2208L512 212.9408l102.3744 59.0848v118.2464z" fill="#008CFF" p-id="2952"></path><path d="M512 470.0416a9.6 9.6 0 0 1-9.6-9.6v-123.7504l-107.1872-61.8752a9.6 9.6 0 1 1 9.6-16.6144l111.9744 64.64a9.6256 9.6256 0 0 1 4.8128 8.32v129.3056a9.6 9.6 0 0 1-9.6 9.5744z" fill="#008CFF" p-id="2953"></path><path d="M640.7936 249.6768a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2954"></path><path d="M512 340.7616a9.5744 9.5744 0 0 1-4.8128-17.92l100.352-57.9328a9.5744 9.5744 0 1 1 9.6 16.6144l-100.352 57.9328a9.5488 9.5488 0 0 1-4.7872 1.3056z" fill="#008CFF" p-id="2955"></path><path d="M521.0112 601.6256a9.5744 9.5744 0 0 1-4.8128-17.92l130.048-75.008a9.5744 9.5744 0 1 1 9.6 16.6144l-130.048 75.008a9.2928 9.2928 0 0 1-4.7872 1.3056z" fill="#008CFF" p-id="2956"></path><path d="M523.4688 872.064a9.6 9.6 0 0 1-9.6-9.5232l-2.4576-270.4384a9.6 9.6 0 0 1 9.5232-9.6768c4.8128 0.5888 9.6256 4.224 9.6768 9.5232l2.4576 270.4384a9.6 9.6 0 0 1-9.5232 9.6768h-0.0768z" fill="#008CFF" p-id="2957"></path><path d="M537.8304 575.1808a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM540.1344 845.7984a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664zM667.8784 500.1728a23.808 23.808 0 1 1-33.6896 33.664 23.808 23.808 0 0 1 33.6896-33.664z" fill="#1AC678" p-id="2958"></path></svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

148
src/assets/styles/ant-design/btn.less

@ -8,19 +8,16 @@ @@ -8,19 +8,16 @@
&-primary {
color: @white;
background-color: @button-primary-color;
border-width: 0;
&:hover,
&:focus {
color: @white !important;
color: @white;
background-color: @button-primary-hover-color;
}
}
&[disabled],
&[disabled]:hover {
&-primary:not(&-background-ghost):not([disabled]) {
color: @white;
background-color: fade(@button-primary-color, 40%);
}
}
&-default {
@ -37,7 +34,7 @@ @@ -37,7 +34,7 @@
}
[data-theme='light'] &.ant-btn-link.is-disabled {
color: rgba(0, 0, 0, 0.25);
color: rgb(0 0 0 / 25%);
text-shadow: none;
cursor: not-allowed !important;
background-color: transparent !important;
@ -46,7 +43,7 @@ @@ -46,7 +43,7 @@
}
[data-theme='dark'] &.ant-btn-link.is-disabled {
color: rgba(255, 255, 255, 0.25) !important;
color: rgb(255 255 255 / 25%) !important;
text-shadow: none;
cursor: not-allowed !important;
background-color: transparent !important;
@ -54,6 +51,8 @@ @@ -54,6 +51,8 @@
box-shadow: none;
}
// color: @white;
&-success.ant-btn-link:not([disabled='disabled']) {
color: @button-success-color;
@ -62,6 +61,10 @@ @@ -62,6 +61,10 @@
color: @button-success-hover-color;
border-color: transparent;
}
&:active {
color: @button-success-active-color;
}
}
&-success.ant-btn-link.ant-btn-loading,
@ -74,11 +77,11 @@ @@ -74,11 +77,11 @@
}
}
&-success:not(.ant-btn-link) {
&-success:not(.ant-btn-link, .is-disabled) {
color: @white;
background-color: @button-success-color;
border-color: @button-success-color;
border-width: 0;
//border-width: 0;
&:hover,
&:focus {
@ -87,11 +90,9 @@ @@ -87,11 +90,9 @@
border-color: @button-success-hover-color;
}
&[disabled],
&[disabled]:hover {
color: @white;
background-color: fade(@button-success-color, 40%);
border-color: fade(@button-success-color, 40%);
&:active {
background-color: @button-success-active-color;
border-color: @button-success-active-color;
}
}
@ -103,13 +104,17 @@ @@ -103,13 +104,17 @@
color: @button-warn-hover-color;
border-color: transparent;
}
&:active {
color: @button-warn-active-color;
}
}
&-warning:not(.ant-btn-link) {
&-warning:not(.ant-btn-link, .is-disabled) {
color: @white;
background-color: @button-warn-color;
border-color: @button-warn-color;
border-width: 0;
//border-width: 0;
&:hover,
&:focus {
@ -118,11 +123,9 @@ @@ -118,11 +123,9 @@
border-color: @button-warn-hover-color;
}
&[disabled],
&[disabled]:hover {
color: @white;
background-color: fade(@button-warn-color, 40%);
border-color: fade(@button-warn-color, 40%);
&:active {
background-color: @button-warn-active-color;
border-color: @button-warn-active-color;
}
}
@ -134,13 +137,17 @@ @@ -134,13 +137,17 @@
color: @button-error-hover-color;
border-color: transparent;
}
&:active {
color: @button-error-active-color;
}
}
&-error:not(.ant-btn-link) {
&-error:not(.ant-btn-link, .is-disabled) {
color: @white;
background-color: @button-error-color;
border-color: @button-error-color;
border-width: 0;
//border-width: 0;
&:hover,
&:focus {
@ -149,41 +156,98 @@ @@ -149,41 +156,98 @@
border-color: @button-error-hover-color;
}
&[disabled],
&[disabled]:hover {
color: @white;
background-color: fade(@button-error-color, 40%);
border-color: fade(@button-error-color, 40%);
&:active {
background-color: @button-error-active-color;
border-color: @button-error-active-color;
}
}
&-background-ghost.ant-btn-link,
&.ant-btn-dashed:not([disabled='disabled']) {
color: @text-color-call-out;
&-background-ghost {
border-width: 1px;
background-color: transparent !important;
&:hover {
color: @button-primary-color;
&[disabled],
&[disabled]:hover {
color: fade(@white, 40%) !important;
background-color: transparent !important;
border-color: fade(@white, 40%) !important;
}
}
&-background-ghost {
&-dashed&-background-ghost,
&-default&-background-ghost {
color: @button-ghost-color;
background-color: transparent;
border-color: @button-ghost-color;
border-width: 1px;
&:hover,
&:focus {
color: @button-ghost-hover-color !important;
background-color: @button-ghost-hover-bg-color;
color: @button-ghost-hover-color;
border-color: @button-ghost-hover-color;
}
&:active {
color: @button-ghost-active-color;
border-color: @button-ghost-active-color;
}
&[disabled],
&[disabled]:hover {
color: @button-ghost-color;
background-color: fade(@white, 40%);
border-color: fade(@button-ghost-color, 40%);
color: fade(@white, 40%) !important;
border-color: fade(@white, 40%) !important;
}
}
&-background-ghost&-success:not(.ant-btn-link) {
color: @button-success-color;
background-color: transparent;
border-color: @button-success-color;
border-width: 1px;
&:hover,
&:focus {
color: @button-success-hover-color !important;
border-color: @button-success-hover-color;
}
&:active {
color: @button-success-active-color;
border-color: @button-success-active-color;
}
}
&-background-ghost&-warning:not(.ant-btn-link) {
color: @button-warn-color;
background-color: transparent;
border-color: @button-warn-color;
border-width: 1px;
&:hover,
&:focus {
color: @button-warn-hover-color !important;
border-color: @button-warn-hover-color;
}
&:active {
color: @button-warn-active-color;
border-color: @button-warn-active-color;
}
}
&-background-ghost&-error:not(.ant-btn-link) {
color: @button-error-color;
background-color: transparent;
border-color: @button-error-color;
border-width: 1px;
&:hover,
&:focus {
color: @button-error-hover-color !important;
border-color: @button-error-hover-color;
}
&:active {
color: @button-error-active-color;
border-color: @button-error-active-color;
}
}

8
src/assets/styles/ant-design/index.less

@ -61,3 +61,11 @@ span.anticon:not(.app-iconify) { @@ -61,3 +61,11 @@ span.anticon:not(.app-iconify) {
border-top: 0 !important;
border-left: 0 !important;
}
.ant-form-item-control-input-content {
> div {
> div {
max-width: 100%;
}
}
}

3
src/assets/styles/ant-design/input.less

@ -1,7 +1,8 @@ @@ -1,7 +1,8 @@
@import (reference) '../color.less';
.ant-input {
&-number {
&-number,
&-number-group-wrapper {
min-width: 110px;
}
}

5
src/assets/styles/color.less

@ -113,19 +113,24 @@ html { @@ -113,19 +113,24 @@ html {
@button-primary-color: @primary-color;
@button-primary-hover-color: darken(@primary-color, 5%);
@button-primary-active-color: darken(@primary-color, 5%);
@button-ghost-color: @primary-color;
@button-ghost-hover-color: lighten(@primary-color, 10%);
@button-ghost-hover-bg-color: #e1ebf6;
@button-ghost-active-color: darken(@white, 10%);
@button-success-color: @success-color;
@button-success-hover-color: darken(@success-color, 10%);
@button-success-active-color: darken(@success-color, 10%);
@button-warn-color: @warning-color;
@button-warn-hover-color: darken(@warning-color, 10%);
@button-warn-active-color: darken(@warning-color, 10%);
@button-error-color: @error-color;
@button-error-hover-color: darken(@error-color, 10%);
@button-error-active-color: darken(@error-color, 10%);
@button-cancel-color: @text-color-call-out;
@button-cancel-bg-color: @white;

188
src/assets/styles/common.less

@ -50,3 +50,191 @@ @@ -50,3 +50,191 @@
opacity: 0.75;
}
}
// =================================
// Custom Basic Table
// =================================
html[data-theme='dark'] {
.@{custom-basic-table-prefix-cls} {
// [黑暗模式]table顶部插槽多选栏样式
.alert {
background-color: #323232;
border-color: #424242;
}
}
}
.@{custom-basic-table-prefix-cls} {
max-width: 100%;
height: 100%;
&-row__striped {
td {
background-color: @app-content-background;
}
}
&-form-container {
padding: 16px;
.ant-form {
width: 100%;
padding: 12px 10px 6px 10px;
margin-bottom: 8px;
background-color: @component-background;
border-radius: 2px;
}
}
.ant-tag {
margin-right: 0;
}
.ant-table-wrapper {
padding: 6px;
background-color: @component-background;
border-radius: 2px;
.ant-table-title {
min-height: 40px;
padding: 0 0 8px !important;
}
.ant-table.ant-table-bordered .ant-table-title {
border: none !important;
}
}
.ant-table {
width: 100%;
overflow-x: hidden;
&-title {
display: flex;
padding: 8px 6px;
border-bottom: none;
justify-content: space-between;
align-items: center;
}
.ant-table-tbody > tr.ant-table-row-selected td {
background-color: fade(@primary-color, 8%) !important;
}
}
.ant-pagination {
margin: 10px 0 0;
}
.ant-table-footer {
padding: 0;
.ant-table-wrapper {
padding: 0;
}
table {
border: none !important;
}
.ant-table-body {
overflow-x: hidden !important;
}
td {
padding: 12px 8px;
}
}
// [明亮模式]table顶部插槽多选栏样式
.alert {
height: 38px;
background-color: #f3f3f3;
border-color: #e3e3e3;
}
&--inset {
.ant-table-wrapper {
padding: 0;
}
}
// 表格头部工具栏
&__toolbar {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
> * {
margin-right: 8px;
}
}
// 表格列动作列
&__action {
display: flex;
align-items: center;
height: 22px;
.action-divider {
display: table;
}
&.left {
justify-content: flex-start;
}
&.center {
justify-content: center;
}
&.right {
justify-content: flex-end;
}
button {
display: flex;
align-items: center;
span {
margin-left: 0 !important;
}
}
button.ant-btn-circle {
span {
margin: auto !important;
}
}
.ant-divider,
.ant-divider-vertical {
margin: 0 2px;
}
.icon-more {
transform: rotate(90deg);
svg {
font-size: 1.1em;
font-weight: 700;
}
}
}
// 表格设置
&__settings {
& > * {
margin-right: 12px;
}
svg {
width: 1.3em;
height: 1.3em;
}
}
}

6
src/assets/styles/index.less

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
@import 'common.less';
@import 'ant-design/index.less';
@import 'theme.less';
@import 'kicc.less';
@import 'vxe-table/index.less';
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset !important;
@ -22,8 +22,8 @@ html, @@ -22,8 +22,8 @@ html,
body {
width: 100%;
height: 100%;
overflow: visible !important;
overflow-x: hidden !important;
overflow: visible;
overflow-x: hidden;
&.color-weak {
filter: invert(80%);

268
src/assets/styles/kicc.less

@ -1,268 +0,0 @@ @@ -1,268 +0,0 @@
/**
* @program: kicc-ui
* @description: kicc系统相关样式
* 在kicc系统中全局调用的样式全部在这里配置
* @author: entfrm开发团队-王翔
* @create: 2022/4/7
*/
.table-settings {
& > * {
margin-right: 12px;
}
svg {
width: 1.3em;
height: 1.3em;
}
}
// 基础表格样式
[data-theme='dark'] {
.ant-table-tbody > tr:hover.ant-table-row-selected > td,
.ant-table-tbody > tr.ant-table-row-selected td {
background-color: #262626;
}
.@{basic-table-prefix-cls} {
// [黑暗模式]table顶部插槽多选栏样式
.alert {
background-color: #323232;
border-color: #424242;
}
}
}
.@{basic-table-prefix-cls} {
max-width: 100%;
&-row__striped {
td {
background-color: @app-content-background;
}
}
&-form-container {
padding: 16px;
.ant-form {
padding: 12px 10px 6px 10px;
margin-bottom: 16px;
background-color: @component-background;
border-radius: 2px;
}
}
.ant-tag {
margin-right: 0;
}
.ant-table-wrapper {
padding: 6px;
background-color: @component-background;
border-radius: 2px;
.ant-table-title {
min-height: 40px;
padding: 0 0 8px 0 !important;
}
.ant-table.ant-table-bordered .ant-table-title {
border: none !important;
}
}
.ant-table {
width: 100%;
overflow-x: hidden;
&-title {
display: flex;
padding: 8px 6px;
border-bottom: none;
justify-content: space-between;
align-items: center;
}
.ant-table-tbody > tr.ant-table-row-selected td {
background-color: fade(@primary-color, 8%) !important;
}
}
.ant-pagination {
margin: 10px 0 0 0;
}
.ant-table-footer {
padding: 0;
.ant-table-wrapper {
padding: 0;
}
table {
border: none !important;
}
.ant-table-body {
overflow-x: hidden !important;
overflow-y: scroll !important;
}
td {
padding: 12px 8px;
}
// [明亮模式]table顶部插槽多选栏样式
.alert {
height: 38px;
background-color: #f3f3f3;
border-color: #e3e3e3;
}
&--inset {
.ant-table-wrapper {
padding: 0;
}
}
}
// 表格头部样式
.@{basic-table-header-prefix-cls} {
&__toolbar {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
> * {
margin-right: 8px;
}
}
}
// 表格动作样式
.@{basic-table-action-prefix-cls} {
display: flex;
align-items: center;
.action-divider {
display: table;
}
&.left {
justify-content: flex-start;
}
&.center {
justify-content: center;
}
&.right {
justify-content: flex-end;
}
button {
display: flex;
align-items: center;
span {
margin-left: 0 !important;
}
}
button.ant-btn-circle {
span {
margin: auto !important;
}
}
.ant-divider,
.ant-divider-vertical {
margin: 0 2px;
}
.icon-more {
transform: rotate(90deg);
svg {
font-size: 1.1em;
font-weight: 700;
}
}
}
// 表格设置样式
.table-coulmn-drag-icon {
margin: 0 5px;
cursor: move;
}
.@{basic-column-setting-prefix-cls} {
&__popover-title {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
}
&__check-item {
display: flex;
align-items: center;
min-width: 100%;
padding: 4px 16px 8px 0;
.ant-checkbox-wrapper {
width: 100%;
&:hover {
color: @primary-color;
}
}
}
&__fixed-left,
&__fixed-right {
color: rgba(0, 0, 0, 0.45);
cursor: pointer;
&.active,
&:hover {
color: @primary-color;
}
&.disabled {
color: @disabled-color;
cursor: not-allowed;
}
}
&__fixed-right {
transform: rotate(180deg);
}
&__cloumn-list {
svg {
width: 1em !important;
height: 1em !important;
}
.ant-popover-inner-content {
// max-height: 360px;
padding-right: 0;
padding-left: 0;
// overflow: auto;
}
.ant-checkbox-group {
width: 100%;
min-width: 260px;
// flex-wrap: wrap;
}
.scrollbar {
height: 220px;
}
}
}
}

12
src/assets/styles/transition/fade.less

@ -1,3 +1,15 @@ @@ -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-leave-active {
transition: opacity 0.2s ease-in-out;

7
src/assets/styles/var/index.less

@ -8,12 +8,13 @@ @@ -8,12 +8,13 @@
@import (reference) '../color.less';
@import 'easing';
@import 'breakpoint';
@import 'kicc';
@namespace: kicc;
// tabs
@multiple-height: 30px;
@multiple-card-height: 50px;
@multiple-smooth-height: 50px;
// headers
@header-height: 48px;
@ -44,3 +45,7 @@ @@ -44,3 +45,7 @@
@content();
}
}
@custom-basic-table-prefix-cls: ~'@{namespace}-custom-basic-table';
@vxe-table-prefix-cls: ~'@{namespace}-vxe-table';

13
src/assets/styles/var/kicc.less

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
/**
* @program: kicc-ui
* @description: kicc系统相关变量定义
* 在kicc系统中全局调用的变量全部在这里配置
* @author: entfrm开发团队-王翔
* @create: 2022/4/7
*/
// 基础表格变量
@basic-table-prefix-cls: ~'@{namespace}-basic-table';
@basic-table-header-prefix-cls: ~'@{namespace}-basic-table-header';
@basic-table-action-prefix-cls: ~'@{namespace}-basic-table-action';
@basic-column-setting-prefix-cls: ~'@{namespace}-basic-column-setting';

1
src/assets/styles/vxe-table/index.less

@ -0,0 +1 @@ @@ -0,0 +1 @@
@import './vxe.dark.less';

110
src/assets/styles/vxe-table/vxe.dark.less

@ -0,0 +1,110 @@ @@ -0,0 +1,110 @@
[data-theme='dark'] .@{vxe-table-prefix-cls} {
@fontColor: #c9d1d9;
@bgColor: #151515;
@borderColor: #606060;
.vxe-cell--item,
.vxe-cell--title,
.vxe-cell,
.vxe-body--expanded-cell {
color: @fontColor;
}
.vxe-toolbar {
background-color: @bgColor;
}
.vxe-table--render-default .vxe-table--body-wrapper,
.vxe-table--render-default .vxe-table--footer-wrapper {
background-color: @bgColor;
}
// 外边框
.vxe-table--render-default .vxe-table--border-line {
border-color: @borderColor;
}
// header 下边框
.vxe-table .vxe-table--header-wrapper .vxe-table--header-border-line {
border-bottom-color: @borderColor;
}
// footer 上边框
.vxe-table--render-default .vxe-table--footer-wrapper {
border-top-color: @borderColor;
}
// 展开行 边框
.vxe-table--render-default .vxe-body--expanded-column {
border-bottom-color: @borderColor;
}
// 行斑马纹
.vxe-table--render-default .vxe-body--row.row--stripe {
background-color: #1e1e1e;
}
// 行hover
.vxe-table--render-default .vxe-body--row.row--hover {
background-color: #262626;
}
// 选中行
.vxe-table--render-default .vxe-body--row.row--checked {
background-color: #44403a;
&.row--hover {
background-color: #59524b;
}
}
.vxe-table--render-default.border--default .vxe-table--header-wrapper,
.vxe-table--render-default.border--full .vxe-table--header-wrapper,
.vxe-table--render-default.border--outer .vxe-table--header-wrapper {
background-color: #1d1d1d;
}
.vxe-table--render-default.border--default .vxe-body--column,
.vxe-table--render-default.border--default .vxe-footer--column,
.vxe-table--render-default.border--default .vxe-header--column,
.vxe-table--render-default.border--inner .vxe-body--column,
.vxe-table--render-default.border--inner .vxe-footer--column,
.vxe-table--render-default.border--inner .vxe-header--column {
background-image: linear-gradient(#1d1d1d, #1d1d1d);
}
// 列宽拖动
.vxe-header--column .vxe-resizable.is--line:before {
background-color: #505050;
}
// checkbox
.vxe-custom--option .vxe-checkbox--icon:before,
.vxe-export--panel-column-option .vxe-checkbox--icon:before,
.vxe-table--filter-option .vxe-checkbox--icon:before,
.vxe-table--render-default .vxe-cell--checkbox .vxe-checkbox--icon:before {
background-color: @bgColor;
border-color: @borderColor;
}
.vxe-toolbar .vxe-custom--option-wrapper {
background-color: @bgColor;
}
.vxe-button {
background-color: @bgColor;
border-color: @borderColor;
}
.vxe-button.type--button:not(.is--disabled):active {
background-color: @bgColor;
}
.vxe-toolbar .vxe-custom--wrapper.is--active > .vxe-button {
background-color: @bgColor;
}
.vxe-toolbar .vxe-custom--option-wrapper .vxe-custom--footer button {
color: @fontColor;
}
}

10
src/components/AMap/src/AMapDesigner/index.vue

@ -905,10 +905,10 @@ @@ -905,10 +905,10 @@
}
.operatePanel {
border: 1px solid @borderColor;
background: @component-background;
border: 1px solid @component-background;
width: @siderWidth;
height: 100%;
background-color: white;
position: absolute;
top: 0;
right: 0;
@ -928,7 +928,7 @@ @@ -928,7 +928,7 @@
font-family: Times;
text-align: center;
border-radius: 4px 0 0 4px;
color: #fff;
color: @component-background;
visibility: visible;
left: 0;
box-shadow: 0 2px 10px rgba(0,0,0,.2);
@ -951,8 +951,8 @@ @@ -951,8 +951,8 @@
}
.headToolbar {
border: 1px solid @borderColor;
right: @siderWidth;
background: @component-background;
border: 1px solid @component-background;
}
}

20
src/components/AMap/src/amap.data.tsx

@ -1,9 +1,3 @@ @@ -1,9 +1,3 @@
import { BasicColumn } from '/@/components/Table';
import { commonUpload } from '/@/api/platform/core/controller/upload';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
import { VxeTableDefines } from 'vxe-table/types/table';
import Icon from '/@/components/Icon/index';
/**
* @program: kicc-ui
@ -12,6 +6,18 @@ import Icon from '/@/components/Icon/index'; @@ -12,6 +6,18 @@ import Icon from '/@/components/Icon/index';
* @create: 2022/5/22
*/
import { BasicColumn } from '/@/components/Table';
import { commonUpload } from '/@/api/platform/core/controller/upload';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
import type { VxeColumnProps, VxeColumnPropTypes } from 'vxe-table/types/column';
import Icon from '/@/components/Icon/index';
export interface ColumnOptions extends VxeColumnProps {
children?: ColumnOptions[]
slots?: VxeColumnPropTypes.Slots
}
export type MapPointType = {
value: string;
label: string;
@ -247,7 +253,7 @@ export const taskPresetChildColumns: BasicColumn[] = [ @@ -247,7 +253,7 @@ export const taskPresetChildColumns: BasicColumn[] = [
];
/** 地图标记点表格列 */
export const mapPointColumns: VxeTableDefines.ColumnOptions[] = [
export const mapPointColumns: ColumnOptions[] = [
{
field: 'drag',
width: '50px',

14
src/components/AMap/src/components/MapPointModal.vue

@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
@register="registerModal"
@ok="handleSubmit"
>
<div class="pointBody">
<div :class="[prefixCls ,'pointBody']">
<div class="leftLayout">
<AMapDesigner ref="AMapDesignerEl"
:options="state.mapData"
@ -28,12 +28,12 @@ @@ -28,12 +28,12 @@
import { AMapDesigner } from '/@/components/AMap';
import Sortable from 'sortablejs';
import { VxeGridProps } from 'vxe-table';
import { mapPointColumns } from '../amap.data';
import { mapPointColumns, ColumnOptions } from '../amap.data';
import { defaultMapData } from '/@/enums/amapEnum';
import { add, cloneDeep, concat } from 'lodash-es';
import { add, cloneDeep } from 'lodash-es';
import { MapLogistic } from '/@/api/platform/common/entity/mapLogistic';
import { VxeTableDefines } from 'vxe-table/types/table';
import Icon from '/@/components/Icon/index';
import {useDesign} from '/@/hooks/web/useDesign';
/** 类型规范统一声明定义区域 */
interface WindowState {
@ -46,6 +46,7 @@ @@ -46,6 +46,7 @@
const MapLogisticPointVxeGridEl = ref();
const MapTaskPresetPointVxeGridEl = ref();
const AMapDesignerEl = ref();
const { prefixCls } = useDesign('vxe-table');
const state = reactive<WindowState>({
sortable: null,
gridOptions: {
@ -66,7 +67,7 @@ @@ -66,7 +67,7 @@
state.mapData = cloneDeep(data.mapData);
const props: Partial<ModalProps> = { confirmLoading: false };
props.title = '标记点配置';
const columns: VxeTableDefines.ColumnOptions[] = [
const columns: ColumnOptions[] = [
{
field: 'drag',
width: '50px',
@ -171,8 +172,5 @@ @@ -171,8 +172,5 @@
}
}
</style>

2
src/components/Application/src/AppLogo.vue

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
<template>
<div class="anticon" :class="getAppLogoClass" @click="goHome">
<img src="../../../assets/images/logo.svg">
<img src="../../../assets/images/logo.png">
<div v-show="showTitle" class="ml-2 truncate md:opacity-100" :class="getTitleClass">
{{ title }}
</div>

4
src/components/Button/src/BasicButton.vue

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
<template>
<Button v-bind="getBindValue" :class="getButtonClass" @click="onClick">
<template #default>
<template #default="data">
<Icon v-if="preIcon" :icon="preIcon" :size="iconSize"/>
<slot/>
<slot v-bind="data || {}"/>
<Icon v-if="postIcon" :icon="postIcon" :size="iconSize"/>
</template>
</Button>

9
src/components/Button/src/props.ts

@ -1,5 +1,12 @@ @@ -1,5 +1,12 @@
const validColors = ['error', 'warning', 'success', ''] as const;
type ButtonColorType = typeof validColors[number];
export const buttonProps = {
color: { type: String, validator: (v) => ['error', 'warning', 'success', ''].includes(v) },
color: {
type: String as PropType<ButtonColorType>,
validator: (v) => validColors.includes(v),
default: '',
},
loading: { type: Boolean },
disabled: { type: Boolean },
/**

17
src/components/ClickOutSide/src/ClickOutSide.vue

@ -3,24 +3,17 @@ @@ -3,24 +3,17 @@
<slot/>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue';
import { MaybeElementRef, onClickOutside } from '@vueuse/core';
export default defineComponent({
name: 'ClickOutSide',
emits: ['mounted', 'clickOutside'],
setup(_, { emit }) {
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { onClickOutside } from '@vueuse/core';
const emit = defineEmits(['mounted', 'clickOutside']);
const wrap = ref<ElRef>(null);
onClickOutside(wrap as MaybeElementRef, () => {
onClickOutside(wrap, () => {
emit('clickOutside');
});
onMounted(() => {
emit('mounted');
});
return { wrap };
},
});
</script>

99
src/components/Container/src/collapse/CollapseContainer.vue

@ -1,48 +1,18 @@ @@ -1,48 +1,18 @@
<template>
<div :class="prefixCls">
<CollapseHeader v-bind="$props"
:prefixCls="prefixCls"
:show="show"
@expand="handleExpand"
>
<template #title>
<slot name="title"/>
</template>
<template #action>
<slot name="action"/>
</template>
</CollapseHeader>
<div class="p-2">
<CollapseTransition :enable="canExpan">
<Skeleton v-if="loading" :active="loading"/>
<div v-else v-show="show" :class="`${prefixCls}__body`">
<slot/>
</div>
</CollapseTransition>
</div>
<div v-if="$slots.footer" :class="`${prefixCls}__footer`">
<slot name="footer"/>
</div>
</div>
</template>
<script lang="ts">
import type { PropType } from 'vue';
import { defineComponent, ref } from 'vue';
// component
<script lang="tsx">
import { ref, unref, defineComponent, type PropType, type ExtractPropTypes } from 'vue';
import { isNil } from 'lodash-es';
import { Skeleton } from 'ant-design-vue';
import { CollapseTransition } from '/@/components/Transition';
import CollapseHeader from './CollapseHeader.vue';
import { triggerWindowResize } from '/@/utils/event';
// hook
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { useDesign } from '/@/hooks/web/useDesign';
const props = {
const collapseContainerProps = {
title: { type: String, default: '' },
loading: { type: Boolean },
/**
* 可以扩展吗
* 是否扩展
*/
canExpan: { type: Boolean, default: true },
/**
@ -63,35 +33,54 @@ @@ -63,35 +33,54 @@
lazyTime: { type: Number, default: 0 },
};
export type CollapseContainerProps = ExtractPropTypes<typeof collapseContainerProps>;
export default defineComponent({
name: 'CollapseContainer',
components: {
Skeleton,
CollapseHeader,
CollapseTransition,
},
props,
setup(props) {
const show = ref(true);
props: collapseContainerProps,
setup(props, { expose, slots }) {
const { prefixCls } = useDesign('collapse-container');
/**
* 处理开发事件
*/
function handleExpand() {
show.value = !show.value;
const show = ref(true);
const handleExpand = (val: boolean) => {
show.value = isNil(val) ? !show.value : val;
if (props.triggerWindowResize) {
// 200
// 200 milliseconds here is because the expansion has animation,
useTimeoutFn(triggerWindowResize, 200);
}
}
return {
show,
handleExpand,
prefixCls,
};
expose({ handleExpand });
return () => (
<div class={unref(prefixCls)}>
<CollapseHeader
{...props}
prefixCls={unref(prefixCls)}
onExpand={handleExpand}
show={show.value}
v-slots={{
title: slots.title,
action: slots.action,
}}
/>
<div class="p-2">
<CollapseTransition enable={props.canExpan}>
{props.loading ? (
<Skeleton active={props.loading} />
) : (
<div class={`${prefixCls}__body`} v-show={show.value}>{slots.default?.()}</div>
)}
</CollapseTransition>
</div>
{slots.footer && <div class={`${prefixCls}__footer`}>{slots.footer()}</div>}
</div>
);
},
});
</script>

60
src/components/Container/src/collapse/CollapseHeader.vue

@ -1,42 +1,44 @@ @@ -1,42 +1,44 @@
<template>
<div :class="[`${prefixCls}__header px-2 py-5`, $attrs.class]">
<BasicTitle :helpMessage="helpMessage" normal>
<template v-if="title">
{{ title }}
</template>
<template v-else>
<slot name="title"/>
</template>
</BasicTitle>
<div :class="`${prefixCls}__action`">
<slot name="action"/>
<BasicArrow v-if="canExpan"
up
:expand="show"
@click="$emit('expand')"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="tsx">
import { defineComponent, computed, unref, type ExtractPropTypes } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { BasicArrow, BasicTitle } from '/@/components/Basic';
const props = {
prefixCls: { type: String },
const collapseHeaderProps = {
prefixCls: String,
title: String,
show: Boolean,
canExpan: Boolean,
helpMessage: {
type: [Array, String] as PropType<string[] | string>,
default: '',
},
title: { type: String },
show: { type: Boolean },
canExpan: { type: Boolean },
};
export type CollapseHeaderProps = ExtractPropTypes<typeof collapseHeaderProps>;
export default defineComponent({
components: { BasicArrow, BasicTitle },
name: 'CollapseHeader',
inheritAttrs: false,
props,
props: collapseHeaderProps,
emits: ['expand'],
setup(props, { slots, attrs, emit }) {
const { prefixCls } = useDesign('collapse-container');
const _prefixCls = computed(() => props.prefixCls || unref(prefixCls));
return () => (
<div class={[`${unref(_prefixCls)}__header px-2 py-5`, attrs.class]}>
<BasicTitle helpMessage={props.helpMessage} normal>
{slots.title?.() || props.title}
</BasicTitle>
<div class={`${unref(_prefixCls)}__action`}>
{slots.action
? slots.action({ expand: props.show, onClick: () => emit('expand') })
: props.canExpan && (
<BasicArrow up expand={props.show} onClick={() => emit('expand')} />
)}
</div>
</div>
);
},
});
</script>

15
src/components/ContextMenu/src/ContextMenu.vue

@ -60,9 +60,11 @@ @@ -60,9 +60,11 @@
const top = body.clientHeight < y + menuHeight ? y - menuHeight : y;
return {
...styles,
position: 'absolute',
width: `${width}px`,
left: `${left + 1}px`,
top: `${top + 1}px`,
zIndex: 9999,
};
});
@ -87,7 +89,8 @@ @@ -87,7 +89,8 @@
}
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 contentProps = {
@ -124,15 +127,11 @@ @@ -124,15 +127,11 @@
}
const { items } = props;
return (
<Menu
inlineIndent={12}
mode="vertical"
class={prefixCls}
ref={wrapRef}
style={unref(getStyle)}
>
<div class={prefixCls}>
<Menu inlineIndent={12} mode="vertical" ref={wrapRef} style={unref(getStyle)}>
{renderMenuItem(items)}
</Menu>
</div>
);
};
},

1
src/components/ContextMenu/src/typing.ts

@ -6,6 +6,7 @@ export interface Axis { @@ -6,6 +6,7 @@ export interface Axis {
export interface ContextMenuItem {
label: string;
icon?: string;
hidden?: boolean;
disabled?: boolean;
handler?: Fn;
divider?: boolean;

3
src/components/Cropper/src/CopperModal.vue

@ -129,6 +129,7 @@ @@ -129,6 +129,7 @@
uploadApi: {
type: Function as PropType<(params: apiFunParams) => Promise<any>>,
},
src: { type: String },
};
export default defineComponent({
@ -138,7 +139,7 @@ @@ -138,7 +139,7 @@
emits: ['uploadSuccess', 'register'],
setup(props, { emit }) {
let filename = '';
const src = ref('');
const src = ref(props.src || '');
const previewSource = ref('');
const cropper = ref<Cropper>();
let scaleX = 1;

6
src/components/Description/src/Description.vue

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
import type { DescriptionsProps } from 'ant-design-vue/es/descriptions/index';
import type { CSSProperties } from 'vue';
import type { CollapseContainerOptions } from '/@/components/Container/index';
import { defineComponent, computed, ref, unref } from 'vue';
import { defineComponent, computed, ref, unref, toRefs } from 'vue';
import { get } from 'lodash-es';
import { Descriptions } from 'ant-design-vue';
import { CollapseContainer } from '/@/components/Container/index';
@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
import { getSlot } from '/@/utils/helper/tsxHelper';
import { useAttrs } from '/@/hooks/core/useAttrs';
const props = {
useCollapse: { type: Boolean, default: true },
title: { type: String, default: '' },
@ -121,6 +122,9 @@ @@ -121,6 +122,9 @@
return null;
}
const getField = get(_data, field);
if (getField && !toRefs(_data).hasOwnProperty(field)) {
return isFunction(render) ? render('', _data) : '';
}
return isFunction(render) ? render(getField, _data) : getField ?? '';
};

2
src/components/Description/src/typing.ts

@ -14,7 +14,7 @@ export interface DescItem { @@ -14,7 +14,7 @@ export interface DescItem {
// render
render?: (
val: any,
data: Recordable
data: Recordable,
) => VNode | undefined | JSX.Element | Element | string | number;
}

26
src/components/Excel/src/Export2Excel.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import xlsx from 'xlsx';
import * as xlsx from 'xlsx';
import type { WorkBook } from 'xlsx';
import type { JsonToSheet, AoAToSheet } from './typing';
@ -6,6 +6,28 @@ const { utils, writeFile } = xlsx; @@ -6,6 +6,28 @@ const { utils, writeFile } = xlsx;
const DEF_FILE_NAME = 'excel-list.xlsx';
/**
* @param data source data
* @param worksheet worksheet object
* @param min min width
*/
function setColumnWidth(data, worksheet, min = 3) {
const obj = {};
worksheet['!cols'] = [];
data.forEach((item) => {
Object.keys(item).forEach((key) => {
const cur = item[key];
const length = cur?.length ?? min;
obj[key] = Math.max(length, obj[key] ?? min);
});
});
Object.keys(obj).forEach((key) => {
worksheet['!cols'].push({
wch: obj[key],
});
});
}
export function jsonToSheetXlsx<T = any>({
data,
header,
@ -20,7 +42,7 @@ export function jsonToSheetXlsx<T = any>({ @@ -20,7 +42,7 @@ export function jsonToSheetXlsx<T = any>({
}
const worksheet = utils.json_to_sheet(arrData, json2sheetOpts);
setColumnWidth(arrData, worksheet);
/* add worksheet to workbook */
const workbook: WorkBook = {
SheetNames: [filename],

118
src/components/Excel/src/ImportExcel.vue

@ -14,15 +14,68 @@ @@ -14,15 +14,68 @@
</template>
<script lang="ts">
import { defineComponent, ref, unref } from 'vue';
import XLSX from 'xlsx';
import type { ExcelData } from './typing';
import * as XLSX from 'xlsx';
import { dateUtil } from '/@/utils/dateUtil';
import type { ExcelData } from './typing';
export default defineComponent({
name: 'ImportExcel',
emits: ['success', 'error'],
setup(_, { emit }) {
props: {
// Date
dateFormat: {
type: String,
},
// +08:00
// https://github.com/SheetJS/sheetjs/issues/1470#issuecomment-501108554
timeZone: {
type: Number,
default: 8,
},
//
isReturnFile: {
type: Boolean,
default: false,
},
},
emits: ['success', 'error', 'cancel'],
setup(props, { emit }) {
const inputRef = ref<HTMLInputElement | null>(null);
const loadingRef = ref<Boolean>(false);
const cancelRef = ref<Boolean>(true);
function shapeWorkSheel(sheet: XLSX.WorkSheet, range: XLSX.Range) {
let str = ' ',
char = 65,
customWorkSheet = {
t: 's',
v: str,
r: '<t> </t><phoneticPr fontId="1" type="noConversion"/>',
h: str,
w: str,
};
if (!sheet || !sheet['!ref']) return [];
let c = 0,
r = 1;
while (c < range.e.c + 1) {
while (r < range.e.r + 1) {
if (!sheet[String.fromCharCode(char) + r]) {
sheet[String.fromCharCode(char) + r] = customWorkSheet;
}
r++;
}
r = 1;
str += ' ';
customWorkSheet = {
t: 's',
v: str,
r: '<t> </t><phoneticPr fontId="1" type="noConversion"/>',
h: str,
w: str,
};
c++;
char++;
}
}
/**
* @description: 第一行作为头部
@ -31,8 +84,8 @@ @@ -31,8 +84,8 @@
if (!sheet || !sheet['!ref']) return [];
const headers: string[] = [];
// A3:B7=>{s:{c:0, r:2}, e:{c:1, r:6}}
const range = XLSX.utils.decode_range(sheet['!ref']);
const range: XLSX.Range = XLSX.utils.decode_range(sheet['!ref']);
shapeWorkSheel(sheet, range);
const R = range.s.r;
/* start in the first row */
for (let C = range.s.c; C <= range.e.c; ++C) {
@ -51,10 +104,28 @@ @@ -51,10 +104,28 @@
*/
function getExcelData(workbook: XLSX.WorkBook) {
const excelData: ExcelData[] = [];
const { dateFormat, timeZone } = props;
for (const sheetName of workbook.SheetNames) {
const worksheet = workbook.Sheets[sheetName];
const header: string[] = getHeaderRow(worksheet);
const results = XLSX.utils.sheet_to_json(worksheet);
let results = XLSX.utils.sheet_to_json(worksheet, {
raw: true,
dateNF: dateFormat, //Not worked
}) as object[];
results = results.map((row: object) => {
for (let field in row) {
if (row[field] instanceof Date) {
if (timeZone === 8) {
row[field].setSeconds(row[field].getSeconds() + 43);
}
if (dateFormat) {
row[field] = dateUtil(row[field]).format(dateFormat);
}
}
}
return row;
});
excelData.push({
header,
results,
@ -76,7 +147,7 @@ @@ -76,7 +147,7 @@
reader.onload = async (e) => {
try {
const data = e.target && e.target.result;
const workbook = XLSX.read(data, { type: 'array' });
const workbook = XLSX.read(data, { type: 'array', cellDates: true });
// console.log(workbook);
/* DO SOMETHING WITH workbook HERE */
const excelData = getExcelData(workbook);
@ -106,18 +177,45 @@ @@ -106,18 +177,45 @@
* @description: 触发选择文件管理器
*/
function handleInputClick(e: Event) {
const files = e && (e.target as HTMLInputElement).files;
const target = e && (e.target as HTMLInputElement);
const files = target?.files;
const rawFile = files && files[0]; // only setting files[0]
target.value = '';
if (!rawFile) return;
cancelRef.value = false;
if (props.isReturnFile) {
emit('success', rawFile);
return;
}
upload(rawFile);
}
/**
* @description 文件选择器关闭后,判断取消状态
*/
function handleFocusChange() {
const timeId = setInterval(() => {
if (cancelRef.value === true) {
emit('cancel');
}
clearInterval(timeId);
window.removeEventListener('focus', handleFocusChange);
}, 1000);
}
/**
* @description: 点击上传按钮
*/
function handleUpload() {
const inputRefDom = unref(inputRef);
inputRefDom && inputRefDom.click();
if (inputRefDom) {
cancelRef.value = true;
inputRefDom.click();
window.addEventListener('focus', handleFocusChange);
}
}
return { handleUpload, handleInputClick, inputRef };

1
src/components/Form/index.ts

@ -12,5 +12,6 @@ export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue'; @@ -12,5 +12,6 @@ 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 ApiCascader } from './src/components/ApiCascader.vue';
export { default as ApiTransfer } from './src/components/ApiTransfer.vue';
export { BasicForm };

31
src/components/Form/src/BasicForm.vue

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
<slot name="formHeader"/>
<template v-for="schema in getSchema" :key="schema.field">
<FormItem
:isAdvanced="fieldsIsAdvancedMap[schema.field]"
:tableAction="tableAction"
:formActionType="formActionType"
:schema="schema"
@ -56,6 +57,8 @@ @@ -56,6 +57,8 @@
import { useDebounceFn } from '@vueuse/core';
import { basicProps } from './props';
import { useDesign } from '/@/hooks/web/useDesign';
import { cloneDeep } from 'lodash-es';
import { isFunction, isArray } from '/@/utils/is';
export default defineComponent({
name: 'BasicForm',
@ -83,7 +86,11 @@ @@ -83,7 +86,11 @@
// Get the basic configuration of the form
const getProps = computed((): FormProps => {
return { ...props, ...unref(propsRef) } as FormProps;
let mergeProps = deepMerge(props, unref(propsRef)) as FormProps;
if (mergeProps.labelWidth) {
mergeProps.labelCol = undefined;
}
return mergeProps;
});
const getFormClass = computed(() => {
@ -111,9 +118,9 @@ @@ -111,9 +118,9 @@
const getSchema = computed((): FormSchema[] => {
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
for (const schema of schemas) {
const { defaultValue, component } = schema;
const { defaultValue, component, isHandleDateDefaultValue = true } = schema;
// handle date type
if (defaultValue && dateItemType.includes(component)) {
if (isHandleDateDefaultValue && defaultValue && dateItemType.includes(component)) {
if (!Array.isArray(defaultValue)) {
schema.defaultValue = dateUtil(defaultValue);
} else {
@ -126,13 +133,15 @@ @@ -126,13 +133,15 @@
}
}
if (unref(getProps).showAdvancedButton) {
return schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[];
return cloneDeep(
schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[],
);
} else {
return schemas as FormSchema[];
return cloneDeep(schemas as FormSchema[]);
}
});
const { handleToggleAdvanced } = useAdvanced({
const { handleToggleAdvanced, fieldsIsAdvancedMap } = useAdvanced({
advanceState,
emit,
getProps,
@ -165,7 +174,7 @@ @@ -165,7 +174,7 @@
updateSchema,
resetSchema,
appendSchemaByField,
removeSchemaByFiled,
removeSchemaByField,
resetFields,
scrollToField,
} = useFormEvents({
@ -232,9 +241,12 @@ @@ -232,9 +241,12 @@
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
}
function setFormModel(key: string, value: any) {
function setFormModel(key: string, value: any, schema: FormSchema) {
formModel[key] = value;
const { validateTrigger } = unref(getBindValue);
if (isFunction(schema.dynamicRules) || isArray(schema.rules)) {
return;
}
if (!validateTrigger || validateTrigger === 'change') {
validateFields([key]).catch((_) => {});
}
@ -259,7 +271,7 @@ @@ -259,7 +271,7 @@
updateSchema,
resetSchema,
setProps,
removeSchemaByFiled,
removeSchemaByField,
appendSchemaByField,
clearValidate,
validateFields,
@ -290,6 +302,7 @@ @@ -290,6 +302,7 @@
getFormActionBindProps: computed(
(): Recordable => ({ ...getProps.value, ...advanceState }),
),
fieldsIsAdvancedMap,
...formActionType,
};
},

2
src/components/Form/src/componentMap.ts

@ -27,6 +27,7 @@ import ApiSelect from './components/ApiSelect.vue'; @@ -27,6 +27,7 @@ import ApiSelect from './components/ApiSelect.vue';
import ApiTree from './components/ApiTree.vue';
import ApiTreeSelect from './components/ApiTreeSelect.vue';
import ApiCascader from './components/ApiCascader.vue';
import ApiTransfer from './components/ApiTransfer.vue';
import { BasicUpload } from '/@/components/Upload';
import { StrengthMeter } from '/@/components/StrengthMeter';
import { IconPicker } from '/@/components/Icon';
@ -57,6 +58,7 @@ componentMap.set('ApiCascader', ApiCascader); @@ -57,6 +58,7 @@ componentMap.set('ApiCascader', ApiCascader);
componentMap.set('Cascader', Cascader);
componentMap.set('Slider', Slider);
componentMap.set('Rate', Rate);
componentMap.set('ApiTransfer', ApiTransfer);
componentMap.set('DatePicker', DatePicker);
componentMap.set('MonthPicker', DatePicker.MonthPicker);

9
src/components/Form/src/components/ApiCascader.vue

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
<template>
<a-cascader
v-model:value="state"
v-bind="$attrs"
:options="options"
:load-data="loadData"
change-on-select
@ -41,7 +40,6 @@ @@ -41,7 +40,6 @@
LoadingOutlined,
[Cascader.name]: Cascader,
},
inheritAttrs: false,
props: {
value: {
type: Array,
@ -97,10 +95,10 @@ @@ -97,10 +95,10 @@
if (next) {
const value = next[valueField];
const item = {
isLeaf: isLeaf && typeof isLeaf === 'function' ? isLeaf(next) : false,
...omit(next, [labelField, valueField]),
label: next[labelField],
value: numberToString ? `${value}` : value,
isLeaf: isLeaf && typeof isLeaf === 'function' ? isLeaf(next) : false,
};
const children = Reflect.get(next, childrenField);
if (children) {
@ -172,7 +170,7 @@ @@ -172,7 +170,7 @@
);
function handleChange(keys, args) {
emitData.value = keys;
emitData.value = args;
emit('defaultChange', keys, args);
}
@ -186,15 +184,14 @@ @@ -186,15 +184,14 @@
return '';
}
return {
state,
options,
loading,
t,
handleRenderDisplay,
handleChange,
loadData,
handleRenderDisplay,
};
},
});

29
src/components/Form/src/components/ApiRadioGroup.vue

@ -1,17 +1,20 @@ @@ -1,17 +1,20 @@
<!--
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
-->
<template>
<RadioGroup v-model:value="state"
v-bind="attrs"
button-style="solid"
@change="handleChange"
>
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
<template v-for="item in getOptions" :key="`${item.value}`">
<RadioButton v-if="props.isBtn" :value="item.value" :disabled="item.disabled">
<RadioButton
v-if="props.isBtn"
:value="item.value"
:disabled="item.disabled"
@click="handleClick(item)"
>
{{ item.label }}
</RadioButton>
<Radio v-else :value="item.value" :disabled="item.disabled">
<Radio
v-else
:value="item.value"
:disabled="item.disabled"
@click="handleClick(item)"
>
{{ item.label }}
</Radio>
</template>
@ -66,7 +69,7 @@ @@ -66,7 +69,7 @@
const attrs = useAttrs();
const { t } = useI18n();
// Embedded in the form, just use the hook binding to perform form verification
const [state] = useRuleFormItem(props);
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
// Processing options value
const getOptions = computed(() => {
@ -124,11 +127,11 @@ @@ -124,11 +127,11 @@
emit('options-change', unref(getOptions));
}
function handleChange(_, ...args) {
function handleClick(...args) {
emitData.value = args;
}
return { state, getOptions, attrs, loading, t, handleChange, props };
return { state, getOptions, attrs, loading, t, handleClick, props };
},
});
</script>

16
src/components/Form/src/components/ApiSelect.vue

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<template>
<Select
v-model:value="state"
v-bind="$attrs"
v-model:value="state"
:options="getOptions"
@dropdown-visible-change="handleFetch"
@change="handleChange"
@ -48,10 +48,7 @@ @@ -48,10 +48,7 @@
default: null,
},
// api params
params: {
type: Object as PropType<Recordable>,
default: () => ({}),
},
params: propTypes.any.def({}),
// support xxx.xxx.xx
resultField: propTypes.string.def(''),
labelField: propTypes.string.def('label'),
@ -59,7 +56,7 @@ @@ -59,7 +56,7 @@
immediate: propTypes.bool.def(true),
alwaysLoad: propTypes.bool.def(false),
},
emits: ['options-change', 'change'],
emits: ['options-change', 'change', 'update:value'],
setup(props, { emit }) {
const options = ref<OptionsItem[]>([]);
const loading = ref(false);
@ -91,6 +88,13 @@ @@ -91,6 +88,13 @@
props.immediate && !props.alwaysLoad && fetch();
});
watch(
() => state.value,
(v) => {
emit('update:value', v);
},
);
watch(
() => props.params,
() => {

138
src/components/Form/src/components/ApiTransfer.vue

@ -0,0 +1,138 @@ @@ -0,0 +1,138 @@
<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;
}
if (Array.isArray(props.targetKeys)){
return props.targetKeys;
}
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>

19
src/components/Form/src/components/FormItem.vue

@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
default: () => ({}),
},
setFormModel: {
type: Function as PropType<(key: string, value: any) => void>,
type: Function as PropType<(key: string, value: any, schema: FormSchema) => void>,
default: null,
},
tableAction: {
@ -44,6 +44,9 @@ @@ -44,6 +44,9 @@
formActionType: {
type: Object as PropType<FormActionType>,
},
isAdvanced: {
type: Boolean,
},
},
setup(props, { slots }) {
const { t } = useI18n();
@ -77,10 +80,14 @@ @@ -77,10 +80,14 @@
componentProps = componentProps({ schema, tableAction, formModel, formActionType }) ?? {};
}
if (schema.component === 'Divider') {
componentProps = Object.assign({ type: 'horizontal' }, componentProps, {
componentProps = Object.assign(
{ type: 'horizontal' },
{
orientation: 'left',
plain: true,
});
},
componentProps,
);
}
return componentProps as Recordable;
});
@ -103,8 +110,8 @@ @@ -103,8 +110,8 @@
const { show, ifShow } = props.schema;
const { showAdvancedButton } = props.formProps;
const itemIsAdvanced = showAdvancedButton
? isBoolean(props.schema.isAdvanced)
? props.schema.isAdvanced
? isBoolean(props.isAdvanced)
? props.isAdvanced
: true
: true;
@ -250,7 +257,7 @@ @@ -250,7 +257,7 @@
}
const target = e ? e.target : null;
const value = target ? (isCheck ? target.checked : target.value) : e;
props.setFormModel(field, value);
props.setFormModel(field, value, props.schema);
},
};
const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;

19
src/components/Form/src/components/RadioButtonGroup.vue

@ -1,17 +1,14 @@ @@ -1,17 +1,14 @@
<!--
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
-->
<template>
<RadioGroup v-model:value="state" v-bind="attrs" button-style="solid">
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
<template v-for="item in getOptions" :key="`${item.value}`">
<RadioButton :value="item.value" :disabled="item.disabled">
<RadioButton :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
{{ item.label }}
</RadioButton>
</template>
</RadioGroup>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from 'vue';
import { defineComponent, PropType, computed, ref } from 'vue';
import { Radio } from 'ant-design-vue';
import { isString } from '/@/utils/is';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
@ -35,10 +32,12 @@ @@ -35,10 +32,12 @@
default: () => [],
},
},
emits: ['change'],
setup(props) {
const attrs = useAttrs();
const emitData = ref<any[]>([]);
// Embedded in the form, just use the hook binding to perform form verification
const [state] = useRuleFormItem(props);
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
// Processing options value
const getOptions = computed((): OptionsItem[] => {
@ -51,7 +50,11 @@ @@ -51,7 +50,11 @@
return options.map((item) => ({ label: item, value: item })) as OptionsItem[];
});
return { state, getOptions, attrs };
function handleClick(...args) {
emitData.value = args;
}
return { state, getOptions, attrs, handleClick };
},
});
</script>

4
src/components/Form/src/helper.ts

@ -3,7 +3,7 @@ import type { ComponentType } from './types/index'; @@ -3,7 +3,7 @@ import type { ComponentType } from './types/index';
import { useI18n } from '/@/hooks/web/useI18n';
import { dateUtil } from '/@/utils/dateUtil';
import { isNumber, isObject } from '/@/utils/is';
import type { ConfigType } from 'dayjs';
const { t } = useI18n();
/**
@ -52,7 +52,7 @@ export function setComponentRuleType( @@ -52,7 +52,7 @@ export function setComponentRuleType(
export function processDateValue(attr: Recordable, component: string) {
const { valueFormat, value } = attr;
if (valueFormat) {
attr.value = isObject(value) ? dateUtil(value).format(valueFormat) : value;
attr.value = isObject(value) ? dateUtil(value as ConfigType).format(valueFormat) : value;
} else if (DATE_TYPE.includes(component) && value) {
attr.value = dateUtil(attr.value);
}

8
src/components/Form/src/hooks/useAdvanced.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import type { ColEx } from '../types';
import type { AdvanceState } from '../types/hooks';
import { ComputedRef, getCurrentInstance, Ref } from 'vue';
import { ComputedRef, getCurrentInstance, Ref, shallowReactive } from 'vue';
import type { FormProps, FormSchema } from '../types/form';
import { computed, unref, watch } from 'vue';
import { isBoolean, isFunction, isNumber, isObject } from '/@/utils/is';
@ -113,6 +113,8 @@ export default function ({ @@ -113,6 +113,8 @@ export default function ({
}
}
const fieldsIsAdvancedMap = shallowReactive({});
function updateAdvanced() {
let itemColSum = 0;
let realItemColSum = 0;
@ -148,7 +150,7 @@ export default function ({ @@ -148,7 +150,7 @@ export default function ({
if (isAdvanced) {
realItemColSum = itemColSum;
}
schema.isAdvanced = isAdvanced;
fieldsIsAdvancedMap[schema.field] = isAdvanced;
}
}
@ -166,5 +168,5 @@ export default function ({ @@ -166,5 +168,5 @@ export default function ({
advanceState.isAdvanced = !advanceState.isAdvanced;
}
return { handleToggleAdvanced };
return { handleToggleAdvanced, fieldsIsAdvancedMap };
}

10
src/components/Form/src/hooks/useForm.ts

@ -79,8 +79,8 @@ export function useForm(props?: Props): UseFormReturnType { @@ -79,8 +79,8 @@ export function useForm(props?: Props): UseFormReturnType {
});
},
removeSchemaByFiled: async (field: string | string[]) => {
unref(formRef)?.removeSchemaByFiled(field);
removeSchemaByField: async (field: string | string[]) => {
unref(formRef)?.removeSchemaByField(field);
},
// TODO promisify
@ -88,13 +88,13 @@ export function useForm(props?: Props): UseFormReturnType { @@ -88,13 +88,13 @@ export function useForm(props?: Props): UseFormReturnType {
return unref(formRef)?.getFieldsValue() as T;
},
setFieldsValue: async <T>(values: T) => {
setFieldsValue: async (values: Recordable) => {
const form = await getForm();
form.setFieldsValue<T>(values);
form.setFieldsValue(values);
},
appendSchemaByField: async (
schema: FormSchema,
schema: FormSchema | FormSchema[],
prefixField: string | undefined,
first: boolean,
) => {

74
src/components/Form/src/hooks/useFormEvents.ts

@ -2,7 +2,15 @@ import type { ComputedRef, Ref } from 'vue'; @@ -2,7 +2,15 @@ import type { ComputedRef, Ref } from 'vue';
import type { FormProps, FormSchema, FormActionType } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw, nextTick } from 'vue';
import { isArray, isFunction, isObject, isString, isDef, isNullOrUnDef } from '/@/utils/is';
import {
isArray,
isFunction,
isObject,
isString,
isDef,
isNullOrUnDef,
isEmpty,
} from '/@/utils/is';
import { deepMerge } from '/@/utils';
import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper';
import { dateUtil } from '/@/utils/dateUtil';
@ -58,7 +66,7 @@ export function useFormEvents({ @@ -58,7 +66,7 @@ export function useFormEvents({
// key 支持 a.b.c 的嵌套写法
const delimiter = '.';
const nestKeyArray = fields.filter((item) => item.indexOf(delimiter) >= 0);
const nestKeyArray = fields.filter((item) => String(item).indexOf(delimiter) >= 0);
const validKeys: string[] = [];
Object.keys(values).forEach((key) => {
@ -68,6 +76,11 @@ export function useFormEvents({ @@ -68,6 +76,11 @@ export function useFormEvents({
const hasKey = Reflect.has(values, key);
value = handleInputNumberValue(schema?.component, value);
const { componentProps } = schema || {};
let _props = componentProps as any;
if (typeof componentProps === 'function') {
_props = _props({ formModel: unref(formModel) });
}
// 0| '' is allow
if (hasKey && fields.includes(key)) {
// time type
@ -77,31 +90,29 @@ export function useFormEvents({ @@ -77,31 +90,29 @@ export function useFormEvents({
for (const ele of value) {
arr.push(ele ? dateUtil(ele) : null);
}
formModel[key] = arr;
unref(formModel)[key] = arr;
} else {
const { componentProps } = schema || {};
let _props = componentProps as any;
if (typeof componentProps === 'function') {
_props = _props({ formModel });
}
formModel[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
unref(formModel)[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
}
} else {
formModel[key] = value;
unref(formModel)[key] = value;
}
if (_props?.onChange) {
_props?.onChange(value);
}
validKeys.push(key);
} else {
nestKeyArray.forEach((nestKey: string) => {
try {
const value = eval('values' + delimiter + nestKey);
const value = nestKey.split('.').reduce((out, item) => out[item], values);
if (isDef(value)) {
formModel[nestKey] = value;
unref(formModel)[nestKey] = unref(value);
validKeys.push(nestKey);
}
} catch (e) {
// key not exist
if (isDef(defaultValueRef.value[nestKey])) {
formModel[nestKey] = cloneDeep(defaultValueRef.value[nestKey]);
unref(formModel)[nestKey] = cloneDeep(unref(defaultValueRef.value[nestKey]));
}
}
});
@ -112,7 +123,7 @@ export function useFormEvents({ @@ -112,7 +123,7 @@ export function useFormEvents({
/**
* @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));
if (!fields) {
return;
@ -123,7 +134,7 @@ export function useFormEvents({ @@ -123,7 +134,7 @@ export function useFormEvents({
fieldList = [fields];
}
for (const field of fieldList) {
_removeSchemaByFiled(field, schemaList);
_removeSchemaByFeild(field, schemaList);
}
schemaRef.value = schemaList;
}
@ -131,7 +142,7 @@ export function useFormEvents({ @@ -131,7 +142,7 @@ export function useFormEvents({
/**
* @description: Delete based on field name
*/
function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {
function _removeSchemaByFeild(field: string, schemaList: FormSchema[]): void {
if (isString(field)) {
const index = schemaList.findIndex((schema) => schema.field === field);
if (index !== -1) {
@ -144,19 +155,23 @@ export function useFormEvents({ @@ -144,19 +155,23 @@ export function useFormEvents({
/**
* @description: Insert after a certain field, if not insert the last
*/
async function appendSchemaByField(schema: FormSchema, prefixField?: string, first = false) {
async function appendSchemaByField(
schema: FormSchema | FormSchema[],
prefixField?: string,
first = false,
) {
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
const index = schemaList.findIndex((schema) => schema.field === prefixField);
const _schemaList = isObject(schema) ? [schema as FormSchema] : (schema as FormSchema[]);
if (!prefixField || index === -1 || first) {
first ? schemaList.unshift(schema) : schemaList.push(schema);
first ? schemaList.unshift(..._schemaList) : schemaList.push(..._schemaList);
schemaRef.value = schemaList;
_setDefaultValue(schema);
return;
}
if (index !== -1) {
schemaList.splice(index + 1, 0, schema);
schemaList.splice(index + 1, 0, ..._schemaList);
}
_setDefaultValue(schema);
@ -205,16 +220,20 @@ export function useFormEvents({ @@ -205,16 +220,20 @@ export function useFormEvents({
return;
}
const schema: FormSchema[] = [];
updateData.forEach((item) => {
unref(getSchema).forEach((val) => {
let _val;
updateData.forEach((item) => {
if (val.field === item.field) {
const newSchema = deepMerge(val, item);
_val = item;
}
});
if (_val !== undefined && val.field === _val.field) {
const newSchema = deepMerge(val, _val);
schema.push(newSchema as FormSchema);
} else {
schema.push(val);
}
});
});
_setDefaultValue(schema);
schemaRef.value = uniqBy(schema, 'field');
@ -237,7 +256,9 @@ export function useFormEvents({ @@ -237,7 +256,9 @@ export function useFormEvents({
Reflect.has(item, 'field') &&
item.field &&
!isNullOrUnDef(item.defaultValue) &&
!(item.field in currentFieldsValue)
(!(item.field in currentFieldsValue) ||
isNullOrUnDef(currentFieldsValue[item.field]) ||
isEmpty(currentFieldsValue[item.field]))
) {
obj[item.field] = item.defaultValue;
}
@ -293,6 +314,9 @@ export function useFormEvents({ @@ -293,6 +314,9 @@ export function useFormEvents({
const res = handleFormValues(values);
emit('submit', res);
} catch (error: any) {
if (error?.outOfDate === false && error?.errorFields) {
return;
}
throw new Error(error);
}
}
@ -306,7 +330,7 @@ export function useFormEvents({ @@ -306,7 +330,7 @@ export function useFormEvents({
updateSchema,
resetSchema,
appendSchemaByField,
removeSchemaByFiled,
removeSchemaByField,
resetFields,
setFieldsValue,
scrollToField,

18
src/components/Form/src/hooks/useFormValues.ts

@ -76,8 +76,13 @@ export function useFormValues({ @@ -76,8 +76,13 @@ export function useFormValues({
}
// Remove spaces
if (isString(value)) {
// remove params from URL
if(value === '') {
value = undefined;
}else {
value = value.trim();
}
}
if (!tryDeconstructArray(key, value, res) && !tryDeconstructObject(key, value, res)) {
// 没有解构成功的,按原样赋值
set(res, key, value);
@ -97,14 +102,21 @@ export function useFormValues({ @@ -97,14 +102,21 @@ export function useFormValues({
}
for (const [field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD'] of fieldMapToTime) {
if (!field || !startTimeKey || !endTimeKey || !values[field]) {
if (!field || !startTimeKey || !endTimeKey) {
continue;
}
// If the value to be converted is empty, remove the field
if (!values[field]) {
Reflect.deleteProperty(values, field);
continue;
}
const [startTime, endTime]: string[] = values[field];
values[startTimeKey] = dateUtil(startTime).format(format);
values[endTimeKey] = dateUtil(endTime).format(format);
const [startTimeFormat, endTimeFormat] = Array.isArray(format) ? format : [format, format];
values[startTimeKey] = dateUtil(startTime).format(startTimeFormat);
values[endTimeKey] = dateUtil(endTime).format(endTimeFormat);
Reflect.deleteProperty(values, field);
}

10
src/components/Form/src/props.ts

@ -5,11 +5,13 @@ import type { TableActionType } from '/@/components/Table'; @@ -5,11 +5,13 @@ import type { TableActionType } from '/@/components/Table';
import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
import type { RowProps } from 'ant-design-vue/lib/grid/Row';
import { propTypes } from '/@/utils/propTypes';
import componentSetting from '/@/settings/componentSetting';
const { form } = componentSetting;
export const basicProps = {
model: {
type: Object as PropType<Recordable>,
default: {},
default: () => ({}),
},
// 标签宽度 固定宽度
labelWidth: {
@ -23,7 +25,7 @@ export const basicProps = { @@ -23,7 +25,7 @@ export const basicProps = {
compact: propTypes.bool,
// 表单配置规则
schemas: {
type: [Array] as PropType<FormSchema[]>,
type: Array as PropType<FormSchema[]>,
default: () => [],
},
mergeDynamicData: {
@ -45,7 +47,7 @@ export const basicProps = { @@ -45,7 +47,7 @@ export const basicProps = {
// 禁用表单
disabled: propTypes.bool,
emptySpan: {
type: [Number, Object] as PropType<number>,
type: [Number, Object] as PropType<number | Recordable>,
default: 0,
},
// 是否显示收起展开按钮
@ -95,7 +97,7 @@ export const basicProps = { @@ -95,7 +97,7 @@ export const basicProps = {
wrapperCol: Object as PropType<Partial<ColEx>>,
colon: propTypes.bool,
colon: propTypes.bool.def(form.colon),
labelAlign: propTypes.string,

12
src/components/Form/src/types/form.ts

@ -7,7 +7,7 @@ import type { TableActionType } from '/@/components/Table/src/types/table'; @@ -7,7 +7,7 @@ import type { TableActionType } from '/@/components/Table/src/types/table';
import type { CSSProperties } from 'vue';
import type { RowProps } from 'ant-design-vue/lib/grid/Row';
export type FieldMapToTime = [string, [string, string], string?][];
export type FieldMapToTime = [string, [string, string], (string | [string, string])?][];
export type Rule = RuleObject & {
trigger?: 'blur' | 'change' | ['change', 'blur'];
@ -26,16 +26,16 @@ export interface ButtonProps extends AntdButtonProps { @@ -26,16 +26,16 @@ export interface ButtonProps extends AntdButtonProps {
export interface FormActionType {
submit: () => Promise<void>;
setFieldsValue: <T>(values: T) => Promise<void>;
setFieldsValue: (values: Recordable) => Promise<void>;
resetFields: () => Promise<void>;
getFieldsValue: () => Recordable;
clearValidate: (name?: string | string[]) => Promise<void>;
updateSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
resetSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
setProps: (formProps: Partial<FormProps>) => Promise<void>;
removeSchemaByFiled: (field: string | string[]) => Promise<void>;
removeSchemaByField: (field: string | string[]) => Promise<void>;
appendSchemaByField: (
schema: FormSchema,
schema: FormSchema | FormSchema[],
prefixField: string | undefined,
first?: boolean | undefined,
) => Promise<void>;
@ -175,6 +175,10 @@ export interface FormSchema { @@ -175,6 +175,10 @@ export interface FormSchema {
// 默认值
defaultValue?: any;
// 是否自动处理与时间相关组件的默认值
isHandleDateDefaultValue?: boolean;
isAdvanced?: boolean;
// Matching details components

3
src/components/Form/src/types/index.ts

@ -113,4 +113,5 @@ export type ComponentType = @@ -113,4 +113,5 @@ export type ComponentType =
| 'Render'
| 'Slider'
| 'Rate'
| 'Divider';
| 'Divider'
| 'ApiTransfer';

2
src/components/Icon/src/Icon.vue

@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
CSSProperties,
} from 'vue';
import SvgIcon from './SvgIcon.vue';
import Iconify from '@iconify/iconify';
import Iconify from '@purge-icons/generated';
import { isString } from '/@/utils/is';
import { propTypes } from '/@/utils/propTypes';

80
src/components/Icon/src/IconPicker.vue

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
:class="prefixCls"
>
<template #addonAfter>
<Popover
<a-popover
v-model="visible"
placement="bottomLeft"
trigger="click"
@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
<a-input
:placeholder="t('component.icon.search')"
allowClear
@change="handleSearchChange"
@change="debounceHandleSearchChange"
/>
</div>
</template>
@ -31,18 +31,7 @@ @@ -31,18 +31,7 @@
v-for="icon in getPaginationList"
:key="icon"
:class="currentSelect === icon ? 'border border-primary' : ''"
class="
p-2
w-1/8
cursor-pointer
mr-1
mt-1
flex
justify-center
items-center
border border-solid
hover:border-primary
"
class="p-2 w-1/8 cursor-pointer mr-1 mt-1 flex justify-center items-center border border-solid hover:border-primary"
:title="icon"
@click="handleClick(icon)"
>
@ -53,7 +42,7 @@ @@ -53,7 +42,7 @@
</ul>
</ScrollContainer>
<div v-if="getTotal >= pageSize" class="flex py-2 items-center justify-center">
<Pagination
<a-pagination
showLessItems
size="small"
:pageSize="pageSize"
@ -62,7 +51,7 @@ @@ -62,7 +51,7 @@
/>
</div>
</div>
<template v-else><div class="p-5"> <Empty/></div>
<template v-else><div class="p-5"><a-empty/></div>
</template>
</template>
@ -70,17 +59,18 @@ @@ -70,17 +59,18 @@
<SvgIcon :name="currentSelect"/>
</span>
<Icon v-else :icon="currentSelect || 'ion:apps-outline'" class="cursor-pointer px-2 py-1"/>
</Popover>
</a-popover>
</template>
</a-input>
</template>
<script lang="ts">
import { defineComponent, ref, watchEffect, watch, unref } from 'vue';
<script lang="ts" setup>
import { ref, watchEffect, watch, unref } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { ScrollContainer } from '/@/components/Container';
import { Input, Popover, Pagination, Empty } from 'ant-design-vue';
import Icon from './Icon.vue';
import SvgIcon from './SvgIcon.vue';
import iconsData from '../data/icons.data';
import { propTypes } from '/@/utils/propTypes';
import { usePagination } from '/@/hooks/web/usePagination';
@ -90,6 +80,12 @@ @@ -90,6 +80,12 @@
import { useMessage } from '/@/hooks/web/useMessage';
import svgIcons from 'virtual:svg-icons-names';
// 使WebStormunused
const AInput = Input;
const APopover = Popover;
const APagination = Pagination;
const AEmpty = Empty;
function getIcons() {
const data = iconsData as any;
const prefix: string = data?.prefix ?? '';
@ -106,19 +102,16 @@ @@ -106,19 +102,16 @@
return svgIcons.map((icon) => icon.replace('icon-', ''));
}
export default defineComponent({
name: 'IconPicker',
components: { [Input.name]: Input, Icon, Popover, ScrollContainer, Pagination, Empty, SvgIcon },
inheritAttrs: false,
props: {
const props = defineProps({
value: propTypes.string,
width: propTypes.string.def('100%'),
pageSize: propTypes.number.def(140),
copy: propTypes.bool.def(false),
mode: propTypes.oneOf<('svg' | 'iconify')[]>(['svg', 'iconify']).def('iconify'),
},
emits: ['change'],
setup(props, { emit }) {
});
const emit = defineEmits(['change', 'update:value']);
const isSvgMode = props.mode === 'svg';
const icons = isSvgMode ? getSvgIcons() : getIcons();
@ -130,12 +123,21 @@ @@ -130,12 +123,21 @@
const { prefixCls } = useDesign('icon-picker');
const debounceHandleSearchChange = useDebounceFn(handleSearchChange, 100);
const { clipboardRef, isSuccessRef } = useCopyToClipboard(props.value);
let clipboardRef;
let isSuccessRef;
if (props.copy) {
const clipboard = useCopyToClipboard(props.value);
clipboardRef = clipboard?.clipboardRef;
isSuccessRef = clipboard?.isSuccessRef;
}
const { createMessage } = useMessage();
const { getPaginationList, getTotal, setCurrentPage } = usePagination(
currentList,
props.pageSize
props.pageSize,
);
watchEffect(() => {
@ -144,7 +146,10 @@ @@ -144,7 +146,10 @@
watch(
() => currentSelect.value,
(v) => emit('change', v)
(v) => {
emit('update:value', v);
return emit('change', v);
},
);
function handlePageChange(page: number) {
@ -170,21 +175,6 @@ @@ -170,21 +175,6 @@
}
currentList.value = icons.filter((item) => item.includes(value));
}
return {
t,
prefixCls,
visible,
isSvgMode,
getTotal,
getPaginationList,
handlePageChange,
handleClick,
currentSelect,
handleSearchChange: debounceHandleSearchChange,
};
},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-icon-picker';

21
src/components/Loading/src/Loading.vue

@ -1,6 +1,12 @@ @@ -1,6 +1,12 @@
<template>
<section v-show="loading" class="full-loading" :class="{ absolute }">
<Spin v-bind="$attrs"
<section
v-show="loading"
class="full-loading"
:class="{ absolute, [theme]: !!theme }"
:style="[background ? `background-color: ${background}` : '']"
>
<Spin
v-bind="$attrs"
:tip="tip"
:size="size"
:spinning="loading"
@ -39,6 +45,9 @@ @@ -39,6 +45,9 @@
background: {
type: String as PropType<string>,
},
theme: {
type: String as PropType<'dark' | 'light'>,
},
},
});
</script>
@ -53,7 +62,7 @@ @@ -53,7 +62,7 @@
height: 100%;
justify-content: center;
align-items: center;
background-color: rgba(240, 242, 245, 0.4);
background-color: rgb(240 242 245 / 40%);
&.absolute {
position: absolute;
@ -64,8 +73,12 @@ @@ -64,8 +73,12 @@
}
html[data-theme='dark'] {
.full-loading {
.full-loading:not(.light) {
background-color: @modal-mask-bg;
}
}
.full-loading.dark {
background-color: @modal-mask-bg;
}
</style>

4
src/components/Loading/src/useLoading.ts

@ -4,7 +4,7 @@ import type { LoadingProps } from './typing'; @@ -4,7 +4,7 @@ import type { LoadingProps } from './typing';
import type { Ref } from 'vue';
export interface UseLoadingOptions {
target?: HTMLElement | Ref<ElRef>;
target?: any;
props?: Partial<LoadingProps>;
}
@ -16,7 +16,7 @@ export function useLoading(props: Partial<LoadingProps>): [Fn, Fn, (string) => v @@ -16,7 +16,7 @@ export function useLoading(props: Partial<LoadingProps>): [Fn, Fn, (string) => v
export function useLoading(opt: Partial<UseLoadingOptions>): [Fn, Fn, (string) => void];
export function useLoading(
opt: Partial<LoadingProps> | Partial<UseLoadingOptions>
opt: Partial<LoadingProps> | Partial<UseLoadingOptions>,
): [Fn, Fn, (string) => void] {
let props: Partial<LoadingProps>;
let target: HTMLElement | Ref<ElRef> = document.body;

2
src/components/Markdown/index.ts

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
import { withInstall } from '/@/utils';
import markDown from './src/Markdown.vue';
import markDownViewer from './src/MarkdownViewer.vue';
export const MarkDown = withInstall(markDown);
export const MarkdownViewer = withInstall(markDownViewer);
export * from './src/typing';

30
src/components/Markdown/src/Markdown.vue

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
<div ref="wrapRef"/>
</template>
<script lang="ts">
import type { Ref } from 'vue';
import {
defineComponent,
ref,
@ -18,6 +19,7 @@ @@ -18,6 +19,7 @@
import { useModalContext } from '../../Modal';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
import { getTheme } from './getTheme';
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
@ -30,14 +32,14 @@ @@ -30,14 +32,14 @@
emits: ['change', 'get', 'update:value'],
setup(props, { attrs, emit }) {
const wrapRef = ref<ElRef>(null);
const vditorRef = ref<Nullable<any>>(null);
const vditorRef = ref(null) as Ref<Nullable<Vditor>>;
const initedRef = ref(false);
const modalFn = useModalContext();
const { getLocale } = useLocale();
const { getDarkMode } = useRootSetting();
const valueRef = ref('');
const valueRef = ref(props.value || '');
watch(
[() => getDarkMode.value, () => initedRef.value],
@ -45,13 +47,14 @@ @@ -45,13 +47,14 @@
if (!inited) {
return;
}
const theme = val === 'dark' ? 'dark' : 'classic';
instance.getVditor()?.setTheme(theme);
instance
.getVditor()
?.setTheme(getTheme(val) as any, getTheme(val, 'content'), getTheme(val, 'code'));
},
{
immediate: true,
flush: 'post',
}
},
);
watch(
@ -61,7 +64,7 @@ @@ -61,7 +64,7 @@
instance.getVditor()?.setValue(v);
}
valueRef.value = v;
}
},
);
const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => {
@ -86,10 +89,22 @@ @@ -86,10 +89,22 @@
if (!wrapEl) return;
const bindValue = { ...attrs, ...props };
const insEditor = new Vditor(wrapEl, {
theme: getDarkMode.value === 'dark' ? 'dark' : 'classic',
//
theme: getTheme(getDarkMode.value) as any,
lang: unref(getCurrentLang),
mode: 'sv',
fullscreen: {
index: 520,
},
preview: {
theme: {
//
current: getTheme(getDarkMode.value, 'content'),
},
hljs: {
//
style: getTheme(getDarkMode.value, 'code'),
},
actions: [],
},
input: (v) => {
@ -117,7 +132,6 @@ @@ -117,7 +132,6 @@
}
const instance = {
// @ts-ignore
getVditor: (): Vditor => vditorRef.value!,
};

62
src/components/Markdown/src/MarkdownViewer.vue

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
<template>
<div id="markdownViewer" ref="viewerRef" :class="$props.class"/>
</template>
<script lang="ts" setup>
import { defineProps, onBeforeUnmount, onDeactivated, Ref, ref, unref, watch } from 'vue';
import VditorPreview from 'vditor/dist/method.min';
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { getTheme } from './getTheme';
const props = defineProps({
value: { type: String },
class: { type: String },
});
const viewerRef = ref<ElRef>(null);
const vditorPreviewRef = ref(null) as Ref<Nullable<VditorPreview>>;
const { getDarkMode } = useRootSetting();
function init() {
const viewerEl = unref(viewerRef) as HTMLElement;
vditorPreviewRef.value = VditorPreview.preview(viewerEl, props.value, {
mode: getTheme(getDarkMode.value, 'content'),
theme: {
//
current: getTheme(getDarkMode.value, 'content'),
},
hljs: {
//
style: getTheme(getDarkMode.value, 'code'),
},
});
}
watch(
() => getDarkMode.value,
(val) => {
VditorPreview.setContentTheme(getTheme(val, 'content'));
VditorPreview.setCodeTheme(getTheme(val, 'code'));
init();
},
);
watch(
() => props.value,
(v, oldValue) => {
v !== oldValue && init();
},
);
function destroy() {
const vditorInstance = unref(vditorPreviewRef);
if (!vditorInstance) return;
try {
vditorInstance?.destroy?.();
} catch (error) {}
vditorPreviewRef.value = null;
}
onMountedOrActivated(init);
onBeforeUnmount(destroy);
onDeactivated(destroy);
</script>

19
src/components/Markdown/src/getTheme.ts

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
/**
*
* @param darkModeVal
* @param themeMode (), ,
*/
export const getTheme = (
darkModeVal: 'light' | 'dark' | string,
themeMode: 'default' | 'content' | 'code' = 'default',
) => {
const isDark = darkModeVal === 'dark';
switch (themeMode) {
case 'default':
return isDark ? 'dark' : 'classic';
case 'content':
return isDark ? 'dark' : 'light';
case 'code':
return isDark ? 'dracula' : 'github';
}
};

5
src/components/Menu/src/BasicMenu.vue

@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
:class="getMenuClass"
:subMenuOpenDelay="0.2"
v-bind="getInlineCollapseOptions"
@openChange="handleOpenChange"
@open-change="handleOpenChange"
@click="handleMenuClick"
>
<template v-for="item in items" :key="item.path">
@ -30,9 +30,8 @@ @@ -30,9 +30,8 @@
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { REDIRECT_NAME } from '/@/router/constant';
import { useDesign } from '/@/hooks/web/useDesign';
import { getCurrentParentPath } from '/@/router/helper/menuHelper';
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
import { getAllParentPath } from '/@/router/helper/menuHelper';
import { getAllParentPath, getCurrentParentPath } from '/@/router/helper/menuHelper';
export default defineComponent({
name: 'BasicMenu',

11
src/components/Menu/src/components/BasicMenuItem.vue

@ -6,20 +6,15 @@ @@ -6,20 +6,15 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { Menu } from 'ant-design-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { itemProps } from '../props';
import MenuItemContent from './MenuItemContent.vue';
import MenuItemContent from './MenuItemContent.vue';
export default defineComponent({
name: 'BasicMenuItem',
components: { MenuItem: Menu.Item, MenuItemContent },
props: itemProps,
setup() // props
{
const { prefixCls } = useDesign('basic-menu-item');
return {
prefixCls,
};
setup() {
return {};
},
});
</script>

3
src/components/Menu/src/components/MenuItemContent.vue

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
<template>
<span :class="`${prefixCls}- flex items-center`">
<Icon v-if="getIcon"
<Icon
v-if="getIcon"
:icon="getIcon"
:size="18"
:class="`${prefixCls}-wrapper__icon mr-2`"

9
src/components/Menu/src/props.ts

@ -4,6 +4,8 @@ import type { PropType } from 'vue'; @@ -4,6 +4,8 @@ import type { PropType } from 'vue';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { ThemeEnum } from '/@/enums/appEnum';
import { propTypes } from '/@/utils/propTypes';
import type { MenuTheme } from 'ant-design-vue';
import type { MenuMode } from 'ant-design-vue/lib/menu/src/interface';
export const basicProps = {
items: {
type: Array as PropType<Menu[]>,
@ -22,7 +24,10 @@ export const basicProps = { @@ -22,7 +24,10 @@ export const basicProps = {
type: String as PropType<MenuTypeEnum>,
default: MenuTypeEnum.MIX,
},
theme: propTypes.string.def(ThemeEnum.DARK),
theme: {
type: String as PropType<MenuTheme>,
default: ThemeEnum.DARK,
},
inlineCollapsed: propTypes.bool,
mixSider: propTypes.bool,
@ -36,7 +41,7 @@ export const basicProps = { @@ -36,7 +41,7 @@ export const basicProps = {
export const itemProps = {
item: {
type: Object as PropType<Menu>,
default: {},
default: () => ({}),
},
level: propTypes.number,
theme: propTypes.oneOf(['dark', 'light']),

4
src/components/Menu/src/useOpenKeys.ts

@ -14,7 +14,7 @@ export function useOpenKeys( @@ -14,7 +14,7 @@ export function useOpenKeys(
menuState: MenuState,
menus: Ref<MenuType[]>,
mode: Ref<MenuModeEnum>,
accordion: Ref<boolean>
accordion: Ref<boolean>,
) {
const { getCollapsed, getIsMixSidebar } = useMenuSetting();
@ -37,7 +37,7 @@ export function useOpenKeys( @@ -37,7 +37,7 @@ export function useOpenKeys(
}
},
16,
!native
!native,
);
}

18
src/components/Modal/src/BasicModal.vue

@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
</ModalWrapper>
<template v-for="item in Object.keys(omit($slots, 'default'))" #[item]="data">
<slot :name="item" v-bind="data"/>
<slot :name="item" v-bind="data || {}"/>
</template>
</Modal>
</template>
@ -72,6 +72,7 @@ @@ -72,6 +72,7 @@
import { basicProps } from './props';
import { useFullScreen } from './hooks/useModalFullScreen';
import { omit } from 'lodash-es';
import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({
name: 'BasicModal',
@ -83,6 +84,7 @@ @@ -83,6 +84,7 @@
const visibleRef = ref(false);
const propsRef = ref<Partial<ModalProps> | null>(null);
const modalWrapperRef = ref<any>(null);
const { prefixCls } = useDesign('basic-modal');
// modal Bottom and top height
const extHeightRef = ref(0);
@ -104,7 +106,7 @@ @@ -104,7 +106,7 @@
}
// Custom title component: get title
const getMergeProps = computed((): ModalProps => {
const getMergeProps = computed((): Recordable => {
return {
...props,
...(unref(propsRef) as any),
@ -118,7 +120,7 @@ @@ -118,7 +120,7 @@
});
// modal component does not need title and origin buttons
const getProps = computed((): ModalProps => {
const getProps = computed((): Recordable => {
const opt = {
...unref(getMergeProps),
visible: unref(visibleRef),
@ -137,8 +139,9 @@ @@ -137,8 +139,9 @@
...attrs,
...unref(getMergeProps),
visible: unref(visibleRef),
wrapClassName: unref(getWrapClassName),
};
attr['wrapClassName'] = `${attr?.['wrapClassName'] || ''} ${unref(getWrapClassName)}`;
if (unref(fullScreenRef)) {
return omit(attr, ['height', 'title']);
}
@ -169,13 +172,14 @@ @@ -169,13 +172,14 @@
},
{
immediate: false,
}
},
);
//
async function handleCancel(e: Event) {
e?.stopPropagation();
//
if ((e.target as HTMLElement)?.classList?.contains(prefixCls + '-close--custom')) return;
if (props.closeFunc && isFunction(props.closeFunc)) {
const isClose: boolean = await props.closeFunc();
visibleRef.value = !isClose;
@ -212,7 +216,7 @@ @@ -212,7 +216,7 @@
extHeightRef.value = height;
}
function handleTitleDbClick(e: ChangeEvent) {
function handleTitleDbClick(e) {
if (!props.canFullscreen) return;
e.stopPropagation();
handleFullScreen(e);

9
src/components/Modal/src/components/Modal.tsx

@ -9,7 +9,8 @@ export default defineComponent({ @@ -9,7 +9,8 @@ export default defineComponent({
name: 'Modal',
inheritAttrs: false,
props: basicProps,
setup(props, { slots }) {
emits: ['cancel'],
setup(props, { slots, emit }) {
const { visible, draggable, destroyOnClose } = toRefs(props);
const attrs = useAttrs();
useModalDragMove({
@ -18,8 +19,12 @@ export default defineComponent({ @@ -18,8 +19,12 @@ export default defineComponent({
draggable,
});
const onCancel = (e: Event) => {
emit('cancel', e);
};
return () => {
const propsData = { ...unref(attrs), ...props } as Recordable;
const propsData = { ...unref(attrs), ...props, onCancel } as Recordable;
return <Modal {...propsData}>{extendSlots(slots)}</Modal>;
};
},

2
src/components/Modal/src/components/ModalClose.vue

@ -97,7 +97,7 @@ @@ -97,7 +97,7 @@
}
}
& span:nth-child(2) {
& span:last-child {
&:hover {
color: @error-color;
}

1
src/components/Modal/src/components/ModalFooter.vue

@ -19,7 +19,6 @@ @@ -19,7 +19,6 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { basicProps } from '../props';
export default defineComponent({
name: 'BasicModalFooter',

1
src/components/Modal/src/components/ModalHeader.vue

@ -17,5 +17,6 @@ @@ -17,5 +17,6 @@
},
title: { type: String },
},
emits: ['dblclick'],
});
</script>

11
src/components/Modal/src/components/ModalWrapper.vue

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
<template>
<ScrollContainer ref="wrapperRef">
<div ref="spinRef"
<div
ref="spinRef"
v-loading="loading"
:style="spinStyle"
:loading-tip="loadingTip"
@ -25,7 +26,7 @@ @@ -25,7 +26,7 @@
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
import { ScrollContainer } from '/@/components/Container';
import { createModalContext } from '../hooks/useModalContext';
import {MaybeElementRef, useMutationObserver} from '@vueuse/core';
import { useMutationObserver } from '@vueuse/core';
const props = {
loading: { type: Boolean },
@ -59,14 +60,14 @@ @@ -59,14 +60,14 @@
useWindowSizeFn(setModalHeight.bind(null, false));
useMutationObserver(
spinRef as MaybeElementRef,
spinRef,
() => {
setModalHeight();
},
{
attributes: true,
subtree: true,
}
},
);
createModalContext({
@ -93,7 +94,7 @@ @@ -93,7 +94,7 @@
} else {
minRealHeightRef.value = realHeightRef.value;
}
}
},
);
onMounted(() => {

5
src/components/Modal/src/index.less

@ -19,14 +19,13 @@ @@ -19,14 +19,13 @@
width: 520px;
padding-bottom: 0;
.scrollbar {
.ant-modal-body > .scrollbar {
padding: 14px;
}
&-title {
font-size: 16px;
font-weight: bold;
line-height: 16px;
.base-title {
cursor: move !important;
@ -54,7 +53,7 @@ @@ -54,7 +53,7 @@
}
&-content {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
box-shadow: 0 4px 8px 0 rgb(0 0 0 / 20%), 0 6px 20px 0 rgb(0 0 0 / 19%);
}
&-footer {

2
src/components/Page/index.ts

@ -5,3 +5,5 @@ import pageWrapper from './src/PageWrapper.vue'; @@ -5,3 +5,5 @@ import pageWrapper from './src/PageWrapper.vue';
export const PageFooter = withInstall(pageFooter);
export const PageWrapper = withInstall(pageWrapper);
export const PageWrapperFixedHeightKey = 'PageWrapperFixedHeight';

4
src/components/Page/src/PageFooter.vue

@ -39,8 +39,8 @@ @@ -39,8 +39,8 @@
line-height: 44px;
background-color: @component-background;
border-top: 1px solid @border-color-base;
box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05),
0 -12px 48px 16px rgba(0, 0, 0, 0.03);
box-shadow: 0 -6px 16px -8px rgb(0 0 0 / 8%), 0 -9px 28px 0 rgb(0 0 0 / 5%),
0 -12px 48px 16px rgb(0 0 0 / 3%);
transition: width 0.2s;
&__left {

25
src/components/Page/src/PageWrapper.vue

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<template>
<div ref="wrapperRef" :class="getClass">
<PageHeader
v-if="content || $slots.headerContent || title || getHeaderSlots.length"
v-if="getShowHeader"
v-bind="omit($attrs, 'class')"
ref="headerRef"
:ghost="ghost"
@ -18,7 +18,8 @@ @@ -18,7 +18,8 @@
</template>
</PageHeader>
<div ref="contentRef"
<div
ref="contentRef"
class="overflow-hidden"
:class="getContentClass"
:style="getContentStyle"
@ -37,7 +38,7 @@ @@ -37,7 +38,7 @@
</div>
</template>
<script lang="ts">
import type { CSSProperties, PropType } from 'vue';
import { CSSProperties, PropType, provide } from 'vue';
import { defineComponent, computed, watch, ref, unref } from 'vue';
import PageFooter from './PageFooter.vue';
import { useDesign } from '/@/hooks/web/useDesign';
@ -45,6 +46,7 @@ @@ -45,6 +46,7 @@
import { omit } from 'lodash-es';
import { PageHeader } from 'ant-design-vue';
import { useContentHeight } from '/@/hooks/web/useContentHeight';
import { PageWrapperFixedHeightKey } from '..';
export default defineComponent({
name: 'PageWrapper',
@ -62,6 +64,7 @@ @@ -62,6 +64,7 @@
contentFullHeight: propTypes.bool,
contentClass: propTypes.string,
fixedHeight: propTypes.bool,
upwardSpace: propTypes.oneOfType([propTypes.number, propTypes.string]).def(0),
},
setup(props, { slots, attrs }) {
const wrapperRef = ref(null);
@ -70,15 +73,22 @@ @@ -70,15 +73,22 @@
const footerRef = ref(null);
const { prefixCls } = useDesign('page-wrapper');
provide(
PageWrapperFixedHeightKey,
computed(() => props.fixedHeight),
);
const getIsContentFullHeight = computed(() => {
return props.contentFullHeight;
});
const getUpwardSpace = computed(() => props.upwardSpace);
const { redoHeight, setCompensation, contentHeight } = useContentHeight(
getIsContentFullHeight,
wrapperRef,
[headerRef, footerRef],
[contentRef]
[contentRef],
getUpwardSpace,
);
setCompensation({ useLayoutFooter: true, elements: [footerRef] });
@ -92,6 +102,10 @@ @@ -92,6 +102,10 @@
];
});
const getShowHeader = computed(
() => props.content || slots?.headerContent || props.title || getHeaderSlots.value.length,
);
const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
const getHeaderSlots = computed(() => {
@ -131,7 +145,7 @@ @@ -131,7 +145,7 @@
{
flush: 'post',
immediate: true,
}
},
);
return {
@ -143,6 +157,7 @@ @@ -143,6 +157,7 @@
getClass,
getHeaderSlots,
prefixCls,
getShowHeader,
getShowFooter,
omit,
getContentClass,

4
src/components/Qrcode/src/Qrcode.vue

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
<script lang="ts">
import { defineComponent, watch, PropType, ref, unref, onMounted } from 'vue';
import { toCanvas, QRCodeRenderersOptions, LogoType } from './qrcodePlus';
import { toDataURL } from 'qrcode';
import qrcode from 'qrcode';
import { downloadByUrl } from '/@/utils/file/download';
import { QrcodeDoneEventParams } from './typing';
@ -63,7 +63,7 @@ @@ -63,7 +63,7 @@
}
if (tag === 'img') {
const url = await toDataURL(renderValue, {
const url = await qrcode.toDataURL(renderValue, {
errorCorrectionLevel: 'H',
width,
...options,

11
src/components/Scrollbar/src/Scrollbar.vue

@ -152,7 +152,7 @@ @@ -152,7 +152,7 @@
display: none;
width: 0;
height: 0;
opacity: 0;
opacity: 0%;
}
}
}
@ -163,12 +163,12 @@ @@ -163,12 +163,12 @@
width: 0;
height: 0;
cursor: pointer;
background-color: rgba(144, 147, 153, 0.3);
background-color: rgb(144 147 153 / 30%);
border-radius: inherit;
transition: 0.3s background-color;
&:hover {
background-color: rgba(144, 147, 153, 0.5);
background-color: rgb(144 147 153 / 50%);
}
}
@ -178,8 +178,7 @@ @@ -178,8 +178,7 @@
bottom: 2px;
z-index: 1;
border-radius: 4px;
opacity: 0;
-webkit-transition: opacity 80ms ease;
opacity: 0%;
transition: opacity 80ms ease;
&.is-vertical {
@ -205,7 +204,7 @@ @@ -205,7 +204,7 @@
.scrollbar:active > .scrollbar__bar,
.scrollbar:focus > .scrollbar__bar,
.scrollbar:hover > .scrollbar__bar {
opacity: 1;
opacity: 100%;
transition: opacity 340ms ease-out;
}
</style>

4
src/components/Scrollbar/src/bar.ts

@ -43,7 +43,7 @@ export default defineComponent({ @@ -43,7 +43,7 @@ export default defineComponent({
const clickTrackHandler = (e: any) => {
const offset = Math.abs(
e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]
e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client],
);
const thumbHalf = thumb.value[bar.value.offset] / 2;
const thumbPositionPercentage =
@ -103,7 +103,7 @@ export default defineComponent({ @@ -103,7 +103,7 @@ export default defineComponent({
move: props.move,
bar: bar.value,
}),
})
}),
);
},
});

2
src/components/Scrollbar/src/util.ts

@ -34,7 +34,7 @@ export function renderThumbStyle({ move, size, bar }) { @@ -34,7 +34,7 @@ export function renderThumbStyle({ move, size, bar }) {
return style;
}
function extend<T, K>(to: T, _from: K): T & K {
function extend<T extends {}, K>(to: T, _from: K): T & K {
return Object.assign(to, _from);
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save