From 833dd3451aa6580a415471344a32c5e7dec41af6 Mon Sep 17 00:00:00 2001 From: Toyas Date: Fri, 24 Apr 2026 17:34:41 +0800 Subject: [PATCH] refactor(admin): Rework permission routes and operations dashboard --- .../video-frontend-admin/src/api/admin.ts | 20 +- frontend/video-frontend-admin/src/api/auth.ts | 9 +- .../video-frontend-admin/src/api/comment.ts | 25 +- frontend/video-frontend-admin/src/api/role.ts | 79 ++++ .../src/api/statistics.ts | 24 +- .../video-frontend-admin/src/components.d.ts | 1 + .../src/components/TagsView.vue | 52 +-- .../video-frontend-admin/src/router/index.ts | 88 ++++- .../video-frontend-admin/src/stores/user.ts | 28 +- .../src/styles/index.scss | 85 +++++ .../video-frontend-admin/src/types/index.ts | 24 ++ .../src/views/content/category.vue | 6 + .../src/views/content/comment.vue | 198 +++++----- .../src/views/content/tag.vue | 5 + .../src/views/dashboard/index.vue | 120 +++--- .../src/views/layout/index.vue | 268 ++++++++++--- .../src/views/login/index.vue | 70 ---- .../src/views/system/admin.vue | 74 +++- .../src/views/system/role.vue | 351 ++++++++++++++++++ .../src/views/user/list.vue | 184 +++++---- .../src/views/video/list.vue | 86 ++++- .../src/views/video/review.vue | 194 +++++----- 22 files changed, 1423 insertions(+), 568 deletions(-) create mode 100644 frontend/video-frontend-admin/src/api/role.ts create mode 100644 frontend/video-frontend-admin/src/views/system/role.vue diff --git a/frontend/video-frontend-admin/src/api/admin.ts b/frontend/video-frontend-admin/src/api/admin.ts index 23de437..3cb6b9f 100644 --- a/frontend/video-frontend-admin/src/api/admin.ts +++ b/frontend/video-frontend-admin/src/api/admin.ts @@ -13,8 +13,14 @@ function normalizeAdmin(raw: any): AdminUser { avatar: raw?.avatar || '', email: raw?.email || '', phone: raw?.phone || '', - role: firstRole?.code === 'ADMIN_SUPER' ? 'admin' : 'manager', + role: firstRole?.code || '', roleName: firstRole?.name || '', + roles: Array.isArray(raw?.roles) ? raw.roles.map((item: any) => item.code || item.name || '') : [], + roleNames: Array.isArray(raw?.roles) ? raw.roles.map((item: any) => item.name || item.code || '') : [], + roleIds: Array.isArray(raw?.roleIds) + ? raw.roleIds.map((item: any) => Number(item)) + : (Array.isArray(raw?.roles) ? raw.roles.map((item: any) => Number(item.id || 0)).filter((item: number) => item > 0) : []), + permissions: [], status: Number(raw?.status ?? 0), lastLoginTime: raw?.lastLoginTime || '', lastLoginIp: raw?.lastLoginIp || '', @@ -70,15 +76,15 @@ export const adminApi = { nickname: string email?: string phone?: string - role?: string + roleIds: number[] }): Promise { return request.post('/user', { username: data.username, password: data.password, realName: data.nickname, - email: data.email, - phone: data.phone, - roleIds: [data.role === 'admin' ? 1 : 2] + ...(data.email ? { email: data.email } : {}), + ...(data.phone ? { phone: data.phone } : {}), + roleIds: data.roleIds }) }, @@ -91,13 +97,13 @@ export const adminApi = { nickname?: string email?: string phone?: string - role?: string + roleIds: number[] }): Promise { const payload: Record = { id: data.id, username: data.username, realName: data.nickname, - roleIds: [data.role === 'admin' ? 1 : 2] + roleIds: data.roleIds } if (data.email) payload.email = data.email diff --git a/frontend/video-frontend-admin/src/api/auth.ts b/frontend/video-frontend-admin/src/api/auth.ts index c3c6cd2..519b545 100644 --- a/frontend/video-frontend-admin/src/api/auth.ts +++ b/frontend/video-frontend-admin/src/api/auth.ts @@ -10,6 +10,7 @@ export type { LoginParams, LoginResult, CaptchaResult, AdminUser } function normalizeAdminInfo(raw: any): AdminUser { const roles = Array.isArray(raw?.roles) ? raw.roles : [] + const permissions = Array.isArray(raw?.permissions) ? raw.permissions : [] const roleCode = roles[0] || '' return { @@ -21,6 +22,10 @@ function normalizeAdminInfo(raw: any): AdminUser { phone: '', role: roleCode === 'ADMIN_SUPER' ? 'super-admin' : roleCode || 'admin', roleName: roleCode === 'ADMIN_SUPER' ? '超级管理员' : roleCode || '管理员', + roles, + roleNames: roles, + permissions, + roleIds: Array.isArray(raw?.roleIds) ? raw.roleIds.map((item: any) => Number(item)) : [], status: 1, lastLoginTime: '', lastLoginIp: '', @@ -50,7 +55,9 @@ export const authApi = { tokenType: result.tokenType || 'Bearer', expiresIn: result.expiresIn || 0, adminId: result.adminId || result.id || 0, - username: result.username || '' + username: result.username || '', + roles: Array.isArray(result.roles) ? result.roles : [], + permissions: Array.isArray(result.permissions) ? result.permissions : [] } }, diff --git a/frontend/video-frontend-admin/src/api/comment.ts b/frontend/video-frontend-admin/src/api/comment.ts index d7989a2..b703ee4 100644 --- a/frontend/video-frontend-admin/src/api/comment.ts +++ b/frontend/video-frontend-admin/src/api/comment.ts @@ -1,8 +1,27 @@ import request from '@/utils/request.ts' import type { PageResult, PlatformComment, CommentQueryParams } from '@/types' +function normalizeComment(raw: any): PlatformComment { + return { + id: Number(raw?.id || 0), + videoId: Number(raw?.videoId || 0), + videoTitle: raw?.videoTitle || '', + userId: Number(raw?.userId || 0), + userNickname: raw?.userNickname || '', + userAvatar: raw?.userAvatar || '', + parentId: Number(raw?.parentId || 0), + rootId: Number(raw?.rootId || 0), + content: raw?.content || '', + likeCount: Number(raw?.likeCount || 0), + replyCount: Number(raw?.replyCount || 0), + isTop: Number(raw?.isTop ?? raw?.topStatus ?? 0), + status: Number(raw?.status ?? 1), + createTime: raw?.createTime || '' + } +} + function normalizeCommentPage(raw: any, page: number, size: number): PageResult { - const records = Array.isArray(raw?.records) ? raw.records : [] + const records = Array.isArray(raw?.records) ? raw.records.map(normalizeComment) : [] const total = Number(raw?.total || records.length || 0) const shouldPaginateLocally = (!raw?.total || raw.total === 0) && records.length > size @@ -43,6 +62,10 @@ export const commentApi = { return request.delete(`/platform/comment/${commentId}`) }, + restore(commentId: number): Promise { + return request.put(`/platform/comment/${commentId}/restore`) + }, + /** * 获取评论统计数据 */ diff --git a/frontend/video-frontend-admin/src/api/role.ts b/frontend/video-frontend-admin/src/api/role.ts new file mode 100644 index 0000000..4332d9f --- /dev/null +++ b/frontend/video-frontend-admin/src/api/role.ts @@ -0,0 +1,79 @@ +import request from '@/utils/request.ts' +import type { AdminPermission, AdminRole, PageResult, PageParams } from '@/types' + +function normalizePermission(raw: any): AdminPermission { + return { + id: Number(raw?.id || 0), + name: raw?.name || '', + code: raw?.code || '', + description: raw?.description || '', + createTime: raw?.createTime || '' + } +} + +function normalizeRole(raw: any): AdminRole { + const permissions = Array.isArray(raw?.permissions) ? raw.permissions.map(normalizePermission) : [] + return { + id: Number(raw?.id || 0), + name: raw?.name || '', + code: raw?.code || '', + description: raw?.description || '', + permissionIds: Array.isArray(raw?.permissionIds) + ? raw.permissionIds.map((item: any) => Number(item)) + : permissions.map((item: AdminPermission) => item.id), + permissions, + createTime: raw?.createTime || '' + } +} + +function normalizeRolePage(raw: any, page: number, size: number): PageResult { + const records = Array.isArray(raw?.records) ? raw.records.map(normalizeRole) : [] + const total = Number(raw?.total || records.length || 0) + return { + records, + total, + size: Number(raw?.size || size), + current: Number(raw?.current || page), + pages: Number(raw?.pages || Math.ceil(total / size) || 1) + } +} + +export const roleApi = { + async getList(params: PageParams & { keyword?: string }): Promise> { + const page = params.page || 1 + const size = params.size || 10 + const result = await request.get('/role/list', params) + return normalizeRolePage(result, page, size) + }, + + async getAll(): Promise { + const result = await request.get('/role/all') + return Array.isArray(result) ? result.map(normalizeRole) : [] + }, + + async getDetail(id: number): Promise { + const result = await request.get(`/role/${id}`) + return normalizeRole(result) + }, + + create(data: { name: string; code: string; description?: string; permissionIds: number[] }): Promise { + return request.post('/role', data) + }, + + update(data: { id: number; name: string; code: string; description?: string; permissionIds?: number[] }): Promise { + return request.put('/role', data) + }, + + updatePermissions(id: number, permissionIds: number[]): Promise { + return request.put(`/role/${id}/permissions`, permissionIds) + }, + + delete(id: number): Promise { + return request.delete(`/role/${id}`) + }, + + async getPermissions(): Promise { + const result = await request.get('/role/permissions/list') + return Array.isArray(result) ? result.map(normalizePermission) : [] + } +} diff --git a/frontend/video-frontend-admin/src/api/statistics.ts b/frontend/video-frontend-admin/src/api/statistics.ts index 5180667..a116d5a 100644 --- a/frontend/video-frontend-admin/src/api/statistics.ts +++ b/frontend/video-frontend-admin/src/api/statistics.ts @@ -1,6 +1,14 @@ import request from '@/utils/request.ts' +import { useUserStore } from '@/stores' import type { DashboardData, StatisticsData, TrendData } from '@/types' +function formatLocalDate(date: Date) { + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + return `${year}-${month}-${day}` +} + function getDateKey(input?: string) { if (!input) return '' return String(input).slice(0, 10) @@ -12,7 +20,7 @@ function buildDailySeries(items: T[], getDate: (item: T) => string, getValue: for (let i = 6; i >= 0; i--) { const d = new Date(today) d.setDate(today.getDate() - i) - days.push(d.toISOString().slice(0, 10)) + days.push(formatLocalDate(d)) } const map = new Map(days.map((day) => [day, 0])) @@ -91,11 +99,19 @@ export const statisticsApi = { * 获取仪表盘数据 */ async getDashboard(): Promise { + const userStore = useUserStore() + const [dashboard, users, videos, comments] = await Promise.all([ request.get('/dashboard/stats'), - request.get('/platform/user/list', { page: 1, size: 200 }), - request.get('/platform/content/video/list', { page: 1, size: 200 }), - request.get('/platform/comment/list', { page: 1, size: 200 }) + userStore.hasPermission('user:manage') + ? request.get('/platform/user/list', { page: 1, size: 200 }) + : Promise.resolve({ records: [] }), + userStore.hasPermission('video:manage') + ? request.get('/platform/content/video/list', { page: 1, size: 200 }) + : Promise.resolve({ records: [] }), + userStore.hasPermission('comment:manage') + ? request.get('/platform/comment/list', { page: 1, size: 200 }) + : Promise.resolve({ records: [] }) ]) return normalizeDashboard( diff --git a/frontend/video-frontend-admin/src/components.d.ts b/frontend/video-frontend-admin/src/components.d.ts index 8789539..1ff4a10 100644 --- a/frontend/video-frontend-admin/src/components.d.ts +++ b/frontend/video-frontend-admin/src/components.d.ts @@ -39,6 +39,7 @@ declare module 'vue' { ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElSkeleton: typeof import('element-plus/es')['ElSkeleton'] + ElSpace: typeof import('element-plus/es')['ElSpace'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] diff --git a/frontend/video-frontend-admin/src/components/TagsView.vue b/frontend/video-frontend-admin/src/components/TagsView.vue index 67908fd..7560b2f 100644 --- a/frontend/video-frontend-admin/src/components/TagsView.vue +++ b/frontend/video-frontend-admin/src/components/TagsView.vue @@ -159,62 +159,67 @@ onMounted(() => { diff --git a/frontend/video-frontend-admin/src/views/layout/index.vue b/frontend/video-frontend-admin/src/views/layout/index.vue index 4ad6486..767c465 100644 --- a/frontend/video-frontend-admin/src/views/layout/index.vue +++ b/frontend/video-frontend-admin/src/views/layout/index.vue @@ -1,12 +1,18 @@