读书会活动打卡小程序开发笔记(一)

背景分析

书籍是人类进步的阶梯,在信息高度发达而浮躁的当下,静下心来读书成为都市人群的新趋势, 很多读书社团应运而生,那么通过设计一款小程序,把读书会搬到手机上,通过小程序了解最热门的书单和作家,可以每天组织阅读打卡和评比;书友会时常组织书友进行线下活动,那么通过小程序可以方便的搞定报名、签到、活动信息收集,活动结束后还可以进行评价。

功能规划

读书会活动打卡小程序开发笔记(一)_第1张图片

数据库设计


EnrollModel.DB_STRUCTURE = {
    _pid: 'string|true',
    ENROLL_ID: 'string|true',

    ENROLL_TITLE: 'string|true|comment=标题',
    ENROLL_STATUS: 'int|true|default=1|comment=状态 0=未启用,1=使用中',

    ENROLL_CATE_ID: 'string|true|default=0|comment=分类',
    ENROLL_CATE_NAME: 'string|false|comment=分类冗余',

    ENROLL_START: 'int|false|comment=开始时间',
    ENROLL_END: 'int|false|comment=结束时间',
    ENROLL_DAY_CNT: 'int|false|comment=持续天数',

    ENROLL_ORDER: 'int|true|default=9999',
    ENROLL_VOUCH: 'int|true|default=0',

    ENROLL_FORMS: 'array|true|default=[]',
    ENROLL_OBJ: 'object|true|default={}',

    ENROLL_JOIN_FORMS: 'array|true|default=[]',

    ENROLL_DAYS: 'array|true|default=[]',

    ENROLL_QR: 'string|false',
    ENROLL_VIEW_CNT: 'int|true|default=0',
    ENROLL_JOIN_CNT: 'int|true|default=0',
    ENROLL_USER_CNT: 'int|true|default=0',

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

    ENROLL_ADD_TIME: 'int|true',
    ENROLL_EDIT_TIME: 'int|true',
    ENROLL_ADD_IP: 'string|false',
    ENROLL_EDIT_IP: 'string|false',
};

EnrollJoinModel.DB_STRUCTURE = {
    _pid: 'string|true',
    ENROLL_JOIN_ID: 'string|true',
    ENROLL_JOIN_ENROLL_ID: 'string|true|comment=打卡PK',

    ENROLL_JOIN_USER_ID: 'string|true|comment=用户ID',
    ENROLL_JOIN_DAY: 'string|true|comment=日期',
    ENROLL_JOIN_FORMS: 'array|true|default=[]|comment=表单',

    ENROLL_JOIN_STATUS: 'int|true|default=1|comment=状态 1=成功', 

    ENROLL_JOIN_ADD_TIME: 'int|true',
    ENROLL_JOIN_EDIT_TIME: 'int|true',
    ENROLL_JOIN_ADD_IP: 'string|false',
    ENROLL_JOIN_EDIT_IP: 'string|false',
};

核心实现


class EnrollService extends BaseProjectService {

    // 获取当前打卡状态
    getJoinStatusDesc(enroll) {
        let timestamp = this._timestamp;

        if (enroll.ENROLL_STATUS == 0)
            return '已停止';
        else if (enroll.ENROLL_START > timestamp)
            return '未开始';
        else if (enroll.ENROLL_END <= timestamp)
            return '已结束';
        else
            return '进行中';
    }

    // 获取某日动态
    async getEnrollJoinByDay(enrollId, day = '') {
        if (!day) day = timeUtil.time('Y-M-D');

        let where = {
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_DAY: day,
            ENROLL_JOIN_STATUS: EnrollJoinModel.STATUS.SUCC
        }
        let joinParams = {
            from: UserModel.CL,
            localField: 'ENROLL_JOIN_USER_ID',
            foreignField: 'USER_MINI_OPENID',
            as: 'user',
        };
        let orderBy = {
            ENROLL_JOIN_ADD_TIME: 'desc'
        }
        let list = await EnrollJoinModel.getListJoin(joinParams, where, 'ENROLL_JOIN_ADD_TIME,user.USER_NAME,user.USER_PIC', orderBy, 1, 100, false, 0);
        return list.list;
    }

    // 获取某活动排行
    async getEnrollUserRank(enrollId) {

        let where = {
            ENROLL_USER_ENROLL_ID: enrollId
        }
        let joinParams = {
            from: UserModel.CL,
            localField: 'ENROLL_USER_MINI_OPENID',
            foreignField: 'USER_MINI_OPENID',
            as: 'user',
        };
        let orderBy = {
            ENROLL_USER_JOIN_CNT: 'desc'
        }
        let fields = 'ENROLL_USER_JOIN_CNT,ENROLL_USER_LAST_DAY,user.USER_NAME,user.USER_PIC';
        let list = await EnrollUserModel.getListJoin(joinParams, where, fields, orderBy, 1, 100, false, 0);
        return list.list;
    }

