This commit is contained in:
JinMao 2021-08-25 10:04:54 +08:00
parent 44cda700e9
commit 5f62d64757
27 changed files with 5053 additions and 4679 deletions

View File

@ -1,5 +1,5 @@
# Whether to open mock
VITE_USE_MOCK = true
VITE_USE_MOCK = false
# public path
VITE_PUBLIC_PATH = /
@ -13,7 +13,7 @@ VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","http://localhos
VITE_DROP_CONSOLE = false
# Basic interface address SPA
VITE_GLOB_API_URL=/basic-api
VITE_GLOB_API_URL=http://localhost:10088/api
# File upload address optional
VITE_GLOB_UPLOAD_URL=/upload

View File

@ -1,6 +0,0 @@
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit "$1"

View File

@ -1,9 +0,0 @@
#!/bin/sh
command_exists () {
command -v "$1" >/dev/null 2>&1
}
# Workaround for Windows 10, Git Bash and Yarn
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

View File

@ -1,8 +0,0 @@
module.exports = {
'*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
'package.json': ['prettier --write'],
'*.vue': ['eslint --fix', 'prettier --write', 'stylelint --fix'],
'*.{scss,less,styl,html}': ['stylelint --fix', 'prettier --write'],
'*.md': ['prettier --write'],
};

View File

@ -1,10 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
[ -n "$CI" ] && exit 0
# Format and submit code according to lintstagedrc.js configuration
npm run lint:lint-staged
npm run lint:pretty

View File

