useOfflineBookingCache.js 6.64 KB
/**
 * 刷新离线预约记录缓存
 * - 仅在有授权且网络可用时调用
 * - 成功后将数据存储到本地缓存(key: OFFLINE_BOOKING_DATA)
 * @param {boolean} force - 是否强制刷新,默认为 false
 * @returns {Promise<void>}
 */

import Taro from '@tarojs/taro'
import { billOfflineAllAPI } from '@/api/index'
import { hasAuth } from '@/utils/authRedirect'
import { formatDatetime } from '@/utils/tools'
import { is_usable_network, get_network_type } from '@/utils/network'

export const OFFLINE_BOOKING_CACHE_KEY = 'OFFLINE_BOOKING_DATA'

let refresh_promise = null

const extract_bill_payload = (bill) => {
    if (!bill) return {}

    const data = { ...bill }
    const list = data.list

    if (list && typeof list === 'object' && !Array.isArray(list)) {
        return { ...list, ...data }
    }

    return data
}

const extract_person_list = (bill) => {
    if (!bill) return []

    /**
     * 从预约记录中提取人员列表
     * - 考虑不同字段名的情况(如 person_list, bill_person_list, persons, qrcode_list, qr_list, detail_list)
     * - 确保返回的是数组类型
     */
    const candidate =
        (Array.isArray(bill.list) ? bill.list : null) ||
        (Array.isArray(bill?.list?.list) ? bill.list.list : null) ||
        bill.person_list ||
        bill.bill_person_list ||
        bill.persons ||
        bill.qrcode_list ||
        bill.qr_list ||
        bill.detail_list ||
        []

    return Array.isArray(candidate) ? candidate : []
}

/**
 * 格式化预约记录项
 * @param {Object} item - 原始预约记录项
 * @returns {Object} 格式化后的预约记录项
 */
const normalize_bill_item = (item) => {
    const data = extract_bill_payload(item)

    data.datetime = data.datetime || formatDatetime(data)
    data.booking_time = data.booking_time || data.datetime
    data.order_time = data.order_time || (data.created_time ? data.created_time.slice(0, -3) : '')

    if (!data.person_name) {
        const person_list = extract_person_list(item)
        const first = person_list[0]
        const name = first?.name || first?.person_name
        if (name) data.person_name = name
    }

    return data
}

/**
 * 获取离线预约记录缓存
 * @returns {Array} 格式化后的预约记录项列表
 */
export const get_offline_booking_cache = () => {
    try {
        const data = Taro.getStorageSync(OFFLINE_BOOKING_CACHE_KEY)
        return Array.isArray(data) ? data : []
    } catch (e) {
        return []
    }
}

/**
 * 检查是否存在离线预约记录缓存
 * @returns {boolean} 是否存在缓存且非空
 */
export const has_offline_booking_cache = () => {
    const list = get_offline_booking_cache()
    return Array.isArray(list) && list.length > 0
}

/**
 * 根据支付ID获取离线预约记录
 * @param {*} pay_id 支付ID
 * @returns {Object|null} 匹配的预约记录项或 null
 */
export const get_offline_booking_by_pay_id = (pay_id) => {
    const list = get_offline_booking_cache()
    const target_pay_id = String(pay_id || '')
    return list.find((item) => String(item?.pay_id || '') === target_pay_id) || null
}

/**
 * 获取预约记录中的人员列表
 * @param {Object} bill - 预约记录项
 * @returns {Array} 人员列表(包含姓名、身份证号、二维码等信息)
 */
export const get_offline_bill_person_list = (bill) => {
    return extract_person_list(bill)
}

/**
 * 构建预约记录中的二维码列表
 * @param {Object} bill - 预约记录项
 * @returns {Array} 二维码列表(包含姓名、身份证号、二维码、预约时间等信息)
 */
export const build_offline_qr_list = (bill) => {
    const list = get_offline_bill_person_list(bill)
    const datetime = bill?.datetime || formatDatetime(bill || {})

    return list
        .filter((item) => item && (item.qr_code || item.qrcode || item.qrCode) && (item.qr_code || item.qrcode || item.qrCode) !== '')
        .map((item) => {
            const begin_time = item.begin_time || bill?.begin_time
            const end_time = item.end_time || bill?.end_time
            const qr_code = item.qr_code || item.qrcode || item.qrCode
            const name = item.name || item.person_name || item.real_name
            const id_number = item.id_number || item.idcard || item.idCard || item.id
            return {
                name,
                id_number,
                qr_code,
                begin_time,
                end_time,
                datetime: item.datetime || (begin_time && end_time ? formatDatetime({ begin_time, end_time }) : datetime),
                pay_id: bill?.pay_id,
                sort: 0,
            }
        })
}

/**
 * 刷新离线预约记录缓存
 * - 仅在有授权且网络可用时调用
 * - 成功后将数据存储到本地缓存(key: OFFLINE_BOOKING_DATA)
 * @param {boolean} force - 是否强制刷新,默认为 false. force 参数的核心作用是控制是否忽略 “正在进行的缓存请求”, 管的是 “是否允许重复发起请求”,不管 “请求能不能成功执行缓存”。
 * @returns {Promise<void>}
 */
export const refresh_offline_booking_cache = async ({ force = false } = {}) => {
    // 1. 检查是否有正在进行的刷新请求
    // 2. 如果有,且 force 为 false,则直接返回该 Promise
    // 3. 如果没有,或 force 为 true,则继续执行刷新逻辑
    // 4. 刷新完成后,将结果存储到本地缓存(key: OFFLINE_BOOKING_CACHE_KEY)
    // 5. 返回刷新结果 Promise

    if (!hasAuth()) return { code: 0, data: null, msg: '未授权' }

    if (refresh_promise && !force) return refresh_promise

    // 核心逻辑:
    // 1. 立刻触发异步逻辑,同时捕获 Promise 状态
    // 2. 保证 refresh_promise 始终是 Promise 类型,适配 await
    // 3. 隔离作用域,避免变量污染
    // 加 () 是为了 “让异步逻辑立刻跑起来”,并把 “跑的结果(Promise)” 存起来,供后续复用和等待。
    refresh_promise = (async () => {
        const network_type = await get_network_type()
        if (!is_usable_network(network_type)) {
            return { code: 0, data: null, msg: '网络不可用' }
        }

        const { code, data, msg } = await billOfflineAllAPI()
        if (code && Array.isArray(data)) {
            // 过滤出状态为3(已完成)的记录
            const normalized = data.map(normalize_bill_item).filter((item) => item && item.pay_id && item.status == 3)
            if (normalized.length > 0) {
                Taro.setStorageSync(OFFLINE_BOOKING_CACHE_KEY, normalized)
            }
        }
        return { code, data, msg }
    })()

    try {
        return await refresh_promise
    } finally {
        refresh_promise = null
    }
}