This commit is contained in:
vben 2021-11-03 00:50:44 +08:00
commit 07c2567751
78 changed files with 12329 additions and 12821 deletions

View File

@ -55,6 +55,8 @@ module.exports = defineConfig({
'space-before-function-paren': 'off',
'vue/attributes-order': 'off',
'vue/v-on-event-hyphenation': 'off',
'vue/multi-word-component-names': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',

View File

@ -6,5 +6,3 @@
# Format and submit code according to lintstagedrc.js configuration
npm run lint:lint-staged
npm run lint:pretty

13
.vscode/settings.json vendored
View File

@ -6,15 +6,8 @@
//===========================================
//============= Editor ======================
//===========================================
"explorer.openEditors.visible": 0,
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"diffEditor.ignoreTrimWhitespace": false,
//===========================================
//============= Other =======================
//===========================================
"breadcrumbs.enabled": true,
"open-in-browser.default": "chrome",
//===========================================
//============= files =======================
//===========================================
@ -69,15 +62,9 @@
},
"stylelint.enable": true,
"stylelint.packageManager": "yarn",
"liveServer.settings.donotShowInfoMsg": true,
"telemetry.enableCrashReporter": false,
"workbench.settings.enableNaturalLanguageSearch": false,
"path-intellisense.mappings": {
"/@/": "${workspaceRoot}/src"
},
"prettier.requireConfig": true,
"typescript.updateImportsOnFileMove.enabled": "always",
"workbench.sideBar.location": "left",
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},

View File

@ -1,3 +1,37 @@
## 2.8.0(2021-11.03)
### Upgrade Instructions
- Package manager changed from `yarn` to `pnpm`
- Delete `node_modules` and `yarn.lock`, install `pnpm` globally
- Execute `pnpm install`
### ✨ Features
- **Others**
- The `VITE_PROXY` configuration in the `.env` file supports single quotes
- Remove warnings during build
### 🐛 Bug Fixes
- **BasicTable**
- Fix the issue that editable cells cannot be submitted in some cases
- Fix the problem that the `inset` attribute does not work
- Fix the problem that the performance of `useTable` and `reload` method `await` of `BasicTable` instance are inconsistent
- Fix the issue that `clickToRowSelect` would ignore the disabled state of the row selection box
- Fix the problem that the page of `BasicTable` will be reset in some cases
- Modify the `deleteTableDataRecord` method
- **BasicModal**
- Fixed the problem that `Modal` could not be closed even when clicking on the mask and pressing the `Esc` key
- Fixed the issue that clicking the close button and the blank area next to the maximize button would also cause `Modal` to close
- **BasicTree** Fix the problem that the node slot does not work
- **CodeEditor** Fix the problem that may cause `Build` failure
- **BasicForm** Fix the problem that the content width of the custom FormItem component may be out of range
- **ApiTreeSelect** Fix the problem that the change of `params` failed to trigger the re-request of api data
- **Others** -Fixed an issue where multiple tabs would not jump to routing when closing tabs in some cases
- Fix the issue that some components may cause abnormal hot update
- Fix the problem that some sub-components of `antdv` will be reported in the build process when directly `import` part of the `antdv`, such as: TabPane, RadioGroup
## 2.7.2(2021-09-14)
### ✨ Features

View File

@ -1,4 +1,4 @@
## [2.7.2](https://github.com/anncwb/vue-vben-admin/compare/v2.7.1...v2.7.2) (2021-09-13)
## [2.8.0](https://github.com/anncwb/vue-vben-admin/compare/v2.7.2...v2.8.0) (2021-11-03)
### Bug Fixes

View File

@ -1,3 +1,11 @@
## 2.8.0(2021-11.03)
### 升级说明
- 包管理器由`yarn`改为 `pnpm`
- 删除`node_modules`和`yarn.lock`,全局安装`pnpm`
- 执行`pnpm install`
### ✨ Features
- **其它**

View File

@ -14,29 +14,15 @@ export function configStyleImportPlugin(isBuild: boolean) {
libraryName: 'ant-design-vue',
esModule: true,
resolveStyle: (name) => {
// 这里是“子组件”列表,无需额外引入样式文件
// 这里是无需额外引入样式文件的“子组件”列表
const ignoreList = [
'typography-text',
'typography-title',
'typography-paragraph',
'typography-link',
'anchor-link',
'sub-menu',
'menu-item',
'menu-item-group',
'dropdown-button',
'breadcrumb-item',
'breadcrumb-separator',
'input-password',
'input-search',
'input-group',
'form-item',
'radio-group',
'checkbox-group',
'layout-sider',
'layout-content',
'layout-footer',
'layout-header',
'step',
'select-option',
'select-opt-group',
@ -59,7 +45,31 @@ export function configStyleImportPlugin(isBuild: boolean) {
'skeleton-image',
'skeleton-button',
];
return ignoreList.includes(name) ? '' : `ant-design-vue/es/${name}/style/index`;
// 这里是需要额外引入样式的子组件列表
// 单独引入子组件时需引入组件样式,否则会在打包后导致子组件样式丢失
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',
};
return ignoreList.includes(name)
? ''
: replaceList.hasOwnProperty(name)
? `ant-design-vue/es/${replaceList[name]}/style/index`
: `ant-design-vue/es/${name}/style/index`;
},
},
],

View File

@ -7,6 +7,7 @@ module.exports = {
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',

View File

@ -1,28 +0,0 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultSuccess } from '../_util';
const demoList = (keyword, count = 20) => {
const result = {
list: [] as any[],
};
for (let index = 0; index < count; index++) {
result.list.push({
name: `${keyword ?? ''}选项${index}`,
id: `${index}`,
});
}
return result;
};
export default [
{
url: '/basic-api/select/getDemoOptions',
timeout: 1000,
method: 'get',
response: ({ query }) => {
const { keyword, count } = query;
console.log(keyword);
return resultSuccess(demoList(keyword, count));
},
},
] as MockMethod[];

View File