    /** 浏览信息 */
    async viewEnroll(userId, id) {

        let fields = '*';

        let where = {
            _id: id,
            ENROLL_STATUS: EnrollModel.STATUS.COMM
        }
        let enroll = await EnrollModel.getOne(where, fields);
        if (!enroll) return null;

        EnrollModel.inc(id, 'ENROLL_VIEW_CNT', 1);

        // 判断用户今日是否有打卡
        let whereJoin = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: id,
            ENROLL_JOIN_DAY: timeUtil.time('Y-M-D'),
            ENROLL_JOIN_STATUS: EnrollJoinModel.STATUS.SUCC
        }
        let enrollJoin = await EnrollJoinModel.getOne(whereJoin);
        if (enrollJoin) {
            enroll.myEnrollJoinId = enrollJoin._id;
        }
        else {
            enroll.myEnrollJoinId = '';
        }

        // 某日打卡列表
        enroll.activity = await this.getEnrollJoinByDay(id);

        // 打卡日期数组
        let dayList = [];
        let start = timeUtil.timestamp2Time(enroll.ENROLL_START, 'Y-M-D');
        start = timeUtil.time2Timestamp(start);
        let today = timeUtil.time2Timestamp(timeUtil.time('Y-M-D'));

        for (let k = start; k <= today;) {
            let month = timeUtil.timestamp2Time(k, 'M月');
            if (month.startsWith('0')) month = month.substring(1);

            let date = timeUtil.timestamp2Time(k, 'D');
            let day = timeUtil.timestamp2Time(k, 'Y-M-D');

            dayList.push({ month, date, day });
            k = k + 86400 * 1000;
        }
        enroll.dayList = dayList;

        // 排行榜 
        let rankList = await this.getEnrollUserRank(id);
        enroll.rankList = rankList;

