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

feat(contract): 添加重命名合同附件功能及相关路由

lanjianrong 1 неделя назад
Родитель
Сommit
8484e3a16a
3 измененных файлов с 106 добавлено и 2 удалено
  1. 34 0
      app/controller/contract_controller.js
  2. 66 2
      app/public/js/contract_detail.js
  3. 6 0
      app/router.js

+ 34 - 0
app/controller/contract_controller.js

@@ -1237,6 +1237,40 @@ module.exports = app => {
                 ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
+
+        /**
+         * 重命名合同附件
+         */
+        async renameFile(ctx) {
+            try {
+                const cid = ctx.params.cid;
+                const tid = parseInt(ctx.params.tid);
+                const cpid = parseInt(ctx.params.cpid);
+                const csid = parseInt(ctx.params.csid);
+                const data = JSON.parse(ctx.request.body.data);
+                if (!cid || !data.id) throw '参数错误';
+                const attService = cpid ? ctx.service.contractPayAtt : (csid ? ctx.service.contractSupplementAtt : ctx.service.contractAtt);
+                const file = await attService.getDataById(data.id);
+                if (!file || file.cid !== cid ||
+                    file.contract_type !== ctx.contract_type ||
+                    (tid ? file.tid !== tid : (file.tid || file.spid !== ctx.contractOptions.spid)) ||
+                    (cpid && file.cpid !== cpid) ||
+                    (csid && file.csid !== csid)) {
+                    throw '不存在该文件';
+                }
+                if (file.uid !== ctx.session.sessionUser.accountId) throw '没有权限重命名此附件';
+                const filename = typeof data.filename === 'string' ? data.filename.trim() : '';
+                if (!filename || filename.length > 255 || /[\\/:*?"<>|\x00-\x1f]/.test(filename)) throw '请输入有效的文件名称(最多255个字符)';
+                if (path.extname(filename).toLowerCase() !== (file.fileext || '').toLowerCase()) throw '不能修改文件后缀';
+                if (!path.parse(filename).name.trim()) throw '文件名称不能为空';
+                await attService.defaultUpdate({ id: file.id, filename });
+                const files = await attService.getAtt(cpid || csid || cid);
+                ctx.body = { err: 0, msg: '', data: files };
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
     }
 
     return ContractController;

+ 66 - 2
app/public/js/contract_detail.js

@@ -640,12 +640,13 @@ $(document).ready(function() {
                 return {...file, showDel}
             })
             newFiles.forEach((file, idx) => {
-                filesHtml += `<tr class="text-center">
-                                        <td>${idx + 1}</td><td class="text-left"><a href="${file.filepath}" target="_blank">${file.filename}</a></td><td>${file.username}</td><td>${moment(file.upload_time).format('YYYY-MM-DD HH:mm:ss')}</td>
+                filesHtml += `<tr class="text-center" data-file-id="${file.id}">
+                                        <td>${idx + 1}</td><td class="text-left contract-file-name"><a href="${file.filepath}" target="_blank">${_.escape(file.filename)}</a></td><td>${file.username}</td><td>${moment(file.upload_time).format('YYYY-MM-DD HH:mm:ss')}</td>
                                         <td>
                                             <div class="btn-group-table">
                                                 ${file.viewpath ? `<a href="${file.viewpath}" target="_blank" class="mr-1"><i class="fa fa-eye fa-fw"></i></a>` : ''}
                                                 <a href="${thisUrl}/${contractConst.typeMap[contract_type]}/${cid}${cpid ? '/pay/' + cpid : ''}/file/${file.id}/download" class="mr-1"><i class="fa fa-download fa-fw"></i></a>
+                                                ${file.showDel ? `<a href="javascript: void(0);" class="text-primary file-rename mr-1" data-id="${file.id}" title="重命名"><i class="fa fa-pencil fa-fw"></i></a>` : ''}
                                                 ${file.showDel ? `<a href="javascript: void(0);" class="text-danger file-del mr-1" data-id="${file.id}"><i class="fa fa-trash-o fa-fw text-danger"></i></a>` : ''}
                                             </div>
                                         </td>
@@ -5035,6 +5036,69 @@ $(document).ready(function() {
             );
         }
     };
+
+    $('body').on('click', '#htfile .file-rename, #cons-pay-file .file-rename, #cons-supplement-file .file-rename', function () {
+        const row = $(this).closest('tr');
+        const cell = row.find('.contract-file-name');
+        if (cell.find('input').length) return;
+        cell.data('filenameHtml', cell.html());
+        const filename = cell.find('a').text();
+        cell.empty().append(
+            $('<div class="d-flex align-items-center"></div>').append(
+                $('<input type="text" class="form-control form-control-sm form-control-width" maxlength="255">').val(filename),
+                $('<div class="btn-group-table ml-2"></div>').append(
+                    '<a href="javascript: void(0);" class="mr-1 file-rename-ok" title="保存"><i class="fa fa-check fa-fw"></i></a>',
+                    '<a href="javascript: void(0);" class="mr-1 file-rename-cancel" title="取消"><i class="fa fa-remove fa-fw"></i></a>'
+                )
+            )
+        );
+        cell.find('input').focus().select();
+    });
+    $('body').on('click', '#htfile .file-rename-cancel, #cons-pay-file .file-rename-cancel, #cons-supplement-file .file-rename-cancel', function () {
+        const cell = $(this).closest('.contract-file-name');
+        if (cell.data('saving')) return;
+        cell.html(cell.data('filenameHtml'));
+    });
+    $('body').on('click', '#htfile .file-rename-ok, #cons-pay-file .file-rename-ok, #cons-supplement-file .file-rename-ok', function () {
+        const row = $(this).closest('tr');
+        const cell = row.find('.contract-file-name');
+        if (cell.data('saving')) return;
+        const node = SpreadJsObj.getSelectObject(contractSheet);
+        if (!node || !node.c_code) return;
+        const payModal = row.closest('#cons-pay-file');
+        const supplementModal = row.closest('#cons-supplement-file');
+        const cpid = payModal.length ? Number(payModal.find('input[name="cpid"]').val()) : null;
+        const csid = supplementModal.length ? Number(supplementModal.find('input[name="csid"]').val()) : null;
+        const owner = cpid ? _.find(contractPays, { id: cpid }) :
+            (csid ? _.find(contractSupplements, { id: csid }) : node);
+        if (!owner) return;
+        const filename = cell.find('input').val().trim();
+        if (!filename) {
+            toastr.error('文件名称不能为空');
+            return;
+        }
+        cell.data('saving', true).find('input').prop('disabled', true);
+        const url = `${thisUrl}/${contractConst.typeMap[contract_type]}/${node.id}${cpid ? '/pay/' + cpid : (csid ? '/supplement/' + csid : '')}/file/rename`;
+        postData(url, { id: Number(row.attr('data-file-id')), filename }, function (files) {
+            owner.files = files;
+            if (cpid) {
+                contractTreeSpreadObj.openContractPayFiles(owner);
+            } else if (csid) {
+                contractTreeSpreadObj.openContractSupplementFiles(owner);
+            } else if (SpreadJsObj.getSelectObject(contractSheet) === node) {
+                contractTreeSpreadObj.setContractFiles(files, node.id);
+            }
+            toastr.success('重命名成功');
+        }, function () {
+            cell.data('saving', false).find('input').prop('disabled', false).focus();
+        });
+    });
+    $('body').on('keydown', '#htfile .contract-file-name input, #cons-pay-file .contract-file-name input, #cons-supplement-file .contract-file-name input', function (event) {
+        if (event.key === 'Enter' || event.key === 'Escape') {
+            event.preventDefault();
+            $(this).closest('.contract-file-name').find(event.key === 'Enter' ? '.file-rename-ok' : '.file-rename-cancel').click();
+        }
+    });
 });
 /**
  * 校验文件大小、格式

+ 6 - 0
app/router.js

@@ -349,9 +349,11 @@ module.exports = app => {
     app.post('/sp/:id/contract/tender/:tid/detail/:type/update', sessionAuth, subProjectCheck, contractCheck, 'contractController.updateBills');
     app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/file/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadFile');
     app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/file/delete', sessionAuth, subProjectCheck, contractCheck, 'contractController.deleteFile');
+    app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/file/rename', sessionAuth, subProjectCheck, contractCheck, 'contractController.renameFile');
     app.get('/sp/:id/contract/tender/:tid/detail/:type/:cid/file/:fid/download', sessionAuth, subProjectCheck, contractCheck, 'contractController.downloadFile');
     app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/pay/:cpid/file/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadFile');
     app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/pay/:cpid/file/delete', sessionAuth, subProjectCheck, contractCheck, 'contractController.deleteFile');
+    app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/pay/:cpid/file/rename', sessionAuth, subProjectCheck, contractCheck, 'contractController.renameFile');
     app.get('/sp/:id/contract/tender/:tid/detail/:type/:cid/pay/:cpid/file/:fid/download', sessionAuth, subProjectCheck, contractCheck, 'contractController.downloadFile');
     app.post('/sp/:id/contract/tender/:tid/col-set', sessionAuth, subProjectCheck, contractCheck, 'contractController.colSet');
     app.post('/sp/:id/contract/tender/:tid/col-set/copy', sessionAuth, subProjectCheck, contractCheck, 'contractController.copyColSet');
@@ -360,6 +362,7 @@ module.exports = app => {
     app.post('/sp/:id/contract/tender/:tid/detail/:type/check', sessionAuth, subProjectCheck, contractCheck, 'contractController.checkAudit');
     app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/supplement/:csid/file/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadFile');
     app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/supplement/:csid/file/delete', sessionAuth, subProjectCheck, contractCheck, 'contractController.deleteFile');
+    app.post('/sp/:id/contract/tender/:tid/detail/:type/:cid/supplement/:csid/file/rename', sessionAuth, subProjectCheck, contractCheck, 'contractController.renameFile');
     app.get('/sp/:id/contract/tender/:tid/detail/:type/:cid/supplement/:csid/file/:fid/download', sessionAuth, subProjectCheck, contractCheck, 'contractController.downloadFile');
     app.post('/sp/:id/contract/tender/:tid/detail/ai/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadAndAi');
     app.post('/sp/:id/contract/tender/:tid/detail/:type/ai/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadAndAi');
@@ -378,9 +381,11 @@ module.exports = app => {
     app.post('/sp/:id/contract/detail/:type/update', sessionAuth, subProjectCheck, contractCheck, 'contractController.updateBills');
     app.post('/sp/:id/contract/detail/:type/:cid/file/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadFile');
     app.post('/sp/:id/contract/detail/:type/:cid/file/delete', sessionAuth, subProjectCheck, contractCheck, 'contractController.deleteFile');
+    app.post('/sp/:id/contract/detail/:type/:cid/file/rename', sessionAuth, subProjectCheck, contractCheck, 'contractController.renameFile');
     app.get('/sp/:id/contract/detail/:type/:cid/file/:fid/download', sessionAuth, subProjectCheck, contractCheck, 'contractController.downloadFile');
     app.post('/sp/:id/contract/detail/:type/:cid/pay/:cpid/file/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadFile');
     app.post('/sp/:id/contract/detail/:type/:cid/pay/:cpid/file/delete', sessionAuth, subProjectCheck, contractCheck, 'contractController.deleteFile');
+    app.post('/sp/:id/contract/detail/:type/:cid/pay/:cpid/file/rename', sessionAuth, subProjectCheck, contractCheck, 'contractController.renameFile');
     app.get('/sp/:id/contract/detail/:type/:cid/pay/:cpid/file/:fid/download', sessionAuth, subProjectCheck, contractCheck, 'contractController.downloadFile');
     app.post('/sp/:id/contract/detail/check', sessionAuth, subProjectCheck, contractCheck, 'contractController.checkAudit');
     app.post('/sp/:id/contract/detail/:type/check', sessionAuth, subProjectCheck, contractCheck, 'contractController.checkAudit');
@@ -392,6 +397,7 @@ module.exports = app => {
     app.post('/sp/:id/contract/setting/update', sessionAuth, subProjectCheck, 'contractController.updateSetting');
     app.post('/sp/:id/contract/detail/:type/:cid/supplement/:csid/file/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadFile');
     app.post('/sp/:id/contract/detail/:type/:cid/supplement/:csid/file/delete', sessionAuth, subProjectCheck, contractCheck, 'contractController.deleteFile');
+    app.post('/sp/:id/contract/detail/:type/:cid/supplement/:csid/file/rename', sessionAuth, subProjectCheck, contractCheck, 'contractController.renameFile');
     app.get('/sp/:id/contract/detail/:type/:cid/supplement/:csid/file/:fid/download', sessionAuth, subProjectCheck, contractCheck, 'contractController.downloadFile');
     app.post('/sp/:id/contract/detail/ai/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadAndAi');
     app.post('/sp/:id/contract/detail/:type/ai/upload', sessionAuth, subProjectCheck, contractCheck, 'contractController.uploadAndAi');