@ -1,202 +0,0 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultError, resultPageSuccess, resultSuccess } from '../_util';
const accountList = (() => {
const result: any[] = [];
for (let index = 0; index < 20; index++) {
result.push({
id: `${index}`,
account: '@first',
email: '@email',
nickname: '@cname()',
role: '@first',
createTime: '@datetime',
remark: '@cword(10,20)',
'status|1': ['0', '1'],
});
}
return result;
})();
const roleList = (() => {
const result: any[] = [];
for (let index = 0; index < 4; index++) {
result.push({
id: index + 1,
orderNo: `${index + 1}`,
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index],
roleValue: '@first',
createTime: '@datetime',
remark: '@cword(10,20)',
menu: [['0', '1', '2'], ['0', '1'], ['0', '2'], ['2']][index],
'status|1': ['0', '1'],
});
}
return result;
})();
const deptList = (() => {
const result: any[] = [];
for (let index = 0; index < 3; index++) {
result.push({
id: `${index}`,
deptName: ['华东分部', '华南分部', '西北分部'][index],
orderNo: index + 1,
createTime: '@datetime',
remark: '@cword(10,20)',
'status|1': ['0', '0', '1'],
children: (() => {
const children: any[] = [];
for (let j = 0; j < 4; j++) {
children.push({
id: `${index}-${j}`,
deptName: ['研发部', '市场部', '商务部', '财务部'][j],
orderNo: j + 1,
createTime: '@datetime',
remark: '@cword(10,20)',
'status|1': ['0', '1'],
parentDept: `${index}`,
children: undefined,
});
}
return children;
})(),
});
}
return result;
})();
const menuList = (() => {
const result: any[] = [];
for (let index = 0; index < 3; index++) {
result.push({
id: `${index}`,
icon: ['ion:layers-outline', 'ion:git-compare-outline', 'ion:tv-outline'][index],
component: 'LAYOUT',
type: '0',
menuName: ['Dashboard', '权限管理', '功能'][index],
permission: '',
orderNo: index + 1,
createTime: '@datetime',
'status|1': ['0', '0', '1'],
children: (() => {
const children: any[] = [];
for (let j = 0; j < 4; j++) {
children.push({
id: `${index}-${j}`,
type: '1',
menuName: ['菜单1', '菜单2', '菜单3', '菜单4'][j],
icon: 'ion:document',
permission: ['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index],
component: [
'/dashboard/welcome/index',
'/dashboard/analysis/index',
'/dashboard/workbench/index',
'/dashboard/test/index',
][j],
orderNo: j + 1,
createTime: '@datetime',
'status|1': ['0', '1'],
parentMenu: `${index}`,
children: (() => {
const children: any[] = [];
for (let k = 0; k < 4; k++) {
children.push({
id: `${index}-${j}-${k}`,
type: '2',
menuName: '按钮' + (j + 1) + '-' + (k + 1),
icon: '',
permission:
['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index] +
':btn' +
(k + 1),
component: [
'/dashboard/welcome/index',
'/dashboard/analysis/index',
'/dashboard/workbench/index',
'/dashboard/test/index',
][j],
orderNo: j + 1,
createTime: '@datetime',
'status|1': ['0', '1'],
parentMenu: `${index}-${j}`,
children: undefined,
});
}
return children;
})(),
});
}
return children;
})(),
});
}
return result;
})();
export default [
{
url: '/basic-api/system/getAccountList',
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, accountList);
},
},
{
url: '/basic-api/system/getRoleListByPage',
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, roleList);
},
},
{
url: '/basic-api/system/setRoleStatus',
timeout: 500,
method: 'post',
response: ({ query }) => {
const { id, status } = query;
return resultSuccess({ id, status });
},
},
{
url: '/basic-api/system/getAllRoleList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(roleList);
},
},
{
url: '/basic-api/system/getDeptList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(deptList);
},
},
{
url: '/basic-api/system/getMenuList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(menuList);
},
},
{
url: '/basic-api/system/accountExist',
timeout: 500,
method: 'post',
response: ({ body }) => {
const { account } = body || {};
if (account && account.indexOf('admin') !== -1) {
return resultError('该字段不能包含admin');
} else {
return resultSuccess(`${account} can use`);
}
},
},
] as MockMethod[];

View File

@ -1,52 +0,0 @@
import { MockMethod } from 'vite-plugin-mock';
import { Random } from 'mockjs';
import { resultPageSuccess } from '../_util';
function getRandomPics(count = 10): string[] {
const arr: string[] = [];
for (let i = 0; i < count; i++) {
arr.push(Random.image('800x600', Random.color(), Random.color(), Random.title()));
}
return arr;
}
const demoList = (() => {
const result: any[] = [];
for (let index = 0; index < 200; index++) {
result.push({
id: `${index}`,
beginTime: '@datetime',
endTime: '@datetime',
address: '@city()',
name: '@cname()',
name1: '@cname()',
name2: '@cname()',
name3: '@cname()',
name4: '@cname()',
name5: '@cname()',
name6: '@cname()',
name7: '@cname()',
name8: '@cname()',
avatar: Random.image('400x400', Random.color(), Random.color(), Random.first()),
imgArr: getRandomPics(Math.ceil(Math.random() * 3) + 1),
imgs: getRandomPics(Math.ceil(Math.random() * 3) + 1),
date: `@date('yyyy-MM-dd')`,
time: `@time('HH:mm')`,
'no|100000-10000000': 100000,
'status|1': ['normal', 'enable', 'disable'],
});
}
return result;
})();
export default [
{
url: '/basic-api/table/getDemoList',
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, demoList);
},
},
] as MockMethod[];

View File

@ -1,38 +0,0 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultSuccess } from '../_util';
const demoTreeList = (keyword) => {
const result = {
list: [] as Recordable[],
};
for (let index = 0; index < 5; index++) {
const children: Recordable[] = [];
for (let j = 0; j < 3; j++) {
children.push({
title: `${keyword ?? ''}选项${index}-${j}`,
value: `${index}-${j}`,
key: `${index}-${j}`,
});
}
result.list.push({
title: `${keyword ?? ''}选项${index}`,
value: `${index}`,
key: `${index}`,
children,
});
}
return result;
};
export default [
{
url: '/basic-api/tree/getDemoOptions',
timeout: 1000,
method: 'get',
response: ({ query }) => {
const { keyword } = query;
console.log(keyword);
return resultSuccess(demoTreeList(keyword));
},
},
] as MockMethod[];

View File

