import { clearBookingState, clearMyRoomData, getCurrentUser, getLoginStatus, saveBookingList, saveCurrentBooking, saveEffectiveContracts, saveCurrentUser, saveMyRoomData, savePendingContractCount, savePendingContracts, saveRegisteredUser, setCheckedInStatus } from './app-state' import { getMyEffectiveContracts, getMyPendingSignContracts, orderSearchedMePage } from '@/api/index.js' import store from '@/store' import { normalizeBookingList, parseOrderListResponse, pickCurrentBooking, pickCurrentStayOrder } from './booking-helper' import { getCurrentLanguage } from './i18n' const SYNC_TTL = 3000 let syncStayStatePromise = null let lastSyncStayStateAt = 0 function getSessionSyncText(key = '') { const isEn = getCurrentLanguage() === 'en' const map = { pendingContract: isEn ? 'Pending Contract Signature' : '待签合同' } return map[key] || '' } function parseContractList(response) { const payload = response && response.data ? response.data : response if (Array.isArray(payload)) { return payload } if (payload && Array.isArray(payload.data)) { return payload.data } if (payload && payload.data && Array.isArray(payload.data.data)) { return payload.data.data } return [] } function buildLeaseText(order = {}) { const start = String(order.startDate || order.start || order.checkinDate || '').slice(0, 10) const end = String(order.endDate || order.end || order.checkoutDate || '').slice(0, 10) if (start && end) { return `${start} - ${end}` } return start || end || '' } function mapOrderToRoomData(order = {}) { const imageUrls = Array.isArray(order.imageUrls) ? order.imageUrls : typeof order.imageUrls === 'string' ? order.imageUrls.split(',').map(item => item.trim()).filter(Boolean) : [] const roomLabel = [ order.buildingName || order.buildingSectionName || order.unitName || '', order.roomNo || order.roomCode || order.roomName || '' ].filter(Boolean).join(' ') const title = [ order.areaName || order.campusName || '', order.roomTypeName || order.roomType || '' ].filter(Boolean).join(' · ') return { ...order, id: roomLabel || order.roomNo || order.roomCode || order.orderNo || '', roomLabel: roomLabel || order.roomNo || order.roomCode || '', titleZh: title || order.roomTypeName || order.roomName || '当前入住房间', titleEn: order.roomTypeNameEn || title || order.roomTypeName || 'Current Stay', leaseText: buildLeaseText(order), image: order.imageUrl || imageUrls[0] || '' } } function pickFirstValue(...values) { for (let index = 0; index < values.length; index += 1) { const value = values[index] if (value === undefined || value === null) { continue } const text = String(value).trim() if (text) { return text } } return '' } function buildPendingContractQuery(order = {}) { const safeOrder = order || {} const orderNo = pickFirstValue(safeOrder.orderNo, safeOrder.no, safeOrder.code, safeOrder.OrderNo) if (!orderNo) { return null } return { ProviderType: 'WechatMiniProgram', OrderNo: orderNo } } function buildEffectiveContractQuery(order = {}) { const safeOrder = order || {} const orderNo = pickFirstValue(safeOrder.orderNo, safeOrder.no, safeOrder.code, safeOrder.OrderNo) if (!orderNo) { return null } return { OrderNo: orderNo } } function enrichBookingLanguageFields(booking = {}) { if (!booking || typeof booking !== 'object') { return booking } return { ...booking, statusTextZh: booking.statusTextZh || '待签合同', statusTextEn: booking.statusTextEn || 'Pending Contract Signature' } } function buildContractStepBooking(pendingContracts = []) { const contract = Array.isArray(pendingContracts) ? pendingContracts[0] : null if (!contract || typeof contract !== 'object') { return null } return { ...contract, orderNo: contract.orderNo || contract.OrderNo || '', roomName: contract.roomName || contract.roomTypeName || contract.houseTypeName || '', roomTypeName: contract.roomTypeName || contract.houseTypeName || contract.roomName || '', startDate: contract.start || contract.startDate || '', endDate: contract.end || contract.endDate || '', status: 'contract_pending_sign', statusKey: 'contract_pending_sign', statusCode: 10, statusText: getSessionSyncText('pendingContract'), statusTextZh: '待签合同', statusTextEn: 'Pending Contract Signature' } } function syncStoredUser(hasCheckedIn, currentOrder, currentBooking) { const user = getCurrentUser() if (!user || typeof user !== 'object' || !Object.keys(user).length) { return } const nextUser = { ...user, hasCheckedIn, currentOrder: currentOrder || null, currentBooking: currentBooking || null, bookingStatus: currentBooking ? (currentBooking.status || currentBooking.statusKey || 'none') : 'none', bookingRejectReason: currentBooking ? (currentBooking.rejectReasonText || currentBooking.rejectReason || '') : '' } saveCurrentUser(nextUser) saveRegisteredUser(nextUser) if (store && store.commit) { store.commit('$tStore', { name: 'vuex_user', value: { ...(store.state && store.state.vuex_user ? store.state.vuex_user : {}), ...nextUser } }) } } function syncStoreState({ hasCheckedIn = false, currentOrder = null, pendingContracts = [], effectiveContracts = [], orderList = [] } = {}) { if (!store || !store.commit) { return } store.commit('$tStore', { name: 'vuex_checkin_status', value: !!hasCheckedIn }) store.commit('$tStore', { name: 'vuex_current_order', value: currentOrder || null }) store.commit('$tStore', { name: 'vuex_pending_contracts', value: Array.isArray(pendingContracts) ? pendingContracts : [] }) store.commit('$tStore', { name: 'vuex_pending_contract_count', value: Array.isArray(pendingContracts) ? pendingContracts.length : 0 }) store.commit('$tStore', { name: 'vuex_effective_contracts', value: Array.isArray(effectiveContracts) ? effectiveContracts : [] }) store.commit('$tStore', { name: 'vuex_valid_orders', value: Array.isArray(orderList) ? orderList : [] }) } function requestStayState(language = 'zh') { return orderSearchedMePage({ PageIndex: 1, PageSize: 100, IsExport: false }, language) .then((orderResponse) => { const orderList = normalizeBookingList(parseOrderListResponse(orderResponse), language) const currentOrder = pickCurrentStayOrder(orderList) const pendingContractQuery = buildPendingContractQuery(currentOrder) const effectiveContractQuery = buildEffectiveContractQuery(currentOrder) return Promise.all([ Promise.resolve(orderList), Promise.resolve(currentOrder), pendingContractQuery ? getMyPendingSignContracts(pendingContractQuery, language).catch(() => []) : Promise.resolve([]), effectiveContractQuery ? getMyEffectiveContracts(effectiveContractQuery, language).catch(() => []) : Promise.resolve([]) ]) }) .then(([orderList, currentOrder, pendingContractsResponse, effectiveContractsResponse]) => { const pendingContracts = parseContractList(pendingContractsResponse) const effectiveContracts = parseContractList(effectiveContractsResponse) const currentBooking = enrichBookingLanguageFields(pickCurrentBooking(orderList) || buildContractStepBooking(pendingContracts)) return { hasCheckedIn: !!currentOrder, currentOrder, currentBooking, orderList, pendingContracts, effectiveContracts } }) } export function syncLoginStayState(options = {}) { const { language = 'zh', force = false } = options if (!getLoginStatus()) { return Promise.resolve({ hasCheckedIn: false, currentOrder: null, currentBooking: null, orderList: [] }) } const now = Date.now() if (!force && syncStayStatePromise) { return syncStayStatePromise } if (!force && lastSyncStayStateAt && now - lastSyncStayStateAt < SYNC_TTL) { return Promise.resolve({ skipped: true }) } const syncSource = store && store.dispatch ? store.dispatch('fetchUserGlobalStatus', { force, language }) : requestStayState(language) syncStayStatePromise = syncSource .then((result = {}) => { const orderList = Array.isArray(result.orderList) ? result.orderList : (Array.isArray(result.validOrders) ? result.validOrders : []) const pendingContracts = Array.isArray(result.pendingContracts) ? result.pendingContracts : [] const effectiveContracts = Array.isArray(result.effectiveContracts) ? result.effectiveContracts : [] const currentOrder = result.currentOrder || pickCurrentStayOrder(orderList) const currentBooking = enrichBookingLanguageFields(result.currentBooking || pickCurrentBooking(orderList) || buildContractStepBooking(pendingContracts)) const hasCheckedIn = typeof result.hasCheckedIn === 'boolean' ? result.hasCheckedIn : !!currentOrder saveBookingList(orderList) if (currentBooking) { saveCurrentBooking(currentBooking) } else { clearBookingState() saveBookingList(orderList) } setCheckedInStatus(hasCheckedIn) savePendingContracts(pendingContracts) savePendingContractCount(pendingContracts.length) saveEffectiveContracts(effectiveContracts) if (hasCheckedIn) { saveMyRoomData(mapOrderToRoomData(currentOrder)) } else { clearMyRoomData() } syncStoreState({ hasCheckedIn, currentOrder, pendingContracts, effectiveContracts, orderList }) syncStoredUser(hasCheckedIn, currentOrder, currentBooking) lastSyncStayStateAt = Date.now() return { hasCheckedIn, currentOrder, currentBooking, orderList, pendingContracts, effectiveContracts } }) .finally(() => { syncStayStatePromise = null }) return syncStayStatePromise }