Просмотр исходного кода

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

Tony Kang 6 часов назад
Родитель
Сommit
d3f54037c5

+ 50 - 1
app/controller/dashboard_controller.js

@@ -48,6 +48,10 @@ module.exports = app => {
             const allAuditCostStageBook = await ctx.service.costStageAudit.getAuditStage('book', ctx.session.sessionUser.accountId);
             const allAuditCostStageBook = await ctx.service.costStageAudit.getAuditStage('book', ctx.session.sessionUser.accountId);
             const allAuditCostStageAnalysis = await ctx.service.costStageAudit.getAuditStage('analysis', ctx.session.sessionUser.accountId);
             const allAuditCostStageAnalysis = await ctx.service.costStageAudit.getAuditStage('analysis', ctx.session.sessionUser.accountId);
             const allAuditCostStageDuty = await ctx.service.costStageAudit.getAuditStage('duty', ctx.session.sessionUser.accountId);
             const allAuditCostStageDuty = await ctx.service.costStageAudit.getAuditStage('duty', ctx.session.sessionUser.accountId);
+            // 获取所有待审批的合同列表
+            const allAuditContracts = await ctx.service.contractSpAudit.getAuditContract(ctx.session.sessionUser.accountId);
+            // 获取所有待审批的合同支付(回款)列表
+            const allAuditContractPays = await ctx.service.contractSpAudit.getAuditContractPay(ctx.session.sessionUser.accountId);
             const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
             const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
             const auditShenpiTenders = await ctx.service.ledgerAudit.getDonesByAudit(ctx.session.sessionUser.accountId);
             const auditShenpiTenders = await ctx.service.ledgerAudit.getDonesByAudit(ctx.session.sessionUser.accountId);
             const auditShenpiStages = await ctx.service.stageAudit.getDonesByAudit(ctx.session.sessionUser.accountId);
             const auditShenpiStages = await ctx.service.stageAudit.getDonesByAudit(ctx.session.sessionUser.accountId);
@@ -68,6 +72,8 @@ module.exports = app => {
             const auditShenpiCostStageBook = await ctx.service.costStageAudit.getDonesByAudit('book', ctx.session.sessionUser.accountId);
             const auditShenpiCostStageBook = await ctx.service.costStageAudit.getDonesByAudit('book', ctx.session.sessionUser.accountId);
             const auditShenpiCostStageAnalysis = await ctx.service.costStageAudit.getDonesByAudit('analysis', ctx.session.sessionUser.accountId);
             const auditShenpiCostStageAnalysis = await ctx.service.costStageAudit.getDonesByAudit('analysis', ctx.session.sessionUser.accountId);
             const auditShenpiCostStageDuty = await ctx.service.costStageAudit.getDonesByAudit('duty', ctx.session.sessionUser.accountId);
             const auditShenpiCostStageDuty = await ctx.service.costStageAudit.getDonesByAudit('duty', ctx.session.sessionUser.accountId);
+            const auditShenpiContracts = await ctx.service.contractSpAudit.getDonesByAudit(ctx.session.sessionUser.accountId);
+            const auditShenpiContractPays = await ctx.service.contractSpAudit.getDonesByAuditPay(ctx.session.sessionUser.accountId);
             const dashboardStatus = {
             const dashboardStatus = {
                 all: 0,
                 all: 0,
                 dashboard: 0,
                 dashboard: 0,
@@ -93,6 +99,9 @@ module.exports = app => {
                     costStageBook: 0,
                     costStageBook: 0,
                     costStageAnalysis: 0,
                     costStageAnalysis: 0,
                     costStageDuty: 0,
                     costStageDuty: 0,
+                    contract: 0,
+                    contractPay: 0,
+                    contractReceipt: 0,
                 },
                 },
             };
             };
             let noticeList = [];
             let noticeList = [];
@@ -138,6 +147,13 @@ module.exports = app => {
                 noticeList.push(...ctx.helper.addKeyValue4ObjArray(spCostStageAnalysis, 'shenpi_type', 'costStageAnalysis'));
                 noticeList.push(...ctx.helper.addKeyValue4ObjArray(spCostStageAnalysis, 'shenpi_type', 'costStageAnalysis'));
                 const spCostStageDuty = subProject.page_show.cost ? ctx.helper._.filter(auditShenpiCostStageDuty, { spid: subProject.id }) : [];
                 const spCostStageDuty = subProject.page_show.cost ? ctx.helper._.filter(auditShenpiCostStageDuty, { spid: subProject.id }) : [];
                 noticeList.push(...ctx.helper.addKeyValue4ObjArray(spCostStageDuty, 'shenpi_type', 'costStageDuty'));
                 noticeList.push(...ctx.helper.addKeyValue4ObjArray(spCostStageDuty, 'shenpi_type', 'costStageDuty'));
+                const spContracts = subProject.page_show.openContract ? ctx.helper._.filter(auditShenpiContracts, { spid: subProject.id }) : [];
+                noticeList.push(...ctx.helper.addKeyValue4ObjArray(spContracts, 'shenpi_type', 'contract'));
+                const spContractPays = (subProject.page_show.openContractTenderShenpi || subProject.page_show.openContractSubProjectShenpi) ? ctx.helper._.filter(auditShenpiContractPays, { spid: subProject.id }) : [];
+                for (const pay of spContractPays) {
+                    pay.shenpi_type = pay.contract_type === 2 ? 'contractReceipt' : 'contractPay';
+                }
+                noticeList.push(...spContractPays);
             }
             }
             const noticeDayList = [];
             const noticeDayList = [];
             noticeList = ctx.helper._.orderBy(noticeList, ['shenpi_time'], ['desc']);
             noticeList = ctx.helper._.orderBy(noticeList, ['shenpi_time'], ['desc']);
