导读:课时包是培训机构的"钱袋子"——购课、上课、过期都要动课时,漏记错扣,月底对账就乱。本文给出一套模型:两张表管账、有效期优先、事务防超扣、双档预警,附 SQL。
核心问题只有一个:学员还剩多少课时可用。得管住买了多少、用了多少、还剩多少。
CREATE TABLE class_package (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
student_id BIGINT NOT NULL,
total_hours DECIMAL(5,1) NOT NULL,
used_hours DECIMAL(5,1) NOT NULL DEFAULT 0,
remain_hours DECIMAL(5,1) GENERATED ALWAYS AS (total_hours - used_hours) STORED,
expire_at DATE NOT NULL,
status TINYINT NOT NULL DEFAULT 0
);
CREATE TABLE class_consume (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
package_id BIGINT NOT NULL,
lesson_id BIGINT NOT NULL,
consume_hours DECIMAL(5,1) NOT NULL,
consumed_at DATETIME NOT NULL,
operator_id BIGINT NOT NULL
);要点:剩余课时用生成列实时计算,不手工维护;扣课必写流水,流水是唯一"证据"。
学员常同时持有多个课时包(续费、赠课、专项),一次上课扣哪个?两个原则:
function pickPackage(studentId, type, hours) {
return db.query(
`SELECT id, remain_hours FROM class_package
WHERE student_id = ? AND status = 0 AND package_type = ?
AND remain_hours >= ? ORDER BY expire_at ASC LIMIT 1`,
[studentId, type, hours]
);
}
// 扣课事务:先扣余量再写流水
BEGIN;
UPDATE class_package SET used_hours = used_hours + 2
WHERE id = ? AND remain_hours >= 2;
INSERT INTO class_consume (package_id, lesson_id, consume_hours) VALUES (?, ?, 2);
COMMIT;要点:更新带 remain_hours >= 2 防并发超扣;事务保证余量与流水原子完成。
课时快用完才被发现,易起纠纷。两档预警:
SELECT s.name, p.remain_hours,
DATEDIFF(p.expire_at, CURDATE()) AS days_left
FROM class_package p JOIN student s ON s.id = p.student_id
WHERE p.status = 0
AND (p.remain_hours <= 3 OR DATEDIFF(p.expire_at, CURDATE()) <= 30);要点:预警按日跑批、触发落表防重复;学员端只发余量。
课时包按「两张表管账 → 有效期优先扣课 → 事务防超扣 → 双档预警」落地,生成列算余量、流水做证据、状态机管冻结。同类分层在乔拓云教育系统的课时管理模块中有对应实现,可按这套模型直接起步。
课时账的难点不在"减法",而在"什么时候减、减哪个包、减完怎么证明"。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。