appointmentHelper.js 7.13 KB
/** 预约状态:后端中文 ↔ 管理端/门店 PC 日历 UI */

export function pickRowField(row, ...keys) {
  if (!row) return undefined
  for (let i = 0; i < keys.length; i++) {
    const v = row[keys[i]]
    if (v !== undefined && v !== null && v !== '') return v
  }
  return undefined
}

export function parseApiDateTime(val) {
  if (val == null || val === '') return null
  if (val instanceof Date) return Number.isNaN(val.getTime()) ? null : val
  if (typeof val === 'number') {
    const d = new Date(val)
    return Number.isNaN(d.getTime()) ? null : d
  }
  const str = String(val).trim()
  if (!str) return null
  if (/^\d+$/.test(str)) {
    const d = new Date(Number(str))
    return Number.isNaN(d.getTime()) ? null : d
  }
  const normalized = str.replace('T', ' ').replace(/-/g, '/')
  const d = new Date(normalized)
  if (!Number.isNaN(d.getTime())) return d
  const d2 = new Date(str)
  return Number.isNaN(d2.getTime()) ? null : d2
}

/** 后端 LqYyjl 列表 yysj 范围:毫秒时间戳,毫秒时间戳 */
export function buildYysjTimestampRange(startDate, endDate) {
  const s = parseApiDateTime(startDate)
  const e = parseApiDateTime(endDate)
  if (!s || !e) return ''
  return [s.getTime(), e.getTime()].join(',')
}

export function apiStatusToUi(fStatus) {
  const s = (fStatus || '').trim()
  if (s === '已预约' || s === '已确认') return 'booked'
  if (s === '服务中') return 'serving'
  if (s === '已转耗卡' || s === '已完成') return 'converted'
  if (s === '已取消') return 'cancelled'
  return 'booked'
}

export function uiStatusToApi(uiStatus) {
  if (uiStatus === 'booked') return '已预约'
  if (uiStatus === 'serving') return '服务中'
  if (uiStatus === 'converted') return '已完成'
  if (uiStatus === 'cancelled') return '已取消'
  return ''
}

export function statusText(uiOrApi) {
  const ui = apiStatusToUi(uiOrApi) === 'booked' && !['booked', 'serving', 'converted', 'cancelled'].includes(uiOrApi)
    ? uiOrApi
    : apiStatusToUi(uiOrApi)
  if (ui === 'booked' || uiOrApi === '已预约') return '已预约'
  if (ui === 'serving' || uiOrApi === '服务中') return '服务中'
  if (ui === 'converted' || uiOrApi === '已完成' || uiOrApi === '已转耗卡') return '已完成'
  if (ui === 'cancelled' || uiOrApi === '已取消') return '已取消'
  return uiOrApi || '无'
}

/** 是否应展示关联耗卡(已转耗卡/已完成或存在有效耗卡) */
export function hasLinkedConsume(row) {
  if (!row) return false
  if (pickRowField(row, 'consumeId', 'ConsumeId')) return true
  if (pickRowField(row, 'hasEffectiveConsume', 'HasEffectiveConsume')) return true
  const fStatus = pickRowField(row, 'F_Status', 'fStatus', 'f_Status', 'status')
  return apiStatusToUi(fStatus) === 'converted'
}

export function mapRelatedConsumeList(list) {
  return (list || []).map(item => ({
    id: pickRowField(item, 'id', 'Id') || '',
    hksj: pickRowField(item, 'hksj', 'Hksj'),
    xfje: pickRowField(item, 'xfje', 'Xfje'),
    hymc: pickRowField(item, 'hymc', 'Hymc') || '无'
  })).filter(item => item.id)
}

export function formatDateYMD(d) {
  const dt = d instanceof Date ? d : parseApiDateTime(d)
  if (!dt) return ''
  const y = dt.getFullYear()
  const m = String(dt.getMonth() + 1).padStart(2, '0')
  const day = String(dt.getDate()).padStart(2, '0')
  return `${y}-${m}-${day}`
}

export function formatTimeHM(dt) {
  if (!dt) return ''
  const d = dt instanceof Date ? dt : parseApiDateTime(dt)
  if (!d) {
    const str = String(dt)
    if (str.includes(' ')) {
      const part = str.split(' ')[1] || ''
      return part.substring(0, 5)
    }
    return str.length >= 5 ? str.substring(0, 5) : ''
  }
  return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
}

