212 lines
5.9 KiB
JavaScript
212 lines
5.9 KiB
JavaScript
const api = require('../../utils/api');
|
|
const auth = require('../../utils/auth');
|
|
|
|
const STATUSES = ['正常', '迟到', '请假', '不参加讨论', '早退'];
|
|
const WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
|
const STATUS_META = {
|
|
正常: '#2E7D32',
|
|
迟到: '#C67B30',
|
|
请假: '#3A7BD5',
|
|
早退: '#8B7A6A',
|
|
'不参加讨论': '#C0392B'
|
|
};
|
|
const STATUS_ITEMS = STATUSES.map((label) => ({
|
|
label,
|
|
color: STATUS_META[label] || '#C67B30'
|
|
}));
|
|
|
|
function errMessage(err) {
|
|
if (err && typeof err === 'object') {
|
|
if (err.detail) return String(err.detail);
|
|
if (err.error) return String(err.error);
|
|
if (err.message) return err.message;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function pad2(n) {
|
|
return n < 10 ? '0' + n : String(n);
|
|
}
|
|
|
|
function fmtTime(ts) {
|
|
if (!ts) return '';
|
|
const d = new Date(String(ts).replace(' ', 'T'));
|
|
if (isNaN(d.getTime())) return String(ts);
|
|
const now = new Date();
|
|
const startOfDay = (x) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();
|
|
const diff = Math.round((startOfDay(now) - startOfDay(d)) / 86400000);
|
|
const hm = pad2(d.getHours()) + ':' + pad2(d.getMinutes());
|
|
if (diff === 0) return '今天 ' + hm;
|
|
if (diff === 1) return '昨天 ' + hm;
|
|
return pad2(d.getMonth() + 1) + '-' + pad2(d.getDate()) + ' ' + hm;
|
|
}
|
|
|
|
Page({
|
|
data: {
|
|
statuses: STATUSES,
|
|
statusItems: STATUS_ITEMS,
|
|
statusIndex: -1,
|
|
loading: true,
|
|
classDate: '',
|
|
weekday: '',
|
|
dayNum: '',
|
|
checked: false,
|
|
record: null,
|
|
statusColor: '',
|
|
statusBg: '',
|
|
history: [],
|
|
group: [],
|
|
groupName: '',
|
|
checkedCount: 0,
|
|
total: 0,
|
|
tab: 'group',
|
|
submitting: false,
|
|
refreshing: false,
|
|
loadError: '',
|
|
},
|
|
|
|
onShow() {
|
|
this.loadPage();
|
|
},
|
|
|
|
onPullDownRefresh() {
|
|
this.loadPage().then(() => wx.stopPullDownRefresh());
|
|
},
|
|
|
|
loadPage() {
|
|
this.setData({ loadError: '' });
|
|
return auth.ensureLogin()
|
|
.then((token) => {
|
|
if (!token) {
|
|
wx.switchTab({ url: '/pages/profile/profile' });
|
|
return;
|
|
}
|
|
return this.loadWeek();
|
|
})
|
|
.catch((err) => {
|
|
const msg = (err && (err.error || err.detail || err.message)) || '加载失败,请重试';
|
|
this.setData({ loading: false, loadError: msg });
|
|
wx.showToast({ title: msg, icon: 'none' });
|
|
});
|
|
},
|
|
|
|
onRetry() {
|
|
this.loadPage();
|
|
},
|
|
|
|
loadWeek() {
|
|
this.setData({ loading: true });
|
|
return api.request({ url: '/api/v1/checkin/week' }).then((res) => {
|
|
const classDate = res.class_date || '';
|
|
const weekday = WEEKDAYS[new Date(classDate + 'T00:00:00').getDay()] || '';
|
|
const dayNum = classDate.split('-')[2] || '';
|
|
const statusIndex = res.record && res.record.status
|
|
? Math.max(0, STATUSES.indexOf(res.record.status))
|
|
: -1;
|
|
const statusColor = res.record ? (STATUS_META[res.record.status] || '#C67B30') : '';
|
|
this.setData({
|
|
classDate,
|
|
weekday,
|
|
dayNum,
|
|
checked: !!res.checked,
|
|
record: res.record || null,
|
|
statusIndex,
|
|
statusColor,
|
|
statusBg: statusColor ? statusColor + '1A' : ''
|
|
});
|
|
return this.loadGroup();
|
|
}).then(() => {
|
|
this.setData({ loading: false });
|
|
}).catch(() => {
|
|
this.setData({ loading: false });
|
|
});
|
|
},
|
|
|
|
loadGroup() {
|
|
const data = this.data.classDate ? { class_date: this.data.classDate } : {};
|
|
return api.request({ url: '/api/v1/checkin/group', data }).then((res) => {
|
|
const members = (res.members || []).map((m) => ({
|
|
...m,
|
|
shortName: (m.name || '?').charAt(0),
|
|
timeText: m.checked && m.record ? fmtTime(m.record.checked_at) : ''
|
|
}));
|
|
const checkedCount = members.filter((m) => m.checked).length;
|
|
this.setData({
|
|
group: members,
|
|
groupName: res.group_name || '',
|
|
checkedCount,
|
|
total: members.length
|
|
});
|
|
}).catch(() => {});
|
|
},
|
|
|
|
loadHistory() {
|
|
return api.request({ url: '/api/v1/checkin/list', data: { page: 1, size: 20 } }).then((res) => {
|
|
const history = (res.list || []).map((item) => {
|
|
const color = STATUS_META[item.status] || '#C67B30';
|
|
return {
|
|
...item,
|
|
timeText: fmtTime(item.checked_at),
|
|
color,
|
|
bg: color + '1A'
|
|
};
|
|
});
|
|
this.setData({ history });
|
|
}).catch(() => {});
|
|
},
|
|
|
|
onStatusTap(e) {
|
|
if (this.data.submitting) {
|
|
return;
|
|
}
|
|
const statusIndex = Number(e.currentTarget.dataset.index);
|
|
const status = STATUSES[statusIndex];
|
|
if (!status) {
|
|
return;
|
|
}
|
|
const prevIndex = this.data.statusIndex;
|
|
this.setData({ statusIndex, submitting: true });
|
|
api.request({
|
|
url: '/api/v1/checkin',
|
|
method: 'POST',
|
|
data: {
|
|
status,
|
|
class_date: this.data.classDate,
|
|
course_type: '会员课程'
|
|
}
|
|
}).then((res) => {
|
|
const record = res.record || null;
|
|
const statusColor = record ? (STATUS_META[record.status] || '#C67B30') : '';
|
|
this.setData({ submitting: false, checked: true, record, statusColor, statusBg: statusColor ? statusColor + '1A' : '' });
|
|
wx.showToast({ title: '打卡成功', icon: 'success' });
|
|
this.loadGroup();
|
|
if (this.data.tab === 'personal') {
|
|
this.loadHistory();
|
|
}
|
|
}).catch((err) => {
|
|
this.setData({ submitting: false, statusIndex: prevIndex });
|
|
wx.showToast({ title: errMessage(err) || '打卡失败', icon: 'none' });
|
|
});
|
|
},
|
|
|
|
switchTab(e) {
|
|
const tab = e.currentTarget.dataset.tab;
|
|
if (tab !== 'group' && tab !== 'personal') {
|
|
return;
|
|
}
|
|
this.setData({ tab });
|
|
if (tab === 'personal') {
|
|
this.loadHistory();
|
|
}
|
|
},
|
|
|
|
|
|
onRefresh() {
|
|
this.setData({ refreshing: true });
|
|
const task = this.data.tab === 'group' ? this.loadWeek() : this.loadHistory();
|
|
Promise.resolve(task).then(() => {
|
|
this.setData({ refreshing: false });
|
|
});
|
|
}
|
|
});
|