Merge remote-tracking branch 'vben/main' into Gf-Vben-Admin

# Conflicts:
#	pnpm-lock.yaml
This commit is contained in:
JinMao 2022-05-01 12:11:03 +08:00
commit ac8c7df7e1
13 changed files with 136 additions and 41 deletions

View File

@ -21,7 +21,7 @@ Vue Vben Admin is a free and open source middle and back-end template. Using the
- **Authority** Built-in complete dynamic routing permission generation scheme. - **Authority** Built-in complete dynamic routing permission generation scheme.
- **Component** Multiple commonly used components are encapsulated twice - **Component** Multiple commonly used components are encapsulated twice
## 预览 ## Preview
- [vue-vben-admin](https://vvbin.cn/next/) - Full version Chinese site - [vue-vben-admin](https://vvbin.cn/next/) - Full version Chinese site
- [vue-vben-admin-gh-pages](https://anncwb.github.io/vue-vben-admin/) - Full version of the github site - [vue-vben-admin-gh-pages](https://anncwb.github.io/vue-vben-admin/) - Full version of the github site

View File

@ -64,6 +64,7 @@ export function configStyleImportPlugin(_isBuild: boolean) {
'layout-footer': 'layout', 'layout-footer': 'layout',
'layout-header': 'layout', 'layout-header': 'layout',
'month-picker': 'date-picker', 'month-picker': 'date-picker',
'range-picker': 'date-picker',
}; };
return ignoreList.includes(name) return ignoreList.includes(name)

View File

@ -35,19 +35,19 @@
"@ant-design/colors": "^6.0.0", "@ant-design/colors": "^6.0.0",
"@ant-design/icons-vue": "^6.1.0", "@ant-design/icons-vue": "^6.1.0",
"@iconify/iconify": "^2.2.1", "@iconify/iconify": "^2.2.1",
"@logicflow/core": "^1.1.11", "@logicflow/core": "^1.1.13",
"@logicflow/extension": "^1.1.11", "@logicflow/extension": "^1.1.13",
"@vue/runtime-core": "^3.2.31", "@vue/runtime-core": "^3.2.33",
"@vue/shared": "^3.2.31", "@vue/shared": "^3.2.33",
"@vueuse/core": "^8.2.5", "@vueuse/core": "^8.3.0",
"@vueuse/shared": "^8.2.5", "@vueuse/shared": "^8.3.0",
"@zxcvbn-ts/core": "^2.0.1", "@zxcvbn-ts/core": "^2.0.1",
"ant-design-vue": "3.1.1", "ant-design-vue": "^3.2.0",
"axios": "^0.26.1", "axios": "^0.26.1",
"codemirror": "^5.65.2", "codemirror": "^5.65.3",
"cropperjs": "^1.5.12", "cropperjs": "^1.5.12",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"dayjs": "^1.11.0", "dayjs": "^1.11.1",
"echarts": "^5.3.2", "echarts": "^5.3.2",
"intro.js": "^5.1.0", "intro.js": "^5.1.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
@ -59,11 +59,11 @@
"qrcode": "^1.5.0", "qrcode": "^1.5.0",
"qs": "^6.10.3", "qs": "^6.10.3",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"showdown": "^2.0.3", "showdown": "^2.1.0",
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
"tinymce": "^5.10.3", "tinymce": "^5.10.3",
"vditor": "^3.8.13", "vditor": "^3.8.13",
"vue": "^3.2.31", "vue": "^3.2.33",
"vue-i18n": "^9.1.9", "vue-i18n": "^9.1.9",
"vue-json-pretty": "^2.0.6", "vue-json-pretty": "^2.0.6",
"vue-router": "^4.0.14", "vue-router": "^4.0.14",
@ -75,7 +75,7 @@
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^16.2.3", "@commitlint/cli": "^16.2.3",
"@commitlint/config-conventional": "^16.2.1", "@commitlint/config-conventional": "^16.2.1",
"@iconify/json": "^2.1.25", "@iconify/json": "^2.1.30",
"@purge-icons/generated": "^0.8.1", "@purge-icons/generated": "^0.8.1",
"@types/codemirror": "^5.60.5", "@types/codemirror": "^5.60.5",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
@ -84,30 +84,30 @@
"@types/intro.js": "^3.0.2", "@types/intro.js": "^3.0.2",
"@types/lodash-es": "^4.17.6", "@types/lodash-es": "^4.17.6",
"@types/mockjs": "^1.0.6", "@types/mockjs": "^1.0.6",
"@types/node": "^17.0.23", "@types/node": "^17.0.25",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.4.2", "@types/qrcode": "^1.4.2",
"@types/qs": "^6.9.7", "@types/qs": "^6.9.7",
"@types/showdown": "^1.9.4", "@types/showdown": "^1.9.4",
"@types/sortablejs": "^1.10.7", "@types/sortablejs": "^1.10.7",
"@typescript-eslint/eslint-plugin": "^5.18.0", "@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.18.0", "@typescript-eslint/parser": "^5.20.0",
"@vitejs/plugin-legacy": "^1.8.0", "@vitejs/plugin-legacy": "^1.8.1",
"@vitejs/plugin-vue": "^2.3.1", "@vitejs/plugin-vue": "^2.3.1",
"@vitejs/plugin-vue-jsx": "^1.3.9", "@vitejs/plugin-vue-jsx": "^1.3.10",
"@vue/compiler-sfc": "3.2.31", "@vue/compiler-sfc": "^3.2.33",
"@vue/test-utils": "^2.0.0-rc.19", "@vue/test-utils": "^2.0.0-rc.21",
"autoprefixer": "^10.4.4", "autoprefixer": "^10.4.4",
"commitizen": "^4.2.4", "commitizen": "^4.2.4",
"conventional-changelog-cli": "^2.2.2", "conventional-changelog-cli": "^2.2.2",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"dotenv": "^16.0.0", "dotenv": "^16.0.0",
"eslint": "^8.12.0", "eslint": "^8.13.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.6.0", "eslint-plugin-vue": "^8.6.0",
"esno": "^0.14.1", "esno": "^0.14.1",
"fs-extra": "^10.0.1", "fs-extra": "^10.1.0",
"husky": "^7.0.4", "husky": "^7.0.4",
"inquirer": "^8.2.2", "inquirer": "^8.2.2",
"less": "^4.1.2", "less": "^4.1.2",
@ -115,13 +115,13 @@
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"postcss": "^8.4.12", "postcss": "^8.4.12",
"postcss-html": "^1.3.0", "postcss-html": "^1.4.1",
"postcss-less": "^6.0.0", "postcss-less": "^6.0.0",
"prettier": "^2.6.2", "prettier": "^2.6.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.70.1", "rollup": "^2.70.2",
"rollup-plugin-visualizer": "^5.6.0", "rollup-plugin-visualizer": "^5.6.0",
"stylelint": "^14.6.1", "stylelint": "^14.7.1",
"stylelint-config-prettier": "^9.0.3", "stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended": "^7.0.0", "stylelint-config-recommended": "^7.0.0",
"stylelint-config-recommended-vue": "^1.4.0", "stylelint-config-recommended-vue": "^1.4.0",
@ -129,7 +129,7 @@
"stylelint-order": "^5.0.0", "stylelint-order": "^5.0.0",
"ts-node": "^10.7.0", "ts-node": "^10.7.0",
"typescript": "^4.6.3", "typescript": "^4.6.3",
"vite": "^2.9.1", "vite": "^2.9.5",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.0", "vite-plugin-html": "^3.2.0",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
@ -141,7 +141,7 @@
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-theme": "^0.8.6", "vite-plugin-theme": "^0.8.6",
"vite-plugin-vue-setup-extend": "^0.4.0", "vite-plugin-vue-setup-extend": "^0.4.0",
"vite-plugin-windicss": "^1.8.3", "vite-plugin-windicss": "^1.8.4",
"vue-eslint-parser": "^8.3.0", "vue-eslint-parser": "^8.3.0",
"vue-tsc": "^0.33.9" "vue-tsc": "^0.33.9"
}, },