@ -1,6 +1,6 @@
{
"name": "vben-admin",
"version": "2.7.2",
"version": "2.8.0",
"author": {
"name": "vben",
"email": "anncwb@126.com",
@ -24,42 +24,44 @@
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
"lint:pretty": "pretty-quick --staged",
"test:unit": "jest",
"test:unit-coverage": "jest --coverage",
"test:gzip": "http-server dist --cors --gzip -c-1",
"test:br": "http-server dist --cors --brotli -c-1",
"test:gzip": "npx http-server dist --cors --gzip -c-1",
"test:br": "npx http-server dist --cors --brotli -c-1",
"reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run bootstrap",
"prepare": "husky install",
"gen:icon": "esno ./build/generate/icon/index.ts"
},
"dependencies": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.0.1",
"@iconify/iconify": "^2.0.4",
"@vueuse/core": "^6.6.2",
"@vueuse/core": "^6.7.4",
"@vueuse/shared": "^6.7.4",
"@zxcvbn-ts/core": "^1.0.0-beta.0",
"ant-design-vue": "2.2.8",
"axios": "^0.23.0",
"axios": "^0.24.0",
"crypto-js": "^4.1.1",
"echarts": "^5.2.1",
"echarts": "^5.2.2",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"moment": "^2.29.1",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0",
"pinia": "2.0.0-rc.14",
"print-js": "^1.6.0",
"pinia": "2.0.0",
"qrcode": "^1.4.4",
"qs": "^6.10.1",
"resize-observer-polyfill": "^1.5.1",
"sortablejs": "^1.14.0",
"vue": "^3.2.20",
"vue": "^3.2.21",
"vue-i18n": "^9.1.9",
"vue-json-pretty": "^2.0.4",
"vue-router": "^4.0.12",
"vue-types": "^4.1.1"
},
"devDependencies": {
"@commitlint/cli": "^13.2.1",
"@commitlint/config-conventional": "^13.2.0",
"@iconify/json": "^1.1.416",
"@commitlint/cli": "^14.1.0",
"@commitlint/config-conventional": "^14.1.0",
"@iconify/json": "^1.1.422",
"@purge-icons/generated": "^0.7.0",
"@types/codemirror": "^5.60.5",
"@types/crypto-js": "^4.0.2",
@ -69,66 +71,66 @@
"@types/jest": "^27.0.2",
"@types/lodash-es": "^4.17.5",
"@types/mockjs": "^1.0.4",
"@types/node": "^16.11.1",
"@types/node": "^16.11.6",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.4.1",
"@types/qs": "^6.9.7",
"@types/showdown": "^1.9.4",
"@types/sortablejs": "^1.10.7",
"@typescript-eslint/eslint-plugin": "^5.1.0",
"@typescript-eslint/parser": "^5.1.0",
"@typescript-eslint/eslint-plugin": "^5.3.0",
"@typescript-eslint/parser": "^5.3.0",
"@vitejs/plugin-legacy": "^1.6.2",
"@vitejs/plugin-vue": "^1.9.3",
"@vitejs/plugin-vue": "^1.9.4",
"@vitejs/plugin-vue-jsx": "^1.2.0",
"@vue/compiler-sfc": "3.2.20",
"@vue/compiler-sfc": "3.2.21",
"@vue/test-utils": "^2.0.0-rc.16",
"autoprefixer": "^10.3.7",
"autoprefixer": "^10.4.0",
"commitizen": "^4.2.4",
"conventional-changelog-cli": "^2.1.1",
"cross-env": "^7.0.3",
"dotenv": "^10.0.0",
"eslint": "^8.0.1",
"eslint": "^8.1.0",
"eslint-config-prettier": "^8.3.0",
"eslint-define-config": "^1.1.1",
"eslint-define-config": "^1.1.2",
"eslint-plugin-jest": "^25.2.2",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^7.19.1",
"eslint-plugin-vue": "^8.0.3",
"esno": "^0.10.1",
"fs-extra": "^10.0.0",
"http-server": "^14.0.0",
"husky": "^7.0.2",
"husky": "^7.0.4",
"inquirer": "^8.2.0",
"is-ci": "^3.0.0",
"jest": "^27.3.1",
"less": "^4.1.2",
"lint-staged": "^11.2.3",
"lint-staged": "11.2.6",
"npm-run-all": "^4.1.5",
"postcss": "^8.3.9",
"postcss": "^8.3.11",
"postcss-html": "^1.2.0",
"postcss-less": "^5.0.0",
"prettier": "^2.4.1",
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"rollup-plugin-visualizer": "^5.5.2",
"stylelint": "^13.13.1",
"stylelint": "^14.0.1",
"stylelint-config-html": "^1.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^22.0.0",
"stylelint-order": "^4.1.0",
"stylelint-config-standard": "^23.0.0",
"stylelint-order": "^5.0.0",
"ts-jest": "^27.0.7",
"ts-node": "^10.3.0",
"ts-node": "^10.4.0",
"typescript": "^4.4.4",
"vite": "^2.6.10",
"vite": "^2.6.13",
"vite-plugin-compression": "^0.3.5",
"vite-plugin-html": "^2.1.1",
"vite-plugin-imagemin": "^0.4.6",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-purge-icons": "^0.7.0",
"vite-plugin-pwa": "^0.11.3",
"vite-plugin-style-import": "^1.2.1",
"vite-plugin-style-import": "^1.3.0",
"vite-plugin-svg-icons": "^1.0.5",
"vite-plugin-theme": "^0.8.1",
"vite-plugin-vue-setup-extend": "^0.1.0",
"vite-plugin-windicss": "^1.4.12",
"vue-eslint-parser": "^8.0.0",
"vue-tsc": "^0.28.7"
"vue-eslint-parser": "^8.0.1",
"vue-tsc": "^0.28.10"
},
"resolutions": {
"//": "Used to install imagemin dependencies, because imagemin may not be installed in China. If it is abroad, you can delete it",

11731
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,9 @@
module.exports = {
printWidth: 100,
tabWidth: 2,
useTabs: false,
semi: true,
vueIndentScriptAndStyle: true,
singleQuote: true,
quoteProps: 'as-needed',
bracketSpacing: true,
trailingComma: 'all',
jsxSingleQuote: false,
arrowParens: 'always',
insertPragma: false,
requirePragma: false,
proseWrap: 'never',
htmlWhitespaceSensitivity: 'strict',
endOfLine: 'auto',

12
src/api/demo/error.ts Normal file
View File

@ -0,0 +1,12 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
// The address does not exist
Error = '/error',
}
/**
* @description: Trigger ajax error
*/
export const fireErrorApi = () => defHttp.get({ url: Api.Error });

View File

@ -1,11 +0,0 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
TREE_OPTIONS_LIST = '/tree/getDemoOptions',
}
/**
* @description: Get sample options value
*/
export const treeOptionsListApi = (params?: Recordable) =>
defHttp.get<Recordable[]>({ url: Api.TREE_OPTIONS_LIST, params });

View File

@ -3,7 +3,7 @@ export interface BasicPageParams {
pageSize: number;
}
export interface BasicFetchResult<T extends any> {
export interface BasicFetchResult<T> {
items: T[];
total: number;
}

View File

@ -39,7 +39,7 @@
html[data-theme='dark'] {
.@{prefix-cls} {
border: 1px solid rgb(196, 188, 188);
border: 1px solid rgb(196 188 188);
}
}

View File

@ -42,7 +42,7 @@
background-color: linear-gradient(-225deg, #d5dbe4, #f8f8f8);
border-radius: 2px;
box-shadow: inset 0 -2px 0 0 #cdcde6, inset 0 0 1px 1px #fff,
0 1px 2px 1px rgba(30, 35, 90, 0.4);
0 1px 2px 1px rgb(30 35 90 / 40%);
align-items: center;
justify-content: center;

View File

@ -125,7 +125,7 @@
width: 100%;
height: 100%;
padding-top: 50px;
background-color: rgba(0, 0, 0, 0.25);
background-color: rgb(0 0 0 / 25%);
justify-content: center;
&--mobile {
@ -159,7 +159,7 @@
&__item {
&-enter {
opacity: 0 !important;
opacity: 0% !important;
}
}
}
@ -168,16 +168,16 @@
&-content {
position: relative;
width: 632px;
margin: 0 auto auto auto;
margin: 0 auto auto;
background-color: @component-background;
border-radius: 16px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
box-shadow: 0 25px 50px -12px rgb(0 0 0 / 25%);
flex-direction: column;
}
&-input__wrapper {
display: flex;
padding: 14px 14px 0 14px;
padding: 14px 14px 0;
justify-content: space-between;
align-items: center;
}
@ -245,7 +245,7 @@
background-color: @primary-color;
.@{prefix-cls}-list__item-enter {
opacity: 1;
opacity: 100%;
}
}
@ -259,7 +259,7 @@
&-enter {
width: 30px;
opacity: 0;
opacity: 0%;
}
}
}

View File

