提交角色管理

This commit is contained in:
2024-01-24 23:12:44 +08:00
parent 88ee84d9f6
commit 543f3a50d9
26 changed files with 1129 additions and 683 deletions

34
src/api/region.ts Normal file
View File

@ -0,0 +1,34 @@
import axios from 'axios';
export interface ListRegion {
id: undefined;
remark: string;
createTime: string;
name: string;
enabled: string;
}
// 获取区域列表
export function regionList(data: any) {
return axios.get<ListRegion>(`/api/rest/dept?name=${data.name}&`, data);
}
// 添加区域
export function createRegion(data: ListRegion) {
return axios.post<ListRegion>('/api/rest/dept', data);
}
// 更新区域信息
export function updateRegion(data: ListRegion) {
return axios.patch(`/api/rest/dept/${data.id}`, data);
}
// 删除区域
export function removeRegion(id: string) {
return axios.delete(`/api/rest/dept/${id}`);
}
// 启用状态
export function enabledRegion(id: string) {
return axios.patch(`/api/rest/dept/toggle/${id}`);
}

View File

@ -9,14 +9,13 @@ export interface RoleCreateRecord {
remark: string; remark: string;
} }
export interface ListRecord { // 基础信息
username: string; export interface RoleList {
phone: string; id: string;
email: string; remark: string;
enable: string; name: string;
nickname: string; enabled: string;
avater: string; authorities: string;
address: string;
} }
export interface RoleRecord extends RoleCreateRecord { export interface RoleRecord extends RoleCreateRecord {
@ -27,17 +26,14 @@ export interface RoleListRecord extends RoleRecord {
name: string; name: string;
} }
export function create(data: RoleCreateRecord) { // 查询所有的角色列表、
return axios.post(`/api/role`, data); export function getRoleList() {
return axios.get('/api/rest/role');
} }
// 更新用户 // 切换启用状态
export function update(data: RoleRecord) { export function enabled(id: string) {
return axios.patch(`/api/rest/user/${data.id}`, data); return axios.patch(`/api/rest/role/${id}/toggle`);
}
export function getDetail(id: number) {
return axios.get<RoleRecord>(`/api/role/${id}`);
} }
// 删除用户 // 删除用户
@ -45,17 +41,20 @@ export function remove(id: string) {
return axios.delete(`/api/rest/role/${id}`); return axios.delete(`/api/rest/role/${id}`);
} }
// 模糊查询用户列表 // 添加角色
export function create(data: RoleList) {
return axios.post(`/api/rest/role`, data);
}
// 更新用户
export function update(data: RoleList) {
return axios.patch(`/api/rest/role/${data.id}`, data);
}
export function getDetail(id: number) {
return axios.get<RoleRecord>(`/api/rest/role/${id}`);
}
export function queryRoles(params?: ListParams<Partial<RoleRecord>>) { export function queryRoles(params?: ListParams<Partial<RoleRecord>>) {
return queryList<RoleRecord>(`/api/rest/user/query`, params); return queryList<RoleRecord>(`/api/rest/role/query`, params);
}
// 添加用户
export function addUser(params: ListRecord) {
return axios.post('/api/rest/user/register', params);
}
// 是否启用
export function enabled(id: string) {
return axios.patch(`/api/rest/user/${id}/toggle`);
} }

View File

@ -28,7 +28,11 @@ import localeUserSetting from '@/views/user/setting/locale/en-US';
import systemUser from '@/views/system/user/locale/en-US'; import systemUser from '@/views/system/user/locale/en-US';
import localRole from '@/views/character/manage/locale/zh-CN'; import localCustomer from '@/views/customer/manage/locale/en-US';
import localRole from '@/views/role/manage/locale/en-US';
import localRegion from '@/views/role/region/locale/en-US';
import localeSettings from './en-US/settings'; import localeSettings from './en-US/settings';
export default { export default {
@ -69,6 +73,8 @@ export default {
...locale500, ...locale500,
...localeUserInfo, ...localeUserInfo,
...localeUserSetting, ...localeUserSetting,
...localCustomer,
...localRole, ...localRole,
...localRegion,
...systemUser, ...systemUser,
}; };

View File

@ -29,6 +29,10 @@ import localeUserSetting from '@/views/user/setting/locale/zh-CN';
import systemUser from '@/views/system/user/locale/zh-CN'; import systemUser from '@/views/system/user/locale/zh-CN';
import localCustomer from '@/views/customer/manage/locale/zh-CN'; import localCustomer from '@/views/customer/manage/locale/zh-CN';
import localRole from '@/views/role/manage/locale/zh-CN';
import localRegion from '@/views/role/region/locale/zh-CN';
import localeSettings from './zh-CN/settings'; import localeSettings from './zh-CN/settings';
export default { export default {
@ -71,6 +75,7 @@ export default {
...localeUserInfo, ...localeUserInfo,
...localeUserSetting, ...localeUserSetting,
...localCustomer, ...localCustomer,
...localRole,
...localRegion,
...systemUser, ...systemUser,
}; };

View File

@ -45,4 +45,4 @@ const EXCEPTION: AppRouteRecordRaw = {
], ],
}; };
export default EXCEPTION; // export default EXCEPTION;

View File

@ -35,4 +35,4 @@ const LIST: AppRouteRecordRaw = {
], ],
}; };
export default LIST; // export default LIST;

View File

@ -35,4 +35,4 @@ const RESULT: AppRouteRecordRaw = {
], ],
}; };
export default RESULT; // export default RESULT;

View File

@ -0,0 +1,38 @@
import { DEFAULT_LAYOUT } from '../base';
import { AppRouteRecordRaw } from '../types';
const ROLE: AppRouteRecordRaw = {
path: '/role',
name: 'role',
component: DEFAULT_LAYOUT,
meta: {
locale: 'menu.role',
icon: 'icon-idcard',
requiresAuth: true,
order: 3,
},
children: [
{
path: 'manage',
name: 'RoleManage',
component: () => import('@/views/role/manage/index.vue'),
meta: {
locale: 'menu.role.manage',
requiresAuth: true,
permissions: ['*'],
},
},
{
path: 'region',
name: 'Region',
component: () => import('@/views/role/region/index.vue'),
meta: {
locale: 'menu.role.region',
requiresAuth: true,
permissions: ['*'],
},
},
],
};
export default ROLE;

