Notes on the development of a small program for college admissions and registration for the elderly based on WeChat applet

business background

The University for the Elderly is a classroom for "empty-nest" seniors to update their knowledge, a place to exercise and nourish their minds, a playground for fun and entertainment, a platform for making friends, and a base for intellectual development! Today, with the popularization of mobile phone networks, the majority of the elderly can learn about training classes and courses, register information, and check the registration results through small programs without leaving their homes. The background staff can also collect registration materials through electronic means, saving a lot of money. The tired time of the elderly rushing around also improves the work efficiency of the elderly university.

functional planning

The main functions include announcement notification, classroom style, training class list, training course introduction, my registration, background training project management, registration list management, background notification management, background administrator management and other functions

Registration module

  • Registration project management: start / deadline / whether to review / whether to cancel / whether to modify / number of people and other parameters can be flexibly set, and can customize the data items filled in by the elderly
  • Registration review: You can set whether to review the registration list. If the review fails, you can prompt the user to improve the information
  • My registration record: can modify or cancel my registration record
  • Detailed registration data: support the export of registration list data to Excel, printing

Technical selection

  • This project is developed using the WeChat applet platform.
  • Using Tencent's specialized small program cloud development technology, cloud resources include cloud functions, databases, bandwidth, storage space, timers, etc. The resource quota is cheap and can be built without domain names and servers.
  • The applet itself is ready-to-go, suitable for the use of small tools, and also suitable for rapid development and iteration.
  • The cloud development technology adopts Tencent's internal link, there is no risk of being hacked, no DDOS attack, saving firewall costs, high security and maintenance-free.
  • Resource carrying capacity can be flexibly expanded at any time according to business development needs.

Database Design

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

    ENROLL_JOIN_IS_ADMIN: 'int|true|default=0|comment=Whether the administrator added 0/1',

    ENROLL_JOIN_USER_ID: 'string|true|comment=user ID', 
    ENROLL_JOIN_FORMS: 'array|true|default=[]|comment=form',

    ENROLL_JOIN_STATUS: 'int|true|default=1|comment=Status 0=pending review 1=Sign up successfully, 99=Not reviewed',
    ENROLL_JOIN_REASON: 'string|false|comment=Review the reasons for rejection or cancellation',

    ENROLL_JOIN_LAST_TIME: 'int|true|default=0', 
    
    ENROLL_JOIN_ADD_TIME: 'int|true',
    ENROLL_JOIN_EDIT_TIME: 'int|true',
    ENROLL_JOIN_ADD_IP: 'string|false',
    ENROLL_JOIN_EDIT_IP: 'string|false',
};

UserModel.DB_STRUCTURE = {
    _pid: 'string|true',
    USER_ID: 'string|true',

    USER_MINI_OPENID: 'string|true|comment=Applets openid',
    USER_STATUS: 'int|true|default=1|comment=Status 0=pending review,1=normal,8=Not reviewed,9=disabled',
    USER_CHECK_REASON: 'string|false|comment=Reasons not reviewed',

    USER_NAME: 'string|false|comment=User's Nickname',
    USER_MOBILE: 'string|false|comment=contact number',

    USER_FORMS: 'array|true|default=[]',
    USER_OBJ: 'object|true|default={}',

    USER_LOGIN_CNT: 'int|true|default=0|comment=number of logins',
    USER_LOGIN_TIME: 'int|false|comment=Last login time',


    USER_ADD_TIME: 'int|true',
    USER_ADD_IP: 'string|false',

    USER_EDIT_TIME: 'int|true',
    USER_EDIT_IP: 'string|false',
}


core implementation

class EnrollService extends BaseProjectService {

    // Get current registration status
    getJoinStatusDesc(enroll) {
        let timestamp = this._timestamp;

        if (enroll.ENROLL_STATUS == 0)
            return 'stopped';
        else if (enroll.ENROLL_START > timestamp)
            return 'has not started';
        else if (enroll.ENROLL_END <= timestamp)
            return 'has expired';
        else if (enroll.ENROLL_MAX_CNT > 0
            && enroll.ENROLL_JOIN_CNT >= enroll.ENROLL_MAX_CNT)
            return 'full';
        else
            return 'processing';
    }

