usePermission.js 9.79 KB
/**
 * 通用权限检查 Composable
 *
 * @description 提供统一的权限检查逻辑,支持登录、VIP 等多种权限类型
 * @module composables/usePermission
 * @author Claude Code
 * @created 2026-02-13
 *
 * @example
 * // 基础使用 - 检查登录权限
 * const { requireLogin } = usePermission()
 *
 * requireLogin(() => {
 *   // 已登录时执行的操作
 *   openDocument()
 * })
 *
 * @example
 * // 高级使用 - 自定义提示文案
 * const { checkPermission } = usePermission()
 *
 * checkPermission(PermissionType.LOGIN, callback, {
 *   content: '请先登录后查看完整内容',
 *   confirmText: '立即登录'
 * })
 */

import { useUserStore } from '@/stores/user'
import Taro from '@tarojs/taro'
import { routerStore } from '@/stores/router'
import { PermissionType, getPermissionConfig, getActionPermissionConfig } from '@/config/permissions'

/**
 * 通用权限检查 Hook
 *
 * @description 提供权限检查、权限弹窗等功能
 * @returns {Object} 权限检查方法集合
 */
export function usePermission() {
  const userStore = useUserStore()

  /**
   * 检查登录状态
   * @description 判断用户是否已登录
   * @returns {boolean} 是否已登录
   *
   * @example
   * const { isLoggedIn } = usePermission()
   * if (isLoggedIn()) {
   *   console.log('用户已登录')
   * }
   */
  const isLoggedIn = () => {
    return userStore.isLoggedIn
  }

  const getCurrentPageUrl = () => {
    const pages = Taro.getCurrentPages()
    const currentPage = pages[pages.length - 1]
    if (!currentPage || !currentPage.route) {
      return ''
    }
    const options = currentPage.options || {}
    const query = Object.keys(options)
      .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(options[key])}`)
      .join('&')
    return `/${currentPage.route}${query ? `?${query}` : ''}`
  }

  /**
   * 通用权限检查
   * @description 检查指定权限,无权限时弹窗提示,有权限时执行回调
   * @param {string} permissionType - 权限类型(使用 PermissionType 枚举)
   * @param {Function} callback - 有权限时执行的回调函数
   * @param {Object} customOptions - 自定义配置选项(会覆盖默认配置)
   * @returns {boolean} 是否有权限(true=有权限,false=无权限)
   *
   * @example
   * // 使用默认配置
   * checkPermission(PermissionType.LOGIN, () => {
   *   console.log('已登录,执行操作')
   * })
   *
   * @example
   * // 自定义提示文案
   * checkPermission(PermissionType.LOGIN, callback, {
   *   content: '请先登录后查看完整内容',
   *   confirmText: '立即登录'
   * })
   */
  const checkPermission = (permissionType, callback, customOptions = {}) => {
    console.log(`[usePermission] 检查权限: ${permissionType}`)

    // 根据权限类型执行不同的检查逻辑
    switch (permissionType) {
      case PermissionType.LOGIN:
        return checkLoginPermission(callback, customOptions)

      case PermissionType.VIP:
        return checkVipPermission(callback, customOptions)

      case PermissionType.VERIFIED:
        return checkVerifiedPermission(callback, customOptions)

      default:
        console.warn(`[usePermission] 未知的权限类型: ${permissionType}`)
        return false
    }
  }

  /**
   * 检查登录权限
   * @description 判断用户是否登录,未登录时弹窗引导
   * @param {Function} callback - 已登录时执行的回调
   * @param {Object} customOptions - 自定义配置选项
   * @returns {boolean} 是否已登录
   * @private
   */
  const checkLoginPermission = (callback, customOptions = {}) => {
    if (isLoggedIn()) {
      // 已登录,直接执行回调
      console.log('[usePermission] 用户已登录,执行回调')
      callback?.()
      return true
    }

    // 未登录,弹窗提示
    console.log('[usePermission] 用户未登录,显示登录提示')
    showLoginModal(callback, customOptions)
    return false
  }

  /**
   * 检查 VIP 权限(预留)
   * @description 检查用户是否为 VIP,非 VIP 时弹窗引导
   * @param {Function} callback - 有权限时执行的回调
   * @param {Object} customOptions - 自定义配置选项
   * @returns {boolean} 是否有权限
   * @private
   */
  const checkVipPermission = (callback, customOptions = {}) => {
    // 预留:检查 VIP 状态
    // const isVip = userStore.userInfo?.is_vip
    const isVip = true // 暂时返回 true

    if (isVip) {
      callback?.()
      return true
    }

    showPermissionModal(PermissionType.VIP, callback, customOptions)
    return false
  }

  /**
   * 检查实名认证权限(预留)
   * @description 检查用户是否实名认证,未认证时弹窗引导
   * @param {Function} callback - 有权限时执行的回调
   * @param {Object} customOptions - 自定义配置选项
   * @returns {boolean} 是否有权限
   * @private
   */
  const checkVerifiedPermission = (callback, customOptions = {}) => {
    // 预留:检查实名认证状态
    // const isVerified = userStore.userInfo?.is_verified
    const isVerified = true // 暂时返回 true

    if (isVerified) {
      callback?.()
      return true
    }

    showPermissionModal(PermissionType.VERIFIED, callback, customOptions)
    return false
  }

  /**
   * 显示登录弹窗
   * @description 显示登录引导弹窗,点击确定跳转登录页
   * @param {Function} callback - 用户登录成功后希望执行的回调(用于登录后返回)
   * @param {Object} customOptions - 自定义配置选项
   * @private
   */
  const showLoginModal = (callback, customOptions = {}) => {
    const config = getPermissionConfig(PermissionType.LOGIN, customOptions)

    Taro.showModal({
      title: config.title,
      content: config.content,
      confirmText: config.confirmText,
      cancelText: config.cancelText,
      success: (res) => {
        if (res.confirm) {
          // 用户点击"去登录"
          console.log('[usePermission] 用户选择去登录')
          const store = routerStore()
          const currentUrl = getCurrentPageUrl()
          if (currentUrl) {
            store.add(currentUrl)
          }
          goToLoginPage()
        } else {
          // 用户点击"暂不登录"
          console.log('[usePermission] 用户取消登录')
        }
      }
    })
  }

  /**
   * 显示权限提示弹窗(通用)
   * @description 显示权限不足的提示弹窗
   * @param {string} permissionType - 权限类型
   * @param {Function} callback - 有权限时执行的回调
   * @param {Object} customOptions - 自定义配置选项
   * @private
   */
  const showPermissionModal = (permissionType, callback, customOptions = {}) => {
    const config = getPermissionConfig(permissionType, customOptions)

    Taro.showModal({
      title: config.title,
      content: config.content,
      confirmText: config.confirmText,
      cancelText: config.cancelText,
      success: (res) => {
        if (res.confirm) {
          console.log(`[usePermission] 用户确认权限提示: ${permissionType}`)
          // 根据权限类型执行不同操作
          handlePermissionAction(permissionType)
        }
      }
    })
  }

  /**
   * 处理权限确认后的操作
   * @description 根据权限类型跳转到对应页面
   * @param {string} permissionType - 权限类型
   * @private
   */
  const handlePermissionAction = (permissionType) => {
    switch (permissionType) {
      case PermissionType.LOGIN:
        goToLoginPage()
        break

      case PermissionType.VIP:
        // 跳转到 VIP 开通页面
        console.log('[usePermission] 跳转到 VIP 开通页面')
        break

      case PermissionType.VERIFIED:
        // 跳转到实名认证页面
        console.log('[usePermission] 跳转到实名认证页面')
        break
    }
  }

  /**
   * 跳转到登录页
   * @description 跳转到登录页面
   * @private
   */
  const goToLoginPage = () => {
    Taro.navigateTo({
      url: '/pages/login/index'
    })
  }

  /**
   * 便捷方法:要求登录权限
   * @description 专门用于检查登录权限的便捷方法
   * @param {Function} callback - 已登录时执行的回调
   * @param {Object} customOptions - 自定义配置选项
   * @returns {boolean} 是否已登录
   *
   * @example
   * const { requireLogin } = usePermission()
   *
   * // 查看资料需要登录
   * onView(item) {
   *   requireLogin(() => {
   *     openDocument(item.url)
   *   })
   * }
   */
  const requireLogin = (callback, customOptions = {}) => {
    return checkPermission(PermissionType.LOGIN, callback, customOptions)
  }

  const requireAction = (action, callback, customOptions = {}) => {
    const actionConfig = getActionPermissionConfig(action, customOptions)
    return checkPermission(actionConfig.permission_type, callback, actionConfig.options)
  }

  /**
   * 便捷方法:静默检查权限(不弹窗)
   * @description 只检查权限状态,不弹窗提示
   * @param {string} permissionType - 权限类型
   * @returns {boolean} 是否有权限
   *
   * @example
   * const { hasPermission } = usePermission()
   *
   * if (hasPermission(PermissionType.LOGIN)) {
   *   console.log('用户已登录')
   * }
   */
  const hasPermission = (permissionType) => {
    switch (permissionType) {
      case PermissionType.LOGIN:
        return isLoggedIn()
      case PermissionType.VIP:
        return true // 暂时返回 true
      case PermissionType.VERIFIED:
        return true // 暂时返回 true
      default:
        return false
    }
  }

  // ========== 返回 ==========
  return {
    /** 核心方法:通用权限检查 */
    checkPermission,

    /** 便捷方法:检查登录权限(最常用) */
    requireLogin,

    requireAction,

    /** 工具方法:静默检查是否有权限(不弹窗) */
    hasPermission,

    /** 工具方法:获取当前登录状态 */
    isLoggedIn
  }
}