feat(系统设置): 系统用户组管理接口对接
This commit is contained in:
parent
cc2a6b9140
commit
3a9ef7bef1
|
@ -37,7 +37,7 @@
|
||||||
"@7polo/kity": "2.0.8",
|
"@7polo/kity": "2.0.8",
|
||||||
"@7polo/kityminder-core": "1.4.53",
|
"@7polo/kityminder-core": "1.4.53",
|
||||||
"@arco-design/web-vue": "^2.47.0",
|
"@arco-design/web-vue": "^2.47.0",
|
||||||
"@arco-themes/vue-ms-theme-default": "^0.0.14",
|
"@arco-themes/vue-ms-theme-default": "^0.0.15",
|
||||||
"@form-create/arco-design": "^3.1.21",
|
"@form-create/arco-design": "^3.1.21",
|
||||||
"@vueuse/core": "^9.13.0",
|
"@vueuse/core": "^9.13.0",
|
||||||
"ace-builds": "^1.22.0",
|
"ace-builds": "^1.22.0",
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
import MSR from '@/api/http/index';
|
import MSR from '@/api/http/index';
|
||||||
import { updateUserGroupU, getUserGroupU, addUserGroupU, deleteUserGroupU } from '@/api/requrls/system/usergroup';
|
import {
|
||||||
// import { QueryParams, CommonList } from '@/models/common';
|
updateUserGroupU,
|
||||||
import { UserGroupItem } from '@/models/system/usergroup';
|
getUserGroupU,
|
||||||
|
addUserGroupU,
|
||||||
|
deleteUserGroupU,
|
||||||
|
getGlobalUSettingUrl,
|
||||||
|
editGlobalUSettingUrl,
|
||||||
|
postUserByUserGroupUrl,
|
||||||
|
deleteUserFromUserGroupUrl,
|
||||||
|
} from '@/api/requrls/system/usergroup';
|
||||||
|
import { TableQueryParams, CommonList } from '@/models/common';
|
||||||
|
import { UserGroupItem, UserGroupAuthSeting, SaveGlobalUSettingData, UserTableItem } from '@/models/system/usergroup';
|
||||||
|
|
||||||
export function updateOrAddUserGroup(data: Partial<UserGroupItem>) {
|
export function updateOrAddUserGroup(data: Partial<UserGroupItem>) {
|
||||||
return MSR.post<UserGroupItem>({
|
return MSR.post<UserGroupItem>({
|
||||||
|
@ -28,3 +37,19 @@ export function deleteUserGroup(id: string) {
|
||||||
export function getUsergroupInfo(id: string) {
|
export function getUsergroupInfo(id: string) {
|
||||||
return MSR.get<UserGroupItem>({ url: `${getUserGroupU}${id}` });
|
return MSR.get<UserGroupItem>({ url: `${getUserGroupU}${id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getGlobalUSetting(id: string) {
|
||||||
|
return MSR.get<UserGroupAuthSeting[]>({ url: `${getGlobalUSettingUrl}${id}` });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveGlobalUSetting(data: SaveGlobalUSettingData) {
|
||||||
|
return MSR.post<UserGroupAuthSeting[]>({ url: editGlobalUSettingUrl, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function postUserByUserGroup(data: TableQueryParams) {
|
||||||
|
return MSR.post<CommonList<UserTableItem[]>>({ url: postUserByUserGroupUrl, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteUserFromUserGroup(id: string) {
|
||||||
|
return MSR.get<string>({ url: `${deleteUserFromUserGroupUrl}${id}` });
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/** 修改用户组 */
|
/** 修改用户组 */
|
||||||
export const updateUserGroupU = `/user/role/global/update`;
|
export const updateUserGroupU = `/user/role/global/update`;
|
||||||
/** 编辑用户组对应的权限配置 */
|
/** 编辑用户组对应的权限配置 */
|
||||||
export const editGlobalUSetting = `/user/role/global/permission/update`;
|
export const editGlobalUSettingUrl = `/user/role/global/permission/update`;
|
||||||
/** 添加用户组 */
|
/** 添加用户组 */
|
||||||
export const addUserGroupU = `/user/role/global/add`;
|
export const addUserGroupU = `/user/role/global/add`;
|
||||||
/** 获取用户组对应的权限配置 */
|
/** 获取用户组对应的权限配置 */
|
||||||
export const getGlobalUSetting = `/user/role/global/permission/list`;
|
export const getGlobalUSettingUrl = `/user/role/global/permission/setting/`;
|
||||||
/** 获取用户组 */
|
/** 获取用户组 */
|
||||||
export const getUserGroupU = `/user/role/global/list`;
|
export const getUserGroupU = `/user/role/global/list`;
|
||||||
/** 获取单个用户组信息 */
|
/** 获取单个用户组信息 */
|
||||||
|
@ -14,8 +14,8 @@ export const getUsergroupInfoU = `/user/role/global/get/`;
|
||||||
export const deleteUserGroupU = `/user/role/global/delete/`;
|
export const deleteUserGroupU = `/user/role/global/delete/`;
|
||||||
|
|
||||||
/** 根据用户组获取用户列表 */
|
/** 根据用户组获取用户列表 */
|
||||||
export const getUserByUserGroupU = `/user/role/relation/global/list/`;
|
export const postUserByUserGroupUrl = `/user/role/relation/global/list`;
|
||||||
/** 创建用户组添加用户 */
|
/** 创建用户组添加用户 */
|
||||||
export const addUserToUserGroupU = `/user/role/relation/global/add/`;
|
export const addUserToUserGroupU = `/user/role/relation/global/add/`;
|
||||||
/** 删除用户组用户 */
|
/** 删除用户组用户 */
|
||||||
export const deleteUserFromUserGroupU = `/user/role/relation/global/delete/`;
|
export const deleteUserFromUserGroupUrl = `/user/role/relation/global/delete/`;
|
||||||
|
|
|
@ -121,7 +121,7 @@ export default function useTableProps(
|
||||||
|
|
||||||
// 设置请求参数,如果出了分页参数还有搜索参数,在模板页面调用此方法,可以加入参数
|
// 设置请求参数,如果出了分页参数还有搜索参数,在模板页面调用此方法,可以加入参数
|
||||||
const loadListParams = ref<object>({});
|
const loadListParams = ref<object>({});
|
||||||
const setLoadPaListrams = (params?: object) => {
|
const setLoadListParams = (params?: object) => {
|
||||||
loadListParams.value = params || {};
|
loadListParams.value = params || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ export default function useTableProps(
|
||||||
sort: sortItem.value,
|
sort: sortItem.value,
|
||||||
filter: filterItem.value,
|
filter: filterItem.value,
|
||||||
keyword: keyword.value,
|
keyword: keyword.value,
|
||||||
|
...loadListParams.value,
|
||||||
});
|
});
|
||||||
const tmpArr = data.list as unknown as MsTableData;
|
const tmpArr = data.list as unknown as MsTableData;
|
||||||
propsRes.value.data = tmpArr.map((item: TableData) => {
|
propsRes.value.data = tmpArr.map((item: TableData) => {
|
||||||
|
@ -155,8 +156,8 @@ export default function useTableProps(
|
||||||
return data;
|
return data;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(err);
|
|
||||||
// TODO 表格异常放到solt的empty
|
// TODO 表格异常放到solt的empty
|
||||||
|
console.log(err);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
@ -213,7 +214,7 @@ export default function useTableProps(
|
||||||
setLoading,
|
setLoading,
|
||||||
loadList,
|
loadList,
|
||||||
setPagination,
|
setPagination,
|
||||||
setLoadPaListrams,
|
setLoadListParams,
|
||||||
setKeyword,
|
setKeyword,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,3 +39,63 @@ export interface UserGroupItem {
|
||||||
// 自定义排序
|
// 自定义排序
|
||||||
pos: number;
|
pos: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserGroupPermissionItem {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
enable: boolean;
|
||||||
|
license: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AuthScopeType = 'SYSTEM' | 'PROJECT' | 'ORGANIZATION';
|
||||||
|
|
||||||
|
// 用户组对应的权限配置
|
||||||
|
export interface UserGroupAuthSeting {
|
||||||
|
// 菜单项ID
|
||||||
|
id: AuthScopeType;
|
||||||
|
// 菜单所属类型
|
||||||
|
type?: string;
|
||||||
|
// 菜单项名称
|
||||||
|
name: string;
|
||||||
|
// 是否企业版
|
||||||
|
license: boolean;
|
||||||
|
// 是否全选
|
||||||
|
enable: boolean;
|
||||||
|
// 菜单下的权限列表
|
||||||
|
permissions?: UserGroupPermissionItem[];
|
||||||
|
// 子菜单
|
||||||
|
children?: UserGroupAuthSeting[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 权限表格DataItem
|
||||||
|
export interface AuthTableItem {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
enable: boolean;
|
||||||
|
license: boolean;
|
||||||
|
ability?: string | undefined;
|
||||||
|
permissions?: UserGroupPermissionItem[];
|
||||||
|
// 对应表格权限的复选框组的绑定值
|
||||||
|
perChecked?: string[];
|
||||||
|
operationObject?: string;
|
||||||
|
isSystem?: boolean;
|
||||||
|
isOrganization?: boolean;
|
||||||
|
isProject?: boolean;
|
||||||
|
indeterminate?: boolean;
|
||||||
|
}
|
||||||
|
export interface SavePermissions {
|
||||||
|
id: string;
|
||||||
|
enable: boolean;
|
||||||
|
}
|
||||||
|
export interface SaveGlobalUSettingData {
|
||||||
|
userRoleId: string;
|
||||||
|
permissions: SavePermissions[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserTableItem {
|
||||||
|
id: string;
|
||||||
|
userId: string;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import type { LoginData } from '@/models/user';
|
||||||
import type { UserState } from './types';
|
import type { UserState } from './types';
|
||||||
|
|
||||||
const useUserStore = defineStore('user', {
|
const useUserStore = defineStore('user', {
|
||||||
|
// 开启数据持久化
|
||||||
|
persist: true,
|
||||||
state: (): UserState => ({
|
state: (): UserState => ({
|
||||||
name: undefined,
|
name: undefined,
|
||||||
avatar: undefined,
|
avatar: undefined,
|
||||||
|
|
|
@ -1,16 +1,62 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div class="relative">
|
||||||
<a-table
|
<a-table
|
||||||
|
:span-method="dataSpanMethod"
|
||||||
:scroll="{ y: '860px', x: '1440px' }"
|
:scroll="{ y: '860px', x: '1440px' }"
|
||||||
:columns="columns"
|
:data="tableData"
|
||||||
:data="data"
|
:loading="loading"
|
||||||
:bordered="{ wrapper: true, cell: true }"
|
:bordered="{ wrapper: true, cell: true }"
|
||||||
size="small"
|
size="small"
|
||||||
|
:pagination="false"
|
||||||
|
>
|
||||||
|
<template #columns>
|
||||||
|
<a-table-column :width="100" :title="t('system.userGroup.function')" data-index="ability" />
|
||||||
|
<a-table-column :width="150" :title="t('system.userGroup.operationObject')" data-index="operationObject" />
|
||||||
|
<a-table-column :title="t('system.userGroup.auth')">
|
||||||
|
<template #cell="{ record, rowIndex }">
|
||||||
|
<a-checkbox-group v-model="record.perChecked" @change="(v) => handleAuthChange(v, rowIndex)">
|
||||||
|
<a-checkbox v-for="item in record.permissions" :key="item.id" :disabled="item.license" :value="item.id">{{
|
||||||
|
t(item.name)
|
||||||
|
}}</a-checkbox>
|
||||||
|
</a-checkbox-group>
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
<a-table-column :width="50" fixed="right" align="center" :bordered="false">
|
||||||
|
<template #title>
|
||||||
|
<a-checkbox
|
||||||
|
v-if="tableData && tableData?.length > 0"
|
||||||
|
:model-value="allChecked"
|
||||||
|
:indeterminate="allIndeterminate"
|
||||||
|
@change="handleAllChangeByCheckbox"
|
||||||
|
></a-checkbox>
|
||||||
|
</template>
|
||||||
|
<template #cell="{ record, rowIndex }">
|
||||||
|
<a-checkbox
|
||||||
|
:model-value="record.enable"
|
||||||
|
:indeterminate="record.indeterminate"
|
||||||
|
@change="(value) => handleActionChangeAll(value, rowIndex)"
|
||||||
/>
|
/>
|
||||||
|
</template>
|
||||||
|
</a-table-column>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
<div class="action">
|
||||||
|
<ms-button class="btn" @click="handleReset">{{ t('system.userGroup.reset') }}</ms-button>
|
||||||
|
<a-button class="btn" :disabled="!canSave" type="primary" @click="handleSave">{{
|
||||||
|
t('system.userGroup.save')
|
||||||
|
}}</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { TableData } from '@arco-design/web-vue';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { RenderFunction, VNodeChild } from 'vue';
|
import { RenderFunction, VNodeChild, ref, watchEffect } from 'vue';
|
||||||
|
import { type TableColumnData, type TableData } from '@arco-design/web-vue';
|
||||||
|
import useUserGroupStore from '@/store/modules/system/usergroup';
|
||||||
|
import { getGlobalUSetting, saveGlobalUSetting } from '@/api/modules/system/usergroup';
|
||||||
|
import { UserGroupAuthSeting, AuthTableItem, type AuthScopeType, SavePermissions } from '@/models/system/usergroup';
|
||||||
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
|
||||||
export declare type OperationName = 'selection-checkbox' | 'selection-radio' | 'expand' | 'drag-handle';
|
export declare type OperationName = 'selection-checkbox' | 'selection-radio' | 'expand' | 'drag-handle';
|
||||||
|
|
||||||
|
@ -23,59 +69,229 @@
|
||||||
isLastLeftFixed?: boolean;
|
isLastLeftFixed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns = [
|
const loading = ref(false);
|
||||||
{
|
const store = useUserGroupStore();
|
||||||
title: 'Name',
|
|
||||||
dataIndex: 'name',
|
const systemSpan = ref(1);
|
||||||
},
|
const projectSpan = ref(1);
|
||||||
{
|
const organizationSpan = ref(1);
|
||||||
title: 'Salary',
|
// 表格的总全选
|
||||||
dataIndex: 'salary',
|
const allChecked = ref(false);
|
||||||
},
|
const allIndeterminate = ref(false);
|
||||||
{
|
|
||||||
title: 'Address',
|
const tableData = ref<AuthTableItem[]>();
|
||||||
dataIndex: 'address',
|
// 是否可以保存
|
||||||
},
|
const canSave = ref(false);
|
||||||
{
|
|
||||||
title: 'Email',
|
const dataSpanMethod = (data: {
|
||||||
dataIndex: 'email',
|
record: TableData;
|
||||||
},
|
column: TableColumnData | TableOperationColumn;
|
||||||
];
|
rowIndex: number;
|
||||||
const data = [
|
columnIndex: number;
|
||||||
{
|
}) => {
|
||||||
key: '1',
|
const { record, column } = data;
|
||||||
name: 'Jane Doe',
|
if ((column as TableColumnData).dataIndex === 'ability') {
|
||||||
salary: 23000,
|
if (record.isSystem) {
|
||||||
address: '32 Park Road, London',
|
return {
|
||||||
email: 'jane.doe@example.com',
|
rowspan: 2,
|
||||||
},
|
};
|
||||||
{
|
}
|
||||||
key: '2',
|
if (record.isOrganization) {
|
||||||
name: 'Alisa Ross',
|
return {
|
||||||
salary: 25000,
|
rowspan: organizationSpan.value,
|
||||||
address: '35 Park Road, London',
|
};
|
||||||
email: 'alisa.ross@example.com',
|
}
|
||||||
},
|
if (record.isProject) {
|
||||||
{
|
return {
|
||||||
key: '3',
|
rowspan: projectSpan.value,
|
||||||
name: 'Kevin Sandra',
|
};
|
||||||
salary: 22000,
|
}
|
||||||
address: '31 Park Road, London',
|
}
|
||||||
email: 'kevin.sandra@example.com',
|
};
|
||||||
},
|
|
||||||
{
|
const { t } = useI18n();
|
||||||
key: '4',
|
|
||||||
name: 'Ed Hellen',
|
/**
|
||||||
salary: 17000,
|
* 生成数据
|
||||||
address: '42 Park Road, London',
|
* @param type
|
||||||
email: 'ed.hellen@example.com',
|
* @param idx
|
||||||
},
|
*/
|
||||||
{
|
const makeData = (item: UserGroupAuthSeting, type: AuthScopeType) => {
|
||||||
key: '5',
|
const result: AuthTableItem[] = [];
|
||||||
name: 'William Smith',
|
item.children?.forEach((child, index) => {
|
||||||
salary: 27000,
|
const perChecked =
|
||||||
address: '62 Park Road, London',
|
child?.permissions?.reduce((acc: string[], cur) => {
|
||||||
email: 'william.smith@example.com',
|
if (cur.enable) {
|
||||||
},
|
acc.push(cur.id);
|
||||||
];
|
}
|
||||||
|
return acc;
|
||||||
|
}, []) || [];
|
||||||
|
result.push({
|
||||||
|
id: child?.id,
|
||||||
|
license: child?.license,
|
||||||
|
enable: child?.enable,
|
||||||
|
permissions: child?.permissions,
|
||||||
|
indeterminate: perChecked?.length > 0,
|
||||||
|
perChecked,
|
||||||
|
ability: index === 0 ? t(`system.userGroup.${type}`) : undefined,
|
||||||
|
operationObject: t(child.name),
|
||||||
|
isSystem: index === 0 && type === 'SYSTEM',
|
||||||
|
isOrganization: index === 0 && type === 'ORGANIZATION',
|
||||||
|
isProject: index === 0 && type === 'PROJECT',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformData = (data: UserGroupAuthSeting[]) => {
|
||||||
|
const result: AuthTableItem[] = [];
|
||||||
|
data.forEach((item) => {
|
||||||
|
if (item.type === 'SYSTEM') {
|
||||||
|
systemSpan.value = item.children?.length || 0;
|
||||||
|
}
|
||||||
|
if (item.type === 'PROJECT') {
|
||||||
|
projectSpan.value = item.children?.length || 0;
|
||||||
|
}
|
||||||
|
if (item.type === 'ORGANIZATION') {
|
||||||
|
organizationSpan.value = item.children?.length || 0;
|
||||||
|
}
|
||||||
|
result.push(...makeData(item, item.id));
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initData = async (id: string) => {
|
||||||
|
try {
|
||||||
|
let tmpArr = [];
|
||||||
|
loading.value = true;
|
||||||
|
const res = await getGlobalUSetting(id);
|
||||||
|
tmpArr = transformData(res);
|
||||||
|
tableData.value = tmpArr;
|
||||||
|
} catch (error) {
|
||||||
|
tableData.value = [];
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 表格总全选change事件
|
||||||
|
const handleAllChangeByCheckbox = () => {
|
||||||
|
if (!tableData.value) return;
|
||||||
|
allChecked.value = !allChecked.value;
|
||||||
|
allIndeterminate.value = false;
|
||||||
|
const tmpArr = tableData.value;
|
||||||
|
tmpArr.forEach((item) => {
|
||||||
|
item.enable = allChecked.value;
|
||||||
|
item.indeterminate = false;
|
||||||
|
item.perChecked = allChecked.value ? item.permissions?.map((ele) => ele.id) : [];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格总全选联动触发事件
|
||||||
|
const handleAllChange = () => {
|
||||||
|
if (!tableData.value) return;
|
||||||
|
const tmpArr = tableData.value;
|
||||||
|
const { length: allLength } = tmpArr;
|
||||||
|
const { length } = tmpArr.filter((item) => item.enable);
|
||||||
|
if (length === allLength) {
|
||||||
|
allChecked.value = true;
|
||||||
|
allIndeterminate.value = false;
|
||||||
|
} else if (length === 0) {
|
||||||
|
allChecked.value = false;
|
||||||
|
allIndeterminate.value = false;
|
||||||
|
} else {
|
||||||
|
allChecked.value = false;
|
||||||
|
allIndeterminate.value = true;
|
||||||
|
}
|
||||||
|
if (!canSave.value) canSave.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格最后一列的复选框change事件
|
||||||
|
const handleActionChangeAll = (value: boolean | (string | number | boolean)[], rowIndex: number) => {
|
||||||
|
if (!tableData.value) return;
|
||||||
|
const tmpArr = tableData.value;
|
||||||
|
tmpArr[rowIndex].indeterminate = false;
|
||||||
|
if (value) {
|
||||||
|
tmpArr[rowIndex].enable = true;
|
||||||
|
tmpArr[rowIndex].perChecked = tmpArr[rowIndex].permissions?.map((item) => item.id);
|
||||||
|
} else {
|
||||||
|
tmpArr[rowIndex].enable = false;
|
||||||
|
tmpArr[rowIndex].perChecked = [];
|
||||||
|
}
|
||||||
|
tableData.value = [...tmpArr];
|
||||||
|
handleAllChange();
|
||||||
|
if (!canSave.value) canSave.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格第三列的复选框change事件
|
||||||
|
const handleAuthChange = (values: (string | number | boolean)[], rowIndex: number) => {
|
||||||
|
if (!tableData.value) return;
|
||||||
|
const tmpArr = tableData.value;
|
||||||
|
const length = tmpArr[rowIndex].permissions?.length || 0;
|
||||||
|
if (values.length === length) {
|
||||||
|
tmpArr[rowIndex].enable = true;
|
||||||
|
tmpArr[rowIndex].indeterminate = false;
|
||||||
|
handleAllChange();
|
||||||
|
} else if (values.length === 0) {
|
||||||
|
tmpArr[rowIndex].enable = false;
|
||||||
|
tmpArr[rowIndex].indeterminate = false;
|
||||||
|
handleAllChange();
|
||||||
|
} else {
|
||||||
|
tmpArr[rowIndex].enable = false;
|
||||||
|
tmpArr[rowIndex].indeterminate = true;
|
||||||
|
}
|
||||||
|
if (!canSave.value) canSave.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
const handleSave = async () => {
|
||||||
|
if (!tableData.value) return;
|
||||||
|
const permissions: SavePermissions[] = [];
|
||||||
|
|
||||||
|
const tmpArr = tableData.value;
|
||||||
|
tmpArr.forEach((item) => {
|
||||||
|
item.permissions?.forEach((ele) => {
|
||||||
|
ele.enable = item.perChecked?.includes(ele.id) || false;
|
||||||
|
permissions.push({
|
||||||
|
id: ele.id,
|
||||||
|
enable: ele.enable,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await saveGlobalUSetting({
|
||||||
|
userRoleId: store.currentId,
|
||||||
|
permissions,
|
||||||
|
});
|
||||||
|
initData(store.currentId);
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('error', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 恢复默认值
|
||||||
|
const handleReset = () => {
|
||||||
|
if (store.currentId) {
|
||||||
|
initData(store.currentId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (store.currentId) {
|
||||||
|
initData(store.currentId);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.action {
|
||||||
|
position: absolute;
|
||||||
|
right: 24px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 24px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: calc(100% - 24px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
v-model="searchKey"
|
v-model="searchKey"
|
||||||
class="w-[252px]"
|
class="w-[252px]"
|
||||||
:placeholder="t('system.userGroup.searchHolder')"
|
:placeholder="t('system.userGroup.searchHolder')"
|
||||||
@press-enter="searchData"
|
@press-enter="enterData"
|
||||||
|
@search="searchData"
|
||||||
/>
|
/>
|
||||||
<div class="mt-2 flex flex-col">
|
<div class="mt-2 flex flex-col">
|
||||||
<div class="flex h-[38px] items-center justify-between px-[8px] leading-[24px]">
|
<div class="flex h-[38px] items-center justify-between px-[8px] leading-[24px]">
|
||||||
|
@ -109,6 +110,33 @@
|
||||||
eventTag: 'delete',
|
eventTag: 'delete',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 点击用户组列表
|
||||||
|
const handleListItemClick = (element: UserGroupItem) => {
|
||||||
|
const { id, name, type } = element;
|
||||||
|
currentId.value = id;
|
||||||
|
store.setInfo({ currentName: name, currentTitle: type, currentId: id });
|
||||||
|
};
|
||||||
|
|
||||||
|
// 用户组数据初始化
|
||||||
|
const initData = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getUserGroupList();
|
||||||
|
if (res.length > 0) {
|
||||||
|
userGroupList.value = res;
|
||||||
|
handleListItemClick(res[0]);
|
||||||
|
// 弹窗赋值
|
||||||
|
const tmpObj: PopVisibleItem = {};
|
||||||
|
res.forEach((element) => {
|
||||||
|
tmpObj[element.id] = false;
|
||||||
|
});
|
||||||
|
popVisible.value = tmpObj;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
// 新增用户组
|
// 新增用户组
|
||||||
const addUserGroup = () => {
|
const addUserGroup = () => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
@ -139,6 +167,7 @@
|
||||||
try {
|
try {
|
||||||
await deleteUserGroup(id);
|
await deleteUserGroup(id);
|
||||||
Message.success(t('system.user.deleteUserSuccess'));
|
Message.success(t('system.user.deleteUserSuccess'));
|
||||||
|
initData();
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
@ -151,39 +180,12 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 点击用户组列表
|
|
||||||
const handleListItemClick = (element: UserGroupItem) => {
|
|
||||||
const { id, name, type } = element;
|
|
||||||
currentId.value = id;
|
|
||||||
store.setInfo({ currentName: name, currentTitle: type });
|
|
||||||
};
|
|
||||||
|
|
||||||
// 用户组数据初始化
|
|
||||||
const initData = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getUserGroupList();
|
|
||||||
if (res.length > 0) {
|
|
||||||
userGroupList.value = res;
|
|
||||||
handleListItemClick(res[0]);
|
|
||||||
// 弹窗赋值
|
|
||||||
const tmpObj: PopVisibleItem = {};
|
|
||||||
res.forEach((element) => {
|
|
||||||
tmpObj[element.id] = false;
|
|
||||||
});
|
|
||||||
popVisible.value = tmpObj;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 关闭confirm 弹窗
|
// 关闭confirm 弹窗
|
||||||
const handlePopConfirmCancel = (id: string) => {
|
const handlePopConfirmCancel = (id: string) => {
|
||||||
popVisible.value = { ...popVisible.value, [id]: false };
|
popVisible.value = { ...popVisible.value, [id]: false };
|
||||||
};
|
};
|
||||||
// 修改用户组名字,权限范围
|
// 修改用户组名字,权限范围
|
||||||
const handlePopConfirmSubmit = async (item: CustomMoreActionItem, id: string) => {
|
const handlePopConfirmSubmit = async (item: CustomMoreActionItem, id: string) => {
|
||||||
popVisible.value = { ...popVisible.value, [id]: false };
|
|
||||||
if (item.eventKey === 'rename') {
|
if (item.eventKey === 'rename') {
|
||||||
// 修改用户组名字
|
// 修改用户组名字
|
||||||
try {
|
try {
|
||||||
|
@ -207,10 +209,11 @@
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
popVisible.value = { ...popVisible.value, [id]: false };
|
||||||
initData();
|
initData();
|
||||||
};
|
};
|
||||||
|
|
||||||
function searchData(eve: Event) {
|
function enterData(eve: Event) {
|
||||||
if (!(eve.target as HTMLInputElement).value) {
|
if (!(eve.target as HTMLInputElement).value) {
|
||||||
initData();
|
initData();
|
||||||
return;
|
return;
|
||||||
|
@ -219,6 +222,15 @@
|
||||||
const tmpArr = userGroupList.value.filter((ele) => ele.name.includes(keyword));
|
const tmpArr = userGroupList.value.filter((ele) => ele.name.includes(keyword));
|
||||||
userGroupList.value = tmpArr;
|
userGroupList.value = tmpArr;
|
||||||
}
|
}
|
||||||
|
function searchData(value: string) {
|
||||||
|
if (!value) {
|
||||||
|
initData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const keyword = value;
|
||||||
|
const tmpArr = userGroupList.value.filter((ele) => ele.name.includes(keyword));
|
||||||
|
userGroupList.value = tmpArr;
|
||||||
|
}
|
||||||
// 新增用户组
|
// 新增用户组
|
||||||
const handleAddUserGroup = async (value: Partial<UserGroupItem>) => {
|
const handleAddUserGroup = async (value: Partial<UserGroupItem>) => {
|
||||||
try {
|
try {
|
||||||
|
@ -226,6 +238,7 @@
|
||||||
const res = await updateOrAddUserGroup(value);
|
const res = await updateOrAddUserGroup(value);
|
||||||
if (res) {
|
if (res) {
|
||||||
Message.success(t('system.userGroup.addUserGroupSuccess'));
|
Message.success(t('system.userGroup.addUserGroupSuccess'));
|
||||||
|
addUserGroupVisible.value = false;
|
||||||
initData();
|
initData();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
:popup-visible="renameVisible"
|
:popup-visible="renameVisible"
|
||||||
:ok-text="t('system.userGroup.confirm')"
|
:ok-text="t('system.userGroup.confirm')"
|
||||||
:cancel-text="t('system.userGroup.cancel')"
|
:cancel-text="t('system.userGroup.cancel')"
|
||||||
@ok="handleSubmit"
|
@before-ok="handleSubmit"
|
||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
@popup-visible-change="() => (form.name = '')"
|
@popup-visible-change="() => (form.name = '')"
|
||||||
>
|
>
|
||||||
|
@ -29,13 +29,13 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { watchEffect, reactive, ref, computed, onUnmounted } from 'vue';
|
import { watchEffect, ref, computed, onUnmounted } from 'vue';
|
||||||
import { CustomMoreActionItem, RenameType, UserGroupItem } from '@/models/system/usergroup';
|
import { CustomMoreActionItem, RenameType, UserGroupItem } from '@/models/system/usergroup';
|
||||||
import { ValidatedError } from '@arco-design/web-vue';
|
import { ValidatedError } from '@arco-design/web-vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const form = reactive({
|
const form = ref({
|
||||||
name: '',
|
name: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@
|
||||||
list: UserGroupItem[];
|
list: UserGroupItem[];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const validateName = (value: string, callback: (error?: string) => void) => {
|
const validateName = (value: string | undefined, callback: (error?: string) => void) => {
|
||||||
if (props.type === 'rename') {
|
if (props.type === 'rename') {
|
||||||
if (value === '') {
|
if (value === undefined || value === '') {
|
||||||
callback(t('system.userGroup.userGroupNameIsNotNone'));
|
callback(t('system.userGroup.userGroupNameIsNotNone'));
|
||||||
} else {
|
} else {
|
||||||
if (value === props.defaultName) {
|
if (value === props.defaultName) {
|
||||||
|
@ -88,20 +88,22 @@
|
||||||
|
|
||||||
const renameVisible = ref(props.visible);
|
const renameVisible = ref(props.visible);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = async () => {
|
||||||
formRef.value.validate((errors: undefined | Record<string, ValidatedError>) => {
|
await formRef.value.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
emit('submit', { eventKey: props.type, name: form.name });
|
emit('submit', { eventKey: props.type, name: form.value.name });
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
form.name = '';
|
form.value.name = '';
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
};
|
};
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
renameVisible.value = props.visible;
|
renameVisible.value = props.visible;
|
||||||
form.name = props.defaultName;
|
form.value.name = props.defaultName;
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|
|
@ -1,94 +1,45 @@
|
||||||
<template>
|
<template>
|
||||||
<MsBaseTable v-bind="propsRes" v-on="propsEvent"> </MsBaseTable>
|
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
|
||||||
|
<template #action="{ record }">
|
||||||
|
<ms-button type="link" @click="handleRemove(record)">{{ t('system.userGroup.remove') }}</ms-button>
|
||||||
|
</template>
|
||||||
|
</MsBaseTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getTableList } from '@/api/modules/api-test/index';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
import { onMounted } from 'vue';
|
import useUserGroupStore from '@/store/modules/system/usergroup';
|
||||||
|
import { watchEffect } from 'vue';
|
||||||
|
import { postUserByUserGroup, deleteUserFromUserGroup } from '@/api/modules/system/usergroup';
|
||||||
|
import { UserTableItem } from '@/models/system/usergroup';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const store = useUserGroupStore();
|
||||||
|
|
||||||
const columns: MsTableColumn = [
|
const columns: MsTableColumn = [
|
||||||
{
|
{
|
||||||
title: 'ID',
|
title: 'system.userGroup.name',
|
||||||
dataIndex: 'num',
|
|
||||||
filterable: {
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
text: '> 20000',
|
|
||||||
value: '20000',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '> 30000',
|
|
||||||
value: '30000',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
filter: (value, record) => record.salary > value,
|
|
||||||
multiple: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '接口名称',
|
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
width: 200,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '请求类型',
|
title: 'system.userGroup.email',
|
||||||
dataIndex: 'method',
|
dataIndex: 'email',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '责任人',
|
title: 'system.userGroup.phone',
|
||||||
dataIndex: 'username',
|
dataIndex: 'email',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '路径',
|
title: 'system.userGroup.operation',
|
||||||
dataIndex: 'path',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '标签',
|
|
||||||
dataIndex: 'tags',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '更新时间',
|
|
||||||
dataIndex: 'updateTime',
|
|
||||||
sortable: {
|
|
||||||
sortDirections: ['ascend', 'descend'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用例数',
|
|
||||||
dataIndex: 'caseTotal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用例状态',
|
|
||||||
dataIndex: 'caseStatus',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '用例通过率',
|
|
||||||
dataIndex: 'casePassingRate',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '接口状态',
|
|
||||||
dataIndex: 'status',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '创建时间',
|
|
||||||
slotName: 'createTime',
|
|
||||||
width: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '描述',
|
|
||||||
dataIndex: 'description',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
slotName: 'action',
|
slotName: 'action',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const { propsRes, propsEvent, loadList } = useTable(getTableList, {
|
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(postUserByUserGroup, {
|
||||||
columns,
|
columns,
|
||||||
scroll: { y: 750, x: 2000 },
|
scroll: { y: 750, x: 2000 },
|
||||||
selectable: true,
|
selectable: true,
|
||||||
|
@ -96,7 +47,14 @@
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
await loadList();
|
await loadList();
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
const handleRemove = async (record: UserTableItem) => {
|
||||||
|
await deleteUserFromUserGroup(record.id);
|
||||||
|
await fetchData();
|
||||||
|
};
|
||||||
|
watchEffect(() => {
|
||||||
|
if (store.currentId) {
|
||||||
|
setLoadListParams({ roleId: store.currentId });
|
||||||
fetchData();
|
fetchData();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="user-group flex flex-row bg-white">
|
<div class="user-group flex flex-row bg-white">
|
||||||
<div class="user-group-left">
|
<div class="user-group-left">
|
||||||
<UserGroupLeft />
|
<user-group-left v-if="collapse" />
|
||||||
|
<div class="usergroup-collapse">
|
||||||
|
<icon-double-left v-if="collapse" class="icon" @click="collapse = false" />
|
||||||
|
<icon-double-right v-else class="icon" @click="collapse = true" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grow-1 w-[100%] overflow-x-scroll p-[24px]">
|
<div class="grow-1 w-[100%] overflow-x-scroll p-[24px]">
|
||||||
<div class="grow-1 flex flex-row items-center justify-between">
|
<div class="grow-1 flex flex-row items-center justify-between">
|
||||||
|
@ -35,6 +39,7 @@
|
||||||
import AuthTable from './components/authTable.vue';
|
import AuthTable from './components/authTable.vue';
|
||||||
|
|
||||||
const currentTable = ref('auth');
|
const currentTable = ref('auth');
|
||||||
|
const collapse = ref(true);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
@ -52,5 +57,21 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
border-right: 1px solid var(--color-border);
|
border-right: 1px solid var(--color-border);
|
||||||
|
.usergroup-collapse {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: -16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 16px;
|
||||||
|
height: 36px;
|
||||||
|
background-color: var(--color-text-n8);
|
||||||
|
cursor: pointer;
|
||||||
|
.icon {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-brand);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export default {
|
export default {
|
||||||
system: {
|
system: {
|
||||||
userGroup: {
|
userGroup: {
|
||||||
|
addUserGroupSuccess: 'Add user group success',
|
||||||
searchHolder: 'Please input user group name',
|
searchHolder: 'Please input user group name',
|
||||||
inSystem: 'In system',
|
inSystem: 'In system',
|
||||||
customUserGroup: 'Custom user group',
|
customUserGroup: 'Custom user group',
|
||||||
|
@ -40,6 +41,34 @@ export default {
|
||||||
beforeDeleteUserGroup:
|
beforeDeleteUserGroup:
|
||||||
'After deletion, the project data under the organization will be deleted together. Please operate with caution!',
|
'After deletion, the project data under the organization will be deleted together. Please operate with caution!',
|
||||||
confirmDelete: 'Confirm delete',
|
confirmDelete: 'Confirm delete',
|
||||||
|
function: 'Function',
|
||||||
|
operationObject: 'Operation object',
|
||||||
|
system: 'System',
|
||||||
|
project: 'Project',
|
||||||
|
organization: 'Organization',
|
||||||
|
save: 'Save',
|
||||||
|
reset: 'Restore default',
|
||||||
|
name: 'Name',
|
||||||
|
email: 'Email',
|
||||||
|
operation: 'Operation',
|
||||||
|
phone: 'Phone',
|
||||||
|
remove: 'Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
permission: {
|
||||||
|
system_user_role: {
|
||||||
|
name: 'Name',
|
||||||
|
read: 'Read',
|
||||||
|
add: 'Add',
|
||||||
|
update: 'Update',
|
||||||
|
delete: 'Delete',
|
||||||
|
},
|
||||||
|
system_test_resource_pool: {
|
||||||
|
name: 'Name',
|
||||||
|
read: 'Read',
|
||||||
|
add: 'Add',
|
||||||
|
update: 'Update',
|
||||||
|
delete: 'Delete',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export default {
|
export default {
|
||||||
system: {
|
system: {
|
||||||
userGroup: {
|
userGroup: {
|
||||||
|
addUserGroupSuccess: '添加用户组成功',
|
||||||
global: '全局用户组',
|
global: '全局用户组',
|
||||||
searchHolder: '请输入用户组名称',
|
searchHolder: '请输入用户组名称',
|
||||||
inSystem: '系统内置',
|
inSystem: '系统内置',
|
||||||
|
@ -39,6 +40,34 @@ export default {
|
||||||
isDeleteUserGroup: '是否删除: {name}?',
|
isDeleteUserGroup: '是否删除: {name}?',
|
||||||
beforeDeleteUserGroup: '删除后,该组织下的项目数据将一起删除,请谨慎操作!',
|
beforeDeleteUserGroup: '删除后,该组织下的项目数据将一起删除,请谨慎操作!',
|
||||||
confirmDelete: '确认删除',
|
confirmDelete: '确认删除',
|
||||||
|
function: '功能',
|
||||||
|
operationObject: '操作对象',
|
||||||
|
system: '系统',
|
||||||
|
project: '项目',
|
||||||
|
organization: '组织',
|
||||||
|
save: '保存',
|
||||||
|
reset: '恢复默认',
|
||||||
|
name: '姓名',
|
||||||
|
email: '邮箱',
|
||||||
|
operation: '操作',
|
||||||
|
phone: '手机',
|
||||||
|
remove: '移除',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
permission: {
|
||||||
|
system_user_role: {
|
||||||
|
name: '系统用户',
|
||||||
|
read: '读取',
|
||||||
|
add: '添加',
|
||||||
|
update: '更新',
|
||||||
|
delete: '删除',
|
||||||
|
},
|
||||||
|
system_test_resource_pool: {
|
||||||
|
name: '系统测试资源池',
|
||||||
|
read: '读取',
|
||||||
|
add: '添加',
|
||||||
|
update: '更新',
|
||||||
|
delete: '删除',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue