综上所述,招生报名缴费小程序的开发背景是满足数字化趋势、提供用户需求、提高效率、降低错误和欺诈风险,并在教育市场中获得竞争优势。这种小程序为学校、大学和培训机构提供了一个现代化、便捷的方式来管理招生流程,同时也为申请者提供更好的用户体验。
招生报名缴费小程序是一个用于学校、大学、培训机构或其他教育机构的应用程序,旨在帮助学生完成入学申请和支付报名费用。以下是招生报名缴费小程序可能包括的功能和组成部分:
ActivityModel.DB_STRUCTURE = {
_pid: 'string|true',
ACTIVITY_ID: 'string|true',
ACTIVITY_TITLE: 'string|true|comment=标题',
ACTIVITY_STATUS: 'int|true|default=1|comment=状态 0=未启用,1=使用中',
ACTIVITY_CATE_ID: 'string|true|default=0|comment=分类',
ACTIVITY_CATE_NAME: 'string|false|comment=分类冗余',
ACTIVITY_CANCEL_SET: 'int|true|default=1|comment=取消设置 0=不允,1=允许,2=仅截止前可取消',
ACTIVITY_CHECK_SET: 'int|true|default=0|comment=审核 0=不需要审核,1=需要审核',
ACTIVITY_MAX_CNT: 'int|true|default=20|comment=人数上限 0=不限',
ACTIVITY_START: 'int|false|comment=开始时间戳',
ACTIVITY_END: 'int|false|comment=截止时间戳',
ACTIVITY_START_DAY: 'string|false|comment=开始时间',
ACTIVITY_END_DAY: 'string|false|comment=截止时间',
ACTIVITY_START_MONTH: 'string|false|comment=开始月份',
ACTIVITY_END_MONTH: 'string|false|comment=截止月份',
ACTIVITY_ORDER: 'int|true|default=9999',
ACTIVITY_VOUCH: 'int|true|default=0',
ACTIVITY_FORMS: 'array|true|default=[]',
ACTIVITY_OBJ: 'object|true|default={}',
ACTIVITY_JOIN_FORMS: 'array|true|default=[]',
ACTIVITY_QR: 'string|false',
ACTIVITY_VIEW_CNT: 'int|true|default=0',
ACTIVITY_COMMENT_CNT: 'int|true|default=0',
ACTIVITY_METHOD: 'int|true|default=0|comment=支付方式 0=线下,1=线上',
ACTIVITY_FEE: 'int|false|comment=支付金额 分',
ACTIVITY_JOIN_CNT: 'int|true|default=0',
ACTIVITY_PAY_CNT: 'int|true|default=0|comment=支付数',
ACTIVITY_PAY_FEE: 'int|true|default=0|comment=支付额',
ACTIVITY_ADD_TIME: 'int|true',
ACTIVITY_EDIT_TIME: 'int|true',
ACTIVITY_ADD_IP: 'string|false',
ACTIVITY_EDIT_IP: 'string|false',
};
// 字段前缀
ActivityModel.FIELD_PREFIX = "ACTIVITY_";
/**
* 状态 0=未启用,1=使用中
*/
ActivityModel.STATUS = {
UNUSE: 0,
COMM: 1
};
ActivityJoinModel.DB_STRUCTURE = {
_pid: 'string|true',
ACTIVITY_JOIN_ID: 'string|true',
ACTIVITY_JOIN_ACTIVITY_ID: 'string|true|comment=报名PK',
ACTIVITY_JOIN_IS_ADMIN: 'int|true|default=0|comment=是否管理员添加 0/1',
ACTIVITY_JOIN_CANCEL_TIME: 'int|true|default=0|comment=取消时间',
ACTIVITY_JOIN_USER_ID: 'string|true|comment=用户ID',
ACTIVITY_JOIN_FORMS: 'array|true|default=[]|comment=表单',
ACTIVITY_JOIN_OBJ: 'object|true|default={}',
ACTIVITY_JOIN_STATUS: 'int|true|default=1|comment=状态 0=待审核 1=报名成功, 98=自己取消,99=审核未过/取消',
ACTIVITY_JOIN_REASON: 'string|false|comment=审核拒绝或者取消理由',
ACTIVITY_JOIN_FEE: 'int|true|default=0|comment=需支付费用 分',
ACTIVITY_JOIN_PAY_TRADE_NO: 'string|false|comment=商家订单号 32位',
ACTIVITY_JOIN_PAY_STATUS: 'int|true|default=0|comment=支付状态 0=未支付 1=已支付 8=已退款 99=无需支付',
ACTIVITY_JOIN_PAY_FEE: 'int|true|default=0|comment=已支付费用 分',
ACTIVITY_JOIN_PAY_TIME: 'int|true|default=0|comment=支付时间',
ACTIVITY_JOIN_ADD_TIME: 'int|true',
ACTIVITY_JOIN_EDIT_TIME: 'int|true',
ACTIVITY_JOIN_ADD_IP: 'string|false',
ACTIVITY_JOIN_EDIT_IP: 'string|false',
};
// 字段前缀
ActivityJoinModel.FIELD_PREFIX = "ACTIVITY_JOIN_";
/**
* 状态 0=待审核 1=报名成功, 99=审核未过
*/
ActivityJoinModel.STATUS = {
WAIT: 0,
SUCC: 1,
CANCEL: 98,
ADMIN_CANCEL: 99
};
ActivityJoinModel.STATUS_DESC = {
WAIT: '待审核',
SUCC: '成功',
CANCEL: '取消',
ADMIN_CANCEL: '审核未过'
};
async minuteJob() {
console.log('### minuteJob >>>>>');
// 未支付的成功订单取消
let time = this._timestamp - 6 * 60 * 1000;
console.log('###### Begin>>> 未支付订单6分钟后取消, time<=' + time + ', ' + timeUtil.timestamp2Time(time));
let where = {
ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]],
ACTIVITY_JOIN_PAY_STATUS: 0,
ACTIVITY_JOIN_ADD_TIME: ['<=', time],
}
let rows = await ActivityJoinModel.getAll(where, '*', {}, 3000, false);
console.log('未支付订单6分钟后取消, count=', rows.length);
for (let k in rows) {
let activityJoin = rows[k];
let tradeNo = activityJoin.ACTIVITY_JOIN_PAY_TRADE_NO;
if (!await this.fixActivityJoinPay(tradeNo, activityJoin.ACTIVITY_JOIN_ACTIVITY_ID)) {
console.log('该报名记录未支付,已取消并删除!', activityJoin);
}
}
console.log('###### END. 未支付订单6分钟后取消');
}
// 获取当前报名状态
getJoinStatusDesc(activity) {
let timestamp = this._timestamp;
if (activity.ACTIVITY_STATUS == 0)
return '报名停止';
else if (activity.ACTIVITY_START > timestamp)
return '报名未开始';
else if (activity.ACTIVITY_END <= timestamp)
return '报名截止';
else if (activity.ACTIVITY_MAX_CNT > 0
&& activity.ACTIVITY_JOIN_CNT >= activity.ACTIVITY_MAX_CNT)
return '报名已满';
else
return '报名中';
}
/** 浏览信息 */
async viewActivity(userId, id) {
await this.fixUserActivityJoinPayRecord(userId);
let fields = '*';
let where = {
_id: id,
ACTIVITY_STATUS: ActivityModel.STATUS.COMM
}
let activity = await ActivityModel.getOne(where, fields);
if (!activity) return null;
ActivityModel.inc(id, 'ACTIVITY_VIEW_CNT', 1);
// 判断是否有报名
let whereJoin = {
ACTIVITY_JOIN_USER_ID: userId,
ACTIVITY_JOIN_ACTIVITY_ID: id,
ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
}
let activityJoin = await ActivityJoinModel.getOne(whereJoin);
if (activityJoin) {
activity.myActivityJoinId = activityJoin._id;
activity.myActivityJoinTag = (activityJoin.ACTIVITY_JOIN_STATUS == ActivityJoinModel.STATUS.WAIT) ? '待审核' : '已报名';
if (activity.myActivityJoinTag == '已报名' && activityJoin.ACTIVITY_JOIN_PAY_STATUS == 1) {
activity.myActivityJoinTag = '已报名缴费';
}
}
else {
activity.myActivityJoinId = '';
activity.myActivityJoinTag = '';
}
return activity;
}
/** 取得分页列表 */
async getActivityList({
cateId, //分类查询条件
search, // 搜索条件
sortType, // 搜索菜单
sortVal, // 搜索菜单
orderBy, // 排序
page,
size,
isTotal = true,
oldTotal
}) {
orderBy = orderBy || {
'ACTIVITY_ORDER': 'asc',
'ACTIVITY_ADD_TIME': 'desc'
};
let fields = 'ACTIVITY_START_MONTH,ACTIVITY_END_MONTH,ACTIVITY_START_DAY,ACTIVITY_END_DAY,ACTIVITY_JOIN_CNT,ACTIVITY_OBJ,ACTIVITY_VIEW_CNT,ACTIVITY_TITLE,ACTIVITY_MAX_CNT,ACTIVITY_START,ACTIVITY_END,ACTIVITY_ORDER,ACTIVITY_STATUS,ACTIVITY_CATE_NAME,ACTIVITY_OBJ';
let where = {};
where.and = {
_pid: this.getProjectId() //复杂的查询在此处标注PID
};
if (cateId && cateId !== '0') where.and.ACTIVITY_CATE_ID = cateId;
where.and.ACTIVITY_STATUS = ActivityModel.STATUS.COMM; // 状态
if (util.isDefined(search) && search) {
where.or = [{
ACTIVITY_TITLE: ['like', search]
},];
} else if (sortType && util.isDefined(sortVal)) {
// 搜索菜单
switch (sortType) {
case 'cateId': {
if (sortVal) where.and.ACTIVITY_CATE_ID = String(sortVal);
break;
}
case 'sort': {
// 排序
orderBy = this.fmtOrderBySort(sortVal, 'ACTIVITY_ADD_TIME');
break;
}
case 'today': { //今天
let time = timeUtil.time('Y-M-D');
where.and.ACTIVITY_START_DAY = ['<=', time];
where.and.ACTIVITY_END_DAY = ['>=', time];
break;
}
case 'tomorrow': { //明日
let time = timeUtil.time('Y-M-D', 86400);
where.and.ACTIVITY_START_DAY = ['<=', time];
where.and.ACTIVITY_END_DAY = ['>=', time];
break;
}
case 'month': { //本月
let month = timeUtil.time('Y-M');
where.and.ACTIVITY_START_MONTH = ['<=', month];
where.and.ACTIVITY_END_MONTH = ['>=', month];
break;
}
}
}
return await ActivityModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal);
}
/** 取得我的报名分页列表 */
async getMyActivityJoinList(userId, {
search, // 搜索条件
sortType, // 搜索菜单
sortVal, // 搜索菜单
orderBy, // 排序
page,
size,
isTotal = true,
oldTotal
}) {
await this.fixUserActivityJoinPayRecord(userId);
orderBy = orderBy || {
'ACTIVITY_JOIN_ADD_TIME': 'desc'
};
let fields = 'ACTIVITY_JOIN_PAY_STATUS,ACTIVITY_JOIN_REASON,ACTIVITY_JOIN_ACTIVITY_ID,ACTIVITY_JOIN_STATUS,ACTIVITY_JOIN_ADD_TIME,activity.ACTIVITY_END,activity.ACTIVITY_START,activity.ACTIVITY_TITLE';
let where = {
ACTIVITY_JOIN_USER_ID: userId
};
if (util.isDefined(search) && search) {
where['activity.ACTIVITY_TITLE'] = {
$regex: '.*' + search,
$options: 'i'
};
} else if (sortType) {
// 搜索菜单
switch (sortType) {
case 'timedesc': { //按时间倒序
orderBy = {
'activity.ACTIVITY_START': 'desc',
'ACTIVITY_JOIN_ADD_TIME': 'desc'
};
break;
}
case 'timeasc': { //按时间正序
orderBy = {
'activity.ACTIVITY_START': 'asc',
'ACTIVITY_JOIN_ADD_TIME': 'asc'
};
break;
}
case 'succ': {
where.ACTIVITY_JOIN_STATUS = ActivityJoinModel.STATUS.SUCC;
break;
}
case 'wait': {
where.ACTIVITY_JOIN_STATUS = ActivityJoinModel.STATUS.WAIT;
break;
}
case 'usercancel': {
where.ACTIVITY_JOIN_STATUS = ActivityJoinModel.STATUS.CANCEL;
break;
}
case 'cancel': {
where.ACTIVITY_JOIN_STATUS = ActivityJoinModel.STATUS.ADMIN_CANCEL;
break;
}
}
}
let joinParams = {
from: ActivityModel.CL,
localField: 'ACTIVITY_JOIN_ACTIVITY_ID',
foreignField: '_id',
as: 'activity',
};
let result = await ActivityJoinModel.getListJoin(joinParams, where, fields, orderBy, page, size, isTotal, oldTotal);
return result;
}
/** 取得我的报名详情 */
async getMyActivityJoinDetail(userId, activityJoinId) {
let fields = '*';
let where = {
_id: activityJoinId,
ACTIVITY_JOIN_USER_ID: userId
};
let activityJoin = await ActivityJoinModel.getOne(where, fields);
if (activityJoin) {
activityJoin.activity = await ActivityModel.getOne(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID, 'ACTIVITY_TITLE,ACTIVITY_START,ACTIVITY_END');
}
return activityJoin;
}
// 修正某用户所有未支付的成功订单状态,无须支付的不用处理
async fixUserActivityJoinPayRecord(userId) {
let where = {
ACTIVITY_JOIN_USER_ID: userId,
ACTIVITY_JOIN_PAY_STATUS: 0,
ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]],
}
let list = await ActivityJoinModel.getAll(where);
for (let k = 0; k < list.length; k++) {
await this.fixActivityJoinPay(list[k].ACTIVITY_JOIN_PAY_TRADE_NO, list[k].ACTIVITY_JOIN_ACTIVITY_ID);
}
}
// 修正某订单状态 (仅需支付订单)
async fixActivityJoinPay(tradeNo, activityId) {
if (!tradeNo) {
// 无支付号空单 删除
await ActivityJoinModel.del({ ACTIVITY_JOIN_PAY_TRADE_NO: tradeNo });
// 重新统计
this.statActivityJoin(activityId);
return false;
}
let payService = new PayService();
if (!await payService.fixPayResult(tradeNo)) {
// 关闭未支付单
payService.closePay(tradeNo);
// 未支付
await ActivityJoinModel.del({ ACTIVITY_JOIN_PAY_TRADE_NO: tradeNo });
// 重新统计
this.statActivityJoin(activityId);
return false;
}
// 已支付
let pay = await PayModel.getOne({ PAY_TRADE_NO: tradeNo });
if (!pay) this.AppError('支付流水异常,请核查');
// 更新支付信息
let data = {
ACTIVITY_JOIN_PAY_STATUS: 1,
ACTIVITY_JOIN_PAY_TRADE_NO: tradeNo,
ACTIVITY_JOIN_PAY_FEE: pay.PAY_TOTAL_FEE,
ACTIVITY_JOIN_PAY_TIME: pay.PAY_END_TIME,
}
await ActivityJoinModel.edit({ ACTIVITY_JOIN_PAY_TRADE_NO: tradeNo }, data);
// 重新统计
this.statActivityJoin(activityId);
return true;
}
//################## 报名
// 报名
async prepay(userId, activityId, forms) {
this.AppError('[招生报名缴费]该功能暂不开放,如有需要请加作者微信:cclinux0730');
}
async statActivityJoin(activityId) {
// 报名数
let where = {
ACTIVITY_JOIN_ACTIVITY_ID: activityId,
ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
}
let cnt = await ActivityJoinModel.count(where);
// 已支付记录
let wherePayCnt = {
ACTIVITY_JOIN_ACTIVITY_ID: activityId,
ACTIVITY_JOIN_PAY_STATUS: 1,
ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
}
let payCnt = await ActivityJoinModel.count(wherePayCnt);
// 已支付金额
let wherePayFee = {
ACTIVITY_JOIN_ACTIVITY_ID: activityId,
ACTIVITY_JOIN_PAY_STATUS: 1,
ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
}
let payFee = await ActivityJoinModel.sum(wherePayFee, 'ACTIVITY_JOIN_PAY_FEE');
let data = {
ACTIVITY_JOIN_CNT: cnt,
ACTIVITY_PAY_CNT: payCnt,
ACTIVITY_PAY_FEE: payFee,
}
await ActivityModel.edit(activityId, data);
}
/** 报名前获取关键信息 */
async detailForActivityJoin(userId, activityId) {
await this.fixUserActivityJoinPayRecord(userId);
let fields = 'ACTIVITY_JOIN_FORMS, ACTIVITY_TITLE, ACTIVITY_FEE, ACTIVITY_METHOD';
let where = {
_id: activityId,
ACTIVITY_STATUS: ActivityModel.STATUS.COMM
}
let activity = await ActivityModel.getOne(where, fields);
if (!activity)
this.AppError('该报名不存在');
let whereMy = {
ACTIVITY_JOIN_USER_ID: userId,
}
let orderByMy = {
ACTIVITY_JOIN_ADD_TIME: 'desc'
}
//***取得本人所有记录
let joinList = await ActivityJoinModel.getAll(whereMy, 'ACTIVITY_JOIN_OBJ,ACTIVITY_JOIN_FORMS', orderByMy);
let addressList = [];
let addressList2 = [];
for (let k = 0; k < joinList.length; k++) {
let exist = false;
for (let j = 0; j < addressList.length; j++) {
if (addressList[j].name === joinList[k].ACTIVITY_JOIN_OBJ.name) {
exist = true;
break;
}
}
if (!exist) {
addressList.push(joinList[k].ACTIVITY_JOIN_OBJ);
addressList2.push(joinList[k].ACTIVITY_JOIN_FORMS);
}
}
// 取出本人最近一次的填写表单
let joinMy = await ActivityJoinModel.getOne(whereMy, 'ACTIVITY_JOIN_FORMS', orderByMy);
joinMy = null;
let myForms = joinMy ? joinMy.ACTIVITY_JOIN_FORMS : [];
activity.myForms = myForms;
activity.addressList = addressList;
activity.addressList2 = addressList2;
activity.ACTIVITY_FEE = Number(dataUtil.fmtMoney(activity.ACTIVITY_FEE / 100));
return activity;
}
/** 取消我的报名 只有成功和待审核可以取消 */
async cancelMyActivityJoin(userId, activityJoinId) {
let where = {
_id: activityJoinId,
ACTIVITY_JOIN_USER_ID: userId,
ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]] //只有成功和待审核可以取消
};
let activityJoin = await ActivityJoinModel.getOne(where);
if (!activityJoin) {
this.AppError('未找到可取消的报名记录');
}
let activity = await ActivityModel.getOne(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID);
if (!activity)
this.AppError('该报名不存在');
if (activity.ACTIVITY_CANCEL_SET == 0)
this.AppError('该报名不能取消报名');
if (activity.ACTIVITY_CANCEL_SET == 2 && activity.ACTIVITY_END < this._timestamp)
this.AppError('该报名已经截止,无法取消');
if (activityJoin.ACTIVITY_JOIN_PAY_STATUS == 99) {
// 无须支付
// 更新记录
let data = {
ACTIVITY_JOIN_STATUS: ActivityJoinModel.STATUS.CANCEL,
ACTIVITY_JOIN_CANCEL_TIME: this._timestamp,
}
await ActivityJoinModel.edit(activityJoinId, data);
}
else {
let tradeNo = activityJoin.ACTIVITY_JOIN_PAY_TRADE_NO;
if (!await this.fixActivityJoinPay(tradeNo, activityJoin.ACTIVITY_JOIN_ACTIVITY_ID)) {
this.AppError('该报名记录未支付,已取消并删除!');
}
let payService = new PayService();
await payService.refundPay(tradeNo, '用户取消报名');
// 更新记录
let data = {
ACTIVITY_JOIN_STATUS: ActivityJoinModel.STATUS.CANCEL,
ACTIVITY_JOIN_CANCEL_TIME: this._timestamp,
ACTIVITY_JOIN_PAY_STATUS: 8,
}
await ActivityJoinModel.edit(activityJoinId, data);
}
// 统计
await this.statActivityJoin(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID);
}
/** 按天获取报名项目 */
async getActivityListByDay(day) {
let where = {
ACTIVITY_START_DAY: ['<=', day],
ACTIVITY_END_DAY: ['>=', day]
};
let orderBy = {
'ACTIVITY_ORDER': 'asc',
'ACTIVITY_ADD_TIME': 'desc'
};
let fields = 'ACTIVITY_TITLE,ACTIVITY_START,ACTIVITY_OBJ.cover';
let list = await ActivityModel.getAll(where, fields, orderBy);
let retList = [];
for (let k = 0; k < list.length; k++) {
let node = {};
node.timeDesc = timeUtil.timestamp2Time(list[k].ACTIVITY_START, 'h:m');
node.title = list[k].ACTIVITY_TITLE;
node.pic = list[k].ACTIVITY_OBJ.cover[0];
node._id = list[k]._id;
retList.push(node);
}
return retList;
}
/**
* 获取从某天开始可报名的日期
* @param {*} fromDay 日期 Y-M-D
*/
async getActivityHasDaysFromDay(fromDay) {
let where = {
ACTIVITY_STATUS: 1,
//ACTIVITY_START_DAY: ['<=', fromDay],
ACTIVITY_END_DAY: ['>=', fromDay]
};
let fields = 'ACTIVITY_START_DAY,ACTIVITY_END_DAY';
let list = await ActivityModel.getAllBig(where, fields);
if (list.length == 0) return;
let min = await ActivityModel.min(where, 'ACTIVITY_START_DAY');
let max = await ActivityModel.max(where, 'ACTIVITY_END_DAY');
let minTimestamp = timeUtil.time2Timestamp(min);
let maxTimestamp = timeUtil.time2Timestamp(max);
let retList = [];
for (let n = minTimestamp; n <= maxTimestamp; n += 86400 * 1000) {
let day = timeUtil.timestamp2Time(n, 'Y-M-D');
if (day < fromDay) continue;
for (let k = 0; k < list.length; k++) {
if (day >= list[k].ACTIVITY_START_DAY && day <= list[k].ACTIVITY_END_DAY) {
if (!retList.includes(day)) retList.push(day);
break;
}
}
}
return retList;
}
下载地址