Commit 37669d067c43a3807df848f0caf67cbeab3e1b33

Authored by Vben
1 parent c8e84dc1

wip: add account management page

mock/demo/system.ts 0 → 100644
  1 +import { MockMethod } from 'vite-plugin-mock';
  2 +import { resultPageSuccess } from '../_util';
  3 +
  4 +const list = (() => {
  5 + const result: any[] = [];
  6 + for (let index = 0; index < 20; index++) {
  7 + result.push({
  8 + id: `${index}`,
  9 + account: '@first',
  10 + email: '@email',
  11 + nickname: '@cname()',
  12 + role: '@first',
  13 + updateTime: '@datetime',
  14 + remark: '@cword(0,20)',
  15 + });
  16 + }
  17 + return result;
  18 +})();
  19 +
  20 +export default [
  21 + {
  22 + url: '/api/system/getAccountList',
  23 + timeout: 100,
  24 + method: 'get',
  25 + response: ({ query }) => {
  26 + const { page = 1, pageSize = 20 } = query;
  27 + return resultPageSuccess(page, pageSize, list);
  28 + },
  29 + },
  30 +] as MockMethod[];
mock/demo/table-demo.ts
@@ -28,7 +28,7 @@ const demoList = (() =&gt; { @@ -28,7 +28,7 @@ const demoList = (() =&gt; {
28 export default [ 28 export default [
29 { 29 {
30 url: '/api/table/getDemoList', 30 url: '/api/table/getDemoList',
31 - timeout: 1000, 31 + timeout: 100,
32 method: 'get', 32 method: 'get',
33 response: ({ query }) => { 33 response: ({ query }) => {
34 const { page = 1, pageSize = 20 } = query; 34 const { page = 1, pageSize = 20 } = query;
src/api/demo/model/systemModel.ts 0 → 100644
  1 +import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
  2 +
  3 +export type Params = BasicPageParams & {
  4 + account?: string;
  5 + nickname?: string;
  6 +};
  7 +
  8 +export interface DemoListItem {
  9 + id: string;
  10 + account: string;
  11 + email: string;
  12 + nickname: string;
  13 + role: number;
  14 + updateTime: string;
  15 + remark: string;
  16 +}
  17 +
  18 +/**
  19 + * @description: Request list return value
  20 + */
  21 +export type DemoListGetResultModel = BasicFetchResult<DemoListItem>;
src/api/demo/system.ts 0 → 100644
  1 +import { Params, DemoListGetResultModel } from './model/systemModel';
  2 +import { defHttp } from '/@/utils/http/axios';
  3 +
  4 +enum Api {
  5 + // The address does not exist
  6 + AccountList = '/system/getAccountList',
  7 +}
  8 +
  9 +export const getAccountList = (params: Params) =>
  10 + defHttp.get<DemoListGetResultModel>({ url: Api.AccountList, params });
src/components/Table/src/style/index.less
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 4
5 .@{prefix-cls} { 5 .@{prefix-cls} {
6 &-form-container { 6 &-form-container {
  7 + width: 100%;
7 padding: 16px; 8 padding: 16px;
8 9
9 .ant-form { 10 .ant-form {
@@ -50,8 +51,8 @@ @@ -50,8 +51,8 @@
50 51
51 // 52 //
52 .ant-table { 53 .ant-table {
53 - // width: 100%;  
54 - // overflow-x: hidden; 54 + width: 100%;
  55 + overflow-x: hidden;
55 // border: none; 56 // border: none;
56 57
57 &-title { 58 &-title {
@@ -159,15 +160,15 @@ @@ -159,15 +160,15 @@
159 // overflow-y: hidden !important; 160 // overflow-y: hidden !important;
160 // } 161 // }
161 162
162 - // .ant-table-fixed {  
163 - // border-bottom: none;  
164 - // } 163 + // .ant-table-fixed {
  164 + // border-bottom: none;
  165 + // }
165 // } 166 // }
166 167
167 // .ant-table-bordered .ant-table-thead > tr:not(:last-child) > th, 168 // .ant-table-bordered .ant-table-thead > tr:not(:last-child) > th,
168 // .ant-table-tbody > tr > td { 169 // .ant-table-tbody > tr > td {
169 // word-break: break-word; 170 // word-break: break-word;
170 - // border-color: @border-color !important; 171 + // // border-color: @border-color !important;
171 // } 172 // }
172 173
173 .ant-table-footer { 174 .ant-table-footer {
src/locales/lang/en/routes/demo/system.ts 0 → 100644
  1 +export default {
  2 + moduleName: 'System management',
  3 +
  4 + account: 'Account management',
  5 +};
src/locales/lang/zh_CN/routes/demo/system.ts 0 → 100644
  1 +export default {
  2 + moduleName: '系统管理',
  3 +
  4 + account: '账号管理',
  5 +};
src/router/menus/modules/demo/system.ts 0 → 100644
  1 +import type { MenuModule } from '/@/router/types';
  2 +import { t } from '/@/hooks/web/useI18n';
  3 +
  4 +const menu: MenuModule = {
  5 + orderNo: 2000,
  6 + menu: {
  7 + name: t('routes.demo.system.moduleName'),
  8 + path: '/system',
  9 + children: [
  10 + {
  11 + path: 'account',
  12 + name: t('routes.demo.system.account'),
  13 + },
  14 + ],
  15 + },
  16 +};
  17 +export default menu;
src/router/routes/modules/dashboard.ts
@@ -9,7 +9,7 @@ const dashboard: AppRouteModule = { @@ -9,7 +9,7 @@ const dashboard: AppRouteModule = {
9 component: LAYOUT, 9 component: LAYOUT,
10 redirect: '/dashboard/workbench', 10 redirect: '/dashboard/workbench',
11 meta: { 11 meta: {
12 - icon: 'bx:bx-home', 12 + icon: 'ion:grid-outline',
13 title: t('routes.dashboard.dashboard'), 13 title: t('routes.dashboard.dashboard'),
14 }, 14 },
15 children: [ 15 children: [
src/router/routes/modules/demo/charts.ts
@@ -9,7 +9,7 @@ const charts: AppRouteModule = { @@ -9,7 +9,7 @@ const charts: AppRouteModule = {
9 component: LAYOUT, 9 component: LAYOUT,
10 redirect: '/charts/apexChart', 10 redirect: '/charts/apexChart',
11 meta: { 11 meta: {
12 - icon: 'vaadin:spline-area-chart', 12 + icon: 'ion:bar-chart-outline',
13 title: t('routes.demo.charts.charts'), 13 title: t('routes.demo.charts.charts'),
14 }, 14 },
15 children: [ 15 children: [
src/router/routes/modules/demo/comp.ts
@@ -9,7 +9,7 @@ const comp: AppRouteModule = { @@ -9,7 +9,7 @@ const comp: AppRouteModule = {
9 component: LAYOUT, 9 component: LAYOUT,
10 redirect: '/comp/basic', 10 redirect: '/comp/basic',
11 meta: { 11 meta: {
12 - icon: 'ic:outline-settings-input-component', 12 + icon: 'ion:layers-outline',
13 title: t('routes.demo.comp.comp'), 13 title: t('routes.demo.comp.comp'),
14 }, 14 },
15 15
src/router/routes/modules/demo/feat.ts
@@ -9,7 +9,7 @@ const feat: AppRouteModule = { @@ -9,7 +9,7 @@ const feat: AppRouteModule = {
9 component: LAYOUT, 9 component: LAYOUT,
10 redirect: '/feat/icon', 10 redirect: '/feat/icon',
11 meta: { 11 meta: {
12 - icon: 'ic:outline-featured-play-list', 12 + icon: 'ion:git-compare-outline',
13 title: t('routes.demo.feat.feat'), 13 title: t('routes.demo.feat.feat'),
14 }, 14 },
15 children: [ 15 children: [
src/router/routes/modules/demo/iframe.ts
@@ -10,7 +10,7 @@ const iframe: AppRouteModule = { @@ -10,7 +10,7 @@ const iframe: AppRouteModule = {
10 component: LAYOUT, 10 component: LAYOUT,
11 redirect: '/frame/doc', 11 redirect: '/frame/doc',
12 meta: { 12 meta: {
13 - icon: 'mdi:page-next-outline', 13 + icon: 'ion:tv-outline',
14 title: t('routes.demo.iframe.frame'), 14 title: t('routes.demo.iframe.frame'),
15 }, 15 },
16 16
src/router/routes/modules/demo/level.ts
@@ -9,7 +9,7 @@ const permission: AppRouteModule = { @@ -9,7 +9,7 @@ const permission: AppRouteModule = {
9 component: LAYOUT, 9 component: LAYOUT,
10 redirect: '/level/menu1/menu1-1/menu1-1-1', 10 redirect: '/level/menu1/menu1-1/menu1-1-1',
11 meta: { 11 meta: {
12 - icon: 'carbon:user-role', 12 + icon: 'ion:menu-outline',
13 title: t('routes.demo.level.level'), 13 title: t('routes.demo.level.level'),
14 }, 14 },
15 15
src/router/routes/modules/demo/page.ts
@@ -12,7 +12,7 @@ const page: AppRouteModule = { @@ -12,7 +12,7 @@ const page: AppRouteModule = {
12 component: LAYOUT, 12 component: LAYOUT,
13 redirect: '/page-demo/exception', 13 redirect: '/page-demo/exception',
14 meta: { 14 meta: {
15 - icon: 'mdi:page-next-outline', 15 + icon: 'ion:aperture-outline',
16 title: t('routes.demo.page.page'), 16 title: t('routes.demo.page.page'),
17 }, 17 },
18 children: [ 18 children: [
src/router/routes/modules/demo/permission.ts
@@ -10,7 +10,7 @@ const permission: AppRouteModule = { @@ -10,7 +10,7 @@ const permission: AppRouteModule = {
10 component: LAYOUT, 10 component: LAYOUT,
11 redirect: '/permission/front/page', 11 redirect: '/permission/front/page',
12 meta: { 12 meta: {
13 - icon: 'carbon:user-role', 13 + icon: 'ion:key-outline',
14 title: t('routes.demo.permission.permission'), 14 title: t('routes.demo.permission.permission'),
15 }, 15 },
16 16
src/router/routes/modules/demo/system.ts 0 → 100644
  1 +import type { AppRouteModule } from '/@/router/types';
  2 +
  3 +import { LAYOUT } from '/@/router/constant';
  4 +import { t } from '/@/hooks/web/useI18n';
  5 +
  6 +const system: AppRouteModule = {
  7 + path: '/system',
  8 + name: 'System',
  9 + component: LAYOUT,
  10 + redirect: '/system/account',
  11 + meta: {
  12 + icon: 'ion:settings-outline',
  13 + title: t('routes.demo.system.moduleName'),
  14 + },
  15 + children: [
  16 + {
  17 + path: 'account',
  18 + name: 'Account',
  19 + meta: {
  20 + title: t('routes.demo.system.account'),
  21 + },
  22 + component: () => import('/@/views/demo/system/account/index.vue'),
  23 + },
  24 + ],
  25 +};
  26 +
  27 +export default system;
src/router/routes/modules/home.ts
@@ -9,7 +9,7 @@ const dashboard: AppRouteModule = { @@ -9,7 +9,7 @@ const dashboard: AppRouteModule = {
9 component: LAYOUT, 9 component: LAYOUT,
10 redirect: '/home/welcome', 10 redirect: '/home/welcome',
11 meta: { 11 meta: {
12 - icon: 'bx:bx-home', 12 + icon: 'ion:home-outline',
13 title: t('routes.dashboard.welcome'), 13 title: t('routes.dashboard.welcome'),
14 }, 14 },
15 children: [ 15 children: [
src/views/biz/.gitkeep deleted 100644 → 0
src/views/demo/.gitkeep deleted 100644 → 0
src/views/demo/system/account/AccountModal.vue 0 → 100644
  1 +<template>
  2 + <BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
  3 + <BasicForm @register="registerForm" />
  4 + </BasicModal>
  5 +</template>
  6 +<script lang="ts">
  7 + import { defineComponent, ref, computed, unref } from 'vue';
  8 + import { BasicModal, useModalInner } from '/@/components/Modal';
  9 + import { BasicForm, useForm } from '/@/components/Form/index';
  10 + import { accountFormSchema } from './account.data';
  11 + export default defineComponent({
  12 + name: 'AccountModal',
  13 + components: { BasicModal, BasicForm },
  14 + setup() {
  15 + const isUpdate = ref(true);
  16 +
  17 + const [registerForm, { setFieldsValue, validate }] = useForm({
  18 + labelWidth: 100,
  19 + schemas: accountFormSchema,
  20 + showActionButtonGroup: false,
  21 + actionColOptions: {
  22 + span: 23,
  23 + },
  24 + });
  25 +
  26 + const [registerModal, { setModalProps }] = useModalInner((data) => {
  27 + isUpdate.value = !!data?.isUpdate;
  28 +
  29 + if (unref(isUpdate)) {
  30 + setFieldsValue({
  31 + ...data.record,
  32 + });
  33 + }
  34 + });
  35 +
  36 + const getTitle = computed(() => (!unref(isUpdate) ? '新增账号' : '编辑账号'));
  37 +
  38 + async function handleSubmit() {
  39 + try {
  40 + const values = await validate();
  41 + setModalProps({ confirmLoading: true });
  42 + // TODO custom api
  43 + console.log(values);
  44 + } finally {
  45 + setModalProps({ confirmLoading: true });
  46 + }
  47 + }
  48 +
  49 + return { registerModal, registerForm, getTitle, handleSubmit };
  50 + },
  51 + });
  52 +</script>
src/views/demo/system/account/account.data.ts 0 → 100644
  1 +import { BasicColumn } from '/@/components/Table';
  2 +import { FormSchema } from '/@/components/Table';
  3 +
  4 +export const columns: BasicColumn[] = [
  5 + {
  6 + title: 'ID',
  7 + dataIndex: 'id',
  8 + width: 80,
  9 + },
  10 + {
  11 + title: '用户名',
  12 + dataIndex: 'account',
  13 + width: 120,
  14 + },
  15 + {
  16 + title: '昵称',
  17 + dataIndex: 'nickname',
  18 + width: 120,
  19 + },
  20 + {
  21 + title: '邮箱',
  22 + dataIndex: 'email',
  23 + width: 200,
  24 + },
  25 + {
  26 + title: '更新时间',
  27 + dataIndex: 'updateTime',
  28 + width: 180,
  29 + },
  30 + {
  31 + title: '角色',
  32 + dataIndex: 'role',
  33 + width: 200,
  34 + },
  35 + {
  36 + title: '备注',
  37 + dataIndex: 'remark',
  38 + width: 200,
  39 + },
  40 +];
  41 +
  42 +export const searchFormSchema: FormSchema[] = [
  43 + {
  44 + field: 'account',
  45 + label: '用户名',
  46 + component: 'Input',
  47 + colProps: { span: 8 },
  48 + },
  49 + {
  50 + field: 'nickname',
  51 + label: '昵称',
  52 + component: 'Input',
  53 + colProps: { span: 8 },
  54 + },
  55 +];
  56 +
  57 +export const accountFormSchema: FormSchema[] = [
  58 + {
  59 + field: 'account',
  60 + label: '用户名',
  61 + component: 'Input',
  62 + required: true,
  63 + },
  64 + {
  65 + field: 'nickname',
  66 + label: '昵称',
  67 + component: 'Input',
  68 + required: true,
  69 + },
  70 + {
  71 + label: '邮箱',
  72 + field: 'email',
  73 + component: 'Input',
  74 + required: true,
  75 + },
  76 + // TODO
  77 + {
  78 + label: '角色',
  79 + field: 'role',
  80 + component: 'Input',
  81 + required: true,
  82 + },
  83 + {
  84 + label: '备注',
  85 + field: 'remark',
  86 + component: 'InputTextArea',
  87 + },
  88 +];
src/views/demo/system/account/index.vue 0 → 100644
  1 +<template>
  2 + <div :class="[prefixCls]">
  3 + <BasicTable @register="registerTable">
  4 + <template #toolbar>
  5 + <a-button type="primary" @click="handleCreateAccount"> 新增账号 </a-button>
  6 + </template>
  7 + <template #action="{ record }">
  8 + <TableAction
  9 + :actions="[
  10 + {
  11 + label: '编辑',
  12 + onClick: handleEdit.bind(null, record),
  13 + },
  14 + {
  15 + label: '删除',
  16 + color: 'error',
  17 + popConfirm: {
  18 + title: '是否确认删除',
  19 + confirm: handleDelete.bind(null, record),
  20 + },
  21 + },
  22 + ]"
  23 + />
  24 + </template>
  25 + </BasicTable>
  26 + <AccountModal @register="registerModal" />
  27 + </div>
  28 +</template>
  29 +<script lang="ts">
  30 + import { defineComponent } from 'vue';
  31 +
  32 + import { useDesign } from '/@/hooks/web/useDesign';
  33 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  34 + import { getAccountList } from '/@/api/demo/system';
  35 +
  36 + import { useModal } from '/@/components/Modal';
  37 + import AccountModal from './AccountModal.vue';
  38 +
  39 + import { columns, searchFormSchema } from './account.data';
  40 +
  41 + export default defineComponent({
  42 + name: 'AccountManagement',
  43 + components: { BasicTable, AccountModal, TableAction },
  44 + setup() {
  45 + const { prefixCls } = useDesign('account-management');
  46 +
  47 + const [registerModal, { openModal }] = useModal();
  48 + const [registerTable] = useTable({
  49 + title: '账号列表',
  50 + api: getAccountList,
  51 + columns,
  52 + formConfig: {
  53 + labelWidth: 120,
  54 + schemas: searchFormSchema,
  55 + },
  56 + useSearchForm: true,
  57 + showTableSetting: true,
  58 + actionColumn: {
  59 + width: 160,
  60 + title: '操作',
  61 + dataIndex: 'action',
  62 + slots: { customRender: 'action' },
  63 + },
  64 + });
  65 +
  66 + function handleCreateAccount() {
  67 + openModal(true, {
  68 + isUpdate: false,
  69 + });
  70 + }
  71 +
  72 + function handleEdit(record: Recordable) {
  73 + openModal(true, {
  74 + record,
  75 + isUpdate: true,
  76 + });
  77 + }
  78 +
  79 + function handleDelete(record: Recordable) {
  80 + console.log(record);
  81 + }
  82 +
  83 + return {
  84 + prefixCls,
  85 + registerTable,
  86 + registerModal,
  87 + handleCreateAccount,
  88 + handleEdit,
  89 + handleDelete,
  90 + };
  91 + },
  92 + });
  93 +</script>
  94 +<style lang="less" scoped>
  95 + @prefix-cls: ~'@{namespace}-account-management';
  96 +
  97 + .@{prefix-cls} {
  98 + display: flex;
  99 + }
  100 +</style>