diff --git a/admin/client/src/router/index.js b/admin/client/src/router/index.js index 51d12d1..25009e3 100644 --- a/admin/client/src/router/index.js +++ b/admin/client/src/router/index.js @@ -119,16 +119,46 @@ export const asyncRoutes = [ meta: { title: '教学中心', icon: 'user' } }, { - path: 'coupons', - name: 'Coupons', - component: () => import('@/views/crm/coupon'), - meta: { title: '优惠券管理', icon: 'money' } + path: 'users', + name: 'CrmUsers', + component: () => import('@/views/crm/index'), + redirect: '/crm/users/students', + meta: { title: '用户管理', icon: 'peoples' }, + children: [ + { + path: 'students', + name: 'Students', + component: () => import('@/views/crm/student'), + meta: { title: '学员管理', icon: 'peoples' } + }, + { + path: 'honors', + name: 'Honors', + component: () => import('@/views/crm/honor'), + meta: { title: '学员荣誉管理', icon: 'medal' } + } + ] }, { - path: 'issued-coupons', - name: 'IssuedCoupons', - component: () => import('@/views/crm/issued_coupon'), - meta: { title: '已发优惠券', icon: 'list' } + path: 'coupon-manage', + name: 'CouponManage', + component: () => import('@/views/crm/index'), + redirect: '/crm/coupon-manage/settings', + meta: { title: '优惠券管理', icon: 'money' }, + children: [ + { + path: 'settings', + name: 'Coupons', + component: () => import('@/views/crm/coupon'), + meta: { title: '优惠券设置', icon: 'money' } + }, + { + path: 'issued', + name: 'IssuedCoupons', + component: () => import('@/views/crm/issued_coupon'), + meta: { title: '已发优惠券', icon: 'list' } + } + ] }, { path: 'banners', @@ -136,18 +166,6 @@ export const asyncRoutes = [ component: () => import('@/views/crm/banner'), meta: { title: '轮播图管理', icon: 'drag' } }, - { - path: 'students', - name: 'Students', - component: () => import('@/views/crm/student'), - meta: { title: '学员管理', icon: 'peoples' } - }, - { - path: 'honors', - name: 'Honors', - component: () => import('@/views/crm/honor'), - meta: { title: '学员荣誉管理', icon: 'medal' } - }, { path: 'showcases', name: 'Showcases', diff --git a/admin/server/media/2025/12/12/fQi6MP0c77zs92230c8a3602901b00dc40ae2fbdae26.jpeg b/admin/server/media/2025/12/12/fQi6MP0c77zs92230c8a3602901b00dc40ae2fbdae26.jpeg new file mode 100644 index 0000000..f51743a Binary files /dev/null and b/admin/server/media/2025/12/12/fQi6MP0c77zs92230c8a3602901b00dc40ae2fbdae26.jpeg differ diff --git a/wechat-mini-program/pages/coupon/coupon.js b/wechat-mini-program/pages/coupon/coupon.js index 3ccf00e..67a5951 100644 --- a/wechat-mini-program/pages/coupon/coupon.js +++ b/wechat-mini-program/pages/coupon/coupon.js @@ -3,12 +3,20 @@ const app = getApp() Page({ data: { coupons: [], - user: {} + user: {}, + loading: true }, onLoad() { this.fetchCoupons(); }, onShow() { + // Optimistically update from global data + if (app.globalData.userInfo && app.globalData.userInfo.phone) { + this.setData({ + user: app.globalData.userInfo, + loading: false + }); + } this.getUserInfo(); this.fetchCoupons(); }, @@ -19,12 +27,14 @@ Page({ // Fetch latest user info from backend to check if phone exists in DB request({ url: '/user/' }).then(user => { app.globalData.userInfo = user; // Sync global data - this.setData({ user: user }); + this.setData({ user: user, loading: false }); }).catch(err => { console.error('Failed to fetch user info', err) // Fallback to global data if fetch fails if (app.globalData.userInfo) { - this.setData({ user: app.globalData.userInfo }); + this.setData({ user: app.globalData.userInfo, loading: false }); + } else { + this.setData({ loading: false }); } }) }, diff --git a/wechat-mini-program/pages/coupon/coupon.wxml b/wechat-mini-program/pages/coupon/coupon.wxml index 8cc15a0..7812a26 100644 --- a/wechat-mini-program/pages/coupon/coupon.wxml +++ b/wechat-mini-program/pages/coupon/coupon.wxml @@ -4,7 +4,7 @@ - + VIP会员权益 开通会员享受更多优惠 diff --git a/wechat-mini-program/pages/login/login.js b/wechat-mini-program/pages/login/login.js index c8e9d52..b5ee00b 100644 --- a/wechat-mini-program/pages/login/login.js +++ b/wechat-mini-program/pages/login/login.js @@ -3,7 +3,6 @@ const { request } = require('../../utils/request') Page({ data: { - hasUserInfo: false, hasPhone: false }, onLoad() { @@ -24,16 +23,14 @@ Page({ // If we are here, user probably needs to authorize. // Update UI state - const hasNick = user.wechat_nickname && user.wechat_nickname !== '微信用户'; const hasPhone = !!user.phone; this.setData({ - hasUserInfo: hasNick, hasPhone: hasPhone }) // If somehow we ended up here but profile is full, go home - if (hasNick && hasPhone) { + if (hasPhone) { wx.switchTab({ url: '/pages/index/index' }) } } else { @@ -46,46 +43,6 @@ Page({ } } }, - getUserProfile(e) { - wx.getUserProfile({ - desc: '用于完善会员资料', - success: (res) => { - const { userInfo } = res - console.log('getUserProfile success', userInfo) - - // Update backend - // We need user ID from globalData - if (app.globalData.userInfo && app.globalData.userInfo.id) { - this.updateUserInfo(userInfo) - } else { - // Should not happen if app.js login succeeded - wx.showToast({ title: '登录状态异常,请重启', icon: 'none' }) - } - }, - fail: (err) => { - console.error('getUserProfile failed', err) - wx.showToast({ title: '需要授权才能继续', icon: 'none' }) - } - }) - }, - updateUserInfo(wxUserInfo) { - request({ - url: `/students/${app.globalData.userInfo.id}/`, - method: 'PATCH', - data: { - wechat_nickname: wxUserInfo.nickName, - avatar: wxUserInfo.avatarUrl - // name: wxUserInfo.nickName // Optional: sync name too - } - }).then(res => { - console.log('Update user info success', res) - app.globalData.userInfo = { ...app.globalData.userInfo, ...res } - this.setData({ hasUserInfo: true }) - }).catch(err => { - console.error('Update user info failed', err) - wx.showToast({ title: '更新资料失败', icon: 'none' }) - }) - }, getPhoneNumber(e) { console.log('getPhoneNumber', e) if (e.detail.errMsg === 'getPhoneNumber:ok') { @@ -98,34 +55,16 @@ Page({ }).then(res => { console.log('Get phone success', res) if (res.phone) { - this.setData({ hasPhone: true }) - if (app.globalData.userInfo) { - app.globalData.userInfo.phone = res.phone - } - - wx.showToast({ - title: '登录成功', - icon: 'success' - }) - - // Redirect to home - setTimeout(() => { - wx.switchTab({ url: '/pages/index/index' }) - }, 1500) + app.globalData.userInfo = { ...app.globalData.userInfo, ...res } + this.setData({ hasPhone: true }) + wx.switchTab({ url: '/pages/index/index' }) } }).catch(err => { console.error('Get phone failed', err) wx.showToast({ title: '获取手机号失败', icon: 'none' }) }) } else { - console.log('User denied phone number') - // If user denies, we can optionally let them in anyway if that's the requirement? - // User said: "If openID exists, direct login". - // This implies for NEW users, they MIGHT need to authorize phone. - // But strictly speaking, once they authorized UserProfile (Avatar/Nick), - // the OpenID exists. - // But the "User Phone" part is usually critical. - // Let's keep strict requirement for phone for NEW users for now unless asked otherwise. + wx.showToast({ title: '需要授权手机号才能继续', icon: 'none' }) } } }) diff --git a/wechat-mini-program/pages/login/login.wxml b/wechat-mini-program/pages/login/login.wxml index a21c715..be02c77 100644 --- a/wechat-mini-program/pages/login/login.wxml +++ b/wechat-mini-program/pages/login/login.wxml @@ -8,11 +8,7 @@ 为了提供更好的服务,请授权以下信息 - - - - - + diff --git a/wechat-mini-program/pages/profile/profile.wxml b/wechat-mini-program/pages/profile/profile.wxml index 263e044..18fcd2e 100644 --- a/wechat-mini-program/pages/profile/profile.wxml +++ b/wechat-mini-program/pages/profile/profile.wxml @@ -43,7 +43,7 @@ - 个人信息 + 我的信息 {{isFormOpen ? '▲' : '▼'}}