MaiXinRong 1 день назад
Родитель
Сommit
39cddbd0bd

+ 82 - 45
app/controller/ledger_controller.js

@@ -1186,6 +1186,77 @@ module.exports = app => {
             }
             }
         }
         }
 
 
+        async aiRelaFile(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.rela_id || !data.rela_type) throw '参数错误';
+
+                const files = await ctx.service.tempFile.getFiles({ where: { tid: ctx.tender.id, rela_id: data.rela_id, rela_type: data.rela_type} });
+                ctx.body = { err: 0, msg: '', data: files }
+            } catch(err) {
+                ctx.log(err);
+                ctx.ajaxErrorBody(err, '获取历史文件失败');
+            }
+        }
+        async aiUploadFile(ctx) {
+            let stream;
+            try {
+                const parts = ctx.multipart({ autoFields: true });
+
+                let index = 0;
+                const create_time = Date.parse(new Date()) / 1000;
+                stream = await parts();
+                const user = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
+                const rela_id = parts.field.rela_id;
+                const rela_type = parts.field.rela_type;
+
+                const uploadfiles = [];
+                while (stream !== undefined) {
+                    if (!stream.filename) throw '未发现文件!';
+
+                    const fileInfo = path.parse(stream.filename);
+                    const filepath = `app/public/upload/${ctx.tender.id}/temp/${ctx.moment().format('YYYYMMDD')}/${create_time + '_' + index + fileInfo.ext}`;
+
+                    // 保存文件
+                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
+                    await sendToWormhole(stream);
+
+                    // 插入到stage_pay对应的附件列表中
+                    uploadfiles.push({
+                        rela_id, rela_type,
+                        filename: fileInfo.name,
+                        fileext: fileInfo.ext,
+                        filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size,
+                        filepath,
+                    });
+                    ++index;
+                    if (Array.isArray(parts.field.size) && index < parts.field.size.length) {
+                        stream = await parts();
+                    } else {
+                        stream = undefined;
+                    }
+                }
+                const result = await ctx.service.tempFile.addFiles(ctx.tender.id, uploadfiles, user);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (err) {
+                ctx.log(err);
+                if (stream) await sendToWormhole(stream);
+                ctx.ajaxErrorBody(err, '上传文件失败');
+            }
+        }
+        async aiDeleteFile(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.fid) throw '参数错误';
+
+                await ctx.service.tempFile.delFiles(data.fid);
+                ctx.body = {err: 0, msg: '', data: data.fid};
+            } catch(err) {
+                ctx.log(err);
+                ctx.ajaxErrorBody(err, '删除文件错误');
+            }
+        }
+
         async _aiCompliePosCalcDetail(ctx, data) {
         async _aiCompliePosCalcDetail(ctx, data) {
             const pos = await this.ctx.service.pos.getDataById(data.pos);
             const pos = await this.ctx.service.pos.getDataById(data.pos);
             if (!pos) throw '选择的计量单元不存在,请刷新页面后再试';
             if (!pos) throw '选择的计量单元不存在,请刷新页面后再试';
@@ -1285,63 +1356,29 @@ module.exports = app => {
             }
             }
         }
         }
         async aiComplie(ctx) {
         async aiComplie(ctx) {
-            let stream;
             try {
             try {
-                const parts = ctx.multipart({ autoFields: true });
-
-                let index = 0;
-                const create_time = Date.parse(new Date()) / 1000;
-                stream = await parts();
-                const user = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
-                const rela_id = parts.field.rela_id;
-                const rela_type = parts.field.rela_type;
-                const billsName = parts.field.rela_bills_name;
-                const rela_template = parts.field.rela_template;
-                const template = await ctx.service.calcTmpl.getTemplate(rela_template);
-                const keyword = parts.field.rela_keyword;
-                const billsType = parts.field.rela_billsType;
-
-                const uploadfiles = [];
-                while (stream !== undefined) {
-                    if (!stream.filename) throw '未发现上传文件!';
-
-                    const fileInfo = path.parse(stream.filename);
-                    const filepath = `app/public/upload/${ctx.tender.id}/temp/${ctx.moment().format('YYYYMMDD')}/${create_time + '_' + index + fileInfo.ext}`;
-
-                    // 保存文件
-                    await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
-                    await sendToWormhole(stream);
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data.rela_id || !data.rela_type || !data.template || !data.fid) throw '参数错误';
 
 
-                    // 插入到stage_pay对应的附件列表中
-                    uploadfiles.push({
-                        rela_id, rela_type,
-                        filename: fileInfo.name,
-                        fileext: fileInfo.ext,
-                        filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size,
-                        filepath,
-                    });
-                    ++index;
-                    if (Array.isArray(parts.field.size) && index < parts.field.size.length) {
-                        stream = await parts();
-                    } else {
-                        stream = undefined;
-                    }
-                }
-                const result = await ctx.service.tempFile.addFiles(ctx.tender.id, uploadfiles, user);
+                const billsName = data.bills_name;
+                const template = await ctx.service.calcTmpl.getTemplate(data.template);
+                const keyword = data.keyword || '';
+                const billsType = data.billsType;
+                const files = await ctx.service.tempFile.getFiles({ where: { id: data.fid }});
+                if (!files || files.length === 0) throw '文件已被删除,请刷新页面后重试';
 
 
-                switch(rela_type) {
+                switch(data.rela_type) {
                     case 'pos':
                     case 'pos':
-                        await this._aiCompliePosCalcDetail(ctx, { billsName, template, pos: rela_id, files: result, keyword });
+                        await this._aiCompliePosCalcDetail(ctx, { billsName, template, pos: data.rela_id, files, keyword });
                         break;
                         break;
                     case 'bills':
                     case 'bills':
-                        await this._aiCompliePosAndDetail(ctx, { billsName, template, bills: rela_id, files: result, keyword, billsType });
+                        await this._aiCompliePosAndDetail(ctx, { billsName, template, bills: data.rela_id, files, keyword, billsType });
                         break;
                         break;
                     default:
                     default:
                         throw '暂不提供该ai识别内容';
                         throw '暂不提供该ai识别内容';
                 }
                 }
             } catch (err) {
             } catch (err) {
                 ctx.log(err);
                 ctx.log(err);
-                if (stream) await sendToWormhole(stream);
                 ctx.ajaxErrorBody(err, 'ai识别填写失败');
                 ctx.ajaxErrorBody(err, 'ai识别填写失败');
             }
             }
         }
         }

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