View File

@ -24,6 +24,7 @@
params: { type: Object }, params: { type: Object },
immediate: { type: Boolean, default: true }, immediate: { type: Boolean, default: true },
resultField: propTypes.string.def(''), resultField: propTypes.string.def(''),
afterFetch: { type: Function as PropType<Fn> },
}, },
emits: ['options-change', 'change'], emits: ['options-change', 'change'],
setup(props, { attrs, emit }) { setup(props, { attrs, emit }) {
@ -61,7 +62,7 @@
}); });
async function fetch() { async function fetch() {
const { api } = props; const { api, afterFetch } = props;
if (!api || !isFunction(api)) return; if (!api || !isFunction(api)) return;
loading.value = true; loading.value = true;
treeData.value = []; treeData.value = [];
@ -71,6 +72,9 @@
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
if (afterFetch && isFunction(afterFetch)) {
result = afterFetch(result);
}
loading.value = false; loading.value = false;
if (!result) return; if (!result) return;
if (!isArray(result)) { if (!isArray(result)) {

View File

@ -2,7 +2,7 @@ import type { ComputedRef, Ref } from 'vue';
import type { FormProps, FormSchema, FormActionType } from '../types/form'; import type { FormProps, FormSchema, FormActionType } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface'; import type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw, nextTick } from 'vue'; import { unref, toRaw, nextTick } from 'vue';
import { isArray, isFunction, isNullOrUnDef, isObject, isString } from '/@/utils/is'; import { isArray, isFunction, isObject, isString, isDef } from '/@/utils/is';
import { deepMerge } from '/@/utils'; import { deepMerge } from '/@/utils';
import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper'; import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper';
import { dateUtil } from '/@/utils/dateUtil'; import { dateUtil } from '/@/utils/dateUtil';
@ -55,6 +55,10 @@ export function useFormEvents({
.map((item) => item.field) .map((item) => item.field)
.filter(Boolean); .filter(Boolean);
// key 支持 a.b.c 的嵌套写法
const delimiter = '.';
const nestKeyArray = fields.filter((item) => item.indexOf(delimiter) >= 0);
const validKeys: string[] = []; const validKeys: string[] = [];
Object.keys(values).forEach((key) => { Object.keys(values).forEach((key) => {
const schema = unref(getSchema).find((item) => item.field === key); const schema = unref(getSchema).find((item) => item.field === key);
@ -85,6 +89,21 @@ export function useFormEvents({
formModel[key] = value; formModel[key] = value;
} }
validKeys.push(key); validKeys.push(key);
} else {
nestKeyArray.forEach((nestKey: string) => {
try {
const value = eval('values' + delimiter + nestKey);
if (isDef(value)) {
formModel[nestKey] = value;
validKeys.push(nestKey);
}
} catch (e) {
// key not exist
if (isDef(defaultValueRef.value[nestKey])) {
formModel[nestKey] = defaultValueRef.value[nestKey];
}
}
});
} }
}); });
validateFields(validKeys).catch((_) => {}); validateFields(validKeys).catch((_) => {});

View File

@ -7,9 +7,18 @@ interface PaginationRenderProps {
originalElement: any; originalElement: any;
} }
type PaginationPositon =
| 'topLeft'
| 'topCenter'
| 'topRight'
| 'bottomLeft'
| 'bottomCenter'
| 'bottomRight';
export declare class PaginationConfig extends Pagination { export declare class PaginationConfig extends Pagination {
position?: 'top' | 'bottom' | 'both'; position?: PaginationPositon[];
} }
export interface PaginationProps { export interface PaginationProps {
/** /**
* total number of data items * total number of data items
@ -96,4 +105,11 @@ export interface PaginationProps {
* @type Function * @type Function
*/ */
itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element; itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element;
/**
* specify the position of Pagination
* @default ['bottomRight']
* @type string[]
*/
position?: PaginationPositon[];
} }

View File

@ -71,7 +71,7 @@
selectedKeys: state.selectedKeys, selectedKeys: state.selectedKeys,
checkedKeys: state.checkedKeys, checkedKeys: state.checkedKeys,
checkStrictly: state.checkStrictly, checkStrictly: state.checkStrictly,
filedNames: unref(getFieldNames), fieldNames: unref(getFieldNames),
'onUpdate:expandedKeys': (v: KeyType[]) => { 'onUpdate:expandedKeys': (v: KeyType[]) => {
state.expandedKeys = v; state.expandedKeys = v;
emit('update:expandedKeys', v); emit('update:expandedKeys', v);
@ -119,6 +119,7 @@
getAllKeys, getAllKeys,
getChildrenKeys, getChildrenKeys,
getEnabledKeys, getEnabledKeys,
getSelectedNode,
} = useTree(treeDataRef, getFieldNames); } = useTree(treeDataRef, getFieldNames);
function getIcon(params: Recordable, icon?: string) { function getIcon(params: Recordable, icon?: string) {
@ -293,6 +294,7 @@
() => { () => {
state.checkedKeys = toRaw(props.value || []); state.checkedKeys = toRaw(props.value || []);
}, },
{ immediate: true },
); );
watch( watch(
@ -319,6 +321,7 @@
insertNodesByKey, insertNodesByKey,
deleteNodeByKey, deleteNodeByKey,
updateNodeByKey, updateNodeByKey,
getSelectedNode,
checkAll, checkAll,
expandAll, expandAll,
filterByLevel: (level: number) => { filterByLevel: (level: number) => {

View File

@ -185,4 +185,9 @@ export interface TreeActionType {
updateNodeByKey: (key: string, node: Omit<TreeDataItem, 'key'>) => void; updateNodeByKey: (key: string, node: Omit<TreeDataItem, 'key'>) => void;
setSearchValue: (value: string) => void; setSearchValue: (value: string) => void;
getSearchValue: () => string; getSearchValue: () => string;
getSelectedNode: (
key: KeyType,
treeList?: TreeItem[],
selectNode?: TreeItem | null,
) => TreeItem | null;
} }

View File

@ -1,4 +1,4 @@
import type { InsertNodeParams, KeyType, FieldNames } from './tree'; import type { InsertNodeParams, KeyType, FieldNames, TreeItem } from './tree';
import type { Ref, ComputedRef } from 'vue'; import type { Ref, ComputedRef } from 'vue';
import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree'; import type { TreeDataItem } from 'ant-design-vue/es/tree/Tree';
@ -176,6 +176,23 @@ export function useTree(treeDataRef: Ref<TreeDataItem[]>, getFieldNames: Compute
} }
} }
} }
// Get selected node
function getSelectedNode(key: KeyType, list?: TreeItem[], selectedNode?: TreeItem | null) {
if (!key && key !== 0) return null;
const treeData = list || unref(treeDataRef);
treeData.forEach((item) => {
if (selectedNode?.key || selectedNode?.key === 0) return selectedNode;
if (item.key === key) {
selectedNode = item;
return;
}
if (item.children && item.children.length) {
selectedNode = getSelectedNode(key, item.children, selectedNode);
}
});
return selectedNode || null;
}
return { return {
deleteNodeByKey, deleteNodeByKey,
insertNodeByKey, insertNodeByKey,
@ -185,5 +202,6 @@ export function useTree(treeDataRef: Ref<TreeDataItem[]>, getFieldNames: Compute
getAllKeys, getAllKeys,
getChildrenKeys, getChildrenKeys,
getEnabledKeys, getEnabledKeys,
getSelectedNode,
}; };
} }

