From be2323074b33c4100e9f7fe08067570e72763fbb Mon Sep 17 00:00:00 2001 From: Doubleyin <953994191@qq.com> Date: Tue, 21 Oct 2025 21:51:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E4=BF=AE=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/pages/apply/apply.json | 2 +- miniprogram/pages/apply/apply.ts | 32 ++++--- miniprogram/pages/apply/apply.wxml | 24 +++-- miniprogram/pages/apply/apply.wxss | 23 +++++ miniprogram/pages/employee/employee.ts | 8 +- miniprogram/pages/employee/employee.wxml | 26 +++--- miniprogram/pages/index/index.ts | 11 ++- miniprogram/pages/index/index.wxml | 18 +++- .../pages/index/modules/adminModule.ts | 72 +++++++++++++++ miniprogram/pages/index/modules/dataModule.ts | 48 ---------- .../index/modules/deliveryPersonModule.ts | 56 +++++------ .../pages/index/modules/employeeModule.ts | 92 +++++++++++++++++++ .../pages/index/modules/locationModule.ts | 2 +- .../pages/index/modules/loginModule.ts | 34 ++++++- .../pages/index/modules/mainPageModule.ts | 83 ++++++++++++----- miniprogram/pages/staff/admin-dashboard.ts | 66 +++++++++++++ miniprogram/pages/staff/admin-dashboard.wxml | 1 + miniprogram/pages/staff/admin-dashboard.wxss | 24 ++++- miniprogram/pages/staff/employee-dashboard.ts | 66 +++++++++++++ .../pages/staff/employee-dashboard.wxml | 1 + .../pages/staff/employee-dashboard.wxss | 24 ++++- .../pages/staff/employee-management.ts | 8 +- .../pages/staff/employee-management.wxml | 10 +- miniprogram/services/apiService.ts | 82 +++++++++++++---- miniprogram/services/employeeService.ts | 10 +- .../services/locationTrackingService.ts | 38 ++++++-- miniprogram/services/mapService.ts | 26 ++---- miniprogram/services/userService.ts | 53 ++++++++++- 28 files changed, 729 insertions(+), 211 deletions(-) create mode 100644 miniprogram/pages/index/modules/adminModule.ts create mode 100644 miniprogram/pages/index/modules/employeeModule.ts diff --git a/miniprogram/pages/apply/apply.json b/miniprogram/pages/apply/apply.json index c7e3c26..a8b1be3 100644 --- a/miniprogram/pages/apply/apply.json +++ b/miniprogram/pages/apply/apply.json @@ -1,5 +1,5 @@ { - "navigationBarTitleText": "申请加入货运团队", + "navigationBarTitleText": "员工账号绑定", "navigationBarBackgroundColor": "#1aad19", "navigationBarTextStyle": "white", "usingComponents": {} diff --git a/miniprogram/pages/apply/apply.ts b/miniprogram/pages/apply/apply.ts index 1befc89..9059485 100644 --- a/miniprogram/pages/apply/apply.ts +++ b/miniprogram/pages/apply/apply.ts @@ -61,7 +61,7 @@ Page({ if (result.success) { wx.showToast({ - title: '申请提交成功', + title: '绑定成功', icon: 'success', duration: 2000 }); @@ -79,13 +79,27 @@ Page({ } // 延迟返回并刷新首页 - setTimeout(() => { + setTimeout(async () => { // 获取当前页面栈 const pages = getCurrentPages(); if (pages.length >= 2) { // 获取首页实例并调用刷新方法 const indexPage = pages[pages.length - 2]; if (indexPage && indexPage.refreshPageAfterLogin) { + // 重新获取用户状态,确保绑定成功后状态正确更新 + if (indexPage.data.mainPageModule) { + const loginModule = indexPage.data.mainPageModule.getLoginModule(); + const app = getApp(); + const userStatus = await loginModule.determineUserStatus(app.globalData.userInfo); + + // 更新页面状态 + indexPage.setData({ + 'authStatus.userStatus': userStatus + }); + + console.log('✅ 绑定成功后重新获取用户状态:', userStatus); + } + indexPage.refreshPageAfterLogin(); } } @@ -125,16 +139,6 @@ Page({ return false; } - // 手机号验证 - if (!/^1[3-9]\d{9}$/.test(phone)) { - wx.showToast({ - title: '请输入正确的手机号', - icon: 'none', - duration: 2000 - }); - return false; - } - return true; }, @@ -150,13 +154,13 @@ Page({ throw new Error('微信登录失败,请重试'); } - // 调用实际的注册接口 + // 调用实际的绑定接口 return await userService.register({ name: data.name, phone: data.phone }); } catch (error) { - console.error('注册流程失败:', error); + console.error('绑定流程失败:', error); throw error; } }, diff --git a/miniprogram/pages/apply/apply.wxml b/miniprogram/pages/apply/apply.wxml index 4674231..575c901 100644 --- a/miniprogram/pages/apply/apply.wxml +++ b/miniprogram/pages/apply/apply.wxml @@ -2,16 +2,16 @@ - 加入货运团队 - 请填写您的个人信息 + 员工账号绑定 + 请填写您的员工信息 - + - 姓名 + 员工姓名 + - 手机号 + 员工工号 + + + 请正确输入自己的姓名和工号,忘记请联系管理员 + 未分属于本公司用户请勿绑定(绑定不会保留个人信息) + + - + \ No newline at end of file diff --git a/miniprogram/pages/apply/apply.wxss b/miniprogram/pages/apply/apply.wxss index 27055fb..16af0e4 100644 --- a/miniprogram/pages/apply/apply.wxss +++ b/miniprogram/pages/apply/apply.wxss @@ -84,6 +84,29 @@ opacity: 0.5; } +/* 提示信息 */ +.apply-tips { + padding: 30rpx; + background-color: #f8f9fa; + border-top: 1rpx solid #eee; + border-bottom: 1rpx solid #eee; +} + +.tips-text { + display: block; + font-size: 26rpx; + color: #666; + line-height: 1.6; + margin-bottom: 10rpx; +} + +.tips-warning { + display: block; + font-size: 24rpx; + color: #ff6b35; + line-height: 1.6; +} + /* 底部操作按钮 */ .apply-footer { padding: 30rpx; diff --git a/miniprogram/pages/employee/employee.ts b/miniprogram/pages/employee/employee.ts index 1449311..9ffcf26 100644 --- a/miniprogram/pages/employee/employee.ts +++ b/miniprogram/pages/employee/employee.ts @@ -126,16 +126,16 @@ Page({ if (!phone.trim()) { this.setData({ - errorMessage: '请输入手机号' + errorMessage: '请输入员工工号' }); return false; } - // 简单的手机号格式验证 - const phoneRegex = /^1[3-9]\d{9}$/; + // 简单的工号格式验证 + const phoneRegex = /^\d+$/; if (!phoneRegex.test(phone)) { this.setData({ - errorMessage: '请输入正确的手机号格式' + errorMessage: '工号只能包含数字' }); return false; } diff --git a/miniprogram/pages/employee/employee.wxml b/miniprogram/pages/employee/employee.wxml index 192c928..a3fbd6e 100644 --- a/miniprogram/pages/employee/employee.wxml +++ b/miniprogram/pages/employee/employee.wxml @@ -54,7 +54,7 @@ @@ -70,16 +70,16 @@ {{item.name.charAt(0)}} - - {{item.name}} - - {{item.role === 'ADMIN' ? '👑' : '🚚'}} - {{getRoleText(item.role)}} - + + {{item.name}} + + {{item.role === 'ADMIN' ? '👑' : '🚚'}} + {{getRoleText(item.role)}} + + + 工号: {{item.phone}} + ID: {{item.id}} - {{item.phone}} - ID: {{item.id}} - + \ No newline at end of file diff --git a/miniprogram/pages/staff/admin-dashboard.wxss b/miniprogram/pages/staff/admin-dashboard.wxss index 75824a6..a024752 100644 --- a/miniprogram/pages/staff/admin-dashboard.wxss +++ b/miniprogram/pages/staff/admin-dashboard.wxss @@ -5,16 +5,21 @@ display: flex; flex-direction: column; padding: 0; + /* 安全区域适配 - 为整个容器添加顶部安全区域 */ + padding-top: env(safe-area-inset-top); + box-sizing: border-box; } /* 顶部导航栏样式 */ .admin-header { background: rgba(255, 255, 255, 0.95); - padding: 30rpx 40rpx; + padding: 40rpx 40rpx 30rpx 40rpx; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); + /* 移除margin-top,使用容器的padding-top来处理安全区域 */ + min-height: 140rpx; } .header-left { @@ -259,4 +264,21 @@ .footer-time { font-size: 22rpx; color: #999; +} + +/* 解绑微信按钮样式 */ +.unbind-btn { + background: #e74c3c; + color: white; + border: none; + border-radius: 8rpx; + padding: 12rpx 20rpx; + font-size: 24rpx; + cursor: pointer; + transition: all 0.3s ease; +} + +.unbind-btn:active { + background: #c0392b; + transform: translateY(1rpx); } \ No newline at end of file diff --git a/miniprogram/pages/staff/employee-dashboard.ts b/miniprogram/pages/staff/employee-dashboard.ts index 155d3ff..e457a89 100644 --- a/miniprogram/pages/staff/employee-dashboard.ts +++ b/miniprogram/pages/staff/employee-dashboard.ts @@ -1,5 +1,6 @@ // 员工界面 - 全屏工作面板 import { UserInfo } from '../../types'; +import userService from '../../services/userService'; Page({ data: { @@ -156,5 +157,70 @@ Page({ wx.makePhoneCall({ phoneNumber: '400-123-4567' }); + }, + + /** + * 解绑微信处理 + */ + async onUnbindWechat() { + try { + // 确认对话框 + wx.showModal({ + title: '确认解绑', + content: '解绑微信后,您将需要重新登录并绑定账号。确定要继续吗?', + confirmText: '确定解绑', + confirmColor: '#e74c3c', + cancelText: '取消', + success: async (res) => { + if (res.confirm) { + // 显示加载中 + wx.showLoading({ + title: '解绑中...', + mask: true + }); + + try { + // 调用解绑服务 + const result = await userService.unbindWechat(); + + wx.hideLoading(); + + if (result.success) { + wx.showToast({ + title: '解绑成功', + icon: 'success', + duration: 2000 + }); + + // 延迟跳转到登录页面 + setTimeout(() => { + wx.reLaunch({ + url: '/pages/login/login' + }); + }, 2000); + } else { + wx.showToast({ + title: result.message || '解绑失败', + icon: 'none' + }); + } + } catch (error) { + wx.hideLoading(); + wx.showToast({ + title: '解绑失败,请重试', + icon: 'none' + }); + console.error('解绑微信错误:', error); + } + } + } + }); + } catch (error) { + console.error('解绑微信处理错误:', error); + wx.showToast({ + title: '操作失败,请重试', + icon: 'none' + }); + } } }); \ No newline at end of file diff --git a/miniprogram/pages/staff/employee-dashboard.wxml b/miniprogram/pages/staff/employee-dashboard.wxml index 6b189d4..59f22d5 100644 --- a/miniprogram/pages/staff/employee-dashboard.wxml +++ b/miniprogram/pages/staff/employee-dashboard.wxml @@ -81,5 +81,6 @@ 员工工作系统 v1.0 {{currentTime}} + \ No newline at end of file diff --git a/miniprogram/pages/staff/employee-dashboard.wxss b/miniprogram/pages/staff/employee-dashboard.wxss index 408835c..9dbe00b 100644 --- a/miniprogram/pages/staff/employee-dashboard.wxss +++ b/miniprogram/pages/staff/employee-dashboard.wxss @@ -5,16 +5,21 @@ display: flex; flex-direction: column; padding: 0; + /* 安全区域适配 - 为整个容器添加顶部安全区域 */ + padding-top: env(safe-area-inset-top); + box-sizing: border-box; } /* 顶部导航栏样式 */ .employee-header { background: rgba(255, 255, 255, 0.95); - padding: 30rpx 40rpx; + padding: 40rpx 40rpx 30rpx 40rpx; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); + /* 移除margin-top,使用容器的padding-top来处理安全区域 */ + min-height: 140rpx; } .header-left { @@ -320,4 +325,21 @@ .footer-time { font-size: 22rpx; color: #999; +} + +/* 解绑微信按钮样式 */ +.unbind-btn { + background: #e74c3c; + color: white; + border: none; + border-radius: 8rpx; + padding: 12rpx 20rpx; + font-size: 24rpx; + cursor: pointer; + transition: all 0.3s ease; +} + +.unbind-btn:active { + background: #c0392b; + transform: translateY(1rpx); } \ No newline at end of file diff --git a/miniprogram/pages/staff/employee-management.ts b/miniprogram/pages/staff/employee-management.ts index 543f41d..8cefb7b 100644 --- a/miniprogram/pages/staff/employee-management.ts +++ b/miniprogram/pages/staff/employee-management.ts @@ -148,16 +148,16 @@ Page({ if (!phone.trim()) { this.setData({ - errorMessage: '请输入手机号' + errorMessage: '请输入员工工号' }); return false; } - // 简单的手机号格式验证 - const phoneRegex = /^1[3-9]\d{9}$/; + // 简单的工号格式验证 + const phoneRegex = /^\d+$/; if (!phoneRegex.test(phone)) { this.setData({ - errorMessage: '请输入正确的手机号格式' + errorMessage: '工号只能包含数字' }); return false; } diff --git a/miniprogram/pages/staff/employee-management.wxml b/miniprogram/pages/staff/employee-management.wxml index 89b2938..99a9c86 100644 --- a/miniprogram/pages/staff/employee-management.wxml +++ b/miniprogram/pages/staff/employee-management.wxml @@ -57,7 +57,7 @@ @@ -80,7 +80,7 @@ {{getRoleText(item.role)}} - {{item.phone}} + 工号: {{item.phone}} ID: {{item.id}} @@ -122,10 +122,10 @@ - 手机号码 + 员工工号 - 提示:添加员工后,用户可以使用该员工的姓名和手机号进行注册 + 提示:添加员工后,用户可以使用该员工的姓名和工号进行绑定 diff --git a/miniprogram/services/apiService.ts b/miniprogram/services/apiService.ts index 90fa6fe..43078e9 100644 --- a/miniprogram/services/apiService.ts +++ b/miniprogram/services/apiService.ts @@ -95,8 +95,10 @@ class ApiService { if (res.statusCode >= 200 && res.statusCode < 300) { resolve(res.data); } else { - console.error(`API Error: HTTP ${res.statusCode}: ${res.errMsg}`); - reject(new Error(`HTTP ${res.statusCode}: ${res.errMsg}`)); + // 优先使用服务器返回的具体错误信息,如果没有则使用默认错误信息 + const errorMessage = res.data || res.errMsg || '请求失败'; + console.error(`API Error: HTTP ${res.statusCode}: ${errorMessage}`); + reject(new Error(`HTTP ${res.statusCode}: ${errorMessage}`)); } }, fail: (err: any) => { @@ -163,29 +165,58 @@ async ServerLogin(code: string) { } /** - * 注册接口 - * @param userInfo 注册用户信息 - * @returns 注册结果和员工信息 + * 绑定接口 + * @param userInfo 绑定用户信息 + * @returns 绑定结果和员工信息 */ async userRegister(userInfo: { name: string; phone: string }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> { console.log('API userRegister调用,参数userInfo:', userInfo); - // 服务器现在返回统一的DTO格式:{ success: boolean, userInfo: UserInfoResponse } + // 服务器返回直接的用户信息格式:{id, name, phone, role, openid} const response = await this.request('/user/register', { method: 'POST', data: userInfo, }); - return { - success: response.success, - employeeInfo: { - id: response.userInfo.id, - name: response.userInfo.name || userInfo.name, // 如果服务器返回null,使用用户输入的值 - phone: response.userInfo.phone || userInfo.phone, // 如果服务器返回null,使用用户输入的值 - role: response.userInfo.role || 'DELIVERY_PERSON' - }, - message: response.message - }; + // 检查响应格式,兼容不同的返回格式 + if (response.id) { + // 直接返回用户信息格式 + return { + success: true, + employeeInfo: { + id: response.id, + name: response.name || userInfo.name, + phone: response.phone || userInfo.phone, + role: response.role || 'DELIVERY_PERSON' + }, + message: '绑定成功' + }; + } else if (response.userInfo && response.userInfo.id) { + // 包装格式:{success, userInfo, message} + return { + success: response.success !== false, + employeeInfo: { + id: response.userInfo.id, + name: response.userInfo.name || userInfo.name, + phone: response.userInfo.phone || userInfo.phone, + role: response.userInfo.role || 'DELIVERY_PERSON' + }, + message: response.message + }; + } else { + // 未知格式,返回错误 + console.error('未知的绑定响应格式:', response); + return { + success: false, + employeeInfo: { + id: 0, + name: userInfo.name, + phone: userInfo.phone, + role: 'DELIVERY_PERSON' + }, + message: '绑定响应格式错误' + }; + } } @@ -197,6 +228,25 @@ async ServerLogin(code: string) { return await this.request('/user/logout', { method: 'POST' }); } + /** + * 解绑微信接口 + * 清除当前用户的openid绑定,允许重新注册其他账号 + * @returns 解绑结果 + */ + async unbindWechat(): Promise<{ success: boolean; message?: string }> { + console.log('API unbindWechat调用'); + + const response = await this.request('/user/unbind', { + method: 'POST', + data: {} + }); + + return { + success: response.success, + message: response.message + }; + } + /** * 签退接口 * @param userId 用户ID diff --git a/miniprogram/services/employeeService.ts b/miniprogram/services/employeeService.ts index 4e7ed55..5e76373 100644 --- a/miniprogram/services/employeeService.ts +++ b/miniprogram/services/employeeService.ts @@ -77,8 +77,8 @@ class EmployeeService { } /** - * 根据手机号查找员工 - * @param phone 手机号 + * 根据工号查找员工 + * @param phone 工号 * @returns 员工信息或null */ async findEmployeeByPhone(phone: string): Promise { @@ -87,9 +87,9 @@ class EmployeeService { } /** - * 验证员工信息(用于注册时检查) - * @param name 姓名 - * @param phone 手机号 + * 验证员工信息(用于绑定时检查) + * @param name 姓名 + * @param phone 工号 * @returns 验证结果 */ async validateEmployee(name: string, phone: string): Promise<{ success: boolean; message?: string; employee?: EmployeeInfo }> { diff --git a/miniprogram/services/locationTrackingService.ts b/miniprogram/services/locationTrackingService.ts index c2f6ac0..0fe0fe8 100644 --- a/miniprogram/services/locationTrackingService.ts +++ b/miniprogram/services/locationTrackingService.ts @@ -423,17 +423,40 @@ class LocationTrackingService { const formattedUsers = message.users.map((user: any) => { // 支持多种数据格式:locationData字段或直接字段 const locationData = user.locationData || user; - return { + + // 验证必需字段是否存在 + if (!user.userId && !locationData.userId) { + console.error('❌ 用户数据缺少userId字段:', user); + return null; + } + + if (locationData.latitude === undefined || locationData.longitude === undefined) { + console.error('❌ 用户数据缺少位置信息:', user); + return null; + } + + // 对于位置更新消息,允许缺少name和role字段,从本地缓存中获取 + const existingUser = this.onlineUsers.get(user.userId || locationData.userId); + + const formattedUser = { userId: user.userId || locationData.userId, - name: user.name || user.userName || `用户${user.userId || locationData.userId}`, - role: user.role || 'employee', + name: user.name || user.userName || (existingUser ? existingUser.name : `用户${user.userId || locationData.userId}`), + role: user.role || (existingUser ? existingUser.role : 'DRIVER'), userStatus: user.userStatus !== false, // 转换为布尔值 lastUpdateTime: user.lastUpdateTime || locationData.timestamp || Date.now(), latitude: locationData.latitude, longitude: locationData.longitude, timestamp: locationData.timestamp || user.timestamp || Date.now() }; - }); + + // 验证必需字段 + if (!formattedUser.userId) { + console.error('❌ 用户数据缺少userId字段:', formattedUser); + return null; + } + + return formattedUser; + }).filter(user => user !== null); // 过滤掉无效数据 console.log('📊 转换后的用户位置数据:', formattedUsers); @@ -500,12 +523,15 @@ class LocationTrackingService { const longitude = user.longitude; const timestamp = user.timestamp || user.lastUpdateTime || Date.now(); + // 对于位置更新消息,允许缺少name和role字段,从本地缓存中获取 + const existingUser = this.onlineUsers.get(user.userId); + // 更新或添加用户信息 this.onlineUsers.set(user.userId, { userId: user.userId, - name: user.name || user.userName || `用户${user.userId}`, + name: user.name || user.userName || (existingUser ? existingUser.name : `用户${user.userId}`), avatarUrl: '/images/user-avatar.png', - role: user.role || 'employee', + role: user.role || (existingUser ? existingUser.role : 'DRIVER'), lastLocation: { userId: user.userId, longitude: longitude, diff --git a/miniprogram/services/mapService.ts b/miniprogram/services/mapService.ts index e19d1ac..5d8ec0c 100644 --- a/miniprogram/services/mapService.ts +++ b/miniprogram/services/mapService.ts @@ -64,26 +64,12 @@ class MapService { clearTimeout(timeout); console.error('高德地图SDK定位失败:', err); - // 如果高德SDK失败,尝试使用微信原生API - console.log('尝试使用微信原生getLocation API...'); - wx.getLocation({ - type: 'gcj02', - success: (wxRes) => { - console.log('微信原生API定位成功:', wxRes); - resolve({ - longitude: wxRes.longitude, - latitude: wxRes.latitude - }); - }, - fail: (wxErr) => { - console.error('微信原生API定位失败:', wxErr); - // 所有方法都失败,使用模拟位置 - console.log('所有定位方法失败,使用模拟位置'); - resolve({ - longitude: 102.7123, - latitude: 25.0409 - }); - } + // 注释:高德SDK失败后,直接使用模拟位置,不调用微信原生API + // 原因:微信小程序可能没有位置权限,避免权限错误 + console.log('高德地图SDK定位失败,使用模拟位置'); + resolve({ + longitude: 102.7123, + latitude: 25.0409 }); } }, (locationString: string) => { diff --git a/miniprogram/services/userService.ts b/miniprogram/services/userService.ts index a3d287d..3075765 100644 --- a/miniprogram/services/userService.ts +++ b/miniprogram/services/userService.ts @@ -113,7 +113,7 @@ class UserService { } /** - * 执行静默登录流程:微信登录->个人服务器登录->进入基础界面->签到/注册 + * 执行静默登录流程:微信登录->个人服务器登录->进入基础界面->签到/绑定 * @returns 登录结果 */ async wxLogin(): Promise<{ @@ -293,14 +293,59 @@ class UserService { } /** - * 用户注册 - * @param registerInfo 注册信息 - * @returns 注册结果和员工信息 + * 用户绑定 + * @param registerInfo 绑定信息 + * @returns 绑定结果和员工信息 */ async register(registerInfo: { name: string; phone: string }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> { return apiService.userRegister(registerInfo); } + /** + * 解绑微信 + * 清除当前用户的openid绑定,允许重新注册其他账号 + * @returns 解绑结果 + */ + async unbindWechat(): Promise<{ success: boolean; message?: string }> { + try { + console.log('开始解绑微信流程'); + + // 调用API解绑 + const result = await apiService.unbindWechat(); + + if (result.success) { + console.log('微信解绑成功'); + + // 清除本地存储的登录信息 + wx.removeStorageSync('userInfo'); + wx.removeStorageSync('token'); + wx.removeStorageSync('openid'); + wx.removeStorageSync('session_key'); + + // 清除全局数据 + const app = getApp(); + app.globalData.userInfo = null; + app.globalData.token = null; + app.globalData.openid = null; + app.globalData.isLoggedIn = false; + + console.log('本地登录信息已清除'); + + // 解绑成功后跳转到主界面 + setTimeout(() => { + wx.reLaunch({ + url: '/pages/index/index' + }); + }, 500); + } + + return result; + } catch (error) { + console.error('解绑微信失败:', error); + return { success: false, message: '解绑微信失败,请重试' }; + } + } + /** * 获取用户权限列表 * @returns 权限列表