Files
QSY-lvjuxcx/store/index.js
liangjian 445bd850f4 feat: 新增工单中心、房间巡查、失物招领等业务模块
- 新增工单中心(ticket_center)与工单工作台(ticket_workbench)页面
- 新增房间巡查(room_inspection)与失物招领发布(lost_found_publish)页面
- 预约看样流程新增房型/楼栋/楼层选择器组件
- 新增工具模块: booking-entry、privacy、reservation-flow
- api/index.js 补充楼层列表、看样提交等接口
- locales/messages.js 补充多语言文案
- manifest.json 开启微信小程序隐私检查
- 完善登录、注册、申请详情、账单等相关页面交互
2026-07-24 09:35:46 +08:00

275 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 candidates = [order.orderNo, order.no, order.code, order.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 }, 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