@ -1,81 +1,3 @@
<template>
<div class="p-2">
<div class="bg-white mb-2 p-4">
<BasicForm @register="registerForm" />
</div>
{{ sliderProp.width }}
<div class="bg-white p-2">
<List
:grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }"
:data-source="data"
:pagination="paginationProp"
>
<template #header>
<div class="flex justify-end space-x-2"
><slot name="header"></slot>
<Tooltip>
<template #title>
<div class="w-50">每行显示数量</div
><Slider
id="slider"
v-bind="sliderProp"
v-model:value="grid"
@change="sliderChange"
/></template>
<Button><TableOutlined /></Button>
</Tooltip>
<Tooltip @click="fetch">
<template #title>刷新</template>
<Button><RedoOutlined /></Button>
</Tooltip>
</div>
</template>
<template #renderItem="{ item }">
<ListItem>
<Card>
<template #title></template>
<template #cover>
<div :class="height">
<Image :src="item.imgs[0]" />
</div>
</template>
<template class="ant-card-actions" #actions>
<!-- <SettingOutlined key="setting" />-->
<EditOutlined key="edit" />
<Dropdown
:trigger="['hover']"
:dropMenuList="[
{
text: '删除',
event: '1',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, item.id),
},
},
]"
popconfirm
>
<EllipsisOutlined key="ellipsis" />
</Dropdown>
</template>
<CardMeta>
<template #title>
<TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" />
</template>
<template #avatar>
<Avatar :src="item.avatar" />
</template>
<template #description>{{ item.time }}</template>
</CardMeta>
</Card>
</ListItem>
</template>
</List>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue';
import {
@ -87,7 +9,6 @@
import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue';
import { Dropdown } from '/@/components/Dropdown';
import { BasicForm, useForm } from '/@/components/Form';
import { propTypes } from '/@/utils/propTypes';
import { Button } from '/@/components/Button';
import { isFunction } from '/@/utils/is';
import { useSlider, grid } from './data';
@ -99,9 +20,15 @@
//
const props = defineProps({
// API
params: propTypes.object.def({}),
params: {
type: Object,
default: () => ({}),
},
//api
api: propTypes.func,
api: {
type: Function,
default: null,
},
});
//
const emit = defineEmits(['getMethod', 'delete']);
@ -167,7 +94,7 @@
pageSize.value = pz;
fetch();
}
function pageSizeChange(current, size) {
function pageSizeChange(_current, size) {
pageSize.value = size;
fetch();
}
@ -176,3 +103,81 @@
emit('delete', id);
}
</script>
<template>
<div class="p-2">
<div class="p-4 mb-2 bg-white">
<BasicForm @register="registerForm" />
</div>
{{ sliderProp.width }}
<div class="p-2 bg-white">
<List
:grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }"
:data-source="data"
:pagination="paginationProp"
>
<template #header>
<div class="flex justify-end space-x-2"
><slot name="header"></slot>
<Tooltip>
<template #title>
<div class="w-50">每行显示数量</div
><Slider
id="slider"
v-bind="sliderProp"
v-model:value="grid"
@change="sliderChange"
/></template>
<Button><TableOutlined /></Button>
</Tooltip>
<Tooltip @click="fetch">
<template #title>刷新</template>
<Button><RedoOutlined /></Button>
</Tooltip>
</div>
</template>
<template #renderItem="{ item }">
<ListItem>
<Card>
<template #title></template>
<template #cover>
<div :class="height">
<Image :src="item.imgs[0]" />
</div>
</template>
<template #actions>
<EditOutlined key="edit" />
<Dropdown
:trigger="['hover']"
:dropMenuList="[
{
text: '删除',
event: '1',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, item.id),
},
},
]"
popconfirm
>
<EllipsisOutlined key="ellipsis" />
</Dropdown>
</template>
<CardMeta>
<template #title>
<TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" />
</template>
<template #avatar>
<Avatar :src="item.avatar" />
</template>
<template #description>{{ item.time }}</template>
</CardMeta>
</Card>
</ListItem>
</template>
</List>
</div>
</div>
</template>

View File