export function mapYyjlListRow(row) {
  const yysj = pickRowField(row, 'yysj', 'Yysj')
  const yyjs = pickRowField(row, 'yyjs', 'Yyjs')
  const fStatus = pickRowField(row, 'F_Status', 'f_Status', 'fStatus')
  const date = formatDateYMD(yysj)
  const startTime = formatTimeHM(yysj)
  const endTime = formatTimeHM(yyjs)
  const status = apiStatusToUi(fStatus)
  return {
    id: pickRowField(row, 'id', 'Id', 'F_Id'),
    memberId: pickRowField(row, 'gk', 'Gk'),
    memberName: pickRowField(row, 'gkxm', 'Gkxm') || '无',
    date,
    startTime,
    endTime,
    timeRange: startTime && endTime ? `${startTime}-${endTime}` : '',
    roomId: pickRowField(row, 'roomId', 'RoomId', 'F_RoomId') || '',
    roomName: pickRowField(row, 'roomName', 'RoomName', 'F_RoomName') || '',
    therapistIds: pickRowField(row, 'yyjks', 'Yyjks') ? [pickRowField(row, 'yyjks', 'Yyjks')] : [],
    therapistNames: pickRowField(row, 'yyjksName', 'YyjksName') ? [pickRowField(row, 'yyjksName', 'YyjksName')] : [],
    staffName: pickRowField(row, 'yyjksName', 'YyjksName') || '无',
    yyr: pickRowField(row, 'yyr', 'Yyr') || '',
    yyrName: pickRowField(row, 'yyrName', 'YyrName') || '无',
    storeId: pickRowField(row, 'djmd', 'Djmd') || '',
    storeName: pickRowField(row, 'djmdName', 'DjmdName') || '',
    project: pickRowField(row, 'yytyxm', 'Yytyxm') || pickRowField(row, 'gkxm', 'Gkxm') || '无',
    status,
    fStatus: fStatus,
    remark: pickRowField(row, 'remark', 'Remark', 'F_Remark') || '',
    InviteId: pickRowField(row, 'InviteId', 'inviteId') || '',
    projectSummary: pickRowField(row, 'projectSummary', 'ProjectSummary') || '',
    consumeId: pickRowField(row, 'consumeId', 'ConsumeId') || '',
    hasEffectiveConsume: !!pickRowField(row, 'hasEffectiveConsume', 'HasEffectiveConsume'),
    mobile: '',
    items: [],
    itemLabels: row.yytyxm ? [row.yytyxm] : [],
    colorKey: 'blue'
  }
}

export function mapYyjlInfoToFormRecord(info, pxList = []) {
  const date = formatDateYMD(info.yysj)
  const items = (pxList || []).map(px => ({
    projectId: px.billingItemId || px.px,
    itemId: px.px,
    billingItemId: px.billingItemId,
    label: px.pxmc,
    count: Number(px.projectNumber) || 1,
    workers: (px.jksList || []).map(j => ({ workerId: j.jks, workerName: j.jksxm }))
  }))
  const itemLabels = items.map(x => `${x.label}×${x.count}`)
  const therapistIds = []
  const therapistNames = []
  items.forEach(it => {
    ;(it.workers || []).forEach(w => {
      if (w.workerId && !therapistIds.includes(w.workerId)) {
        therapistIds.push(w.workerId)
        therapistNames.push(w.workerName || w.workerId)
      }
    })
  })
  if (!therapistIds.length && info.yyjks) {
    therapistIds.push(info.yyjks)
    therapistNames.push(info.yyjksName || info.yyjks)
  }
  return {
    id: info.id,
    memberId: info.gk,
    memberName: info.gkxm || '无',
    storeId: info.djmd,
    storeName: info.djmdName || '无',
    yyr: info.yyr,
    yyrName: info.yyrName || '无',
    date,
    startTime: formatTimeHM(info.yysj),
    endTime: formatTimeHM(info.yyjs),
    roomId: info.roomId,
    roomName: info.roomName || '无',
    remark: info.remark || '',
    status: apiStatusToUi(info.F_Status),
    fStatus: info.F_Status,
    InviteId: info.InviteId || '',
    consumeId: info.consumeId || '',
    hasEffectiveConsume: !!info.hasEffectiveConsume,
    relatedConsumes: mapRelatedConsumeList(info.relatedConsumeList),
    items,
    itemLabels,
    therapistIds,
    therapistNames
  }
}