关于小程序:从0100物业缴费支付小程序开发笔记

3次阅读

共计 6828 个字符,预计需要花费 18 分钟才能阅读完成。

设计背景

小区物业费用缴纳,公寓租金收取,出租屋租金收取等场景,大部分都是靠人工收取,而宽广业主和住户可能工夫或者工作忙碌,不能到现场付款,那么设计一个这样的小程序,不便物业公司进行账务收款,账务统计,节俭人力物力老本,不管在家中或者当地,都能够通过小程序间接缴费,不受工夫、地点束缚,操作简略,方便快捷

概要设计

数据字典


SheetModel.DB_STRUCTURE = {
    _pid: 'string|true',
    SHEET_ID: 'string|true',

    SHEET_TITLE: 'string|true|comment= 题目',
    SHEET_STATUS: 'int|true|default=1|comment= 状态 0= 未启用,1= 应用中',

    SHEET_CATE_ID: 'string|true|default=0|comment= 分类',
    SHEET_CATE_NAME: 'string|false|comment= 分类冗余',

    SHEET_ORDER: 'int|true|default=9999',
    SHEET_VOUCH: 'int|true|default=0',

    SHEET_FORMS: 'array|true|default=[]',
    SHEET_OBJ: 'object|true|default={}',

    SHEET_QR: 'string|false',
    SHEET_VIEW_CNT: 'int|true|default=0',


    SHEET_CNT: 'int|true|default=0',
    SHEET_PAY_CNT: 'int|true|default=0',
    SHEET_WAIT_CNT: 'int|true|default=0',
    SHEET_NO_CNT: 'int|true|default=0',

    SHEET_FEE: 'int|true|default=0',
    SHEET_PAY_FEE: 'int|true|default=0',
    SHEET_WAIT_FEE: 'int|true|default=0',

    SHEET_ADD_TIME: 'int|true',
    SHEET_EDIT_TIME: 'int|true',
    SHEET_ADD_IP: 'string|false',
    SHEET_EDIT_IP: 'string|false',
};
SheetDataModel.DB_STRUCTURE = {
    _pid: 'string|true',
    SHEET_DATA_ID: 'string|true', 
    SHEET_DATA_SHEET_ID: 'string|true|comment=FK',
    SHEET_DATA_SHEET_TITLE: 'string|false',


    SHEET_DATA_PAY_TRADE_NO: 'string|false|comment= 商家订单号 32 位',
    SHEET_DATA_PAY_STATUS: 'int|true|default=0|comment= 领取状态 0= 未领取 1= 已领取 99= 无需领取',
    SHEET_DATA_PAY_FEE: 'int|true|default=0|comment= 已领取费用 分',
    SHEET_DATA_PAY_TIME: 'int|true|default=0|comment= 领取工夫',

    SHEET_DATA_NAME: 'string|false| 姓名',
    SHEET_DATA_MOBILE: 'string|false| 手机号',
    SHEET_DATA_FEE: 'int|true|default=0|comment= 需领取费用 分',

    SHEET_DATA_FORMS: 'array|true|default=[]',
    SHEET_DATA_OBJ: 'object|true|default={}',

    SHEET_DATA_ADD_TIME: 'int|true',
    SHEET_DATA_EDIT_TIME: 'int|true',
    SHEET_DATA_ADD_IP: 'string|false',
    SHEET_DATA_EDIT_IP: 'string|false',
};