@@ -187,6 +203,20 @@ module.exports = app => {
             dashboardShenpis.push(...auditCostStageAnalysis);
             dashboardShenpis.push(...auditCostStageAnalysis);
             const auditCostStageDuty = await this.auditSet(ctx, allAuditCostStageDuty, subProjects, dashboardStatus, 'costStageDuty');
             const auditCostStageDuty = await this.auditSet(ctx, allAuditCostStageDuty, subProjects, dashboardStatus, 'costStageDuty');
             dashboardShenpis.push(...auditCostStageDuty);
             dashboardShenpis.push(...auditCostStageDuty);
+
+            // 处理合同审批数据,转换为统一格式
+            const auditContracts = await this.auditSet(ctx, allAuditContracts, subProjects, dashboardStatus, 'contract');
+            dashboardShenpis.push(...auditContracts);
+
+            // 处理合同支付/回款审批数据,转换为统一格式
+            const auditContractPays = await this.auditSet(ctx, allAuditContractPays, subProjects, dashboardStatus, 'contractPay');
+            // 将回款数据的shenpi_type改为contractReceipt
+            for (const pay of auditContractPays) {
+                if (pay.contract_type === 2) {
+                    pay.shenpi_type = 'contractReceipt';
+                }
+            }
+            dashboardShenpis.push(...auditContractPays);
             // console.log(ctx.helper._.orderBy(dashboardShenpis, ['start_audit', 'shenpi_time'], ['desc', 'desc']));
             // console.log(ctx.helper._.orderBy(dashboardShenpis, ['start_audit', 'shenpi_time'], ['desc', 'desc']));
             const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
             const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
             // 获取销售人员数据
             // 获取销售人员数据
@@ -346,6 +376,15 @@ module.exports = app => {
                             if (!sp.page_show.cost) closeType = true;
                             if (!sp.page_show.cost) closeType = true;
                             calcTime = t.create_time;
                             calcTime = t.create_time;
                             break;
                             break;
+                        case 'contract':
+                            if (!sp.page_show.openContract) closeType = true;
+                            calcTime = t.begin_time;
+                            break;
+                        case 'contractPay':
+                        case 'contractReceipt':
+                            if (!sp.page_show.openContractTenderShenpi && !sp.page_show.openContractSubProjectShenpi) closeType = true;
+                            calcTime = t.begin_time;
+                            break;
                         default:
                         default:
                             closeType = true;
                             closeType = true;
                     }
                     }
@@ -361,7 +400,7 @@ module.exports = app => {
                             dashboardStatus.early += 1;
                             dashboardStatus.early += 1;
                         }
                         }
                     }
                     }
