浏览代码

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

TonyKang 4 年之前
父节点
当前提交
00b1bf940f

+ 6 - 0
app/const/setting.js

@@ -23,6 +23,11 @@ const listPath = [
     { label_name: '金额概况', path: '/list/info', is_default: false }, // 金额概况
 ];
 
+// 登录方式
+const loginWay = {
+    normalPsw: 0, // 正常登录
+    extraPsw: 1, // 副密码登录
+};
 
 module.exports = {
     cType: {
@@ -30,4 +35,5 @@ module.exports = {
         text: cTypeStr,
     },
     listPath,
+    loginWay,
 };

+ 4 - 4
app/controller/change_controller.js

@@ -638,8 +638,8 @@ module.exports = app => {
                     // await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName));
                     const fileInfo = path.parse(stream.filename);
                     const create_time = Date.parse(new Date()) / 1000;
-                    const filepath = `public/upload/change/fujian_${create_time + index.toString() + fileInfo.ext}`;
-                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, 'app', filepath));
+                    const filepath = `app/public/upload/change/fujian_${create_time + index.toString() + fileInfo.ext}`;
+                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
                     await sendToWormhole(stream);
                     // 保存数据到att表
                     const fileData = {
@@ -683,7 +683,7 @@ module.exports = app => {
                 try {
                     const fileInfo = await ctx.service.changeAtt.getDataById(id);
                     if (fileInfo !== undefined && fileInfo !== '') {
-                        const fileName = path.join(this.app.baseDir, 'app', fileInfo.filepath);
+                        const fileName = path.join(this.app.baseDir, fileInfo.filepath);
                         // 解决中文无法下载问题
                         const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
                         let disposition = '';
@@ -727,7 +727,7 @@ module.exports = app => {
                 const fileInfo = await ctx.service.changeAtt.getDataById(data.id);
                 if (fileInfo !== undefined && fileInfo !== '') {
                     // 先删除文件
-                    await fs.unlinkSync(path.join(this.app.baseDir, './app', fileInfo.filepath));
+                    await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
                     // 再删除数据库
                     await ctx.service.changeAtt.deleteById(data.id);
                     responseData.data = '';

+ 5 - 0
app/controller/profile_controller.js

@@ -14,6 +14,7 @@ const smsTypeConst = require('../const/sms_type');
 const qr = require('qr-image');
 const path = require('path');
 const sendToWormhole = require('stream-wormhole');
+const loginWay = require('../const/setting').loginWay;
 
 module.exports = app => {
 
@@ -359,9 +360,13 @@ module.exports = app => {
             const passwordRule = ctx.service.projectAccount.rule('modifyPassword');
             const passwordJsValidator = await this.jsValidator.convert(passwordRule).setSelector('#password-form').build();
 
+            // 获取登录日志
+            const loginLogging = await ctx.service.loginLogging.getLoginLogs(ctx.session.sessionProject.id, ctx.session.sessionUser.accountId);
             const renderData = {
                 accountData,
                 passwordJsValidator,
+                loginLogging,
+                loginWay,
             };
             await this.layout('profile/safe.ejs', renderData);
         }

+ 4 - 4
app/controller/stage_controller.js

@@ -1304,8 +1304,8 @@ module.exports = app => {
                     // }
                     const fileInfo = path.parse(stream.filename);
                     const create_time = Date.parse(new Date()) / 1000;
-                    const filepath = `public/upload/${this.ctx.tender.id}/stage/fujian_${create_time + index.toString() + fileInfo.ext}`;
-                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, 'app', filepath));
+                    const filepath = `app/public/upload/${this.ctx.tender.id}/stage/fujian_${create_time + index.toString() + fileInfo.ext}`;
+                    await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
                     // console.log(await fs.existsSync(path.resolve(this.app.baseDir, 'app', filepath)));
                     // const fileInfo = path.parse(stream.filename);
                     // const fileName = 'stage' + create_time + '_' + index + fileInfo.ext;
@@ -1363,7 +1363,7 @@ module.exports = app => {
                 try {
                     const fileInfo = await ctx.service.stageAtt.getDataById(id);
                     if (fileInfo !== undefined && fileInfo !== '') {
-                        const fileName = path.join(this.app.baseDir, 'app', fileInfo.filepath);
+                        const fileName = path.join(this.app.baseDir, fileInfo.filepath);
                         // 解决中文无法下载问题
                         const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
                         let disposition = '';
@@ -1407,7 +1407,7 @@ module.exports = app => {
                         if (!ctx.helper.canPreview(fileInfo.fileext)) {
                             filepath = `/tender/${ctx.tender.id}/measure/stage/${ctx.params.order}/download/file/${fileInfo.id}`;
                         } else {
-                            filepath = '/' + filepath;
+                            filepath = filepath.replace(/^app|\/app/, '');
                         }
                         fileInfo.filepath && (responseData.data = { filepath });
                     }

+ 2 - 0
app/controller/tender_controller.js

@@ -75,6 +75,8 @@ module.exports = app => {
                 //     }
                 // }
                 tenderList.forEach(async t => {
+                    t.advance_tp = await this.ctx.service.advance.getSumAdvance(t.id);
+
                     if (t.ledger_status === auditConst.ledger.status.checked) {
                         t.lastStage = await this.ctx.service.stage.getLastestStage(t.id, true);
                         t.completeStage = await this.ctx.service.stage.getLastestCompleteStage(t.id);

+ 6 - 0
app/public/js/ledger.js

@@ -2046,6 +2046,12 @@ $(document).ready(function() {
             if (searchLedger) {
                 searchLedger.spread.refresh();
             }
+            if (errorList) {
+                errorList.spread.refresh();
+            }
+            if (checkList) {
+                checkList.spread.refresh();
+            }
         }
     });
     const stdLibCellDoubleClick = function (e, info) {

+ 8 - 1
app/public/js/stage.js

@@ -1710,6 +1710,10 @@ $(document).ready(() => {
                 detail.spread.refresh();
             }
             if (checkedChanges) checkedChanges.refresh();
+
+            if (errorList && errorList.spread) {
+                errorList.spread.refresh();
+            }
         }
     });
 
@@ -1889,6 +1893,9 @@ $(document).ready(() => {
                 detail.spread.refresh();
             }
             if (checkedChanges) checkedChanges.refresh();
+            if (errorList && errorList.spread) {
+                errorList.spread.refresh();
+            }
             window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
         }
     });
@@ -3057,7 +3064,7 @@ $(document).ready(() => {
     });
     // 上传附件
     $('#upload-file-btn').click(function () {
-        if (curAuditor && curAuditor.aid !== parseInt(cur_uid)) {
+        if (curAuditor && curAuditor.aid !== cur_uid) {
             return toastr.error('无法上传图片!');
         }
         const files = $('#upload-file')[0].files;

+ 4 - 0
app/public/js/stage_bwtz.js

@@ -19,11 +19,15 @@ $(document).ready(() => {
     sjsSettingObj.setFxTreeStyle(xmjSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(xmjSpreadSetting);
     SpreadJsObj.initSheet(xmjSheet, xmjSpreadSetting);
+    xmjSheet.frozenColumnCount(3);
+    xmjSheet.options.frozenlineColor = '#93b5e4';
 
     const unitSpread = SpreadJsObj.createNewSpread($('#unit-spread')[0]);
     const unitSheet = unitSpread.getActiveSheet();
     if (thousandth) sjsSettingObj.setTpThousandthFormat(xmjSpreadSetting);
     SpreadJsObj.initSheet(unitSheet, unitSpreadSetting);
+    unitSheet.frozenColumnCount(5);
+    unitSheet.options.frozenlineColor = '#93b5e4';
 
     const unitTreeObj = {
         loadCurUnitData: function () {

+ 5 - 0
app/public/js/tender_list_info.js

@@ -347,6 +347,10 @@ function recursiveGetTenderNodeHtml (node, arr, pid) {
     html.push('<td style="width: 7%" class="text-right">');
     html.push(node.pre_gather_tp);
     html.push('</td>');
+    // 预付款
+    html.push('<td style="width: 7%" class="text-right">');
+    html.push(node.advance_tp);
+    html.push('</td>');
     // 本期应付
     html.push('<td style="width: 7%" class="text-right">');
     html.push(node.yf_tp);
@@ -379,6 +383,7 @@ function getTenderTreeHtml () {
         html.push('<th class="text-center" style="width: 7%">', '截止本期变更', '</th>');
         html.push('<th class="text-center" style="width: 7%">', '截止本期完成', '</th>');
         html.push('<th class="text-center" style="width: 7%">', '截止上期完成', '</th>');
+        html.push('<th class="text-center" style="width: 7%">', '预付款', '<i class="fa fa-question-circle text-primary" data-placement="bottom" data-toggle="tooltip" data-original-title="预付款流程中截止本期金额"></i>', '</th>');
         html.push('<th class="text-center" style="width: 7%">', '本期应付', '</th>');
         html.push('<th class="text-center" style="width: 7%">', '截止本期应付', '</th>');
         html.push('</tr>', '</thead>');

+ 6 - 0
app/service/advance.js

@@ -71,6 +71,12 @@ module.exports = app => {
             return advance;
         }
 
+        async getSumAdvance(tid) {
+            const sql = 'Select sum(cur_amount) as tp From ' + this.tableName + ' where tid = ?';
+            const result = await this.db.queryOne(sql, [tid]);
+            return result ? result.tp : 0;
+        }
+
         /**
          * 创建一条新的记录
          * @param {String} type 类型: 开工预付款|材料预付款 (start|material)

+ 1 - 1
app/service/change_att.js

@@ -65,7 +65,7 @@ module.exports = app => {
                 if (!ctx.helper.canPreview(item.fileext)) {
                     item.filepath = `/change/download/file/${item.id}`;
                 } else {
-                    item.filepath = '/' + item.filepath;
+                    item.filepath = item.filepath.replace(/^app|\/app/, '');
                 }
                 return item;
             });

+ 132 - 0
app/service/login_logging.js

@@ -0,0 +1,132 @@
+'use strict';
+
+/**
+ * 登录日志-数据模型
+ *
+ * @author lanjianrong
+ * @date 2020/8/31
+ * @version
+ */
+const UAParser = require('ua-parser-js');
+
+module.exports = app => {
+    class LoginLogging extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'login_logging';
+        }
+
+        /**
+         * 创建记录
+         * @param {Object} payload - 载荷
+         */
+        async createLog(payload) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                transaction.insert(this.tableName, payload);
+                await transaction.commit();
+            } catch (error) {
+                await transaction.rollback();
+                throw error;
+            }
+        }
+
+        /**
+         * 创建登录日志
+         * @return {Boolean} 日志是否创建成功
+         */
+        async addLoginLog() {
+            const { ctx } = this;
+            const ip = ctx.header['x-real-ip'] ? ctx.header['x-real-ip'] : '';
+            const ipInfo = await this.getIpInfoFromApi(ip);
+            const parser = new UAParser(ctx.header['user-agent']);
+            const osInfo = parser.getOS();
+            const cpuInfo = parser.getCPU();
+            const browserInfo = parser.getBrowser();
+            const payload = {
+                os: `${osInfo.name} ${osInfo.version} ${cpuInfo.architecture}`,
+                browser: `${browserInfo.name} ${browserInfo.version}`,
+                ip,
+                address: ipInfo,
+                uid: ctx.session.sessionUser.accountId,
+                pid: ctx.session.sessionProject.id,
+            };
+            return await this.createLog(payload);
+        }
+
+        /**
+         * 根据ip请求获取详细地址
+         * @param {String} a_ip - ip地址
+         * @return {String} 详细地址
+         */
+        async getIpInfoFromApi(a_ip = '') {
+            if (!a_ip) return '';
+            if (a_ip === '127.0.0.1') return '服务器本机访问';
+            const { ip = '', region = '', city = '', isp = '' } = await this.sendRequest(a_ip);
+            let address = '';
+            region && (address += region + '省');
+            city && (address += city + '市 ');
+            isp && (address += isp + ' ');
+            ip && (address += `(${ip})`);
+            return address;
+        }
+
+        /**
+         * 发送请求获取详细地址
+         * @param {String} ip - ip地址
+         * @param {Number} max - 最大重试次数
+         * @return {Object} the result of request
+         * @private
+         */
+        async sendRequest(ip, max = 3) {
+            return new Promise(resolve => {
+                const start = () => {
+                    if (max <= 0) {
+                        resolve(); // 已达到最大重试次数,返回空的执行承若
+                    }
+                    max--;
+                    this.ctx.curl(`https://api01.aliyun.venuscn.com/ip?ip=${ip}`, {
+                        dateType: 'json',
+                        encoding: 'utf8',
+                        timeout: 2000,
+                        headers: {
+                            Authorization: 'APPCODE 85c64bffe70445c4af9df7ae31c7bfcc',
+                        },
+                    }).then(({ status, data }) => {
+                        if (status === 200) {
+                            const result = JSON.parse(data.toString()).data;
+                            if (!result.ip) {
+                                start();
+                            } else {
+                                max++;
+                                resolve(result);
+                            }
+                        } else {
+                            max--;
+                            start();
+                        }
+                    }).catch(() => {
+                        start();
+                    });
+                };
+                start();
+            });
+        }
+
+        /**
+         * 获取登录日志
+         * @param {Number} pid - 项目id
+         * @param {Number} uid - 用户id
+         * @return {Promise<Array>} 日志数组
+         */
+        async getLoginLogs(pid, uid) {
+            return this.db.select(this.tableName, {
+                where: { pid, uid },
+                orders: [['create_time', 'desc']],
+                columns: ['browser', 'create_time', 'ip', 'os', 'address'],
+                limit: 10, offset: 0,
+            });
+        }
+    }
+    return LoginLogging;
+};

+ 7 - 1
app/service/project_account.js

@@ -14,6 +14,7 @@ const SSO = require('../lib/sso');
 const SMS = require('../lib/sms');
 const SmsAliConst = require('../const/sms_alitemplate');
 const thirdPartyConst = require('../const/third_party');
+const loginWay = require('../const/setting').loginWay;
 
 module.exports = app => {
 
@@ -235,13 +236,18 @@ module.exports = app => {
                         projectInfo.gxby_status = thirdParty.gxby_option && thirdParty.gxby_option.status
                             ? thirdParty.gxby_option.status : thirdPartyConst.gxby;
 
-                        thirdParty.dagl_option = thirdParty.dagl_option ? JSON.parse(thirdParty.dagl_option): null;
+                        thirdParty.dagl_option = thirdParty.dagl_option ? JSON.parse(thirdParty.dagl_option) : null;
                         projectInfo.dagl = thirdParty.dagl;
                         projectInfo.dagl_status = thirdParty.dagl_option && thirdParty.dagl_option.status
                             ? thirdParty.dagl_option.status : thirdPartyConst.dagl;
                     }
                     this.ctx.session.sessionProject = projectInfo;
                     this.ctx.session.sessionProjectList = projectList;
+                    if (loginStatus === loginWay.normalPsw) {
+                        // 正常登录-记录登录日志
+                        await this.ctx.service.loginLogging.addLoginLog();
+                    }
+
                 }
             } catch (error) {
                 console.log(error);

+ 4 - 0
app/service/report.js

@@ -46,6 +46,10 @@ module.exports = app => {
                             runnableRst.push(service.tenderInfo.getTenderInfoEx(params.tender_id));
                             runnableKey.push(filter);
                             break;
+                        case 'advance_pay':
+                            runnableRst.push(service.advance.getAllDataByCondition({ where: {tid: params.tender_id}}));
+                            runnableKey.push(filter);
+                            break;
                         case 'deal_bills' :
                             runnableRst.push(service.dealBills.getDataByTenderId(params.tender_id));
                             runnableKey.push('deal_bills');

+ 3 - 11
app/service/stage_att.js

@@ -63,20 +63,12 @@ module.exports = app => {
          */
         async getDataByTenderIdAndStageId(tid, sid) {
             const { ctx } = this;
-            const sql = 'SELECT att.id, att.lid, att.uid, att.filepath, att.filename, att.fileext, att.filesize, att.re_upload, att.remark, att.in_time,' +
+            const sql = 'SELECT att.id, att.lid, att.uid, att.filename, att.fileext, att.filesize, att.re_upload, att.remark, att.in_time,' +
                 ' pa.name as `username`, leg.name as `lname`, leg.code as `code`, leg.ledger_id as `ledger_id`, leg.b_code as `b_code`' +
                 ' FROM ?? AS att,?? AS pa,?? AS leg' +
                 ' WHERE leg.id = att.lid AND pa.id = att.uid AND att.tid = ? AND att.sid = ? ORDER BY att.id DESC';
             const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, tid, sid];
-            const result = await this.db.query(sql, sqlParam);
-            return result.map(item => {
-                if (!ctx.helper.canPreview(item.fileext)) {
-                    item.filepath = `/tender/${ctx.tender.id}/measure/stage/${ctx.params.order}/download/file/${item.id}`;
-                } else {
-                    item.filepath = '/' + item.filepath;
-                }
-                return item;
-            });
+            return await this.db.query(sql, sqlParam);
         }
 
         /**
@@ -94,7 +86,7 @@ module.exports = app => {
             const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.ctx.service.ledger.tableName, id];
             const result = await this.db.queryOne(sql, sqlParam);
             if (!ctx.helper.canPreview(result.fileext)) result.filepath = `/tender/${ctx.tender.id}/measure/stage/${ctx.params.order}/download/file/${result.id}`;
-            else result.filepath = '/' + result.filepath;
+            else result.filepath = result.filepath.replace(/^app|\/app/, '');
             return result;
         }
     }

+ 1 - 1
app/view/material/audit_modal.ejs

@@ -678,10 +678,10 @@
 <% if (ctx.session.sessionUser.accountId === ctx.material.user_id && (ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo)) { %>
     <script>
         const accountGroup = JSON.parse('<%- JSON.stringify(accountGroup) %>');
+        const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
     </script>
 <% } %>
 <script>
-    const cur_uid  = parseInt('<%- ctx.session.sessionUser.accountId %>');
     $('.sp-location-list').on('shown.bs.modal', function () {
         const scrollBox = $(this).find('div[class="col-8 modal-height-500"]');
         const bdiv = (scrollBox.offset() && scrollBox.offset().top) || 0;

+ 49 - 0
app/view/profile/safe.ejs

@@ -22,6 +22,55 @@
                                 <p>SSO用户请到<a href="#">此处</a>修改密码</p>
                             <% } %>
                         </form>
+                        <!-- 访问日志 -->
+                        <% if(ctx.session.sessionUser.loginStatus === loginWay.normalPsw) { %>
+                            <div class="col-12 mt-5">
+                                <h4>访问日志</h4>
+                                <table class="table table-hover">
+                                    <thead>
+                                        <tr>
+                                            <th></th>
+                                            <th>系统</th>
+                                            <th>浏览器</th>
+                                            <th>登录时间</th>
+                                            <th>登录地址</th>
+                                        </tr>
+                                    </thead>
+                                    <tbody>
+                                        <% loginLogging.forEach((item, idx) => { %>
+                                            <tr>
+                                                <td><%- idx + 1 %></td>
+                                                <td><%- item.os %></td>
+                                                <td><%- item.browser %></td>
+                                                <td><%- ctx.helper.formatFullDate(item.create_time) %></td>
+                                                <td><%- item.address %></td>
+                                            </tr>
+                                        <% }) %>
+                                        <!-- <tr>
+                                            <td>1</td>
+                                            <td>Windows NT 10.0 64-bit</td>
+                                            <td>Chrome 55.0.2883.87 m (64-bit)</td>
+                                            <td>2017-01-12 09:09</td>
+                                            <td>广东省珠海市 电信(116.19.86.133)</td>
+                                        </tr>
+                                        <tr>
+                                            <td>2</td>
+                                            <td>Windows NT 10.0 64-bit</td>
+                                            <td>Chrome 55.0.2883.87 m (64-bit)</td>
+                                            <td>2017-01-12 09:09</td>
+                                            <td>广东省珠海市 电信(116.19.86.133)</td>
+                                        </tr>
+                                        <tr>
+                                            <td>3</td>
+                                            <td>Windows NT 10.0 64-bit</td>
+                                            <td>Chrome 55.0.2883.87 m (64-bit)</td>
+                                            <td>2017-01-12 09:09</td>
+                                            <td>广东省珠海市 电信(116.19.86.133)</td>
+                                        </tr> -->
+                                    </tbody>
+                                </table>
+                            </div>
+                        <% } %>
                     </div>
                 </div>
             </div>

+ 1 - 1
app/view/stage/audit_modal.ejs

@@ -802,7 +802,7 @@
 <% } %>
 <script>
     const preUrl = '<%- preUrl %>';
-    const cur_uid = parseInt('<%- ctx.session.sessionUser.accountdId %>');
+    const cur_uid = parseInt('<%- ctx.session.sessionUser.accountId %>');
     <% if (ctx.stage && ctx.url !== '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.stage.order) { %>
     const dataChecker = DataChecker({
         checkUrl: '/tender/<%- ctx.tender.id %>/measure/stage/<%- ctx.stage.order %>/check',

+ 4 - 0
app/view/stage/bwtz.ejs

@@ -104,6 +104,10 @@
             {title: '经济指标',  colSpan: '1', rowSpan: '2', field: 'dgn_price', hAlign: 2, width: 60, type: 'Number'},
             <% } %>
             {title: '台账金额', colSpan: '1', rowSpan: '2', field: 'total_price', hAlign: 2, width: 70, type: 'Number'},
+            <% if (ctx.tender.info.display.stage.realComplete) { %>
+            {title: '现场实际金额', colSpan: '1', rowSpan: '2', field: 'real_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '预计变更金额', colSpan: '1', rowSpan: '2', field: 'estimate_tp', hAlign: 2, width: 60, type: 'Number'},
+            <% } %>
             {title: '本期计量金额|合同计量', colSpan: '3|1', rowSpan: '1|1', field: 'contract_tp', hAlign: 2, width: 70, type: 'Number'},
             {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_tp', hAlign: 2, width: 70, type: 'Number'},
             {title: '|完成计量', colSpan: '|1', rowSpan: '|1', field: 'gather_tp', hAlign: 2, width: 70, type: 'Number'},

+ 0 - 5
app/view/stage/index.ejs

@@ -593,8 +593,3 @@
     const curAuditor = JSON.parse('<%- JSON.stringify(curAuditor) %>');
     const thirdParty = JSON.parse('<%- JSON.stringify(thirdParty) %>');
 </script>
-<% if (ctx.stage.status === auditConst.status.uncheck && ctx.session.sessionUser.accountId === ctx.stage.user_id) {%>
-<script>
-    const accountList = JSON.parse('<%- JSON.stringify(accountList) %>');
-</script>
-<% } %>

+ 25 - 0
builder_report_index_define.js

@@ -22,6 +22,30 @@ const tag = {
     tp: { type: 'tp' },
     up: { type: 'up' },
 };
+
+// 预付款
+const advance_pay = {
+    name: '预付款记录(advance_pay)',
+    remark: '',
+    id: 44,
+    key: 'advance_pay',
+    prefix: '预付款',
+    cols: [
+        { name: 'id', field: 'id', type: dataType.int },
+        { name: '创建者id', field: 'uuid', type: dataType.int },
+        { name: '审批次数', field: 'times', type: dataType.int },
+        { name: '审批状态', field: 'status', type: dataType.int },
+        { name: '期数索引', field: 'order', type: dataType.int },
+        { name: '类型', field: 'type', type: dataType.int },
+        { name: '支付比例', field: 'pay_ratio', type: dataType.currency },
+        { name: '本期金额', field: 'cur_amount', type: dataType.currency },
+        { name: '截止上期金额', field: 'prev_amount', type: dataType.currency },
+        { name: '截止本期金额', field: 'prev_total_amount', type: dataType.currency },
+        { name: '创建时间', field: 'create_time', type: dataType.str },
+        { name: '备注', field: 'remark', type: dataType.str },
+        { name: '结束时间', field: 'end_time', type: dataType.str },
+    ],
+};
 // 其他台账
 const stage_jgcl = {
     name: '期-甲供材料(mem_stage_jgcl)',
@@ -1189,6 +1213,7 @@ const exportTableDefine = async function(define) {
 };
 
 const defines = [
+    advance_pay,
     union_data,
     month_progress,
     stage_bills, stage_bills_compare,

+ 1 - 0
package.json

@@ -37,6 +37,7 @@
     "qr-image": "^3.2.0",
     "stream-to-array": "^2.3.0",
     "stream-wormhole": "^1.1.0",
+    "ua-parser-js": "^0.7.21",
     "ueditor": "^1.2.3",
     "uglify-es": "^3.3.9",
     "uglify-js": "^3.3.27",