@@ -4223,6 +4223,7 @@ $(document).ready(function() {
         billsTag.loadDatas(data.tags);
         billsTag.loadDatas(data.tags);
         SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), 'tree', ledgerTree);
         SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), 'tree', ledgerTree);
         SpreadJsObj.loadTopAndSelect(ledgerSpread.getActiveSheet(), ckBillsSpread);
         SpreadJsObj.loadTopAndSelect(ledgerSpread.getActiveSheet(), ckBillsSpread);
+        aiTrans.setRelaInfo('bills', SpreadJsObj.getSelectObject(ledgerSheet), SpreadJsObj.getSelectObject(ledgerSheet));
 
 
         posOperationObj.loadCurPosData();
         posOperationObj.loadCurPosData();
         SpreadJsObj.resetTopAndSelect(posSpread.getActiveSheet());
         SpreadJsObj.resetTopAndSelect(posSpread.getActiveSheet());

+ 144 - 16
app/public/js/shares/ai_trans.js

@@ -7,6 +7,57 @@ const AITrans = function() {
                 this.spread = SpreadJsObj.createNewSpread($('#ai-trans-grid-spread')[0]);
                 this.spread = SpreadJsObj.createNewSpread($('#ai-trans-grid-spread')[0]);
                 this.spread.options.tabStripVisible = true;
                 this.spread.options.tabStripVisible = true;
             }
             }
