Files
QSY-lvjuxcx/utils/session-sync.js
liangjian 9fee2c3a74 feat: 优化首页服务入口与租住业务流程
补齐首页待办跳转、押金支付引导和多类租住服务页面能力,统一租客端关键业务流程体验。
2026-08-25 13:53:12 +08:00

365 lines
10 KiB
JavaScript

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 {
ProviderType: 'WechatMiniProgram',
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
}