要害实现


    async getMySheetChartList(userId, time = 180) {let where = {};
        if (!config.IS_DEMO) {let user = await UserModel.getOne({ USER_MINI_OPENID: userId});
            if (!user) return null;

            where = {
                SHEET_DATA_PAY_STATUS: 1,
                SHEET_DATA_NAME: user.USER_NAME,
                SHEET_DATA_MOBILE: user.USER_MOBILE,
                'sheet.SHEET_STATUS': SheetModel.STATUS.COMM
            };
        }
        else {
            where = {
                SHEET_DATA_PAY_STATUS: 1,
                SHEET_DATA_NAME: 'Tom',
                SHEET_DATA_MOBILE: '14600000000',
                'sheet.SHEET_STATUS': SheetModel.STATUS.COMM
            };
        }


        time = Number(time);
        time = this._timestamp - time * 86400 * 1000;

        where.SHEET_DATA_PAY_TIME = ['>=', time];

        let fields = 'SHEET_DATA_PAY_TIME,SHEET_DATA_FORMS,SHEET_DATA_FEE,sheet.SHEET_TITLE';

        let orderBy = {
            'SHEET_DATA_PAY_TIME': 'desc',
            'SHEET_DATA_ADD_TIME': 'desc'
        };

        let joinParams = {
            from: SheetModel.CL,
            localField: 'SHEET_DATA_SHEET_ID',
            foreignField: '_id',
            as: 'sheet',
        };

        let list = await SheetDataModel.getListJoin(joinParams, where, fields, orderBy, 1, 200, false);
        list = list.list;

        if (list.length == 0) return null;

        let categories = [];
        let data = [];

        for (let k = 0; k < list.length; k++) {data.push(Number(list[k].SHEET_DATA_FEE / 100));
            categories.push(list[k].sheet.SHEET_TITLE.substr(0, 15));

            list[k].SHEET_DATA_PAY_TIME = timeUtil.timestamp2Time(list[k].SHEET_DATA_PAY_TIME);
        }
        return {categories, data, list: list.reverse() };

    }

    // 获得账单详情
    async getMySheetDataDetail(userId, sheetDataId) {let where = {};

        if (!config.IS_DEMO) {let user = await UserModel.getOne({ USER_MINI_OPENID: userId, USER_STATUS: UserModel.STATUS.COMM});
            if (!user) this.AppError('用户不存在或者状态异样');

            where = {
                _id: sheetDataId,
                SHEET_DATA_NAME: user.USER_NAME,
                SHEET_DATA_MOBILE: user.USER_MOBILE,
            }
        }
        else {
            where = {
                _id: sheetDataId,
                SHEET_DATA_NAME: 'Tom',
                SHEET_DATA_MOBILE: '14600000000',
            }
        }

        let sheetData = await SheetDataModel.getOne(where);
        if (!sheetData) return null;

        let sheet = await SheetModel.getOne({_id: sheetData.SHEET_DATA_SHEET_ID, SHEET_STATUS: SheetModel.STATUS.COMM});
        if (!sheet) this.AppError('领取我的项目不存在');

        sheetData.sheet = sheet;
        return sheetData;
    }

    /** 获得我的分页列表 */
    async getMySheetDataList(userId, {
        search, // 搜寻条件
        sortType, // 搜寻菜单
        sortVal, // 搜寻菜单
        orderBy, // 排序 
        page,
        size = 30,
        isTotal = true,
        oldTotal
    }) {


        orderBy = orderBy || {'SHEET_DATA_ADD_TIME': 'desc'};
        let fields = 'SHEET_DATA_PAY_TIME,SHEET_DATA_ADD_TIME,SHEET_DATA_FEE,SHEET_DATA_FORMS,SHEET_DATA_PAY_FEE,SHEET_DATA_PAY_STATUS,sheet.SHEET_TITLE,sheet.SHEET_OBJ';

        let where = {};
        if (!config.IS_DEMO) {let user = await UserModel.getOne({ USER_MINI_OPENID: userId});
            if (!user) return null;
            where = {
                SHEET_DATA_NAME: user.USER_NAME,
                SHEET_DATA_MOBILE: user.USER_MOBILE,
                'sheet.SHEET_STATUS': SheetModel.STATUS.COMM
            };
        }
        else {
            where = {
                SHEET_DATA_NAME: 'Tom',
                SHEET_DATA_MOBILE: '14600000000',
                'sheet.SHEET_STATUS': SheetModel.STATUS.COMM
            };
        }

        if (util.isDefined(search) && search) {where['SHEET_DATA_SHEET_TITLE'] = {
                $regex: '.*' + search,
                $options: 'i'
            };
        } else if (sortType) {
            // 搜寻菜单
            switch (sortType) {
                case 'status': {where['SHEET_DATA_PAY_STATUS'] = Number(sortVal);
                    break;
                }
                case 'sort': { // 按工夫倒序
                    orderBy = this.fmtOrderBySort(sortVal, 'SHEET_DATA_ADD_TIME');
                    break;
                }

            }
        }

        let joinParams = {
            from: SheetModel.CL,
            localField: 'SHEET_DATA_SHEET_ID',
            foreignField: '_id',
            as: 'sheet',
        };

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

        return result;
    }

    async statSheetData(sheetId) {
        let where = {SHEET_DATA_SHEET_ID: sheetId}

        // 总数
        let cnt = await SheetDataModel.count(where);


        // 总费用
        let fee = await SheetDataModel.sum(where, 'SHEET_DATA_FEE');


        // 已领取记录
        let wherePayCnt = {
            SHEET_DATA_SHEET_ID: sheetId,
            SHEET_DATA_PAY_STATUS: 1,
        }
        let payCnt = await SheetDataModel.count(wherePayCnt);

        // 毋庸领取
        let whereNoCnt = {
            SHEET_DATA_SHEET_ID: sheetId,
            SHEET_DATA_PAY_STATUS: 99,
        }
        let noCnt = await SheetDataModel.count(whereNoCnt);

        // 已领取金额
        let wherePayFee = {
            SHEET_DATA_SHEET_ID: sheetId,
            SHEET_DATA_PAY_STATUS: 1,
        }
        let payFee = await SheetDataModel.sum(wherePayFee, 'SHEET_DATA_PAY_FEE');

        let waitCnt = cnt - payCnt - noCnt;
        let waitFee = fee - payFee;
        let data = {
            SHEET_CNT: cnt,
            SHEET_PAY_CNT: payCnt,
            SHEET_WAIT_CNT: waitCnt,
            SHEET_NO_CNT: noCnt,

            SHEET_FEE: fee,
            SHEET_PAY_FEE: payFee,
            SHEET_WAIT_FEE: waitFee
        }
        await SheetModel.edit(sheetId, data);
        return {cnt, payCnt, waitCnt, noCnt, fee, payFee, waitFee};
    }

    // 修改本地订单状态
    async fixSheetDataPay(tradeNo, sheetId) {if (!tradeNo) {
            // 无领取号空单
            let data = {
                SHEET_DATA_PAY_STATUS: 0,
                SHEET_DATA_PAY_TRADE_NO: '',
                SHEET_DATA_PAY_FEE: 0,
                SHEET_DATA_PAY_TIME: 0,
            }

            await SheetDataModel.edit({SHEET_DATA_PAY_TRADE_NO: tradeNo}, data);

            // 从新统计
            this.statSheetData(sheetId);

            return false;
        }

        let payService = new PayService();
        if (!await payService.fixPayResult(tradeNo)) {
            // 敞开未领取单
            payService.closePay(tradeNo);

            // 未领取
            let data = {
                SHEET_DATA_PAY_STATUS: 0,
                SHEET_DATA_PAY_TRADE_NO: '',
                SHEET_DATA_PAY_FEE: 0,
                SHEET_DATA_PAY_TIME: 0,
            }

            await SheetDataModel.edit({SHEET_DATA_PAY_TRADE_NO: tradeNo}, data);

            // 从新统计
            this.statSheetData(sheetId);

            return false;
        }

        // 已领取
        let pay = await PayModel.getOne({PAY_TRADE_NO: tradeNo});
        if (!pay) this.AppError('领取流水异样,请核查');

        // 更新领取信息
        let data = {
            SHEET_DATA_PAY_STATUS: 1,
            SHEET_DATA_PAY_TRADE_NO: tradeNo,
            SHEET_DATA_PAY_FEE: pay.PAY_TOTAL_FEE,
            SHEET_DATA_PAY_TIME: pay.PAY_END_TIME,
        }
        await SheetDataModel.edit({SHEET_DATA_PAY_TRADE_NO: tradeNo}, data);


        // 从新统计
        this.statSheetData(sheetId);
        return true;
    }


    // 预领取
    async prepay(userId, sheetDataId) {this.AppError('[ 物业缴费] 该性能暂不凋谢,如有须要请加作者微信:cclinux0730');
    }

    // 查问领取后果
    async queryPayResult(sheetDataId) {let sheetData = await SheetDataModel.getOne(sheetDataId);
        if (!sheetData) return {status: 0};

        return {status: sheetData.SHEET_DATA_PAY_STATUS}
    }

住户端 UI 设计

治理端 UI 设计

源码

github 源码下载

正文完
 0