    /** Browsing information */
    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);

        // Determine if there is a registration
        let whereJoin = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: id,
            ENROLL_JOIN_STATUS: ['in', [EnrollJoinModel.STATUS.WAIT, EnrollJoinModel.STATUS.SUCC]]
        }
        let enrollJoin = await EnrollJoinModel.getOne(whereJoin);
        if (enrollJoin) {
            enroll.myEnrollJoinId = enrollJoin._id;
            enroll.myEnrollJoinTag = (enrollJoin.ENROLL_JOIN_STATUS == EnrollJoinModel.STATUS.WAIT) ? 'pending review' : 'filled in';
        }
        else {
            enroll.myEnrollJoinId = '';
            enroll.myEnrollJoinTag = '';
        }

        return enroll;
    }


    /** Get paginated list */
    async getEnrollList({
        search, // search condition
        sortType, // search menu
        sortVal, // search menu
        orderBy, // sort 
        page,
        size,
        isTotal = true,
        oldTotal
    }) {

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

        let where = {};
        where.and = {
            _pid: this.getProjectId() //Complex queries are marked with PID s here
        };

        where.and.ENROLL_STATUS = EnrollModel.STATUS.COMM; // state  

        if (util.isDefined(search) && search) {
            where.or = [{
                ENROLL_TITLE: ['like', search]
            },];
        } else if (sortType && util.isDefined(sortVal)) {
            // search menu
            switch (sortType) {
                case 'cateId': {
                    if (sortVal) where.and.ENROLL_CATE_ID = String(sortVal);
                    break;
                }
                case 'sort': {
                    orderBy = this.fmtOrderBySort(sortVal, 'ENROLL_ADD_TIME');
                    break;
                }

            }
        }

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

    /** Get my registration tab list */
    async getMyEnrollJoinList(userId, {
        search, // search condition
        sortType, // search menu
        sortVal, // search menu
        orderBy, // sort 
        page,
        size,
        isTotal = true,
        oldTotal
    }) {
        orderBy = orderBy || {
            'ENROLL_JOIN_ADD_TIME': 'desc'
        };
        let fields = 'ENROLL_JOIN_LAST_TIME,ENROLL_JOIN_REASON,ENROLL_JOIN_ENROLL_ID,ENROLL_JOIN_STATUS,ENROLL_JOIN_ADD_TIME,enroll.ENROLL_TITLE,enroll.ENROLL_EDIT_SET,enroll.ENROLL_CANCEL_SET';

        let where = {
            ENROLL_JOIN_USER_ID: userId
        };

        if (util.isDefined(search) && search) {
            where['enroll.ENROLL_TITLE'] = {
                $regex: '.*' + search,
                $options: 'i'
            };
        } else if (sortType) {
            // search menu
            switch (sortType) {
                case 'timedesc': { //in reverse chronological order
                    orderBy = {
                        'ENROLL_JOIN_ADD_TIME': 'desc'
                    };
                    break;
                }
                case 'timeasc': { //in chronological order
                    orderBy = {
                        'ENROLL_JOIN_ADD_TIME': 'asc'
                    };
                    break;
                }
                case 'succ': {
                    where.ENROLL_JOIN_STATUS = EnrollJoinModel.STATUS.SUCC;
                    break;
                }
                case 'wait': {
                    where.ENROLL_JOIN_STATUS = EnrollJoinModel.STATUS.WAIT;
                    break;
                }
                case 'cancel': {
                    where.ENROLL_JOIN_STATUS = EnrollJoinModel.STATUS.ADMIN_CANCEL;
                    break;
                }
            }
        }

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

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

        return result;
    }

    /** Get my registration details */
    async getMyEnrollJoinDetail(userId, enrollJoinId) {

        let fields = '*';

        let where = {
            _id: enrollJoinId,
            ENROLL_JOIN_USER_ID: userId
        };
        let enrollJoin = await EnrollJoinModel.getOne(where, fields);
        if (enrollJoin) {
            enrollJoin.enroll = await EnrollModel.getOne(enrollJoin.ENROLL_JOIN_ENROLL_ID, 'ENROLL_TITLE');
        }
        return enrollJoin;
    }

    //################## Registration 
    // register 
    async enrollJoin(userId, enrollId, forms) {

        // Whether the registration is over
        let whereEnroll = {
            _id: enrollId,
            ENROLL_STATUS: EnrollModel.STATUS.COMM
        }
        let enroll = await EnrollModel.getOne(whereEnroll);
        if (!enroll)
            this.AppError('Should' + ENROLL_NAME + 'does not exist or has stopped');

        // whether to start registration
        if (enroll.ENROLL_START > this._timestamp)
            this.AppError('Should' + ENROLL_NAME + 'not yet started');

        // Has the registration deadline passed?
        if (enroll.ENROLL_END < this._timestamp)
            this.AppError('Should' + ENROLL_NAME + 'has expired');


        // Is the number full
        if (enroll.ENROLL_MAX_CNT > 0) {
            let whereCnt = {
                ENROLL_JOIN_ENROLL_ID: enrollId,
                ENROLL_JOIN_STATUS: ['in', [EnrollJoinModel.STATUS.WAIT, EnrollJoinModel.STATUS.SUCC]]
            }
            let cntJoin = await EnrollJoinModel.count(whereCnt);
            if (cntJoin >= enroll.ENROLL_MAX_CNT)
                this.AppError('Should' + ENROLL_NAME + 'full');
        }

        // have you registered
        let whereMy = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_STATUS: ['in', [EnrollJoinModel.STATUS.WAIT, EnrollJoinModel.STATUS.SUCC]]
        }
        let my = await EnrollJoinModel.getOne(whereMy);
        if (my) {
            if (my.ENROLL_JOIN_STATUS == EnrollJoinModel.STATUS.WAIT)
                this.AppError('You have already filled in the form and are waiting for review, so there is no need to repeat the form');
            else
                this.AppError('You have already filled in the form successfully, no need to repeat the form');
        }

        // warehousing
        let data = {
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_STATUS: (enroll.ENROLL_CHECK_SET == 0) ? EnrollJoinModel.STATUS.SUCC : EnrollJoinModel.STATUS.WAIT,
            ENROLL_JOIN_FORMS: forms
        }

        let enrollJoinId = await EnrollJoinModel.insert(data);

        // total quantity
        this.statEnrollJoin(enrollId);

        let check = enroll.ENROLL_CHECK_SET;

        return { enrollJoinId, check }

    }


    // Amend the registration 
    async enrollJoinEdit(userId, enrollId, enrollJoinId, forms) {
        let whereJoin = {
            _id: enrollJoinId,
            ENROLL_JOIN_USER_ID: userId,
            ENROLL_JOIN_ENROLL_ID: enrollId,
            ENROLL_JOIN_STATUS: ['in', [EnrollJoinModel.STATUS.WAIT, EnrollJoinModel.STATUS.SUCC]],
        }
        let enrollJoin = await EnrollJoinModel.getOne(whereJoin);
        if (!enrollJoin)
            this.AppError('Should' + ENROLL_NAME + 'The record does not exist or has been cancelled by the system');

        // Whether the registration is over
        let whereEnroll = {
            _id: enrollId,
            ENROLL_STATUS: EnrollModel.STATUS.COMM
        }
        let enroll = await EnrollModel.getOne(whereEnroll);
        if (!enroll)
            this.AppError('Should' + ENROLL_NAME + 'does not exist or has stopped');


        if (enroll.ENROLL_EDIT_SET == 0)
            this.AppError('Should' + ENROLL_NAME + 'Modification of data is not allowed');

        if (enroll.ENROLL_EDIT_SET == 2 && enroll.ENROLL_END < this._timestamp)
            this.AppError('Should' + ENROLL_NAME + 'Expired, cannot modify the information');

        if (enroll.ENROLL_EDIT_SET == 3
            && enroll.ENROLL_CHECK_SET == 1
            && enrollJoin.ENROLL_JOIN_STATUS == EnrollJoinModel.STATUS.SUCC
        )
            this.AppError('Should' + ENROLL_NAME + 'It has passed the review and cannot be modified');


        let data = {
            ENROLL_JOIN_FORMS: forms,
            ENROLL_JOIN_LAST_TIME: this._timestamp,
        }
        await EnrollJoinModel.edit(whereJoin, data);

    }

    async statEnrollJoin(id) {
        let where = {
            ENROLL_JOIN_ENROLL_ID: id,
            ENROLL_JOIN_STATUS: ['in', [EnrollJoinModel.STATUS.WAIT, EnrollJoinModel.STATUS.SUCC]]
        }
        let cnt = await EnrollJoinModel.count(where);

        await EnrollModel.edit(id, { ENROLL_JOIN_CNT: cnt });
    }

    /**  Get key information before registering */
    async detailForEnrollJoin(userId, enrollId, enrollJoinId = '') {
        let fields = 'ENROLL_JOIN_FORMS, ENROLL_TITLE';

        let where = {
            _id: enrollId,
            ENROLL_STATUS: EnrollModel.STATUS.COMM
        }
        let enroll = await EnrollModel.getOne(where, fields);
        if (!enroll)
            this.AppError('Should' + ENROLL_NAME + 'does not exist');



        let joinMy = null;
        if (enrollJoinId) {
            // edit
            let whereMy = {
                ENROLL_JOIN_USER_ID: userId,
                _id: enrollJoinId
            }
            joinMy = await EnrollJoinModel.getOne(whereMy);
        }
        else {
            // Take out my last filled form 
            /*
            let whereMy = {
                ENROLL_JOIN_USER_ID: userId,
            }
            let orderByMy = {
                ENROLL_JOIN_ADD_TIME: 'desc'
            }
            joinMy = await EnrollJoinModel.getOne(whereMy, 'ENROLL_JOIN_FORMS', orderByMy);*/
        }

        let myForms = joinMy ? joinMy.ENROLL_JOIN_FORMS : [];
        enroll.myForms = myForms;
        return enroll;
    }

    /** Cancel my registration Only successful and pending approval can be cancelled Cancellation is to delete the record */
    async cancelMyEnrollJoin(userId, enrollJoinId) {
        let where = {
            ENROLL_JOIN_USER_ID: userId,
            _id: enrollJoinId,
            ENROLL_JOIN_STATUS: ['in', [EnrollJoinModel.STATUS.WAIT, EnrollJoinModel.STATUS.SUCC]]
        };
        let enrollJoin = await EnrollJoinModel.getOne(where);

        if (!enrollJoin) {
            this.AppError('No records to cancel found');
        }

        let enroll = await EnrollModel.getOne(enrollJoin.ENROLL_JOIN_ENROLL_ID);
        if (!enroll)
            this.AppError('Should' + ENROLL_NAME + 'does not exist');

        if (enroll.ENROLL_CANCEL_SET == 0)
            this.AppError('Should' + ENROLL_NAME + 'Can't cancel');


        if (enroll.ENROLL_CANCEL_SET == 2 && enroll.ENROLL_END < this._timestamp)
            this.AppError('Should' + ENROLL_NAME + 'It has expired and cannot be cancelled');

        if (enroll.ENROLL_CANCEL_SET == 3
            && enroll.ENROLL_CHECK_SET == 1
            && enrollJoin.ENROLL_JOIN_STATUS == EnrollJoinModel.STATUS.SUCC
        )
            this.AppError('Should' + ENROLL_NAME + 'Approved and cannot be cancelled');

        await EnrollJoinModel.del(where);

        this.statEnrollJoin(enrollJoin.ENROLL_JOIN_ENROLL_ID);

    }

}

UI Design







Background implementation






code

code

Tags: Mini Program webapp

Posted by abid786 on Mon, 10 Oct 2022 05:01:02 +0300