permission.js 7.81 KB
/*
 * @Date: 2025-01-08 18:00:00
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-07-09 11:16:49
 * @FilePath: /jgdl/src/utils/permission.js
 * @Description: 权限控制工具函数
 */
import { useUserStore } from '@/stores/user'
import Taro from '@tarojs/taro'

/**
 * 权限类型枚举
 */
export const PERMISSION_TYPES = {
    // 基础权限:需要完善手机号等基本信息
    BASIC_INFO: 'basic_info',
    // 卖车权限:需要完善基本信息
    SELL_CAR: 'sell_car',
    // 买车权限:需要完善基本信息
    BUY_CAR: 'buy_car',
    // 联系卖家权限:需要完善基本信息
    CONTACT_SELLER: 'contact_seller',
    // 个人中心权限:需要完善基本信息
    PROFILE: 'profile',
    // 订单管理权限:需要完善基本信息
    ORDER_MANAGEMENT: 'order_management',
    // 消息权限:需要完善基本信息
    // MESSAGE: 'message'
}

/**
 * 权限配置
 */
const PERMISSION_CONFIG = {
    [PERMISSION_TYPES.BASIC_INFO]: {
        message: '请先完善个人信息',
        redirectUrl: '/pages/register/index',
        checkFields: ['phone']
    },
    [PERMISSION_TYPES.SELL_CAR]: {
        message: '发布车源需要先完善个人信息',
        redirectUrl: '/pages/register/index',
        checkFields: ['phone']
    },
    [PERMISSION_TYPES.BUY_CAR]: {
        message: '购买车辆需要先完善个人信息',
        redirectUrl: '/pages/register/index',
        checkFields: ['phone']
    },
    [PERMISSION_TYPES.CONTACT_SELLER]: {
        message: '联系卖家需要先完善个人信息',
        redirectUrl: '/pages/register/index',
        checkFields: ['phone']
    },
    [PERMISSION_TYPES.PROFILE]: {
        message: '访问个人中心需要先完善个人信息',
        redirectUrl: '/pages/register/index',
        checkFields: ['phone']
    },
    [PERMISSION_TYPES.ORDER_MANAGEMENT]: {
        message: '查看订单需要先完善个人信息',
        redirectUrl: '/pages/register/index',
        checkFields: ['phone']
    },
    // [PERMISSION_TYPES.MESSAGE]: {
    //     message: '查看消息需要先完善个人信息',
    //     redirectUrl: '/pages/register/index',
    //     checkFields: ['phone']
    // }
}

/**
 * 检查用户是否满足指定字段的要求
 * @param {Object} userInfo - 用户信息
 * @param {Array} checkFields - 需要检查的字段
 * @returns {boolean} 是否满足要求
 */
function checkUserFields(userInfo, checkFields) {
    return checkFields.every(field => {
        const value = userInfo[field]
        return value && value.toString().trim() !== ''
    })
}

/**
 * 权限检查函数
 * @param {string} permissionType - 权限类型
 * @param {Object} options - 配置选项
 * @param {string} options.message - 自定义提示消息
 * @param {string} options.redirectUrl - 自定义跳转地址
 * @param {Array} options.checkFields - 自定义检查字段
 * @param {Function} options.onSuccess - 验证成功回调
 * @param {Function} options.onFail - 验证失败回调
 * @param {boolean} options.showToast - 是否显示提示(默认true)
 * @param {boolean} options.autoRedirect - 是否自动跳转(默认true)
 * @returns {Promise<boolean>} 是否通过权限验证
 */
export async function checkPermission(permissionType, options = {}) {
    const userStore = useUserStore()

    // 获取权限配置
    const config = PERMISSION_CONFIG[permissionType] || PERMISSION_CONFIG[PERMISSION_TYPES.BASIC_INFO]

    // 合并配置
    const finalConfig = {
        message: options.message || config.message,
        redirectUrl: options.redirectUrl || config.redirectUrl,
        checkFields: options.checkFields || config.checkFields,
        showToast: options.showToast !== false,
        autoRedirect: options.autoRedirect !== false,
        onSuccess: options.onSuccess,
        onFail: options.onFail
    }

    try {
        // 如果用户信息为空,先尝试获取
        if (!userStore.isAuthenticated) {
            await userStore.fetchUserInfo()
        }

        // 检查用户字段
        const hasPermission = checkUserFields(userStore.userInfo, finalConfig.checkFields)

        if (hasPermission) {
            // 权限验证成功
            finalConfig.onSuccess && finalConfig.onSuccess()
            return true
        } else {
            // 权限验证失败
            if (finalConfig.showToast) {
                Taro.showToast({
                    title: finalConfig.message,
                    icon: 'none',
                    duration: 2000,
                    success: () => {
                        if (finalConfig.autoRedirect) {
                            setTimeout(() => {
                                Taro.navigateTo({
                                    url: finalConfig.redirectUrl
                                })
                            }, 2000)
                        }
                    }
                })
            } else if (finalConfig.autoRedirect) {
                Taro.navigateTo({
                    url: finalConfig.redirectUrl
                })
            }

            finalConfig.onFail && finalConfig.onFail()
            return false
        }
    } catch (error) {
        console.error('权限检查失败:', error)
        finalConfig.onFail && finalConfig.onFail(error)
        return false
    }
}

/**
 * 权限装饰器函数,用于包装需要权限验证的函数
 * @param {string} permissionType - 权限类型
 * @param {Object} options - 配置选项
 * @returns {Function} 装饰器函数
 */
export function requirePermission(permissionType, options = {}) {
    return function(target, propertyKey, descriptor) {
        const originalMethod = descriptor.value

        descriptor.value = async function(...args) {
            const hasPermission = await checkPermission(permissionType, options)
            if (hasPermission) {
                return originalMethod.apply(this, args)
            }
        }

        return descriptor
    }
}

/**
 * 创建需要权限验证的导航函数
 * @param {string} url - 目标页面路径
 * @param {string} permissionType - 权限类型
 * @param {Object} options - 配置选项
 * @returns {Function} 导航函数
 */
export function createPermissionNavigate(url, permissionType, options = {}) {
    return async function() {
        const hasPermission = await checkPermission(permissionType, options)
        if (hasPermission) {
            Taro.navigateTo({ url })
        }
    }
}

/**
 * 批量权限检查
 * @param {Array} permissions - 权限类型数组
 * @param {Object} options - 配置选项
 * @returns {Promise<boolean>} 是否全部通过权限验证
 */
export async function checkMultiplePermissions(permissions, options = {}) {
    const results = await Promise.all(
        permissions.map(permission =>
            checkPermission(permission, { ...options, showToast: false, autoRedirect: false })
        )
    )

    const allPassed = results.every(result => result)

    if (!allPassed && options.showToast !== false) {
        const config = PERMISSION_CONFIG[permissions[0]] || PERMISSION_CONFIG[PERMISSION_TYPES.BASIC_INFO]
        Taro.showToast({
            title: options.message || config.message,
            icon: 'none',
            duration: 2000
        })
    }

    return allPassed
}

/**
 * 权限中间件,用于页面级别的权限控制
 * @param {string} permissionType - 权限类型
 * @param {Object} options - 配置选项
 * @returns {Function} 中间件函数
 */
export function permissionMiddleware(permissionType, options = {}) {
    return async function() {
        const hasPermission = await checkPermission(permissionType, {
            ...options,
            autoRedirect: true
        })

        if (!hasPermission) {
            // 如果没有权限,阻止页面继续加载
            throw new Error('权限验证失败')
        }

        return hasPermission
    }
}