@ -2,7 +2,7 @@
.CodeMirror {
--base: #545281;
--comment: hsl(210, 25%, 60%);
--comment: hsl(210deg 25% 60%);
--keyword: #af4ab1;
--variable: #0055d1;
--function: #c25205;
@ -53,7 +53,7 @@
color: var(--comment);
text-align: right;
white-space: nowrap;
opacity: 0.6;
opacity: 60%;
}
.CodeMirror-guttermarker {
@ -90,7 +90,7 @@
display: inline-block;
font-size: 0.8em;
content: '>';
opacity: 0.8;
opacity: 80%;
transform: rotate(90deg);
transition: transform 0.2s;
}
@ -125,9 +125,7 @@
}
.cm-fat-cursor-mark {
background-color: rgba(20, 255, 20, 0.5);
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
background-color: rgb(20 255 20 / 50%);
animation: blink 1.06s steps(1) infinite;
}
@ -135,16 +133,14 @@
width: auto;
background-color: #7e7;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
}
@-moz-keyframes blink {
@keyframes blink {
50% {
background-color: transparent;
}
}
@-webkit-keyframes blink {
@keyframes blink {
50% {
background-color: transparent;
}
@ -294,7 +290,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {
}
.CodeMirror-matchingtag {
background: rgba(255, 150, 0, 0.3);
background: rgb(255 150 0 / 30%);
}
.CodeMirror-activeline-background {
@ -394,7 +390,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {
background-color: transparent;
}
.CodeMirror-gutter-wrapper ::-moz-selection {
.CodeMirrorwrapper ::selection {
background-color: transparent;
}
@ -414,11 +410,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {
border-width: 0;
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
-webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
}
@ -457,7 +450,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {
.CodeMirror-gutter,
.CodeMirror-gutters,
.CodeMirror-linenumber {
-moz-box-sizing: content-box;
box-sizing: content-box;
}
@ -505,15 +497,9 @@ div.CodeMirror-dragcursors {
background: #d7d4f0;
}
.CodeMirror-line::-moz-selection,
.CodeMirror-line > span::-moz-selection,
.CodeMirror-line > span > span::-moz-selection {
background: #d7d4f0;
}
.cm-searching {
background-color: #ffa;
background-color: rgba(255, 255, 0, 0.4);
background-color: rgb(255 255 0 / 40%);
}
/* Used to force a border model for a node */

View File

@ -178,22 +178,22 @@
margin: 0;
list-style: none;
background-color: @component-background;
border: 1px solid rgba(0, 0, 0, 0.08);
border: 1px solid rgb(0 0 0 / 8%);
border-radius: 0.25rem;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1),
0 1px 5px 0 rgba(0, 0, 0, 0.06);
box-shadow: 0 2px 2px 0 rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 10%),
0 1px 5px 0 rgb(0 0 0 / 6%);
background-clip: padding-box;
user-select: none;
.item-style();
.ant-divider {
margin: 0 0;
margin: 0;
}
&__popup {
.ant-divider {
margin: 0 0;
margin: 0;
}
.item-style();

View File

@ -234,17 +234,17 @@
background: #eee;
background-image: linear-gradient(
45deg,
rgba(0, 0, 0, 0.25) 25%,
rgb(0 0 0 / 25%) 25%,
transparent 0,
transparent 75%,
rgba(0, 0, 0, 0.25) 0
rgb(0 0 0 / 25%) 0
),
linear-gradient(
45deg,
rgba(0, 0, 0, 0.25) 25%,
rgb(0 0 0 / 25%) 25%,
transparent 0,
transparent 75%,
rgba(0, 0, 0, 0.25) 0
rgb(0 0 0 / 25%) 0
);
background-position: 0 0, 12px 12px;
background-size: 24px 24px;

View File

@ -135,15 +135,14 @@
}
&-image-mask {
opacity: 0;
opacity: 0%;
position: absolute;
width: inherit;
height: inherit;
border-radius: inherit;
border: inherit;
background: rgba(0, 0, 0, 0.4);
background: rgb(0 0 0 / 40%);
cursor: pointer;
-webkit-transition: opacity 0.4s;
transition: opacity 0.4s;
::v-deep(svg) {
@ -152,7 +151,7 @@
}
&-image-mask:hover {
opacity: 40;
opacity: 4000%;
}
&-upload-btn {

View File

@ -10,5 +10,6 @@ export { default as ApiSelect } from './src/components/ApiSelect.vue';
export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue';
export { default as ApiCascader } from './src/components/ApiCascader.vue';
export { BasicForm };

View File

@ -25,6 +25,7 @@ import ApiRadioGroup from './components/ApiRadioGroup.vue';
import RadioButtonGroup from './components/RadioButtonGroup.vue';
import ApiSelect from './components/ApiSelect.vue';
import ApiTreeSelect from './components/ApiTreeSelect.vue';
import ApiCascader from './components/ApiCascader.vue';
import { BasicUpload } from '/@/components/Upload';
import { StrengthMeter } from '/@/components/StrengthMeter';
import { IconPicker } from '/@/components/Icon';
@ -50,6 +51,7 @@ componentMap.set('RadioButtonGroup', RadioButtonGroup);
componentMap.set('RadioGroup', Radio.Group);
componentMap.set('Checkbox', Checkbox);
componentMap.set('CheckboxGroup', Checkbox.Group);
componentMap.set('ApiCascader', ApiCascader);
componentMap.set('Cascader', Cascader);
componentMap.set('Slider', Slider);
componentMap.set('Rate', Rate);

View File

@ -0,0 +1,197 @@
<template>
<a-cascader
v-model:value="state"
:options="options"
:load-data="loadData"
change-on-select
@change="handleChange"
:displayRender="handleRenderDisplay"
>
<template #suffixIcon v-if="loading">
<LoadingOutlined spin />
</template>
<template #notFoundContent v-if="loading">
<span>
<LoadingOutlined spin class="mr-1" />
{{ t('component.form.apiSelectNotFound') }}
</span>
</template>
</a-cascader>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, unref, watch, watchEffect } from 'vue';
import { Cascader } from 'ant-design-vue';
import { propTypes } from '/@/utils/propTypes';
import { isFunction } from '/@/utils/is';
import { get, omit } from 'lodash-es';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
import { LoadingOutlined } from '@ant-design/icons-vue';
interface Option {
value: string;
label: string;
loading?: boolean;
isLeaf?: boolean;
children?: Option[];
}
export default defineComponent({
name: 'ApiCascader',
components: {
LoadingOutlined,
[Cascader.name]: Cascader,
},
props: {
value: {
type: Array,
},
api: {
type: Function as PropType<(arg?: Recordable) => Promise<Option[]>>,
default: null,
},
numberToString: propTypes.bool,
resultField: propTypes.string.def(''),
labelField: propTypes.string.def('label'),
valueField: propTypes.string.def('value'),
childrenField: propTypes.string.def('children'),
asyncFetchParamKey: propTypes.string.def('parentCode'),
immediate: propTypes.bool.def(true),
// init fetch params
initFetchParams: {
type: Object as PropType<Recordable>,
default: () => ({}),
},
//
isLeaf: {
type: Function as PropType<(arg: Recordable) => boolean>,
default: null,
},
displayRenderArray: {
type: Array,
},
},
emits: ['change', 'defaultChange'],
setup(props, { emit }) {
const apiData = ref<any[]>([]);
const options = ref<Option[]>([]);
const loading = ref<boolean>(false);
const emitData = ref<any[]>([]);
const isFirstLoad = ref(true);
// Embedded in the form, just use the hook binding to perform form verification
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
watch(
apiData,
(data) => {
const opts = generatorOptions(data);
options.value = opts;
},
{ deep: true },
);
function generatorOptions(options: any[]): Option[] {
const { labelField, valueField, numberToString, childrenField, isLeaf } = props;
return options.reduce((prev, next: Recordable) => {
if (next) {
const value = next[valueField];
const item = {
...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) {
Reflect.set(item, childrenField, generatorOptions(children));
}
prev.push(item);
}
return prev;
}, [] as Option[]);
}
async function initialFetch() {
const api = props.api;
if (!api || !isFunction(api)) return;
apiData.value = [];
loading.value = true;
try {
const res = await api(props.initFetchParams);
if (Array.isArray(res)) {
apiData.value = res;
return;
}
if (props.resultField) {
apiData.value = get(res, props.resultField) || [];
}
} catch (error) {
console.warn(error);
} finally {
loading.value = false;
}
}
async function loadData(selectedOptions: Option[]) {
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
const api = props.api;
if (!api || !isFunction(api)) return;
try {
const res = await api({
[props.asyncFetchParamKey]: Reflect.get(targetOption, 'value'),
});
if (Array.isArray(res)) {
const children = generatorOptions(res);
targetOption.children = children;
return;
}
if (props.resultField) {
const children = generatorOptions(get(res, props.resultField) || []);
targetOption.children = children;
}
} catch (e) {
console.error(e);
} finally {
targetOption.loading = false;
}
}
watchEffect(() => {
props.immediate && initialFetch();
});
watch(
() => props.initFetchParams,
() => {
!unref(isFirstLoad) && initialFetch();
},
{ deep: true },
);
function handleChange(keys, args) {
emitData.value = keys;
emit('defaultChange', keys, args);
}
function handleRenderDisplay({ labels, selectedOptions }) {
if (unref(emitData).length === selectedOptions.length) {
return labels.join(' / ');
}
if (props.displayRenderArray) {
return props.displayRenderArray.join(' / ');
}
return '';
}
return {
state,
options,
loading,
handleChange,
loadData,
handleRenderDisplay,
};
},
});
</script>

View File

@ -242,7 +242,7 @@ export function useFormEvents({
const values = await validate();
const res = handleFormValues(values);
emit('submit', res);
} catch (error) {
} catch (error: any) {
throw new Error(error);
}
}

View File

@ -98,6 +98,7 @@ export type ComponentType =
| 'Checkbox'
| 'CheckboxGroup'
| 'AutoComplete'
| 'ApiCascader'
| 'Cascader'
| 'DatePicker'
| 'MonthPicker'

View File

@ -57,7 +57,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;

View File

@ -1,4 +1,5 @@
<template>
<!-- eslint-disable vue/no-v-html -->
<div v-html="getHtmlData" :class="$props.class" class="markdown-viewer"></div>
</template>

View File

@ -54,7 +54,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 {

View File

@ -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 {

View File

@ -432,7 +432,7 @@
bottom: 0;
left: 0;
z-index: @preview-comp-z-index;
background: rgba(0, 0, 0, 0.5);
background: rgb(0 0 0 / 50%);
user-select: none;
&-content {
@ -458,7 +458,7 @@
overflow: hidden;
color: @white;
cursor: pointer;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgb(0 0 0 / 50%);
border-radius: 50%;
transition: all 0.2s;
@ -470,7 +470,7 @@
}
&:hover {
background-color: rgba(0, 0, 0, 0.8);
background-color: rgb(0 0 0 / 80%);
}
}
@ -480,7 +480,7 @@
left: 50%;
padding: 0 22px;
font-size: 16px;
background: rgba(109, 109, 109, 0.6);
background: rgb(109 109 109 / 60%);
border-radius: 15px;
transform: translateX(-50%);
}
@ -494,7 +494,7 @@
height: 44px;
padding: 0 22px;
margin-left: -139px;
background: rgba(109, 109, 109, 0.6);
background: rgb(109 109 109 / 60%);
border-radius: 22px;
justify-content: center;
@ -526,12 +526,12 @@
height: 50px;
font-size: 28px;
cursor: pointer;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgb(0 0 0 / 50%);
border-radius: 50%;
transition: all 0.2s;
&:hover {
background-color: rgba(0, 0, 0, 0.8);
background-color: rgb(0 0 0 / 80%);
}
&.left {

View File

@ -88,7 +88,7 @@
}
.ant-image-preview-operations {
background-color: rgba(0, 0, 0, 0.4);
background-color: rgb(0 0 0 / 40%);
}
}
</style>

View File

@ -148,7 +148,7 @@
display: none;
width: 0;
height: 0;
opacity: 0;
opacity: 0%;
}
}
}
@ -159,12 +159,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%);
}
}
@ -174,8 +174,7 @@
bottom: 2px;
z-index: 1;
border-radius: 4px;
opacity: 0;
-webkit-transition: opacity 80ms ease;
opacity: 0%;
transition: opacity 80ms ease;
&.is-vertical {
@ -201,7 +200,7 @@
.scrollbar:active > .scrollbar__bar,
.scrollbar:focus > .scrollbar__bar,
.scrollbar:hover > .scrollbar__bar {
opacity: 1;
opacity: 100%;
transition: opacity 340ms ease-out;
}
</style>

View File

@ -188,7 +188,7 @@
&-vertical&-collapse &-item,
&-vertical&-collapse &-submenu-title {
padding: 0 0;
padding: 0;
}
&-vertical &-submenu-title-icon {

View File

@ -92,7 +92,7 @@
background-color: transparent;
border-color: @white;
border-style: solid;
border-width: 0 5px 0 5px;
border-width: 0 5px;
content: '';
}

View File

@ -357,7 +357,7 @@
padding: 16px;
.ant-form {
padding: 12px 10px 6px 10px;
padding: 12px 10px 6px;
margin-bottom: 16px;
background-color: @component-background;
border-radius: 2px;
@ -375,7 +375,7 @@
.ant-table-title {
min-height: 40px;
padding: 0 0 8px 0 !important;
padding: 0 0 8px !important;
}
.ant-table.ant-table-bordered .ant-table-title {
@ -401,7 +401,7 @@
}
.ant-pagination {
margin: 10px 0 0 0;
margin: 10px 0 0;
}
.ant-table-footer {

View File

@ -42,7 +42,7 @@
.@{prefix-cls} {
&__help {
margin-left: 8px;
color: rgba(0, 0, 0, 0.65) !important;
color: rgb(0 0 0 / 65%) !important;
}
}
</style>

View File

@ -265,7 +265,7 @@
result = await beforeEditSubmit({
record: pick(record, keys),
index,
key,
key: key as string,
value,
});
} catch (e) {

View File

@ -420,7 +420,7 @@
&__fixed-left,
&__fixed-right {
color: rgba(0, 0, 0, 0.45);
color: rgb(0 0 0 / 45%);
cursor: pointer;
&.active,

View File

@ -399,7 +399,7 @@
const children = get(item, childrenField) || [];
const title = get(item, titleField);
const searchIdx = title.indexOf(searchText);
const searchIdx = searchText ? title.indexOf(searchText) : -1;
const isHighlight =
searchState.startSearch && !isEmpty(searchText) && highlight && searchIdx !== -1;
const highlightStyle = `color: ${isBoolean(highlight) ? '#f50' : highlight}`;
@ -408,7 +408,7 @@
<span class={unref(getBindValues)?.blockNode ? `${prefixCls}__content` : ''}>
<span>{title.substr(0, searchIdx)}</span>
<span style={highlightStyle}>{searchText}</span>
<span>{title.substr(searchIdx + searchText.length)}</span>
<span>{title.substr(searchIdx + (searchText as string).length)}</span>
</span>
) : (
title

View File

@ -292,7 +292,7 @@
position: relative;
overflow: hidden;
text-align: center;
background-color: rgb(238, 238, 238);
background-color: rgb(238 238 238);
border: 1px solid #ddd;
border-radius: @radius;
@ -313,7 +313,7 @@
position: absolute;
top: 0;
font-size: 12px;
-webkit-text-size-adjust: none;
text-size-adjust: none;
background-color: -webkit-gradient(
linear,
left top,

View File

@ -209,7 +209,7 @@
}
&.normal {
background-color: rgba(0, 0, 0, 0.3);
background-color: rgb(0 0 0 / 30%);
}
}

View File

@ -67,7 +67,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;
@ -76,7 +76,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;

View File

@ -30,12 +30,12 @@ span.anticon:not(.app-iconify) {
}
.ant-image-preview-operations {
background-color: rgba(0, 0, 0, 0.3);
background-color: rgb(0 0 0 / 30%);
}
.ant-popover {
&-content {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
}
}

View File

@ -5,7 +5,7 @@
@import './theme.less';
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset !important;
box-shadow: 0 0 0 1000px white inset !important;
}
:-webkit-autofill {
@ -14,7 +14,7 @@ input:-webkit-autofill {
html {
overflow: hidden;
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
html,

View File

@ -17,15 +17,15 @@
// }
::-webkit-scrollbar-track {
background-color: rgba(0, 0, 0, 0.05);
background-color: rgb(0 0 0 / 5%);
}
::-webkit-scrollbar-thumb {
// background: rgba(0, 0, 0, 0.6);
background-color: rgba(144, 147, 153, 0.3);
background-color: rgb(144 147 153 / 30%);
// background-color: rgba(144, 147, 153, 0.3);
border-radius: 2px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.2);
box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
}
::-webkit-scrollbar-thumb:hover {
@ -46,6 +46,6 @@
width: 100%;
height: 2px;
background-color: @primary-color;
opacity: 0.75;
opacity: 75%;
}
}

View File

@ -4,7 +4,7 @@
html[data-theme='light'] {
.text-secondary {
color: rgba(0, 0, 0, 0.45);
color: rgb(0 0 0 / 45%);
}
.ant-alert-success {
@ -43,10 +43,10 @@ html[data-theme='light'] {
}
.ant-calendar-selected-day .ant-calendar-date {
color: rgba(0, 0, 0, 0.8);
color: rgb(0 0 0 / 80%);
}
.ant-select-tree li .ant-select-tree-node-content-wrapper.ant-select-tree-node-selected {
color: rgba(0, 0, 0, 0.9);
color: rgb(0 0 0 / 90%);
}
}

View File

@ -5,7 +5,7 @@
.fade-enter-from,
.fade-leave-to {
opacity: 0;
opacity: 0%;
}
/* fade-slide */
@ -15,12 +15,12 @@
}
.fade-slide-enter-from {
opacity: 0;
opacity: 0%;
transform: translateX(-30px);
}
.fade-slide-leave-to {
opacity: 0;
opacity: 0%;
transform: translateX(30px);
}
@ -35,12 +35,12 @@
}
.fade-bottom-enter-from {
opacity: 0;
opacity: 0%;
transform: translateY(-10%);
}
.fade-bottom-leave-to {
opacity: 0;
opacity: 0%;
transform: translateY(10%);
}
@ -51,12 +51,12 @@
}
.fade-scale-enter-from {
opacity: 0;
opacity: 0%;
transform: scale(1.2);
}
.fade-scale-leave-to {
opacity: 0;
opacity: 0%;
transform: scale(0.8);
}
@ -71,11 +71,11 @@
}
.fade-top-enter-from {
opacity: 0;
opacity: 0%;
transform: translateY(8%);
}
.fade-top-leave-to {
opacity: 0;
opacity: 0%;
transform: translateY(-8%);
}

