/** 商家老板:角色与权限管理 */ import request from '../../utils/request.js'; import { STAFF_API, isStaffMode, isMerchantOwnerOnly } from '../../utils/staff-api.js'; /** 与后端 constants.PERMISSION_DEFINITIONS 一致,接口为空时前端兜底 */ const FALLBACK_PERMISSIONS = [ { perm_code: 'staff_manage', perm_name: '子客服管理' }, { perm_code: 'role_manage', perm_name: '角色管理' }, { perm_code: 'wallet_allocate', perm_name: '划额度' }, { perm_code: 'wallet_revoke', perm_name: '收回额度' }, { perm_code: 'wallet_view', perm_name: '查看额度' }, { perm_code: 'finance_view', perm_name: '查看商家余额' }, { perm_code: 'order_dispatch', perm_name: '派单发单' }, { perm_code: 'order_view_all', perm_name: '查看全部订单' }, { perm_code: 'order_view_self', perm_name: '只看自己派的单' }, { perm_code: 'order_detail', perm_name: '订单详情' }, { perm_code: 'order_settle', perm_name: '结单' }, { perm_code: 'order_refund_apply', perm_name: '申请退款' }, { perm_code: 'order_cancel', perm_name: '撤销订单' }, { perm_code: 'order_change_player', perm_name: '换打手' }, { perm_code: 'penalty_apply', perm_name: '申请罚单' }, { perm_code: 'penalty_manage', perm_name: '改撤罚单' }, { perm_code: 'penalty_view', perm_name: '查看罚单' }, { perm_code: 'staff_disable', perm_name: '封禁解封客服' }, { perm_code: 'template_manage', perm_name: '派单模板' }, { perm_code: 'audit_view', perm_name: '操作日志' }, { perm_code: 'rank_view', perm_name: '客服排行榜' }, { perm_code: 'im_chat', perm_name: '订单IM' }, { perm_code: 'stats_view', perm_name: '统计数据' }, ]; Page({ data: { statusBar: 20, permScrollHeight: 360, loading: false, roles: [], rawPermissions: [], permissionOptions: [], selectedPerms: [], showEditPanel: false, showCreatePanel: false, editingRoleId: null, editingRoleName: '', newRoleName: '', }, onLoad() { const sys = wx.getSystemInfoSync(); const h = sys.windowHeight || 667; this.setData({ statusBar: sys.statusBarHeight || 20, permScrollHeight: Math.floor(h * 0.45), }); if (!this.ensureOwnerAccess()) return; this.loadRoles(); }, onShow() { if (!isMerchantOwnerOnly()) return; if (!this.data.showEditPanel && !this.data.showCreatePanel) { this.loadRoles(); } }, ensureOwnerAccess() { if (isStaffMode() || Number(wx.getStorageSync('shangjiastatus')) !== 1) { wx.showToast({ title: '仅商家老板可管理角色权限', icon: 'none' }); setTimeout(() => wx.navigateBack(), 1200); return false; } return true; }, /** allPerms: [{perm_code, perm_name}] selectedCodes: ['order_dispatch', ...] */ buildPermOptions(allPerms, selectedCodes) { const list = (allPerms && allPerms.length) ? allPerms : FALLBACK_PERMISSIONS; const set = new Set(selectedCodes || []); return list.map((p) => { const code = p.perm_code || p; const name = p.perm_name || code; return { perm_code: code, perm_name: name, checked: set.has(code), }; }); }, normalizeRoles(list) { return (list || []).map((r) => ({ ...r, permCount: (r.permissions && r.permissions.length) || 0, })); }, resolveAllPermissions(apiList) { if (apiList && apiList.length) return apiList; return FALLBACK_PERMISSIONS; }, async loadRoles() { this.setData({ loading: true }); try { const res = await request({ url: STAFF_API.roleList, method: 'POST' }); if (res.data && res.data.code === 0) { const d = res.data.data || {}; const rawPermissions = this.resolveAllPermissions(d.all_permissions); this.setData({ roles: this.normalizeRoles(d.roles), rawPermissions, }); return rawPermissions; } wx.showToast({ title: (res.data && res.data.msg) || '加载失败', icon: 'none' }); } catch (e) { wx.showToast({ title: '加载失败', icon: 'none' }); } finally { this.setData({ loading: false }); } const fallback = FALLBACK_PERMISSIONS; this.setData({ rawPermissions: fallback }); return fallback; }, goBack() { wx.navigateBack(); }, openCreate() { const raw = this.data.rawPermissions.length ? this.data.rawPermissions : FALLBACK_PERMISSIONS; this.setData({ showCreatePanel: true, showEditPanel: false, newRoleName: '', selectedPerms: [], permissionOptions: this.buildPermOptions(raw, []), }); }, closeCreate() { this.setData({ showCreatePanel: false, permissionOptions: [], selectedPerms: [] }); }, onNameInput(e) { this.setData({ newRoleName: e.detail.value }); }, togglePermItem(e) { const code = e.currentTarget.dataset.code; if (!code) return; const opts = (this.data.permissionOptions || []).map((p) => ( p.perm_code === code ? { ...p, checked: !p.checked } : p )); this.setData({ permissionOptions: opts, selectedPerms: opts.filter((x) => x.checked).map((x) => x.perm_code), }); }, async editRole(e) { const id = e.currentTarget.dataset.id; let role = this.data.roles.find((r) => String(r.id) === String(id)); if (!role) return; let rawPermissions = this.data.rawPermissions; if (!rawPermissions.length) { rawPermissions = await this.loadRoles(); role = this.data.roles.find((r) => String(r.id) === String(id)); if (!role) return; } const perms = role.permissions || []; this.setData({ showEditPanel: true, showCreatePanel: false, editingRoleId: role.id, editingRoleName: role.role_name || '', selectedPerms: [...perms], permissionOptions: this.buildPermOptions(rawPermissions, perms), }); }, closeEdit() { this.setData({ showEditPanel: false, editingRoleId: null, editingRoleName: '', selectedPerms: [], permissionOptions: [], }); }, async saveRolePerms() { const { editingRoleId, selectedPerms } = this.data; if (!editingRoleId) return; wx.showLoading({ title: '保存中' }); try { const res = await request({ url: STAFF_API.roleSetPerms, method: 'POST', data: { role_id: editingRoleId, permissions: selectedPerms }, }); wx.showToast({ title: (res.data && res.data.msg) || '已保存', icon: 'none' }); if (res.data && res.data.code === 0) { this.closeEdit(); this.loadRoles(); } } finally { wx.hideLoading(); } }, async createRole() { const name = (this.data.newRoleName || '').trim(); if (!name) { wx.showToast({ title: '请输入角色名', icon: 'none' }); return; } wx.showLoading({ title: '创建中' }); try { const res = await request({ url: STAFF_API.roleCreate, method: 'POST', data: { role_name: name, permissions: this.data.selectedPerms }, }); wx.showToast({ title: (res.data && res.data.msg) || '完成', icon: 'none' }); if (res.data && res.data.code === 0) { this.closeCreate(); this.loadRoles(); } } finally { wx.hideLoading(); } }, });