ソースを参照

驳回指导函

zhuliu 6 日 前
コミット
b0a1bfe7ec

+ 2 - 1
public/index.html

@@ -7,8 +7,9 @@
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
     <title><%= htmlWebpackPlugin.options.title %></title>
 </head>
+<script type="text/javascript" src="<%= htmlWebpackPlugin.options.onlyOffice %>"></script>
 <!-- <script type="text/javascript" src="http://192.168.2.24:9997/web-apps/apps/api/documents/api.js"></script> -->
-<script type="text/javascript" src="https://fms.xsip.cn/web-apps/apps/api/documents/api.js"></script>
+<!-- <script type="text/javascript" src="https://fms.xsip.cn/web-apps/apps/api/documents/api.js"></script> -->
 
 <body>
 <div id="app" ></div>

+ 6 - 1
src/api/newApi/AI.js

@@ -53,5 +53,10 @@ export default {
         return axios.post("/xiaoshi/dify/oa/generateResult", data);
     },
 
-    
+    /**
+     * 生成驳回指导函
+     */
+    generateRejection(data) {
+        return axios.post("/AI/generateRejection", data);
+    },
 }

+ 129 - 0
src/assets/css/main.scss

@@ -292,4 +292,133 @@
 .link{
   color: #409EFF;
   cursor: pointer;
+}
+
+.file_type_list{
+  list-style-type: none;
+  padding: 0;
+  .file-item {
+    padding: 15px;
+    margin: 10px 0;
+    border-radius: 5px;
+    display: flex;
+    align-items: center;
+    transition: all 0.3s ease;
+    border-left: 5px solid #ddd;
+    &:hover {
+      transform: translateY(-2px);
+      box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+    }
+  }
+  .word{
+    border-left-color: #2b579a;
+    background-color: #eaf2ff;
+  }
+  .excel{
+    border-left-color: #207245;
+    background-color: #e8f5e9;
+  }
+  .powerpoint{
+    border-left-color: #d24726;
+    background-color: #ffebee;
+  }
+  .pdf{
+    border-left-color: #e53935;
+    background-color: #ffebee !important;
+  }
+  .image{
+    border-left-color: #5e35b1;
+    background-color: #f3e5f5;
+  }
+  .video{
+    border-left-color: #00838f;
+    background-color: #e0f7fa;
+  }
+  .audio{
+    border-left-color: #ff8f00;
+    background-color: #fff3e0;
+  }
+  .archive{
+    border-left-color: #607d8b;
+    background-color: #eceff1;
+  }
+  .text{
+    border-left-color: #1976d2;
+    background-color: #e3f2fd;
+  }
+  .file-icon {
+    font-size: 28px;
+    margin-right: 15px;
+    width: 30px;
+    text-align: center;
+  }
+  .file-info {
+    flex-grow: 1;
+  }
+  
+  .file-name {
+    font-weight: bold;
+    font-size: 16px !important;
+    margin-bottom: 5px;
+  }
+  
+  .file-type {
+    font-size: 14px !important;
+    color: #666;
+  }
+  
+  .file-size {
+    font-size: 12px !important;
+    color: #999;
+  }
+
+  .file-extension {
+    background-color: #eee;
+    padding: 2px 6px;
+    border-radius: 3px;
+    font-size: 12px;
+    margin-left: 5px;
+  }
+  /* 预览按钮 - 更自然的设计 */
+  .preview-btn {
+    background: transparent;
+    color: #2196F3;
+    border: 1px solid #2196F3;
+    padding: 8px 16px;
+    border-radius: 6px;
+    cursor: pointer;
+    font-size: 14px;
+    font-weight: 500;
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+    position: relative;
+    overflow: hidden;
+    z-index: 1;
+  }
+  
+  .preview-btn::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background: #2196F3;
+    z-index: -1;
+    transform: scaleX(0);
+    transform-origin: right;
+    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  }
+  
+  .preview-btn:hover {
+    color: white;
+  }
+  
+  .preview-btn:hover::before {
+    transform: scaleX(1);
+    transform-origin: left;
+  }
+  
+  .preview-btn:active {
+    transform: scale(0.98);
+  }
 }

ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/EXCEL.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/IMAGE.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/PPTX.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/Pdf.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/Video.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/WORD.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/audio.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/txt文件.svg


ファイルの差分が大きいため隠しています
+ 1 - 0
src/icons/fileTypeSvg/压缩通用.svg


+ 2 - 0
src/icons/index.js

@@ -5,5 +5,7 @@ import SvgIcon from '@/components/SvgIcon'// svg component
 Vue.component('svg-icon', SvgIcon)
 
 const req = require.context('./svg', false, /\.svg$/)
+const req1 = require.context('./fileTypeSvg', false, /\.svg$/)
 const requireAll = requireContext => requireContext.keys().map(requireContext)
 requireAll(req)
+requireAll(req1)

+ 61 - 0
src/utils/constants.js