View File

@ -4,9 +4,18 @@ import useAppStore from './modules/app';
import useUserStore from './modules/user'; import useUserStore from './modules/user';
import useTabBarStore from './modules/tab-bar'; import useTabBarStore from './modules/tab-bar';
import useCustomerStore from './modules/customer'; import useCustomerStore from './modules/customer';
import useRoleStore from './modules/role';
import useRegionStore from './modules/region';
const pinia = createPinia(); const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); pinia.use(piniaPluginPersistedstate);
export { useAppStore, useUserStore, useTabBarStore, useCustomerStore }; export {
useAppStore,
useUserStore,
useTabBarStore,
useCustomerStore,
useRoleStore,
useRegionStore,
};
export default pinia; export default pinia;

View File

@ -1,15 +1,8 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { import { queryRoles, addUser, remove, update, enabled } from '@/api/customer';
queryRoles,
ListRecord,
addUser,
remove,
update,
enabled,
} from '@/api/role';
import { customerState } from './type'; import { customerState } from './type';
const useCustomerStore = defineStore('role', { const useCustomerStore = defineStore('customer', {
state: (): customerState => ({ state: (): customerState => ({
current: undefined, current: undefined,
pageSize: undefined, pageSize: undefined,
@ -23,7 +16,7 @@ const useCustomerStore = defineStore('role', {
}), }),
getters: { getters: {
roleInfo(state: customerState): customerState { CustomerInfo(state: customerState): customerState {
return { ...state }; return { ...state };
}, },
}, },

View File

@ -0,0 +1,50 @@
import { defineStore } from 'pinia';
import {
createRegion,
regionList,
removeRegion,
enabledRegion,
updateRegion,
ListRegion,
} from '@/api/region';
import { regionStore } from './type';
const useRegionStore = defineStore('region', {
state: (): regionStore => ({
id: undefined,
remark: undefined,
createTime: undefined,
name: undefined,
enabled: undefined,
}),
getters: {
RegionInfo(state: regionStore): regionStore {
return { ...state };
},
},
actions: {
// 获取所有的角色列表
async getRegionList(data: any) {
return regionList(data);
},
async enabledStatus(id: string) {
return enabledRegion(id);
},
async deleteRegion(id: string) {
return removeRegion(id);
},
async addRegion(params: ListRegion) {
return createRegion(params);
},
async updateRegion(params: ListRegion) {
return updateRegion(params);
},
},
});
export default useRegionStore;

View File

@ -0,0 +1,7 @@
export interface regionStore {
id?: undefined;
remark?: string;
createTime?: string;
name?: string;
enabled?: string;
}

View File

@ -0,0 +1,50 @@
import { defineStore } from 'pinia';
import {
RoleList,
getRoleList,
enabled,
remove,
create,
update,
} from '@/api/role';
import { roleState } from './type';
const useRoleStore = defineStore('role', {
state: (): roleState => ({
id: undefined,
remark: undefined,
name: undefined,
enabled: undefined,
authorities: undefined,
}),
getters: {
RoleInfo(state: roleState): roleState {
return { ...state };
},
},
actions: {
// 获取所有的角色列表
async getRoleList() {
return getRoleList();
},
async enabledStatus(id: string) {
return enabled(id);
},
async deleteRole(id: string) {
return remove(id);
},
async addRole(params: RoleList) {
return create(params);
},
async updateRole(params: RoleList) {
return update(params);
},
},
});
export default useRoleStore;

View File

@ -0,0 +1,8 @@
export type RoleType = '' | '*' | 'admin' | 'user' | string[];
export interface roleState {
id?: string;
remark?: string;
name?: string;
enabled?: string;
authorities?: string;
}

View File

@ -1,489 +0,0 @@
<template>
<div class="container">
<Breadcrumb :items="['menu.role', 'menu.role.manage']" />
<a-card class="general-card" :title="$t('menu.list.searchTable')">
<a-row>
<a-col :flex="1">
<a-form
:model="formModel"
:label-col-props="{ span: 6 }"
:wrapper-col-props="{ span: 18 }"
label-align="left"
>
<a-row :gutter="16">
<a-col :span="7">
<a-form-item
field="username"
:label="$t('searchTable.form.username')"
>
<a-input
v-model="formModel.username"
:placeholder="$t('searchTable.form.username.placeholder')"
/>
</a-form-item>
</a-col>
<a-col :span="9">
<a-form-item
field="phone"
:label="$t('searchTable.form.phone')"
>
<a-input
v-model="formModel.phone"
:placeholder="$t('searchTable.form.phone.placeholder')"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item
field="email"
:label="$t('searchTable.form.email')"
>
<a-input
v-model="formModel.email"
:placeholder="$t('searchTable.form.email.placeholder')"
/>
</a-form-item>
</a-col>
<!-- <a-col :span="9">
<a-form-item field="role" :label="$t('searchTable.form.role')">
<a-select
v-model="formModel.role"
:options="roleOptions"
:placeholder="$t('searchTable.form.role.placeholder')"
/>
</a-form-item>
</a-col> -->
</a-row>
</a-form>
</a-col>
<a-divider style="height: 84px" direction="vertical" />
<!-- 更新和重置按钮 -->
<a-col :flex="'86px'" style="text-align: right">
<a-space direction="vertical" :size="18">
<a-button type="primary" @click="search">
<template #icon>
<icon-search />
</template>
{{ $t('searchTable.form.search') }}
</a-button>
<a-button @click="reset">
<template #icon>
<icon-refresh />
</template>
{{ $t('searchTable.form.reset') }}
</a-button>
</a-space>
</a-col>
</a-row>
<a-divider style="margin-top: 0" />
<a-row :gutter="10">
<a-col :span="9">
<a-button
type="primary"
@click="handleClick"
style="margin-right: 16px"
>
<template #icon>
<icon-plus />
</template>
{{ $t('searchTable.operation.create') }}
</a-button>
<a-button type="primary" status="danger" @click="handleDelete">
<template #icon>
<icon-close />
</template>
{{ $t('searchTable.operation.delete') }}
</a-button>
</a-col>
</a-row>
<a-divider style="margin-top: 16px" />
<a-table
row-key="id"
:loading="loading"
:pagination="false"
:columns="(cloneColumns as TableColumnData[])"
:data="renderData"
:bordered="false"
:size="size"
:row-selection="true"
@select="selectRow"
>
<template #index="{ rowIndex }">
{{ rowIndex + 1 + (pagination.page - 1) * pagination.size }}
</template>
<template #enabled="{ record }">
<a-switch
:model-value="record.enabled"
:checked-value="true"
:unchecked-value="false"
@change="enabledStatus(record)"
/>
</template>
<template #operations="{ record }">
<a-button
type="text"
size="small"
@click="handleClick(record, 'modify')"
>
{{ $t('searchTable.columns.operations.detail') }}
</a-button>
</template>
</a-table>
<a-space direction="vertical" size="large" style="margin-top: 16px">
<a-pagination
show-total
:current="pagination.page"
@change="onPageChange"
:page-size="pagination.pageSize"
:total="pagination.total"
/>
</a-space>
<a-modal
v-model:visible="visible"
:title="dialogTitle"
:mask-closable="false"
@cancel="handleCancel"
:before-ok="handleBeforeOk"
>
<a-form :model="formDate">
<a-form-item field="username" :label="$t('add.user.info.username')">
<a-input
v-model="formDate.username"
:placeholder="$t('add.user.info.username.placeholder')"
:required="required"
:rules="[
{
required: true,
message: '用户名不能为空',
},
]"
/>
</a-form-item>
<a-form-item field="password" :label="$t('add.user.info.password')">
<a-input-password
v-model="formDate.password"
:placeholder="$t('add.user.info.password.placeholder')"
:rules="[
{
required: true,
message: '密码不能为空',
},
]"
/>
</a-form-item>
<a-form-item field="phone" :label="$t('add.user.info.phone')">
<a-input
v-model="formDate.phone"
:placeholder="$t('add.user.info.phone.placeholder')"
:rules="[
{
required: true,
message: '手机号码不能为空',
},
]"
/>
</a-form-item>
<a-form-item field="email" :label="$t('add.user.info.email')">
<a-input
v-model="formDate.email"
:placeholder="$t('add.user.info.email.placeholder')"
/>
</a-form-item>
<a-form-item field="nickName" :label="$t('add.user.info.nickName')">
<a-input
v-model="formDate.nickName"
:placeholder="$t('add.user.info.nickName.placeholder')"
/>
</a-form-item>
<a-form-item field="address" :label="$t('add.user.info.address')">
<a-input
v-model="formDate.address"
:placeholder="$t('add.user.info.address.placeholder')"
/>
</a-form-item>
<a-form-item field="dept" :label="$t('add.user.info.dept')">
<a-select
v-model="formDate.dept"
:placeholder="$t('add.user.info.dept.placeholder')"
>
<a-option value="user">user</a-option>
<a-option value="auditor">auditor</a-option>
<a-option value="admin">admin</a-option>
</a-select>
</a-form-item>
</a-form>
</a-modal>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, reactive, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { useCustomerStore } from '@/store';
import { ListParams } from '@/api/list';
import { Pagination } from '@/types/global';
import { ListRecord } from '@/api/role';
import { Message } from '@arco-design/web-vue';
import useLoading from '@/hooks/loading';
import { status } from 'nprogress';
import { stat } from 'fs';
type SizeProps = 'mini' | 'small' | 'medium' | 'large';
type Column = TableColumnData & { checked?: true };
//
const generateFormModel = () => {
return {
username: '',
phone: '',
email: '',
role: '',
};
};
const { t } = useI18n();
const { loading, setLoading } = useLoading();
const roleStore = useCustomerStore();
const renderData = ref<ListRecord[]>([]);
const cloneColumns = ref<Column[]>([]);
const showColumns = ref<Column[]>([]);
const size = ref<SizeProps>('medium');
const seleteRowList = ref();
const visible = ref(false);
const messageType = ref();
let formDifer = {};
const dialogTitle = ref('添加用户');
const form = () => {
return {
id: '',
username: '',
password: '',
phone: '',
email: '',
nickName: '',
address: '',
dept: '',
};
};
const formDate = ref(form());
//
const handleClick = (record: any, type: string) => {
if (type === 'modify') {
messageType.value = 'modify';
formDifer = record;
formDate.value = { ...record };
dialogTitle.value = '修改用户信息';
}
visible.value = true;
};
//
const diffDataForm = (newData: any, oldData: any) => {
const result = {}; //
Object.keys(oldData).forEach((key) => {
if (oldData[key] !== newData[key] || key === 'id') {
result[key] = newData[key];
}
});
return result;
};
//
const handleBeforeOk = async (done: any) => {
try {
formDifer = diffDataForm(formDate.value, formDifer);
if (dialogTitle.value === '修改用户信息') {
const res = await roleStore.updateUser(formDifer);
if (res.status === 200) {
Message.success({
content: t('add.user.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('add.user.info.fail'),
duration: 3 * 1000,
});
}
} else {
const res = await roleStore.addUser(formDate.value);
if (res.status === 200) {
Message.success({
content: t('modify.user.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('modify.user.info.fail'),
duration: 3 * 1000,
});
}
}
} catch (err) {
// you can report use errorHandler or other
} finally {
formDate.value = form();
search();
}
};
//
const enabledStatus = async (record: string) => {
const res = await roleStore.enabledStatus(record.id);
search();
};
//
const selectRow = (rowKeys: string[]) => {
seleteRowList.value = rowKeys;
};
//
const handleDelete = async () => {
const res = await roleStore.deleteUser(seleteRowList.value);
};
//
const handleCancel = () => {
formDate.value = form();
visible.value = false;
dialogTitle.value = '添加用户';
};
// formModel
const formModel = ref(generateFormModel());
//
const basePagination: Pagination = {
page: 1,
size: 10,
};
const pagination = reactive({
...basePagination,
});
//
const onPageChange = (current: number) => {
const page = current;
fetchData({ ...basePagination, page });
};
//
const fetchData = async (params: { page: 1; size: 10 }) => {
setLoading(true);
try {
const { data } = await roleStore.getUserInfo(params);
renderData.value = data.list;
pagination.page = params.page;
pagination.total = data.total;
} catch (err) {
// you can report use errorHandler or other
} finally {
setLoading(false);
}
};
//
const search = () => {
fetchData({
...basePagination,
...formModel.value,
} as unknown as any);
};
search();
//
const reset = () => {
formModel.value = generateFormModel();
};
//
const columns = computed<TableColumnData[]>(() => [
{
title: t('searchTable.columns.index'),
dataIndex: 'index',
slotName: 'index',
},
{
title: t('searchTable.columns.username'),
dataIndex: 'username',
},
{
title: t('searchTable.columns.phone'),
dataIndex: 'phone',
},
{
title: t('searchTable.columns.email'),
dataIndex: 'email',
},
{
title: t('searchTable.columns.nickName'),
dataIndex: 'nickName',
},
{
title: t('searchTable.columns.address'),
dataIndex: 'address',
},
{
title: t('searchTable.columns.enabled'),
dataIndex: 'enabled',
slotName: 'enabled',
},
{
title: t('searchTable.columns.operations'),
dataIndex: 'operations',
slotName: 'operations',
},
]);
//
watch(
() => columns.value,
(val) => {
cloneColumns.value = val;
cloneColumns.value.forEach((item, index) => {
item.checked = true;
});
showColumns.value = cloneColumns.value;
},
{ deep: true, immediate: true }
);
//
const roleOptions = computed<SelectOptionData[]>(() => [
{
label: t('searchTable.form.role.user'),
vlaue: 'user',
},
{
label: t('searchTable.form.role.auditor'),
vlaue: 'auditor',
},
]);
</script>
<script lang="ts">
export default {
name: 'Manage',
};
</script>
<style scoped lang="less">
.container {
padding: 0 20px 20px 20px;
}
</style>

View File

@ -1,45 +0,0 @@
export default {
'menu.list.searchTable': 'Search Table',
'menu.role.manage': 'Role Manage',
'searchTable.form.number': 'Set Number',
'searchTable.form.number.placeholder': 'Please enter Set Number',
'searchTable.form.name': 'Set Name',
'searchTable.form.name.placeholder': 'Please enter Set Name',
'searchTable.form.contentType': 'Content Type',
'searchTable.form.contentType.img': 'image-text',
'searchTable.form.contentType.horizontalVideo': 'Horizontal short video',
'searchTable.form.contentType.verticalVideo': 'Vertical short video',
'searchTable.form.filterType': 'Filter Type',
'searchTable.form.filterType.artificial': 'artificial',
'searchTable.form.filterType.rules': 'Rules',
'searchTable.form.createdTime': 'Create Date',
'searchTable.form.status': 'Status',
'searchTable.form.status.online': 'Online',
'searchTable.form.status.offline': 'Offline',
'searchTable.form.search': 'Search',
'searchTable.form.reset': 'Reset',
'searchTable.form.selectDefault': 'All',
'searchTable.operation.create': 'Create',
'searchTable.operation.import': 'Import',
'searchTable.operation.download': 'Download',
// columns
'searchTable.columns.index': '#',
'searchTable.columns.number': 'Set Number',
'searchTable.columns.name': 'Set Name',
'searchTable.columns.contentType': 'Content Type',
'searchTable.columns.filterType': 'Filter Type',
'searchTable.columns.count': 'Count',
'searchTable.columns.createdTime': 'CreatedTime',
'searchTable.columns.status': 'Status',
'searchTable.columns.operations': 'Operations',
'searchTable.columns.operations.view': 'View',
// size
'searchTable.size.mini': 'mini',
'searchTable.size.small': 'small',
'searchTable.size.medium': 'middle',
'searchTable.size.large': 'large',
// actions
'searchTable.actions.refresh': 'refresh',
'searchTable.actions.density': 'density',
'searchTable.actions.columnSetting': 'columnSetting',
};

View File

@ -1,46 +0,0 @@
export default {
'menu.list.searchTable': '查询表格',
'menu.role.manage': '角色管理',
'roleManage.username': '用户名',
'searchTable.form.username': '用户名',
'searchTable.form.username.placeholder': '请输入用户名',
'searchTable.form.phone': '电话号码',
'searchTable.form.phone.placeholder': '请输入电话号码',
'searchTable.form.role': '角色',
'searchTable.form.role.placeholder': '请选择角色',
'searchTable.form.role.user': '普通用户',
'searchTable.form.email': 'Email',
'searchTable.form.email.placeholder': '请输入Email',
'searchTable.form.role.auditor': '审核员',
'searchTable.form.search': '查询',
'searchTable.form.reset': '重置',
'searchTable.columns.nickName': '昵称',
'searchTable.columns.username': '用户名',
'searchTable.columns.phone': '电话',
'searchTable.columns.email': 'Email',
'searchTable.columns.enabled': '是否启用',
'searchTable.columns.avater': '头像',
'searchTable.columns.address': '地址',
'searchTable.columns.operations.detail': '详细',
'searchTable.operation.create': '添加',
'searchTable.operation.delete': '删除',
'add.user.info': '添加用户',
'add.user.info.username': '用户名',
'add.user.info.username.placeholder': '请输入用户名',
'add.user.info.password': '密码',
'add.user.info.password.placeholder': '请输入密码',
'add.user.info.phone': '电话号码',
'add.user.info.phone.placeholder': '请输入电话号码',
'add.user.info.email': 'Email',
'add.user.info.email.placeholder': '请输入Email',
'add.user.info.nickName': '昵称',
'add.user.info.nickName.placeholder': '请输入昵称',
'add.user.info.address': '地址',
'add.user.info.address.placeholder': '请输入地址',
'add.user.info.dept': '角色',
'add.user.info.dept.placeholder': '请选择角色',
'add.user.info.sucess': '添加成功',
'add.user.info.fail': '添加失败',
'modify.user.info.sucess': '修改成功',
'modify.user.info.fail': '修改失败',
};

View File

@ -151,45 +151,61 @@
v-model:visible="visible" v-model:visible="visible"
:title="dialogTitle" :title="dialogTitle"
:mask-closable="false" :mask-closable="false"
:footer="false"
@cancel="handleCancel" @cancel="handleCancel"
@before-ok="handleBeforeOk" @before-ok="handleBeforeOk"
> >
<a-form :model="formDate"> <a-form :model="formDate">
<a-form-item field="username" :label="$t('add.user.info.username')"> <a-form-item
<a-input field="username"
v-model="formDate.username" :label="$t('add.user.info.username')"
:placeholder="$t('add.user.info.username.placeholder')"
:required="required"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '用户名不能为空', message: '用户名不能为空',
}, },
]" ]"
:validate-trigger="['change', 'input']"
>
<a-input
v-model="formDate.username"
:placeholder="$t('add.user.info.username.placeholder')"
/> />
</a-form-item> </a-form-item>
<a-form-item field="password" :label="$t('add.user.info.password')"> <a-form-item
<a-input-password field="password"
v-model="formDate.password" :label="$t('add.user.info.password')"
:placeholder="$t('add.user.info.password.placeholder')"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '密码不能为空', message: '密码不能为空',
}, },
]" ]"
:validate-trigger="['change', 'input']"
>
<a-input-password
v-model="formDate.password"
:placeholder="$t('add.user.info.password.placeholder')"
/> />
</a-form-item> </a-form-item>
<a-form-item field="phone" :label="$t('add.user.info.phone')"> <a-form-item
<a-input field="phone"
v-model="formDate.phone" :label="$t('add.user.info.phone')"
:placeholder="$t('add.user.info.phone.placeholder')"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '手机号码不能为空', message: '手机号码不能为空',
}, },
{
length: 11,
message: '请输入正确手机号码',
},
]" ]"
:validate-trigger="['change', 'input']"
>
<a-input
v-model="formDate.phone"
:placeholder="$t('add.user.info.phone.placeholder')"
/> />
</a-form-item> </a-form-item>
<a-form-item field="email" :label="$t('add.user.info.email')"> <a-form-item field="email" :label="$t('add.user.info.email')">
@ -220,6 +236,14 @@
<a-option value="admin">admin</a-option> <a-option value="admin">admin</a-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item>
<a-space style="margin-top: 10px">
<a-button html-type="submit" type="primary" @click="handleOk"
>提交
</a-button>
<a-button @click="handleCancel">取消</a-button>
</a-space>
</a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>
</a-card> </a-card>
@ -299,28 +323,19 @@ const diffDataForm = (newData: any, oldData: any) => {
}; };
// //
const handleBeforeOk = async (done: any) => { const handleOk = async (done: any) => {
console.log(1); if (
formDate.value.username !== '' &&
formDate.value.password !== '' &&
formDate.value.phone !== ''
) {
try { try {
formDifer = diffDataForm(formDate.value, formDifer); formDifer = diffDataForm(formDate.value, formDifer);
if (dialogTitle.value === '修改用户信息') { if (dialogTitle.value === '修改用户信息') {
const res = await customerStore.updateUser(formDifer); const res = await customerStore.updateUser(formDifer);
if (res.status === 200) { if (res.status === 200) {
Message.success({ visible.value = false;
content: t('add.user.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('add.user.info.fail'),
duration: 3 * 1000,
});
}
} else {
const res = await customerStore.addUser(formDate.value);
if (res.status === 200) {
Message.success({ Message.success({
content: t('modify.user.info.sucess'), content: t('modify.user.info.sucess'),
duration: 3 * 1000, duration: 3 * 1000,
@ -331,6 +346,20 @@ const handleBeforeOk = async (done: any) => {
duration: 3 * 1000, duration: 3 * 1000,
}); });
} }
} else {
const res = await customerStore.addUser(formDate.value);
if (res.status === 200) {
visible.value = false;
Message.success({
content: t('add.user.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('add.user.info.fail'),
duration: 3 * 1000,
});
}
} }
} catch (err) { } catch (err) {
// you can report use errorHandler or other // you can report use errorHandler or other
@ -339,6 +368,7 @@ const handleBeforeOk = async (done: any) => {
dialogTitle.value = '添加用户'; dialogTitle.value = '添加用户';
search(); search();
} }
}
}; };
// //
@ -349,12 +379,25 @@ const enabledStatus = async (record: string) => {
// //
const selectRow = (rowKeys: string[]) => { const selectRow = (rowKeys: string[]) => {
seleteRowList.value = rowKeys; seleteRowList.value = rowKeys[rowKeys.length - 1];
}; };
// //
const handleDelete = async () => { const handleDelete = async () => {
const res = await customerStore.deleteUser(seleteRowList.value); const res = await customerStore.deleteUser(seleteRowList.value);
seleteRowList.value = [];
if (res.status === 200) {
search();
Message.success({
content: t('delete.user.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('delete.user.fail'),
duration: 3 * 1000,
});
}
}; };
// //

View File

@ -43,4 +43,6 @@ export default {
'add.user.info.fail': '添加失败', 'add.user.info.fail': '添加失败',
'modify.user.info.sucess': '修改成功', 'modify.user.info.sucess': '修改成功',
'modify.user.info.fail': '修改失败', 'modify.user.info.fail': '修改失败',
'delete.user.sucess': '删除用户成功',
'delete.user.fail': '删除用户失败',
}; };

View File

@ -0,0 +1,338 @@
<template>
<div class="container">
<Breadcrumb :items="['menu.role', 'menu.role.manage']" />
<a-card class="general-card" :title="$t('menu.role.list')">
<a-row :gutter="10">
<a-col :span="9">
<a-button
type="primary"
@click="handleClick"
style="margin-right: 16px"
>
<template #icon>
<icon-plus />
</template>
{{ $t('roleTable.operation.create') }}
</a-button>
<a-button type="primary" status="danger" @click="handleDelete">
<template #icon>
<icon-close />
</template>
{{ $t('roleTable.operation.delete') }}
</a-button>
</a-col>
</a-row>
<a-divider style="margin-top: 16px" />
<a-table
row-key="id"
:loading="loading"
:pagination="false"
:columns="(cloneColumns as TableColumnData[])"
:data="renderData"
:bordered="false"
:size="size"
:row-selection="true"
@select="selectRow"
>
<template #index="{ rowIndex }">
{{ rowIndex + 1 }}
</template>
<template #createTime="{ record }">
{{ dayjs(record.createTime).format('YYYY-MM-DD') }}
</template>
<template #enabled="{ record }">
<a-switch
:model-value="record.enabled"
:checked-value="true"
:unchecked-value="false"
@change="enabledStatus(record)"
/>
</template>
<template #operations="{ record }">
<a-button
type="text"
size="small"
@click="handleClick(record, 'modify')"
>
{{ $t('roleTable.columns.operations.detail') }}
</a-button>
</template>
</a-table>
<a-modal
v-model:visible="visible"
:title="dialogTitle"
:mask-closable="false"
:footer="false"
@cancel="handleCancel"
>
<a-form :model="formDate">
<a-form-item
field="name"
:label="$t('add.role.info.name')"
:rules="[{ required: true, message: 'name is required' }]"
:validate-trigger="['change', 'input']"
>
<a-input
v-model="formDate.name"
:placeholder="$t('add.role.info.name.placeholder')"
/>
</a-form-item>
<a-form-item field="remark" :label="$t('add.role.info.remark')">
<a-input
v-model="formDate.remark"
:placeholder="$t('add.role.info.remark.placeholder')"
/>
</a-form-item>
<a-form-item
field="authorities"
:label="$t('add.role.info.authorities')"
>
<a-select
v-model="formDate.authorities"
:placeholder="$t('add.role.info.authorities.placeholder')"
>
<a-option value="user">user</a-option>
<a-option value="auditor">auditor</a-option>
<a-option value="admin">admin</a-option>
</a-select>
</a-form-item>
<a-form-item>
<a-space style="margin-top: 10px">
<a-button html-type="submit" type="primary" @click="validate"
>提交</a-button
>
<a-button @click="handleCancel">取消</a-button>
</a-space>
</a-form-item>
</a-form>
</a-modal>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { RoleList } from '@/api/role';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { Message } from '@arco-design/web-vue';
import { useRoleStore } from '@/store';
import useLoading from '@/hooks/loading';
import dayjs from 'dayjs';
type SizeProps = 'mini' | 'small' | 'medium' | 'large';
type Column = TableColumnData & { checked?: true };
const { t } = useI18n();
const { loading, setLoading } = useLoading();
const size = ref<SizeProps>('medium');
const roleStore = useRoleStore();
const renderData = ref<RoleList[]>([]);
const cloneColumns = ref<Column[]>([]);
const showColumns = ref<Column[]>([]);
const seleteRowList = ref();
const visible = ref(false);
const dialogTitle = ref('添加角色');
const messageType = ref();
let formDifer = {};
const form = () => {
return {
name: '',
remark: '',
authorities: [],
};
};
const formDate = ref(form());
//
const fetchData = async () => {
setLoading(true);
try {
const { data } = await roleStore.getRoleList();
renderData.value = data;
} catch (err) {
// you can report use errorHandler or other
} finally {
setLoading(false);
}
};
fetchData();
//
const selectRow = (rowKeys: string) => {
seleteRowList.value = rowKeys[rowKeys.length - 1];
};
//
const handleDelete = async () => {
const res = await roleStore.deleteRole(seleteRowList.value);
seleteRowList.value = [];
if (res.status === 200) {
fetchData();
Message.success({
content: t('delete.role.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('delete.role.fail'),
duration: 3 * 1000,
});
}
};
//
const enabledStatus = async (record: string) => {
await roleStore.enabledStatus(record.id);
fetchData();
};
//
const handleClick = (record: any, type: string) => {
if (type === 'modify') {
messageType.value = 'modify';
formDifer = record;
formDate.value = { ...record };
dialogTitle.value = '修改角色信息';
}
visible.value = true;
};
//
const diffDataForm = (newData: any, oldData: any) => {
const result = {}; //
Object.keys(oldData).forEach((key) => {
if (oldData[key] !== newData[key] || key === 'id') {
result[key] = newData[key];
}
});
return result;
};
//
const validate = async () => {
if (formDate.value.name !== '') {
try {
formDifer = diffDataForm(formDate.value, formDifer);
if (dialogTitle.value === '修改角色信息') {
const res = await roleStore.updateRole(formDifer);
if (res.status === 200) {
visible.value = false;
Message.success({
content: t('modify.role.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('modify.role.info.fail'),
duration: 3 * 1000,
});
}
} else {
const res = await roleStore.addRole(formDate.value);
if (res.status === 200) {
visible.value = false;
Message.success({
content: t('add.role.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('add.role.info.fail'),
duration: 3 * 1000,
});
}
}
} catch (err) {
// you can report use errorHandler or other
} finally {
formDate.value = form();
dialogTitle.value = '添加角色';
fetchData();
}
}
};
//
const handleCancel = () => {
formDate.value = form();
visible.value = false;
dialogTitle.value = '添加角色';
};
//
const columns = computed<TableColumnData[]>(() => [
{
title: t('roleTable.columns.index'),
dataIndex: 'index',
slotName: 'index',
},
{
title: t('roleTable.columns.name'),
dataIndex: 'name',
},
{
title: t('roleTable.columns.remark'),
dataIndex: 'remark',
},
{
title: t('roleTable.columns.authorities'),
dataIndex: 'authorities',
},
{
title: t('roleTable.columns.createTime'),
dataIndex: 'createTime',
slotName: 'createTime',
},
// {
// title: t('roleTable.columns.updateTime'),
// dataIndex: 'updateTime',
// slotName: 'updateTime',
// },
{
title: t('roleTable.columns.enabled'),
dataIndex: 'enabled',
slotName: 'enabled',
},
{
title: t('roleTable.columns.operations'),
dataIndex: 'operations',
slotName: 'operations',
},
]);
//
watch(
() => columns.value,
(val) => {
cloneColumns.value = val;
cloneColumns.value.forEach((item, index) => {
item.checked = true;
});
showColumns.value = cloneColumns.value;
},
{ deep: true, immediate: true }
);
</script>
<script lang='ts'>
export default {
name: 'RoleManage',
};
</script>
<style scoped lang="less">
.container {
padding: 0 20px 20px 20px;
}
</style>

View File

@ -0,0 +1,6 @@
export default {
'menu.role.manage': 'Role Manage',
'menu.role.list': 'Role List',
'searchTable.operation.create': 'Create',
'searchTable.operation.delete': 'Delete',
};

View File

@ -0,0 +1,33 @@
export default {
'menu.role.manage': '角色管理',
'menu.role.list': '角色列表',
'roleTable.operation.create': '添加',
'roleTable.operation.delete': '删除',
'roleTable.columns.index': '序号',
'roleTable.columns.name': '名称',
'roleTable.columns.remark': '备注',
'roleTable.columns.enabled': '是否启用',
'roleTable.columns.authorities': '权限',
'roleTable.columns.createTime': '创建时间',
'roleTable.columns.updateTime': '更新时间',
'roleTable.columns.operations': '操作',
'roleTable.columns.operations.detail': '详细',
'delete.role.sucess': '删除角色成功',
'delete.role.fail': '删除角色失败',
'add.role.info.name': '角色身份',
'add.role.info.name.placeholder': '请输入角色身份',
'add.role.info.remark': '备注',
'add.role.info.remark.placeholder': '请输入备注',
'add.role.info.authorities': '管理权限',
'add.role.info.authorities.placeholder': '请选择管理权限',
'add.role.info.sucess': '添加角色成功',
'add.role.info.fail': '添加角色失败',
'modify.role.info.sucess': '修改角色信息成功',
'modify.role.info.fail': '修改角色信息失败',
'from.ok': '确认',
'from.cancel': '取消',
};

View File

@ -0,0 +1,378 @@
<template>
<div class="container">
<Breadcrumb :items="['menu.role', 'menu.role.region']" />
<a-card class="general-card" :title="$t('menu.region.list')">
<a-row>
<a-col :flex="1">
<a-form
:model="formModel"
:label-col-props="{ span: 6 }"
:wrapper-col-props="{ span: 18 }"
label-align="left"
>
<a-row :gutter="16">
<a-col :span="9">
<a-form-item
field="username"
:label="$t('searchTable.form.regionName')"
>
<a-input
v-model="formModel.name"
:placeholder="$t('searchTable.form.regionName.placeholder')"
/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-col>
<a-divider style="height: 84px" direction="vertical" />
<!-- 更新和重置按钮 -->
<a-col :flex="'86px'" style="text-align: right">
<a-space direction="vertical" :size="18">
<a-button type="primary" @click="search">
<template #icon>
<icon-search />
</template>
{{ $t('searchTable.form.search') }}
</a-button>
<a-button @click="reset">
<template #icon>
<icon-refresh />
</template>
{{ $t('searchTable.form.reset') }}
</a-button>
</a-space>
</a-col>
</a-row>
<a-divider style="margin-top: 0" />
<a-row :gutter="10">
<a-col :span="9">
<a-button
type="primary"
@click="handleClick"
style="margin-right: 16px"
>
<template #icon>
<icon-plus />
</template>
{{ $t('searchTable.operation.create') }}
</a-button>
<a-button type="primary" status="danger" @click="handleDelete">
<template #icon>
<icon-close />
</template>
{{ $t('searchTable.operation.delete') }}
</a-button>
</a-col>
</a-row>
<a-divider style="margin-top: 16px" />
<a-table
row-key="id"
:loading="loading"
:pagination="false"
:columns="(cloneColumns as TableColumnData[])"
:data="renderData"
:bordered="false"
:size="size"
:row-selection="true"
@select="selectRow"
>
<template #index="{ rowIndex }">
{{ rowIndex + 1 }}
</template>
<template #createTime="{ record }">
{{ dayjs(record.createTime).format('YYYY-MM-DD') }}
</template>
<template #enabled="{ record }">
<a-switch
:model-value="record.enabled"
:checked-value="true"
:unchecked-value="false"
@change="enabledStatus(record)"
/>
</template>
<template #operations="{ record }">
<a-button
type="text"
size="small"
@click="handleClick(record, 'modify')"
>
{{ $t('searchTable.columns.operations.detail') }}
</a-button>
</template>
</a-table>
<a-modal
v-model:visible="visible"
:title="dialogTitle"
:mask-closable="false"
:footer="false"
@cancel="handleCancel"
@before-ok="handleBeforeOk"
>
<a-form :model="formDate">
<a-form-item
field="name"
:label="$t('add.region.info.name')"
:rules="[
{
required: true,
message: '区域名不能为空',
},
]"
:validate-trigger="['change', 'input']"
>
<a-input
v-model="formDate.name"
:placeholder="$t('add.region.info.name.placeholder')"
/>
</a-form-item>
<a-form-item field="remark" :label="$t('add.region.info.remark')">
<a-input
v-model="formDate.remark"
:placeholder="$t('add.region.info.remark.placeholder')"
:required="required"
/>
</a-form-item>
<a-form-item>
<a-space style="margin-top: 10px">
<a-button html-type="submit" type="primary" @click="handleOk"
>提交</a-button
>
<a-button @click="handleCancel">取消</a-button>
</a-space>
</a-form-item>
</a-form>
</a-modal>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, reactive, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { useRegionStore } from '@/store';
import { ListParams } from '@/api/list';
import { Pagination } from '@/types/global';
import { ListRecord } from '@/api/customer';
import { Message } from '@arco-design/web-vue';
import useLoading from '@/hooks/loading';
import dayjs from 'dayjs';
type SizeProps = 'mini' | 'small' | 'medium' | 'large';
type Column = TableColumnData & { checked?: true };
//
const generateFormModel = () => {
return {
name: '',
};
};
const { t } = useI18n();
const { loading, setLoading } = useLoading();
const regionStore = useRegionStore();
const renderData = ref<ListRecord[]>([]);
const cloneColumns = ref<Column[]>([]);
const showColumns = ref<Column[]>([]);
const size = ref<SizeProps>('medium');
const seleteRowList = ref();
const visible = ref(false);
const messageType = ref();
const dialogTitle = ref('添加区域');
const form = () => {
return {
name: '',
remark: '',
};
};
const formDate = ref(form());
//
const handleClick = (record: any, type: string) => {
if (type === 'modify') {
messageType.value = 'modify';
formDate.value = { ...record };
dialogTitle.value = '修改区域信息';
}
visible.value = true;
};
//
const handleOk = async (done: any) => {
if (formDate.value.name !== '') {
try {
if (dialogTitle.value === '修改区域信息') {
const res = await regionStore.updateRegion(formDate.value);
if (res.status === 200) {
visible.value = false;
Message.success({
content: t('modify.user.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('modify.user.info.fail'),
duration: 3 * 1000,
});
}
} else {
const res = await regionStore.addRegion(formDate.value);
if (res.status === 200) {
visible.value = false;
Message.success({
content: t('add.user.info.sucess'),
duration: 3 * 1000,
});
} else {
Message.error({
content: t('add.user.info.fail'),
duration: 3 * 1000,
});
}
}
} catch (err) {
// you can report use errorHandler or other
} finally {
formDate.value = form();
dialogTitle.value = '添加区域';
search();
}
}
};
//
const enabledStatus = async (record: string) => {
const res = await regionStore.enabledStatus(record.id);
search();
};
//
const selectRow = (rowKeys: string[]) => {
seleteRowList.value = rowKeys[rowKeys.length - 1];
};
//
const handleDelete = async () => {
const res = await regionStore.deleteRegion(seleteRowList.value);
if (res.status === 200) {
search();
Message.success({
content: t('delete.region.sucess'),
duration: 3 * 1000,
});
seleteRowList.value = '';
} else {
Message.error({
content: t('delete.region.fail'),
duration: 3 * 1000,
});
}
};
//
const handleCancel = () => {
formDate.value = form();
visible.value = false;
dialogTitle.value = '添加区域';
};
// formModel
const formModel = ref(generateFormModel());
//
const fetchData = async (params: any) => {
setLoading(true);
try {
const { data } = await regionStore.getRegionList(params);
renderData.value = data;
} catch (err) {
// you can report use errorHandler or other
} finally {
setLoading(false);
}
};
//
const search = () => {
fetchData({
...formModel.value,
} as unknown as any);
};
search();
//
const reset = () => {
formModel.value = generateFormModel();
};
//
const columns = computed<TableColumnData[]>(() => [
{
title: t('searchTable.columns.regionIndex'),
dataIndex: 'index',
slotName: 'index',
},
{
title: t('searchTable.columns.regionName'),
dataIndex: 'name',
},
{
title: t('searchTable.columns.id'),
dataIndex: 'id',
},
{
title: t('searchTable.columns.remark'),
dataIndex: 'remark',
},
{
title: t('searchTable.columns.createTime'),
dataIndex: 'createTime',
slotName: 'createTime',
},
{
title: t('searchTable.columns.enabled'),
dataIndex: 'enabled',
slotName: 'enabled',
},
{
title: t('searchTable.columns.operations'),
dataIndex: 'operations',
slotName: 'operations',
},
]);
//
watch(
() => columns.value,
(val) => {
cloneColumns.value = val;
cloneColumns.value.forEach((item, index) => {
item.checked = true;
});
showColumns.value = cloneColumns.value;
},
{ deep: true, immediate: true }
);
</script>
<script lang="ts">
export default {
name: 'RegionManage',
};
</script>
<style scoped lang="less">
.container {
padding: 0 20px 20px 20px;
}
</style>

View File

@ -0,0 +1,3 @@
export default {
'menu.role.region': 'Region',
};

View File

@ -0,0 +1,22 @@
export default {
'menu.role.region': '区域管理',
'menu.region.list': '区域列表',
'searchTable.form.regionName': '区域名称',
'searchTable.form.regionName.placeholder': '请输入区域名称',
'searchTable.columns.regionIndex': '序号',
'searchTable.columns.regionName': '区域名称',
'searchTable.columns.id': '区域ID',
'searchTable.columns.remark': '备注',
'searchTable.columns.createTime': '创建时间',
'searchTable.columns.operations': '操作',
'searchTable.columns.operations.detail': '详细',
'delete.region.sucess': '删除区域成功',
'delete.region.fail': '删除区域失败',
'add.region.info.name': '区域名称',
'add.region.info.name.placeholder': '请输入区域名称',
'add.region.info.remark': '备注',
'add.region.info.remark.placeholder': '请输入备注',
};

View File

@ -86,6 +86,8 @@ const checkEquals = (
}; };
const user = useUser(); const user = useUser();
const validate = async () => { const validate = async () => {
const vali = await formRef.value?.validate(); const vali = await formRef.value?.validate();
if (!vali) { if (!vali) {