diff --git a/backend/internal/modules/adminauth/repository.go b/backend/internal/modules/adminauth/repository.go index a50fa3b..4526daa 100644 --- a/backend/internal/modules/adminauth/repository.go +++ b/backend/internal/modules/adminauth/repository.go @@ -144,7 +144,20 @@ func (r *Repository) ensureDefaultAdmin() error { Nickname: "超级管理员", Status: "active", } - return r.db.Create(&admin).Error + if err := r.db.Create(&admin).Error; err != nil { + return err + } + + // 自动关联 super_admin 角色 + var superAdminRole model.Role + if err := r.db.Where("code = ?", "super_admin").First(&superAdminRole).Error; err == nil { + r.db.Create(&model.AdminUserRole{ + AdminID: admin.ID, + RoleID: superAdminRole.ID, + }) + } + + return nil } func toDTO(admin model.AdminUser) AdminDTO { diff --git a/backend/internal/modules/chat/repository.go b/backend/internal/modules/chat/repository.go index 1c266b9..8d7bba0 100644 --- a/backend/internal/modules/chat/repository.go +++ b/backend/internal/modules/chat/repository.go @@ -686,12 +686,11 @@ func (r *Repository) GetAvailableSupportAdmins() ([]SupportAdminDTO, error) { } var admins []adminRow err := r.db.Table("admin_users AS au"). - Select("au.id, au.nickname"). + Select("DISTINCT au.id, COALESCE(NULLIF(au.nickname, ''), au.username) AS nickname"). Joins("JOIN admin_user_roles AS aur ON aur.admin_user_id = au.id"). Joins("JOIN role_permissions AS rp ON rp.role_id = aur.role_id"). Joins("JOIN permissions AS p ON p.id = rp.permission_id"). Where("au.status = ? AND p.code = ?", "active", "chat:view"). - Distinct("au.id"). Scan(&admins).Error if err != nil { return nil, err @@ -722,9 +721,9 @@ func (r *Repository) GetAvailableSupportAdmins() ([]SupportAdminDTO, error) { result := make([]SupportAdminDTO, len(admins)) for i, a := range admins { result[i] = SupportAdminDTO{ - ID: a.ID, - Nickname: a.Nickname, - ChatCount: loadMap[a.ID], + ID: a.ID, + Nickname: a.Nickname, + ChatCount: loadMap[a.ID], } } return result, nil diff --git a/backend/internal/modules/systemconfig/repository.go b/backend/internal/modules/systemconfig/repository.go index b239661..22d8444 100644 --- a/backend/internal/modules/systemconfig/repository.go +++ b/backend/internal/modules/systemconfig/repository.go @@ -41,7 +41,7 @@ var defaultConfigs = []defaultConfig{ {Key: "settlement.platform_fee_rate", Value: "0.00", Description: "平台抽成比例"}, {Key: "settlement.owner_cycle_days", Value: "0", Description: "号主结算周期天数"}, {Key: "withdraw.min_amount", Value: "100", Description: "提现最低金额预留"}, - {Key: "chat.default_support_admin_id", Value: "1", Description: "订单群聊默认接入的客服管理员 ID"}, + {Key: "chat.default_support_admin_id", Value: "1", Description: "订单群聊回退客服 ID(仅当无可用客服时使用)"}, {Key: homeAnnouncementsConfigKey, Value: defaultHomeAnnouncementsConfigValue(), Description: "移动端首页公告 JSON 数组"}, {Key: homeBannersConfigKey, Value: defaultHomeBannersConfigValue(), Description: "移动端首页轮播图 JSON 数组"}, {Key: publishOptionsConfigKey, Value: defaultPublishOptionsConfigValue(), Description: "发布页选项配置 JSON"}, diff --git a/backend/migrations/000002_seed.sql b/backend/migrations/000002_seed.sql index ecc9d0a..e133a5c 100644 --- a/backend/migrations/000002_seed.sql +++ b/backend/migrations/000002_seed.sql @@ -67,6 +67,27 @@ INSERT IGNORE INTO role_permissions (role_id, permission_id) SELECT r.id, p.id FROM roles r, permissions p WHERE r.code = 'finance' AND p.code IN ('dashboard:view', 'wallet:view', 'order:view'); +-- ------------------------------------------- +-- 管理员账号 +-- ------------------------------------------- + +-- 生成 admin 密码 hash: admin123456 +INSERT INTO admin_users (username, password_hash, nickname, status) VALUES +('admin', '$2a$10$vvDd.cYJCOBl9kr5jdRYXu9C/7GXcHmXsG17zJPHzPOZ0XGbqcWNS', '超级管理员', 'active'), +('kf1', '$2a$10$7cx3B4IWunLZO24o11YVGu4qY1J1naDdsTyvoCpcnOO.GV15qaf3C', '客服1', 'active'), +('kf2', '$2a$10$m6kLCXciFygpqIGUZ9LQtuEFAl40hb.S7zJmMiuC83WrU7OQM3TPC', '客服2', 'active') +ON DUPLICATE KEY UPDATE nickname = VALUES(nickname); + +-- admin 关联 super_admin 角色 +INSERT IGNORE INTO admin_user_roles (admin_user_id, role_id) +SELECT au.id, r.id FROM admin_users au, roles r +WHERE au.username = 'admin' AND r.code = 'super_admin'; + +-- 客服关联 cs 角色 +INSERT IGNORE INTO admin_user_roles (admin_user_id, role_id) +SELECT au.id, r.id FROM admin_users au, roles r +WHERE au.username IN ('kf1', 'kf2') AND r.code = 'cs'; + -- ------------------------------------------- -- 系统配置 -- ------------------------------------------- @@ -80,6 +101,6 @@ INSERT INTO system_configs (`key`, `value`, description) VALUES ('platform.fee_ratio', '0.1', '平台抽成比例'), ('listing.review_required', 'true', '商品是否需要审核'), ('order.pending_payment_timeout_minutes', '15', '待支付超时时间(分钟)'), -('chat.default_support_admin_id', '1', '订单群聊默认接入的客服管理员 ID'), +('chat.default_support_admin_id', '1', '订单群聊回退客服 ID(仅当无可用客服时使用)'), ('chat.auto_welcome_message', '欢迎加入订单群聊!如有任何问题,请随时沟通。', '建群后自动发送的欢迎话术') ON DUPLICATE KEY UPDATE description = VALUES(description); diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 5a149eb..a6caca0 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -12,6 +12,9 @@ export {} declare module 'vue' { export interface GlobalComponents { ElAlert: typeof import('element-plus/es')['ElAlert'] + ElAvatar: typeof import('element-plus/es')['ElAvatar'] + ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] + ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElButton: typeof import('element-plus/es')['ElButton'] ElCarousel: typeof import('element-plus/es')['ElCarousel'] ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem'] @@ -27,6 +30,8 @@ declare module 'vue' { ElIcon: typeof import('element-plus/es')['ElIcon'] ElInput: typeof import('element-plus/es')['ElInput'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] + ElMenu: typeof import('element-plus/es')['ElMenu'] + ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElOption: typeof import('element-plus/es')['ElOption'] ElPagination: typeof import('element-plus/es')['ElPagination'] ElRadio: typeof import('element-plus/es')['ElRadio'] diff --git a/frontend/src/layouts/AdminLayout.vue b/frontend/src/layouts/AdminLayout.vue index b064c9c..bfeb21d 100644 --- a/frontend/src/layouts/AdminLayout.vue +++ b/frontend/src/layouts/AdminLayout.vue @@ -18,12 +18,13 @@ import { } from '@element-plus/icons-vue' import { ElMessage } from 'element-plus' import { computed, ref } from 'vue' -import { useRouter } from 'vue-router' +import { useRoute, useRouter } from 'vue-router' import { logoutAdmin } from '@/api/adminAuth' import { useAdminSessionStore } from '@/stores/adminSession' const router = useRouter() +const route = useRoute() const adminSession = useAdminSessionStore() const isCollapsed = ref(false) @@ -57,6 +58,7 @@ const navItems = computed(() => { }) }) +const activeMenu = computed(() => route.path) const adminName = computed(() => adminSession.nickname || adminSession.username || '管理员') async function handleLogout() { @@ -77,7 +79,7 @@ async function handleLogout() {
H - 哈夫币后台 + 哈夫币后台 @@ -85,21 +87,41 @@ async function handleLogout() {
- + + +
-
- 管理系统 - {{ adminName }} +
+ + 首页 + {{ route.meta.title }} + +
+
+ + + +
- 退出
@@ -107,3 +129,139 @@ async function handleLogout() {
+ + diff --git a/frontend/src/views/admin/components/TransferDialog.vue b/frontend/src/views/admin/components/TransferDialog.vue index 5ae93d4..5afd4ea 100644 --- a/frontend/src/views/admin/components/TransferDialog.vue +++ b/frontend/src/views/admin/components/TransferDialog.vue @@ -1,7 +1,8 @@