usePlanView.js 5.32 KB
/**
 * 计划书查看 Composable
 *
 * @description 封装计划书查看逻辑,支持:
 * - 单文件直接预览
 * - 多文件显示选择弹框
 * - 预览成功后标记为已查看
 * - 传入 proposal 数据自动处理状态和文件
 *
 * @example
 * const { viewProposal } = usePlanView()
 *
 * // 方式1:传入完整的 proposal 对象(从消息详情 API 获取)
 * viewProposal({
 *   id: 123,
 *   order_status: '7',
 *   proposal_files: [
 *     { file_name: '计划书.pdf', file_url: 'xxx', id: 1 }
 *   ]
 * })
 *
 * // 方式2:传入已转换的 item(从计划书列表获取)
 * viewProposal(planItem)
 *
 * @author Claude Code
 * @version 1.0.0
 */

import { useFileOperation } from './useFileOperation'
import { viewAPI } from '@/api/plan'
import Taro from '@tarojs/taro'

/**
 * 计划书查看 Hook
 *
 * @returns {Object} 包含 viewProposal 方法的对象
 */
export function usePlanView() {
  const { viewFile } = useFileOperation()

  /**
   * 订单状态映射
   *
   * @param {string} orderStatus - API 返回的状态值
   * @returns {string} 前端状态:'pending' | 'processing' | 'generated' | 'viewed'
   *
   * @description 状态值说明(根据API文档):
   * - "3" = 待处理 (pending)
   * - "5" = 处理中 (processing)
   * - "7" = 已生成 (generated)
   * - "9" = 已查看 (viewed)
   */
  const mapOrderStatus = (orderStatus) => {
    const statusMap = {
      '3': 'pending',      // 待处理
      '5': 'processing',  // 处理中
      '7': 'generated',   // 已生成
      '9': 'viewed'       // 已查看
    }
    return statusMap[orderStatus] || 'pending'
  }

  /**
   * 获取状态文本
   *
   * @param {string} status - 前端状态值
   * @returns {string} 状态文本
   */
  const getStatusText = (status) => {
    const textMap = {
      'pending': '待处理',
      'processing': '处理中',
      'generated': '已生成',
      'viewed': '已查看'
    }
    return textMap[status] || '待处理'
  }

  /**
   * 查看计划书
   *
   * @param {Object} proposal - 计划书对象(支持两种格式)
   * @param {number} proposal.id - 计划书 ID(必需)
   * @param {string} proposal.order_status - 订单状态(API 格式:'3'|'5'|'7'|'9')
   * @param {Array} proposal.proposal_files - 文件列表(API 格式)
   * @param {string} proposal.status - 订单状态(前端格式,兼容列表数据)
   * @param {Array} proposal.proposalFiles - 文件列表(兼容列表数据)
   * @param {Object} callbacks - 回调函数
   * @param {Function} callbacks.onViewSuccess - 查看成功后回调,参数为 proposalId
   * @param {Function} callbacks.beforeView - 查看前回调,返回 false 可取消查看
   * @returns {Promise<void>}
   */
  const viewProposal = async (proposal, callbacks = {}) => {
    const { beforeView, onViewSuccess } = callbacks

    // 1. 状态检查 - 解析两种可能的状态字段
    const status = proposal.status || mapOrderStatus(proposal.order_status)

    if (status === 'pending' || status === 'processing') {
      Taro.showToast({
        title: '计划书尚未生成,请稍后',
        icon: 'none'
      })
      return
    }

    // 2. 解析文件列表 - 支持两种可能的字段名
    const proposalFiles = proposal.proposal_files || proposal.proposalFiles || []

    if (!proposalFiles || proposalFiles.length === 0) {
      Taro.showToast({
        title: '暂无可查看的计划书',
        icon: 'none'
      })
      return
    }

    // 3. 执行查看前回调
    if (beforeView) {
      const shouldContinue = await beforeView(proposal)
      if (shouldContinue === false) return
    }

    /**
     * 处理单个文件的查看
     *
     * @param {Object} file - 文件对象
     * @param {string} file.file_url - 文件 URL
     * @param {string} file.file_name - 文件名称
     */
    const handleFileView = async (file) => {
      try {
        const previewSuccess = await viewFile({
          downloadUrl: file.file_url,
          fileName: file.file_name
        })

        if (!previewSuccess) return

        // 4. 预览成功后标记为已查看
        if (status !== 'viewed' && proposal.id) {
          const viewRes = await viewAPI({ i: proposal.id })

          if (viewRes.code === 1) {
            Taro.showToast({
              title: '已标记为查看',
              icon: 'success',
              duration: 1000
            })

            // 触发成功回调
            if (onViewSuccess) {
              onViewSuccess(proposal.id)
            }
          }
        }
      } catch (error) {
        console.error('查看计划书文件失败:', error)
      }
    }

    // 5. 单文件直接查看
    if (proposalFiles.length === 1) {
      await handleFileView(proposalFiles[0])
      return
    }

    // 6. 多文件显示选择弹框
    const fileList = proposalFiles.map((file, index) => ({
      text: file.file_name || `计划书 ${index + 1}`,
      file: file
    }))

    Taro.showActionSheet({
      itemList: fileList.map(f => f.text),
      success: async (res) => {
        const selectedIndex = res.tapIndex
        if (selectedIndex !== undefined && selectedIndex >= 0) {
          const selectedFile = fileList[selectedIndex].file
          await handleFileView(selectedFile)
        }
      }
    })
  }

  return {
    viewProposal,
    mapOrderStatus,
    getStatusText
  }
}