View File

@ -460,6 +460,27 @@
span: 8, span: 8,
}, },
}, },
{
field: 'field36',
component: 'ApiTree',
label: '远程Tree',
helpMessage: ['ApiTree组件', '使用接口提供的数据生成选项'],
required: true,
componentProps: {
api: treeOptionsListApi,
params: {
count: 2,
},
afterFetch: (v) => {
//do something
return v;
},
resultField: 'list',
},
colProps: {
span: 8,
},
},
{ {
field: 'divider-linked', field: 'divider-linked',
component: 'Divider', component: 'Divider',

View File

@ -12,14 +12,14 @@
show-icon show-icon
/> />
<Divider /> <Divider />
<a-button type="primary" class="mr-2" @click="switchToken(2)" :disabled="!isBackPremissionMode"> <a-button type="primary" class="mr-2" @click="switchToken(2)" :disabled="!isBackPermissionMode">
点击切换按钮权限(用户id为2) 点击切换按钮权限(用户id为2)
</a-button> </a-button>
<a-button type="primary" @click="switchToken(1)" :disabled="!isBackPremissionMode"> <a-button type="primary" @click="switchToken(1)" :disabled="!isBackPermissionMode">
点击切换按钮权限(用户id为1,默认) 点击切换按钮权限(用户id为1,默认)
</a-button> </a-button>
<template v-if="isBackPremissionMode"> <template v-if="isBackPermissionMode">
<Divider>组件方式判断权限</Divider> <Divider>组件方式判断权限</Divider>
<Authority :value="'1000'"> <Authority :value="'1000'">
<a-button type="primary" class="mx-4"> 拥有code ['1000']权限可见 </a-button> <a-button type="primary" class="mx-4"> 拥有code ['1000']权限可见 </a-button>
@ -77,7 +77,7 @@
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore(); const userStore = useUserStore();
const isBackPremissionMode = computed( const isBackPermissionMode = computed(
() => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK, () => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK,
); );
@ -95,7 +95,7 @@
hasPermission, hasPermission,
permissionStore, permissionStore,
switchToken, switchToken,
isBackPremissionMode, isBackPermissionMode,
}; };
}, },
}); });