View File

@ -4,7 +4,7 @@
&-enter-from,
&-leave,
&-leave-to {
opacity: 0;
opacity: 0%;
transform: scale(0);
}
}
@ -15,7 +15,7 @@
&-enter-from,
&-leave,
&-leave-to {
opacity: 0;
opacity: 0%;
transform: scale(0) rotate(-45deg);
}
}

View File

@ -3,7 +3,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
}
&-enter-from {
@ -20,7 +20,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
}
&-enter-from {
@ -37,7 +37,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
}
&-enter-from {
@ -54,7 +54,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
}
&-enter-from {

View File

@ -3,7 +3,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
transform: translateY(-15px);
}
}
@ -13,7 +13,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
transform: translateY(15px);
}
}
@ -23,7 +23,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
transform: translateX(-15px);
}
}
@ -33,7 +33,7 @@
&-enter-from,
&-leave-to {
opacity: 0;
opacity: 0%;
transform: translateX(15px);
}
}

View File

@ -6,7 +6,7 @@
.zoom-out-enter-from,
.zoom-out-leave-to {
opacity: 0;
opacity: 0%;
transform: scale(0);
}
@ -17,11 +17,11 @@
}
.zoom-fade-enter-from {
opacity: 0;
opacity: 0%;
transform: scale(0.92);
}
.zoom-fade-leave-to {
opacity: 0;
opacity: 0%;
transform: scale(1.06);
}

