/** * App 跳转参数处理 * 花开物业 App 通过 launchMiniProgram 的 extraData 传入支付参数和登录凭证, * 小程序通过 referrerInfo.extraData 接收(查询字符串格式)。 * * extraData 示例: * payAmount=10&acct=xxx&custId=xxx&token=xxx&userId=xxx&sign=xxx&... */ const STORAGE_KEY = 'app_launch_payment_data' const APP_QUERY_KEY = 'app_query_params' /** * 需要转为数组的参数字段(逗号分隔字符串 → 数组) */ const ARRAY_PARAMS = ['billIds'] /** * 解析查询字符串为对象,数组字段自动拆分 */ function parseQueryString(str) { if (!str || typeof str !== 'string') return null const params = {} str.split('&').forEach(item => { const idx = item.indexOf('=') if (idx === -1) return const key = item.substring(0, idx) const val = item.substring(idx + 1) const decoded = decodeURIComponent(val || '') // 同名参数合并为数组;已知数组字段按逗号拆分 if (key in params) { if (Array.isArray(params[key])) { params[key].push(decoded) } else { params[key] = [params[key], decoded] } } else { params[key] = ARRAY_PARAMS.includes(key) && decoded.includes(',') ? decoded.split(',').map(v => v.trim()).filter(Boolean) : decoded } }) return params } /** * 归一化 billId/billIds:单个 id 用 billId,多个用 billIds,统一转为 billIds 数组 */ function normalizeBillParams(obj) { if (!obj) return // 先解码再拆分为数组 if (typeof obj.billIds === 'string') { const decoded = decodeURIComponent(obj.billIds) obj.billIds = decoded.includes(',') ? decoded.split(',').map(v => v.trim()).filter(Boolean) : [decoded] } // billId 存在且 billIds 不存在时,包装为数组 if (obj.billId && !obj.billIds) { const decoded = decodeURIComponent( typeof obj.billId === 'string' ? obj.billId : String(obj.billId) ) obj.billIds = decoded.includes(',') ? decoded.split(',').map(v => v.trim()).filter(Boolean) : [decoded] delete obj.billId } } /** * 从启动参数中获取 App 传入的全部数据(支付参数 + token + userId) */ export function captureAppLaunchData(onShowOptions) { let data = null let queryData = null const tryGetData = (options, label) => { if (!options) return null console.log(label, JSON.stringify(options)) // 保存 path query 参数(供接口调用) if (options.query && Object.keys(options.query).length > 0) { queryData = options.query console.log(label + ' path query 参数:', JSON.stringify(queryData)) } // 优先从 query 获取 if (options.query && Object.keys(options.query).length > 0) { return options.query } // referrerInfo.extraData:可能是对象也可能是查询字符串 const extraData = options?.referrerInfo?.extraData if (extraData) { if (typeof extraData === 'string') { console.log(label + ' extraData 是查询字符串,解析中...') return parseQueryString(extraData) } return extraData } return null } // 冷启动 try { data = tryGetData(wx.getLaunchOptionsSync?.() || {}, '冷启动') } catch (e) { console.error('getLaunchOptionsSync 失败:', e) } // 热启动 if (!data) { data = tryGetData(onShowOptions, '热启动') } if (data && (data.payAmount || data.acct || data.custId || data.billId || data.billIds)) { // 归一化 billId/billIds:单个 id 用 billId,多个用 billIds,统一转为 billIds 数组 normalizeBillParams(data) // 恢复登录态 if (data.token) { uni.setStorageSync('token', data.token) console.log('已恢复 token') } if (data.userId) { uni.setStorageSync('userId', data.userId) console.log('已恢复 userId') } uni.setStorageSync(STORAGE_KEY, data) console.log('已存储 App 支付数据:', JSON.stringify(data)) } // 归一化 queryData 中的 billId/billIds normalizeBillParams(queryData) // 单独保存参数供接口使用(优先 queryData,fallback 到 data,即 extraData 来源) const queryParams = queryData || data if (queryParams) { uni.setStorageSync(APP_QUERY_KEY, queryParams) console.log('已存储 App 接口参数:', JSON.stringify(queryParams)) } return data } /** 检查是否已登录(token 存在) */ export function isLoggedIn() { return !!uni.getStorageSync('token') } /** 获取 App 传入的支付数据 */ export function getAppPaymentData() { try { return uni.getStorageSync(STORAGE_KEY) || null } catch (e) { return null } } /** 获取 App 传入的 path query 参数(供接口调用) */ export function getAppQueryParams() { try { return uni.getStorageSync(APP_QUERY_KEY) || null } catch (e) { return null } } /** 清除 */ export function clearAppPaymentData() { uni.removeStorageSync(STORAGE_KEY) } /** 清除 path query 参数(在支付完成后调用) */ export function clearAppQueryParams() { uni.removeStorageSync(APP_QUERY_KEY) } /** 组装 paymentItem */ export function buildPaymentItemFromApp(appData) { if (!appData) return null const amount = Number(appData.payAmount || appData.orderAmount || 0).toFixed(2) const displayName = appData.goodName || appData.remark || appData.type || '缴费' return { ...appData, type: displayName, rechargeAmount: amount } }