diff --git a/huakai-app/App.vue b/huakai-app/App.vue index 13d0db7..9732e90 100644 --- a/huakai-app/App.vue +++ b/huakai-app/App.vue @@ -1,73 +1,80 @@ diff --git a/huakai-app/manifest.json b/huakai-app/manifest.json index 78f1196..9160d58 100644 --- a/huakai-app/manifest.json +++ b/huakai-app/manifest.json @@ -1,132 +1,129 @@ { - "name" : "花开物业", - "appid" : "__UNI__29C3D60", - "description" : "物业用户端app", - "versionName" : "1.0.1", - "versionCode" : "103", - "transformPx" : false, - /* 5+App特有相关 */ - "app-plus" : { - "usingComponents" : true, - "nvueStyleCompiler" : "uni-app", - "compilerVersion" : 3, - "splashscreen" : { - "alwaysShowBeforeRender" : true, - "waiting" : true, - "autoclose" : true, - "delay" : 0 - }, - /* 模块配置 */ - "modules" : { - "Geolocation" : {}, - "Maps" : {}, - "Camera" : {}, - "Contacts" : {}, - "Gallery" : {}, - "Push" : {} - }, - /* 应用发布信息 */ - "distribute" : { - /* android打包配置 */ - "android" : { - "permissions" : [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - }, - /* ios打包配置 */ - "ios" : { - "dSYMs" : false, - "privacyDescription" : { - "NSPhotoLibraryUsageDescription" : "需要访问您的相册,用于选择图片上传", - "NSPhotoLibraryAddUsageDescription" : "保存二维码图片到相册" - } - }, - /* SDK配置 */ - "sdkConfigs" : { - "geolocation" : { - "system" : { - "__platform__" : [ "ios", "android" ] - } - }, - "maps" : { - "amap" : { - "name" : "玉米汁穿过三峡人家", - "appkey_ios" : "39a4c28a01c3ec15684b21d4093aad3d", - "appkey_android" : "044055aed47cb305e86419fd82e4c5f3" - } - }, - "push" : { - "unipush" : { - "version" : "2", - "offline" : true, - "icons" : { - "small" : { - "mdpi" : "D:/图片文档/logo-app.png" - } - } - } - }, - "share" : { - "weixin" : { - "appid" : "", - "UniversalLinks" : "" - } - } - } - } - }, - /* 快应用特有相关 */ - "quickapp" : {}, - /* 小程序特有相关 */ - "mp-weixin" : { - "appid" : "wx40625124315d2de1", - "setting" : { - "urlCheck" : false - }, - "requiredPrivateInfos" : [ "chooseLocation", "getLocation" ], - "permission" : { - "scope.camera" : { - "desc" : "用于扫码" - }, - "scope.userLocation" : { - "desc" : "你的位置信息将用于定位选择" - } - }, - "usingComponents" : true - }, - "mp-alipay" : { - "usingComponents" : true - }, - "mp-baidu" : { - "usingComponents" : true - }, - "mp-toutiao" : { - "usingComponents" : true - }, - "uniStatistics" : { - "enable" : false - }, - "vueVersion" : "3", - "app-harmony" : { - "distribute" : { - "bundleName" : "com.chengkong.property.owner" - } - } -} + "name": "花开物业", + "appid": "__UNI__29C3D60", + "description": "物业用户端app", + "versionName": "1.0.1", + "versionCode": "103", + "transformPx": false, + /* 5+App特有相关 */ + "app-plus": { + "usingComponents": true, + "nvueStyleCompiler": "uni-app", + "compilerVersion": 3, + "splashscreen": { + "alwaysShowBeforeRender": true, + "waiting": true, + "autoclose": true, + "delay": 0 + }, + /* 模块配置 */ + "modules": { + "Geolocation": {}, + "Maps": {}, + "Camera": {}, + "Contacts": {}, + "Gallery": {}, + "Push": {} + }, + /* 应用发布信息 */ + "distribute": { + /* android打包配置 */ + "android": { + "permissions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios": { + "dSYMs": false, + "privacyDescription": { + "NSPhotoLibraryUsageDescription": "需要访问您的相册,用于选择图片上传", + "NSPhotoLibraryAddUsageDescription": "保存二维码图片到相册" + } + }, + /* SDK配置 */ + "sdkConfigs": { + "geolocation": { + "system": { + "__platform__": ["ios", "android"] + } + }, + "maps": { + "amap": { + "name": "玉米汁穿过三峡人家", + "appkey_ios": "39a4c28a01c3ec15684b21d4093aad3d", + "appkey_android": "044055aed47cb305e86419fd82e4c5f3" + } + }, + "push": { + "unipush": { + "version": "2", + "offline": true, + "icons": { + "small": { + "mdpi": "D:/图片文档/logo-app.png" + } + } + } + }, + "share": { + "weixin": { + "appid": "", + "UniversalLinks": "" + } + } + } + } + }, + /* 快应用特有相关 */ + "quickapp": {}, + /* 小程序特有相关 */ + "mp-weixin": { + "appid": "wxa6184796ceba80ca", + "setting": { + "urlCheck": false + }, + "requiredPrivateInfos": ["chooseLocation", "getLocation"], + "permission": { + "scope.camera": { + "desc": "用于扫码" + } + }, + "usingComponents": true + }, + "mp-alipay": { + "usingComponents": true + }, + "mp-baidu": { + "usingComponents": true + }, + "mp-toutiao": { + "usingComponents": true + }, + "uniStatistics": { + "enable": false + }, + "vueVersion": "3", + "app-harmony": { + "distribute": { + "bundleName": "com.chengkong.property.owner" + } + } +} \ No newline at end of file diff --git a/huakai-app/package-lock.json b/huakai-app/package-lock.json index 1913237..bc6d311 100644 --- a/huakai-app/package-lock.json +++ b/huakai-app/package-lock.json @@ -1,5 +1,5 @@ { - "name": "property-uniapp-project", + "name": "huakai-app", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/huakai-app/pageSubPack/api/apiSub.js b/huakai-app/pageSubPack/api/apiSub.js index 382909a..0cd815f 100644 --- a/huakai-app/pageSubPack/api/apiSub.js +++ b/huakai-app/pageSubPack/api/apiSub.js @@ -92,14 +92,14 @@ export const upDateMyHouse = (data) => { // =========问卷调查========= // 问卷列表 export const getQuestionnaireList = (data) => { - return get('/api/resident/questionnaire/list',data) + return get('/api/resident/questionnaire/list', data) } // 问卷详情 export const getQuestionnaireDetail = (data) => { - return get('/api/resident/questionnaire/myAnswers',data) + return get('/api/resident/questionnaire/myAnswers', data) } // 提交问卷 -export const submitQuestionnair = (id,data) => { +export const submitQuestionnair = (id, data) => { return post(`/api/resident/questionnaire/${id}/submit`, data) } // =====投诉意见======= @@ -109,19 +109,19 @@ export const getComplainType = () => { } // 获取投诉列表 export const getComplainList = (data) => { - return get('/complain/getComplainList',data) + return get('/complain/getComplainList', data) } // 提交投诉建议 export const addComplain = (data) => { - return post('/complain/add',data) + return post('/complain/add', data) } // 投诉详情 export const getComplainDetail = (data) => { - return get('/complain/detail',data) + return get('/complain/detail', data) } // 联系物业 export const getManagePhoneData = (data) => { - return get('/api/manage/banner/getManagePhone',data) + return get('/api/manage/banner/getManagePhone', data) } // 修改身份证照片 @@ -223,3 +223,187 @@ export const getParkingDetail = (data) => { export const rebindCar = (data) => { return post(`/ResidentCarAreaManage/rebind`, data) } + + + +// RZbank +/** + * 归一化 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 +} + +// 获取日照银行小程序拉起参数 +export const getBankMiniProgramParams = (data) => { + return post('/api/pay/yidang/create', data) +} +/** + * 支付返回结果 + * 日照银行支付小程序完成支付后,通过 navigateBackMiniProgram 携带 extraData 返回, + * 本小程序在 App.onShow 中通过 referrerInfo.extraData 接收(场景值 1038)。 + * 这里只负责捕获/读取/清除原始返回数据,成功/失败判定见 resolvePaymentResult。 + */ +const PAYMENT_RESULT_KEY = 'payment_return_result' +/** + * 捕获支付返回结果(在 App.onShow 中调用) + * 注意:App 冷/热启动进入时 extraData 是支付参数(payAmount/billIds 等), + * 并非支付返回,需跳过,避免覆盖真实结果。 + */ +export function capturePaymentResult(onShowOptions) { + console.log(onShowOptions) + if (!onShowOptions) return + const extraData = onShowOptions?.referrerInfo?.extraData + if (!extraData) return + + // 含支付参数字段说明是 App 跳转进入(冷/热启动),不是支付返回,跳过 + if (typeof extraData === 'object' && (extraData.payAmount || extraData.billId || extraData.billIds || extraData + .acct || extraData.custId)) { + return + } + + let parsed = extraData + if (typeof extraData === 'string') { + try { + parsed = JSON.parse(extraData) + } catch (e) { + parsed = parseQueryString(extraData) + } + } + console.log('捕获到支付返回结果:', JSON.stringify(parsed)) + uni.setStorageSync(PAYMENT_RESULT_KEY, parsed) +} + +/** 读取支付返回结果(读取后建议调用 clearPaymentReturnResult 清除) */ +export function getPaymentReturnResult() { + try { + return uni.getStorageSync(PAYMENT_RESULT_KEY) || null + } catch (e) { + return null + } +} + +/** 清除支付返回结果 */ +export function clearPaymentReturnResult() { + uni.removeStorageSync(PAYMENT_RESULT_KEY) +} + +// 失败/成功信号值(大小写不敏感),字段名与取值以日照银行实际返回为准,如不一致只需调整下方映射 +const FAIL_SIGNALS = ['fail', 'failed', 'cancel', 'cancelled', 'error', 'closed', 'notpay', 'payerror', '2', 'false', + 'no', '01' +] +const SUCCESS_SIGNALS = ['success', 'ok', 'paid', 'finish', 'finished', '1', '0000', '0', '200', 'true', 'yes', '00'] +const RESULT_FIELDS = ['payResult', 'result', 'status', 'payStatus', 'tradeState', 'returnCode', 'code', 'errCode', + 'orderState' +] + +/** + * 判定日照银行返回的支付结果:'success' | 'fail' | null(无法判定) + */ +export function resolvePaymentResult(data) { + console.log("日照银行返回数据:", data) + if (!data || typeof data !== 'object') return null + // 布尔字段优先 + if (typeof data.success === 'boolean') return data.success ? 'success' : 'fail' + if (typeof data.isSuccess === 'boolean') return data.isSuccess ? 'success' : 'fail' + for (const key of RESULT_FIELDS) { + const v = data[key] + if (v === undefined || v === null || v === '') continue + const s = String(v).trim().toLowerCase() + if (FAIL_SIGNALS.includes(s)) return 'fail' + if (SUCCESS_SIGNALS.includes(s)) return 'success' + } + return null +} \ No newline at end of file diff --git a/huakai-app/pageSubPack/api/date.js b/huakai-app/pageSubPack/api/date.js new file mode 100644 index 0000000..d4d27e6 --- /dev/null +++ b/huakai-app/pageSubPack/api/date.js @@ -0,0 +1,42 @@ +/** + * 日期格式化 + * @param {Date|number|string} time 时间戳/日期字符串/Date对象 + * @param {string} fmt 格式 'yyyy-MM-dd HH:mm:ss' + * @returns {string} + */ +export function formatDate(time, fmt = 'yyyy-MM-dd HH:mm:ss') { + if (!time) return '' + let date + if (typeof time === 'number') { + // 小程序时间戳注意:毫秒直接用,秒要*1000 + date = new Date(time.toString().length === 10 ? time * 1000 : time) + } else { + date = new Date(time) + } + // 兼容ios:2025-08-01 → 2025/08/01 + if (isNaN(date.getTime())) { + date = new Date(String(time).replace(/-/g, '/')) + } + if (isNaN(date.getTime())) return '' + + const o = { + 'M+': date.getMonth() + 1, // 月 + 'd+': date.getDate(), // 日 + 'H+': date.getHours(), // 24小时制 + 'h+': date.getHours() % 12, //12小时 + 'm+': date.getMinutes(), // 分 + 's+': date.getSeconds(), // 秒 + 'q+': Math.floor((date.getMonth() + 3) / 3), //季度 + 'S': date.getMilliseconds() //毫秒 + } + if (/(y+)/.test(fmt)) { + fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) + } + for (const k in o) { + if (new RegExp(`(${k})`).test(fmt)) { + const str = o[k] + '' + fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : str.padStart(2, '0')) + } + } + return fmt +} \ No newline at end of file diff --git a/huakai-app/pageSubPack/api/request.js b/huakai-app/pageSubPack/api/request.js index 0d29659..a3c7cf5 100644 --- a/huakai-app/pageSubPack/api/request.js +++ b/huakai-app/pageSubPack/api/request.js @@ -1,18 +1,34 @@ let baseUrl = ''; if (process.env.NODE_ENV === 'development') { - // baseUrl = 'https://wuyeapi.ckdzkj.com'; // 开发环境 - baseUrl = "https://wuyeapi.bugtc.com" + baseUrl = 'https://wuyeapi.ckdzkj.com'; // 开发环境 + // baseUrl = "http://192.168.0.222:8080" + // baseUrl = 'https://wuyeapi.ckdzkj.com'; + // baseUrl = "https://apitest.ckdzkj.com" + // baseUrl = "https://wuyeapi.bugtc.com" + // baseUrl = 'https://during-immovable-eats.ngrok-free.dev'; } else { - baseUrl = 'https://wuyeapi.bugtc.com'; // 生产环境 + baseUrl = 'https://wuyeapi.ckdzkj.com'; + // baseUrl = 'https://apitest.ckdzkj.com'; + // baseUrl = 'https://during-immovable-eats.ngrok-free.dev'; } - +// 图片基础地址 +// const imgBaseUrl = 'https://wuyeadmin.bugtc.com' +const imgBaseUrl = 'https://wuye.ckdzkj.com' +export { + baseUrl, + imgBaseUrl +}; /** * 显示接口错误提示(自动处理长消息截断问题) * @param {string|Object} msg - 错误消息或含 msg 字段的错误对象 */ export function showApiError(msg) { const message = typeof msg === 'string' ? msg : (msg.msg || msg.message || '请求失败'); - uni.showToast({ title: message || '请求失败', icon: 'error', duration: 2000 }); + uni.showToast({ + title: message || '请求失败', + icon: 'error', + duration: 2000 + }); } export default function request(url, data = {}, method = "GET") { @@ -36,7 +52,10 @@ export default function request(url, data = {}, method = "GET") { // HTTP 失败 if (res.statusCode !== 200) { - reject({ msg: `请求异常 ${res.statusCode}`, code: res.statusCode }); + reject({ + msg: `请求异常 ${res.statusCode}`, + code: res.statusCode + }); return; } @@ -44,7 +63,11 @@ export default function request(url, data = {}, method = "GET") { // token 过期 — 清除登录态,提示用户,但不强制跳转(用户可继续浏览非敏感页面) if (resData.code === 401) { - uni.showToast({ title: '登录已过期,请重新登录', icon: 'none', duration: 2000 }); + uni.showToast({ + title: '登录已过期,请重新登录', + icon: 'none', + duration: 2000 + }); uni.removeStorageSync('token'); uni.removeStorageSync('userId'); // 使用 navigateTo 而非 reLaunch,用户可通过返回按钮退出登录页 @@ -53,11 +76,16 @@ export default function request(url, data = {}, method = "GET") { url: '/pageSubPack/loginSub/pwd-login', fail: () => { // 如果 navigateTo 失败(如页面栈满),则用 reLaunch - uni.reLaunch({ url: '/pageSubPack/loginSub/pwd-login' }); + uni.reLaunch({ + url: '/pageSubPack/loginSub/pwd-login' + }); } }); }, 1500); - reject({ msg: '登录过期', code: 401 }); + reject({ + msg: '登录过期', + code: 401 + }); return; } @@ -68,14 +96,26 @@ export default function request(url, data = {}, method = "GET") { // 业务失败(code === 500 统一 showToast 展示完整 msg) else { if (resData.code === 500 && resData.msg) { - uni.showToast({ title: resData.msg, icon: 'error', duration: 2500 }); + uni.showToast({ + title: resData.msg, + icon: 'error', + duration: 2500 + }); } - reject({ msg: resData.msg || '请求失败', code: resData.code, data: resData }); + reject({ + msg: resData.msg || '请求失败', + code: resData.code, + data: resData + }); } }, fail: (err) => { uni.hideLoading(); - reject({ msg: '网络异常', code: -1, raw: err }); + reject({ + msg: '网络异常', + code: -1, + raw: err + }); } }); }); @@ -99,15 +139,15 @@ export const upload = (filePath, url) => { }, success: (res) => { try { - const data = JSON.parse(res.data); - resolve(data.data || ''); // 直接返回图片地址 - } catch (e) { - resolve(''); - } + const data = JSON.parse(res.data); + resolve(data.data || ''); // 直接返回图片地址 + } catch (e) { + resolve(''); + } }, fail: (err) => { reject(err); } }); }); -}; +}; \ No newline at end of file diff --git a/huakai-app/pageSubPack/api/useImageUpload.js b/huakai-app/pageSubPack/api/useImageUpload.js index 497d1ff..4835aed 100644 --- a/huakai-app/pageSubPack/api/useImageUpload.js +++ b/huakai-app/pageSubPack/api/useImageUpload.js @@ -1,5 +1,9 @@ // 服务器地址(与 request.js 保持一致) -const baseUrl = 'http://192.168.0.239:8080'; +// const baseUrl = 'http://192.168.0.239:8080'; +// const baseUrl = 'http://192.168.1.222:8080'; +import { + baseUrl +} from './request.js'; /** * 图片上传 Hook @@ -7,7 +11,9 @@ const baseUrl = 'http://192.168.0.239:8080'; * 解决编辑回显后重新上传的问题 */ -import { reactive } from 'vue' +import { + reactive +} from 'vue' /** * @param {Object} options 配置 @@ -18,7 +24,7 @@ import { reactive } from 'vue' export function useImageUpload(options = {}) { const { uploadUrl = '/api/resident/file/uploadImage', - fileKey = 'file' + fileKey = 'file' } = options // 使用 reactive 对象存储所有状态 @@ -87,12 +93,16 @@ export function useImageUpload(options = {}) { const uploadImage = () => { // 如果没有新选择临时文件,直接返回已有的服务器URL if (!state.tempFilePath) { - return Promise.resolve({ url: state.serverUrl }) + return Promise.resolve({ + url: state.serverUrl + }) } // 如果已经有服务器URL且没有重新选择,也直接返回 if (state.serverUrl && !state.tempFilePath) { - return Promise.resolve({ url: state.serverUrl }) + return Promise.resolve({ + url: state.serverUrl + }) } state.uploading = true @@ -118,11 +128,14 @@ export function useImageUpload(options = {}) { const data = JSON.parse(res.data) if (data.code === 200 && data.data) { // 更新服务器URL(确保存的是字符串) - const url = typeof data.data === 'string' ? data.data : (data.data?.url || '') + const url = typeof data.data === 'string' ? data.data : (data.data + ?.url || '') state.serverUrl = url // 清空临时文件 state.tempFilePath = null - resolve({ url }) + resolve({ + url + }) } else { uni.showToast({ title: data.msg || '上传失败', @@ -164,7 +177,9 @@ export function useImageUpload(options = {}) { return await uploadImage() } // 否则返回已有的服务器URL - return { url: state.serverUrl } + return { + url: state.serverUrl + } } /** @@ -187,4 +202,4 @@ export function useImageUpload(options = {}) { getSubmitUrl, reset } -} +} \ No newline at end of file diff --git a/huakai-app/pageSubPack/loginSub/forget-pwd.vue b/huakai-app/pageSubPack/loginSub/forget-pwd.vue index 4d8dccf..4dc53d3 100644 --- a/huakai-app/pageSubPack/loginSub/forget-pwd.vue +++ b/huakai-app/pageSubPack/loginSub/forget-pwd.vue @@ -2,234 +2,235 @@ - - 忘记密码 + + 忘记密码 - - - - - + + + + - - - - - - - + + + + + + - - + diff --git a/huakai-app/pageSubPack/loginSub/login.vue b/huakai-app/pageSubPack/loginSub/login.vue index 9018a10..170e674 100644 --- a/huakai-app/pageSubPack/loginSub/login.vue +++ b/huakai-app/pageSubPack/loginSub/login.vue @@ -1,91 +1,87 @@ diff --git a/huakai-app/pageSubPack/loginSub/pwd-login.vue b/huakai-app/pageSubPack/loginSub/pwd-login.vue index 4ecc162..88f1185 100644 --- a/huakai-app/pageSubPack/loginSub/pwd-login.vue +++ b/huakai-app/pageSubPack/loginSub/pwd-login.vue @@ -1,320 +1,310 @@ diff --git a/huakai-app/pageSubPack/loginSub/register-new-user.vue b/huakai-app/pageSubPack/loginSub/register-new-user.vue index 5e4f56e..ecc0dc9 100644 --- a/huakai-app/pageSubPack/loginSub/register-new-user.vue +++ b/huakai-app/pageSubPack/loginSub/register-new-user.vue @@ -13,24 +13,34 @@ - + - - + - - + - - + +