View File

@ -1,8 +1,6 @@
import { ref, unref } from 'vue';
export function useLockFn<P extends any[] = any[], V extends any = any>(
fn: (...args: P) => Promise<V>,
) {
export function useLockFn<P extends any[] = any[], V = any>(fn: (...args: P) => Promise<V>) {
const lockRef = ref(false);
return async function (...args: P) {
if (unref(lockRef)) return;

View File

@ -51,7 +51,7 @@ export function copyTextToClipboard(input: string, { target = document.body }: O
let isSuccess = false;
try {
isSuccess = document.execCommand('copy');
} catch (e) {
} catch (e: any) {
throw new Error(e);
}

View File

@ -169,7 +169,7 @@
color: @breadcrumb-item-normal-color;
a {
color: rgba(0, 0, 0, 0.65);
color: rgb(0 0 0 / 65%);
&:hover {
color: @primary-color;
@ -184,10 +184,10 @@
&--dark {
.ant-breadcrumb-link {
color: rgba(255, 255, 255, 0.6);
color: rgb(255 255 255 / 60%);
a {
color: rgba(255, 255, 255, 0.8);
color: rgb(255 255 255 / 80%);
&:hover {
color: @white;
@ -197,7 +197,7 @@
.ant-breadcrumb-separator,
.anticon {
color: rgba(255, 255, 255, 0.8);
color: rgb(255 255 255 / 80%);
}
}
}

View File

@ -95,7 +95,7 @@
&__entry {
position: relative;
//height: 240px;
padding: 130px 30px 30px 30px;
padding: 130px 30px 30px;
border-radius: 10px;
}

View File

@ -67,7 +67,7 @@
.@{header-trigger-prefix-cls} {
display: flex;
height: 100%;
padding: 1px 10px 0 10px;
padding: 1px 10px 0;
cursor: pointer;
align-items: center;

View File

@ -189,7 +189,7 @@
&--mobile {
.@{logo-prefix-cls} {
&__title {
opacity: 1;
opacity: 100%;
}
}
}

View File

@ -65,7 +65,7 @@
updateColorWeak(colorWeak);
updateGrayMode(grayMode);
createMessage.success(t('layout.setting.resetSuccess'));
} catch (error) {
} catch (error: any) {
createMessage.error(error);
}
}

View File

@ -66,7 +66,7 @@
cursor: pointer;
background-color: #f0f2f5;
border-radius: 4px;
box-shadow: 0 1px 2.5px 0 rgba(0, 0, 0, 0.18);
box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
&::before,
&::after {

View File

@ -60,7 +60,7 @@
&:hover {
background-color: @primary-color;
box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15);
box-shadow: 0 0 4px 0 rgb(28 36 56 / 15%);
}
}
</style>

View File

@ -80,13 +80,14 @@
<script lang="ts">
import type { Menu } from '/@/router/types';
import type { CSSProperties } from 'vue';
import { computed, defineComponent, onMounted, ref, unref } from 'vue';
import { computed, defineComponent, onMounted, ref, unref, watch } from 'vue';
import type { RouteLocationNormalized } from 'vue-router';
import { ScrollContainer } from '/@/components/Container';
import { SimpleMenu, SimpleMenuTag } from '/@/components/SimpleMenu';
import { Icon } from '/@/components/Icon';
import { AppLogo } from '/@/components/Application';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { usePermissionStore } from '/@/store/modules/permission';
import { useDragLine } from './useLayoutSider';
import { useGlobSetting } from '/@/hooks/setting';
import { useDesign } from '/@/hooks/web/useDesign';
@ -138,6 +139,7 @@
} = useMenuSetting();
const { title } = useGlobSetting();
const permissionStore = usePermissionStore();
useDragLine(sideRef, dragBarRef, true);
@ -191,6 +193,17 @@
menuModules.value = await getShallowMenus();
});
// Menu changes
watch(
[() => permissionStore.getLastBuildMenuTime, () => permissionStore.getBackMenuList],
async () => {
menuModules.value = await getShallowMenus();
},
{
immediate: true,
},
);
listenerRouteChange((route) => {
currentRoute.value = route;
setActive(true);
@ -362,19 +375,19 @@
&.light {
.@{prefix-cls}-logo {
border-bottom: 1px solid rgb(238, 238, 238);
border-bottom: 1px solid rgb(238 238 238);
}
&.open {
> .scrollbar {
border-right: 1px solid rgb(238, 238, 238);
border-right: 1px solid rgb(238 238 238);
}
}
.@{prefix-cls}-module {
&__item {
font-weight: normal;
color: rgba(0, 0, 0, 0.65);
color: rgb(0 0 0 / 65%);
&--active {
color: @primary-color;
@ -384,15 +397,15 @@
}
.@{prefix-cls}-menu-list {
&__content {
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 0 4px 0 rgb(0 0 0 / 10%);
}
&__title {
.pushpin {
color: rgba(0, 0, 0, 0.35);
color: rgb(0 0 0 / 35%);
&:hover {
color: rgba(0, 0, 0, 0.85);
color: rgb(0 0 0 / 85%);
}
}
}
@ -442,7 +455,7 @@
&__item {
position: relative;
padding: 12px 0;
color: rgba(255, 255, 255, 0.65);
color: rgb(255 255 255 / 65%);
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
@ -487,7 +500,7 @@
left: 0;
width: 100%;
font-size: 14px;
color: rgba(255, 255, 255, 0.65);
color: rgb(255 255 255 / 65%);
text-align: center;
cursor: pointer;
background-color: @trigger-dark-bg-color;
@ -496,7 +509,7 @@
}
&.light &-trigger {
color: rgba(0, 0, 0, 0.65);
color: rgb(0 0 0 / 65%);
background-color: #fff;
border-top: 1px solid #eee;
}
@ -515,21 +528,21 @@
// margin-left: -6px;
font-size: 18px;
color: @primary-color;
border-bottom: 1px solid rgb(238, 238, 238);
opacity: 0;
border-bottom: 1px solid rgb(238 238 238);
opacity: 0%;
transition: unset;
align-items: center;
justify-content: space-between;
&.show {
min-width: 130px;
opacity: 1;
opacity: 100%;
transition: all 0.5s ease;
}
.pushpin {
margin-right: 6px;
color: rgba(255, 255, 255, 0.65);
color: rgb(255 255 255 / 65%);
cursor: pointer;
&:hover {
@ -572,7 +585,7 @@
background-color: #f8f8f9;
border-top: none;
border-bottom: none;
box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15);
box-shadow: 0 0 4px 0 rgb(28 36 56 / 15%);
}
}
</style>

View File

@ -50,7 +50,7 @@ html[data-theme='light'] {
&:hover {
.ant-tabs-close-x {
opacity: 1;
opacity: 100%;
}
}
@ -59,7 +59,7 @@ html[data-theme='light'] {
height: 12px;
font-size: 12px;
color: inherit;
opacity: 0;
opacity: 0%;
transition: none;
&:hover {
@ -95,7 +95,7 @@ html[data-theme='light'] {
transition: none;
.ant-tabs-close-x {
opacity: 1;
opacity: 100%;
}
svg {
@ -135,7 +135,7 @@ html[data-theme='light'] {
&--hide-close {
.ant-tabs-close-x {
opacity: 0 !important;
opacity: 0% !important;
}
}

View File

@ -2,7 +2,7 @@ import type { RouteRecordRaw, RouteMeta } from 'vue-router';
import { RoleEnum } from '/@/enums/roleEnum';
import { defineComponent } from 'vue';
export type Component<T extends any = any> =
export type Component<T = any> =
| ReturnType<typeof defineComponent>
| (() => Promise<typeof import('*.vue')>)
| (() => Promise<T>);

View File

@ -3,7 +3,7 @@
*/
import moment from 'moment';
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm';
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
const DATE_FORMAT = 'YYYY-MM-DD ';
export function formatToDateTime(

View File

@ -36,22 +36,19 @@ export function downloadByBase64(buf: string, filename: string, mime?: string, b
export function downloadByData(data: BlobPart, filename: string, mime?: string, bom?: BlobPart) {
const blobData = typeof bom !== 'undefined' ? [bom, data] : [data];
const blob = new Blob(blobData, { type: mime || 'application/octet-stream' });
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(blob, filename);
} else {
const blobURL = window.URL.createObjectURL(blob);
const tempLink = document.createElement('a');
tempLink.style.display = 'none';
tempLink.href = blobURL;
tempLink.setAttribute('download', filename);
if (typeof tempLink.download === 'undefined') {
tempLink.setAttribute('target', '_blank');
}
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
const blobURL = window.URL.createObjectURL(blob);
const tempLink = document.createElement('a');
tempLink.style.display = 'none';
tempLink.href = blobURL;
tempLink.setAttribute('download', filename);
if (typeof tempLink.download === 'undefined') {
tempLink.setAttribute('target', '_blank');
}
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobURL);
}
/**

View File

@ -81,6 +81,7 @@ export class VAxios {
this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
// If cancel repeat request is turned on, then cancel repeat request is prohibited
const {
// @ts-ignore
headers: { ignoreCancelToken },
} = config;
@ -149,6 +150,7 @@ export class VAxios {
data: formData,
headers: {
'Content-type': ContentTypeEnum.FORM_DATA,
// @ts-ignore
ignoreCancelToken: true,
},
});

View File

@ -1,6 +1,6 @@
import { isObject, isString } from '/@/utils/is';
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm';
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
export function joinTimestamp<T extends boolean>(
join: boolean,
@ -35,7 +35,7 @@ export function formatRequestDate(params: Recordable) {
if (value) {
try {
params[key] = isString(value) ? value.trim() : value;
} catch (error) {
} catch (error: any) {
throw new Error(error);
}
}

View File

@ -210,7 +210,7 @@
display: flex;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgb(0 0 0 / 50%);
backdrop-filter: blur(8px);
justify-content: center;
align-items: center;

View File

@ -1,8 +1,10 @@
module.exports = {
root: true,
plugins: ['stylelint-order'],
customSyntax: 'postcss-less',
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
rules: {
'selector-class-pattern': null,
'selector-pseudo-class-no-unknown': [
true,
{
@ -67,4 +69,24 @@ module.exports = {
],
},
ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
overrides: [
{
files: ['*.vue', '**/*.vue'],
extends: ['stylelint-config-recommended', 'stylelint-config-html'],
rules: {
'selector-pseudo-class-no-unknown': [
true,
{
ignorePseudoClasses: ['deep', 'global'],
},
],
'selector-pseudo-element-no-unknown': [
true,
{
ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'],
},
],
},
},
],
};

View File

@ -24,13 +24,13 @@
"@types/koa": "^2.13.4",
"@types/koa-bodyparser": "^5.0.2",
"@types/koa-router": "^7.4.4",
"@types/node": "^16.11.1",
"@types/node": "^16.11.6",
"nodemon": "^2.0.14",
"pm2": "^5.1.2",
"rimraf": "^3.0.2",
"ts-node": "^10.3.0",
"ts-node": "^10.4.0",
"tsconfig-paths": "^3.11.0",
"tsup": "^5.4.2",
"tsup": "^5.5.0",
"typescript": "^4.4.4"
}
}

View File

@ -27,7 +27,7 @@ export default defineConfig({
* Used for animation when the element is displayed
* @param maxOutput The larger the maxOutput output, the larger the generated css volume
*/
function createEnterPlugin(maxOutput = 8) {
function createEnterPlugin(maxOutput = 7) {
const createCss = (index: number, d = 'x') => {
const upd = d.toUpperCase();
return {

12161
yarn.lock

File diff suppressed because it is too large Load Diff