Files
wechat-clock-mini/pages/profile/profile.js
王宏豪 cd04c1b5ef feat(database): 迁移用户关联字段并优化打卡系统
- 修改数据库配置将MYSQL_DB从mys_info_v3改为mys_info_test
- 新增auth_users表wechat_openid字段并建立唯一索引
- 为plan_checkins表添加计划性能索引(idx_plan_period_student)
- 将checkin_records_old表关联方式从student_id改为user_id
- 将plan_checkins表关联方式从student_id改为user_id并更新附件路径
- 移除routes/auth.py中的uuid导入使用安全token生成函数
- 重构routes/checkin.py打卡逻辑去除course_type字段并优化返回结构
- 添加打卡时间限制验证功能防止过期打卡操作
- 实现小组统计功能支持老师查看各组打卡情况
- 更新主页index.html界面适配新的打卡和计划功能
- 调整计划提交时间规则为周五至周四周期
- 添加月度和年度计划提交状态验证机制
2026-09-10 14:11:58 +08:00

266 lines
6.8 KiB
JavaScript

const api = require('../../utils/api');
const auth = require('../../utils/auth');
const ROLE_LABELS = {
student: '成员',
member: '成员',
teacher: '管理员',
leader: '组长',
'group_leader': '组长',
admin: '管理员'
};
const LOGIN_TYPE_LABELS = {
wechat: '微信授权',
phone: '手机号',
admin: '管理员'
};
Page({
data: {
view: 'loading',
profile: null,
phoneLoading: false,
phoneError: '',
loadError: '',
avatarSrc: '',
avatarFallback: '明',
roleLabel: '',
loginTypeLabel: '',
classGroups: [],
avatarUploading: false,
privacyAgreed: false
},
onShow() {
this.setData({
phoneError: '',
privacyAgreed: !!wx.getStorageSync('privacy_agreed')
});
this.loadPage();
},
onPullDownRefresh() {
this.refresh().finally(() => wx.stopPullDownRefresh());
},
refresh() {
if (this.data.view !== 'profile') {
return this.loadPage();
}
return new Promise((resolve) => {
api.request({ url: '/api/v1/profile' })
.then((res) => {
this.applyProfile(res);
resolve();
})
.catch(() => {
wx.showToast({ title: '刷新失败', icon: 'none' });
resolve();
});
});
},
loadPage() {
this.setData({ loadError: '' });
return auth.ensureLogin()
.then((token) => {
if (!token) {
this.showPhoneLogin();
return null;
}
this.setData({ view: 'loading' });
return this.loadProfile();
})
.catch(() => {
this.showPhoneLogin();
});
},
loadProfile() {
return api.request({ url: '/api/v1/profile' })
.then((res) => {
this.applyProfile(res);
})
.catch((err) => {
if (!auth.getToken()) {
this.showPhoneLogin();
} else {
this.setData({
view: 'loadError',
loadError: (err && err.error) || '加载失败'
});
}
});
},
applyProfile(res) {
const displayName = res.display_name || res.name || '';
const classGroups = (res.class_groups || []).map((g) => ({
class_id: g.class_id,
class_code: g.class_code,
period: g.period,
group: g.group,
role: this.roleLabel(g.role)
}));
this.setData({
view: 'profile',
profile: res,
phoneError: '',
loadError: '',
avatarSrc: this.fullUrl(res.wechat_avatar),
avatarFallback: this.firstChar(displayName),
roleLabel: this.roleLabel(res.role),
loginTypeLabel: this.loginTypeLabel(res.login_type),
classGroups
});
},
showPhoneLogin() {
this.setData({
view: 'phoneLogin',
phoneLoading: false,
privacyAgreed: !!wx.getStorageSync('privacy_agreed')
});
},
roleLabel(role) {
return ROLE_LABELS[role] || role || '成员';
},
loginTypeLabel(type) {
return LOGIN_TYPE_LABELS[type] || type || '手机号';
},
fullUrl(rel) {
if (!rel) return '';
return /^https?:\/\//i.test(rel) ? rel : api.STATIC_BASE_URL + rel;
},
firstChar(str) {
const t = (str && typeof str === 'string') ? str.trim() : '';
return t ? t.charAt(0) : '明';
},
onChooseAvatar(e) {
const path = e.detail && e.detail.avatarUrl;
if (!path) {
wx.showToast({ title: '未选择头像', icon: 'none' });
return;
}
this.setData({ avatarUploading: true });
wx.uploadFile({
url: api.BASE_URL + '/api/v1/profile/avatar',
filePath: path,
name: 'file',
header: { Authorization: 'Bearer ' + auth.getToken() },
success: (res) => {
let data = {};
try {
data = JSON.parse(res.data);
} catch (e) {
data = {};
}
if (data.success && data.wechat_avatar) {
const newAvatar = data.wechat_avatar;
const newUrl = this.fullUrl(newAvatar);
this.setData({
'profile.wechat_avatar': newAvatar,
avatarSrc: newUrl
});
wx.showToast({ title: '头像已更新', icon: 'success' });
} else {
wx.showToast({ title: data.error || '上传失败', icon: 'none' });
}
},
fail: (err) => {
wx.showToast({ title: '上传失败', icon: 'none' });
},
complete: () => {
this.setData({ avatarUploading: false });
}
});
},
onGetPhoneNumber(e) {
if (this.data.phoneLoading) {
return;
}
if (!this.data.privacyAgreed) {
wx.showToast({ title: '请先阅读并同意用户协议和隐私政策', icon: 'none', duration: 2000 });
return;
}
const phoneCode = e.detail && e.detail.code;
if (!phoneCode) {
const message = '未授权手机号,请点击上方按钮重试';
this.setData({ phoneError: message });
wx.showToast({ title: message, icon: 'none' });
return;
}
this.setData({ phoneLoading: true, phoneError: '' });
auth.loginWithPhone(phoneCode)
.then(() => this.loadProfile())
.catch((err) => {
const message = (err && err.error) || '手机号登录失败';
this.setData({ phoneLoading: false, phoneError: message });
wx.showToast({ title: message, icon: 'none', duration: 2500 });
});
},
onRetry() {
this.loadPage();
},
togglePrivacy() {
const agreed = !this.data.privacyAgreed;
this.setData({ privacyAgreed: agreed });
if (agreed) {
wx.setStorageSync('privacy_agreed', true);
} else {
wx.removeStorageSync('privacy_agreed');
}
},
openPrivacy(e) {
const type = e.currentTarget.dataset.type || 'privacy';
wx.navigateTo({ url: '/pages/privacy/privacy?type=' + type });
},
logoutAccount() {
wx.showModal({
title: '退出登录',
content: '确定要退出登录吗?退出后将清除本机登录信息,需要重新登录。',
confirmText: '退出',
confirmColor: '#c0392b',
success: (res) => {
if (!res.confirm) return;
try {
api.request({ url: '/api/v1/auth/logout', method: 'POST' }).catch(() => {});
} catch (e) {}
auth.clearToken();
wx.removeStorageSync('privacy_agreed');
wx.showToast({ title: '已退出', icon: 'success' });
setTimeout(() => {
wx.reLaunch({ url: '/pages/home/home' });
}, 1000);
}
});
},
// ---- 分享 ----
onShareAppMessage() {
const name = (this.data.profile && (this.data.profile.display_name || this.data.profile.name)) || '';
const title = name
? name + ' 推荐你用明缘云道场,打卡学习超好用'
: '推荐你用明缘云道场,打卡学习超好用';
return {
title,
path: '/pages/home/home?from=profile_share'
};
},
onShareTimeline() {
return {
title: '明缘云道场 · 学习成长,每日精进',
query: 'from=timeline'
};
}
});