@ -30,7 +30,6 @@
"test:gzip": "http-server dist --cors --gzip -c-1",
"test:br": "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": {

3
src/api/Curd.ts Normal file
View File

@ -0,0 +1,3 @@
import { defHttp } from '/@/utils/http/axios';
export const Curd = (params) => defHttp.post({ url: '/curd', params });

View File

@ -15,7 +15,7 @@ import { defHttp } from '/@/utils/http/axios';
enum Api {
AccountList = '/system/getAccountList',
IsAccountExist = '/system/accountExist',
DeptList = '/system/getDeptList',
DeptList = 'https://open.ys7.com/api/lapp/device/list',
setRoleStatus = '/system/setRoleStatus',
MenuList = '/system/getMenuList',
RolePageList = '/system/getRoleListByPage',
@ -26,7 +26,7 @@ export const getAccountList = (params: AccountParams) =>
defHttp.get<AccountListGetResultModel>({ url: Api.AccountList, params });
export const getDeptList = (params?: DeptListItem) =>
defHttp.get<DeptListGetResultModel>({ url: Api.DeptList, params });
defHttp.post<DeptListGetResultModel>({ url: Api.DeptList, params });
export const getMenuList = (params?: MenuParams) =>
defHttp.get<MenuListGetResultModel>({ url: Api.MenuList, params });

View File

@ -2,7 +2,7 @@ import { defHttp } from '/@/utils/http/axios';
import { getMenuListResultModel } from './model/menuModel';
enum Api {
GetMenuList = '/getMenuList',
GetMenuList = '/router/list',
}
/**

View File

@ -1,9 +1,5 @@
import { defHttp } from '/@/utils/http/axios';
import {
LoginParams,
GetUserInfoByUserIdParams,
GetUserInfoByUserIdModel,
} from './model/userModel';
import { LoginParams, GetUserInfoModel } from './model/userModel';
import { ErrorMessageMode } from '/#/axios';
@ -25,6 +21,7 @@ export function loginApi(params: LoginParams, mode: ErrorMessageMode = 'modal')
},
{
errorMessageMode: mode,
apiUrl: 'http://localhost:10088',
},
);
}

View File

@ -66,6 +66,7 @@ export function transformRouteToMenu(routeModList: AppRouteModule[], routerMappi
};
},
});
joinParentPath(list);
return cloneDeep(list);
}

View File

@ -24,7 +24,7 @@ const setting: ProjectConfig = {
settingButtonPosition: SettingButtonPositionEnum.AUTO,
// Permission mode
permissionMode: PermissionModeEnum.ROUTE_MAPPING,
permissionMode: PermissionModeEnum.BACK,
// Permission-related cache is stored in sessionStorage or localStorage
permissionCacheType: CacheTypeEnum.LOCAL,

View File

@ -184,7 +184,7 @@ export const usePermissionStore = defineStore({
// this function may only need to be executed once, and the actual project can be put at the right time by itself
let routeList: AppRouteRecordRaw[] = [];
try {
this.changePermissionCode();
// this.changePermissionCode();
routeList = (await getMenuList()) as AppRouteRecordRaw[];
} catch (error) {
console.error(error);

View File

@ -83,13 +83,13 @@ export class VAxios {
const {
headers: { ignoreCancelToken },
} = config;
const ignoreCancel =
ignoreCancelToken !== undefined
? ignoreCancelToken
: this.options.requestOptions?.ignoreCancelToken;
!ignoreCancel && axiosCanceler.addPending(config);
if (requestInterceptors && isFunction(requestInterceptors)) {
config = requestInterceptors(config, this.options);
}

View File

@ -52,8 +52,18 @@ const transform: AxiosTransform = {
// 这里逻辑可以根据项目进行修改
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
if (!hasSuccess) {
if (hasSuccess) {
if (message) {
notification.success({ message });
}
return result;
}
checkStatus(code, message, options.errorMessageMode);
// if (options.errorMessageMode === 'modal') {
// createErrorModal({ title: t('sys.api.errorTip'), content: message });
// } else if (options.errorMessageMode === 'message') {
// createMessage.error(message);
// }
// errorMessageMode=modal的时候会显示modal错误弹窗而不是消息提示用于一些比较重要的错误
if (options.errorMessageMode === 'modal') {
createErrorModal({ title: t('sys.api.errorTip'), content: message });
@ -63,38 +73,8 @@ const transform: AxiosTransform = {
}
Promise.reject(new Error(message));
return message;
}
// 接口请求成功,直接返回结果
if (code === ResultEnum.SUCCESS) {
if (message) {
notification.success({ message });
}
return result;
}
// 接口请求错误,统一提示错误信息
if (code === ResultEnum.ERROR) {
if (message) {
createMessage.error(data.message);
Promise.reject(new Error(message));
} else {
const msg = t('sys.api.errorMessage');
createMessage.error(msg);
Promise.reject(new Error(msg));
}
throw new Error( t('sys.api.apiRequestFailed'));
}
// 登录超时
if (code === ResultEnum.TIMEOUT) {
const timeoutMsg = t('sys.api.timeoutMessage');
createErrorModal({
title: t('sys.api.operationFailed'),
content: timeoutMsg,
});
Promise.reject(new Error(timeoutMsg));
return message;
}
return message;
},
// 请求之前处理config
@ -174,6 +154,7 @@ const transform: AxiosTransform = {
responseInterceptorsCatch: (error: any) => {
const { t } = useI18n();
const errorLogStore = useErrorLogStoreWithOut();
errorLogStore.addAjaxErrorInfo(error);
const { response, code, message, config } = error || {};
const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none';
@ -212,8 +193,8 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
{
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
// authentication schemese.g: Bearer
// authenticationScheme: 'Bearer',
authenticationScheme: 'Bearer',
// authenticationScheme: '',
timeout: 10 * 1000,
// 基础接口地址
// baseURL: globSetting.apiUrl,

View File

@ -1,5 +1,6 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
{{ formRef }}
<BasicForm @register="registerForm" />
</BasicModal>
</template>
@ -16,10 +17,11 @@
emits: ['success', 'register'],
setup(_, { emit }) {
const isUpdate = ref(true);
const formRef = ref();
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
model: formRef,
showActionButtonGroup: false,
});
@ -55,7 +57,7 @@
}
}
return { registerModal, registerForm, getTitle, handleSubmit };
return { registerModal, registerForm, getTitle, handleSubmit, formRef };
},
});
</script>

View File

@ -0,0 +1,60 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from './dept.data';
import { getDeptList } from '/@/api/demo/system';
export default defineComponent({
name: 'DeptModal',
components: { BasicModal, BasicForm },
emits: ['success', 'register'],
setup(_, { emit }) {
const isUpdate = ref(true);
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
});
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
setFieldsValue({
...data.record,
});
}
// const treeData = await getDeptList();
// updateSchema({
// field: 'parentDept',
// componentProps: { treeData },
// });
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增部门' : '编辑部门'));
async function handleSubmit() {
// try {
// const values = await validate();
// setModalProps({ confirmLoading: true });
// // TODO custom api
// console.log(values);
// closeModal();
// emit('success');
// } finally {
// setModalProps({ confirmLoading: false });
// }
}
return { registerModal, registerForm, getTitle, handleSubmit };
},
});
</script>

108
src/views/dept/dept.data.ts Normal file
View File

@ -0,0 +1,108 @@
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: '部门名称',
dataIndex: 'deptName',
width: 160,
align: 'left',
},
{
title: '排序',
dataIndex: 'orderNo',
width: 50,
},
{
title: '状态',
dataIndex: 'status',
width: 80,
customRender: ({ record }) => {
const status = record.status;
const enable = ~~status === 0;
const color = enable ? 'green' : 'red';
const text = enable ? '启用' : '停用';
return h(Tag, { color: color }, () => text);
},
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
{
title: '备注',
dataIndex: 'remark',
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'deptName',
label: '部门名称',
component: 'Input',
colProps: { span: 8 },
},
{
field: 'status',
label: '状态',
component: 'Select',
componentProps: {
options: [
{ label: '启用', value: '0' },
{ label: '停用', value: '1' },
],
},
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'deptName',
label: '部门名称',
component: 'Input',
required: true,
},
{
field: 'parentDept',
label: '上级部门',
component: 'TreeSelect',
componentProps: {
replaceFields: {
title: 'deptName',
key: 'id',
value: 'id',
},
getPopupContainer: () => document.body,
},
required: true,
},
{
field: 'orderNo',
label: '排序',
component: 'InputNumber',
required: true,
},
{
field: 'status',
label: '状态',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '启用', value: '0' },
{ label: '停用', value: '1' },
],
},
required: true,
},
{
label: '备注',
field: 'remark',
component: 'InputTextArea',
},
];

100
src/views/dept/index.vue Normal file
View File

@ -0,0 +1,100 @@
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="handleCreate"> 新增部门 </a-button>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
icon: 'clarity:note-edit-line',
onClick: handleEdit.bind(null, record),
},
{
icon: 'ant-design:delete-outlined',
color: 'error',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</BasicTable>
<DeptModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { getDeptList } from '/@/api/demo/system';
import { useModal } from '/@/components/Modal';
import DeptModal from './DeptModal.vue';
import { columns, searchFormSchema } from './dept.data';
export default defineComponent({
name: 'DeptManagement',
components: { BasicTable, DeptModal, TableAction },
setup() {
const [registerModal, { openModal }] = useModal();
const [registerTable, { reload }] = useTable({
title: '部门列表',
api: getDeptList,
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
pagination: false,
striped: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
canResize: false,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
});
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
});
}
function handleDelete(record: Recordable) {
console.log(record);
}
function handleSuccess() {
reload();
}
return {
registerTable,
registerModal,
handleCreate,
handleEdit,
handleDelete,
handleSuccess,
};
},
});
</script>

View File

@ -0,0 +1,70 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
showFooter
:title="getTitle"
width="50%"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts">
import { defineComponent, ref, computed, unref } from 'vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from './menu.data';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { getMenuList } from '/@/api/demo/system';
export default defineComponent({
name: 'MenuDrawer',
components: { BasicDrawer, BasicForm },
emits: ['success', 'register'],
setup(_, { emit }) {
const isUpdate = ref(true);
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { lg: 12, md: 24 },
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
resetFields();
setDrawerProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
setFieldsValue({
...data.record,
});
}
const treeData = await getMenuList();
updateSchema({
field: 'parentMenu',
componentProps: { treeData },
});
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增菜单' : '编辑菜单'));
async function handleSubmit() {
try {
const values = await validate();
setDrawerProps({ confirmLoading: true });
// TODO custom api
console.log(values);
closeDrawer();
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
return { registerDrawer, registerForm, getTitle, handleSubmit };
},
});
</script>

104
src/views/menu/index.vue Normal file
View File

@ -0,0 +1,104 @@
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="handleCreate"> 新增菜单 </a-button>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
icon: 'clarity:note-edit-line',
onClick: handleEdit.bind(null, record),
},
{
icon: 'ant-design:delete-outlined',
color: 'error',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</BasicTable>
<MenuDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useDrawer } from '/@/components/Drawer';
import MenuDrawer from './MenuDrawer.vue';
import { columns, searchFormSchema } from './menu.data';
import { Curd } from '/@/api/Curd';
export default defineComponent({
name: 'MenuManagement',
components: { BasicTable, MenuDrawer, TableAction },
setup() {
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload }] = useTable({
title: '菜单列表',
api: Curd,
beforeFetch: (v) => {
v.i = 'router';
v.a = 'list';
return v;
},
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
pagination: false,
striped: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
canResize: false,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
});
function handleCreate() {
openDrawer(true, {
isUpdate: false,
});
}
function handleEdit(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
});
}
function handleDelete(record: Recordable) {
console.log(record);
}
function handleSuccess() {
reload();
}
return {
registerTable,
registerDrawer,
handleCreate,
handleEdit,
handleDelete,
handleSuccess,
};
},
});
</script>

202
src/views/menu/menu.data.ts Normal file
View File

@ -0,0 +1,202 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
import { Icon } from '/@/components/Icon';
export const columns: BasicColumn[] = [
{
title: '菜单名称',
dataIndex: 'name',
width: 200,
align: 'left',
},
{
title: '图标',
dataIndex: 'icon',
width: 50,
customRender: ({ record }) => {
return h(Icon, { icon: record.meta.icon });
},
},
{
title: '权限标识',
dataIndex: 'permission',
width: 180,
},
{
title: '组件',
dataIndex: 'component',
},
{
title: '排序',
dataIndex: 'orderNo',
width: 50,
},
{
title: '状态',
dataIndex: 'status',
width: 80,
customRender: ({ record }) => {
const status = record.status;
const enable = ~~status === 1;
const color = enable ? 'green' : 'red';
const text = enable ? '启用' : '停用';
return h(Tag, { color: color }, () => text);
},
},
{
title: '创建时间',
dataIndex: 'create_at',
width: 180,
},
];
const isDir = (type: string) => type === '0';
const isMenu = (type: string) => type === '1';
const isButton = (type: string) => type === '2';
export const searchFormSchema: FormSchema[] = [
{
field: 'menuName',
label: '菜单名称',
component: 'Input',
colProps: { span: 8 },
},
{
field: 'status',
label: '状态',
component: 'Select',
componentProps: {
options: [
{ label: '启用', value: '0' },
{ label: '停用', value: '1' },
],
},
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'type',
label: '菜单类型',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '目录', value: '0' },
{ label: '菜单', value: '1' },
{ label: '按钮', value: '2' },
],
},
colProps: { lg: 24, md: 24 },
},
{
field: 'menuName',
label: '菜单名称',
component: 'Input',
required: true,
},
{
field: 'parentMenu',
label: '上级菜单',
component: 'TreeSelect',
componentProps: {
replaceFields: {
title: 'menuName',
key: 'id',
value: 'id',
},
getPopupContainer: () => document.body,
},
},
{
field: 'orderNo',
label: '排序',
component: 'InputNumber',
required: true,
},
{
field: 'icon',
label: '图标',
component: 'IconPicker',
required: true,
show: ({ values }) => !isButton(values.type),
},
{
field: 'routePath',
label: '路由地址',
component: 'Input',
required: true,
show: ({ values }) => !isButton(values.type),
},
{
field: 'component',
label: '组件路径',
component: 'Input',
show: ({ values }) => isMenu(values.type),
},
{
field: 'permission',
label: '权限标识',
component: 'Input',
show: ({ values }) => !isDir(values.type),
},
{
field: 'status',
label: '状态',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '启用', value: '0' },
{ label: '禁用', value: '1' },
],
},
},
{
field: 'isExt',
label: '是否外链',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '否', value: '0' },
{ label: '是', value: '1' },
],
},
show: ({ values }) => !isButton(values.type),
},
{
field: 'keepalive',
label: '是否缓存',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '否', value: '0' },
{ label: '是', value: '1' },
],
},
show: ({ values }) => isMenu(values.type),
},
{
field: 'show',
label: '是否显示',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '是', value: '0' },
{ label: '否', value: '1' },
],
},
show: ({ values }) => !isButton(values.type),
},
];

View File

@ -0,0 +1,84 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
showFooter
:title="getTitle"
width="500px"
@ok="handleSubmit"
>
<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">
import { defineComponent, ref, computed, unref } from 'vue';
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, BasicTree },
emits: ['success', 'register'],
setup(_, { emit }) {
const isUpdate = ref(true);
const treeData = ref<TreeItem[]>([]);
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 90,
schemas: formSchema,
showActionButtonGroup: false,
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
resetFields();
setDrawerProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
setFieldsValue({
...data.record,
});
}
treeData.value = (await getMenuList()) as any as TreeItem[];
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色'));
async function handleSubmit() {
try {
const values = await validate();
setDrawerProps({ confirmLoading: true });
// TODO custom api
console.log(values);
closeDrawer();
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
return {
registerDrawer,
registerForm,
getTitle,
handleSubmit,
treeData,
};
},
});
</script>

101
src/views/role/index.vue Normal file
View File

@ -0,0 +1,101 @@
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button type="primary" @click="handleCreate"> 新增角色 </a-button>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
icon: 'clarity:note-edit-line',
onClick: handleEdit.bind(null, record),
},
{
icon: 'ant-design:delete-outlined',
color: 'error',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</BasicTable>
<RoleDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useDrawer } from '/@/components/Drawer';
import RoleDrawer from './RoleDrawer.vue';
import { columns, searchFormSchema } from './role.data';
import { Curd } from '/@/api/Curd';
export default defineComponent({
name: 'RoleManagement',
components: { BasicTable, RoleDrawer, TableAction },
setup() {
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload }] = useTable({
title: '角色列表',
api: Curd,
beforeFetch: (v) => {
v.i = 'role';
v.a = 'list';
return v;
},
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
});
function handleCreate() {
openDrawer(true, {
isUpdate: false,
});
}
function handleEdit(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
});
}
function handleDelete(record: Recordable) {
console.log(record);
}
function handleSuccess() {
reload();
}
return {
registerTable,
registerDrawer,
handleCreate,
handleEdit,
handleDelete,
handleSuccess,
};
},
});
</script>

View File

@ -0,0 +1,69 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
export const columns: BasicColumn[] = [
{
title: '角色名称',
dataIndex: 'name',
width: 200,
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'roleNme',
label: '角色名称',
component: 'Input',
colProps: { span: 8 },
},
{
field: 'status',
label: '状态',
component: 'Select',
componentProps: {
options: [
{ label: '启用', value: '0' },
{ label: '停用', value: '1' },
],
},
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'roleName',
label: '角色名称',
required: true,
component: 'Input',
},
{
field: 'roleValue',
label: '角色值',
required: true,
component: 'Input',
},
{
field: 'status',
label: '状态',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '启用', value: '0' },
{ label: '停用', value: '1' },
],
},
},
{
label: '备注',
field: 'remark',
component: 'InputTextArea',
},
{
label: ' ',
field: 'menu',
slot: 'menu',
component: 'Input',
},
];

View File

@ -1,8 +1,20 @@
<template>
<LoginFormTitle v-show="getShow" class="enter-x" />
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow">
<Form
class="p-4 enter-x"
:model="formData"
:rules="getFormRules"
ref="formRef"
v-show="getShow"
@keypress.enter="handleLogin"
>
<FormItem name="account" class="enter-x">
<Input size="large" v-model:value="formData.account" :placeholder="t('sys.login.userName')" />
<Input
size="large"
v-model:value="formData.account"
:placeholder="t('sys.login.userName')"
class="fix-auto-fill"
/>
</FormItem>
<FormItem name="password" class="enter-x">
<InputPassword
@ -107,7 +119,7 @@
const rememberMe = ref(false);
const formData = reactive({
account: 'vben',
account: 'admin',
password: '123456',
});

8702
yarn.lock

File diff suppressed because it is too large Load Diff