- 修改数据库配置将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界面适配新的打卡和计划功能 - 调整计划提交时间规则为周五至周四周期 - 添加月度和年度计划提交状态验证机制
125 lines
3.6 KiB
JavaScript
125 lines
3.6 KiB
JavaScript
// 根据小程序版本自动选择后端地址
|
||
function _getBaseUrls() {
|
||
let envType = 'release';
|
||
try {
|
||
const accountInfo = wx.getAccountInfoSync();
|
||
envType = accountInfo.miniProgram.envVersion || 'release';
|
||
} catch (e) {
|
||
// 低版本基础库不支持时默认线上环境
|
||
envType = 'release';
|
||
}
|
||
switch (envType) {
|
||
case 'develop':
|
||
// 开发版:本地服务
|
||
return {
|
||
baseUrl: 'https://test.muguaclub.cn/clock',
|
||
staticUrl: 'https://test.muguaclub.cn',
|
||
h5Url: 'https://test.muguaclub.cn'
|
||
};
|
||
case 'trial':
|
||
// 体验版:测试环境
|
||
return {
|
||
baseUrl: 'https://test.muguaclub.cn/clock',
|
||
staticUrl: 'https://test.muguaclub.cn',
|
||
h5Url: 'https://test.muguaclub.cn'
|
||
};
|
||
case 'release':
|
||
default:
|
||
// 线上版:正式环境
|
||
return {
|
||
baseUrl: 'https://m.muguaclub.cn/clock',
|
||
staticUrl: 'https://m.muguaclub.cn',
|
||
h5Url: 'https://m.muguaclub.cn'
|
||
};
|
||
}
|
||
}
|
||
|
||
const _urls = _getBaseUrls();
|
||
const BASE_URL = _urls.baseUrl;
|
||
const STATIC_BASE_URL = _urls.staticUrl;
|
||
const H5_BASE_URL = _urls.h5Url;
|
||
|
||
let redirectingProfile = false;
|
||
|
||
function goProfile() {
|
||
if (redirectingProfile) {
|
||
return;
|
||
}
|
||
const pages = getCurrentPages();
|
||
const current = pages.length ? pages[pages.length - 1] : null;
|
||
const route = current && current.route;
|
||
if (route === 'pages/profile/profile') {
|
||
return;
|
||
}
|
||
redirectingProfile = true;
|
||
wx.switchTab({
|
||
url: '/pages/profile/profile',
|
||
complete() {
|
||
setTimeout(() => {
|
||
redirectingProfile = false;
|
||
}, 1200);
|
||
}
|
||
});
|
||
}
|
||
|
||
function request(options) {
|
||
const { url, method = 'GET', data = {}, auth = true } = options;
|
||
const isIdempotent = method === 'GET' || method === 'DELETE';
|
||
let retried = false;
|
||
|
||
return new Promise((resolve, reject) => {
|
||
const doRequest = () => {
|
||
const header = { 'Content-Type': 'application/json' };
|
||
const token = wx.getStorageSync('token');
|
||
if (auth && token) {
|
||
header['Authorization'] = 'Bearer ' + token;
|
||
}
|
||
wx.request({
|
||
url: BASE_URL + url,
|
||
method,
|
||
data,
|
||
header,
|
||
success(res) {
|
||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||
resolve(res.data);
|
||
} else if (res.statusCode === 401) {
|
||
wx.removeStorageSync('token');
|
||
if (auth) {
|
||
goProfile();
|
||
}
|
||
reject(res.data || { error: '未登录' });
|
||
} else {
|
||
reject(res.data || { error: '请求失败' });
|
||
}
|
||
},
|
||
fail(err) {
|
||
// 冷启动时首个请求可能因网络栈未就绪而失败,空闲时对幂等请求自动重试一次
|
||
const msg = (err && err.errMsg) || '';
|
||
const domainError = /url not in domain list|domain not/i.test(msg);
|
||
if (!retried && isIdempotent && !domainError) {
|
||
retried = true;
|
||
setTimeout(doRequest, 800);
|
||
return;
|
||
}
|
||
reject(err);
|
||
}
|
||
});
|
||
};
|
||
doRequest();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 把计划附件的相对路径转为完整的静态资源 URL。
|
||
* 路径格式:attachments/{user_id}/{plan_type}/{period_key}/{filename}
|
||
*/
|
||
function planFileUrl(path) {
|
||
if (!path) return '';
|
||
if (/^https?:\/\//i.test(path)) return path;
|
||
const parts = String(path).replace(/^attachments\//, '').split('/');
|
||
if (parts.length < 4) return '';
|
||
return STATIC_BASE_URL + '/clock/static/plan/' + parts.slice(0, 4).map(encodeURIComponent).join('/');
|
||
}
|
||
|
||
module.exports = { request, planFileUrl, BASE_URL, STATIC_BASE_URL, H5_BASE_URL };
|