Prechádzať zdrojové kódy

合同附加属性值及税率值增加

ellisran 3 hodín pred
rodič
commit
3b7d975f03

+ 37 - 8
app/const/contract.js

@@ -26,6 +26,8 @@ const typeName = {
 const colSet = {
     [type.expenses]: [
         { name: '合同类型', field: 'type', fixed: ['alias'], gd: true },
+        { name: '甲方', field: 'party_a', fixed: ['alias'], gd: true },
+        { name: '乙方', field: 'party_b', fixed: ['alias'], gd: true },
         { name: '累计应付', field: 'yf_price', fixed: ['alias'] },
         { name: '应付进度', field: 'stackedBar', fixed: ['alias'] },
         { name: '累计实付', field: 'sf_price', fixed: ['alias'] },
@@ -37,6 +39,8 @@ const colSet = {
     ],
     [type.income]: [
         { name: '合同类型', field: 'type', fixed: ['alias'], gd: true },
+        { name: '甲方', field: 'party_a', fixed: ['alias'], gd: true },
+        { name: '乙方', field: 'party_b', fixed: ['alias'], gd: true },
         { name: '累计应回', field: 'yf_price', fixed: ['alias'] },
         { name: '应回进度', field: 'stackedBar', fixed: ['alias'] },
         { name: '累计实回', field: 'sf_price', fixed: ['alias'] },
@@ -51,6 +55,8 @@ const colSet = {
 const defaultColSet = {
     [type.expenses]: [
         { field: 'type', show: 1, gd: true },
+        { field: 'party_a', show: 0, gd: true },
+        { field: 'party_b', show: 0, gd: true },
         { field: 'yf_price', show: 1 },
         { field: 'stackedBar', show: 1 },
         { field: 'sf_price', show: 0 },
@@ -62,6 +68,8 @@ const defaultColSet = {
     ],
     [type.income]: [
         { field: 'type', show: 1, gd: true },
+        { field: 'party_a', show: 0, gd: true },
+        { field: 'party_b', show: 0, gd: true },
         { field: 'yf_price', show: 1 },
         { field: 'stackedBar', show: 1 },
         { field: 'sf_price', show: 0 },
@@ -73,20 +81,41 @@ const defaultColSet = {
     ],
 };
 
-const defaultAttribute = [
-    { name: '税率(%)', field: 'type', fixed: ['alias'], type: 'int' },
-    { name: '数值', field: 'num_val', fixed: [], type: 'int' },
-    { name: '丙方', field: 'third', fixed: [], type: 'text' },
-    { name: '丁方', field: 'fourth', fixed: [], type: 'text' },
-    { name: '文本', field: 'text', fixed: [], type: 'text' },
-    { name: '合同内容', field: 'contract_content', fixed: [], type: 'long_text', tip: '独占一行,上限1000' },
-    { name: '支付条件', field: 'pay_condition', fixed: [], type: 'long_text', tip: '独占一行,上限1000' },
+const attributeSet = [
+    { name: '数值', field: 'num_val', fixed: [], type: 'int', type_name: '数字' },
+    { name: '丙方', field: 'party_c', fixed: [], type: 'text', type_name: '文本' },
+    { name: '丁方', field: 'party_d', fixed: [], type: 'text', type_name: '文本' },
+    { name: '文本', field: 'text', fixed: [], type: 'text', type_name: '文本' },
+    { name: '合同内容', field: 'contract_content', fixed: [], type: 'long_text', type_name: '长文本', tip: '独占一行,上限1000' },
+    { name: '支付条件', field: 'pay_condition', fixed: [], type: 'long_text', type_name: '长文本', tip: '独占一行,上限1000' },
 ];
 
+const defaultAttributeSet = [
+    { field: 'num_val', show: 0, alias: '数值' },
+    { field: 'party_c', show: 0, alias: '丙方' },
+    { field: 'party_d', show: 0, alias: '丁方' },
+    { field: 'text', show: 0, alias: '文本' },
+    { field: 'contract_content', show: 0, alias: '合同内容' },
+    { field: 'pay_condition', show: 0, alias: '支付条件' },
+];
+
+const defaultAttribute = {
+    num_val: null,
+    party_c: '',
+    party_d: '',
+    text: '',
+    contract_content: '',
+    pay_condition: '',
+};
+
+
 module.exports = {
     type,
     typeMap,
     typeName,
     colSet,
     defaultColSet,
+    attributeSet,
+    defaultAttributeSet,
+    defaultAttribute,
 };

+ 9 - 1
app/controller/contract_controller.js

@@ -867,6 +867,8 @@ module.exports = app => {
                     thisUrl: `/sp/${ctx.subProject.id}/contract${types_from === 'tender' ? '/tender' : ''}/setting`,
                     is_setting: true,
                 };
+                const attributeSet = commonJson && commonJson.contract_attribute ? commonJson.contract_attribute : contractConst.attributeSet;
+                renderData.attributeSet = ctx.service.contractColSet.analysisColSetWithDefine(contractConst.attributeSet, attributeSet, contractConst.defaultAttributeSet);
                 await this.layout('contract/setting.ejs', renderData);
             } catch (err) {
                 ctx.log(err);
@@ -882,6 +884,7 @@ module.exports = app => {
          */
         async updateSetting(ctx) {
             try {
+                const responseData = { err: 0, msg: '', data: null };
                 if (!ctx.subProject) throw '没有对应的项目数据';
                 if (ctx.session.sessionUser.is_admin === 0) throw '没有访问权限';
 
@@ -897,10 +900,15 @@ module.exports = app => {
                         const result = await ctx.service.contract.savePageShow(ctx.subProject.id, ctx.subProject.page_show);
                         if (!result) throw '保存数据失败';
                         break;
+                    case 'attribute_set':
+                        const result2 = await ctx.service.subProject.saveCommonJson(ctx.subProject.id, 'contract_attribute', data.attribute_set);
+                        if (!result2) throw '保存数据失败';
+                        responseData.data = ctx.service.contractColSet.analysisColSetWithDefine(contractConst.attributeSet, data.attribute_set, contractConst.defaultAttributeSet);
+                        break;
                     default:
                         throw '参数有误';
                 }
-                ctx.body = { err: 0, msg: '', data: null };
+                ctx.body = responseData;
             } catch (error) {
                 ctx.log(error);
                 this.ajaxErrorBody(error, '保存数据失败');

+ 30 - 12
app/public/js/contract_detail.js

@@ -11,7 +11,8 @@ $(document).ready(function() {
             {title: '创建人', colSpan: '1', rowSpan: '2', field: 'username', hAlign: 1, width: 80, formatter: '@', readOnly: true},
             {title: '合同金额', colSpan: '1', rowSpan: '2', field: 'total_price', hAlign: 2, width: 120, formatter: '@', readOnly: true},
             {title: '合同类型', colSpan: '1', rowSpan: '2', field: 'type', hAlign: 0, width: 120, readOnly: 'readOnly.type', cellType: 'customizeCombo', comboItems: types, cellTypeKey: 1},
-            {title: '合同状态', colSpan: '1', rowSpan: '2', field: 'status', hAlign: 1, width: 100, formatter: '@', readOnly: true, getValue:'getValue.status', foreColor:'foreColor.status'},
+            {title: '甲方', colSpan: '1', rowSpan: '2', field: 'party_a', hAlign: 1, width: 80, formatter: '@', readOnly: true},
+            {title: '乙方', colSpan: '1', rowSpan: '2', field: 'party_b', hAlign: 1, width: 80, formatter: '@', readOnly: true},
             {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 120, formatter: '@', cellType: 'ellipsisAutoTip', scrollHeightClass: '.sjs-height-1'},
         ],
         emptyRows: 0,
@@ -83,7 +84,7 @@ $(document).ready(function() {
             return data.c_code && data.status ? auditConst.auditClassColor[data.status] : '';
         };
     }
-    const gdColField = ['type'];
+    const gdColField = ['type', 'party_a', 'party_b'];
     const colMap = {
       yf_price: {title: '累计应付', colSpan: '1', rowSpan: '2', field: 'yf_price', hAlign: 2, width: 120, formatter: '@', readOnly: true},
       stackedBar: {title: '应付进度', colSpan: '1', rowSpan: '2', formatter: '@', readOnly: true, field: 'stackedBar', hAlign: 0, width: 200, cellType: 'stackedBar', stackedBarCover: true, bc_type: 'grid', getTip: getStackedBarTip, hintNum: true},
@@ -151,7 +152,7 @@ $(document).ready(function() {
     };
     const contractTree = createNewPathTree('revise', treeSetting);
 
-    const contractDetail = ['c_code', 'name', 'total_price', 'pay_price', 'debit_price','yf_price', 'sf_price', 'party_a', 'party_a_user', 'party_b', 'party_b_user', 'sign_date', 'address', 'entity', 'bank', 'bank_account', 'remark', 'settle_code', 'create_time'];
+    const contractDetail = ['c_code', 'name', 'total_price', 'pay_price', 'debit_price','yf_price', 'sf_price', 'party_a', 'party_a_user', 'party_b', 'party_b_user', 'sign_date', 'address', 'entity', 'bank', 'bank_account', 'remark', 'settle_code', 'tax', 'create_time'];
 
     // 清单 相关方法&绑定spreadjs事件
     const contractTreeSpreadObj = {
@@ -1642,6 +1643,9 @@ $(document).ready(function() {
                     } else if (c === 'remark') {
                         $('#htdetail_' + c).html('<textarea class="form-control form-control-sm" rows="3">' + node[c] + '</textarea>');
                         continue;
+                    } else if (c === 'tax') {
+                        $('#htdetail_' + c).html('<input type="number" min="0" max="100" step="1" class="form-control form-control-sm" value="' + (node[c] ? node[c] : '') + '">');
+                        continue;
                     }
                     $('#htdetail_' + c).html('<input type="text" class="form-control form-control-sm" value="' + node[c] + '">');
                 }
@@ -1678,15 +1682,24 @@ $(document).ready(function() {
                 toastr.warning('合同金额只能输入数字');
                 return;
             }
+            if (data.tax !== '') {
+                const reg = /^(\d{1,2}|100)$/;
+                if (!reg.test(data.tax)) {
+                    toastr.warning('税率只能输入0-100之间的整数');
+                    return;
+                }
+            } else {
+                data.tax = null;
+            }
             if (parseFloat(data.total_price) < node.yf_price) {
                 const name = contract_type === contractConst.type.expenses ? '付' : '回';
                 toastr.warning('合同金额不能小于累计应' + name);
                 return;
             }
-            if (data.party_b === '') {
-                toastr.warning('签订单位(乙方)不能为空');
-                return;
-            }
+            // if (data.party_b === '') {
+            //     toastr.warning('签订单位(乙方)不能为空');
+            //     return;
+            // }
             // 更新至服务器
             postData(window.location.pathname + '/update', {postType: 'update-contract', postData: data}, function (result) {
                 toastr.success('已编辑成功');
@@ -2190,13 +2203,16 @@ $(document).ready(function() {
         });
     }
 
-
     if (permission_add) {
+        const signDate = $('#cons-add input[name="sign_date"]').datepicker().data('datepicker');
         $('#cons-add').on('show.bs.modal', function () {
             $('#cons-add input[name="code"]').val('');
             $('#cons-add input[name="name"]').val('');
             $('#cons-add input[name="total_price"]').val('');
+            $('#cons-add input[name="party_a"]').val('');
             $('#cons-add input[name="party_b"]').val('');
+            $('#cons-add input[name="sign_date"]').val('');
+            signDate.selectDate('');
             $('#cons-add textarea[name="remark"]').val('');
         });
 
@@ -2211,7 +2227,9 @@ $(document).ready(function() {
                 code: $('#cons-add input[name="code"]').val(),
                 name: $('#cons-add input[name="name"]').val(),
                 total_price: $('#cons-add input[name="total_price"]').val(),
+                party_a: $('#cons-add input[name="party_a"]').val(),
                 party_b: $('#cons-add input[name="party_b"]').val(),
+                sign_date: $('#cons-add input[name="sign_date"]').val(),
                 remark: $('#cons-add textarea[name="remark"]').val(),
                 type: $('#cons-add select[name="type"]').val(),
             }
@@ -2232,10 +2250,10 @@ $(document).ready(function() {
                 toastr.error('合同金额只能输入数字');
                 return;
             }
-            if (!data.party_b) {
-                toastr.error('请输入签订单位(乙方)');
-                return;
-            }
+            // if (!data.party_b) {
+            //     toastr.error('请输入签订单位(乙方)');
+            //     return;
+            // }
             console.log(node, data);
             postData(window.location.pathname + '/update', {postType: 'add-contract', postData: { select: node, contract: data }}, function (result) {
                 const refreshNode = contractTree.loadPostData(result);

+ 143 - 0
app/public/js/contract_setting.js

@@ -143,6 +143,7 @@ $(document).ready(() => {
         }
     }
 
+    // 审批设置
     $('#contract-shenpi-set input[type="checkbox"]').change(function() {
         postData(`/sp/${spid}/contract/setting/update`, { type: 'page_show',
             openContractSubProjectShenpi: $('#openContractSubProjectShenpi')[0].checked,
@@ -152,4 +153,146 @@ $(document).ready(() => {
         }, function (result) {
         });
     });
+
+    // 附加属性设置
+// 立即获取表格 tbody 并绑定事件(确保脚本加载时即可初始化)
+    const $tbody = $('#attribute-set-table');
+
+// 保存初始 HTML,在关闭时恢复(保证再次打开时为初始状态)
+    let _initialColSetTbodyHtml = $tbody.html();
+
+// 更新上下移链接显示状态
+    function updateMoveButtons() {
+        const $currentRows = $tbody.find('tr');
+        const totalRows = $currentRows.length;
+
+        $currentRows.each(function(index) {
+            const $row = $(this);
+            const $upLink = $row.find('.move-up');
+            const $downLink = $row.find('.move-down');
+
+            if (totalRows === 1) {
+                $upLink.hide();
+                $downLink.hide();
+            } else if (index === 0) {
+                $upLink.hide();
+                $downLink.show();
+            } else if (index === totalRows - 1) {
+                $upLink.show();
+                $downLink.hide();
+            } else {
+                $upLink.show();
+                $downLink.show();
+            }
+        });
+        checkAttribute();
+    }
+
+    function checkAttribute() {
+        const $currentRows =  $('#attribute-set-table').find('tr');
+        const attribute_set = [];
+
+        $currentRows.each(function() {
+            const $row = $(this);
+            let alias = '';
+            const $aliasInput = $row.find('input[type="text"]');
+            if ($aliasInput.length) {
+                alias = $aliasInput.val().trim();
+            }
+
+            // 仅组装数据库需要的3个字段
+            const rowData = {
+                field: $row.attr('code'), // 字段标识(必填)
+                show: Number($row.find('.form-check-input').is(':checked')), // 是否显示(必填)
+                alias: alias // 别名(必填,固定列保存"-")
+            };
+
+            attribute_set.push(rowData); // 所有行按顺序存入数组,顺序=表格排序
+        });
+        // 和 attributeSet对比部分值和顺序,如果不同则返回true,否则返回false
+        const defaultAttr = [];
+        for (const attr of attributeSet) {
+            defaultAttr.push({
+                field: attr.field,
+                show: attr.show,
+                alias: attr.alias || '' // 确保默认值也有 alias 字段,且空值为 '-'
+            });
+        }
+        console.log(attribute_set, defaultAttr);
+        if (_.isEqual(attribute_set, defaultAttr)) {
+            $('#show-attribute-btn').hide();
+            $('#cancel-attribute-btn').hide();
+        } else {
+            $('#show-attribute-btn').show();
+            $('#cancel-attribute-btn').show();
+        }
+    }
+
+// 立即初始化链接状态(页面渲染完成后就计算显示)
+    updateMoveButtons();
+
+    $tbody.on('change', 'input', function () {
+        checkAttribute();
+    });
+
+    $('#set-attribute-btn').click(function() {
+        const $currentRows =  $('#attribute-set-table').find('tr');
+        const attribute_set = [];
+
+        $currentRows.each(function() {
+            const $row = $(this);
+            let alias = '';
+            const $aliasInput = $row.find('input[type="text"]');
+            if ($aliasInput.length) {
+                alias = $aliasInput.val().trim();
+            }
+
+            // 仅组装数据库需要的3个字段
+            const rowData = {
+                field: $row.attr('code'), // 字段标识(必填)
+                show: Number($row.find('.form-check-input').is(':checked')), // 是否显示(必填)
+                alias: alias // 别名(必填,固定列保存"-")
+            };
+
+            attribute_set.push(rowData); // 所有行按顺序存入数组,顺序=表格排序
+        });
+        console.log(attribute_set);
+        postData(`/sp/${spid}/contract/setting/update`, { type: 'attribute_set',
+            attribute_set,
+        }, function (result) {
+            toastr.success('设置成功');
+            attributeSet = result;
+            _initialColSetTbodyHtml = $tbody.html(); // 更新初始 HTML 为当前状态(保存后以当前状态为初始状态)
+            checkAttribute();
+        });
+    });
+
+    $('#cancel-attribute-btn').click(function() {
+        toastr.warning('已取消改动');
+        $tbody.html(_initialColSetTbodyHtml); // 恢复初始 HTML
+        updateMoveButtons(); // 恢复后重新计算链接显示状态
+    });
+
+// 事件委托:从一开始就绑定上/下移事件
+    $tbody.on('click', '.move-up', function(e) {
+        e.preventDefault();
+        const $currentRow = $(this).closest('tr');
+        const $prevRow = $currentRow.prev('tr');
+
+        if ($prevRow.length) {
+            $currentRow.insertBefore($prevRow);
+            updateMoveButtons();
+        }
+    });
+
+    $tbody.on('click', '.move-down', function(e) {
+        e.preventDefault();
+        const $currentRow = $(this).closest('tr');
+        const $nextRow = $currentRow.next('tr');
+
+        if ($nextRow.length) {
+            $currentRow.insertAfter($nextRow);
+            updateMoveButtons();
+        }
+    });
 });

+ 2 - 0
app/service/contract.js

@@ -56,7 +56,9 @@ module.exports = app => {
                     c_code: data.code,
                     name: data.name,
                     total_price: data.total_price ? parseFloat(data.total_price) : 0,
+                    party_a: data.party_a,
                     party_b: data.party_b,
+                    sign_date: data.sign_date,
                     remark: data.remark,
                     type: data.type,
                     create_time: new Date(),

+ 10 - 3
app/service/contract_col_set.js

@@ -66,6 +66,7 @@ module.exports = app => {
             colSetDefine.forEach(csd => {
                 colSetDefineMap.set(csd.field, csd);
             });
+            const gdResult = []; // 固定列结果,最后合并到 result 前面
             for (const cs of colSet) {
               const field = cs.field;
               const csd = colSetDefineMap.get(field); // 从字段定义中取 name、fixed
@@ -73,7 +74,11 @@ module.exports = app => {
 
               if (csd) {
                   // 合并:colSetDefine(name、fixed)> colSet(show、alias、顺序)> defaultColSet(兜底)
-                  result.push({ ...dcs, ...cs, ...csd });
+                  if (csd.gd) {
+                      gdResult.push({ ...dcs, ...cs, ...csd }); // 固定列先保存到 gdResult,最后合并到 result 前面
+                  } else {
+                      result.push({ ...dcs, ...cs, ...csd });
+                  }
               }
               colSetFieldSet.add(field); // 标记该字段已处理
             }
@@ -83,13 +88,15 @@ module.exports = app => {
                 if (!colSetFieldSet.has(field)) { // 未在 colSet 中找到的字段
                     const dcs = defaultColSet.find(x => x.field === field); // 取默认配置
                     if (dcs.gd) { // 补充到结果头中
-                        result.unshift({ ...dcs, ...csd });
+                        gdResult.push({ ...dcs, ...csd });
                     } else {
                         result.push({ ...dcs, ...csd });
                     }
                 }
             }
-
+            console.log(gdResult, result);
+            // 合并固定列和非固定列,固定列在前
+            result.unshift(...gdResult);
             return result;
         }
     }

+ 8 - 11
app/view/contract/detail.ejs

@@ -107,10 +107,10 @@
                                     <tr>
                                         <th class="text-center align-middle" width="10%">合同编号</th>
                                         <td width="20%" class="change-input-td" id="htdetail_c_code"></td>
-                                        <th class="text-center align-middle"width="10%">合同名称</th>
+                                        <th class="text-center align-middle" width="10%">合同名称</th>
                                         <td width="30%" class="change-input-td" id="htdetail_name"></td>
-                                        <th class="text-center align-middle"width="10%">创建时间</th>
-                                        <td width="20%" id="htdetail_create_time"></td>
+                                        <th class="text-center align-middle" width="10%">税率(%)</th>
+                                        <td width="20%" class="change-input-td" id="htdetail_tax"></td>
                                     </tr>
                                     <tr>
                                         <th class="text-center align-middle">合同金额</th>
@@ -141,13 +141,8 @@
                                         <td class="change-input-td" id="htdetail_party_b"></td>
                                         <th class="text-center align-middle">签约人</th>
                                         <td class="change-input-td" id="htdetail_party_b_user"></td>
-                                        <% if (ctx.contract_type === contractConst.type.expenses) { %>
                                         <th class="text-center align-middle">签约地点</th>
                                         <td class="change-input-td" id="htdetail_address"></td>
-                                        <% } else if (ctx.contract_type === contractConst.type.income) { %>
-                                        <th class="text-center align-middle">结算书编号</th>
-                                        <td id="htdetail_settle_code"></td>
-                                        <% } %>
                                     </tr>
                                     <% if (ctx.contract_type === contractConst.type.expenses) { %>
                                     <tr class="contract-expenses">
@@ -160,12 +155,14 @@
                                     </tr>
                                     <% } %>
                                     <tr>
-                                        <% if (ctx.contract_type === contractConst.type.expenses) { %>
                                         <th class="text-center align-middle">结算书编号</th>
                                         <td id="htdetail_settle_code"></td>
-                                        <% } %>
+                                        <th class="text-center align-middle">创建时间</th>
+                                        <td id="htdetail_create_time"></td>
+                                    </tr>
+                                    <tr>
                                         <th class="text-center align-middle">备注</th>
-                                        <td class="change-input-td" colspan="<% if (ctx.contract_type === contractConst.type.expenses) { %>3<% } else if (ctx.contract_type === contractConst.type.income) { %>5<% } %>" id="htdetail_remark"></td>
+                                        <td class="change-input-td" colspan="5" id="htdetail_remark"></td>
                                     </tr>
                                 </table>
                             </div>

+ 9 - 1
app/view/contract/detail_modal.ejs

@@ -32,10 +32,18 @@
                     </select>
                 </div>
                 <div class="form-group">
-                    <label>签订单位(乙方)<b class="text-danger">*</b></label>
+                    <label>签订单位(甲方)</label>
+                    <input class="form-control form-control-sm" placeholder="请输入签订单位" type="text" name="party_a">
+                </div>
+                <div class="form-group">
+                    <label>签订单位(乙方)</label>
                     <input class="form-control form-control-sm" placeholder="请输入签订单位" type="text" name="party_b">
                 </div>
                 <div class="form-group">
+                    <label>签订日期</label>
+                    <input class="datepicker-here form-control form-control-sm" name="sign_date" placeholder="点击选择时间" data-date-format="yyyy-MM-dd" data-language="zh" type="text" autocomplete="off">
+                </div>
+                <div class="form-group">
                     <label>备注</label>
                     <textarea class="form-control form-control-sm" name="remark" rows="3"></textarea>
                 </div>

+ 41 - 70
app/view/contract/setting.ejs

@@ -11,7 +11,7 @@
                 <div class="row m-0 mt-3">
                     <div class="col-6">
                         <div class="card mb-3">
-                            <div class="card-header">
+                            <div class="card-header" style="min-height: 47px;">
                                 <div class="float-left">合同类型</div>
                                 <div class="float-right" id="show-type-btn" style="display: none">
                                     <button id="cancel-type-btn" class="btn btn-sm btn-secondary">取消</button>
@@ -71,7 +71,7 @@
                     </div>
                     <div class="col-6">
                         <div class="card mb-3">
-                            <div class="card-header">
+                            <div class="card-header" style="min-height: 47px;">
                                 <div class="float-left">资金用途</div>
                                 <div class="float-right" id="show-used-btn" style="display: none">
                                     <button id="cancel-used-btn" class="btn btn-sm btn-secondary">取消</button>
@@ -137,11 +137,14 @@
                             </div>
                         </div>
                     </div>
-                    <div class="col-8">
+                    <div class="col-9">
                         <div class="card mb-3">
-                            <div class="card-header d-flex justify-content-between">
-                                <div class="card-title mb-0">合同附加属性(未开发完,勿点!)</div>
-                                <span class="pull-right">项目/标段合同同步生效</span>
+                            <div class="card-header d-flex justify-content-between" style="min-height: 47px;">
+                                <div class="float-left">合同附加属性(项目/标段合同同步生效)</div>
+                                <div class="float-right" id="show-attribute-btn" style="display: none">
+                                    <button id="cancel-attribute-btn" class="btn btn-sm btn-secondary">取消</button>
+                                    <button id="set-attribute-btn" class="btn btn-sm btn-success">保存</button>
+                                </div>
                             </div>
                             <div class="card-body">
                                 <table class="table">
@@ -153,70 +156,37 @@
                                         <th width="">说明</th>
                                         <th width="15%">操作</th>
                                     </tr>
-                                    <tbody class="text-center">
-                                    <tr>
-                                        <td>税率(%)</td><td>数字</td><td>-</td>
-                                        <td><input type="checkbox" class=""></td>
-                                        <td></td>
-                                        <td>
-                                            <a href="#" class="mx-2 text-muted"><i class="fa fa-arrow-up"></i></a>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-down"></i></a>
-                                        </td>
-                                    </tr>
-                                    <tr>
-                                        <td>数值</td><td>数字</td><td><input type="text" class="form-control form-control-sm"></td>
-                                        <td><input type="checkbox" class=""></td>
-                                        <td></td>
-                                        <td>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-up"></i></a>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-down"></i></a>
-                                        </td>
-                                    </tr>
-                                    <tr>
-                                        <td>丙方</td><td>文本</td><td><input type="text" class="form-control form-control-sm"></td>
-                                        <td><input type="checkbox" class=""></td>
-                                        <td></td>
-                                        <td>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-up"></i></a>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-down"></i></a>
-                                        </td>
-                                    </tr>
-                                    <tr>
-                                        <td>丁方</td><td>文本</td><td><input type="text" class="form-control form-control-sm"></td>
-                                        <td><input type="checkbox" class=""></td>
-                                        <td></td>
-                                        <td>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-up"></i></a>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-down"></i></a>
-                                        </td>
-                                    </tr>
-                                    <tr>
-                                        <td>文本</td><td>文本</td><td><input type="text" class="form-control form-control-sm"></td>
-                                        <td><input type="checkbox" class=""></td>
-                                        <td></td>
-                                        <td>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-up"></i></a>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-down"></i></a>
-                                        </td>
-                                    </tr>
-                                    <tr>
-                                        <td>合同内容</td><td>长文本</td><td><input type="text" class="form-control form-control-sm"></td>
-                                        <td><input type="checkbox" class=""></td>
-                                        <td>独占一行,上限1000</td>
-                                        <td>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-up"></i></a>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-down"></i></a>
-                                        </td>
-                                    </tr>
-                                    <tr>
-                                        <td>支付条件</td><td>长文本</td><td><input type="text" class="form-control form-control-sm"></td>
-                                        <td><input type="checkbox" class=""></td>
-                                        <td>独占一行,上限1000</td>
-                                        <td>
-                                            <a href="#" class="mx-2"><i class="fa fa-arrow-up"></i></a>
-                                            <a href="#" class="mx-2 text-muted"><i class="fa fa-arrow-down"></i></a>
-                                        </td>
-                                    </tr>
+                                    <tbody class="text-center" id="attribute-set-table">
+                                    <% for (const cs of attributeSet) { %>
+                                        <tr code="<%- cs.field %>">
+                                            <td><%- cs.name %></td><td><%- cs.type_name %></td>
+                                            <% if (cs.fixed.indexOf('alias') >= 0) { %>
+                                                <td class="disabled">-</td>
+                                            <% } else {%>
+                                                <td><input type="text" class="form-control form-control-sm" value="<%- cs.alias %>"></td>
+                                            <% } %>
+                                            <% if (cs.fixed.indexOf('show') >= 0 ) { %>
+                                                <td>
+                                                    <div class="form-check">
+                                                        <input class="form-check-input" type="checkbox" id="inlineCheckbox-<%- cs.code %>" checked="" disabled="">
+                                                        <label class="form-check-label" for="inlineCheckbox-<%- cs.code %>"></label>
+                                                    </div>
+                                                </td>
+                                            <% } else { %>
+                                                <td>
+                                                    <div class="form-check">
+                                                        <input class="form-check-input" type="checkbox" id="inlineCheckbox-<%- cs.code %>" <% if (cs.show) { %> checked <% } %> >
+                                                        <label class="form-check-label" for="inlineCheckbox-<%- cs.code %>"></label>
+                                                    </div>
+                                                </td>
+                                            <% } %>
+                                            <td><%- cs.tip %></td>
+                                            <td>
+                                                <a href="javascript:;" class="move-up text-primary mr-2" style="text-decoration: none;">上移</a>
+                                                <a href="javascript:;" class="move-down text-primary" style="text-decoration: none;">下移</a>
+                                            </td>
+                                        </tr>
+                                    <% } %>
                                     </tbody>
                                 </table>
                             </div>
@@ -262,4 +232,5 @@
     let tender_type = JSON.parse(unescape('<%- escape(JSON.stringify(tender_types)) %>'));
     let subProject_used = JSON.parse(unescape('<%- escape(JSON.stringify(used)) %>'));
     let tender_used = JSON.parse(unescape('<%- escape(JSON.stringify(tender_used)) %>'));
+    let attributeSet = JSON.parse(unescape('<%- escape(JSON.stringify(attributeSet)) %>'));
 </script>

+ 3 - 1
sql/update.sql

@@ -18,7 +18,9 @@ ADD COLUMN `times` tinyint(3) NULL DEFAULT 1 COMMENT '审批次数' AFTER `statu
 ADD COLUMN `sp_group` int(11) NULL DEFAULT 0 COMMENT '固定审批组id' AFTER `times`,
 ADD COLUMN `final_auditor_str` varchar(50) NOT NULL DEFAULT '' COMMENT '终审人相关(cache)' AFTER `sp_group`,
 ADD COLUMN `type` varchar(255) NULL DEFAULT '' COMMENT '合同类型(筛选的字段)' AFTER `final_auditor_str`,
-ADD COLUMN `remark1` varchar(1000) NULL DEFAULT '' COMMENT '备注1' AFTER `remark`;
+ADD COLUMN `remark1` varchar(1000) NULL DEFAULT '' COMMENT '备注1' AFTER `remark`,
+ADD COLUMN `tax` tinyint(3) NULL COMMENT '税率' AFTER `calc2`,
+ADD COLUMN `attribute_json` mediumtext NULL COMMENT '附加属性json' AFTER `tax`;
 
 ALTER TABLE `zh_contract_pay`
 ADD COLUMN `need_shenpi` tinyint(1) NULL COMMENT '是否需要审批' AFTER `fpcid`,