+        },
+        getFileMiniHtml: function(file) {
+            const html = [];
+            html.push(`<div class="card mb-2 p-1 thumbnail-container" fid="${file.id}" name="ai-his-file" title="${file.filename+file.fileext}">`);
+            html.push('<div class="ai-del-btn text-danger"><span aria-hidden="true">&times;</span></div>');
+            html.push(`<img src="${file.viewpath}">`);
+            html.push('</div>');
+            return html.join('');
+        },
+        selectFile: function(fid) {
+            $('[name=ai-his-file]').removeClass('thumbnail-active');
+            $(`[fid="${fid}"]`).addClass('thumbnail-active');
+            transResultObj.showFile(fid);
+        },
+        afterUploadFile: function(file) {
+            if (!this.rela_node.aiRelaFile) this.rela_node.aiRelaFile = [];
+            this.rela_node.aiRelaFile.push(file);
+            $('#ai-trans-file-add').parent().append(this.getFileMiniHtml(file));
+            this.selectFile(file.id);
+        },
+        deleteFile: function(fid) {
+            const fileIndex = transResultObj.rela_node.aiRelaFile.findIndex(x => { return x.id === fid; });
+            const file = transResultObj.rela_node.aiRelaFile[fileIndex];
+            if (!file) return;
+            const fileObj = $(`[fid="${fid}"]`);
+            if (fileObj.hasClass('thumbnail-active')) {
+                $('#ai-trans-show-file').attr('src', "");
+            }
+
+            postData(window.location.pathname + '/ai/deleteFile', { fid }, function(){
+                transResultObj.rela_node.aiRelaFile.splice(fileIndex, 1);
+                fileObj.remove();
+            });
+        },
+        reloadAiRelaFile: function() {
+            $('#ai-trans-file-add').nextAll().remove();
+            const html = [];
+            for (const file of this.rela_node.aiRelaFile) {
+                html.push(this.getFileMiniHtml(file));
+            }
+            $('#ai-trans-file-add').after(html.join(''));
+        },
+        loadAiRelaFile: async function() {
+            if (this.rela_node.aiRelaFile) return;
+            this.rela_node.aiRelaFile = await postDataAsync(window.location.pathname + '/ai/file', { rela_id: this.rela_node.id, rela_type: this.rela_type });
+            this.reloadAiRelaFile();
+            $('#ai-trans-show-file').attr('src', '');
+        },
+        showFile: function(fid) {
+            const file = this.rela_node.aiRelaFile.find(x => { return x.id === fid; });
+            $('#ai-trans-show-file').attr('src', file.viewpath);
         }
         }
     };
     };
     $('#ai-trans-grid').bind('shown.bs.modal', function() {
     $('#ai-trans-grid').bind('shown.bs.modal', function() {
@@ -57,21 +108,29 @@ const AITrans = function() {
         $('#ai-trans-grid').modal('show');
         $('#ai-trans-grid').modal('show');
     };
     };
 
 
-    $('#ai-trans-ok').click(function() {
-        const files = $('#ai-trans-file')[0].files;
-        if (!files || files.length === 0) return;
-
+    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) {
+        e.preventDefault();
+        e.dataTransfer.dropEffect = 'copy';
+    });
+    document.getElementById('ai-trans-file-add').addEventListener('drop', function(e) {
+        if (transResultObj.rela_node.aiRelaFile && transResultObj.rela_node.aiRelaFile.length >= 3) {
+            toastr.warning('保存的图片超过限制,请先删除旧图片后再操作');
+            return;
+        }
+        e.preventDefault();
+        const files = e.dataTransfer.files;
         const formData = new FormData();
         const formData = new FormData();
         formData.append('rela_type', transResultObj.rela_type);
         formData.append('rela_type', transResultObj.rela_type);
         formData.append('rela_id', transResultObj.rela_id);
         formData.append('rela_id', transResultObj.rela_id);
-        if (transResultObj.rela_type === 'ancGcl') {
-            formData.append('rela_template', transResultObj.rela_node.calc_template);
-        } else {
-            formData.append('rela_template', transResultObj.rela_bills.calc_template);
-        }
-        formData.append('rela_bills_name', transResultObj.rela_bills.name);
-        formData.append('rela_keyword', $('#ai-trans-keyword').val());
-        formData.append('rela_billsType', transResultObj.billsType);
         for (const file of files) {
         for (const file of files) {
             if (file === undefined) {
             if (file === undefined) {
                 toastr.error('未选择图片!');
                 toastr.error('未选择图片!');
@@ -90,13 +149,79 @@ const AITrans = function() {
             formData.append('size', filesize);
             formData.append('size', filesize);
             formData.append('file[]', file);
             formData.append('file[]', file);
         }
         }
-        postDataWithFile(window.location.pathname + '/aiComplie', formData, function (data) {
+        postDataWithFile(window.location.pathname + '/ai/uploadFile', formData, function (data) {
+            transResultObj.afterUploadFile(data[0]);
+        });
+    });
+    $('body').on('click', '[name=ai-his-file]', function() {
+        transResultObj.selectFile(this.getAttribute('fid'));
+    });
+    $("#ai-trans-file-add").on('paste', function(e) {
+        let file = null;
+        const data = (event.clipboardData || window.clipboardData).items;
+        for (let i = 0; i < data.length; i += 1) {
+            if ((data[i].kind == 'file') && (data[i].type.match('^image/'))) {
+                file = data[i].getAsFile();
+                break;
+            }
+        }
+        if (file) {
+            const formData = new FormData();
+            formData.append('rela_type', transResultObj.rela_type);
+            formData.append('rela_id', transResultObj.rela_id);
+            formData.append('file', file);
+            formData.append('size', file.size);
+            console.log(formData);
+            postDataWithFile(window.location.pathname + '/ai/uploadFile', formData, function (data) {
+                transResultObj.afterUploadFile(data[0]);
+            });
+        }
+    });
+    $('body').on('click', '.ai-del-btn', function() {
+        const fid = $(this).parent().attr('fid');
+        transResultObj.deleteFile(fid);
+        e.stopPropagation();
+    });
+    $('#ai-trans-ok').click(function() {
+        const files = $('.thumbnail-container');
+        if (files.length === 0) {
+            toastr.warning('请先上传/拖动/粘贴图片');
+            return;
+        }
+        const select = $('.thumbnail-active')[0];
+        if (!select) {
+            toastr.warning('请选择历史图片,或者重新上传/拖动/粘贴图片');
+            return;
+        }
+        const complieData = {
+            rela_id: transResultObj.rela_node.id,
+            rela_type: transResultObj.rela_type,
+            fid: select.getAttribute('fid'),
+            billsType: transResultObj.billsType,
+            keyword: $('#ai-trans-keyword').val(),
+            bills_name: transResultObj.rela_bills.name,
+        };
+        if (transResultObj.rela_type === 'ancGcl') {
+            complieData.template = transResultObj.rela_node.calc_template;
+        } else {
+            complieData.template = transResultObj.rela_bills.calc_template;
+        }
+
+        postData(window.location.pathname + '/ai/complie', complieData, function (data) {
             if (transResultObj.callback) transResultObj.callback(data);
             if (transResultObj.callback) transResultObj.callback(data);
             $('#ai-trans').modal('hide');
             $('#ai-trans').modal('hide');
         });
         });
     });
     });
-    const transDetail = function(callback) {
+    const transDetail = async function(callback) {
+        if (transResultObj.rela_type === 'bills') {
+            $('#ai-trans-title').html(`AI识别部位(${transResultObj.rela_node.b_code} ${transResultObj.rela_node.name})`);
+        } else if (transResultObj.rela_type === 'pos') {
+            $('#ai-trans-title').html(`AI识别设计量细目(${transResultObj.rela_bills.b_code} ${transResultObj.rela_bills.name} / ${transResultObj.rela_node.name})`);
+        } else if (transResultObj.rela_type === 'ancGcl') {
+            $('#ai-trans-title').html(`AI识别附属工程量明细(${transResultObj.rela_bills.b_code} ${transResultObj.rela_bills.name} / ${transResultObj.rela_node.name})`);
+        }
         transResultObj.callback = callback;
         transResultObj.callback = callback;
+        transResultObj.loadAiRelaFile();
         $('#ai-trans').modal('show');
         $('#ai-trans').modal('show');
     };
     };
     const billsIdentify = function (callback) {
     const billsIdentify = function (callback) {
@@ -113,5 +238,8 @@ const AITrans = function() {
         transResultObj.rela_id = rela_node ? rela_node.id : undefined;
         transResultObj.rela_id = rela_node ? rela_node.id : undefined;
         transResultObj.rela_bills = rela_bills;
         transResultObj.rela_bills = rela_bills;
     };
     };
-    return { show, setRelaInfo, billsIdentify, transDetail, rela_type: function() {return transResultObj.rela_type} }
-};
+    return {
+        show,
+        setRelaInfo, billsIdentify, transDetail, rela_type: function() {return transResultObj.rela_type}
+    }
+}

+ 4 - 1
app/router.js

@@ -712,7 +712,10 @@ module.exports = app => {
     app.post('/tender/:id/ledger/deal2sgfh', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.deal2sgfh');
     app.post('/tender/:id/ledger/deal2sgfh', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.deal2sgfh');
     app.post('/tender/:id/ledger/sgfh2deal', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.sgfh2deal');
     app.post('/tender/:id/ledger/sgfh2deal', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.sgfh2deal');
     app.post('/tender/:id/ledger/check', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.check');
     app.post('/tender/:id/ledger/check', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.check');
-    app.post('/tender/:id/ledger/aiComplie', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.aiComplie');
+    app.post('/tender/:id/ledger/ai/file', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.aiRelaFile');
+    app.post('/tender/:id/ledger/ai/uploadFile', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.aiUploadFile');
+    app.post('/tender/:id/ledger/ai/deleteFile', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.aiDeleteFile');
+    app.post('/tender/:id/ledger/ai/complie', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.aiComplie');
     app.post('/tender/:id/measure/ledger/auditors', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.ledgerAuditors');
     app.post('/tender/:id/measure/ledger/auditors', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.ledgerAuditors');
     app.get('/tender/:id/ledger/cpd', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.exportLedgerData');
     app.get('/tender/:id/ledger/cpd', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.exportLedgerData');
     app.post('/tender/:id/ledger/cpd/load', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.importLedgerData');
     app.post('/tender/:id/ledger/cpd/load', sessionAuth, tenderCheck, subProjectCheck, uncheckTenderCheck, 'ledgerController.importLedgerData');

+ 1 - 1
app/service/temp_file.js

@@ -35,7 +35,7 @@ module.exports = app => {
         }
         }
 
 
         async getFiles(condition) {
         async getFiles(condition) {
-            condition.orders = [['create_time', 'desc']];
+            condition.orders = [['create_time', 'asc']];
             const result = await this.getAllDataByCondition(condition);
             const result = await this.getAllDataByCondition(condition);
             this._analysisData(result);
             this._analysisData(result);
             return result;
             return result;

+ 85 - 10
app/view/shares/ai_trans.ejs

@@ -19,31 +19,106 @@
         </div>
         </div>
     </div>
     </div>
 </div>
 </div>
+<!--<div class="modal fade" id="ai-trans" data-backdrop="static">-->
+    <!--<div class="modal-dialog modal-lg" role="document">-->
+        <!--<div class="modal-content">-->
+            <!--<div class="modal-header">-->
+                <!--<h5 class="modal-title">AI识别</h5>-->
+                <!--<button type="button" class="close" data-dismiss="modal" aria-label="Close">-->
+                    <!--<span aria-hidden="true">&times;</span>-->
+                <!--</button>-->
+            <!--</div>-->
+            <!--<div class="modal-body">-->
+                <!--<div class="form-group">-->
+                    <!--<label for="ai-trans-file">选择文件</label><i class="fa fa-spinner fa-pulse fa-lg fa-fw text-primary" id="select-excel-loading" style="display: none;"></i>-->
+                    <!--<input type="file" class="form-control-file" id="ai-trans-file" accept="*.json" name="file">-->
+                <!--</div>-->
+                <!--<div class="form-group">-->
+                    <!--<label for="ai-trans-file">高级设置</label>-->
+                    <!--<div class="input-group input-group-sm ml-2 mt-1">-->
+                        <!--<div class="input-group-prepend">-->
+                            <!--<span class="input-group-text">仅识别:</span>-->
+                        <!--</div>-->
+                        <!--<input type="text" class="form-control mr-3" style="width: 240px" value="" id="ai-trans-keyword">-->
+                    <!--</div>-->
+                <!--</div>-->
+            <!--</div>-->
+            <!--<div class="modal-footer">-->
+                <!--<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>-->
+            <!--</div>-->
+        <!--</div>-->
+    <!--</div>-->
+<!--</div>-->
 <div class="modal fade" id="ai-trans" data-backdrop="static">
 <div class="modal fade" id="ai-trans" data-backdrop="static">
+    <style>
+        .thumbnail-active {
+            border: 1px solid dodgerblue; !important;
+        }
+        .thumbnail-container img {
+            width: 100%;
+            height: 90px;
+            border: 1px solid #ddd;
+            border-radius: 4px;
+            transition: transform 0.2s;
+        }
+        .ai-del-btn {
+            position: absolute;
+            top: 0;
+            right: 0;
+            background: none;
+            border: none;
+            cursor: pointer;
+            font-size: 20px;
+            font-weight: bolder;
+            line-height: normal;
+            margin-top: -0.5em;
+        }
+        img[src=""],img:not([src]){
+            opacity:0;
+        }
+    </style>
     <div class="modal-dialog modal-lg" role="document">
     <div class="modal-dialog modal-lg" role="document">
         <div class="modal-content">
         <div class="modal-content">
             <div class="modal-header">
             <div class="modal-header">
-                <h5 class="modal-title">AI识别</h5>
+                <h5 class="modal-title" id="ai-trans-title">AI识别</h5>
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                     <span aria-hidden="true">&times;</span>
                     <span aria-hidden="true">&times;</span>
                 </button>
                 </button>
             </div>
             </div>
             <div class="modal-body">
             <div class="modal-body">
                 <div class="form-group">
                 <div class="form-group">
-                    <label for="ai-trans-file">选择文件</label><i class="fa fa-spinner fa-pulse fa-lg fa-fw text-primary" id="select-excel-loading" style="display: none;"></i>
-                    <input type="file" class="form-control-file" id="ai-trans-file" accept="*.json" name="file">
-                </div>
-                <div class="form-group">
-                    <label for="ai-trans-file">高级设置</label>
-                    <div class="input-group input-group-sm ml-2 mt-1">
-                        <div class="input-group-prepend">
-                            <span class="input-group-text">仅识别:</span>
+                    <div class="row">
+                        <div class="col-2">
+                            <div class="text-black-50 mb-2">可Ctrl+V粘贴图片</div>
+                            <div class="card mb-2" id="ai-trans-file-add">
+                                <div class="card-body">
+                                    <div class="d-flex p-1" >
+                                        <!--<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>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="col-10">
+                            <div class="image-view border" style="height: 500px">
+                                <img class="w-100 h-100" id="ai-trans-show-file" style="object-fit: contain">
+                            </div>
                         </div>
                         </div>
-                        <input type="text" class="form-control mr-3" style="width: 240px" value="" id="ai-trans-keyword">
                     </div>
                     </div>
                 </div>
                 </div>
+                <!--<div class="form-group">-->
+                    <!--<label for="ai-trans-file">高级设置</label>-->
+                    <!--<div class="input-group input-group-sm ml-2 mt-1">-->
+                        <!--<div class="input-group-prepend">-->
+                            <!--<span class="input-group-text">仅识别:</span>-->
+                        <!--</div>-->
+                        <!--<input type="text" class="form-control mr-3" style="width: 240px" value="" id="ai-trans-keyword">-->
+                    <!--</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">
                 <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>