@@ -270,5 +270,66 @@ litigationResult:{
   4:"二审驳回上诉请求",
   5:"二审依法改判或撤销或变更",
   6:"二审查清事实后改判",
+},
+
+
+// 文件类型图标
+fileIconTypeOption:{
+  word: "WORD",
+  excel: "EXCEL",
+  powerpoint: "PPTX",
+  pdf: "Pdf",
+  image: "IMAGE",
+  video: "Video",
+  audio: "audio",
+  archive: "压缩通用",
+  text: "txt文件"
+},
+fileIconTypeOption1:{
+  word: "📝",
+  excel: "📊",
+  powerpoint: "📽️",
+  pdf: "📄",
+  image: "🖼️",
+  video: "🎬",
+  audio: "🎵",
+  archive: "📦",
+  text: "📝"
+},
+fileTypeOption:{
+  pdf:'pdf',
+  doc:'word',
+  docx:'word',
+  xls: 'excel',
+  xlsx: 'excel',
+  ppt: 'powerpoint',
+  pptx: 'powerpoint',
+  jpg: 'image',
+  jpeg: 'image',
+  png: 'image',
+  gif: 'image',
+  bmp: 'image',
+  tiff: 'image',
+  svg: 'image',
+  webp: 'image',
+  mp4: 'video',
+  avi: 'video',
+  mov: 'video',
+  mkv: 'video',
+  flv: 'video',
+  wmv: 'video',
+  webm: 'video',
+  mp3: 'audio',
+  wav: 'audio',
+  aac: 'audio',
+  flac: 'audio',
+  ogg: 'audio',
+  m4a: 'audio',
+  zip: 'archive',
+  rar: 'archive',
+  '7z': 'archive',
+  tar: 'archive',
+  gz: 'archive',
 }
 }
+

+ 2 - 2
src/views/AITools/OADefense/OADefense1.vue

@@ -215,10 +215,10 @@
                                     <el-input type="textarea" v-model="changeClaim.claimChangeSuggestion" :rows="6" placeholder="请输入修改建议或者修改后的权利要求"></el-input>
                                 </div>
                             </div>
-                            <div>
+                            <div style="font-size:18px;font-weight:bold">
                                 <span class="file_title">一键全部生成:</span>
                                 <span>
-                                    <el-radio-group v-model="onceAllGenerate">
+                                    <el-radio-group v-model="onceAllGenerate" size="medium">
                                         <el-radio :label="1">是</el-radio>
                                         <el-radio :label="2">否</el-radio>
                                     </el-radio-group>   

+ 4 - 4
src/views/AITools/assistWritingInstruction/mixins/index.js

@@ -19,10 +19,10 @@ export default {
                 this.$message.warning('请等待文件上传成功')
                 return
             }
