设计背景

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

概要设计

数据字典

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源码下载