提交 4628d944 编写于 作者: V Vben

feat: added system management sample page

上级 cd8e924d
......@@ -8,12 +8,11 @@
- axios 支持 form-data 格式请求
- 新增图标选择器组件(支持本地和在线方式)
- 新增修改密码界面
- 新增部门管理示例界面
- 新增 WebSocket 示例和服务脚本
- Tree 组件新增 `renderIcon` 属性用于控制层级图标显示
- Tree->actionItem 新增 show 属性,用于动态控制按钮显示
- Tree 新增工具栏/title/搜索功能
- 新增部门管理/修改密码/账号管理/角色管理/菜单管理示例界面
### ⚡ Performance Improvements
......
......@@ -116,7 +116,7 @@ export default [
},
},
{
url: '/api/system/getRoleList',
url: '/api/system/getRoleListByPage',
timeout: 100,
method: 'get',
response: ({ query }) => {
......@@ -124,6 +124,14 @@ export default [
return resultPageSuccess(page, pageSize, roleList);
},
},
{
url: '/api/system/getAllRoleList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(roleList);
},
},
{
url: '/api/system/getDeptList',
timeout: 100,
......
......@@ -4,11 +4,14 @@ export type AccountParams = BasicPageParams & {
account?: string;
nickname?: string;
};
export type RoleParams = BasicPageParams & {
export type RoleParams = {
roleName?: string;
status?: string;
};
export type RolePageParams = BasicPageParams & RoleParams;
export type DeptParams = {
deptName?: string;
status?: string;
......@@ -66,4 +69,6 @@ export type DeptListGetResultModel = BasicFetchResult<DeptListItem>;
export type MenuListGetResultModel = BasicFetchResult<MenuListItem>;
export type RoleListGetResultModel = BasicFetchResult<RoleListItem>;
export type RolePageListGetResultModel = BasicFetchResult<RoleListItem>;
export type RoleListGetResultModel = RoleListItem[];
......@@ -3,9 +3,11 @@ import {
DeptListItem,
MenuParams,
RoleParams,
RolePageParams,
MenuListGetResultModel,
DeptListGetResultModel,
AccountListGetResultModel,
RolePageListGetResultModel,
RoleListGetResultModel,
} from './model/systemModel';
import { defHttp } from '/@/utils/http/axios';
......@@ -14,7 +16,8 @@ enum Api {
AccountList = '/system/getAccountList',
DeptList = '/system/getDeptList',
MenuList = '/system/getMenuList',
RoleList = '/system/getRoleList',
RolePageList = '/system/getRoleListByPage',
GetAllRoleList = '/system/getAllRoleList',
}
export const getAccountList = (params: AccountParams) =>
......@@ -26,5 +29,8 @@ export const getDeptList = (params?: DeptListItem) =>
export const getMenuList = (params?: MenuParams) =>
defHttp.get<MenuListGetResultModel>({ url: Api.MenuList, params });
export const getRoleList = (params?: RoleParams) =>
defHttp.get<RoleListGetResultModel>({ url: Api.RoleList, params });
export const getRoleListByPage = (params?: RolePageParams) =>
defHttp.get<RolePageListGetResultModel>({ url: Api.RolePageList, params });
export const getAllRoleList = (params?: RoleParams) =>
defHttp.get<RoleListGetResultModel>({ url: Api.GetAllRoleList, params });
......@@ -311,11 +311,12 @@ export default defineComponent({
const realColProps = { ...baseColProps, ...colProps };
const { isIfShow, isShow } = getShow();
const values = unref(getValues);
const getContent = () => {
return colSlot
? getSlot(slots, colSlot, unref(getValues))
? getSlot(slots, colSlot, values)
: renderColContent
? renderColContent(unref(getValues))
? renderColContent(values)
: renderItem();
};
......
......@@ -10,9 +10,12 @@
<Icon icon="ion:ellipsis-vertical" />
<template #overlay>
<Menu @click="handleMenuClick">
<MenuItem v-for="item in toolbarList" :key="item.value">
{{ item.label }}
</MenuItem>
<template v-for="item in toolbarList" :key="item.value">
<MenuItem v-bind="{ key: item.value }">
{{ item.label }}
</MenuItem>
<MenuDivider v-if="item.divider" />
</template>
</Menu>
</template>
</Dropdown>
......@@ -46,6 +49,7 @@
Dropdown,
Menu,
MenuItem: Menu.Item,
MenuDivider: Menu.Divider,
InputSearch: Input.Search,
},
props: {
......@@ -64,9 +68,9 @@
const { t } = useI18n();
const toolbarList = ref([
{ label: t('component.tree.selectAll'), value: ToolbarEnum.SELECT_ALL },
{ label: t('component.tree.unSelectAll'), value: ToolbarEnum.UN_SELECT_ALL },
{ label: t('component.tree.unSelectAll'), value: ToolbarEnum.UN_SELECT_ALL, divider: true },
{ label: t('component.tree.expandAll'), value: ToolbarEnum.EXPAND_ALL },
{ label: t('component.tree.unExpandAll'), value: ToolbarEnum.UN_EXPAND_ALL },
{ label: t('component.tree.unExpandAll'), value: ToolbarEnum.UN_EXPAND_ALL, divider: true },
{ label: t('component.tree.checkStrictly'), value: ToolbarEnum.CHECK_STRICTLY },
{ label: t('component.tree.checkUnStrictly'), value: ToolbarEnum.CHECK_UN_STRICTLY },
]);
......
<script lang="tsx">
import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
import { defineComponent, reactive, computed, unref, ref, watchEffect, toRaw } from 'vue';
import { defineComponent, reactive, computed, unref, ref, watchEffect, toRaw, watch } from 'vue';
import { Tree } from 'ant-design-vue';
import { TreeIcon } from './TreeIcon';
import TreeHeader from './TreeHeader.vue';
......@@ -27,6 +27,7 @@
}
export default defineComponent({
name: 'BasicTree',
inheritAttrs: false,
props: basicProps,
emits: ['update:expandedKeys', 'update:selectedKeys', 'update:value', 'change'],
setup(props, { attrs, slots, emit }) {
......@@ -89,8 +90,9 @@
},
onCheck: (v: CheckKeys) => {
state.checkedKeys = v;
emit('change', v);
emit('update:value', v);
const rawVal = toRaw(v);
emit('change', rawVal);
emit('update:value', rawVal);
},
onRightClick: handleRightClick,
};
......@@ -191,11 +193,21 @@
state.checkedKeys = props.checkedKeys;
});
watchEffect(() => {
if (props.value) {
state.checkedKeys = props.value;
watch(
() => props.value,
() => {
state.checkedKeys = toRaw(props.value || []);
}
});
);
// watchEffect(() => {
// console.log('======================');
// console.log(props.value);
// console.log('======================');
// if (props.value) {
// state.checkedKeys = props.value;
// }
// });
watchEffect(() => {
state.checkStrictly = props.checkStrictly;
......
......@@ -7,45 +7,29 @@ const menu: MenuModule = {
name: t('routes.demo.system.moduleName'),
path: '/system',
tag: {
dot: true,
content: 'new',
},
children: [
{
path: 'account',
name: t('routes.demo.system.account'),
tag: {
dot: true,
type: 'warn',
},
},
{
path: 'role',
name: t('routes.demo.system.role'),
tag: {
dot: true,
},
},
{
path: 'menu',
name: t('routes.demo.system.menu'),
tag: {
dot: true,
},
},
{
path: 'dept',
name: t('routes.demo.system.dept'),
tag: {
dot: true,
},
},
{
path: 'changePassword',
name: t('routes.demo.system.password'),
tag: {
dot: true,
},
},
],
},
......
......@@ -8,13 +8,16 @@
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { accountFormSchema } from './account.data';
import { getDeptList } from '/@/api/demo/system';
export default defineComponent({
name: 'AccountModal',
components: { BasicModal, BasicForm },
setup() {
emits: ['success', 'register'],
setup(_, { emit }) {
const isUpdate = ref(true);
const [registerForm, { setFieldsValue, validate }] = useForm({
const [registerForm, { setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 100,
schemas: accountFormSchema,
showActionButtonGroup: false,
......@@ -23,7 +26,7 @@
},
});
const [registerModal, { setModalProps }] = useModalInner((data) => {
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
......@@ -32,6 +35,18 @@
...data.record,
});
}
const treeData = await getDeptList();
updateSchema([
{
field: 'pwd',
show: !unref(isUpdate),
},
{
field: 'dept',
componentProps: { treeData },
},
]);
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增账号' : '编辑账号'));
......@@ -42,6 +57,7 @@
setModalProps({ confirmLoading: true });
// TODO custom api
console.log(values);
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
......
import { getAllRoleList } from '/@/api/demo/system';
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
......@@ -55,25 +56,52 @@ export const accountFormSchema: FormSchema[] = [
component: 'Input',
required: true,
},
{
field: 'pwd',
label: '密码',
component: 'InputPassword',
required: true,
show: true,
},
{
label: '角色',
field: 'role',
component: 'ApiSelect',
componentProps: {
api: getAllRoleList,
labelField: 'roleName',
valueField: 'roleValue',
},
required: true,
},
{
field: 'dept',
label: '所属部门',
component: 'TreeSelect',
componentProps: {
replaceFields: {
title: 'deptName',
key: 'id',
value: 'id',
},
getPopupContainer: () => document.body,
},
required: true,
},
{
field: 'nickname',
label: '昵称',
component: 'Input',
required: true,
},
{
label: '邮箱',
field: 'email',
component: 'Input',
required: true,
},
// TODO
{
label: '角色',
field: 'role',
component: 'Input',
required: true,
},
{
label: '备注',
field: 'remark',
......
......@@ -2,7 +2,7 @@
<div :class="[prefixCls]">
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="handleCreateAccount"> 新增账号 </a-button>
<a-button type="primary" @click="handleCreate"> 新增账号 </a-button>
</template>
<template #action="{ record }">
<TableAction
......@@ -23,7 +23,7 @@
/>
</template>
</BasicTable>
<AccountModal @register="registerModal" />
<AccountModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts">
......@@ -45,7 +45,7 @@
const { prefixCls } = useDesign('account-management');
const [registerModal, { openModal }] = useModal();
const [registerTable] = useTable({
const [registerTable, { reload }] = useTable({
title: '账号列表',
api: getAccountList,
columns,
......@@ -64,7 +64,7 @@
},
});
function handleCreateAccount() {
function handleCreate() {
openModal(true, {
isUpdate: false,
});
......@@ -81,13 +81,18 @@
console.log(record);
}
function handleSuccess() {
reload();
}
return {
prefixCls,
registerTable,
registerModal,
handleCreateAccount,
handleCreate,
handleEdit,
handleDelete,
handleSuccess,
};
},
});
......
......@@ -7,7 +7,18 @@
width="500px"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
<BasicForm @register="registerForm">
<template #menu="{ model, field }">
<BasicTree
v-model:value="model[field]"
:treeData="treeData"
:replaceFields="{ title: 'menuName', key: 'id' }"
checkable
toolbar
title="菜单分配"
/>
</template>
</BasicForm>
</BasicDrawer>
</template>
<script lang="ts">
......@@ -15,17 +26,19 @@
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from './role.data';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicTree, TreeItem } from '/@/components/Tree';
import { getMenuList } from '/@/api/demo/system';
export default defineComponent({
name: 'RoleDrawer',
components: { BasicDrawer, BasicForm },
components: { BasicDrawer, BasicForm, BasicTree },
emits: ['success', 'register'],
setup(_, { emit }) {
const isUpdate = ref(true);
const treeData = ref<TreeItem[]>([]);
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 90,
schemas: formSchema,
showActionButtonGroup: false,
......@@ -41,11 +54,7 @@
...data.record,
});
}
const treeData = await getMenuList();
updateSchema({
field: 'parentMenu',
componentProps: { treeData },
});
treeData.value = ((await getMenuList()) as any) as TreeItem[];
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色'));
......@@ -63,7 +72,13 @@
}
}
return { registerDrawer, registerForm, getTitle, handleSubmit };
return {
registerDrawer,
registerForm,
getTitle,
handleSubmit,
treeData,
};
},
});
</script>
......@@ -30,7 +30,7 @@
import { defineComponent } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { getRoleList } from '/@/api/demo/system';
import { getRoleListByPage } from '/@/api/demo/system';
import { useDrawer } from '/@/components/Drawer';
import RoleDrawer from './RoleDrawer.vue';
......@@ -44,7 +44,7 @@
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload }] = useTable({
title: '角色列表',
api: getRoleList,
api: getRoleListByPage,
columns,
formConfig: {
labelWidth: 120,
......
......@@ -2,7 +2,6 @@ import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns: BasicColumn[] = [
{
title: '角色名称',
......@@ -94,9 +93,9 @@ export const formSchema: FormSchema[] = [
component: 'InputTextArea',
},
{
label: '菜单分配',
label: ' ',
field: 'menu',
slot: 'menu',
component: 'Render',
component: 'Input',
},
];
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册