-            if(!this.inputs.tec_file.name && !this.inputs.tec_file.guid){
-                this.$message.warning('请上传技术交底书')
-                return
-            }
+            // if(!this.inputs.tec_file.name && !this.inputs.tec_file.guid){
+            //     this.$message.warning('请上传技术交底书')
+            //     return
+            // }
             if(!this.inputs.claim){
                 this.$message.warning('请输入权利要求')
                 return

+ 203 - 0
src/views/AITools/rejection_guidance_letter/components/dialog/errorTip.vue

@@ -0,0 +1,203 @@
+<template>
+  <div>
+    <el-dialog title="文件解析失败提示" :visible.sync="visible" width="600px" :before-close="handleClose" :close-on-click-modal="false" :modal-append-to-body="false">
+        <div class="addRejectionGuidanceLetter">
+            <div style="font-size:16px;color:red" v-html="tip"></div>
+            <p style="font-size:18px;color:black"><b>请上传可解析的文件:</b></p>
+            <div class="upload-box-container" style="margin-top:5px">
+              <!-- 驳回决定书 -->
+              <div v-if="ruleForm.rejection_decision">
+                <div v-if="ruleForm.rejection_decision.showPercentage || ruleForm.rejection_decision.guid" class="upload-box upload">
+                    <div class="upload-placeholder">驳回决定书</div>
+                    <div class="file-info"><span v-if="!ruleForm.rejection_decision.showPercentage">已上传:</span><span class="file-name">{{ruleForm.rejection_decision.name ? ruleForm.rejection_decision.name : ruleForm.rejection_decision.originalName}}</span></div>
+                    <div v-if="ruleForm.rejection_decision.showPercentage" class="progressShow">
+                        <el-progress :percentage="ruleForm.rejection_decision.percentage"></el-progress>
+                    </div>
+                    <span class="clear-btn" @click="ruleForm.rejection_decision = {}">× 清除</span>
+                </div>
+                <el-upload
+                    v-else
+                    ref="upload_file"
+                    class="upload-demo"
+                    drag
+                    action="#"
+                    :auto-upload="false"
+                    :show-file-list='false'
+                    :limit="1"
+                    :on-change="(file)=>onChange(file,'ruleForm.rejection_decision')"
+                    style="width: 100%"
+                >
+                    <div class="el-upload__text">
+                        <div>驳回决定书</div>
+                        <div>点击或拖到上传</div>
+                    </div>
+                </el-upload>
+              </div>
+              <!-- 审通文件 -->
+              <template v-if="ruleForm.review_files">
+                <template  v-for="review_files in ruleForm.review_files">
+                  <div v-if="review_files.examination_opinion" :key="'D'+review_files.num+'审查意见通知书'">
+                    <div v-if="review_files.examination_opinion.showPercentage || review_files.examination_opinion.guid" class="upload-box">
+                        <div class="upload-placeholder">第{{review_files.num}}次审查意见通知书</div>
+                        <div class="file-info"><span v-if="!review_files.examination_opinion.showPercentage">已上传:</span><span class="file-name">{{review_files.examination_opinion.name ? review_files.examination_opinion.name : review_files.examination_opinion.originalName}}</span></div>
+                        <div v-if="review_files.examination_opinion.showPercentage" class="progressShow">
+                            <el-progress :percentage="review_files.examination_opinion.percentage"></el-progress>
+                        </div>
+                        <span class="clear-btn" @click="review_files.examination_opinion = {}">× 清除</span>
+                    </div>
+                    <el-upload
+                        v-else
+                        ref="upload_file"
+                        class="upload-demo"
+                        drag
+                        action="#"
+                        :auto-upload="false"
+                        :show-file-list='false'
+                        :limit="1"
+                        :on-change="(file)=>onChange(file,'examination_opinion',review_files)"
+                        style="width: 100%"
+                    >
+                        <div class="el-upload__text">
+                            <div class="upload-placeholder">第{{review_files.num}}次审查意见通知书</div>
+                            <div class="upload-placeholder">点击或拖拽上传</div>
+                        </div>
+                    </el-upload>
+                  </div>
+                  <div v-if="review_files.state_opinions" :key="'D'+review_files.num+'递交文件合并档'">
+                    <div v-if="review_files.state_opinions.showPercentage || review_files.state_opinions.guid" class="upload-box">
+                        <div class="upload-placeholder">第{{review_files.num}}次递交文件合并档</div>
+                        <div class="file-info"><span v-if="!review_files.state_opinions.showPercentage">已上传:</span><span class="file-name">{{review_files.state_opinions.name ? review_files.state_opinions.name : review_files.state_opinions.originalName}}</span></div>
+                        <div v-if="review_files.state_opinions.showPercentage" class="progressShow">
+                            <el-progress :percentage="review_files.state_opinions.percentage"></el-progress>
+                        </div>
+                        <span class="clear-btn" @click="review_files.state_opinions = {}">× 清除</span>
+                    </div>
+                    <el-upload
+                        v-else
+                        ref="upload_file"
+                        class="upload-demo"
+                        drag
+                        action="#"
+                        :auto-upload="false"
+                        :show-file-list='false'
+                        :limit="1"
+                        :on-change="(file)=>onChange(file,'state_opinions',review_files)"
+                        style="width: 100%"
+                    >
+                        <div class="el-upload__text">
+                            <div class="upload-placeholder">第{{review_files.num}}次递交文件合并档</div>
+                            <div class="upload-placeholder">点击或拖拽上传</div>
+                        </div>
+                    </el-upload>
+                  </div>
+                </template>
+              </template>
+            </div>
+        </div>
+        <span slot="footer" class="dialog-footer">
+          <el-button size="mini" @click="handleClose">取 消</el-button>
+          <el-button size="mini" type="primary" :loading="loading" @click="submit">再次运行</el-button>
+        </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  props: {},
+  data() {
+    return {
+        visible:false,
+        loading:false,
+        tip:'',
+        ruleForm:{}
+    };
+  },
+  watch: {},
+  computed: {},
+  created() {},
+  mounted() {},
+  methods: {
+    open(data){
+        this.tip = data.message.replace('\n','<br>')
+        this.ruleForm = data.data
+        this.visible = true
+    },
+    handleClose(){
+        this.visible = false
+    },
+    submit(){
+        let rejection_decision = this.ruleForm.rejection_decision
+        if(rejection_decision && !rejection_decision.guid){
+            this.$message.error('请上传驳回决定书')
+            return
+        }
+        let review_files = this.ruleForm.review_files
+        let files = review_files.filter(item=>{
+            return (item.examination_opinion && !item.examination_opinion.guid) || (item.state_opinions && !item.state_opinions.guid)
+        })
+        if(files && files.length){
+            let str = files.map(item=>item.num).join('、')
+            this.$message(`第${str}次审通文件未全部上传`)
+            return false
+        }
+        this.$emit('submit',this.ruleForm)
+        this.handleClose()
+    },
+     //上传文件
+    setData(row,field,value){
+      var fieldArray = field.split('.')
+      let current = row || this;  
+      // 遍历路径中的每一部分,直到最后一个属性的父对象  
+      for (let i = 0; i < fieldArray.length - 1; i++) {  
+          // 确保当前对象有下一个属性,否则创建一个空对象(或你需要的任何默认值)  
+          if (!current.hasOwnProperty(fieldArray[i])) {  
+              current[fieldArray[i]] = {};  
+          }  
+          current = current[fieldArray[i]];  
+      }  
+      
+      // 给最后一个属性赋值  
+      current[fieldArray[fieldArray.length - 1]] = value;  
+    },
+    onChange(file,field,row){
+      let formData = new FormData()
+      formData.append('sourceId',this.$constants.sourceId)
+      formData.append('files',file.raw)
+      let fileName = file.raw.name
+      let arr = fileName.split('.')
+      let type = arr[arr.length - 1]
+      var notice_file = {
+          name:fileName,
+          type:type.toLowerCase()
+      }
+      var message = this.$message({
+          message: '文件上传中...',
+          type: 'warning',
+          duration:0
+      });
+      this.$api.uploadFile(formData,(percent)=>{
+          if(!notice_file.showPercentage){
+              notice_file.showPercentage = true
+          }
+          notice_file.percentage = percent
+          this.setData(row,field,notice_file)
+      }).then(response=>{
+          if(response.code == 200){
+              let guid = response.data[0]
+              notice_file.guid = guid
+              notice_file.showPercentage = false
+              this.setData(row,field,notice_file)
+              message.close()
+              this.$message.success('文件上传成功')
+          }
+      }).catch(error=>{
+          message.close()
+      })
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+</style>

+ 608 - 18
src/views/AITools/rejection_guidance_letter/rejection_guidance_letter.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="height_100 rejectionGuidanceLetter">
     <!-- 添加 -->
-    <div v-if="add || confessionSessionList.length==0" class="addRejectionGuidanceLetter">
+    <div v-show="add || confessionSessionList.length==0" class="addRejectionGuidanceLetter">
       <div class="addRejectionGuidanceLetter_warp">
         <div class="head">
           生成驳回指导函
@@ -21,7 +21,7 @@
               <el-input-number v-model="ruleForm.review_count" :min="1" :max="10" class="input-number_center"></el-input-number>
             </el-form-item>
             <div style="padding:15px 0">
-              <b>文件上传:</b>
+              <b><i class="el-icon-star-on red"></i>文件上传:</b>
             </div>
             <div class="upload-box-container">
               <!-- 驳回决定书 -->
@@ -47,7 +47,7 @@
                     style="width: 100%"
                 >
                     <div class="el-upload__text">
-                        <div><i class="el-icon-star-on red"></i>驳回决定书</div>
+                        <div>驳回决定书</div>
                         <div>点击或拖到上传</div>
                     </div>
                 </el-upload>
@@ -116,16 +116,16 @@
         </div>
         <div class="foot">
           <el-button size="small" v-if="confessionSessionList.length" @click="back">返 回</el-button>
-          <el-button type="primary" size="small" :loading="btnLoading" @click="submit">执 行</el-button> 
+          <el-button type="primary" size="small" :loading="btnLoading" @click="submit">生成驳回指导函</el-button> 
         </div>
       </div>
       
     </div>
     <!-- 结果界面 -->
-    <div v-else>
+    <div v-show="!add && confessionSessionList.length" class="rejectionGuidanceLetterResult">
       <!-- 历史记录 -->
       <conversationRecords v-show="showOption.showMenu" name="OA答辩" :show_add="false" :conversation="currentConversation" :confessionSessionList="confessionSessionList" @addConversation="addConversation" @changeConversation="changeConversation" @updateConversation="queryConfessionSession" ></conversationRecords>
-      <div>
+      <div class="rejectionGuidanceLetterResult_content">
         <!-- 头部 -->
         <div class="topMenu">
           <div class="topMenu_left">
@@ -135,20 +135,173 @@
               <el-button size="mini" :type="showOption.showRight?'success':'info'" @click="showOption.showRight = !showOption.showRight">{{showOption.showRight?"隐藏":"显示"}}右侧</el-button>
             </div>
             <el-button type="primary" size="mini" @click="addConversation">添加新会话</el-button>
+            <el-button type="primary" size="mini" v-if="!loading" @click="reSubmit({})">重新生成</el-button>
           </div>
           <div class="topMenu_right">
           </div>
         </div>
         <!-- 内容 -->
-        <div>
+        <div class="mainContent">
           <div class="left" v-show="showOption.showLeft" :style="!showOption.showRight?'width:calc(100% - 0px) !important':''">
+            <div v-show="show" class="showFile">
+              <div class="showFile_head">
+                <el-select  v-model="currentFileGuid" size="mini" placeholder="请选择">
+                  <el-option v-if="details.rejection_decision && details.rejection_decision.guid" :label="details.rejection_decision.name || details.rejection_decision.originalName" :value="details.rejection_decision.guid" @click.native="showPreview(1)"></el-option>
+                  <template v-if="details.review_files && details.review_files.length>0">
+                      <template v-for="(item,index) in details.review_files" >
+                          <el-option
+                              :key="'D'+item.num+'审查意见通知书'"
+                              v-if="item.examination_opinion.guid"
+                              :label="item.examination_opinion.name || item.examination_opinion.originalName"
+                              :value="item.examination_opinion.guid"
+                              @click.native="showPreview(2,index,'examination_opinion')">
+                          </el-option>
+                          <el-option
+                              :key="'D'+item.num+'递交合并档'"
+                              v-if="item.state_opinions.guid"
+                              :label="item.state_opinions.name || item.state_opinions.originalName"
+                              :value="item.state_opinions.guid"
+                              @click.native="showPreview(2,index,'state_opinions')">
+                          </el-option>
+                      </template>
+                  </template>
+                  <template v-if="contrast_files && contrast_files.length>0">
+                      <template v-for="(item,index) in contrast_files" >
+                          <el-option
+                              :key="'对比文件'+item.index"
+                              v-if="item.guid"
+                              :label="'对比文件'+item.index + ':' +item.publicNo"
+                              :value="item.guid"
+                              @click.native="showPreview(3,index)">
+                          </el-option>
+                      </template>
+                  </template>
+                </el-select>
+              </div>
+              <div class="showFile_content"  v-if="show">
+                <vabOnlyOffice class="myIframe" :option='option'></vabOnlyOffice>
+              </div>
+            </div>
+            <el-form v-show="!show" :model="details" label-width="170px" class="required_left">
+              <el-form-item label="客户文号/威世博卷号:" prop="case_volume">
+                {{ details.case_volume }}
+              </el-form-item>
+              <el-form-item label="复审建议:" prop="review_suggest">
+                {{ details.review_suggest }}
+              </el-form-item>
+              <el-form-item label="审通次数:" prop="review_count">
+                {{details.review_count}}
+              </el-form-item>
+              <div style="padding:15px 0">
+                <b>相关文件:</b>
+              </div>
+              <div class="upload-box-container file_type_list">
+                <!-- 驳回决定书 -->
+                <div>
+                  <div v-if="details.rejection_decision" :class="['file-item',fileTypeOption[details.rejection_decision.type] || 'text']">
+                    <span class="file-icon">
+                      <svg-icon class="xiaoshiIcon" :iconClass="fileIconTypeOption[fileTypeOption[details.rejection_decision.type] || 'text']"></svg-icon>
+                    </span>
+                    <div class="file-info">
+                      <div class="upload-placeholder">驳回决定书</div>
+                      <div class="file-name">{{details.rejection_decision.name || details.rejection_decision.originalName}}</div>
+                      <div class="file-type">
+                          类型: <span class="file-extension">{{details.rejection_decision.type.toUpperCase()}}</span>
+                      </div>
+                    </div>
+                    <button class="preview-btn" @click="showPreview(1)">预览</button>
+                  </div>
+                </div>
+                <!-- 审通文件 -->
+                <template v-if="details.review_files">
+                  <template  v-for="(review_files,index) in details.review_files">
+                    <div :key="'D'+review_files.num+'审查意见通知书'" :class="['file-item',fileTypeOption[review_files.examination_opinion.type] || 'text']">
+                      <span class="file-icon">
+                        <svg-icon class="xiaoshiIcon" :iconClass="fileIconTypeOption[fileTypeOption[review_files.examination_opinion.type] || 'text']"></svg-icon>
+                      </span>
+                      <div v-if="review_files.examination_opinion" class="file-info">
+                        <div class="upload-placeholder">第{{review_files.num}}次审查意见通知书</div>
+                        <div class="file-name">{{review_files.examination_opinion.name || review_files.examination_opinion.originalName}}</div>
+                        <div class="file-type">
+                            类型: <span class="file-extension">{{review_files.examination_opinion.type.toUpperCase()}}</span>
+                        </div>
+                      </div>
+                      <button class="preview-btn" @click="showPreview(2,index,'examination_opinion')">预览</button>
+                    </div>
+                    <div :key="'D'+review_files.num+'递交文件合并档'" :class="['file-item',fileTypeOption[review_files.state_opinions.type] || 'text']">
+                      <span class="file-icon">
+                        <svg-icon class="xiaoshiIcon" :iconClass="fileIconTypeOption[fileTypeOption[review_files.state_opinions.type] || 'text']"></svg-icon>
+                      </span>
+                      <div v-if="review_files.state_opinions" class="file-info">
+                        <div class="upload-placeholder">第{{review_files.num}}次递交文件合并档</div>
+                        <div class="file-name">{{review_files.state_opinions.name || review_files.state_opinions.originalName}}</div>
+                        <div class="file-type">
+                            类型: <span class="file-extension">{{review_files.state_opinions.type.toUpperCase()}}</span>
+                        </div>
+                      </div>
+                      <button class="preview-btn" @click="showPreview(2,index,'examination_opinion')">预览</button>
+                    </div>
+                  </template>
+                </template>
+                <!-- 对比文件 -->
+                <template v-if="contrast_files && contrast_files.length>0">
+                  <template v-for="(item,index) in contrast_files">
+                    <div :key="'对比文件'+item.index" v-if="item.guid" :class="['file-item',fileTypeOption[item.type] || 'text']">
+                      <span class="file-icon">
+                        <svg-icon class="xiaoshiIcon" :iconClass="fileIconTypeOption[fileTypeOption[item.type] || 'text']"></svg-icon>
+                      </span>
+                      <div class="file-info">
+                        <div class="upload-placeholder">对比文件{{ item.index }}</div>
+                        <div class="file-name">{{item.publicNo}}-{{ item.title }}</div>
+                        <div class="file-type">
+                            类型: <span class="file-extension">{{item.type.toUpperCase()}}</span>
+                        </div>
+                      </div>
+                      <button class="preview-btn" @click="showPreview(3,index)">预览</button>
+                    </div>
+                  </template>
+                </template>
+              </div>
+            </el-form>
 
           </div>
           <div class="line" v-if="showOption.showLeft && showOption.showRight"></div>
-          <div class="right" v-show="showOption.showRight" :style="!showOption.showLeft?'width:calc(100% - 0px) !important':''"></div>
+          <div class="right" v-show="showOption.showRight" :style="!showOption.showLeft?'width:calc(100% - 0px) !important':''">
+            <div v-if="loading" class="loading-container">
+                <div v-if="loading_text">
+                    {{ loading_text }} <i class="el-icon-loading margin-left_10"></i>
+                </div>
+                <div v-else class="loading-text">
+                    <span>生</span>
+                    <span>成</span>
+                    <span>中</span>
+                    <span>.</span>
+                    <span>.</span>
+                    <span>.</span>
+                </div>
+            </div>
+            <div v-else class="height_100">
+              <div v-if="result && result.code == 1001">
+                <div v-html="result.message.replace('\n','<br>')"></div>
+                <div>
+                  <el-link type="primary" @click="openErrorTip">点击上传</el-link>
+                </div>
+              </div>
+              <div v-else-if="currentConversation.resultFiles && currentConversation.resultFiles.length" class="height_100">
+                <template v-if="result_file.show">
+                    <vabOnlyOffice class="myIframe" :option='result_file.option'></vabOnlyOffice>
+                </template>
+              </div>
+              <div v-else>
+                暂无结果
+              </div>
+            </div>
+          </div>
         </div>
       </div>
     </div>
+
+    <errorTipDialog ref="errorTipDialog" @submit="reSubmit"></errorTipDialog>
   </div>
 </template>
 
@@ -167,9 +320,13 @@ const defaultForm = {
   ]
 }
 import conversationRecords from '../components/conversationRecords.vue';
+import vabOnlyOffice from '@/components/VabOnlyOffice/index.vue'
+import errorTipDialog from './components/dialog/errorTip.vue';
 export default {
   components: {
-    conversationRecords
+    conversationRecords,
+    vabOnlyOffice,
+    errorTipDialog
   },
   props: {},
   data() {
@@ -217,6 +374,8 @@ export default {
             name: this.$s.getObj('userinfo').name
         }
       },
+      confession:{},
+      currentFileGuid:'',
       show:false,
       btnLoading:false,
       loading:false,
@@ -233,14 +392,28 @@ export default {
         case_volume:[
           {required: true, message: '请输入客户文号/威世博卷号', trigger: 'blur' }
         ],
+        review_suggest:[
+          {required: true, message: '请选择复审建议', trigger: 'change' },
+        ],
         review_count:[
           {validator: checkReview_count, trigger: 'change' },
         ]
-      }
+      },
+      details:{},
+      contrast_files:[],
+      result_file:{},
+      result:null
     };
   },
   watch: {},
