从0到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_CODE: 'string|true|comment=核验码15位',
	ACTIVITY_JOIN_IS_CHECKIN: 'int|true|default=0|comment=是否签到 0/1 ',
	ACTIVITY_JOIN_CHECKIN_TIME: 'int|false|default=0|签到时间',

	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=报名成功, 99=审核未过',
	ACTIVITY_JOIN_REASON: 'string|false|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',
};

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_IS_MENU: 'int|true|default=1|comment=是否公开展示名单',

ACTIVITY_MAX_CNT: 'int|true|default=20|comment=人数上限 0=不限',
ACTIVITY_START: 'int|false|comment=活动开始时间',
ACTIVITY_END: 'int|false|comment=活动截止时间',
ACTIVITY_STOP: 'int|true|default=0|comment=报名截止时间 0=永不过期',

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_ADDRESS: 'string|false|comment=详细地址',
ACTIVITY_ADDRESS_GEO: 'object|false|comment=详细地址坐标参数',

ACTIVITY_QR: 'string|false',
ACTIVITY_VIEW_CNT: 'int|true|default=0',
ACTIVITY_JOIN_CNT: 'int|true|default=0',
ACTIVITY_COMMENT_CNT: 'int|true|default=0',

ACTIVITY_USER_LIST: 'array|true|default=[]|comment={name,id,pic}',

ACTIVITY_ADD_TIME: 'int|true',
ACTIVITY_EDIT_TIME: 'int|true',
ACTIVITY_ADD_IP: 'string|false',
ACTIVITY_EDIT_IP: 'string|false',

};

核心实现

async statActivityJoin(id) {
	let where = {
		ACTIVITY_JOIN_ACTIVITY_ID: id,
		ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
	}
	let cnt = await ActivityJoinModel.count(where);


	where = {
		ACTIVITY_JOIN_ACTIVITY_ID: id,
		ACTIVITY_JOIN_STATUS: ActivityJoinModel.STATUS.SUCC
	}
	let joinParams = {
		from: UserModel.CL,
		localField: 'ACTIVITY_JOIN_USER_ID',
		foreignField: 'USER_MINI_OPENID',
		as: 'user',
	};
	let orderBy = {
		ACTIVITY_JOIN_ADD_TIME: 'desc'
	}
	let list = await ActivityJoinModel.getListJoin(joinParams, where, 'ACTIVITY_JOIN_ADD_TIME,user.USER_MINI_OPENID,user.USER_NAME,user.USER_PIC', orderBy, 1, 6, false, 0);
	list = list.list;

	for (let k = 0; k < list.length; k++) {
		list[k] = list[k].user;
	} 

	await ActivityModel.edit(id, { ACTIVITY_JOIN_CNT: cnt, ACTIVITY_USER_LIST: list });
}

/**  报名前获取关键信息 */
async detailForActivityJoin(userId, activityId) {
	let fields = 'ACTIVITY_JOIN_FORMS, ACTIVITY_TITLE';

	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 joinMy = await ActivityJoinModel.getOne(whereMy, 'ACTIVITY_JOIN_FORMS', orderByMy);


	let myForms = joinMy ? joinMy.ACTIVITY_JOIN_FORMS : [];
	activity.myForms = myForms;

	return activity;
}

/** 取消我的报名 只有成功和待审核可以取消 取消即为删除记录 */
async cancelMyActivityJoin(userId, activityJoinId) {
	let where = {
		ACTIVITY_JOIN_USER_ID: userId,
		_id: activityJoinId,
		ACTIVITY_JOIN_STATUS: ['in', [ActivityJoinModel.STATUS.WAIT, ActivityJoinModel.STATUS.SUCC]]
	};
	let activityJoin = await ActivityJoinModel.getOne(where);

	if (!activityJoin) {
		this.AppError('未找到可取消的报名记录');
	}

	if (activityJoin.ACTIVITY_JOIN_IS_CHECKIN == 1)
		this.AppError('该活动已经签到,无法取消');

	let activity = await ActivityModel.getOne(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID);
	if (!activity)
		this.AppError('该活动不存在');

	if (activity.ACTIVITY_END <= this._timestamp)
		this.AppError('该活动已经结束,无法取消');

	if (activity.ACTIVITY_CANCEL_SET == 0)
		this.AppError('该活动不能取消');

	if (activity.ACTIVITY_CANCEL_SET == 2 && activity.ACTIVITY_STOP < this._timestamp)
		this.AppError('该活动已经截止报名,不能取消');

	await ActivityJoinModel.del(where); 

	// 统计
	await this.statActivityJoin(activityJoin.ACTIVITY_JOIN_ACTIVITY_ID);
}

UI设计

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

后台设计

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码git

git代码

技术栈 Codeigniter LeanCloud Bootstrap Admin-LTE jQuery fex-webuploader Codeigniter是一个老牌的php框架,零配置,文档极其丰富,国内的流利程度上看github的start数,让人觉得不可思议,是国外流行比较流行吧。它没有ORM,没有模板引擎,用它,只是因为够用了,LeanCloud自身就是ORM,而PHP天生就是模板语言,所以CI有没有ORM与模板引擎也无所谓。 使用LeanCloud后端云帮我省去了90%以上的后端接口,没有比小程序端用JS直接操作数据库更方便的了,所以直到小程序写完,再来写后台也完全来得及。后台只为了发布商品以及订单发货状态而已。当然Bmob也是一个不错的选择,现在也推出了小程序端sdk了。 后台界面,使用了Admin-LTE,它是基于Bootstrap的一套UI,打包了太多现成的组件,菜单目录树,表格,下拉框,颜色选择器,编辑器,日历,报表,聊天窗口,具体可以下载它的demo来看。基本一套后台能想到能使用到的,都在这里了。 在登录与修改页面,其实还用到零星的vue+element-ui,取dom的最高境界就是不用取dom,数据双向绑定确实方便实惠;还有就是bootstrap没有自带MessageBox很让人抓狂,于是就上了element-ui。说不准以后就让admin-lte与jQuery下岗了,让vue+ele全职来做吧。 最后就是2个工具,composer与bower,分别用来安装php与js库,有了这些包管理工具,安装第三方依赖库,直接敲上bower install bootstrap就达目的了,日后update还是那么的方便,再也不用搜索官网,下载解压,复制到项目等一切繁琐步骤;就跟git一样,一旦用上,就再也回不去了,严重推荐。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值