Compare commits
2 Commits
d4457b9f30
...
1ce760c489
Author | SHA1 | Date | |
---|---|---|---|
1ce760c489 | |||
4dd21ebc53 |
@ -97,7 +97,7 @@ export function useRouterPush(inSetup = true) {
|
||||
const redirect = route.value.query?.redirect as string;
|
||||
console.log(redirect);
|
||||
if (needRedirect && redirect) {
|
||||
await routerPush(redirect);
|
||||
await toHome();
|
||||
} else {
|
||||
await toHome();
|
||||
}
|
||||
|
@ -41,16 +41,26 @@ export function useTable<A extends NaiveUI.TableApiFn>(config: NaiveUI.NaiveTabl
|
||||
transformer: res => {
|
||||
console.log(res);
|
||||
const { data = [], current = 1, size = 10, total = 0 } = res || {};
|
||||
|
||||
// Ensure that the size is greater than 0, If it is less than 0, it will cause paging calculation errors.
|
||||
console.log(total);
|
||||
const pageSize = size <= 0 ? 10 : size;
|
||||
|
||||
const recordsWithIndex = data.map((item, index) => {
|
||||
return {
|
||||
...item,
|
||||
index: (current - 1) * pageSize + index + 1
|
||||
};
|
||||
});
|
||||
if(data.data){
|
||||
var recordsWithIndex = data.data.map((item, index) => {
|
||||
return {
|
||||
...item,
|
||||
index: (current - 1) * pageSize + index + 1
|
||||
};
|
||||
});
|
||||
}else{
|
||||
var recordsWithIndex = data.map((item, index) => {
|
||||
return {
|
||||
...item,
|
||||
index: (current - 1) * pageSize + index + 1
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
console.log(recordsWithIndex);
|
||||
return {
|
||||
data: recordsWithIndex,
|
||||
|
@ -21,6 +21,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
||||
"iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"),
|
||||
login: () => import("@/views/_builtin/login/index.vue"),
|
||||
home: () => import("@/views/home/index.vue"),
|
||||
system_auth: () => import("@/views/system/auth/index.vue"),
|
||||
system_menu: () => import("@/views/system/menu/index.vue"),
|
||||
system_user: () => import("@/views/system/user/index.vue"),
|
||||
};
|
||||
|
@ -84,6 +84,15 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
i18nKey: 'route.system'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'system_auth',
|
||||
path: '/system/auth',
|
||||
component: 'view.system_auth',
|
||||
meta: {
|
||||
title: 'system_auth',
|
||||
i18nKey: 'route.system_auth'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'system_menu',
|
||||
path: '/system/menu',
|
||||
|
@ -170,6 +170,7 @@ const routeMap: RouteMap = {
|
||||
"iframe-page": "/iframe-page/:url",
|
||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
|
||||
"system": "/system",
|
||||
"system_auth": "/system/auth",
|
||||
"system_menu": "/system/menu",
|
||||
"system_user": "/system/user"
|
||||
};
|
||||
|
@ -24,6 +24,7 @@ export function createRouteGuard(router: Router) {
|
||||
next(location);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const authStore = useAuthStore();
|
||||
|
||||
@ -37,19 +38,22 @@ export function createRouteGuard(router: Router) {
|
||||
|
||||
const hasRole = authStore.userInfo.roles.some(role => routeRoles.includes(role));
|
||||
const hasAuth = authStore.isStaticSuper || !routeRoles.length || hasRole;
|
||||
// if(!location){
|
||||
// next({ name: 'home' });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if it is login route when logged in, then switch to the root page
|
||||
if (to.name === loginRoute && isLogin) {
|
||||
next({ name: rootRoute });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// if the route does not need login, then it is allowed to access directly
|
||||
if (!needLogin) {
|
||||
handleRouteSwitch(to, from, next);
|
||||
return;
|
||||
}
|
||||
|
||||
// the route need login but the user is not logged in, then switch to the login page
|
||||
if (!isLogin) {
|
||||
next({ name: loginRoute, query: { redirect: to.fullPath } });
|
||||
@ -164,6 +168,8 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
|
||||
|
||||
function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {
|
||||
// route with href
|
||||
|
||||
|
||||
if (to.meta.href) {
|
||||
window.open(to.meta.href, '_blank');
|
||||
|
||||
|
@ -8,7 +8,6 @@ export const ROOT_ROUTE: CustomRoute = {
|
||||
redirect: '/home',
|
||||
meta: {
|
||||
title: 'root',
|
||||
constant: true
|
||||
}
|
||||
};
|
||||
|
||||
|
37
src/service/api/group.ts
Normal file
37
src/service/api/group.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { request } from '../request';
|
||||
|
||||
/** 获取API权限组列表 */
|
||||
export function fetchGetGroups(params?: Api.Common.CommonSearchParams) {
|
||||
return request<GroupApi.GroupListResponse>({
|
||||
url: '/adminapi/group/index',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/** 添加API权限组 */
|
||||
export function addGroup(data: Partial<GroupApi.Group>) {
|
||||
return request({
|
||||
url: '/adminapi/group/add',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 编辑API权限组 */
|
||||
export function editGroup(data: Partial<GroupApi.Group>) {
|
||||
return request({
|
||||
url: `/adminapi/group/edit/ids/${data.id}`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除API权限组 */
|
||||
export function deleteGroup(id) {
|
||||
return request({
|
||||
url: `/adminapi/group/del/ids`,
|
||||
method: 'post',
|
||||
data:{ids:id}
|
||||
});
|
||||
}
|
@ -1,2 +1,39 @@
|
||||
export * from './auth';
|
||||
export * from './route';
|
||||
|
||||
import { request } from '../request';
|
||||
|
||||
|
||||
/** 添加API权限组 */
|
||||
export function fetchGetAdminList(data) {
|
||||
return request({
|
||||
url: '/adminapi/admin_manager/index',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
/** 添加API权限组 */
|
||||
export function addAdmin(data,type) {
|
||||
return request({
|
||||
url: '/adminapi/admin_manager/add',
|
||||
method:type,
|
||||
data
|
||||
});
|
||||
}
|
||||
/** 添加API权限组 */
|
||||
export function editAdmin(data) {
|
||||
return request({
|
||||
url: '/adminapi/admin_manager/edit/ids',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/** 添加API权限组 */
|
||||
export function deleteAdmin(data) {
|
||||
return request({
|
||||
url: '/adminapi/admin_manager/del/ids',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
@ -7,7 +7,7 @@ export function fetchGetConstantRoutes() {
|
||||
|
||||
/** get user routes */
|
||||
export function fetchGetUserRoutes() {
|
||||
return request<Api.Route.UserRoute>({ url: '/adminapi/rule/index?is_tree=1' });
|
||||
return request<Api.Route.UserRoute>({ url: '/adminapi/admin/menu?is_tree=1' });
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,6 +10,8 @@ import { $t } from '@/locales';
|
||||
import { useRouteStore } from '../route';
|
||||
import { useTabStore } from '../tab';
|
||||
import { clearAuthStorage, getToken } from './shared';
|
||||
import { router } from '@/router';
|
||||
|
||||
|
||||
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||
const route = useRoute();
|
||||
@ -69,8 +71,8 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||
const pass = await loginByToken(response.data.data.userinfo);
|
||||
|
||||
if (pass) {
|
||||
await redirectFromLogin(redirect);
|
||||
|
||||
//await redirectFromLogin(redirect);
|
||||
router.push('home');
|
||||
window.$notification?.success({
|
||||
title: $t('page.login.common.loginSuccess'),
|
||||
content: $t('page.login.common.welcomeBack', { userName: response.data.data.userinfo.nickname }),
|
||||
|
@ -299,14 +299,13 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
|
||||
*/
|
||||
function handleUpdateRootRouteRedirect(redirectKey: LastLevelRouteKey) {
|
||||
const redirect = getRoutePath(redirectKey);
|
||||
|
||||
|
||||
if (redirect) {
|
||||
const rootRoute: CustomRoute = { ...ROOT_ROUTE, redirect };
|
||||
|
||||
router.removeRoute(rootRoute.name);
|
||||
|
||||
const [rootVueRoute] = getAuthVueRoutes([rootRoute]);
|
||||
|
||||
router.addRoute(rootVueRoute);
|
||||
}
|
||||
}
|
||||
|
2
src/typings/elegant-router.d.ts
vendored
2
src/typings/elegant-router.d.ts
vendored
@ -24,6 +24,7 @@ declare module "@elegant-router/types" {
|
||||
"iframe-page": "/iframe-page/:url";
|
||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
||||
"system": "/system";
|
||||
"system_auth": "/system/auth";
|
||||
"system_menu": "/system/menu";
|
||||
"system_user": "/system/user";
|
||||
};
|
||||
@ -86,6 +87,7 @@ declare module "@elegant-router/types" {
|
||||
| "iframe-page"
|
||||
| "login"
|
||||
| "home"
|
||||
| "system_auth"
|
||||
| "system_menu"
|
||||
| "system_user"
|
||||
>;
|
||||
|
32
src/typings/group.d.ts
vendored
Normal file
32
src/typings/group.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 权限组相关类型定义
|
||||
*/
|
||||
declare namespace GroupApi {
|
||||
/** 权限组数据类型 */
|
||||
interface Group {
|
||||
/** 权限组ID */
|
||||
id: number;
|
||||
/** 权限组名称 */
|
||||
name: string;
|
||||
/** 规则ID */
|
||||
rules: string;
|
||||
/** 创建时间 */
|
||||
createtime: string;
|
||||
/** 更新时间 */
|
||||
updatetime: string;
|
||||
/** 状态 */
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** 权限组列表响应 */
|
||||
interface GroupListResponse {
|
||||
/** 权限组列表 */
|
||||
data: Group[];
|
||||
/** 当前页码 */
|
||||
current: number;
|
||||
/** 每页条数 */
|
||||
size: number;
|
||||
/** 总条数 */
|
||||
total: number;
|
||||
}
|
||||
}
|
278
src/views/system/auth/index.vue
Normal file
278
src/views/system/auth/index.vue
Normal file
@ -0,0 +1,278 @@
|
||||
<script setup lang="tsx">
|
||||
import { ref } from 'vue';
|
||||
import type { Ref } from 'vue';
|
||||
import { NButton, NPopconfirm, NTag, NTreeSelect } from 'naive-ui';
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import { yesOrNoRecord } from '@/constants/common';
|
||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
||||
import { fetchGetGroups, addGroup, editGroup, deleteGroup } from '@/service/api/group';
|
||||
import { fetchGetUserRoutes } from '@/service/api/route';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const { bool: visible, setTrue: openModal } = useBoolean();
|
||||
|
||||
const wrapperRef = ref<HTMLElement | null>(null);
|
||||
const title = ref('');
|
||||
const rulesTree = ref<any[]>([]);
|
||||
const rulesLoading = ref(false);
|
||||
|
||||
const model = ref<Partial<GroupApi.Group & { rulesArray: (string | number)[] }>>({
|
||||
id: 0,
|
||||
name: '',
|
||||
rules: '',
|
||||
status: 'normal',
|
||||
rulesArray: []
|
||||
});
|
||||
const rules = {};
|
||||
|
||||
const { columns, columnChecks, data, loading, pagination, getData, getDataByPage } = useTable({
|
||||
apiFn: fetchGetGroups,
|
||||
columns: () => [
|
||||
{
|
||||
key: 'id',
|
||||
title: 'ID',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
title: '权限组名称',
|
||||
align: 'center',
|
||||
width: 250,
|
||||
},
|
||||
{
|
||||
key: 'rules',
|
||||
title: '规则ID',
|
||||
align: 'center',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
key: 'createtime',
|
||||
title: '创建时间',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
key: 'updatetime',
|
||||
title: '更新时间',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: '状态',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
render: (row) => {
|
||||
const status: CommonType.YesOrNo = row.status === 'hidden' ? 'N' : 'Y';
|
||||
|
||||
const tagMap: Record<CommonType.YesOrNo, NaiveUI.ThemeColor> = {
|
||||
Y: 'error',
|
||||
N: 'default'
|
||||
};
|
||||
|
||||
const label = $t(yesOrNoRecord[status]);
|
||||
|
||||
return <NTag type={ tagMap[status] }> { label } </NTag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'operate',
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: 230,
|
||||
render: (row) => (
|
||||
<div class= "flex-center justify-end gap-8px" >
|
||||
<NButton type="primary" ghost size="small" onClick={() => handleEdit(row)}>
|
||||
编辑
|
||||
</NButton>
|
||||
< NPopconfirm onPositiveClick = {() => handleDelete(row.id as number)}>
|
||||
{{
|
||||
default: () => '确定删除吗?',
|
||||
trigger: () => (
|
||||
<NButton type= "error" ghost size = "small" >
|
||||
删除
|
||||
</NButton>
|
||||
)
|
||||
}}
|
||||
</NPopconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
|
||||
|
||||
const operateType = ref('add');
|
||||
|
||||
function handleAdd() {
|
||||
operateType.value = 'add';
|
||||
title.value = '新增API权限组';
|
||||
// 清空model
|
||||
model.value = {
|
||||
id: 0,
|
||||
name: '',
|
||||
rules: '',
|
||||
status: 'normal',
|
||||
rulesArray: []
|
||||
};
|
||||
openModal();
|
||||
}
|
||||
|
||||
async function handleDelete(id: number) {
|
||||
// request
|
||||
const { response } = await deleteGroup(id);
|
||||
console.log(response);
|
||||
if (response?.data?.code === 1) {
|
||||
window.$message?.success('删除成功!');
|
||||
getData();
|
||||
} else {
|
||||
window.$message?.error(response?.data?.msg || '删除失败');
|
||||
}
|
||||
}
|
||||
|
||||
function handleEdit(item: any) {
|
||||
operateType.value = 'edit';
|
||||
title.value = '编辑API权限组';
|
||||
model.value = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
rules: item.rules,
|
||||
status: item.status,
|
||||
rulesArray: rulesStrToArray(item.rules)
|
||||
};
|
||||
openModal();
|
||||
}
|
||||
|
||||
function init() {
|
||||
initRulesTree();
|
||||
}
|
||||
|
||||
// 创建获取规则树数据的函数
|
||||
async function initRulesTree() {
|
||||
rulesLoading.value = true;
|
||||
try {
|
||||
const { response } = await fetchGetUserRoutes();
|
||||
if (response?.data?.code === 1) {
|
||||
// 假设接口返回的数据结构需要转换成tree格式
|
||||
rulesTree.value = formatRulesTree(response.data.data || []);
|
||||
} else {
|
||||
window.$message?.error(response?.data?.msg || '获取规则列表失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取规则列表失败', error);
|
||||
window.$message?.error('获取规则列表失败');
|
||||
} finally {
|
||||
rulesLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 转换规则树数据格式的函数
|
||||
function formatRulesTree(data: any[]) {
|
||||
// 根据实际API返回结构进行格式转换
|
||||
// 这里假设API返回的数据结构已经是合适的树形结构
|
||||
// 可能需要根据实际情况调整键名,如把id改为key,把name改为label等
|
||||
return data.map(item => ({
|
||||
key: item.id,
|
||||
label: item.title || item.name,
|
||||
children: item.children ? formatRulesTree(item.children) : undefined
|
||||
}));
|
||||
}
|
||||
|
||||
// ID字符串转数组的函数
|
||||
function rulesStrToArray(rulesStr: string): (string | number)[] {
|
||||
if (!rulesStr) return [];
|
||||
return rulesStr.split(',').map(item => {
|
||||
// 如果ID是数字类型,则转换为数字
|
||||
const numId = Number(item);
|
||||
return isNaN(numId) ? item : numId;
|
||||
});
|
||||
}
|
||||
|
||||
// ID数组转字符串的函数
|
||||
function rulesArrayToStr(rulesArray: (string | number)[]): string {
|
||||
if (!rulesArray || !rulesArray.length) return '';
|
||||
return rulesArray.join(',');
|
||||
}
|
||||
|
||||
// init
|
||||
init();
|
||||
|
||||
async function handleSubmit() {
|
||||
// 在提交前将规则数组转换为字符串
|
||||
if (model.value.rulesArray) {
|
||||
model.value.rules = rulesArrayToStr(model.value.rulesArray);
|
||||
}
|
||||
|
||||
let res;
|
||||
if (operateType.value === 'add') {
|
||||
res = await addGroup(model.value);
|
||||
} else {
|
||||
res = await editGroup(model.value);
|
||||
}
|
||||
console.log('response: ', res.response);
|
||||
if (res.response?.data?.code === 1) {
|
||||
window.$message?.success(res.response.data.msg);
|
||||
visible.value = false;
|
||||
getData();
|
||||
} else {
|
||||
window.$message?.error(res.response?.data?.msg || '操作失败');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="wrapperRef" class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<NCard title="API权限组管理" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation v-model:columns="columnChecks" :disabled-delete="checkedRowKeys.length === 0"
|
||||
:loading="loading" @add="handleAdd" @refresh="getData" />
|
||||
</template>
|
||||
<NDataTable v-model:checked-row-keys="checkedRowKeys" :columns="columns" :data="data" size="small"
|
||||
:flex-height="!appStore.isMobile" :scroll-x="1088" :loading="loading" :row-key="row => row.id" remote
|
||||
:pagination="pagination" class="sm:h-full" />
|
||||
</NCard>
|
||||
<NModal v-model:show="visible" :title="title" preset="card" class="w-800px">
|
||||
<NScrollbar class="h-480px pr-20px">
|
||||
<NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="100">
|
||||
<NGrid responsive="screen" item-responsive>
|
||||
<NFormItemGi span="24" label="权限组名称" path="name">
|
||||
<NInput v-model:value="model.name" placeholder="请输入权限组名称" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24" label="规则ID" path="rulesArray">
|
||||
<NTreeSelect
|
||||
v-model:value="model.rulesArray"
|
||||
placeholder="请选择规则"
|
||||
:options="rulesTree"
|
||||
:loading="rulesLoading"
|
||||
multiple
|
||||
cascade
|
||||
checkable
|
||||
clearable
|
||||
/>
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 m:12" label="状态" path="status">
|
||||
<NRadioGroup v-model:value="model.status">
|
||||
<NRadio value="hidden" label="禁用" />
|
||||
<NRadio value="normal" label="正常" />
|
||||
</NRadioGroup>
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
</NForm>
|
||||
</NScrollbar>
|
||||
<template #footer>
|
||||
<NSpace justify="end" :size="16">
|
||||
<NButton @click="visible = false">取消</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">确认</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -1,7 +1,220 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>用户管理</h1>
|
||||
<div ref="wrapperRef" class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<NCard title="管理员管理" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation v-model:columns="columnChecks" :disabled-delete="checkedRowKeys.length === 0"
|
||||
:loading="loading" @add="handleAdd" @refresh="getData" />
|
||||
</template>
|
||||
<NDataTable v-model:checked-row-keys="checkedRowKeys" :columns="columns" :data="data" size="small"
|
||||
:flex-height="!appStore.isMobile" :scroll-x="1088" :loading="loading" :row-key="row => row.id" remote
|
||||
:pagination="pagination" class="sm:h-full" />
|
||||
</NCard>
|
||||
<NModal v-model:show="visible" :title="title" preset="card" class="w-800px">
|
||||
<NScrollbar class="h-480px pr-20px">
|
||||
<NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="100">
|
||||
<NGrid responsive="screen" item-responsive>
|
||||
<NFormItemGi span="24 m:12" label="用户名" path="username">
|
||||
<NInput v-model:value="model.username" placeholder="请输入用户名" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 m:12" label="昵称" path="nickname">
|
||||
<NInput v-model:value="model.nickname" placeholder="请输入昵称" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 m:12" label="密码" path="password">
|
||||
<NInput v-model:value="model.password" type="password" placeholder="请输入密码" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 m:12" label="用户组" path="group">
|
||||
<NSelect v-model:value="model.group" :options="groupOptions" placeholder="请选择用户组" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 m:12" label="邮箱" path="email">
|
||||
<NInput v-model:value="model.email" placeholder="请输入邮箱" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 m:12" label="手机号" path="mobile">
|
||||
<NInput v-model:value="model.mobile" placeholder="请输入手机号" />
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
</NForm>
|
||||
</NScrollbar>
|
||||
<template #footer>
|
||||
<NSpace justify="end" :size="16">
|
||||
<NButton @click="visible = false">取消</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">确认</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import type { Ref } from 'vue';
|
||||
import { NButton, NPopconfirm, NTag, NSelect } from 'naive-ui';
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { fetchGetAdminList, addAdmin, editAdmin, deleteAdmin } from '@/service/api/index';
|
||||
import { fetchGetGroups } from '@/service/api/group';
|
||||
import { log } from 'console';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const { bool: visible, setTrue: openModal } = useBoolean();
|
||||
|
||||
const wrapperRef = ref<HTMLElement | null>(null);
|
||||
const title = ref('');
|
||||
|
||||
const groupOptions = ref<{ label: string; value: number }[]>([]);
|
||||
|
||||
// 获取用户组数据
|
||||
async function getGroupOptions() {
|
||||
const { response } = await fetchGetGroups();
|
||||
console.log(response.data)
|
||||
if (response.data.code == 1) {
|
||||
const data = (response.data).data.data;
|
||||
console.log(data);
|
||||
groupOptions.value = data.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log(111111111);
|
||||
getGroupOptions();
|
||||
});
|
||||
const model = ref({
|
||||
username: '',
|
||||
nickname: '',
|
||||
password: '',
|
||||
group: null,
|
||||
email: '',
|
||||
mobile: '',
|
||||
id: 0,
|
||||
});
|
||||
const rules = {};
|
||||
const { columns, columnChecks, data, loading, pagination, getData, getDataByPage } = useTable({
|
||||
apiFn: fetchGetAdminList,
|
||||
columns: () => [
|
||||
{
|
||||
key: 'id',
|
||||
title: 'ID',
|
||||
align: 'center',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
key: 'username',
|
||||
title: '用户名',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
key: 'nickname',
|
||||
title: '昵称',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
key: 'groups_text',
|
||||
title: '用户组',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
title: '邮箱',
|
||||
align: 'center',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
key: 'mobile',
|
||||
title: '手机号',
|
||||
align: 'center',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
key: 'operate',
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
width: 230,
|
||||
render: row => (
|
||||
<div class="flex-center justify-end gap-8px">
|
||||
<NButton type="primary" ghost size="small" onClick={() => handleEdit(row)}>
|
||||
编辑
|
||||
</NButton>
|
||||
<NPopconfirm onPositiveClick={() => handleDelete(row.id)}>
|
||||
{{
|
||||
default: () => '确定删除吗?',
|
||||
trigger: () => (
|
||||
<NButton type="error" ghost size="small">
|
||||
删除
|
||||
</NButton>
|
||||
)
|
||||
}}
|
||||
</NPopconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
|
||||
|
||||
const operateType = ref('add');
|
||||
|
||||
function handleAdd() {
|
||||
operateType.value = 'add';
|
||||
title.value = '新增管理员';
|
||||
// 清空model
|
||||
model.value = {
|
||||
username: '',
|
||||
nickname: '',
|
||||
password: '',
|
||||
group: null,
|
||||
email: '',
|
||||
mobile: '',
|
||||
id: 0,
|
||||
};
|
||||
openModal();
|
||||
}
|
||||
|
||||
async function handleDelete(id: number) {
|
||||
// request
|
||||
const { response } = await deleteAdmin(id);
|
||||
if (response?.data?.code === 1) {
|
||||
window.$message?.success('删除成功!');
|
||||
getData();
|
||||
} else {
|
||||
window.$message?.error(response?.data?.msg || '删除失败');
|
||||
}
|
||||
}
|
||||
|
||||
function handleEdit(item: any) {
|
||||
console.log(item);
|
||||
//item.
|
||||
operateType.value = 'edit';
|
||||
title.value = '编辑管理员';
|
||||
model.value = { ...item };
|
||||
openModal();
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
let res;
|
||||
if (operateType.value === 'add') {
|
||||
res = await addAdmin(model.value,'post');
|
||||
} else {
|
||||
res = await editAdmin(model.value);
|
||||
}
|
||||
if (res.response?.data?.code === 1) {
|
||||
window.$message?.success(res.response.data.msg);
|
||||
visible.value = false;
|
||||
getData();
|
||||
} else {
|
||||
window.$message?.error(res.response?.data?.msg || '操作失败');
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user