-  computed: {},
+  computed: {
+    fileIconTypeOption(){
+      return this.$constants.fileIconTypeOption
+    },
+    fileTypeOption(){
+      return this.$constants.fileTypeOption
+    },
+  },
   created() {
     this.getInit()
   },
@@ -249,6 +422,107 @@ export default {
     async getInit(){
       this.queryConfessionSession()
     },
+    //上传解析失败的文件
+    openErrorTip(){
+      this.$refs.errorTipDialog.open(this.result)
+    },
+    //再次运行
+    reSubmit(data){
+      if(data.rejection_decision && data.rejection_decision.guid){
+        this.$set(this.details,'rejection_decision',data.rejection_decision )
+      }
+      let review_files = data.review_files
+      if(review_files && review_files.length){
+        for(let i = 0;i<review_files.length;i++){
+          let item = review_files[i]
+          let num = item.num
+          let obj = this.details.review_files.find(item1=>{
+            return item1.num == num
+          })
+          if(!obj){
+            continue
+          }
+          if(item.examination_opinion && item.examination_opinion.guid){
+            obj.examination_opinion = item.examination_opinion
+          }
+          if(item.state_opinions && item.state_opinions.guid){
+            obj.state_opinions = item.state_opinions
+          }
+        }
+      }
+
+      let content_str = this.currentConversation.content
+      let content = JSON.parse(content_str)
+      content.input = this.details
+      content.dify_result = ''
+      var params = {
+        content:JSON.stringify(content),
+        confessionSessionId:this.currentConversation.id
+      }
+      this.$api.updateConfessionSession(params).then(response=>{
+          if(response.code == 200){
+            this.generateResult(1)
+          }
+      }).catch(error=>{
+          
+      })
+    },
+    //预览文件
+    showPreview(type,index,field){
+      let data = {
+        originalName:'',
+        guid:'',
+        type:''
+      }
+      let obj = {}
+      switch(type){
+        case 1:
+          obj = this.details.rejection_decision
+          break
+        case 2:
+          obj = this.details.review_files[index][field]
+          break
+        case 3:
+          let obj1 = this.contrast_files[index]
+          obj = {
+            originalName:'对比文件'+obj1.index+':'+obj1.publicNo,
+            guid:obj1.guid,
+            type:obj1.type
+          }
+          break
+      }
+      data.originalName = obj.name || obj.originalName
+      data.guid = obj.guid
+      data.type = obj.type
+      this.$set(this,'currentFileGuid',obj.guid)
+      this.getOption(data)
+    },
+    getOption(data,model='view'){
+      let option_data = data || this.confession
+      if(!option_data.guid){
+          this.$message.warning('文件不存在')
+          return 
+      }
+      let option = {}
+      this.show = false
+      option.name = option_data.originalName
+      option.id = option_data.guid
+      option.title = option_data.originalName
+      option.url = this.$c.url+ (this.$c.env=='production'?'/api':'')+'/fileManager/downloadFile?fileId=' + option_data.guid
+      option.fileType = option_data.type
+      option.key = option_data.guid
+      
+      option.model = model
+      this.$set(this,'option',
+          {
+              ...this.option,
+              ...option
+          }
+      )
+      this.$nextTick(()=>{
+          this.show = true
+      })
+  },
     //查询技术交底书会话记录
     queryConfessionSession(onlyQuery,generate){
       var params = {
@@ -301,14 +575,228 @@ export default {
       }
       this.currentConversation = obj
       this.$set(this,'add',false)
-      await this.getAssistWriteDetail()
+      await this.getDetail()
+      this.getResultContent(this.currentConversation)
+      // 判断当前文件是否存在于所有文件中
+      if(this.isChangeFile()){
+        this.showPreview(1)
+      }
       if(generate){
         this.generateResult()
       }
     },
+    // 判断当前文件是否存在于所有文件中
+    isChangeFile(){
+      if(!this.currentFileGuid){
+        return true
+      }
+      let rejection_decision = this.details.rejection_decision
+      if(this.currentFileGuid == rejection_decision.guid){
+        return false
+      }
+      let review_files = this.details.review_files
+      let files = review_files.filter(item=>{
+        return (item.examination_opinion.guid == this.currentFileGuid) || (item.state_opinions.guid == this.currentFileGuid)
+      })
+      if(files && files.length){
+        return false
+      }
+      let files1 = this.contrast_files.filter(item=>{
+        return item.guid == this.currentFileGuid
+      })
+      if(files1 && files1.length){
+        return false
+      }
+      return true
+    },
+    //装载数据
+    getResultContent(obj){
+      if(obj.resultFiles && obj.resultFiles.length){
+          this.changeResultFile(obj.resultFiles[0])
+      }
+      let content = obj.content
+      this.$set(this,'details',{})
+      this.$set(this,'result',null)
+      this.$set(this,'contrast_files',[])
+      if(!content){
+        return
+      }
+      try{
+          let data = JSON.parse(content)
+          if(!data.input){
+              return
+          }
+          this.$set(this,'details',data.input)
+          if(data.contrast_files){
+            this.$set(this,'contrast_files',data.contrast_files)
+          }
+          if(data.dify_result){
+            this.$set(this,'result',data.dify_result)
+          }
+        
+      }catch(e){
+
+      }
+    },
+    changeResultFile(obj){
+      this.result_file = {
+          file_message:obj || {},
+          guid:obj.guid || '',
+          show:false,
+          showFile:true,
+          option:{
+              url: '',
+              isEdit: false,
+              fileType: '',
+              title: '',
+              lang: 'zh-CN',
+              isPrint: true,
+              user: {
+                  id: this.$s.getObj('userinfo').id,
+                  name: this.$s.getObj('userinfo').name
+              }
+          }
+      }
+      this.getResultOption()
+    },
+    getResultOption(model='edit'){
+      let option_data = this.result_file.file_message
+      if(!option_data.guid){
+          // this.$message.warning('文件不存在')
+          return 
+      }
+      let option = this.result_file.option
+      // this.result_file.show = false
+      this.$set(this.result_file,'show',false)
+      option.name = option_data.originalName
+      option.id = option_data.guid
+      option.title = option_data.originalName
+      option.url = this.$c.url+ (this.$c.env=='production'?'/api':'')+'/fileManager/downloadFile?fileId=' + option_data.guid
+      option.fileType = option_data.type
+      option.key = option_data.guid
+      option.model = model
+      this.$nextTick(()=>{
+          this.$set(this.result_file,'show',true)
+      })
+    },
+    //获取会话详情
+    async getDetail(){
+      var params = {
+          confessionSessionId:this.currentConversation.id
+      }
+      await this.$api.discoveryResultDetail(params).then(response=>{
+          if(response.code == 200){
+              let data = response.data || {}
+              this.currentConversation = {
+                  ...this.currentConversation,
+                  ...data
+              }
+          }
+      }).catch(error=>{
+      })
+    },
     //生成驳回指导函
-    generateResult(){
+    async generateResult(type){
+      let obj = this.ruleForm
+      if(type){
+        obj = this.details
+      }
+      var params = {
+        "rejectionDecision":JSON.stringify(obj.rejection_decision),
+        "reviewFiles":JSON.stringify(obj.review_files),
+        "reviewSuggest":obj.review_suggest,
+        "reviewCount":obj.review_count,
+        "caseVolume":obj.case_volume,
+        confessionSessionId:this.currentConversation.id,
+        conversationId:this.currentConversation.conversationId
+      }
+      this.loading = true
+      this.result = null
+      const response = await fetch('/api/xiaoshi/dify/generateRegection', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+          'Accept': 'text/event-stream',
+        },
+        body:JSON.stringify(params)
+      });
       
+      if (!response.ok){
+          throw new Error('AI API 调用失败');
+      }
+      const reader = response.body.getReader();
+      const decoder = new TextDecoder('utf-8');
+      let noFinishMessage = ''
+      let resultType = null
+      while (true) {
+          const { done, value } = await reader.read();
+          if (done){
+              this.loading = false
+              if(resultType == 1){
+                this.changeConversation(this.currentConversation)
+              }
+              break;
+          } 
+          const chunk = decoder.decode(value);
+          const lines2 = chunk.split('\n\n').filter(line => line.trim() !== '' && line.trim() !== 'data:event: ping')
+          for(const line of lines2){
+              const jsonStr1 = line.replace(/^data:\s{0,}/, '');
+              const jsonStr = jsonStr1.trim()
+              if(jsonStr == 'event: ping' || jsonStr ==''){
+                  continue;
+              }
+              try {
+                  const json = JSON.parse(jsonStr);
+                  if(json.event == 'message'){
+                      if(!this.currentConversation.conversationId){
+                          this.currentConversation.conversationId = json.conversation_id
+                      }
+                      let answer = json.answer
+                      try{
+                        let answer_json = JSON.parse(answer)
+                        if(answer_json.code == 200){
+                          resultType = 1
+                        }else{
+                          this.result = answer_json
+                          this.openErrorTip()
+                        }
+                      }catch(e){
+                      }
+                  }
+                  
+              } catch (e) {
+                  if(jsonStr.indexOf('{') == 0){
+                      noFinishMessage = jsonStr
+                  }else{
+                      noFinishMessage += jsonStr
+                      if(jsonStr.lastIndexOf('}') == jsonStr.length - 1){
+                          try{
+                              const json = JSON.parse(noFinishMessage);
+                              if(json.event == 'message'){
+                                  let answer = json.answer
+                                  try{
+                                      let answer_json = JSON.parse(answer)
+                                      if(answer_json.code == 200){
+                                        resultType = 1
+                                      }else{
+                                        this.result = answer_json
+                                        this.openErrorTip()
+                                      }
+                                  }catch(e){
+                                  }
+                              }
+                          }
+                          catch(e){
+                              console.error('解析响应数据出错:', e);
+                          }finally{
+                              noFinishMessage = ''
+                          }
+                      }
+                  }
+              }
+              
+          }
+      }
     },
     //添加会话
     async addConversation(){
@@ -324,6 +812,9 @@ export default {
     clearConversation(){
       this.$set(this,'currentConversation',{})
       this.$set(this,'confession',{})
+      this.$set(this,'currentFileGuid','')
+      this.$set(this,'details',{})
+      this.$set(this,'contrast_files',[])
     },
     //上传文件
     setData(row,field,value){
@@ -345,9 +836,12 @@ export default {
       let formData = new FormData()
       formData.append('sourceId',this.$constants.sourceId)
       formData.append('files',file.raw)
-      
+      let fileName = file.raw.name
+      let arr = fileName.split('.')
+      let type = arr[arr.length - 1]
       var notice_file = {
-          name:file.raw.name
+          name:fileName,
+          type:type.toLowerCase()
       }
       var message = this.$message({
           message: '文件上传中...',
@@ -386,15 +880,18 @@ export default {
           }
           let review_files = this.ruleForm.review_files
           let files = review_files.filter(item=>{
-            return item.examination_opinion.guid || item.state_opinions.guid
+            return !item.examination_opinion.guid || !item.state_opinions.guid
           })
           if(files && files.length){
             let str = files.map(item=>item.num).join('、')
             this.$message(`第${str}次审通文件未全部上传`)
             return false
           }
+          let content = {
+            input:this.ruleForm
+          }
           var params = {
-            content:JSON.stringify(this.form),
+            content:JSON.stringify(content),
             type:6
           }
           this.btnLoading = false
@@ -528,7 +1025,9 @@ export default {
 </style>
 <style lang="scss" scoped>
 .rejectionGuidanceLetter{
-  width:100%;
+  width:calc(100% - 20px);
+  height: calc(100% - 20px);
+  padding: 10px;
   .red{
       color:red;
   }
@@ -571,5 +1070,96 @@ export default {
       }
     }
   }
+  .rejectionGuidanceLetterResult{
+    height: 100%;
+    display: flex;
+    align-items: stretch;
+    .rejectionGuidanceLetterResult_content{
+      width: 100%;
+    }
+    .topMenu{
+      height: 30px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding-bottom: 10px;
+      i{
+        font-size: 20px;
+      }
+      .topMenu_left{
+        display: flex;
+        align-items: center;
+      }
+    }
+    .line{
+        width:2px;
+        height: 100%;
+        background: #e6e6e6;
+    }
+    .mainContent{
+      display: flex;
+      align-items: stretch;
+      width:100%;
+      height: calc(100% - 40px);
+      .left{
+        width:45%;
+        height:calc(100% - 0px);
+        padding-right: 10px;
+        display: flex;
+        flex-direction: column;
+        .showFile{
+          height: 100%;
+          width: 100%;
+          .showFile_head{
+            display: flex;
+            justify-content: flex-end;
+          }
+          .showFile_content{
+            height: calc(100% - 35px);
+            width: 100%;
+            margin-top: 5px;
+          }
+        }
+      }
+      .right{
+        width:calc(100% - 45% - 2px);
+        min-width: 450px;
+        padding:0 10px;
+        display: flex;
+        flex-direction: column;
+        position: relative;
+        overflow-y: auto;
+        .loading-container{
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          height: 100%;
+          .loading-text {
+              font-size: 24px;
+              font-family: Arial;
+              display: flex;
+              gap: 8px;
+          }
+          .loading-text span {
+              display: inline-block;
+              animation: bounce 1.2s infinite ease-in-out;
+              color: black;
+          }
+  
+          .loading-text span:nth-child(2) { animation-delay: 0.1s; }
+          .loading-text span:nth-child(3) { animation-delay: 0.2s; }
+  
+          @keyframes bounce {
+              0%, 40%, 100% { 
+                  transform: translateY(0);
+              }
+              20% {
+                  transform: translateY(-15px);
+              }
+          }
+        }
+      }
+    }
+  }
 }
 </style>