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

276 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Vue from 'vue'
import Vuex from 'vuex'
import { getEnums, getMyEffectiveContracts, getMyPendingSignContracts, orderSearchedMePage } from '@/api/index.js'
import { normalizeBookingList, parseOrderListResponse, pickCurrentBooking, pickCurrentStayOrder } from '@/utils/booking-helper'
import { getBuiltInEnums } from '@/utils/enum-store'
Vue.use(Vuex)
let lifeData = {}
// 尝试获取本地是否存在lifeData变量,第一次启动时不存在
try {
lifeData = uni.getStorageSync('lifeData')
} catch(e) {
}
// 标记需要永久存储的变量,在每次启动时取出,在 state 中的变量名
let saveStateKeys = ['vuex_user', 'vuex_identity', 'vuex_locale', 'vuex_checkin_status', 'vuex_current_order']
const normalizeIdentityValue = (value) => {
const map = {
resident: '1',
counselor: '2',
'dorm-manager': '3',
social: '0'
}
if (value === undefined || value === null || value === '') return ''
const normalized = map[value] || value
return String(normalized)
}
// 保存变量到本地存储
const saveLifeData = function(key, value) {
// 判断变量是否在存储数组中
if (saveStateKeys.indexOf(key) != -1) {
// 获取本地存储的lifeData对象,将变量添加到对象中
let tmpLifeData = uni.getStorageSync('lifeData')
// 第一次启动时不存在,则放一个空对象
tmpLifeData = tmpLifeData ? tmpLifeData : {},
tmpLifeData[key] = value
// 将变量再次放回本地存储中
uni.setStorageSync('lifeData', tmpLifeData)
}
}
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 logRequestError(name, error) {
console.error(`[store] ${name} failed`, error)
return []
}
function resolveOrderNo(order = {}) {
const safeOrder = order || {}
const candidates = [safeOrder.orderNo, safeOrder.no, safeOrder.code, safeOrder.OrderNo]
for (let index = 0; index < candidates.length; index += 1) {
const value = candidates[index]
if (value === undefined || value === null) {
continue
}
const text = String(value).trim()
if (text) {
return text
}
}
return ''
}
let lastFetchStatusTime = 0
let fetchUserGlobalStatusPromise = null
let globalEnumsPromise = null
let lastFetchEnumsTime = 0
const GLOBAL_ENUMS_TTL = 10 * 60 * 1000
const store = new Vuex.Store({
state: {
// 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量
// 加上vuex_前缀,是防止变量名冲突,也让人一目了然
vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {},
vuex_identity: normalizeIdentityValue(lifeData.vuex_identity),
vuex_checkin_status: lifeData.vuex_checkin_status !== undefined ? lifeData.vuex_checkin_status : false,
vuex_locale: lifeData.vuex_locale ? lifeData.vuex_locale : 'zh-Hans',
// app版本
vuex_version: "1.0.0",
// 是否使用自定义导航栏
vuex_custom_nav_bar: true,
// 状态栏高度
vuex_status_bar_height: 0,
// 自定义导航栏的高度
vuex_custom_bar_height: 0,
vuex_pending_contract_count: 0,
vuex_pending_contracts: [],
vuex_effective_contracts: [],
vuex_valid_orders: [],
vuex_current_order: lifeData.vuex_current_order ? lifeData.vuex_current_order : null,
vuex_enums: getBuiltInEnums(lifeData.vuex_locale || 'zh-Hans')
},
mutations: {
$tStore(state, payload) {
// 判断是否多层调用,state中为对象存在的情况,例如user.info.score = 1
let nameArr = payload.name.split('.')
let saveKey = ''
let len = nameArr.length
if (len >= 2) {
let obj = state[nameArr[0]]
for (let i= 1; i < len - 1; i++) {
obj = obj[nameArr[i]]
}
obj[nameArr[len - 1]] = payload.value
saveKey = nameArr[0]
} else {
// 单层级变量
state[payload.name] = payload.name === 'vuex_identity'
? normalizeIdentityValue(payload.value)
: payload.value
saveKey = payload.name
}
// 保存变量到本地中
saveLifeData(saveKey, state[saveKey])
}
},
actions: {
fetchUserGlobalStatus({ state, commit }, options = {}) {
const force = !!(options && options.force)
const language = (options && options.language) || 'zh'
const currentUser = state.vuex_user || {}
const userCode = currentUser.code || currentUser.userCode || ''
const cachedOrders = Array.isArray(state.vuex_valid_orders) ? state.vuex_valid_orders : []
const cachedPendingContracts = Array.isArray(state.vuex_pending_contracts) ? state.vuex_pending_contracts : []
const cachedEffectiveContracts = Array.isArray(state.vuex_effective_contracts) ? state.vuex_effective_contracts : []
const cachedCurrentOrder = state.vuex_current_order || pickCurrentStayOrder(cachedOrders)
const cachedCurrentBooking = currentUser.currentBooking || pickCurrentBooking(cachedOrders) || null
const cachedResult = {
pendingContracts: cachedPendingContracts,
effectiveContracts: cachedEffectiveContracts,
validOrders: cachedOrders,
currentOrder: cachedCurrentOrder || null,
currentBooking: cachedCurrentBooking,
hasCheckedIn: !!cachedCurrentOrder
}
if (!userCode) return Promise.resolve(cachedResult)
const now = Date.now()
if (!force && fetchUserGlobalStatusPromise) {
return fetchUserGlobalStatusPromise
}
if (!force && now - lastFetchStatusTime < 1000) {
return Promise.resolve(cachedResult)
}
lastFetchStatusTime = now
fetchUserGlobalStatusPromise = Promise.all([
orderSearchedMePage({ PageIndex: 1, PageSize: 100, IsExport: false }, language).catch((error) => logRequestError('orderSearchedMePage', error))
]).then(([orderResponse]) => {
const validOrders = normalizeBookingList(parseOrderListResponse(orderResponse), language)
const currentOrder = pickCurrentStayOrder(validOrders)
const currentOrderNo = resolveOrderNo(currentOrder)
return Promise.all([
Promise.resolve(validOrders),
Promise.resolve(currentOrder),
currentOrderNo
? getMyPendingSignContracts({ OrderNo: currentOrderNo, ProviderType: 'WechatMiniProgram' }, language).catch((error) => logRequestError('getMyPendingSignContracts', error))
: Promise.resolve([]),
currentOrderNo
? getMyEffectiveContracts({ OrderNo: currentOrderNo, ProviderType: 'WechatMiniProgram' }, language).catch((error) => logRequestError('getMyEffectiveContracts', error))
: Promise.resolve([])
])
}).then(([validOrders, currentOrder, pendingContractsResponse, effectiveContractsResponse]) => {
const pendingContracts = parseContractList(pendingContractsResponse)
const effectiveContracts = parseContractList(effectiveContractsResponse)
const currentBooking = pickCurrentBooking(validOrders)
const nextUser = {
...currentUser,
hasCheckedIn: !!currentOrder,
currentOrder: currentOrder || null,
currentBooking: currentBooking || null,
bookingStatus: currentBooking ? (currentBooking.status || currentBooking.statusKey || 'none') : 'none',
bookingRejectReason: currentBooking ? (currentBooking.rejectReasonText || currentBooking.rejectReason || '') : ''
}
commit('$tStore', { name: 'vuex_pending_contracts', value: pendingContracts })
commit('$tStore', { name: 'vuex_pending_contract_count', value: pendingContracts.length })
commit('$tStore', { name: 'vuex_effective_contracts', value: effectiveContracts })
commit('$tStore', { name: 'vuex_valid_orders', value: validOrders })
commit('$tStore', { name: 'vuex_checkin_status', value: !!currentOrder })
commit('$tStore', { name: 'vuex_current_order', value: currentOrder || null })
commit('$tStore', { name: 'vuex_user', value: nextUser })
return {
pendingContracts,
effectiveContracts,
validOrders,
currentOrder,
currentBooking,
hasCheckedIn: !!currentOrder
}
}).catch((error) => {
console.error('[store] fetchUserGlobalStatus failed', error)
return cachedResult
}).finally(() => {
fetchUserGlobalStatusPromise = null
})
return fetchUserGlobalStatusPromise
},
fetchGlobalEnums({ state, commit }, options = {}) {
const force = !!(options && options.force)
const hasEnums = state.vuex_enums && Object.keys(state.vuex_enums).length > 0
const now = Date.now()
if (!force && hasEnums && now - lastFetchEnumsTime < GLOBAL_ENUMS_TTL) {
return Promise.resolve(state.vuex_enums)
}
if (!force && globalEnumsPromise) {
return globalEnumsPromise
}
const language = (options && options.language) || state.vuex_locale
globalEnumsPromise = getEnums({}, language)
.then((res) => {
const data = res && res.data ? res.data : res
const enumsMap = getBuiltInEnums(language)
if (Array.isArray(data)) {
data.forEach(item => {
enumsMap[item.code] = item.data || []
})
}
commit('$tStore', {
name: 'vuex_enums',
value: enumsMap
})
lastFetchEnumsTime = Date.now()
return enumsMap
})
.catch(() => {
return hasEnums ? state.vuex_enums : getBuiltInEnums(language)
})
.finally(() => {
globalEnumsPromise = null
})
return globalEnumsPromise
}
}
,
getters: {
enumOptions: (state) => (code) => {
return state.vuex_enums[code] || []
},
enumLabel: (state) => (code, key) => {
const options = state.vuex_enums[code] || []
const option = options.find(item => String(item.key) === String(key))
return option ? option.value : key
}
}
})
export default store