OADefense1.vue 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  1. <template>
  2. <div class="height_100 OADefense">
  3. <conversationRecords v-show="showMenu" name="OA答辩" :show_add="false" :conversation="currentConversation" :confessionSessionList="confessionSessionList" @addConversation="addConversation" @changeConversation="changeConversation" @updateConversation="queryConfessionSession" ></conversationRecords>
  4. <myView style="height: 100%;width: 100%;" position="row">
  5. <!-- 左侧文件展示 -->
  6. <div slot="left" class="left customize_file" v-show="showLeft">
  7. <div class="head">
  8. <div class="head_left">
  9. <div class="margin-right_10">
  10. <i v-show="showMenu" class="el-icon-s-fold" @click="showMenu = !showMenu"></i>
  11. <i v-show="!showMenu" class="el-icon-s-unfold" @click="showMenu = !showMenu"></i>
  12. </div>
  13. <div style="font-weight:600">OA答辩</div>
  14. <el-button size="mini" class="margin-left_10" type="primary" @click="addConversation">添加新OA答辩</el-button>
  15. <el-button v-if="notice_file.guid && !loading" class="margin-left_10" type="primary" size="mini" @click="regenerate">重新生成</el-button>
  16. </div>
  17. <div class="head_right">
  18. <el-select v-model="current_guid" size="mini" placeholder="请选择">
  19. <el-option v-if="notice_file.guid" :label="`审查意见通知书-${notice_file.originalName || notice_file.name}`" :value="notice_file.guid" @click.native="handleOptionClick(notice_file,1)"></el-option>
  20. <el-option v-if="app_file.guid" :label="`申请文件-${app_file.appNo}`" :value="app_file.guid" @click.native="handleOptionClick(app_file,2)"></el-option>
  21. <el-option v-if="modify_file.guid" :label="`修改对照页`" :value="modify_file.guid" @click.native="handleOptionClick(modify_file,4)"></el-option>
  22. <template v-if="contrast_file && contrast_file.length>0">
  23. <el-option
  24. v-for="(item,index) in contrast_file"
  25. :key="index"
  26. :label="`D${item.index}-${item.publicNo}`"
  27. :value="item.guid"
  28. @click.native="handleOptionClick(item,3)">
  29. </el-option>
  30. </template>
  31. </el-select>
  32. </div>
  33. </div>
  34. <div>
  35. <hr>
  36. </div>
  37. <!-- 输入 -->
  38. <template v-if="add">
  39. <div >
  40. <!-- <p>审查意见书:</p>
  41. <div>
  42. <el-upload
  43. ref="upload_file"
  44. class="upload-demo"
  45. drag
  46. action="#"
  47. :auto-upload="false"
  48. :limit="1"
  49. :file-list="notice_file.guid?[notice_file]:[]"
  50. :on-change="onChange"
  51. style="width: 100%"
  52. >
  53. <i class="el-icon-upload"></i>
  54. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  55. </el-upload>
  56. </div>
  57. <div style="padding: 10px 0;">
  58. <div><b>相关文件(申请文件和对比文件):(<span style="font-size:18px">非必填</span>)</b></div>
  59. <div style="font-size:16px;color:red">
  60. 注:
  61. <br>
  62. 1.如果上传了相关文件则优先使用上传的文件,如果不上传则系统会自动获取文件
  63. <br>
  64. 2.上传的申请文件要包含本申请号码,对比文件包含对比文件序号或者名称
  65. </div>
  66. </div>
  67. <div>
  68. <myUpload :file-list="patent_fileUrls" @on-change="onchangeFile" @on-remove="onRemove" style="height: 180px;" :autoUpload="true"></myUpload>
  69. </div> -->
  70. <div style="height:calc(100vh - 210px);overflow-y: auto;overflow-x:hidden">
  71. <div style="display:flex;align-items: center;justify-content:space-between">
  72. <p class="file_title"><i class="el-icon-star-on"></i>本次需要答复的审查意见通知书</p>
  73. <div>
  74. <el-button size="mini" class="margin-right_10" type="primary" @click="batch_upload">批量上传</el-button>
  75. </div>
  76. </div>
  77. <div class="upload_file">
  78. <div v-if="notice_file.guid" class="file_show">
  79. <myTooltip :content="notice_file.name ? notice_file.name : notice_file.originalName">
  80. <div class="noWrap file_name">
  81. <i class="el-icon-document" style="margin-right: 10px"></i>
  82. <span class="name">{{notice_file.name ? notice_file.name : notice_file.originalName}}</span>
  83. </div>
  84. </myTooltip>
  85. <div class="type">{{ notice_file.guid ? "已上传" : "待上传" }}</div>
  86. <div class="icon" @click="notice_file = {}">
  87. <i class="el-icon-close"></i>
  88. </div>
  89. </div>
  90. <el-upload
  91. v-else
  92. ref="upload_file"
  93. class="upload-demo"
  94. drag
  95. action="#"
  96. :auto-upload="false"
  97. :limit="1"
  98. :on-change="(file)=>onChange(file,'notice_file')"
  99. style="width: 100%"
  100. >
  101. <i class="el-icon-upload"></i>
  102. <div class="el-upload__text">
  103. <div><em>点击上传</em></div>
  104. <div>或将文件拖到此处上传</div>
  105. </div>
  106. </el-upload>
  107. </div>
  108. <!-- 选择最接近本申请的现有技术 -->
  109. <p>
  110. <span class="file_title">最接近本申请的现有技术:</span>
  111. <span>
  112. <el-select size="small" v-model="changeClaim.near_index" placeholder="请选择">
  113. <el-option
  114. v-for="item in 15"
  115. :key="item"
  116. :label="'D' + item"
  117. :value="item">
  118. </el-option>
  119. </el-select>
  120. </span>
  121. </p>
  122. <p>
  123. <span class="file_title">是否进行权要修改:</span>
  124. <span>
  125. <el-radio-group v-model="changeClaim.changeClaim">
  126. <el-radio :label="1">是</el-radio>
  127. <el-radio :label="2">否</el-radio>
  128. <!-- <el-radio :label="3">AI推荐</el-radio> -->
  129. </el-radio-group>
  130. </span>
  131. </p>
  132. <div v-if="changeClaim.changeClaim == 1">
  133. <p class="file_title">修改后完整的权利要求</p>
  134. <div>
  135. <el-input type="textarea" v-model="changeClaim.claim" placeholder="请输入修改后完整的权利要求"></el-input>
  136. </div>
  137. </div>
  138. <div style="margin:25px 0;">
  139. <el-divider content-position="left">相关文件(选填)</el-divider>
  140. </div>
  141. <p class="file_title">本申请文件</p>
  142. <div class="upload_file">
  143. <div v-if="relevant_file.app_file.guid" class="file_show">
  144. <myTooltip :content="relevant_file.app_file.name ? relevant_file.app_file.name : relevant_file.app_file.originalName">
  145. <div class="noWrap file_name">
  146. <i class="el-icon-document" style="margin-right: 10px"></i>
  147. <span class="name">{{relevant_file.app_file.name ? relevant_file.app_file.name : relevant_file.app_file.originalName}}</span>
  148. </div>
  149. </myTooltip>
  150. <div class="type">{{ relevant_file.app_file.guid ? "已上传" : "待上传" }}</div>
  151. <div class="icon" @click="relevant_file.app_file = {}">
  152. <i class="el-icon-close"></i>
  153. </div>
  154. </div>
  155. <el-upload
  156. v-else
  157. ref="upload_file"
  158. class="upload-demo"
  159. drag
  160. action="#"
  161. :auto-upload="false"
  162. :limit="1"
  163. :on-change="(file)=>onChange(file,'relevant_file.app_file')"
  164. style="width: 100%"
  165. >
  166. <i class="el-icon-upload"></i>
  167. <div class="el-upload__text">
  168. <div><em>点击上传</em></div>
  169. <div>或将文件拖到此处上传</div>
  170. </div>
  171. </el-upload>
  172. </div>
  173. <p class="file_title">上一次OA的修改对照页(若有,要包含权利要求和说明书全文内容)</p>
  174. <div class="upload_file">
  175. <div v-if="relevant_file.modify_file.guid" class="file_show">
  176. <myTooltip :content="relevant_file.modify_file.name ? relevant_file.modify_file.name : relevant_file.modify_file.originalName">
  177. <div class="noWrap file_name">
  178. <i class="el-icon-document" style="margin-right: 10px"></i>
  179. <span class="name">{{relevant_file.modify_file.name ? relevant_file.modify_file.name : relevant_file.modify_file.originalName}}</span>
  180. </div>
  181. </myTooltip>
  182. <div class="type">{{ relevant_file.modify_file.guid ? "已上传" : "待上传" }}</div>
  183. <div class="icon" @click="relevant_file.modify_file = {}">
  184. <i class="el-icon-close"></i>
  185. </div>
  186. </div>
  187. <el-upload
  188. v-else
  189. ref="upload_file"
  190. class="upload-demo"
  191. drag
  192. action="#"
  193. :auto-upload="false"
  194. :limit="1"
  195. :on-change="(file)=>onChange(file,'relevant_file.modify_file')"
  196. style="width: 100%"
  197. >
  198. <i class="el-icon-upload"></i>
  199. <div class="el-upload__text">
  200. <div><em>点击上传</em></div>
  201. <div>或将文件拖到此处上传</div>
  202. </div>
  203. </el-upload>
  204. </div>
  205. <template v-if="relevant_file.contrast_file">
  206. <div>
  207. <div v-for="contrast_file in relevant_file.contrast_file" :key="'D'+contrast_file.order">
  208. <p class="file_title">对比文件D{{ contrast_file.order }}</p>
  209. <div class="upload_file">
  210. <div v-if="contrast_file.file.guid" class="file_show">
  211. <myTooltip :content="contrast_file.file.name ? contrast_file.file.name : contrast_file.file.originalName">
  212. <div class="noWrap file_name">
  213. <i class="el-icon-document" style="margin-right: 10px"></i>
  214. <span class="name">{{contrast_file.file.name ? contrast_file.file.name : contrast_file.file.originalName}}</span>
  215. </div>
  216. </myTooltip>
  217. <div class="type">{{ contrast_file.file.guid ? "已上传" : "待上传" }}</div>
  218. <div class="icon" @click="contrast_file.file = {}">
  219. <i class="el-icon-close"></i>
  220. </div>
  221. </div>
  222. <el-upload
  223. v-else
  224. ref="upload_file"
  225. class="upload-demo"
  226. drag
  227. action="#"
  228. :auto-upload="false"
  229. :limit="1"
  230. :on-change="(file)=>onChange(file,'file',contrast_file)"
  231. style="width: 100%"
  232. >
  233. <i class="el-icon-upload"></i>
  234. <div class="el-upload__text">
  235. <div><em>点击上传</em></div>
  236. <div>或将文件拖到此处上传</div>
  237. </div>
  238. </el-upload>
  239. </div>
  240. </div>
  241. <div class="addContrastFile">
  242. <el-button size="medium" @click="add_contrast_file">添加 + </el-button>
  243. </div>
  244. </div>
  245. </template>
  246. </div>
  247. <hr >
  248. <div class="run" >
  249. <div></div>
  250. <el-button type="primary" size="small" @click="run"><div class="btn_content"><i class="el-icon-caret-right"></i>运行</div></el-button>
  251. </div>
  252. </div>
  253. </template>
  254. <template v-else-if="show">
  255. <vabOnlyOffice class="myIframe" :option='option'></vabOnlyOffice>
  256. </template>
  257. <hr>
  258. </div>
  259. <!-- 中间的线 -->
  260. <!-- <div class="line" v-show="showLeft"></div> -->
  261. <!-- 右侧发明点和对话框 -->
  262. <div slot="right" class="right" :style="!showLeft?'width:calc(100% - 0px) !important':''">
  263. <div>
  264. <div class="head">
  265. <div class="head_left">
  266. <div class="margin-right_10">
  267. <i v-show="showLeft" title="收起左侧内容" class="el-icon-s-fold" @click="showLeft = !showLeft"></i>
  268. <i v-show="!showLeft" title="展开左侧内容" class="el-icon-s-unfold" @click="showLeft = !showLeft"></i>
  269. </div>
  270. <div class="style_starIcon__t_QZN">
  271. <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
  272. <path d="M3.66699 1.33366C3.66699 0.965469 3.36852 0.666992 3.00033 0.666992C2.63214 0.666992 2.33366 0.965469 2.33366 1.33366V2.33366H1.33366C0.965469 2.33366 0.666992 2.63214 0.666992 3.00033C0.666992 3.36852 0.965469 3.66699 1.33366 3.66699H2.33366V4.66699C2.33366 5.03518 2.63214 5.33366 3.00033 5.33366C3.36852 5.33366 3.66699 5.03518 3.66699 4.66699V3.66699H4.66699C5.03518 3.66699 5.33366 3.36852 5.33366 3.00033C5.33366 2.63214 5.03518 2.33366 4.66699 2.33366H3.66699V1.33366Z" fill="#444CE7"/>
  273. <path d="M3.66699 11.3337C3.66699 10.9655 3.36852 10.667 3.00033 10.667C2.63214 10.667 2.33366 10.9655 2.33366 11.3337V12.3337H1.33366C0.965469 12.3337 0.666992 12.6321 0.666992 13.0003C0.666992 13.3685 0.965469 13.667 1.33366 13.667H2.33366V14.667C2.33366 15.0352 2.63214 15.3337 3.00033 15.3337C3.36852 15.3337 3.66699 15.0352 3.66699 14.667V13.667H4.66699C5.03518 13.667 5.33366 13.3685 5.33366 13.0003C5.33366 12.6321 5.03518 12.3337 4.66699 12.3337H3.66699V11.3337Z" fill="#444CE7"/>
  274. <path d="M9.28922 1.76101C9.1902 1.50354 8.94284 1.33366 8.66699 1.33366C8.39114 1.33366 8.14378 1.50354 8.04476 1.76101L6.88864 4.76691C6.68837 5.28761 6.62544 5.43766 6.53936 5.55872C6.45299 5.68019 6.34686 5.78632 6.22539 5.87269C6.10432 5.95878 5.95428 6.02171 5.43358 6.22198L2.42767 7.37809C2.17021 7.47712 2.00033 7.72448 2.00033 8.00033C2.00033 8.27617 2.17021 8.52353 2.42767 8.62256L5.43358 9.77867C5.95428 9.97894 6.10432 10.0419 6.22539 10.128C6.34686 10.2143 6.45299 10.3205 6.53936 10.4419C6.62544 10.563 6.68837 10.713 6.88864 11.2337L8.04476 14.2396C8.14379 14.4971 8.39114 14.667 8.66699 14.667C8.94284 14.667 9.1902 14.4971 9.28922 14.2396L10.4453 11.2337C10.6456 10.713 10.7085 10.563 10.7946 10.4419C10.881 10.3205 10.9871 10.2143 11.1086 10.128C11.2297 10.0419 11.3797 9.97894 11.9004 9.77867L14.9063 8.62256C15.1638 8.52353 15.3337 8.27617 15.3337 8.00033C15.3337 7.72448 15.1638 7.47712 14.9063 7.37809L11.9004 6.22198C11.3797 6.02171 11.2297 5.95878 11.1086 5.87269C10.9871 5.78632 10.881 5.68019 10.7946 5.55872C10.7085 5.43766 10.6456 5.28761 10.4453 4.76691L9.28922 1.76101Z" fill="#444CE7"/>
  275. </svg>
  276. </div>
  277. <div class="title">AI 智能书写 <span v-if="loading"><i class="el-icon-loading margin-left_10"></i></span></div>
  278. </div>
  279. <div class="head_right">
  280. <!-- <el-button v-if="!loading && result && result.code != 1001 && !result_file.show" type="primary" size="mini" @click="copy">复制</el-button> -->
  281. <el-button v-if="result_file.show" type="primary" size="mini" :loading="btnLoading" @click="download_file">下载</el-button>
  282. </div>
  283. </div>
  284. </div>
  285. <div v-if="!result && loading" class="loading-container">
  286. <div v-if="loading_text">
  287. {{ loading_text }} <i class="el-icon-loading margin-left_10"></i>
  288. </div>
  289. <div v-else class="loading-text">
  290. <span>思</span>
  291. <span>考</span>
  292. <span>中</span>
  293. <span>.</span>
  294. <span>.</span>
  295. <span>.</span>
  296. </div>
  297. </div>
  298. <div class="result" ref="AIMessage" v-else>
  299. <template v-if="result_file.show">
  300. <vabOnlyOffice class="myIframe" :option='result_file.option'></vabOnlyOffice>
  301. </template>
  302. <!-- 缺少信息 -->
  303. <template v-else-if="result && result.code == 1001">
  304. <div>
  305. <div style="font-size:16px" v-html="result.data.replace('\n','<br>')"></div>
  306. <div>
  307. <el-link type="primary" @click="openErrorTip">点击上传</el-link>
  308. </div>
  309. </div>
  310. </template>
  311. <!-- 请求超时 -->
  312. <template v-else-if="result && result.code == 1002">
  313. <div>
  314. <div style="font-size:16px">
  315. {{ result.data }},请<el-link type="primary" @click="getResult">重试</el-link>
  316. </div>
  317. </div>
  318. </template>
  319. <!-- 修改后的权利要求输出 -->
  320. <template v-else-if="result && result.code == 201">
  321. <div>
  322. <p><b>AI建议修改后的权利要求:</b><span style="color:red;font-size:12px">可以手动修改</span></p>
  323. <el-input type="textarea" :rows="30" v-model="changeClaim.claim"></el-input>
  324. <div class="result_btn">
  325. <el-button type="primary" size="small" @click="reLoadSubmit">确认并继续</el-button>
  326. </div>
  327. </div>
  328. </template>
  329. <!-- 区别技术特征 -->
  330. <template v-else-if="result && result.code == 202">
  331. <div v-for="(item,index) in main_claim_reason" :key="index">
  332. <p><b>权利要求{{ item.after_claimOrder || item.claim_order[0] }}的答辩点:</b><span style="color:red;font-size:12px">可以手动修改</span></p>
  333. <el-input type="textarea" :rows="10" v-model="item.difference_feature"></el-input>
  334. </div>
  335. <div class="result_btn">
  336. <el-button type="primary" size="small" @click="reLoadSubmit">确认并继续</el-button>
  337. </div>
  338. </template>
  339. <!-- 结果 -->
  340. <template v-else-if="result">
  341. <div class="answer_warp">
  342. <div v-for="(item,index) in formateAIAnswer(this.result)" :key="index">
  343. <div v-if="item.type == 'text'" id='answer'>
  344. <div v-if="item.content && item.content != 'null'" v-html="renderMarkdown(item.content)"></div>
  345. </div>
  346. </div>
  347. </div>
  348. </template>
  349. <div class="jiazai" v-if="result && loading">
  350. <span style="color:red;">{{loading_text}}</span> <i class="el-icon-loading margin-left_10"></i>
  351. </div>
  352. </div>
  353. </div>
  354. </myView>
  355. <!-- 错误提示以及上传文件 -->
  356. <errorTipDialog ref="errorTip" @submit="reLoadSubmit"></errorTipDialog>
  357. <!-- 批量上传文件 -->
  358. <batchFileDialog ref="batchFile" :sign="1" @get_file_obj="get_file_obj"></batchFileDialog>
  359. </div>
  360. </template>
  361. <script>
  362. import vabOnlyOffice from '@/components/VabOnlyOffice/index.vue'
  363. import mixin from './mixins/index1.js';
  364. import conversationRecords from '../components/conversationRecords.vue';
  365. import {renderMarkdown} from '@/utils/markdown'
  366. import { downLoad2 } from '@/utils'
  367. import { scrollToBottom } from '../components/mixins/scrollToBottom'
  368. import errorTipDialog from './dialog/errorTip.vue'
  369. import batchFileDialog from './dialog/batchFile.vue';
  370. export default {
  371. components: {
  372. conversationRecords,
  373. vabOnlyOffice,
  374. errorTipDialog,
  375. batchFileDialog
  376. },
  377. props: {},
  378. mixins:[mixin,scrollToBottom],
  379. data() {
  380. return {
  381. showMenu:false,//是否显示左侧菜单
  382. showLeft:true,//展示左侧内容
  383. currentConversation:{},//当前会话
  384. confessionSessionList:[],//会话记录
  385. chat_id:null,
  386. btnLoading:false,//按钮加载
  387. loading:false,//生成中
  388. loading_text:'',
  389. result:'',//OA答辩结果文本
  390. show:false,//显示左侧文件
  391. option:{//左侧文件配置
  392. url: '',
  393. isEdit: false,
  394. fileType: '',
  395. title: '',
  396. lang: 'zh-CN',
  397. isPrint: true,
  398. user: {
  399. id: this.$s.getObj('userinfo').id,
  400. name: this.$s.getObj('userinfo').name
  401. }
  402. },
  403. changeClaim:{
  404. near_index:1,
  405. changeClaim:1,
  406. claim:""
  407. },
  408. main_claim_reason:[],//区别技术特征
  409. confession:{},//文件信息
  410. reLoadSearch:false,//重新生成OA答辩
  411. add:true,//添加审查通知书
  412. notice_file:{},//审查通知书文件
  413. relevant_file:{
  414. app_file:{},
  415. modify_file:{},
  416. contrast_file:[
  417. {
  418. order:1,
  419. file:{}
  420. },
  421. {
  422. order:2,
  423. file:{}
  424. },
  425. {
  426. order:3,
  427. file:{}
  428. },
  429. ]
  430. },
  431. patent_fileUrls:[],//专利文件地址
  432. result_file:{},//结果文件
  433. app_file:{},//申请文件
  434. modify_file:{},//修改对照页文件
  435. contrast_file:[],//对比文件
  436. current_guid:'',//左侧当前显示的文件
  437. };
  438. },
  439. watch: {
  440. result(){
  441. this.scrollToBottom()
  442. }
  443. },
  444. computed: {},
  445. created() {
  446. this.getInit()
  447. },
  448. mounted() {},
  449. methods: {
  450. renderMarkdown,
  451. //初始化
  452. async getInit(){
  453. this.queryConfessionSession()
  454. },
  455. add_contrast_file(){
  456. let order1 = this.relevant_file.contrast_file[this.relevant_file.contrast_file.length-1].order
  457. this.relevant_file.contrast_file.push(
  458. {
  459. order:order1 + 1,
  460. file:{}
  461. }
  462. )
  463. },
  464. //批量上传
  465. batch_upload(){
  466. this.$refs.batchFile.open()
  467. },
  468. get_file_obj(data){
  469. if(data.notice_file){
  470. this.$set(this,'notice_file',data.notice_file)
  471. }
  472. if(data.app_file){
  473. this.$set(this.relevant_file,'app_file',data.app_file)
  474. }
  475. if(data.modify_file){
  476. this.$set(this.relevant_file,'modify_file',data.modify_file)
  477. }
  478. if(data.contrast_file && data.contrast_file.length>0){
  479. let contrast_file = this.relevant_file.contrast_file
  480. for(let i = 0;i<data.contrast_file.length;i++){
  481. let item = data.contrast_file[i]
  482. let order = item.order
  483. let obj = contrast_file.find(file=>{
  484. return file.order == order
  485. })
  486. if(obj){
  487. obj.file = item.file
  488. }else{
  489. let order1 = contrast_file[contrast_file.length-1].order
  490. if(order > order1 + 1){
  491. for(let y = order1 + 1;y < order;y++){
  492. contrast_file.push(
  493. {
  494. order:y,
  495. file:{}
  496. }
  497. )
  498. }
  499. }
  500. contrast_file.push(item)
  501. }
  502. }
  503. }
  504. },
  505. //再次提交
  506. reLoadSubmit(data){
  507. if(data){
  508. this.get_file_obj(data)
  509. }
  510. let content = this.currentConversation.content
  511. var params = {
  512. confessionSessionId:this.currentConversation.id,
  513. }
  514. if(!content){
  515. params.content = JSON.stringify(
  516. {
  517. query:{
  518. // patent_fileUrls:this.patent_fileUrls,
  519. relevant_file:this.relevant_file,
  520. claimChange:this.claimChange,
  521. main_claim_reason:this.main_claim_reason
  522. }
  523. }
  524. )
  525. }else{
  526. try{
  527. let data1 = JSON.parse(content)
  528. if(data1.data && data1.data.code == 1001){
  529. data1.data = {}
  530. }
  531. // if(data1.query && data1.query.patent_fileUrls){
  532. // data1.query.patent_fileUrls = this.patent_fileUrls
  533. // }else{
  534. // data1.query = {
  535. // patent_fileUrls:this.patent_fileUrls
  536. // }
  537. // }
  538. if(data1.query && data1.query.relevant_file){
  539. data1.query.relevant_file = this.relevant_file
  540. }else{
  541. data1.query = {
  542. relevant_file:this.relevant_file,
  543. claimChange:this.claimChange,
  544. main_claim_reason:this.main_claim_reason
  545. }
  546. }
  547. params.content = JSON.stringify(data1)
  548. }catch(e){
  549. params.content = JSON.stringify(
  550. {
  551. query:{
  552. // patent_fileUrls:this.patent_fileUrls,
  553. relevant_file:this.relevant_file,
  554. claimChange:this.claimChange,
  555. main_claim_reason:this.main_claim_reason
  556. }
  557. }
  558. )
  559. }
  560. }
  561. this.$api.updateConfessionSession(params).then(response=>{
  562. if(response.code == 200){
  563. this.reLoadSearch = true
  564. this.queryConfessionSession()
  565. this.getResult()
  566. }
  567. }).catch(error=>{
  568. })
  569. },
  570. //查询技术交底书会话记录
  571. async queryConfessionSession(onlyQuery,request,result){
  572. var params = {
  573. type:2
  574. }
  575. await this.$api.queryConfessionSession(params).then(response=>{
  576. if(response.code == 200){
  577. this.confessionSessionList = response.data || []
  578. if(!onlyQuery && this.confessionSessionList.length>0){
  579. this.add = false
  580. let obj = null
  581. if(this.currentConversation.id){
  582. obj = this.confessionSessionList.find(item=>{
  583. return item.id == this.currentConversation.id
  584. })
  585. }else{
  586. obj = this.confessionSessionList[0]
  587. }
  588. if(obj){
  589. this.changeConversation(obj,true)
  590. }
  591. }else if(this.confessionSessionList.length==0){
  592. this.addConversation()
  593. }
  594. if(request){
  595. this.getResult()
  596. }
  597. if(result){
  598. if(!this.confessionSessionList || this.confessionSessionList.length==0){
  599. return
  600. }
  601. let obj = this.confessionSessionList.find(item=>{
  602. return item.id == this.currentConversation.id
  603. })
  604. if(!obj){
  605. obj = this.confessionSessionList[0]
  606. }
  607. this.getResultContent(obj)
  608. }
  609. }
  610. })
  611. },
  612. //获取生成的技术交底书理解结果
  613. async getConversionDetails(){
  614. var params = {
  615. confessionSessionId:this.currentConversation.id
  616. }
  617. await this.$api.discoveryResultDetail(params).then(response=>{
  618. if(response.code == 200){
  619. let data = response.data || {}
  620. this.currentConversation = {
  621. ...this.currentConversation,
  622. ...data
  623. }
  624. }
  625. }).catch(error=>{
  626. })
  627. },
  628. run(){
  629. this.$set(this,'result_file',{})
  630. var params = {
  631. fileGuid:this.notice_file.guid,
  632. content:JSON.stringify(
  633. {
  634. query:{
  635. // patent_fileUrls:this.patent_fileUrls,
  636. relevant_file:this.relevant_file,
  637. claimChange:this.claimChange,
  638. main_claim_reason:this.main_claim_reason
  639. }
  640. }
  641. ),
  642. type:2
  643. }
  644. this.$api.addConfessionSession(params).then(response=>{
  645. if(response.code == 200){
  646. //查询技术交底书会话记录
  647. this.currentConversation = {
  648. id:response.data
  649. }
  650. this.queryConfessionSession(false,true)
  651. }
  652. }).catch(error=>{
  653. message.close()
  654. })
  655. },
  656. //结果生成过程中切换、添加、刷新提示
  657. async loading_change(){
  658. var isNext = true
  659. if(this.loading){
  660. await this.$confirm('结果正在生成中,如果执行当前操作会取消当前的结果生成, 是否继续?', '提示', {
  661. confirmButtonText: '确定',
  662. cancelButtonText: '取消',
  663. type: 'warning'
  664. }).then(() => {
  665. this.cancelRun()
  666. }).catch(() => {
  667. isNext = false
  668. });
  669. }
  670. return isNext
  671. },
  672. //添加会话
  673. async addConversation(){
  674. let isNext = await this.loading_change()
  675. if(!isNext){
  676. return
  677. }
  678. this.$set(this,'currentConversation',{})
  679. this.$set(this,'confession',{})
  680. this.$set(this,'add',true)
  681. this.$set(this,'notice_file',{})
  682. // this.$set(this,'patent_fileUrls',[])
  683. this.set_relevant_file()
  684. this.$set(this,'changeClaim',{
  685. near_index:1,
  686. changeClaim:1,
  687. claim:''
  688. })
  689. this.$set(this,'main_claim_reason',[])
  690. this.$set(this,'app_file',{})
  691. this.$set(this,'app_file',{})
  692. this.$set(this,'contrast_file',[])
  693. this.$set(this,'result_file',{})
  694. this.$set(this,'current_guid','')
  695. this.$set(this,'result',null)
  696. this.$set(this,'loading_text','')
  697. this.$set(this,'loading',false)
  698. },
  699. //设置相关文件初始化
  700. set_relevant_file(){
  701. this.$set(this,'relevant_file',
  702. {
  703. app_file:{},
  704. modify_file:{},
  705. contrast_file:[
  706. {
  707. order:1,
  708. file:{}
  709. },
  710. {
  711. order:2,
  712. file:{}
  713. },
  714. {
  715. order:3,
  716. file:{}
  717. },
  718. ]
  719. }
  720. )
  721. },
  722. //切换左侧展示的文件
  723. handleOptionClick(obj,type){
  724. switch(type){
  725. case 1:
  726. this.confession = obj
  727. this.getOption()
  728. case 2:
  729. case 3:
  730. case 4:
  731. if(type == 2){
  732. obj.originalName = `申请文件-${obj.appNo}`
  733. }else if(type == 3){
  734. obj.originalName = `D${obj.index}-${obj.publicNo}`
  735. }else if(type == 4){
  736. obj.originalName = "修改对照页"
  737. }
  738. if(obj.type){
  739. this.confession = obj
  740. this.getOption()
  741. }else{
  742. this.getFileByGuid(obj)
  743. }
  744. break;
  745. }
  746. },
  747. //获取文件信息
  748. async getFileByGuid(obj){
  749. if(!obj.guid){
  750. this.$message.warning('当前文件不存在')
  751. return
  752. }
  753. var fileIds = [obj.guid]
  754. await this.$api.getFileData(fileIds).then(response=>{
  755. if(response && response.length>0){
  756. var data = response[0]
  757. // obj.originalName = data.originalName
  758. obj.type = data.type
  759. this.confession = obj
  760. this.getOption()
  761. }
  762. })
  763. },
  764. //切换会话
  765. async changeConversation(obj,sign){
  766. if(!sign){
  767. let isNext = await this.loading_change()
  768. if(!isNext){
  769. return
  770. }
  771. }
  772. this.add = false
  773. if(obj.id == this.currentConversation.id){
  774. this.currentConversation = obj
  775. if(sign && !this.reLoadSearch){
  776. //获取当前会话id
  777. this.chat_id = obj.conversationId
  778. // this.$set(this,'current_guid',this.notice_file.guid)
  779. //装载审查意见通知书并展示
  780. this.confession = obj.systemFile || {}
  781. this.$set(this,'notice_file',JSON.parse(JSON.stringify(this.confession)))
  782. this.$set(this,'current_guid',this.notice_file.guid)
  783. this.getOption()
  784. this.reLoadSearch = false
  785. }
  786. if(this.reLoadSearch){
  787. this.reLoadSearch = false
  788. }
  789. return
  790. }
  791. //装载当前会话信息
  792. this.currentConversation = obj
  793. //获取当前会话id
  794. this.chat_id = obj.conversationId
  795. //装载审查意见通知书并展示
  796. this.confession = obj.systemFile || {}
  797. this.$set(this,'notice_file',JSON.parse(JSON.stringify(this.confession)))
  798. this.$set(this,'current_guid',this.notice_file.guid)
  799. this.getOption()
  800. await this.getConversionDetails()
  801. //装载结果
  802. this.getResultContent(obj)
  803. },
  804. getResultContent(obj){
  805. this.result_file = {
  806. file_message:obj.assoSystemFile || {},
  807. show:false,
  808. option:{
  809. url: '',
  810. isEdit: false,
  811. fileType: '',
  812. title: '',
  813. lang: 'zh-CN',
  814. isPrint: true,
  815. user: {
  816. id: this.$s.getObj('userinfo').id,
  817. name: this.$s.getObj('userinfo').name
  818. }
  819. }
  820. }
  821. this.getResultOption()
  822. this.$set(this,'result',null)
  823. // this.$set(this,'patent_fileUrls',[])
  824. this.set_relevant_file()
  825. this.contrast_file = []
  826. this.app_file = {}
  827. let content = obj.content
  828. if(!content){
  829. // this.$set(this,'patent_fileUrls',[])
  830. this.set_relevant_file()
  831. return
  832. }
  833. try{
  834. let data = JSON.parse(content)
  835. // if(data.query && data.query.patent_fileUrls){
  836. // this.$set(this,'patent_fileUrls',data.query.patent_fileUrls)
  837. // }
  838. if(data.query && data.query.relevant_file){
  839. this.$set(this,'relevant_file',data.query.relevant_file)
  840. }
  841. if(data.query && data.query.claimChange){
  842. this.$set(this,'claimChange',data.query.claimChange)
  843. }
  844. if(data.query && data.query.main_claim_reason){
  845. this.$set(this,'main_claim_reason',data.query.main_claim_reason)
  846. }
  847. if(data.answer){
  848. this.$set(this,'result',data.answer)
  849. }
  850. if(data.relevant_file){
  851. this.app_file = data.relevant_file.app_file || {}
  852. this.modify_file = data.relevant_file.modify_file || {}
  853. this.contrast_file = data.relevant_file.contrast_file || []
  854. }
  855. if(data.data){
  856. let answer_data = data.data
  857. if(answer_data.code == 200){
  858. this.app_file = answer_data.data.app_file || {}
  859. this.modify_file = answer_data.data.modify_file || {}
  860. this.contrast_file = answer_data.data.contrast_file || []
  861. if(!this.result_file.show){
  862. let num = answer_data.data.num
  863. let claim_change = answer_data.data.claim_change
  864. let defense_opinion = answer_data.data.defense_opinion || []
  865. let reason = answer_data.data.reason
  866. let html = `<div style="line-height: 1.8em;"><div style="text-align: center;"><b>意见陈述书</b></div><div style="text-indent: 2em;margin: 0;">尊敬的审查员:</div><div style="text-indent: 2em;margin: 0;">首先,感谢审查员为审查本申请而付出的艰辛劳动!</div><div style="text-indent: 2em;margin: 0;">本意见陈述书是对国家知识产权局发出的第${num}次审查意见通知书所作的答复。</div><div style="text-indent: 2em;margin: 0;">审查意见通知书中指出:${ reason }</div><div style="text-indent: 2em;margin: 0;">申请人在仔细阅读、认真研究审查员的审查意见之后,在原权利要求书的基础上对权利要求进行了修改,并陈述意见如下:</div>`
  867. if(claim_change){
  868. html += `<div style="text-indent: 2em;margin: 0;"><b>一、修改说明</b></div><div style="text-indent: 2em;margin: 0;">${claim_change}</div>`
  869. }
  870. html += `<div style="text-indent: 2em;margin: 0;">`
  871. defense_opinion.forEach(item => {
  872. html = html + `<p>${item}</p>`
  873. });
  874. html = html + `</div><div style="text-indent: 2em;margin: 0;">综上所述,申请人认为,经过上述对原申请文件的陈述,已克服审查员在审查意见通知书中所指出的所有缺陷,希望审查员能以此为基础继续对本发明进行审查,如果审查员认为该申请仍有不符合专利法及其实施细则规定之处,恳请再给予一次陈述意见/修改的机会。</div><div style="text-indent: 2em;margin: 0;">感谢审查员的辛勤工作。</div></div>`
  875. this.$set(this,'result',html)
  876. }
  877. }else if(answer_data.code == 1001){
  878. this.result = answer_data
  879. this.$refs.errorTip.open(answer_data)
  880. }else if(answer_data.code == 1002){
  881. this.result = answer_data
  882. }else if(answer_data.code == 201){
  883. this.result = answer_data
  884. this.$set(this.changeClaim,'claim',answer_data.data)
  885. }else if(answer_data.code == 202){
  886. this.result = answer_data
  887. this.$set(this,'main_claim_reason',answer_data.data)
  888. }
  889. }
  890. }catch(e){
  891. }
  892. },
  893. openErrorTip(){
  894. this.$refs.errorTip.open(this.result)
  895. },
  896. setData(row,field,value){
  897. var fieldArray = field.split('.')
  898. let current = row || this;
  899. // 遍历路径中的每一部分,直到最后一个属性的父对象
  900. for (let i = 0; i < fieldArray.length - 1; i++) {
  901. // 确保当前对象有下一个属性,否则创建一个空对象(或你需要的任何默认值)
  902. if (!current.hasOwnProperty(fieldArray[i])) {
  903. current[fieldArray[i]] = {};
  904. }
  905. current = current[fieldArray[i]];
  906. }
  907. // 给最后一个属性赋值
  908. current[fieldArray[fieldArray.length - 1]] = value;
  909. },
  910. //上传文件
  911. onChange(file,field,row){
  912. let formData = new FormData()
  913. formData.append('sourceId',this.$constants.sourceId)
  914. formData.append('files',file.raw)
  915. var notice_file = {
  916. name:file.raw.name
  917. }
  918. var message = this.$message({
  919. message: '文件上传中...',
  920. type: 'warning',
  921. duration:0
  922. });
  923. this.$api.uploadFile(formData).then(response=>{
  924. if(response.code == 200){
  925. let guid = response.data[0]
  926. notice_file.guid = guid
  927. // this.$set(this,field,notice_file)
  928. this.setData(row,field,notice_file)
  929. message.close()
  930. this.$message.success('文件上传成功')
  931. }
  932. })
  933. },
  934. getOption(data,model='view'){
  935. let option_data = data || this.confession
  936. if(!option_data.guid){
  937. this.$message.warning('文件不存在')
  938. return
  939. }
  940. this.show = false
  941. this.option.name = option_data.originalName
  942. this.option.id = option_data.guid
  943. this.option.title = option_data.originalName
  944. this.option.url = this.$c.url+ (this.$c.env=='production'?'/api':'')+'/fileManager/downloadFile?fileId=' + option_data.guid
  945. this.option.fileType = option_data.type
  946. this.option.key = option_data.guid
  947. this.option.model = model
  948. this.$nextTick(()=>{
  949. this.show = true
  950. })
  951. },
  952. getResultOption(model='edit'){
  953. let option_data = this.result_file.file_message
  954. if(!option_data.guid){
  955. // this.$message.warning('文件不存在')
  956. return
  957. }
  958. let option = this.result_file.option
  959. // this.result_file.show = false
  960. this.$set(this.result_file,'show',false)
  961. option.name = option_data.originalName
  962. option.id = option_data.guid
  963. option.title = option_data.originalName
  964. option.url = this.$c.url+ (this.$c.env=='production'?'/api':'')+'/fileManager/downloadFile?fileId=' + option_data.guid
  965. option.fileType = option_data.type
  966. option.key = option_data.guid
  967. option.model = model
  968. this.$nextTick(()=>{
  969. this.$set(this.result_file,'show',true)
  970. })
  971. },
  972. //下载文件
  973. async download_file(){
  974. if(this.currentConversation.assoSystemFile && this.currentConversation.assoSystemFile.guid){
  975. downLoad2(this.currentConversation.assoSystemFile.guid,this.currentConversation.assoSystemFile.originalName)
  976. return
  977. }
  978. let confessionSessionId = this.currentConversation.id
  979. let filename = this.currentConversation.conversationName
  980. this.btnLoading = true
  981. let html = ''
  982. let answerDomList = document.querySelectorAll('#answer')
  983. if(answerDomList.length == 0){
  984. this.btnLoading = false
  985. return
  986. }
  987. let answerDom = answerDomList[answerDomList.length - 1]
  988. html = answerDom.innerHTML
  989. let guid = await this.$commonJS.exportToWordByHtml(html,filename,true)
  990. if(guid){
  991. this.saveResultFile(confessionSessionId,guid)
  992. }
  993. this.btnLoading = false
  994. },
  995. //保存下载之后的文件
  996. saveResultFile(confessionSessionId,guid){
  997. var params = {
  998. confessionSessionId:confessionSessionId,
  999. guid:guid
  1000. }
  1001. this.$api.addConfessionSessionFile(params).then(response=>{
  1002. if(response.code == 200){
  1003. this.queryConfessionSession()
  1004. }
  1005. })
  1006. },
  1007. //重新生成
  1008. regenerate(){
  1009. this.run()
  1010. },
  1011. },
  1012. };
  1013. </script>
  1014. <style lang="scss">
  1015. .OADefense{
  1016. .file_title{
  1017. font-weight: bold;
  1018. i{
  1019. color: red !important;
  1020. }
  1021. }
  1022. .file_show{
  1023. display: flex;
  1024. align-items: center;
  1025. justify-content: space-between;
  1026. line-height: 100px;
  1027. .file_name{
  1028. width: calc(100% - 90px);
  1029. }
  1030. .type {
  1031. min-width:75px;
  1032. display: block;
  1033. color: #57a5f7;
  1034. }
  1035. .icon {
  1036. display: none;
  1037. }
  1038. }
  1039. .file_show:hover {
  1040. background: #f4f4f4;
  1041. .name {
  1042. color: #57a5f7;
  1043. cursor: pointer;
  1044. }
  1045. .type {
  1046. min-width:75px;
  1047. display: none;
  1048. }
  1049. .icon {
  1050. display: block;
  1051. cursor: pointer;
  1052. }
  1053. }
  1054. .customize_file{
  1055. .upload-demo{
  1056. .el-upload{
  1057. width: 100% !important;
  1058. }
  1059. .el-upload-dragger {
  1060. width: 100% !important;
  1061. height:100px !important;
  1062. display: flex;
  1063. align-items: center;
  1064. .el-icon-upload{
  1065. font-size: 40px !important;
  1066. margin: 0 25px !important;
  1067. }
  1068. }
  1069. }
  1070. }
  1071. }
  1072. </style>
  1073. <style lang="scss" scoped>
  1074. .OADefense{
  1075. position: relative;
  1076. display: flex;
  1077. align-items: stretch;
  1078. height: calc(100% - 20px);
  1079. width:calc(100% - 20px);
  1080. padding: 10px;
  1081. .left{
  1082. width:50%;
  1083. height:calc(100% - 0px);
  1084. padding-right: 10px;
  1085. display: flex;
  1086. flex-direction: column;
  1087. .head{
  1088. display: flex;
  1089. align-items: center;
  1090. justify-content: space-between;
  1091. padding-bottom: 10px;
  1092. .head_left{
  1093. display: flex;
  1094. align-items: center;
  1095. }
  1096. i{
  1097. font-size: 20px;
  1098. }
  1099. }
  1100. .addContrastFile{
  1101. margin-top: 10px;
  1102. display: flex;
  1103. justify-content: center;
  1104. width: 100%;
  1105. }
  1106. .run{
  1107. display: flex;
  1108. justify-content: space-between;
  1109. .btn_content{
  1110. font-size: 14px;
  1111. display: flex;
  1112. align-items: center;
  1113. i{
  1114. margin-right: 5px;
  1115. font-size: 16px;
  1116. }
  1117. }
  1118. }
  1119. }
  1120. .line{
  1121. width:2px;
  1122. height: 100%;
  1123. background: #e6e6e6;
  1124. }
  1125. .right{
  1126. width:calc(100% - 50% - 2px);
  1127. min-width: 450px;
  1128. height:100%;
  1129. padding-left: 10px;
  1130. display: flex;
  1131. flex-direction: column;
  1132. .result_btn{
  1133. margin-top:10px;
  1134. display:flex;
  1135. justify-content:center;
  1136. }
  1137. .head{
  1138. display: flex;
  1139. align-items: center;
  1140. justify-content: space-between;
  1141. .head_left,.head_right{
  1142. display: flex;
  1143. align-items: center;
  1144. }
  1145. }
  1146. .style_starIcon__t_QZN{
  1147. width: 16px;
  1148. height: 16px;
  1149. }
  1150. .title{
  1151. margin-left: 20px;
  1152. font-weight: 600;
  1153. }
  1154. .result{
  1155. margin-top: 20px;
  1156. height:calc(100% - 20px - 30px);
  1157. overflow: auto;
  1158. &:empty::after{
  1159. content: "无结果";
  1160. color:#c2c5c9;
  1161. text-align: center;
  1162. }
  1163. .jiazai{
  1164. display: flex;
  1165. align-items: center;
  1166. height: 20px;
  1167. }
  1168. }
  1169. .loading-container{
  1170. display: flex;
  1171. justify-content: center;
  1172. align-items: center;
  1173. height: 100vh;
  1174. .loading-text {
  1175. font-size: 24px;
  1176. font-family: Arial;
  1177. display: flex;
  1178. gap: 4px;
  1179. }
  1180. .loading-text span {
  1181. display: inline-block;
  1182. animation: bounce 1.2s infinite ease-in-out;
  1183. color: black;
  1184. }
  1185. .loading-text span:nth-child(2) { animation-delay: 0.1s; }
  1186. .loading-text span:nth-child(3) { animation-delay: 0.2s; }
  1187. .loading-text span:nth-child(4) { animation-delay: 0.3s; }
  1188. .loading-text span:nth-child(5) { animation-delay: 0.4s; }
  1189. @keyframes bounce {
  1190. 0%, 40%, 100% {
  1191. transform: translateY(0);
  1192. }
  1193. 20% {
  1194. transform: translateY(-15px);
  1195. }
  1196. }
  1197. }
  1198. }
  1199. }
  1200. </style>