        return enroll;
    }


    /** 取得分页列表 */
    async getEnrollList({
        search, // 搜索条件
        sortType, // 搜索菜单
        sortVal, // 搜索菜单
        orderBy, // 排序 
        page,
        size,
        isTotal = true,
        oldTotal
    }) {

        orderBy = orderBy || {
            'ENROLL_ORDER': 'asc',
            'ENROLL_ADD_TIME': 'desc'
        };
        let fields = 'ENROLL_USER_LIST,ENROLL_JOIN_CNT,ENROLL_OBJ,ENROLL_USER_CNT,ENROLL_TITLE,ENROLL_START,ENROLL_END,ENROLL_ORDER,ENROLL_STATUS,ENROLL_CATE_NAME,ENROLL_OBJ';

        let where = {};
        where.and = {
            _pid: this.getProjectId() //复杂的查询在此处标注PID
        };

        where.and.ENROLL_STATUS = EnrollModel.STATUS.COMM; // 状态  

        if (util.isDefined(search) && search) {
            where.or = [{
                ENROLL_TITLE: ['like', search]
            },];
        } else if (sortType && util.isDefined(sortVal)) {
            // 搜索菜单
            switch (sortType) {
                case 'cateId': {
                    if (sortVal) where.and.ENROLL_CATE_ID = String(sortVal);
                    break;
                }
                case 'sort': {
                    orderBy = this.fmtOrderBySort(sortVal, 'ENROLL_ADD_TIME');
                    break;
                }
                case 'today': { //今天
                    let day = timeUtil.time('Y-M-D');
                    where.and.ENROLL_DAYS = day;
                    break;
                }
                case 'tomorrow': { //明日
                    let day = timeUtil.time('Y-M-D', 86400);
                    where.and.ENROLL_DAYS = day;
                    break;
                }
                case 'yesterday': { //昨天 
                    let day = timeUtil.time('Y-M-D', -86400);
                    where.and.ENROLL_DAYS = day;
                    break;
                }
                case 'month': { //本月 
                    let day = timeUtil.time('Y-M-D');
                    let start = timeUtil.getMonthFirstTimestamp(day);
                    let end = timeUtil.getMonthLastTimestamp(day);
                    start = timeUtil.timestamp2Time(start, 'Y-M-D');
                    end = timeUtil.timestamp2Time(end, 'Y-M-D'); 
                    where.and.ENROLL_DAYS = ['between', start, end];
                    break;
                }

            }
        }

        return await EnrollModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal);
    }

    /** 取得我的打卡分页列表 */
    async getMyEnrollUserList(userId, {
        search, // 搜索条件
        sortType, // 搜索菜单
        sortVal, // 搜索菜单
        orderBy, // 排序 
        page,
        size,
        isTotal = true,
        oldTotal
    }) {
        orderBy = orderBy || {
            'ENROLL_USER_ADD_TIME': 'asc'
        };
        let fields = 'ENROLL_USER_LAST_DAY,ENROLL_USER_ENROLL_ID,ENROLL_USER_JOIN_CNT,enroll.ENROLL_TITLE,enroll.ENROLL_OBJ.cover,enroll.ENROLL_USER_CNT,enroll.ENROLL_CATE_NAME,enroll.ENROLL_DAY_CNT,enroll.ENROLL_START,enroll.ENROLL_END,enroll.ENROLL_STATUS';

        let where = {
            ENROLL_USER_MINI_OPENID: userId
        };

        if (util.isDefined(search) && search) {
            where['enroll.ENROLL_TITLE'] = {
                $regex: '.*' + search,
                $options: 'i'
            };
        } else if (sortType) {
            // 搜索菜单
            let timestamp = this._timestamp;

            switch (sortType) {
                case 'stop': {
                    where['enroll.ENROLL_STATUS'] = 0;
                    break;
                }
                case 'un': {
                    where['enroll.ENROLL_START'] = ['>', timestamp];
                    break;
                }
                case 'over': {
                    where['enroll.ENROLL_END'] = ['<=', timestamp];
                    break;
                }
                case 'run': {
                    where['enroll.ENROLL_STATUS'] = 1;
                    where['enroll.ENROLL_START'] = ['<=', timestamp];
                    where['enroll.ENROLL_END'] = ['>', timestamp];
                    break;
                }

            }
        }

        let joinParams = {
            from: EnrollModel.CL,
            localField: 'ENROLL_USER_ENROLL_ID',
            foreignField: '_id',
            as: 'enroll',
        };

        let result = await EnrollUserModel.getListJoin(joinParams, where, fields, orderBy, page, size, isTotal, oldTotal);

        let list = result.list;
        for (let k = 0; k < list.length; k++) {
            let enroll = {
                ENROLL_START: list[k].enroll.ENROLL_START,
                ENROLL_END: list[k].enroll.ENROLL_END,
                ENROLL_STATUS: list[k].enroll.ENROLL_STATUS,
            }
            let status = this.getJoinStatusDesc(enroll);

            if (status == '进行中') {
                if (list[k].ENROLL_USER_LAST_DAY == timeUtil.time('Y-M-D'))
                    status = '已打卡';
            }
            list[k].status = status;

            list[k].last = list[k].ENROLL_USER_LAST_DAY.split('-')[1] + '-' + list[k].ENROLL_USER_LAST_DAY.split('-')[2];
        }

        return result;
    }

    /** 取得我的打卡清单列表 */
    async getMyEnrollJoinList(userId, {
        enrollId,
        search, // 搜索条件
        sortType, // 搜索菜单
        sortVal, // 搜索菜单
        orderBy, // 排序 
        page,
        size,
        isTotal = true,
        oldTotal
    }) {
        orderBy = orderBy || {
            'ENROLL_JOIN_ADD_TIME': 'desc'
        };
        let fields = '*';

        let where = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: enrollId
        };

        return await EnrollJoinModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal);
    }


    //################## 打卡 
    addEnrollUserList(userList, user) {

        //查询是否存在 并删除
        for (let k = 0; k < userList.length; k++) {
            if (userList[k].id == user.id)
                userList.splice(k, 1);
        }

        userList.unshift(user);

        // 判断个数, 多的删除
        if (userList.length > 3)
            userList.splice(userList.length - 1, 1);

        return userList;
    }

    // 打卡 
    async enrollJoin(userId, enrollId, forms) {

        let user = await UserModel.getOne({ USER_MINI_OPENID: userId, USER_STATUS: UserModel.STATUS.COMM });
        if (!user) this.AppError('用户不存在');

        // 打卡是否结束
        let whereEnroll = {
            _id: enrollId,
            ENROLL_STATUS: EnrollModel.STATUS.COMM
        }
        let enroll = await EnrollModel.getOne(whereEnroll);
        if (!enroll)
            this.AppError('该打卡活动不存在或者已经停止');

        // 是否打卡开始
        if (enroll.ENROLL_START > this._timestamp)
            this.AppError('该打卡活动尚未开始');

        // 是否过了打卡结束期
        if (enroll.ENROLL_END < this._timestamp)
            this.AppError('该打卡活动已经结束');

        let day = timeUtil.time('Y-M-D');

        // 自己今日是否已经有打卡
        let whereMy = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_DAY: day,
            ENROLL_JOIN_STATUS: EnrollJoinModel.STATUS.SUCC
        }
        let my = await EnrollJoinModel.getOne(whereMy);
        if (my) {
            this.AppError('您今日已打卡,无须重复打卡');
        }

        // 入库
        let data = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_STATUS: EnrollJoinModel.STATUS.SUCC,
            ENROLL_JOIN_DAY: day,
            ENROLL_JOIN_FORMS: forms
        }

        let enrollJoinId = await EnrollJoinModel.insert(data);

        // 统计数量
        this.statEnrollJoin(enrollId, userId);

        // 更新用户头像 
        let userList = enroll.ENROLL_USER_LIST;
        userList = this.addEnrollUserList(userList, { pic: user.USER_PIC, id: userId, name: user.USER_NAME });
        EnrollModel.edit(enrollId, { ENROLL_USER_LIST: userList });

        return { enrollJoinId }

    }

    // 统计
    async statEnrollJoin(enrollId, userId = '', del = false) {
        // 总体统计
        let where = {
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_STATUS: EnrollJoinModel.STATUS.SUCC
        }
        let joinCnt = await EnrollJoinModel.count(where);
        let userCnt = await EnrollJoinModel.distinctCnt(where, 'ENROLL_JOIN_USER_ID');

        let data = {
            ENROLL_JOIN_CNT: joinCnt,
            ENROLL_USER_CNT: userCnt,
        }
        await EnrollModel.edit(enrollId, data);

        // 用户统计
        if (!userId) return;
        where = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_STATUS: EnrollJoinModel.STATUS.SUCC
        }
        let userJoinCnt = await EnrollJoinModel.count(where);


        let enrollUserData = {};
        enrollUserData.ENROLL_USER_LAST_DAY = timeUtil.time('Y-M-D');
        enrollUserData.ENROLL_USER_JOIN_CNT = userJoinCnt;
        enrollUserData.ENROLL_USER_DAY_CNT = userJoinCnt;

        where = {
            ENROLL_USER_MINI_OPENID: userId,
            ENROLL_USER_ENROLL_ID: enrollId
        };
        await EnrollUserModel.insertOrUpdate(where, enrollUserData);

        if (del) {
            //删除打卡记录,则更新最近打卡时间
            let last = '';
            where = {
                ENROLL_JOIN_USER_ID: userId,
                ENROLL_JOIN_ENROLL_ID: enrollId,
                ENROLL_JOIN_STATUS: EnrollJoinModel.STATUS.SUCC
            }
            let lastModel = await EnrollJoinModel.getOne(where, 'ENROLL_JOIN_DAY', { 'ENROLL_JOIN_ADD_TIME': 'desc' });
            if (lastModel) last = lastModel.ENROLL_JOIN_DAY;

            where = {
                ENROLL_USER_MINI_OPENID: userId,
                ENROLL_USER_ENROLL_ID: enrollId
            };
            await EnrollUserModel.edit(where, { ENROLL_USER_LAST_DAY: last });
        }

    }

}

