diff --git a/app.js b/app.js index 0ffe35d..2b9b6ac 100644 --- a/app.js +++ b/app.js @@ -34,12 +34,19 @@ App({ fail: (err) => { console.error('静默登录失败', err) this.globalData.isLoggedIn = false + this.globalData.loginFailed = true + + // 通知页面登录失败 + if (this.loginReadyCallback) { + this.loginReadyCallback(null) + } } }) }, globalData: { userInfo: null, - isLoggedIn: false + isLoggedIn: false, + loginFailed: false } }) diff --git a/pages/index/index.js b/pages/index/index.js index 5dae5dc..fefdc04 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -1,19 +1,26 @@ // index.js -const { appointmentDB } = require('../../utils/cloud') +const { appointmentDB, formatRecord } = require('../../utils/cloud') const app = getApp() Page({ data: { isLoggedIn: false, + loginFailed: false, latestRecord: null }, onLoad() { if (app.globalData.isLoggedIn) { this.onLoginReady() + } else if (app.globalData.loginFailed) { + this.onLoginFailed() } else { - app.loginReadyCallback = () => { - this.onLoginReady() + app.loginReadyCallback = (userInfo) => { + if (userInfo) { + this.onLoginReady() + } else { + this.onLoginFailed() + } } } }, @@ -25,20 +32,32 @@ Page({ }, onLoginReady() { - this.setData({ isLoggedIn: true }) + this.setData({ isLoggedIn: true, loginFailed: false }) this.loadLatestRecord() }, - async loadLatestRecord() { - if (!this.data.isLoggedIn) { - this.setData({ latestRecord: null }) - return + onLoginFailed() { + this.setData({ isLoggedIn: false, loginFailed: true }) + }, + + onRetry() { + this.setData({ loginFailed: false }) + app.silentLogin() + app.loginReadyCallback = (userInfo) => { + if (userInfo) { + this.onLoginReady() + } else { + this.onLoginFailed() + } } + }, + + async loadLatestRecord() { try { const openid = app.globalData.userInfo.openid const record = await appointmentDB.getLatest(openid) if (record) { - this.setData({ latestRecord: this.formatRecord(record) }) + this.setData({ latestRecord: formatRecord(record) }) } else { this.setData({ latestRecord: null }) } @@ -48,19 +67,6 @@ Page({ } }, - formatRecord(record) { - const date = record.createTime - let createTimeStr = '' - if (date) { - if (typeof date === 'object' && date.$date) { - createTimeStr = new Date(date.$date).toLocaleString('zh-CN') - } else { - createTimeStr = new Date(date).toLocaleString('zh-CN') - } - } - return { ...record, createTime: createTimeStr } - }, - goAppointment() { wx.navigateTo({ url: '/pages/appointment/appointment' diff --git a/pages/index/index.wxml b/pages/index/index.wxml index e5dd5d7..cbdb92e 100644 --- a/pages/index/index.wxml +++ b/pages/index/index.wxml @@ -1,11 +1,18 @@ - + 正在获取身份信息... + + + ⚠️ + 网络异常,请重试 + 重新加载 + + 🏢 访客预约系统 diff --git a/pages/index/index.wxss b/pages/index/index.wxss index d78fba4..ae325c5 100644 --- a/pages/index/index.wxss +++ b/pages/index/index.wxss @@ -56,6 +56,30 @@ page { color: #999; } +/* 登录失败 */ +.fail-icon { + font-size: 80rpx; + margin-bottom: 20rpx; +} + +.fail-text { + font-size: 28rpx; + color: #999; + margin-bottom: 32rpx; +} + +.retry-btn { + font-size: 28rpx; + color: #fff; + background: #1890ff; + padding: 16rpx 56rpx; + border-radius: 36rpx; +} + +.retry-btn:active { + background: #096dd9; +} + .header-title { font-size: 44rpx; font-weight: 700; @@ -80,11 +104,12 @@ page { border-radius: 20rpx; padding: 36rpx 32rpx; margin-bottom: 24rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06); + box-shadow: 0 8rpx 32rpx rgba(24, 144, 255, 0.12), 0 2rpx 8rpx rgba(0, 0, 0, 0.06); } .action-card:active { background: #f0f0f0; + box-shadow: 0 4rpx 16rpx rgba(24, 144, 255, 0.08), 0 1rpx 4rpx rgba(0, 0, 0, 0.04); } .action-icon-wrap { @@ -140,7 +165,7 @@ page { border-radius: 20rpx; padding: 28rpx 32rpx; margin-top: 8rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06); + box-shadow: 0 8rpx 32rpx rgba(82, 196, 26, 0.12), 0 2rpx 8rpx rgba(0, 0, 0, 0.06); } .latest-header { diff --git a/pages/records/records.js b/pages/records/records.js index c586669..e4bfe7a 100644 --- a/pages/records/records.js +++ b/pages/records/records.js @@ -1,5 +1,5 @@ // records.js -const { appointmentDB } = require('../../utils/cloud') +const { appointmentDB, formatRecord } = require('../../utils/cloud') const app = getApp() Page({ @@ -11,18 +11,12 @@ Page({ }, onLoad() { - if (!app.globalData.isLoggedIn) { - wx.showToast({ title: '请先登录', icon: 'none' }) - setTimeout(() => { - wx.navigateBack() - }, 1500) - return - } this.loadRecords() }, onShow() { - if (app.globalData.isLoggedIn) { + // 仅从预约页返回时刷新,避免 onLoad + onShow 双重加载 + if (this.data._loaded) { this.loadRecords() } }, @@ -32,26 +26,12 @@ Page({ try { const openid = app.globalData.userInfo.openid const records = await appointmentDB.getList(openid) - - // 格式化时间 - const formatted = records.map(item => { - const date = item.createTime - let createTimeStr = '' - if (date) { - if (typeof date === 'object' && date.$date) { - createTimeStr = new Date(date.$date).toLocaleString('zh-CN') - } else { - createTimeStr = new Date(date).toLocaleString('zh-CN') - } - } - return { ...item, createTime: createTimeStr } - }) - - this.setData({ records: formatted, loading: false }) + const formatted = records.map(item => formatRecord(item)) + this.setData({ records: formatted, loading: false, _loaded: true }) this.filterRecords() } catch (err) { console.error('加载预约记录失败', err) - this.setData({ records: [], loading: false }) + this.setData({ records: [], loading: false, _loaded: true }) this.filterRecords() } }, diff --git a/pages/records/records.wxml b/pages/records/records.wxml index 6cc673b..aa4f52f 100644 --- a/pages/records/records.wxml +++ b/pages/records/records.wxml @@ -14,13 +14,16 @@ 已拒绝 + + 已取消 + - {{item.id}} + {{item._id}} {{item.statusText}} diff --git a/utils/cloud.js b/utils/cloud.js index b385c3e..c9ca208 100644 --- a/utils/cloud.js +++ b/utils/cloud.js @@ -1,7 +1,33 @@ // 云数据库操作工具库 -const db = wx.cloud.database() -const _ = db.command +/** + * 延迟获取 db 实例,确保 cloud.init 已完成 + */ +function getDb() { + return wx.cloud.database() +} + +function getCmd() { + return getDb().command +} + +/** + * 格式化云数据库时间字段 + * @param {object} record - 含 createTime 的记录 + * @returns {object} 格式化后的记录 + */ +function formatRecord(record) { + const date = record.createTime + let createTimeStr = '' + if (date) { + if (typeof date === 'object' && date.$date) { + createTimeStr = new Date(date.$date).toLocaleString('zh-CN') + } else { + createTimeStr = new Date(date).toLocaleString('zh-CN') + } + } + return { ...record, createTime: createTimeStr } +} /** * 用户相关操作 @@ -10,50 +36,32 @@ const userDB = { /** * 通过 openId 查找用户,不存在则创建 * @param {string} openid - * @param {object} userInfo - { avatarUrl, nickName } * @returns {Promise} 用户记录 */ - async loginOrCreate(openid, userInfo) { + async loginOrCreate(openid) { + const db = getDb() const res = await db.collection('users').where({ _openid: openid }).get() if (res.data.length > 0) { - // 已存在,更新头像昵称 const existing = res.data[0] await db.collection('users').doc(existing._id).update({ data: { - avatarUrl: userInfo.avatarUrl, - nickName: userInfo.nickName, lastLoginTime: db.serverDate() } }) - return { ...existing, avatarUrl: userInfo.avatarUrl, nickName: userInfo.nickName } + return existing } else { - // 不存在,新建 const addRes = await db.collection('users').add({ data: { _openid: openid, - avatarUrl: userInfo.avatarUrl, - nickName: userInfo.nickName, createTime: db.serverDate(), lastLoginTime: db.serverDate() } }) return { _id: addRes._id, - _openid: openid, - avatarUrl: userInfo.avatarUrl, - nickName: userInfo.nickName + _openid: openid } } - }, - - /** - * 根据 openId 获取用户信息 - * @param {string} openid - * @returns {Promise} - */ - async getByOpenId(openid) { - const res = await db.collection('users').where({ _openid: openid }).get() - return res.data.length > 0 ? res.data[0] : null } } @@ -67,6 +75,7 @@ const appointmentDB = { * @returns {Promise} 新记录 _id */ async create(data) { + const db = getDb() const res = await db.collection('appointments').add({ data: { ...data, @@ -79,16 +88,29 @@ const appointmentDB = { }, /** - * 获取当前用户的预约列表(按创建时间倒序) + * 获取当前用户的预约列表(按创建时间倒序,自动分页取全部) * @param {string} openid * @returns {Promise} */ async getList(openid) { - const res = await db.collection('appointments') - .where({ _openid: openid }) - .orderBy('createTime', 'desc') - .get() - return res.data + const db = getDb() + const MAX_LIMIT = 100 + let allData = [] + let countResult = await db.collection('appointments').where({ _openid: openid }).count() + const total = countResult.total + const batchTimes = Math.ceil(total / MAX_LIMIT) + + for (let i = 0; i < batchTimes; i++) { + const res = await db.collection('appointments') + .where({ _openid: openid }) + .orderBy('createTime', 'desc') + .skip(i * MAX_LIMIT) + .limit(MAX_LIMIT) + .get() + allData = allData.concat(res.data) + } + + return allData }, /** @@ -97,6 +119,7 @@ const appointmentDB = { * @returns {Promise} */ async getLatest(openid) { + const db = getDb() const res = await db.collection('appointments') .where({ _openid: openid }) .orderBy('createTime', 'desc') @@ -112,7 +135,7 @@ const appointmentDB = { * @returns {Promise} 是否成功 */ async cancel(id, openid) { - // 先校验该预约属于当前用户 + const db = getDb() const res = await db.collection('appointments').doc(id).get() if (res.data._openid !== openid) { return false @@ -131,8 +154,9 @@ const appointmentDB = { } module.exports = { - db, - _, + getDb, + getCmd, + formatRecord, userDB, appointmentDB }