View File

@ -12,10 +12,10 @@
<div class="mt-4"> <div class="mt-4">
权限切换(请先切换权限模式为后台权限模式): 权限切换(请先切换权限模式为后台权限模式):
<Space> <Space>
<a-button @click="switchToken(1)" :disabled="!isBackPremissionMode"> <a-button @click="switchToken(1)" :disabled="!isBackPermissionMode">
获取用户id为1的菜单 获取用户id为1的菜单
</a-button> </a-button>
<a-button @click="switchToken(2)" :disabled="!isBackPremissionMode"> <a-button @click="switchToken(2)" :disabled="!isBackPermissionMode">
获取用户id为2的菜单 获取用户id为2的菜单
</a-button> </a-button>
</Space> </Space>
@ -40,7 +40,7 @@
const userStore = useUserStore(); const userStore = useUserStore();
const appStore = useAppStore(); const appStore = useAppStore();
const isBackPremissionMode = computed( const isBackPermissionMode = computed(
() => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK, () => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK,
); );
@ -58,7 +58,7 @@
RoleEnum, RoleEnum,
refreshMenu, refreshMenu,
switchToken, switchToken,
isBackPremissionMode, isBackPermissionMode,
}; };
}, },
}); });

View File

@ -13,6 +13,7 @@
<a-button @click="handleGetCheckData" class="mr-2"> 获取勾选数据 </a-button> <a-button @click="handleGetCheckData" class="mr-2"> 获取勾选数据 </a-button>
<a-button @click="handleSetSelectData" class="mr-2"> 设置选中数据 </a-button> <a-button @click="handleSetSelectData" class="mr-2"> 设置选中数据 </a-button>
<a-button @click="handleGetSelectData" class="mr-2"> 获取选中数据 </a-button> <a-button @click="handleGetSelectData" class="mr-2"> 获取选中数据 </a-button>
<a-button @click="handleGetSelectNode" class="mr-2"> 获取选中节点 </a-button>
<a-button @click="handleSetExpandData" class="mr-2"> 设置展开数据 </a-button> <a-button @click="handleSetExpandData" class="mr-2"> 设置展开数据 </a-button>
<a-button @click="handleGetExpandData" class="mr-2"> 获取展开数据 </a-button> <a-button @click="handleGetExpandData" class="mr-2"> 获取展开数据 </a-button>
@ -69,6 +70,12 @@
createMessage.success(JSON.stringify(keys)); createMessage.success(JSON.stringify(keys));
} }
function handleGetSelectNode() {
const keys = getTree().getSelectedKeys();
const node = getTree().getSelectedNode(keys[0]);
createMessage.success(node !== null ? JSON.stringify(node) : null);
}
function handleSetExpandData() { function handleSetExpandData() {
getTree().setExpandedKeys(['0-0']); getTree().setExpandedKeys(['0-0']);
} }
@ -120,6 +127,7 @@
handleGetSelectData, handleGetSelectData,
handleSetExpandData, handleSetExpandData,
handleGetExpandData, handleGetExpandData,
handleGetSelectNode,
appendNodeByKey, appendNodeByKey,
deleteNodeByKey, deleteNodeByKey,
updateNodeByKey, updateNodeByKey,