-                    const calcType = type === 'stageAss' ? 'stage' : type;
+                    const calcType = type === 'stageAss' ? 'stage' : (type === 'contractReceipt' ? 'contractReceipt' : (type === 'contractPay' ? 'contractPay' : type));
                     dashboardStatus.shenpi[calcType] += 1;
                     dashboardStatus.shenpi[calcType] += 1;
                     t.shenpi_time = calcTime;
                     t.shenpi_time = calcTime;
                     t.shenpi_type = type;
                     t.shenpi_type = type;
@@ -399,6 +438,11 @@ module.exports = app => {
             const auditCostStageBook = ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getAuditStage('book', ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
             const auditCostStageBook = ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getAuditStage('book', ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
             const auditCostStageAnalysis = ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getAuditStage('analysis', ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
             const auditCostStageAnalysis = ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getAuditStage('analysis', ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
             const auditCostStageDuty = ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getAuditStage('duty', ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
             const auditCostStageDuty = ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getAuditStage('duty', ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
+            // 获取待审批的合同列表
+            const auditContracts = ctx.subProject.page_show.openContract ? await ctx.service.contractSpAudit.getAuditContract(ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
+            // 获取待审批的合同支付(回款)列表
+            const auditContractPays = (ctx.subProject.page_show.openContractTenderShenpi || ctx.subProject.page_show.openContractSubProjectShenpi) ? await ctx.service.contractSpAudit.getAuditContractPay(ctx.session.sessionUser.accountId, ctx.subProject.id) : [];
+            
             const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
             const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
             const noticeList = await ctx.service.noticePush.getNotice(ctx.session.sessionProject.id, pa.id, ctx.subProject.id);
             const noticeList = await ctx.service.noticePush.getNotice(ctx.session.sessionProject.id, pa.id, ctx.subProject.id);
             const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
             const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
@@ -432,6 +476,7 @@ module.exports = app => {
             if (ctx.subProject.page_show.safeInspection) shenpi_count.push({ count: await ctx.service.safeInspectionAudit.getCountByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id), name: '安全巡检' });
             if (ctx.subProject.page_show.safeInspection) shenpi_count.push({ count: await ctx.service.safeInspectionAudit.getCountByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id), name: '安全巡检' });
             if (ctx.subProject.page_show.safePayment) shenpi_count.push({ count: await ctx.service.safeStageAudit.getCountByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id), name: '安全计量' });
             if (ctx.subProject.page_show.safePayment) shenpi_count.push({ count: await ctx.service.safeStageAudit.getCountByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id), name: '安全计量' });
             if (ctx.subProject.page_show.phasePay) shenpi_count.push({ count: await ctx.service.phasePayAudit.getCountByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id), name: '合同支付' });
             if (ctx.subProject.page_show.phasePay) shenpi_count.push({ count: await ctx.service.phasePayAudit.getCountByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id), name: '合同支付' });
+            if (ctx.subProject.page_show.openContract) shenpi_count.push({ count: await ctx.service.contractSpAudit.getCountByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id), name: '合同审批' });
             if (ctx.subProject.page_show.cost) {
             if (ctx.subProject.page_show.cost) {
                 shenpi_count.push({ count: await ctx.service.costStageAudit.getCountByChecked('ledger', ctx.session.sessionUser.accountId, ctx.subProject.id), name: '成本报审' });
                 shenpi_count.push({ count: await ctx.service.costStageAudit.getCountByChecked('ledger', ctx.session.sessionUser.accountId, ctx.subProject.id), name: '成本报审' });
                 shenpi_count.push({ count: await ctx.service.costStageAudit.getCountByChecked('book', ctx.session.sessionUser.accountId, ctx.subProject.id), name: '财务账面' });
                 shenpi_count.push({ count: await ctx.service.costStageAudit.getCountByChecked('book', ctx.session.sessionUser.accountId, ctx.subProject.id), name: '财务账面' });
@@ -459,6 +504,7 @@ module.exports = app => {
                 ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getLastEndTimeByChecked('book', ctx.session.sessionUser.accountId, ctx.subProject.id) : null,
                 ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getLastEndTimeByChecked('book', ctx.session.sessionUser.accountId, ctx.subProject.id) : null,
                 ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getLastEndTimeByChecked('analysis', ctx.session.sessionUser.accountId, ctx.subProject.id) : null,
                 ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getLastEndTimeByChecked('analysis', ctx.session.sessionUser.accountId, ctx.subProject.id) : null,
                 ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getLastEndTimeByChecked('duty', ctx.session.sessionUser.accountId, ctx.subProject.id) : null,
                 ctx.subProject.page_show.cost ? await ctx.service.costStageAudit.getLastEndTimeByChecked('duty', ctx.session.sessionUser.accountId, ctx.subProject.id) : null,
+                ctx.subProject.page_show.openContract ? await ctx.service.contractSpAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId, ctx.subProject.id) : null,
             ];
             ];
             const last_time = ctx.app._.max(shenpi_lastime);
             const last_time = ctx.app._.max(shenpi_lastime);
             // console.log(ctx.app._.max(shenpi_lastime), ctx.helper.calcDayNum(last_time));
             // console.log(ctx.app._.max(shenpi_lastime), ctx.helper.calcDayNum(last_time));
@@ -483,6 +529,8 @@ module.exports = app => {
                 auditCostStageBook,
                 auditCostStageBook,
                 auditCostStageAnalysis,
                 auditCostStageAnalysis,
                 auditCostStageDuty,
                 auditCostStageDuty,
+                auditContracts,
+                auditContractPays,
                 shenpi_count,
                 shenpi_count,
                 total_count,
                 total_count,
                 last_day: ctx.helper.calcDayNum(last_time),
                 last_day: ctx.helper.calcDayNum(last_time),
@@ -502,6 +550,7 @@ module.exports = app => {
                 acSafeStage: auditConst.safeStage,
                 acSafeStage: auditConst.safeStage,
                 acPhasePay: auditConst.phasePay,
                 acPhasePay: auditConst.phasePay,
                 acCostStage: auditConst.costStage,
                 acCostStage: auditConst.costStage,
+                acContract: auditConst.contract,
                 noticeList,
                 noticeList,
                 pushType: auditConst.pushType,
                 pushType: auditConst.pushType,
                 projectData,
                 projectData,

+ 15 - 0
app/public/js/contract_detail.js

@@ -1,5 +1,20 @@
 const copyBlockTag = 'zh.calc.copyBlock';
 const copyBlockTag = 'zh.calc.copyBlock';
 $(document).ready(function() {
 $(document).ready(function() {
+    // 检查URL参数,如果tab=pay则自动切换到合同支付/回款选项卡
+    const urlParams = new URLSearchParams(window.location.search);
+    if (urlParams.get('tab') === 'pay') {
+        // 延迟执行,确保DOM完全加载
+        setTimeout(function() {
+            // 移除所有active类
+            $('.bc-bar .nav li a').removeClass('active');
+            $('.tab-content .tab-pane').removeClass('active');
+            
+            // 激活htpay选项卡
+            $('.bc-bar .nav li a[href="#htpay"]').addClass('active');
+            $('#htpay').addClass('active');
+        }, 100);
+    }
+    
     let stdXmj;
     let stdXmj;
     const ckBillsSpread = '/contract/' + window.location.pathname.split('/')[2] + '/' + contractConst.typeMap[contract_type] + '/detail/contract-billsSelect';
     const ckBillsSpread = '/contract/' + window.location.pathname.split('/')[2] + '/' + contractConst.typeMap[contract_type] + '/detail/contract-billsSelect';
     autoFlashHeight();
     autoFlashHeight();

+ 22 - 10
app/public/js/shares/ai_trans.js

@@ -141,15 +141,15 @@ const AITrans = function() {
         $('#ai-trans-grid').modal('show');
         $('#ai-trans-grid').modal('show');
     };
     };
 
 
-    document.getElementById('ai-trans-file-add').addEventListener('dragenter', function(e) {
-        e.preventDefault();
-        this.style.backgroundColor = '#f0f0f0';
-    });
-    document.getElementById('ai-trans-file-add').addEventListener('dragleave', function(e) {
-        if (e.relatedTarget !== this) {
-            this.style.backgroundColor = '';
-        }
-    });
+    // document.getElementById('ai-trans-file-add').addEventListener('dragenter', function(e) {
+    //     e.preventDefault();
+    //     this.style.backgroundColor = '#f0f0f0';
+    // });
+    // document.getElementById('ai-trans-file-add').addEventListener('dragleave', function(e) {
+    //     if (e.relatedTarget !== this) {
+    //         this.style.backgroundColor = '';
+    //     }
+    // });
     document.getElementById('ai-trans-file-add').addEventListener('dragover', function(e) {
     document.getElementById('ai-trans-file-add').addEventListener('dragover', function(e) {
         e.preventDefault();
         e.preventDefault();
         e.dataTransfer.dropEffect = 'copy';
         e.dataTransfer.dropEffect = 'copy';
@@ -176,11 +176,23 @@ const AITrans = function() {
 
 
         transResultObj.uploadFile(files);
         transResultObj.uploadFile(files);
     });
     });
+    $('#ai-trans-file-add').click(function() {
+        if (transResultObj.rela_node.aiRelaFile && transResultObj.rela_node.aiRelaFile.length >= 3) {
+            toastr.warning('保存的图片超过限制,请先删除旧图片后再操作');
+            return;
+        }
+
+        const e = new MouseEvent('click', { view: window, bubbles: true, cancelable: true });
+        document.getElementById('ai-trans-file').dispatchEvent(e);
+    });
+    $('#ai-trans-file').change(function() {
+        transResultObj.uploadFile(this.files);
+    });
     $('body').on('click', '[name=ai-his-file]', function() {
     $('body').on('click', '[name=ai-his-file]', function() {
         transResultObj.selectFile(this.getAttribute('fid'));
         transResultObj.selectFile(this.getAttribute('fid'));
     });
     });
     $('#ai-trans').on('paste', transResultObj.pasteImage);
     $('#ai-trans').on('paste', transResultObj.pasteImage);
-    $('body').on('click', '.ai-del-btn', function() {
+    $('body').on('click', '.ai-del-btn', function(e) {
         const fid = $(this).parent().attr('fid');
         const fid = $(this).parent().attr('fid');
         transResultObj.deleteFile(fid);
         transResultObj.deleteFile(fid);
         e.stopPropagation();
         e.stopPropagation();

Разница между файлами не показана из-за своего большого размера
+ 160 - 16
app/service/contract_sp_audit.js


+ 1 - 1
app/service/tender_cert.js

@@ -109,7 +109,7 @@ module.exports = app => {
 
 
         async getAllCert(tenderId) {
         async getAllCert(tenderId) {
             const sql = 'SELECT tc.id, tc.uid, tc.uid, tc.cert_id, tc.department, tc.job_time, tc.remark,' +
             const sql = 'SELECT tc.id, tc.uid, tc.uid, tc.cert_id, tc.department, tc.job_time, tc.remark,' +
-                '    ac.type, ac.name as ac_name, ac.code, ac.reg_unit, ac.job_title, ac.file_name, ac.file_path, ac.edu_json,' +
+                '    ac.type, ac.name as ac_name, ac.code, ac.reg_unit, ac.job_title, ac.file_name, ac.file_path, ac.edu_json, ac.cert_name,' +
                 '    pa.account, pa.name, pa.role, pa.company' +
                 '    pa.account, pa.name, pa.role, pa.company' +
                 `  FROM ${this.tableName} tc LEFT JOIN ${this.ctx.service.accountCert.tableName} ac ON tc.cert_id = ac.id` +
                 `  FROM ${this.tableName} tc LEFT JOIN ${this.ctx.service.accountCert.tableName} ac ON tc.cert_id = ac.id` +
                 `  LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON tc.uid = pa.id` +
                 `  LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON tc.uid = pa.id` +

Разница между файлами не показана из-за своего большого размера
+ 53 - 1
app/view/dashboard/index.ejs


+ 66 - 0
app/view/dashboard/workspace.ejs

@@ -157,6 +157,9 @@
                                             <% if (dashboardStatus.shenpi.costStageDuty !== 0) { %>
                                             <% if (dashboardStatus.shenpi.costStageDuty !== 0) { %>
                                             <option value="costStageDuty">责任成本(<%- dashboardStatus.shenpi.costStageDuty %>)</option>
                                             <option value="costStageDuty">责任成本(<%- dashboardStatus.shenpi.costStageDuty %>)</option>
                                             <% } %>
                                             <% } %>
+                                            <% if (dashboardStatus.shenpi.contract !== 0 || dashboardStatus.shenpi.contractPay !== 0 || dashboardStatus.shenpi.contractReceipt !== 0) { %>
+                                                <option value="contract">合同管理(<%- (dashboardStatus.shenpi.contract || 0) + (dashboardStatus.shenpi.contractPay || 0) + (dashboardStatus.shenpi.contractReceipt || 0) %>)</option>
+                                            <% } %>
                                         </select>
                                         </select>
                                     </div>
                                     </div>
                                 </div>
                                 </div>
@@ -528,6 +531,57 @@
                                                             <td><%- (am.begin_time ? ctx.moment(am.begin_time).format('YYYY/MM/DD HH:mm') : '') %></td>
                                                             <td><%- (am.begin_time ? ctx.moment(am.begin_time).format('YYYY/MM/DD HH:mm') : '') %></td>
                                                             <td><a href="/sp/<%- am.spid %>/cost/tender/<%- am.tid %>/duty/1/stage" class="btn btn-sm btn-table <%- (am.audit_order === 0 ? 'btn-outline-warning text-warning' : 'btn-outline-primary') %>" role="button"><%- (am.audit_order === 0 ? '重新上报' : '审批')%></a></td>
                                                             <td><a href="/sp/<%- am.spid %>/cost/tender/<%- am.tid %>/duty/1/stage" class="btn btn-sm btn-table <%- (am.audit_order === 0 ? 'btn-outline-warning text-warning' : 'btn-outline-primary') %>" role="button"><%- (am.audit_order === 0 ? '重新上报' : '审批')%></a></td>
                                                         </tr>
                                                         </tr>
+                                                    <% } else if (db.shenpi_type === 'contract') { %>
+                                                        <% const ct = db; %>
+                                                        <tr data-type="contract">
+                                                            <% if (ct.start_audit === 2) { %><td class="text-center text-danger"><i class="fa fa-exclamation-triangle"></i></td><% } else if (ct.start_audit === 1) { %><td class="text-center text-warning"><i class="fa fa-bell"></i></td><% } else { %><td></td><% } %>
+                                                            <td><span class="badge text-width" style="background-color: #e3f2fd; color: #1976d2;">合同审批</span></td>
+                                                            <td><a href="/sp/<%- ct.spid %>/dashboard"><%- ct.sp_name || '项目合同' %></a></td>
+                                                            <td>
+                                                                <% if (ct.is_project_contract) { %>
+                                                                    <a href="/contract/<%- ct.id %>"><%- ct.name %></a>
+                                                                <% } else { %>
+                                                                    <a href="/tender/<%- ct.tid %>"><%- ct.tender_name %></a> - <a href="/contract/<%- ct.id %>"><%- ct.name %></a>
+                                                                <% } %>
+                                                            </td>
+                                                            <td><%- ct.status_text %></td>
+                                                            <td><%- (ct.begin_time ? ctx.moment(ct.begin_time).format('YYYY/MM/DD HH:mm') : '') %></td>
+                                                            <td><a href="/contract/<%- ct.id %>/audit" class="btn btn-outline-primary btn-sm btn-table" role="button">审批</a></td>
+                                                        </tr>
+                                                    <% } else if (db.shenpi_type === 'contractPay') { %>
+                                                        <% const cp = db; %>
+                                                        <tr data-type="contract">
+                                                            <% if (cp.start_audit === 2) { %><td class="text-center text-danger"><i class="fa fa-exclamation-triangle"></i></td><% } else if (cp.start_audit === 1) { %><td class="text-center text-warning"><i class="fa fa-bell"></i></td><% } else { %><td></td><% } %>
+                                                            <td><span class="badge text-width" style="background-color: #fff3e0; color: #f57c00;">合同支付</span></td>
+                                                            <td><a href="/sp/<%- cp.spid %>/dashboard"><%- cp.sp_name %></a></td>
+                                                            <td>
+                                                                <% if (cp.is_project_contract) { %>
+                                                                    <a href="/contract/<%- cp.cid %>"><%- cp.contract_name %></a> - 第<%- cp.times %>期
+                                                                <% } else { %>
+                                                                    <a href="/tender/<%- cp.tid %>"><%- cp.tender_name %></a> - <a href="/contract/<%- cp.cid %>"><%- cp.contract_name %></a> - 第<%- cp.times %>期
+                                                                <% } %>
+                                                            </td>
+                                                            <td>支付</td>
+                                                            <td><%- (cp.begin_time ? ctx.moment(cp.begin_time).format('YYYY/MM/DD HH:mm') : '') %></td>
+                                                            <td><a href="/contract/<%- cp.cid %>/pay/<%- cp.id %>/audit" class="btn btn-outline-primary btn-sm btn-table" role="button">审批</a></td>
+                                                        </tr>
+                                                    <% } else if (db.shenpi_type === 'contractReceipt') { %>
+                                                        <% const cr = db; %>
+                                                        <tr data-type="contract">
+                                                            <% if (cr.start_audit === 2) { %><td class="text-center text-danger"><i class="fa fa-exclamation-triangle"></i></td><% } else if (cr.start_audit === 1) { %><td class="text-center text-warning"><i class="fa fa-bell"></i></td><% } else { %><td></td><% } %>
+                                                            <td><span class="badge text-width" style="background-color: #e8f5e9; color: #388e3c;">合同回款</span></td>
+                                                            <td><a href="/sp/<%- cr.spid %>/dashboard"><%- cr.sp_name %></a></td>
+                                                            <td>
+                                                                <% if (cr.is_project_contract) { %>
+                                                                    <a href="/contract/<%- cr.cid %>"><%- cr.contract_name %></a> - 第<%- cr.times %>期
+                                                                <% } else { %>
+                                                                    <a href="/tender/<%- cr.tid %>"><%- cr.tender_name %></a> - <a href="/contract/<%- cr.cid %>"><%- cr.contract_name %></a> - 第<%- cr.times %>期
+                                                                <% } %>
+                                                            </td>
+                                                            <td>回款</td>
+                                                            <td><%- (cr.begin_time ? ctx.moment(cr.begin_time).format('YYYY/MM/DD HH:mm') : '') %></td>
+                                                            <td><a href="/contract/<%- cr.cid %>/pay/<%- cr.id %>/audit" class="btn btn-outline-primary btn-sm btn-table" role="button">审批</a></td>
+                                                        </tr>
                                                     <% } %>
                                                     <% } %>
                                                 <% } %>
                                                 <% } %>
                                                 </tbody>
                                                 </tbody>
@@ -987,6 +1041,18 @@
                                         html.push(`<li class="list-group-item">
                                         html.push(`<li class="list-group-item">
                                             <span class="${acCostStage.auditStringClass[n.audit_status]}">${acCostStage.auditString[n.audit_status]}</span> <a href="/sp/${n.spid}/cost/tender/${n.id}/duty/1/stage" target="_blank">${n.name}</a> 责任成本 ${n.name}<span class="float-right">${moment(new Date(n.shenpi_time)).format('HH:mm:ss')}</span></li>`);
                                             <span class="${acCostStage.auditStringClass[n.audit_status]}">${acCostStage.auditString[n.audit_status]}</span> <a href="/sp/${n.spid}/cost/tender/${n.id}/duty/1/stage" target="_blank">${n.name}</a> 责任成本 ${n.name}<span class="float-right">${moment(new Date(n.shenpi_time)).format('HH:mm:ss')}</span></li>`);
                                         break;
                                         break;
+                                    case 'contract':
+                                        html.push(`<li class="list-group-item">
+                                            <span class="text-warning">审批中</span> <a href="/contract/${n.id}/audit" target="_blank">${n.name}</a> 合同审批<span class="float-right">${moment(new Date(n.shenpi_time)).format('HH:mm:ss')}</span></li>`);
+                                        break;
+                                    case 'contractPay':
+                                        html.push(`<li class="list-group-item">
+                                            <span class="text-warning">审批中</span> <a href="/contract/${n.cid}/pay/${n.id}/audit" target="_blank">${n.contract_name || n.tender_name}</a> 合同支付 第${n.times}期<span class="float-right">${moment(new Date(n.shenpi_time)).format('HH:mm:ss')}</span></li>`);
+                                        break;
+                                    case 'contractReceipt':
+                                        html.push(`<li class="list-group-item">
+                                            <span class="text-warning">审批中</span> <a href="/contract/${n.cid}/pay/${n.id}/audit" target="_blank">${n.contract_name || n.tender_name}</a> 合同回款 第${n.times}期<span class="float-right">${moment(new Date(n.shenpi_time)).format('HH:mm:ss')}</span></li>`);
+                                        break;
                                     default: continue;
                                     default: continue;
                                 }
                                 }
                             }
                             }

+ 2 - 2
app/view/shares/ai_trans.ejs

@@ -95,7 +95,7 @@
                                 <div class="card-body">
                                 <div class="card-body">
                                     <div class="d-flex p-1" >
                                     <div class="d-flex p-1" >
                                         <!--<i class="fa fa-plus fa-3x text-black-50"></i>-->
                                         <!--<i class="fa fa-plus fa-3x text-black-50"></i>-->
-                                        <span class="text-black-50 p-1 d-flex" style="font-size: 60px; width: 50px; height: 50px; line-height: 30px">+</span>
+                                        <span class="text-black-50 p-1 d-flex" style="font-size: 60px; width: 50px; height: 50px; line-height: 30px; cursor: default;">+</span>
                                     </div>
                                     </div>
                                 </div>
                                 </div>
                             </div>
                             </div>
@@ -118,7 +118,7 @@
                 <!--</div>-->
                 <!--</div>-->
             </div>
             </div>
             <div class="modal-footer">
             <div class="modal-footer">
-                <input type="hidden" class="form-control-file" id="ai-trans-file" name="file">
+                <input type="file" class="form-control-file" id="ai-trans-file" name="file" style="display: none">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
                 <a href="javascript: void(0);" class="btn btn-sm btn-primary" id="ai-trans-ok">确定</a>
                 <a href="javascript: void(0);" class="btn btn-sm btn-primary" id="ai-trans-ok">确定</a>
             </div>
             </div>

+ 22 - 0
deploy/Dockerfile

@@ -0,0 +1,22 @@
+FROM node:12
+
+# 设置工作目录
+WORKDIR /app/calc
+
+# 复制 package.json 和 package-lock.json(如果存在)以利用 Docker 缓存
+COPY package*.json ./
+
+# 安装依赖,使用淘宝镜像加速
+RUN npm install --registry=https://registry.npmmirror.com
+
+# 复制所有源代码
+COPY . .
+
+# 暴露端口 7005(与 dev-docker 命令一致)
+EXPOSE 7005
+
+# 设置环境变量为 weapp(用于 weapp 测试环境)
+ENV EGG_SERVER_ENV=weapp
+
+# 启动应用
+CMD ["npm", "run", "dev-weapp"]

+ 10 - 0
deploy/build.sh

@@ -0,0 +1,10 @@
+docker buildx build --platform linux/amd64 \
+  --load \
+  -t registry.cn-shenzhen.aliyuncs.com/prod_cp/calculation_weapp_dev:latest \
+  -f deploy/Dockerfile .
+
+  docker push registry.cn-shenzhen.aliyuncs.com/prod_cp/calculation_weapp_dev:latest
+
+
+docker cp ./config.weapp.js 5fb7277c5aa9:/app/calc/config/config.weapp.js
+  

+ 42 - 0
deploy/cal.conf

@@ -0,0 +1,42 @@
+upstream calculation_weapp {
+    server 127.0.0.1:7005;
+}
+
+server {
+    listen 80;
+    server_name jluat.cal.com;
+
+    charset utf-8;
+
+    access_log /var/log/nginx/jluat_cal_access.log;
+    error_log /var/log/nginx/jluat_cal_error.log;
+
+    client_max_body_size 100m;
+
+    proxy_connect_timeout 60s;
+    proxy_send_timeout 60s;
+    proxy_read_timeout 60s;
+
+    location / {
+        proxy_pass http://calculation_weapp;
+        
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+        
+        proxy_buffering off;
+        proxy_request_buffering off;
+    }
+
+    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
+        proxy_pass http://calculation_weapp;
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+        
+        expires 30d;
+        add_header Cache-Control "public, immutable";
+    }
+}