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