Files
QSY-lvjuxcx/utils/booking-helper.js
liangjian 1111ac148b feat: 重构核心租住流程页面与交互体验
统一注册、看房、申请与入住等核心页面的视觉和流程衔接,补齐支付、签约与状态流转闭环,提升移动端操作连贯性。
2026-07-29 09:05:38 +08:00

396 lines
12 KiB
JavaScript

import { getCurrentLanguage } from './i18n'
function getBookingText(key = '', language = getCurrentLanguage()) {
const isEn = language === 'en'
const map = {
pendingReview: isEn ? 'Pending Review' : '审核中',
approved: isEn ? 'Approved' : '已通过',
waitingCheckin: isEn ? 'Waiting Check-in' : '待入住',
rejected: isEn ? 'Rejected' : '已驳回',
processing: isEn ? 'Processing' : '处理中',
contractSigned: isEn ? 'Signed' : '已签署'
}
return map[key] || ''
}
function parseJsonStringMaybe(value) {
if (typeof value !== 'string') {
return value
}
const trimmed = value.trim()
if (!trimmed) {
return value
}
const looksLikeJson = (
(trimmed.startsWith('{') && trimmed.endsWith('}'))
|| (trimmed.startsWith('[') && trimmed.endsWith(']'))
)
if (!looksLikeJson) {
return value
}
try {
return JSON.parse(trimmed)
} catch (error) {
console.warn('[orderSearchedMePage] JSON parse failed:', error)
return value
}
}
function parseResponsePayload(response) {
const basePayload = response && response.data ? response.data : response
return parseJsonStringMaybe(basePayload)
}
function collectObjectArray(value, depth = 0) {
if (!value || depth > 6) {
return []
}
const normalizedValue = parseJsonStringMaybe(value)
if (Array.isArray(normalizedValue)) {
if (normalizedValue.some(item => item && typeof item === 'object' && !Array.isArray(item))) {
return normalizedValue
}
for (let index = 0; index < normalizedValue.length; index += 1) {
const nestedList = collectObjectArray(normalizedValue[index], depth + 1)
if (nestedList.length) {
return nestedList
}
}
return []
}
if (typeof normalizedValue !== 'object') {
return []
}
const candidateKeys = [
'data',
'list',
'rows',
'items',
'records',
'result',
'payload',
'$values'
]
for (let index = 0; index < candidateKeys.length; index += 1) {
const key = candidateKeys[index]
if (!Object.prototype.hasOwnProperty.call(normalizedValue, key)) {
continue
}
const nestedList = collectObjectArray(normalizedValue[key], depth + 1)
if (nestedList.length) {
return nestedList
}
}
return []
}
export function parseOrderListResponse(response) {
const payload = parseResponsePayload(response)
const orderList = collectObjectArray(payload)
if (!orderList.length) {
console.warn('[orderSearchedMePage] unsupported response structure:', payload)
} else {
console.log('[orderSearchedMePage] parsed order count:', orderList.length)
}
return orderList
}
export function parseOrderDetailResponse(response) {
const payload = parseResponsePayload(response)
if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
return payload
}
const orderList = collectObjectArray(payload)
return Array.isArray(orderList) && orderList.length ? orderList[0] : {}
}
export function formatOrderDateTime(value) {
if (!value) {
return '--'
}
const date = new Date(value)
if (Number.isNaN(date.getTime())) {
return String(value).replace('T', ' ').slice(0, 16) || '--'
}
const pad = item => String(item).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`
}
export function formatOrderDate(value) {
if (!value) {
return '--'
}
const date = new Date(value)
if (Number.isNaN(date.getTime())) {
return String(value).slice(0, 10) || '--'
}
const pad = item => String(item).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
}
function normalizeStatusKey(order = {}) {
const safeOrder = order || {}
const rawStatus = String(safeOrder.status || safeOrder.orderStatus || '').trim()
if (['pending_review', 'approved_wait_assign', 'assigned_wait_room', 'rejected', 'contract_signed'].includes(rawStatus)) {
return rawStatus
}
const contractStatus = Number(safeOrder.contractStatus)
if (contractStatus === 1) {
return 'contract_signed'
}
const approvalStatus = Number(
safeOrder.approvalStatus !== undefined
? safeOrder.approvalStatus
: safeOrder.auditStatus !== undefined
? safeOrder.auditStatus
: safeOrder.statusCode
)
if (approvalStatus === -1 || /reject|refuse|驳回/i.test(rawStatus)) {
return 'rejected'
}
if (approvalStatus === 0 || /pending|review|审核中|待审批/i.test(rawStatus)) {
return 'pending_review'
}
if (
safeOrder.roomNo ||
safeOrder.roomCode ||
safeOrder.roomName ||
safeOrder.checkinDate ||
safeOrder.startDate ||
safeOrder.start
) {
return 'assigned_wait_room'
}
return 'approved_wait_assign'
}
function resolveStatusText(order = {}, statusKey, language = getCurrentLanguage()) {
const safeOrder = order || {}
const contractStatus = Number(safeOrder.contractStatus)
if (contractStatus === 1 && safeOrder.contractStatusDesc && language !== 'en') {
return safeOrder.contractStatusDesc
}
if (language !== 'en' && safeOrder.approvalStatusDesc) {
return safeOrder.approvalStatusDesc
}
if (language !== 'en' && safeOrder.statusDesc) {
return safeOrder.statusDesc
}
const map = {
pending_review: getBookingText('pendingReview', language),
approved_wait_assign: getBookingText('approved', language),
assigned_wait_room: getBookingText('waitingCheckin', language),
rejected: getBookingText('rejected', language),
contract_signed: getBookingText('contractSigned', language)
}
return map[statusKey] || getBookingText('processing', language)
}
function resolveTagType(statusKey) {
if (statusKey === 'rejected') {
return 'rejected'
}
if (statusKey === 'pending_review') {
return 'pending'
}
if (statusKey === 'contract_signed') {
return 'approved'
}
return 'approved'
}
function getBuildingFloorText(order = {}, language = getCurrentLanguage()) {
const safeOrder = order || {}
const isEn = language === 'en'
const building = [
isEn
? (safeOrder.buildingNameEn || safeOrder.buildingEn || safeOrder.buildingSectionNameEn || safeOrder.buildingName || safeOrder.building || safeOrder.buildingSectionName || '')
: (safeOrder.buildingName || safeOrder.building || safeOrder.buildingSectionName || ''),
isEn
? (safeOrder.floorNameEn || safeOrder.floorEn || safeOrder.floorName || safeOrder.floor || '')
: (safeOrder.floorName || safeOrder.floor || '')
].filter(Boolean).join(' ')
return building || '--'
}
function getRoomTypeText(order = {}, language = getCurrentLanguage()) {
const safeOrder = order || {}
const isEn = language === 'en'
if (isEn) {
return safeOrder.roomTypeNameEn || safeOrder.styleNameEn || safeOrder.roomNameEn || safeOrder.roomTypeName || safeOrder.styleNameZh || safeOrder.roomType || safeOrder.roomName || '--'
}
return safeOrder.roomTypeName || safeOrder.styleNameZh || safeOrder.roomType || safeOrder.roomName || '--'
}
function getOrderNo(order = {}) {
const safeOrder = order || {}
return safeOrder.orderNo || safeOrder.no || safeOrder.code || '--'
}
export function getOrderStatusCode(order = {}) {
const safeOrder = order || {}
const candidates = [
safeOrder.orderStatus,
safeOrder.statusCode,
safeOrder.status
]
for (let index = 0; index < candidates.length; index += 1) {
const value = candidates[index]
if (value === '' || value === null || value === undefined) {
continue
}
const numericValue = Number(value)
if (Number.isFinite(numericValue)) {
return numericValue
}
}
return null
}
export function getOrderTime(order = {}) {
const safeOrder = order || {}
const checkInPeriod = safeOrder.checkInPeriod || {}
const candidates = [
safeOrder.updateTime,
safeOrder.createTime,
safeOrder.createdAt,
safeOrder.startDate,
safeOrder.start,
safeOrder.checkinDate,
checkInPeriod.start
]
const timestamp = candidates
.map(value => new Date(value || 0).getTime())
.find(value => Number.isFinite(value) && value > 0)
return timestamp || 0
}
export function sortOrdersByLatest(orderList = []) {
return [...orderList].sort((prev, next) => getOrderTime(next) - getOrderTime(prev))
}
function hasStayFields(order = {}) {
const safeOrder = order || {}
return !!(
safeOrder.roomNo
|| safeOrder.roomCode
|| safeOrder.slotCode
|| safeOrder.contractNo
|| safeOrder.actualCheckInTime
|| safeOrder.checkinTime
)
}
export function isRejectedBookingOrder(order = {}) {
const statusKey = normalizeStatusKey(order)
const statusCode = getOrderStatusCode(order)
return statusKey === 'rejected' || statusCode === -1
}
export function isCheckedInOrder(order = {}) {
const statusCode = getOrderStatusCode(order)
if (statusCode !== null) {
return statusCode > 0
}
const contractStatus = Number(order.contractStatus)
if (contractStatus === 1) {
return true
}
if (isRejectedBookingOrder(order)) {
return false
}
return hasStayFields(order)
}
export function isCurrentBookingOrder(order = {}) {
if (isRejectedBookingOrder(order) || isCheckedInOrder(order)) {
return false
}
const statusCode = getOrderStatusCode(order)
if (statusCode === 0) {
return true
}
const statusKey = normalizeStatusKey(order)
return ['pending_review', 'approved_wait_assign', 'assigned_wait_room', 'contract_signed'].includes(statusKey)
}
export function normalizeBookingOrder(order = {}, language = getCurrentLanguage()) {
const safeOrder = order || {}
const statusKey = normalizeStatusKey(safeOrder)
const statusCode = getOrderStatusCode(safeOrder)
const checkInPeriod = safeOrder.checkInPeriod || {}
const startDate = safeOrder.startDate || safeOrder.start || safeOrder.checkinDate || checkInPeriod.start
const endDate = safeOrder.endDate || safeOrder.end || safeOrder.checkoutDate || checkInPeriod.end
return {
...safeOrder,
orderNo: getOrderNo(safeOrder),
roomTypeText: getRoomTypeText(safeOrder, language),
buildingFloorText: getBuildingFloorText(safeOrder, language),
startDateText: formatOrderDate(startDate),
endDateText: formatOrderDate(endDate),
createdAtText: formatOrderDateTime(safeOrder.createTime || safeOrder.updateTime || safeOrder.createdAt),
roomNoText: language === 'en'
? (safeOrder.roomNoEn || safeOrder.roomCodeEn || safeOrder.roomNameEn || safeOrder.roomNo || safeOrder.roomCode || safeOrder.roomName || '--')
: (safeOrder.roomNo || safeOrder.roomCode || safeOrder.roomName || safeOrder.roomNoEn || safeOrder.roomCodeEn || safeOrder.roomNameEn || '--'),
areaText: language === 'en'
? (safeOrder.areaNameEn || safeOrder.campusNameEn || safeOrder.areaName || safeOrder.campusName || '--')
: (safeOrder.areaName || safeOrder.campusName || '--'),
rejectReasonText: safeOrder.rejectReason || safeOrder.approveReason || safeOrder.remark || '',
startDate,
endDate,
status: statusKey,
statusCode,
statusKey,
statusText: resolveStatusText(safeOrder, statusKey, language),
tagType: resolveTagType(statusKey)
}
}
export function normalizeBookingList(orderList = [], language = getCurrentLanguage()) {
return sortOrdersByLatest(orderList).map(item => normalizeBookingOrder(item, language))
}
export function normalizeBookingDetail(order = {}, language = getCurrentLanguage()) {
if (!order || typeof order !== 'object' || Array.isArray(order)) {
return null
}
return normalizeBookingOrder(order, language)
}
export function pickCurrentStayOrder(orderList = []) {
return sortOrdersByLatest(orderList).find(item => isCheckedInOrder(item)) || null
}
export function pickCurrentBooking(orderList = []) {
return sortOrdersByLatest(orderList).find(item => isCurrentBookingOrder(item)) || null
}