UI设计

读书会活动打卡小程序开发笔记(一)_第2张图片
读书会活动打卡小程序开发笔记(一)_第3张图片
读书会活动打卡小程序开发笔记(一)_第4张图片
读书会活动打卡小程序开发笔记(一)_第5张图片
读书会活动打卡小程序开发笔记(一)_第6张图片
读书会活动打卡小程序开发笔记(一)_第7张图片
读书会活动打卡小程序开发笔记(一)_第8张图片
读书会活动打卡小程序开发笔记(一)_第9张图片
读书会活动打卡小程序开发笔记(一)_第10张图片
读书会活动打卡小程序开发笔记(一)_第11张图片

后端UI设计

读书会活动打卡小程序开发笔记(一)_第12张图片
读书会活动打卡小程序开发笔记(一)_第13张图片
读书会活动打卡小程序开发笔记(一)_第14张图片
读书会活动打卡小程序开发笔记(一)_第15张图片
读书会活动打卡小程序开发笔记(一)_第16张图片
读书会活动打卡小程序开发笔记(一)_第17张图片
读书会活动打卡小程序开发笔记(一)_第18张图片
读书会活动打卡小程序开发笔记(一)_第19张图片
读书会活动打卡小程序开发笔记(一)_第20张图片
读书会活动打卡小程序开发笔记(一)_第21张图片
读书会活动打卡小程序开发笔记(一)_第22张图片
读书会活动打卡小程序开发笔记(一)_第23张图片
读书会活动打卡小程序开发笔记(一)_第24张图片
读书会活动打卡小程序开发笔记(一)_第25张图片

代码

git代码地址

你可能感兴趣的:(小程序java)