阅行客电子档案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1574 lines
66 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
8 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
8 months ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
7 months ago
7 months ago
2 years ago
7 months ago
2 years ago
7 months ago
2 years ago
7 months ago
7 months ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
8 months ago
7 months ago
8 months ago
7 months ago
8 months ago
2 years ago
  1. <template>
  2. <div>
  3. <div class="collect-header">
  4. <h4 :class="classType">{{ collectTitle }} </h4>
  5. <div class="collect-filter">
  6. <treeselect
  7. v-if="selectedCategory.arrangeType === 3 && isTitleType !== 4 && isTitleType !== 6 && activeIndex !== 1"
  8. v-model="query.project_class"
  9. :options="projectOptions"
  10. style="width: 180px;"
  11. flat
  12. :multiple="false"
  13. :normalizer="normalizerProject"
  14. :default-expand-level="Infinity"
  15. :placeholder="projectPlaceholder"
  16. @input="handleSearch(collectLevel)"
  17. @select="handleSearch(collectLevel)"
  18. >
  19. <p
  20. slot="option-label"
  21. slot-scope="{node}"
  22. style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis; width: 100%; padding-left: 10px;"
  23. :title="node.label"
  24. >
  25. <template> {{ node.label }} </template>
  26. </p>
  27. </treeselect>
  28. <treeselect
  29. v-if="isTitleType !== 6 && isTitleType !== 2"
  30. v-model="query.archive_ctg_no"
  31. :options="classifyOptions"
  32. style="width: 180px;"
  33. flat
  34. :multiple="false"
  35. :normalizer="normalizer"
  36. placeholder="请选择档案分类"
  37. @input="handleSearch(collectLevel)"
  38. @select="handleSearch(collectLevel)"
  39. >
  40. <p
  41. slot="option-label"
  42. slot-scope="{node}"
  43. style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis; width: 100%; padding-left: 10px;"
  44. :title="node.label"
  45. >
  46. <template> {{ node.label }} </template>
  47. </p>
  48. </treeselect>
  49. </div>
  50. <div v-if="isTitleType !== 6" class="head-search">
  51. <!-- 搜索 -->
  52. <el-input v-model="query.search" clearable size="small" :placeholder="placeholderType" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @keyup.enter.native="handleSearch(collectLevel)" @clear="handleSearch(collectLevel)" />
  53. <el-button class="filter-item filter-search" size="mini" type="success" icon="el-icon-search" @click="handleSearch(collectLevel)">搜索</el-button>
  54. <el-button class="filter-item filter-refresh" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetQuery">重置</el-button>
  55. </div>
  56. <div v-if="!isRecycle" class="collect-menu">
  57. <el-menu
  58. :default-active="activeMenuIndex"
  59. mode="horizontal"
  60. @select="handleSelect"
  61. >
  62. <el-submenu index="1">
  63. <template slot="title">
  64. <i class="iconfont icon-changgui" />
  65. <span>常规</span>
  66. </template>
  67. <el-menu-item-group class="collect-submenu-group">
  68. <el-menu-item v-if="isTitleType !== 6" index="1-1" @click="handleForm('add',0)">新增</el-menu-item>
  69. <el-menu-item v-if="isTitleType !== 6" index="1-2" @click="handleForm('edit',0)">编辑</el-menu-item>
  70. <el-menu-item v-if="isTitleType !== 4" index="1-3" @click="toDelete">删除</el-menu-item>
  71. <el-menu-item v-if="isTitleType === 4" index="1-4" @click="toMove">移出</el-menu-item>
  72. </el-menu-item-group>
  73. <el-menu-item-group v-if="(isTitleType === 3 && selectedCategory.arrangeType === 1) || isTitleType === 4 || isTitleType === 6 || (isTitleType === 3 && activeIndex === 1)" class="collect-submenu-group submenu-tree">
  74. <template slot="title">原文上传</template>
  75. <el-menu-item index="1-5" @click="fileUpload(0)">普通上传</el-menu-item>
  76. <el-menu-item index="1-6" @click="fileUpload(1)">大文件上传</el-menu-item>
  77. </el-menu-item-group>
  78. </el-submenu>
  79. <el-submenu v-if="isTitleType !== 6" index="2">
  80. <template slot="title">
  81. <i class="iconfont icon-zhengli" />
  82. <span>整理</span>
  83. </template>
  84. <el-menu-item-group class="collect-submenu-group">
  85. <el-menu-item v-if="isTitleType !== 2" index="2-1" @click="handleBlukImport">批量导入</el-menu-item>
  86. <!-- 项目 / 案卷 / 卷内 / 文件-->
  87. <el-menu-item v-if="activeIndex !== 1 || (isTitleType === 3 && selectedCategory.arrangeType === 1 && activeIndex === 1)" index="2-2" @click="handleBlukEditing">批量修改</el-menu-item>
  88. <el-menu-item v-if="isTitleType === 3 && activeIndex === 0 && selectedCategory.arrangeType !== 1" index="2-3" @click="handleJnSeqAdjustment('anjuan')">案卷顺序调整</el-menu-item>
  89. <el-menu-item v-if="isTitleType === 3 && activeIndex === 0 && selectedCategory.arrangeType !== 1 " index="2-12" @click="handleJnSeqAdjustment('juannei')">卷内顺序调整</el-menu-item>
  90. <el-menu-item v-if="isTitleType === 3 && selectedCategory.arrangeType === 1" index="2-3" @click="handleJnSeqAdjustment('file')">文件顺序调整</el-menu-item>
  91. <el-menu-item v-if="isTitleType !== 2 && !(isTitleType === 3 && (selectedCategory.arrangeType === 1|| selectedCategory.arrangeType === 2) && activeIndex === 1) && isTitleType !== 4" index="2-4" @click="handleFileNumberUpdate(0)">档号更新</el-menu-item>
  92. <!-- 案卷 -->
  93. <el-menu-item v-if="isTitleType === 3 && activeIndex === 0 && selectedCategory.arrangeType !== 1 " index="2-5" @click="handleFileNumberUpdate(1)">卷内档号更新</el-menu-item>
  94. <el-menu-item v-if="isTitleType === 3 && activeIndex === 0 && selectedCategory.arrangeType !== 1" index="2-6" @click="handleUncoil">拆卷</el-menu-item>
  95. <el-menu-item v-if="isTitleType === 3 && activeIndex === 0 && selectedCategory.arrangeType !== 1" index="2-7" @click="handleCombineFile">合卷</el-menu-item>
  96. <el-menu-item v-if="isTitleType === 3 && selectedCategory.arrangeType !== 1" index="2-8" @click="handleInsertFile">插件</el-menu-item>
  97. <!-- 案卷 / 卷内 / 文件 -->
  98. <el-menu-item v-if="isTitleType !== 2" index="2-9" @click="handleCollectMoveFile">移动</el-menu-item>
  99. <!-- 案卷 -->
  100. <el-menu-item v-if="isTitleType === 3 && activeIndex === 0" index="2-10" @click="handleFiling">归档</el-menu-item>
  101. <!-- 文件 -->
  102. <el-menu-item v-if="(isTitleType === 3 && selectedCategory.arrangeType === 1) || (isTitleType === 3 && activeIndex === 1)" index="2-11" @click="handleReturn">退回预归档库</el-menu-item>
  103. </el-menu-item-group>
  104. <el-menu-item-group v-if="isTitleType === 3 && activeIndex === 1 && selectedCategory.arrangeType !== 1" class="collect-submenu-group submenu-tree">
  105. <template slot="title">组卷</template>
  106. <el-menu-item index="2-12" @click="handleQuickPaper">快速组卷</el-menu-item>
  107. <el-menu-item index="2-13" @click="handlePaper">手工组卷</el-menu-item>
  108. </el-menu-item-group>
  109. <el-menu-item-group v-if="isTitleType !== 4" class="collect-submenu-group submenu-tree">
  110. <template slot="title">档案装盒</template>
  111. <el-menu-item index="2-2" @click="handlePackingBox(0)">装盒</el-menu-item>
  112. <el-menu-item v-if="selectedCategory.arrangeType !== 1 " index="2-3" @click="handlePackingBox(1)">分卷装盒</el-menu-item>
  113. </el-menu-item-group>
  114. </el-submenu>
  115. <el-submenu index="3">
  116. <template slot="title">
  117. <i class="iconfont icon-gengduo" />
  118. <span>更多</span>
  119. </template>
  120. <el-menu-item-group class="collect-submenu-group">
  121. <el-menu-item v-if="isTitleType !== 6" index="3-1" @click="handleExport">导出</el-menu-item>
  122. <el-menu-item v-if="!(isTitleType === 3 && (selectedCategory.arrangeType === 3 || selectedCategory.arrangeType === 2) && activeIndex === 1) && (isTitleType !== 2 && isTitleType !== 6)" index="3-2" @click="handlePrint">打印</el-menu-item>
  123. <el-menu-item v-if="!(isTitleType === 3 && (selectedCategory.arrangeType === 3 || selectedCategory.arrangeType === 2) && activeIndex === 1) && (isTitleType !== 2 && isTitleType !== 6) && isTitleType !== 4" index="3-3" @click="handleFourTest">四性检测</el-menu-item>
  124. <el-menu-item v-if="isTitleType === 6" index="3-4" @click="handleOriginalDownload">下载</el-menu-item>
  125. </el-menu-item-group>
  126. <el-menu-item-group v-if="!(isTitleType === 3 && (selectedCategory.arrangeType === 3 || selectedCategory.arrangeType === 2) && activeIndex === 1) && (isTitleType !== 2 && isTitleType !== 4 && isTitleType !== 6)" class="collect-submenu-group submenu-tree">
  127. <template slot="title">电子文件目录</template>
  128. <el-menu-item index="3-5" @click="handleCatalogDownload">目录下载</el-menu-item>
  129. <el-menu-item index="3-6" @click="fileUpload(2)">目录上传</el-menu-item>
  130. </el-menu-item-group>
  131. </el-submenu>
  132. </el-menu>
  133. </div>
  134. <div v-if="isRecycle && (isTitleType === 2 || isTitleType === 3)" class="collect-menu">
  135. <el-button class="filter-item" size="mini" type="success" @click="toRecover"><i class="iconfont icon-huifu" />恢复</el-button>
  136. <el-button class="filter-item" size="mini" type="success" @click="toCompletelyDelete"><i class="iconfont icon-shanchu" />彻底删除</el-button>
  137. </div>
  138. <!--新增 / 编辑 表单组件-->
  139. <el-dialog :class="isAiAutoCategory ? 'preview-dialog ai-preview-dialog' :'preview-dialog'" :modal-append-to-body="false" :close-on-click-modal="false" append-to-body :before-close="handleClose" :visible="formVisible" :title="formTitle">
  140. <span class="dialog-right-top" />
  141. <span class="dialog-left-bottom" />
  142. <div class="setting-dialog">
  143. <!-- form @emitTableList="getTableList" -->
  144. <div style="display: flex; justify-content: flex-start;">
  145. <PreviewForm
  146. v-if="formPreviewData.length"
  147. ref="previewForm"
  148. :is-has-code="true"
  149. :is-disabled="false"
  150. :form-preview-data.sync="formPreviewData"
  151. :selected-category="selectedCategory"
  152. :arc-id="arcId"
  153. :is-des-form-type="isDesFormType"
  154. :is-title-type="isTitleType"
  155. :collect-level="collectLevel"
  156. :category-menu="categoryMenu"
  157. @close-dialog="closeDialog"
  158. @handleForm="handleForm"
  159. @formLoadingShow="formLoadingShow"
  160. />
  161. <div v-if="isAiAutoCategory" v-loading="aiResultCaLoading" style="flex: 1; margin-left: 10px; ">
  162. <pre ref="typingContainer" v-highlightjs="displayedText">{{ displayedText }}</pre>
  163. </div>
  164. </div>
  165. <div slot="footer" class="dialog-footer" style="margin-top: 85px !important;">
  166. <el-button v-if="formIsAddOrEdit==='add' && ((isTitleType === 3 && selectedCategory.arrangeType === 1) || isTitleType === 4 || isTitleType === 6 || (isTitleType === 3 && activeIndex === 1))" type="text" style="width: 84px; border-color: #0348f3; color: #0348f3; " @click="handleAiCategory">AI辅助著录</el-button>
  167. <el-button v-if="formIsAddOrEdit==='add'" type="primary" style="width: 140px; " @click="handlerArchivesSubmit(1)">保存并新增下一条</el-button>
  168. <el-button :loading="archivesBtnLoading" type="primary" @click="handlerArchivesSubmit(0)">保存</el-button>
  169. </div>
  170. </div>
  171. </el-dialog>
  172. <!-- AI辅助著录未处理已解析的文件 -->
  173. <el-dialog class="aiAssist-dialog" title="AI已解析文件" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="aIAssistEnterVisible">
  174. <div class="setting-dialog">
  175. <!-- @select="crud.selectChange"
  176. @select-all="crud.selectAllChange"
  177. @cell-dblclick="tableDoubleClick"
  178. @selection-change="crud.selectionChangeHandler" -->
  179. <el-table
  180. ref="table"
  181. v-loading="aiCategoryloading"
  182. class="archives-table"
  183. :data="aiCategoryData"
  184. row-key="id"
  185. >
  186. <el-table-column type="selection" width="55" align="center" />
  187. <el-table-column label="任务编号" prop="id" />
  188. <el-table-column label="文件数量" prop="fileNum" />
  189. <el-table-column label="创建人" prop="create_by" />
  190. <el-table-column label="创建时间" prop="update_time" align="center" width="160">
  191. <template slot-scope="scope">
  192. <div v-if="scope.row.update_time">{{ scope.row.update_time | parseTime }}</div>
  193. <div v-else>-</div>
  194. </template>
  195. </el-table-column>
  196. <el-table-column label="解析完成时间" prop="analysisTime" align="center" width="160">
  197. <template slot-scope="scope">
  198. <div v-if="scope.row.analysisTime">{{ scope.row.analysisTime | parseTime }}</div>
  199. <div v-else>-</div>
  200. </template>
  201. </el-table-column>
  202. <el-table-column label="状态" prop="status" align="center" width="140">
  203. <template slot-scope="scope">
  204. <span v-if="!scope.row.isAnalysis" class="row-state row-warehousing state-active">解析中</span>
  205. <span v-else class="row-state row-binding state-active">已解析</span>
  206. </template>
  207. </el-table-column>
  208. <el-table-column label="操作" prop="status" align="center" width="140">
  209. <template slot-scope="scope">
  210. <el-button v-if="scope.row.isAnalysis" size="mini" class="check-btn" style="padding: 5px;" @click="getDoHandleEnterAnalysis(scope.row)">
  211. <i class="iconfont icon-tianjiawenjian" />
  212. 新增档案
  213. </el-button>
  214. </template>
  215. </el-table-column>
  216. </el-table>
  217. </div>
  218. </el-dialog>
  219. <!--卷内移出 组件-->
  220. <el-dialog class="tip-dialog" title="提示" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="moveVisible">
  221. <div class="setting-dialog">
  222. <div class="tip-content">
  223. <p class="tipMsg">此移出将把会所选条目返还到未整理列表</p>
  224. <span>你是否还要继续?</span>
  225. </div>
  226. <div slot="footer" class="dialog-footer">
  227. <el-button type="text" @click="moveVisible = false">取消</el-button>
  228. <el-button type="primary" @click.native="handleMoveConfirm">确定</el-button>
  229. </div>
  230. </div>
  231. </el-dialog>
  232. <!-- 原文上传 -->
  233. <UploadOriginal ref="uploadOriginalRef" :selected-category="selectedCategory" :arc-id="arcId" @close-dialog="closeDialog" />
  234. <!-- 大文件上传 -->
  235. <BigUpload ref="uploadBigRef" :selected-category="selectedCategory" :arc-id="arcId" @close-dialog="closeDialog" />
  236. <!-- 批量导入 -->
  237. <BlukImport ref="blukImportRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" />
  238. <!-- 批量修改 -->
  239. <BlukEditing ref="blukEditingRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" />
  240. <!-- 档案调整 -->
  241. <!-- <FileNumberAdjustment ref="fileNumberAdjustmentRef" :selected-category="selectedCategory" :collect-level="collectLevel" /> -->
  242. <!-- 案卷/文件/卷内 顺序调整 -->
  243. <FileSeqAdjustment ref="fileSeqAdjustmentRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" />
  244. <!-- 合卷 -->
  245. <CombineFile ref="combineFileRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" />
  246. <!-- 插件 -->
  247. <InsertFile ref="insertFileRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" />
  248. <!-- 移动 -->
  249. <CollectMoveFile ref="collectMoveFileRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" />
  250. <!-- 打印 -->
  251. <Print ref="printRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" />
  252. <!-- 四性检测 -->
  253. <FourTest ref="fourTestRef" :selected-category="selectedCategory" :collect-level="collectLevel" @close-dialog="closeDialog" />
  254. <!-- 快速组卷 -->
  255. <QuickPaper ref="quickPaperRef" :selected-category="selectedCategory" :arc-id="arcId" :collect-level="collectLevel" @close-dialog="closeDialog" />
  256. <!-- 归档 -->
  257. <ArchivesFilling ref="archivesFillingRef" :selected-category="selectedCategory" :collect-level="collectLevel" :selections="selections" @close-dialog="closeDialog" @handleFillingToFourTest="handleFillingToFourTest" />
  258. <!-- 装盒 / 分卷装盒 -->
  259. <PackingBox ref="packingBox" :selected-category="selectedCategory" :selections="selections" :total-sum-all="totalSumAll" @close-dialog="closeDialog" />
  260. </div>
  261. <div style="display: flex; justify-content: space-between; height: 30px; line-height: 30px; padding: 0 20px; ">
  262. <span v-if="(isTitleType !== 2 && selectedCategory.arrangeType === 3 ) || ((isTitleType === 4 || isTitleType === 6) && selectedCategory.arrangeType === 2) || (isTitleType === 6 && selectedCategory.arrangeType === 1)" style="font-size: 12px;">{{ test }}</span>
  263. <div v-if="isTitleType !== 2 && !isRecycle && isTitleType !== 6 && !(isTitleType === 3 && activeIndex === 1 && selectedCategory.arrangeType !== 1 )" class="mangement-fixed-top">
  264. <el-checkbox v-model="parentsData.fixedStatusBar" @change="statusBarChecked">隐藏状态栏</el-checkbox>
  265. </div>
  266. </div>
  267. </div>
  268. </template>
  269. <script>
  270. import CRUD, { crud } from '@crud/crud'
  271. import { collectionLibraryCrud } from '../mixins/index'
  272. import { FetchInitCategoryInputFieldByPid, FetchCategoryMenu } from '@/api/system/category/category'
  273. import { FetchDetailsById, collectDel, FetchRemoveArchivesSingle, FetchDeleteArchivesFile, FetchUpdateArchivesNo, FetchDisbandArchives, FetchReturnReDocument, FetchCompleteDelArchives, FetchRestoreArchives } from '@/api/collect/collect'
  274. import { FetchInitAssistEnter, FetchDoHandleEnterAnalysis } from '@/api/ai/ai'
  275. import { FetchArchivesClassTree } from '@/api/system/archivesClass'
  276. import Treeselect from '@riophae/vue-treeselect'
  277. import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  278. import PreviewForm from '@/views/components/category/PreviewForm'
  279. import UploadOriginal from './uploadOriginal/index'
  280. import BigUpload from './uploadOriginal/bigUpload'
  281. import BlukImport from './bulkImport/index'
  282. import BlukEditing from './blukEditing/index'
  283. import FileSeqAdjustment from './fileSeqAdjustment/index'
  284. import CombineFile from './combineFile/index'
  285. import InsertFile from './insertFile/index'
  286. import CollectMoveFile from './collectMoveFile/index'
  287. import Print from './print/index'
  288. import FourTest from './fourTest/index'
  289. import QuickPaper from './quickPaper/index'
  290. import PackingBox from './packingBox/index'
  291. import ArchivesFilling from './archivesFilling/index'
  292. import qs from 'qs'
  293. import { downloadFile, exportFile } from '@/utils/index'
  294. import { mapGetters } from 'vuex'
  295. export default {
  296. name: 'CollectHeader',
  297. components: { Treeselect, PreviewForm, UploadOriginal, BigUpload, BlukImport, BlukEditing, FileSeqAdjustment, CombineFile, InsertFile, CollectMoveFile, Print, FourTest, QuickPaper, PackingBox, ArchivesFilling },
  298. mixins: [collectionLibraryCrud, crud()],
  299. props: {
  300. selectedCategory: {
  301. type: Object,
  302. default: function() {
  303. return {}
  304. }
  305. },
  306. isTitleType: {
  307. type: Number,
  308. default: 2
  309. },
  310. selections: {
  311. type: Array,
  312. default: () => []
  313. },
  314. activeIndex: {
  315. type: Number,
  316. default: 0
  317. },
  318. isTabFile: {
  319. type: Boolean,
  320. default: false
  321. },
  322. isRecycle: {
  323. type: Boolean,
  324. default: false
  325. },
  326. test: {
  327. type: String,
  328. default: ''
  329. }
  330. },
  331. inject: ['parentsData'],
  332. data() {
  333. return {
  334. archivesBtnLoading: false,
  335. activeMenuIndex: '1',
  336. formVisible: false,
  337. formTitle: '项目',
  338. formPreviewData: [], // 预览界面data
  339. projectOptions: [],
  340. classifyOptions: [],
  341. moveVisible: false,
  342. recoverVisible: false,
  343. isDesFormType: 'arcives', // 区分是门类得还是档案得
  344. arcId: null,
  345. quickPaper: false,
  346. quickPaperArcId: [],
  347. totalSumAll: 0,
  348. categoryMenu: [],
  349. isAiAutoCategory: false,
  350. displayedText: '',
  351. formIsAddOrEdit: '',
  352. aIAssistEnterVisible: false,
  353. aiCategoryData: [],
  354. aiCategoryloading: false,
  355. aiResultCaLoading: true, // ai分析得内容结果前得loading
  356. isDialogClosed: false, // 新增标志位,用于控制是否继续处理流式响应
  357. reader: null // 用于存储响应体的读取器
  358. }
  359. },
  360. computed: {
  361. ...mapGetters([
  362. 'baseApi'
  363. ]),
  364. collectTitle() {
  365. if (this.isTitleType === 2) {
  366. return '项目'
  367. } else if (this.isTitleType === 3) {
  368. if (this.selectedCategory.arrangeType === 1) {
  369. return '文件'
  370. } else {
  371. if (this.activeIndex === 1) {
  372. return '文件'
  373. } else {
  374. return '案卷'
  375. }
  376. }
  377. } else if (this.isTitleType === 4) {
  378. return '卷内'
  379. } else if (this.isTitleType === 6) {
  380. return '原文'
  381. }
  382. return ''
  383. },
  384. collectLevel() {
  385. if (this.isTitleType === 2) {
  386. return 1
  387. } else if (this.isTitleType === 3) {
  388. if (this.selectedCategory.arrangeType === 1) {
  389. return 3
  390. } else {
  391. if (this.activeIndex === 1) {
  392. if (this.quickPaper) {
  393. return 2
  394. } else {
  395. return 3
  396. }
  397. } else {
  398. return 2
  399. }
  400. }
  401. } else if (this.isTitleType === 4) {
  402. return 3
  403. } else if (this.isTitleType === 6) {
  404. return 4
  405. }
  406. return null
  407. },
  408. classType() {
  409. if (this.isTitleType === 2) {
  410. return ''
  411. } else if (this.isTitleType === 3) {
  412. if (this.selectedCategory.arrangeType === 1) {
  413. return 'is-juannei'
  414. } else {
  415. if (this.activeIndex === 1) {
  416. return 'is-juannei'
  417. } else {
  418. return 'is-anjuan'
  419. }
  420. }
  421. } else if (this.isTitleType === 4) {
  422. return 'is-juannei'
  423. } else if (this.isTitleType === 6) {
  424. return 'is-file'
  425. }
  426. return ''
  427. },
  428. placeholderType() {
  429. if (this.isTitleType === 2) {
  430. return '输入项目名称或编号'
  431. } else if (this.isTitleType === 3 || this.isTitleType === 4) {
  432. return '输入题名或档号'
  433. }
  434. return '输入项目名称或编号'
  435. },
  436. projectPlaceholder() {
  437. if (this.isTitleType === 2) {
  438. return '请选择项目分类'
  439. } else if (this.isTitleType === 3) {
  440. return '请选择项目阶段'
  441. }
  442. return '请选择项目分类'
  443. }
  444. },
  445. watch: {
  446. selectedCategory: function(newValue, oldValue) {
  447. if (newValue && newValue.id) {
  448. this.getInitArchivesClass()
  449. }
  450. },
  451. isTitleType: function(newValue, oldValue) {
  452. console.log('isTitleType', newValue)
  453. },
  454. activeIndex: function(newValue, oldValue) {
  455. if (newValue === 1) {
  456. this.parentsData.isTabFile = true
  457. } else {
  458. this.parentsData.isTabFile = false
  459. }
  460. }
  461. },
  462. created() {
  463. },
  464. mounted() {
  465. this.getInitArchivesClass()
  466. this.getCategoryDataTree()
  467. },
  468. methods: {
  469. getCategoryDataTree() {
  470. FetchCategoryMenu().then(res => {
  471. this.categoryMenu = res
  472. })
  473. },
  474. resetQuery() {
  475. this.query = {
  476. 'search': null,
  477. 'project_class': null,
  478. 'archive_ctg_no': null
  479. }
  480. this.handleSearch(this.collectLevel)
  481. },
  482. // 筛选 - 档案分类
  483. getInitArchivesClass() {
  484. this.classifyOptions = []
  485. this.query = {
  486. 'search': null,
  487. 'project_class': null,
  488. 'archive_ctg_no': null
  489. }
  490. const params = {
  491. 'categoryId': this.selectedCategory.id
  492. }
  493. FetchArchivesClassTree(params).then((res) => {
  494. this.classifyOptions = JSON.parse(JSON.stringify(res))
  495. }).catch(err => {
  496. console.log(err)
  497. })
  498. },
  499. normalizer(node) {
  500. if (node.childArchivesClass === null) {
  501. delete node.childArchivesClass
  502. }
  503. return {
  504. id: node.code,
  505. label: `${node.name} - ${node.code}`,
  506. children: node.childArchivesClass
  507. }
  508. },
  509. handleSelect(key, keyPath) {
  510. console.log(key, keyPath)
  511. },
  512. // 著录界面-form/详情-api
  513. handleForm(type, isPaper) {
  514. this.formIsAddOrEdit = type
  515. if (type === 'add') {
  516. if (this.parentsData.parentsProjectId && this.isTitleType === 3) {
  517. console.log('项目下的案卷')
  518. } else {
  519. if (this.parentsData.parentsAnjuanRow && this.parentsData.parentsAnjuanRow.collect_formal === 2) {
  520. this.$message({ message: '当前档案处于归档流程中,不可操作新增,请先确认!', offset: 8 })
  521. return false
  522. }
  523. }
  524. this.arcId = null
  525. if (isPaper) {
  526. this.quickPaper = true
  527. this.formTitle = '新增案卷'
  528. } else {
  529. this.formTitle = '新增' + this.collectTitle
  530. this.quickPaper = false
  531. }
  532. } else if (type === 'edit') {
  533. this.quickPaper = false
  534. if (this.selections.length === 0) {
  535. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  536. return false
  537. } else if (this.selections.length > 1) {
  538. this.$message({ message: '编辑操作只可勾选唯一目标条目,请先确认!', offset: 8 })
  539. return false
  540. } else if (this.selections[0].collect_formal === 2) {
  541. this.$message({ message: '当前所选的档案处于归档流程中,不可操作编辑,请先确认!', offset: 8 })
  542. return false
  543. }
  544. this.arcId = this.selections[0].id
  545. this.formTitle = '编辑' + this.collectTitle
  546. }
  547. // this.form.dictionaryConfigId = {}
  548. // this.formPreviewData = []
  549. // 档案预编辑获取字段
  550. this.formVisible = true
  551. this.$nextTick(() => {
  552. this.getFormInfo(type)
  553. })
  554. },
  555. getFormInfo(type) {
  556. const currentPageSize = localStorage.getItem('currentPageSize')
  557. if (currentPageSize) {
  558. this.page.size = parseInt(currentPageSize)
  559. } else {
  560. this.page.size = 10
  561. }
  562. console.log('this.page.size', this.page.size)
  563. console.log('this.page.page', this.page.page)
  564. if (type === 'edit') {
  565. const params = {
  566. 'categoryId': this.selectedCategory.id,
  567. 'categoryLevel': this.collectLevel,
  568. 'id': this.arcId
  569. }
  570. FetchDetailsById(params).then(data => {
  571. // const showFiledAll = data.showFiled.filter(item => item.isSequence).sort((a, b) => a.isSequence - b.isSequence)
  572. const showFiledAll = data.showFiled
  573. this.$nextTick(() => {
  574. this.formPreviewData = showFiledAll
  575. this.isDesFormType = 'arcives'
  576. this.$nextTick(() => {
  577. this.$refs.previewForm.archivesType = 'edit'
  578. this.$refs.previewForm.addOrUpdateForm = data.echo
  579. this.$refs.previewForm.FetchNoFormatField(this.selectedCategory.id)
  580. })
  581. })
  582. })
  583. } else {
  584. const params = {
  585. 'categoryId': this.selectedCategory.id,
  586. 'categoryLevel': this.collectLevel
  587. }
  588. FetchInitCategoryInputFieldByPid(params).then(data => {
  589. this.formPreviewData = data
  590. this.isDesFormType = 'arcives'
  591. this.$nextTick(() => {
  592. this.$refs.previewForm.archivesType = 'add'
  593. this.$refs.previewForm.activeIndex = this.activeIndex
  594. const savePrevFromData = JSON.parse(localStorage.getItem('savePrevFromData'))
  595. console.log('savePrevFromData', savePrevFromData)
  596. if (savePrevFromData) {
  597. if ('record_no' in savePrevFromData && 'item_no' in savePrevFromData) {
  598. if (savePrevFromData.item_no && !isNaN(Number(savePrevFromData.item_no))) {
  599. savePrevFromData.item_no = (parseInt(savePrevFromData.item_no) + 1).toString()
  600. }
  601. } else if ('record_no' in savePrevFromData) {
  602. if (savePrevFromData.record_no && !isNaN(Number(savePrevFromData.record_no))) {
  603. savePrevFromData.record_no = (parseInt(savePrevFromData.record_no) + 1).toString()
  604. }
  605. } else if ('item_no' in savePrevFromData) {
  606. if (savePrevFromData.item_no && !isNaN(Number(savePrevFromData.item_no))) {
  607. savePrevFromData.item_no = (parseInt(savePrevFromData.item_no) + 1).toString()
  608. }
  609. }
  610. // 查找 item_no 或 record_no 字段并进行补零操作
  611. const findAndPadField = (fieldName) => {
  612. const field = this.formPreviewData.find(item => item.fieldName === fieldName)
  613. if (field && field.isFilling) {
  614. const fillingDigit = field.fillingDigit
  615. if (savePrevFromData[fieldName]) {
  616. savePrevFromData[fieldName] = savePrevFromData[fieldName].toString().padStart(fillingDigit, '0')
  617. }
  618. }
  619. }
  620. findAndPadField('item_no')
  621. findAndPadField('record_no')
  622. this.$refs.previewForm.addOrUpdateForm = savePrevFromData
  623. }
  624. this.$refs.previewForm.FetchNoFormatField(this.selectedCategory.id)
  625. })
  626. })
  627. }
  628. },
  629. // form - submit
  630. handlerArchivesSubmit(type) {
  631. this.$refs.previewForm.submitForm('addOrUpdateForm', this.selectedCategory.id, this.quickPaperArcId, type)
  632. },
  633. handlerArchivesSubmitAndAdd() {
  634. this.$refs.previewForm.submitForm('addOrUpdateForm', this.selectedCategory.id, this.quickPaperArcId)
  635. },
  636. formLoadingShow(loadingType) {
  637. this.archivesBtnLoading = loadingType
  638. },
  639. // 关闭
  640. handleClose(done) {
  641. this.formVisible = false
  642. this.quickPaper = false
  643. localStorage.removeItem('savePrevFromData')
  644. this.aiCategoryData = []
  645. this.isAiAutoCategory = false
  646. this.displayedText = '' // 清空 displayedText
  647. this.isDialogClosed = true // 设置标志位为 true
  648. if (this.reader) {
  649. this.reader.cancel() // 取消读取器,终止流式响应
  650. }
  651. done()
  652. },
  653. // 删除
  654. toDelete() {
  655. console.log('this.page.page333', this.page.page)
  656. console.log('this.page.total33333', this.page.total)
  657. if (this.selections.length === 0) {
  658. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  659. return false
  660. }
  661. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  662. if (isHasFillFormal) {
  663. this.$message({ message: '您所选的条目有正在归档流程中,不可操作删除,请先确认!', offset: 8 })
  664. return false
  665. }
  666. if (this.collectLevel === 4) {
  667. if (this.parentsData.parentsAnjuanRow && this.parentsData.parentsAnjuanRow.collect_formal === 2) {
  668. this.$message({ message: '当前档案处于归档流程中,不可操作删除,请先确认!', offset: 8 })
  669. return false
  670. }
  671. }
  672. let messageTip
  673. if (this.activeIndex === 1) {
  674. messageTip = '此删除将把会所选条目与其子集彻底删除'
  675. } else {
  676. messageTip = '此删除将把会所选条目与其子集放入回收站'
  677. }
  678. this.$confirm(messageTip + '<span>你是否还要继续?</span>', '提示', {
  679. confirmButtonText: '继续',
  680. cancelButtonText: '取消',
  681. type: 'warning',
  682. dangerouslyUseHTMLString: true
  683. }).then(() => {
  684. if (this.activeIndex === 1) {
  685. const archivesIds = []
  686. this.selections.forEach(val => {
  687. archivesIds.push(val.id)
  688. })
  689. const params = {
  690. 'categoryId': this.selectedCategory.id,
  691. 'categoryLevel': this.collectLevel,
  692. 'archivesIds': archivesIds
  693. }
  694. FetchCompleteDelArchives(params).then((res) => {
  695. if (res.code !== 500) {
  696. this.$message({ message: res, type: 'success', offset: 8 })
  697. localStorage.removeItem('currentPageSize')
  698. localStorage.removeItem('currentPage')
  699. this.handleSearch(this.collectLevel)
  700. } else {
  701. this.$message({ message: '删除所选档案失败', type: 'error', offset: 8 })
  702. }
  703. }).catch(err => {
  704. console.log(err)
  705. })
  706. } else {
  707. this.handleDelConfirm()
  708. }
  709. }).catch(() => {
  710. })
  711. },
  712. // 卷内 - 移除
  713. toMove() {
  714. if (this.selections.length === 0) {
  715. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  716. return false
  717. }
  718. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  719. if (isHasFillFormal) {
  720. this.$message({ message: '您所选的条目有正在归档流程中,不可操作删除,请先确认!', offset: 8 })
  721. return false
  722. }
  723. this.moveVisible = true
  724. },
  725. // 删除 - 确认
  726. handleDelConfirm() {
  727. if (this.collectLevel === 4) {
  728. const params = this.selections.map((item) => {
  729. const json = {}
  730. json.archivesId = item.archive_id
  731. json.categoryId = this.selectedCategory.id
  732. json.documentFileId = item.document_file_id
  733. json.documentId = item.document_id
  734. json.id = item.id
  735. return json
  736. })
  737. FetchDeleteArchivesFile(params).then((res) => {
  738. if (res === 'SUCCESS') {
  739. localStorage.removeItem('currentPageSize')
  740. localStorage.removeItem('currentPage')
  741. this.$message({ message: '删除成功', type: 'success', offset: 8 })
  742. this.handleSearch(this.collectLevel)
  743. } else {
  744. this.$message({ message: '删除所选电子原文失败', type: 'error', offset: 8 })
  745. }
  746. }).catch(err => {
  747. console.log(err)
  748. })
  749. } else {
  750. const archivesIds = []
  751. this.selections.forEach(val => {
  752. archivesIds.push(val.id)
  753. })
  754. const params = {
  755. 'categoryId': this.selectedCategory.id,
  756. 'categoryLevel': this.collectLevel,
  757. 'archivesIds': archivesIds
  758. }
  759. collectDel(params).then((res) => {
  760. if (res.includes('成功')) {
  761. localStorage.removeItem('currentPageSize')
  762. localStorage.removeItem('currentPage')
  763. this.$message({ message: '删除成功', type: 'success', offset: 8 })
  764. this.handleSearch(this.collectLevel)
  765. } else {
  766. this.$message({ message: res, type: 'error', offset: 8 })
  767. }
  768. }).catch(err => {
  769. console.log(err)
  770. })
  771. }
  772. },
  773. // 卷内 - 移出 确认
  774. handleMoveConfirm() {
  775. const archivesIds = []
  776. this.selections.forEach(val => {
  777. archivesIds.push(val.id)
  778. })
  779. const params = {
  780. 'categoryId': this.selectedCategory.id,
  781. 'categoryLevel': this.collectLevel,
  782. 'archivesIds': archivesIds,
  783. 'parentsId': this.parentsData.parentsAnjuanId
  784. }
  785. FetchRemoveArchivesSingle(params).then((res) => {
  786. if (res === true) {
  787. localStorage.removeItem('currentPageSize')
  788. localStorage.removeItem('currentPage')
  789. this.$message({ message: '移出成功', type: 'success', offset: 8 })
  790. this.handleSearch(this.collectLevel)
  791. } else {
  792. this.$message({ message: '移出失败', type: 'error', offset: 8 })
  793. }
  794. this.moveVisible = false
  795. }).catch(err => {
  796. console.log(err)
  797. })
  798. },
  799. // 原文上传
  800. fileUpload(uploadType) {
  801. if (uploadType !== 2) {
  802. if (this.isTitleType !== 6) {
  803. if (this.selections.length === 0) {
  804. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  805. return false
  806. }
  807. if (this.selections.length > 1) {
  808. this.$message({ message: '上传操作只可勾选唯一目标条目,请先确认!', offset: 8 })
  809. return false
  810. }
  811. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  812. if (isHasFillFormal) {
  813. this.$message({ message: '您所选的条目有正在归档流程中,不可操作原文上传,请先确认!', offset: 8 })
  814. return false
  815. }
  816. this.arcId = this.selections[0].id
  817. } else {
  818. if (this.parentsData.parentsAnjuanRow && this.parentsData.parentsAnjuanRow.collect_formal === 2) {
  819. this.$message({ message: '当前档案处于归档流程中,不可操作原文上传,请先确认!', offset: 8 })
  820. return false
  821. }
  822. if (this.selectedCategory.arrangeType === 1) {
  823. this.arcId = this.parentsData.parentsAnjuanId
  824. } else {
  825. if (this.parentsData.isTabFile) {
  826. this.arcId = this.parentsData.parentsAnjuanId
  827. } else {
  828. this.arcId = this.parentsData.parentsJuanneiId
  829. }
  830. }
  831. }
  832. }
  833. if (uploadType === 0) {
  834. this.$refs.uploadOriginalRef.uploadTitle = '普通上传'
  835. this.$refs.uploadOriginalRef.uploadVisible = true
  836. } else if (uploadType === 1) {
  837. this.$refs.uploadBigRef.uploadBigVisible = true
  838. } else if (uploadType === 2) {
  839. this.$refs.uploadOriginalRef.uploadTitle = '原文目录上传'
  840. this.$refs.uploadOriginalRef.uploadVisible = true
  841. }
  842. if (this.$refs.uploadOriginalRef.uploadVisible) {
  843. this.$refs.uploadOriginalRef.uploadType = uploadType
  844. this.$refs.uploadOriginalRef.fileList = []
  845. }
  846. },
  847. // 批量导入
  848. handleBlukImport() {
  849. if (this.parentsData.parentsAnjuanRow && this.parentsData.parentsAnjuanRow.collect_formal === 2) {
  850. this.$message({ message: '当前档案处于归档流程中,不可操作批量导入,请先确认!', offset: 8 })
  851. return false
  852. }
  853. this.$nextTick(() => {
  854. this.$refs.blukImportRef.bulkImportVisible = true
  855. this.$refs.blukImportRef.getInitCategoryInputFieldByPid()
  856. })
  857. },
  858. // 批量修改
  859. handleBlukEditing() {
  860. if (this.selections.length === 0) {
  861. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  862. return false
  863. }
  864. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  865. if (isHasFillFormal) {
  866. this.$message({ message: '您所选的条目有正在归档流程中,不可操作批量修改,请先确认!', offset: 8 })
  867. return false
  868. }
  869. this.$nextTick(() => {
  870. this.$refs.blukEditingRef.bulkEditingVisible = true
  871. this.$refs.blukEditingRef.getInitCategoryInputFieldByPid()
  872. })
  873. },
  874. // 案卷/文件/卷内顺序调整
  875. handleJnSeqAdjustment(type) {
  876. if (type === 'juannei') {
  877. if (this.selections.length === 0) {
  878. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  879. return false
  880. }
  881. if (this.selections.length > 1) {
  882. this.$message({ message: '卷内顺序调整操作只可勾选唯一目标条目,请先确认!', offset: 8 })
  883. return false
  884. }
  885. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  886. if (isHasFillFormal) {
  887. this.$message({ message: '您所选的条目有正在归档流程中,不可操作卷内顺序调整,请先确认!', offset: 8 })
  888. return false
  889. }
  890. this.$nextTick(() => {
  891. this.$refs.fileSeqAdjustmentRef.titleAdjustment = '卷内顺序调整'
  892. this.$refs.fileSeqAdjustmentRef.isJuannei = true
  893. })
  894. } else {
  895. if (this.selections.length < 2) {
  896. this.$message({ message: '请选择多个' + (type === 'file' ? '文件' : '案卷') + '后进行操作!', offset: 8 })
  897. return false
  898. }
  899. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  900. if (isHasFillFormal) {
  901. this.$message({ message: '您所选的条目有正在归档流程中,不可操作案卷/文件顺序调整,请先确认!', offset: 8 })
  902. return false
  903. }
  904. this.$nextTick(() => {
  905. if (type === 'anjuan') {
  906. this.$refs.fileSeqAdjustmentRef.titleAdjustment = '案卷顺序调整'
  907. } else {
  908. this.$refs.fileSeqAdjustmentRef.titleAdjustment = '文件顺序调整'
  909. }
  910. this.$refs.fileSeqAdjustmentRef.isJuannei = false
  911. })
  912. }
  913. this.$nextTick(() => {
  914. this.$refs.fileSeqAdjustmentRef.getDoArchivesAdjust()
  915. })
  916. },
  917. // 档号更新
  918. handleFileNumberUpdate(type) {
  919. if (this.selections.length === 0) {
  920. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  921. return false
  922. }
  923. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  924. if (isHasFillFormal) {
  925. this.$message({ message: '您所选的条目有正在归档流程中,不可操作档号更新,请先确认!', offset: 8 })
  926. return false
  927. }
  928. this.$confirm('此操作将会自动重新生成档号' + '<span>你是否还要继续?</span>', '提示', {
  929. confirmButtonText: '继续',
  930. cancelButtonText: '取消',
  931. type: 'warning',
  932. dangerouslyUseHTMLString: true
  933. }).then(() => {
  934. // updateType 更新类别 1.档号更新 2.卷内档号更新
  935. let updateType
  936. if (type === 0) {
  937. updateType = 1
  938. } else {
  939. updateType = 2
  940. }
  941. const archivesIds = []
  942. this.selections.forEach(val => {
  943. archivesIds.push(val.id)
  944. })
  945. const params = {
  946. 'categoryId': this.selectedCategory.id,
  947. 'categoryLevel': this.collectLevel,
  948. 'archivesIds': archivesIds,
  949. 'updateType': updateType
  950. }
  951. FetchUpdateArchivesNo(params).then((res) => {
  952. if (res.code !== 500) {
  953. this.$message({ message: '档号更新成功', type: 'success', offset: 8 })
  954. this.handleSearch(this.collectLevel)
  955. } else {
  956. this.$message({ message: res.message, type: 'error', offset: 8 })
  957. }
  958. }).catch(err => {
  959. console.log(err)
  960. })
  961. }).catch(() => {
  962. })
  963. },
  964. // 拆卷
  965. handleUncoil() {
  966. if (this.selections.length === 0) {
  967. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  968. return false
  969. }
  970. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  971. if (isHasFillFormal) {
  972. this.$message({ message: '您所选的条目有正在归档流程中,不可操作拆卷,请先确认!', offset: 8 })
  973. return false
  974. }
  975. this.$confirm('拆卷之后,对应的案卷数据将会自动删除' + '<span>你是否还要继续?</span>', '提示', {
  976. confirmButtonText: '继续',
  977. cancelButtonText: '取消',
  978. type: 'warning',
  979. dangerouslyUseHTMLString: true
  980. }).then(() => {
  981. const archivesIds = []
  982. this.selections.forEach(val => {
  983. archivesIds.push(val.id)
  984. })
  985. const params = {
  986. 'categoryId': this.selectedCategory.id,
  987. 'archivesIds': archivesIds
  988. }
  989. FetchDisbandArchives(params).then((res) => {
  990. if (res.code !== 500) {
  991. this.$message({ message: '拆卷成功', type: 'success', offset: 8 })
  992. this.handleSearch(this.collectLevel)
  993. } else {
  994. this.$message({ message: '拆卷失败', type: 'error', offset: 8 })
  995. }
  996. }).catch(err => {
  997. console.log(err)
  998. })
  999. }).catch(() => {
  1000. })
  1001. },
  1002. // 合卷
  1003. handleCombineFile() {
  1004. if (this.selections.length < 2) {
  1005. this.$message({ message: '合卷操作至少勾选2个案卷,请重试!', offset: 8 })
  1006. return false
  1007. }
  1008. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  1009. if (isHasFillFormal) {
  1010. this.$message({ message: '您所选的条目有正在归档流程中,不可操作合卷,请先确认!', offset: 8 })
  1011. return false
  1012. }
  1013. this.$refs.combineFileRef.getTargetList()
  1014. },
  1015. // 插件
  1016. handleInsertFile() {
  1017. if (this.collectLevel === 3) {
  1018. if (this.selections.length === 0) {
  1019. this.$confirm('您未勾选条目,否则直接选择所有条目' + '<span>你是否还要继续?</span>', '提示', {
  1020. confirmButtonText: '继续',
  1021. cancelButtonText: '取消',
  1022. type: 'warning',
  1023. dangerouslyUseHTMLString: true
  1024. }).then(() => {
  1025. this.$refs.insertFileRef.fileNoSelectionData = this.parentsData.$refs.anjuanEle.$refs.ajContent.$refs.tableList.anjuanData
  1026. this.$refs.insertFileRef.getInsertViewTable()
  1027. }).catch(() => {
  1028. })
  1029. } else {
  1030. this.$refs.insertFileRef.getInsertViewTable()
  1031. }
  1032. } else {
  1033. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  1034. if (this.selections.length !== 1) {
  1035. this.$message({ message: '插卷操作只可勾选唯一目标条目,请先确认!', offset: 8 })
  1036. return false
  1037. } else if (isHasFillFormal) {
  1038. this.$message({ message: '您所选的条目有正在归档流程中,不可操作插件,请先确认!', offset: 8 })
  1039. return false
  1040. } else {
  1041. this.$refs.insertFileRef.getInsertViewTable()
  1042. }
  1043. }
  1044. },
  1045. // 移动
  1046. handleCollectMoveFile() {
  1047. if (this.selections.length === 0) {
  1048. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1049. return false
  1050. }
  1051. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  1052. if (isHasFillFormal) {
  1053. this.$message({ message: '您所选的条目有正在归档流程中,不可操作移动,请先确认!', offset: 8 })
  1054. return false
  1055. }
  1056. this.$refs.collectMoveFileRef.collectMoveFileVisible = true
  1057. },
  1058. // 归档
  1059. handleFiling() {
  1060. if (this.selections.length === 0) {
  1061. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1062. return false
  1063. }
  1064. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  1065. if (isHasFillFormal) {
  1066. this.$message({ message: '您所选的条目有正在归档流程中,勿重复操作,请先确认!!', offset: 8 })
  1067. return false
  1068. }
  1069. this.$refs.archivesFillingRef.archivesFillingVisible = true
  1070. },
  1071. handleFillingToFourTest(resultList) {
  1072. this.$refs.fourTestRef.fourTestVisible = true
  1073. this.$refs.fourTestRef.tableData = this.selections
  1074. this.$refs.fourTestRef.updateTableData(resultList, this.selections)
  1075. this.$refs.fourTestRef.isCheck = true
  1076. },
  1077. // 退回预归档库
  1078. handleReturn() {
  1079. if (this.selections.length === 0) {
  1080. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1081. return false
  1082. }
  1083. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  1084. if (isHasFillFormal) {
  1085. this.$message({ message: '您所选的条目有正在归档流程中,不可操作退回预归档库,请先确认!!', offset: 8 })
  1086. return false
  1087. }
  1088. this.$confirm('此操作将把会所选条目退回到预归档库' + '<span>你是否还要继续?</span>', '提示', {
  1089. confirmButtonText: '继续',
  1090. cancelButtonText: '取消',
  1091. type: 'warning',
  1092. dangerouslyUseHTMLString: true
  1093. }).then(() => {
  1094. const archivesIds = this.selections.map(item => item.id)
  1095. const params = {
  1096. 'categoryId': this.selectedCategory.id,
  1097. 'archivesIds': archivesIds
  1098. }
  1099. FetchReturnReDocument(params).then((res) => {
  1100. if (res.code !== 500) {
  1101. if (res === 0) {
  1102. this.crud.notify('', CRUD.NOTIFICATION_TYPE.INFO)
  1103. this.$message({ message: '当前数据中不包含预归档数据,无法返回', offset: 8 })
  1104. } else {
  1105. this.$message({ message: '已成功返回' + res + '条来自预归档的数据', type: 'success', offset: 8 })
  1106. }
  1107. this.handleSearch(this.collectLevel)
  1108. } else {
  1109. this.$message({ message: res.message, type: 'error', offset: 8 })
  1110. }
  1111. }).catch(err => {
  1112. console.log(err)
  1113. })
  1114. }).catch(() => {
  1115. })
  1116. },
  1117. // 导出
  1118. handleExport() {
  1119. if (this.selections.length === 0) {
  1120. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1121. return false
  1122. }
  1123. this.$confirm('此操作将导出所选数据' + '<span>你是否还要继续?</span>', '提示', {
  1124. confirmButtonText: '继续',
  1125. cancelButtonText: '取消',
  1126. type: 'warning',
  1127. dangerouslyUseHTMLString: true
  1128. }).then(() => {
  1129. const archivesIds = []
  1130. this.selections.forEach(val => {
  1131. archivesIds.push(val.id)
  1132. })
  1133. const params = {
  1134. 'categoryId': this.selectedCategory.id,
  1135. 'categoryLevel': this.collectLevel,
  1136. 'archivesIds': archivesIds
  1137. }
  1138. exportFile(this.baseApi + '/api/collect/exportDate?' + qs.stringify(params, { indices: false }))
  1139. }).catch(() => {
  1140. })
  1141. },
  1142. // 打印
  1143. handlePrint() {
  1144. if (this.selections.length === 0) {
  1145. this.$refs.printRef.form.printRange = '当页条目'
  1146. let currentTableData = []
  1147. if (this.collectLevel === 2) {
  1148. currentTableData = this.parentsData.$refs.anjuanEle.$refs.ajContent.$refs.tableList.anjuanData
  1149. } else if (this.collectLevel === 3) {
  1150. if (this.isTitleType === 3) {
  1151. currentTableData = this.parentsData.$refs.anjuanEle.$refs.ajContent.$refs.tableList.anjuanData
  1152. } else {
  1153. currentTableData = this.parentsData.$refs.juanneiEle.junneiData
  1154. }
  1155. }
  1156. this.$refs.printRef.currentTable = JSON.parse(JSON.stringify(currentTableData))
  1157. } else {
  1158. this.$refs.printRef.form.printRange = '勾选条目'
  1159. }
  1160. this.$refs.printRef.printVisible = true
  1161. },
  1162. // 四性检测
  1163. handleFourTest() {
  1164. if (this.selections.length === 0) {
  1165. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1166. return false
  1167. }
  1168. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  1169. if (isHasFillFormal) {
  1170. this.$message({ message: '您所选的条目有正在归档流程中,不可操作四性检测,请先确认!', offset: 8 })
  1171. return false
  1172. }
  1173. this.$refs.fourTestRef.fourTestVisible = true
  1174. this.selections.forEach((item, index) => {
  1175. this.$set(this.selections[index], 'reportResult', {})
  1176. })
  1177. this.$refs.fourTestRef.tableData = this.selections
  1178. },
  1179. // 目录下载
  1180. handleCatalogDownload() {
  1181. if (this.selections.length === 0) {
  1182. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1183. return false
  1184. }
  1185. this.$confirm('此操作将下载所选条目目录' + '<span>你是否还要继续?</span>', '提示', {
  1186. confirmButtonText: '继续',
  1187. cancelButtonText: '取消',
  1188. type: 'warning',
  1189. dangerouslyUseHTMLString: true
  1190. }).then(() => {
  1191. const archivesIds = []
  1192. this.selections.forEach(val => {
  1193. archivesIds.push(val.id)
  1194. })
  1195. const params = {
  1196. 'categoryId': this.selectedCategory.id,
  1197. 'categoryLevel': this.collectLevel,
  1198. 'archivesIds': archivesIds
  1199. }
  1200. exportFile(this.baseApi + '/api/collect/catalogDownload?' + qs.stringify(params, { indices: false }))
  1201. }).catch(() => {
  1202. })
  1203. },
  1204. // 快速组卷
  1205. handleQuickPaper() {
  1206. this.$refs.quickPaperRef.quickVisible = true
  1207. },
  1208. // 手工组卷
  1209. handlePaper() {
  1210. if (this.selections.length === 0) {
  1211. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1212. return false
  1213. }
  1214. this.quickPaperArcId = this.selections.map(item => item.id)
  1215. this.handleForm('add', 1)
  1216. },
  1217. // 装盒 / 分卷装盒
  1218. handlePackingBox(type) {
  1219. if (this.selections.length === 0) {
  1220. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1221. return false
  1222. }
  1223. const isHasFillFormal = this.selections.some(item => item.collect_formal === 2)
  1224. if (isHasFillFormal) {
  1225. this.$message({ message: '您所选的条目有正在归档流程中,不可操作装盒,请先确认!!', offset: 8 })
  1226. return false
  1227. }
  1228. if (this.selectedCategory.arrangeType === 2) {
  1229. if (type === 1) {
  1230. if (this.selections.length > 1) {
  1231. this.$message({ message: '只可勾选唯一目标条目,请先确认!', offset: 8 })
  1232. return false
  1233. }
  1234. }
  1235. if (this.selections[0].child === 0) {
  1236. this.$message({ message: '当前选中的档案无相关卷内文件,不可装盒!', type: 'error', offset: 8 })
  1237. return
  1238. }
  1239. }
  1240. if (this.selections[0].case_no) {
  1241. this.$message({ message: '当前档案已装盒,请勿重复操作!', type: 'error', offset: 8 })
  1242. return
  1243. }
  1244. // 后面与后端对接确定字段name
  1245. // const existsNotEmpty = this.selections.some(item => item.caseNum)
  1246. // if (existsNotEmpty) {
  1247. // this.$message('所选条目中存在已装盒档案,请勿重复操作!')
  1248. // return false
  1249. // }
  1250. console.log('this.parentsData', this.parentsData)
  1251. console.log('this.parentsData.listCategory', this.parentsData.listCategory.id)
  1252. this.$refs.packingBox.packingVisible = true
  1253. this.$refs.packingBox.isPackingOrPartType = type
  1254. this.$refs.packingBox.packFileCategory = this.parentsData.listCategory
  1255. if (type === 0) {
  1256. this.$refs.packingBox.packingTitle = '装盒'
  1257. } else {
  1258. this.$refs.packingBox.packingTitle = '分卷装盒'
  1259. this.$refs.packingBox.getViewTable()
  1260. }
  1261. this.getTotalSumAll()
  1262. },
  1263. getTotalSumAll() {
  1264. this.totalSumAll = 0
  1265. this.selections.map((item) => { if (!isNaN(item.child)) this.totalSumAll += item.child })
  1266. if (isNaN(this.totalSumAll)) {
  1267. return 0
  1268. }
  1269. return this.totalSumAll
  1270. },
  1271. // 原文内的附件下载
  1272. handleOriginalDownload() {
  1273. if (this.selections.length > 1 || this.selections.length === 0) {
  1274. this.$message({ message: '下载操作只可勾选唯一目标条目,请先确认!', offset: 8 })
  1275. return false
  1276. }
  1277. const url = this.baseApi + '/downloadFile' + this.selections[0].file_path
  1278. fetch(url).then(res => res.blob()).then(blob => {
  1279. downloadFile(blob, this.selections[0].file_name.split('.')[0], this.selections[0].file_type)
  1280. }).catch(() => {
  1281. this.$message({ message: '下载文件失败!', type: 'error', offset: 8 })
  1282. })
  1283. },
  1284. // 回收站 - 恢复
  1285. toRecover() {
  1286. if (this.selections.length === 0) {
  1287. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1288. return false
  1289. }
  1290. this.$confirm('此恢复将会把所选条目及其子集一并恢复' + '<span>你是否还要继续?</span>', '提示', {
  1291. confirmButtonText: '继续',
  1292. cancelButtonText: '取消',
  1293. type: 'warning',
  1294. dangerouslyUseHTMLString: true
  1295. }).then(() => {
  1296. const archivesIds = []
  1297. this.selections.forEach(val => {
  1298. archivesIds.push(val.id)
  1299. })
  1300. const params = {
  1301. 'categoryId': this.selectedCategory.id,
  1302. 'categoryLevel': this.collectLevel,
  1303. 'archivesIds': archivesIds,
  1304. 'collectFormal': this.isTitleType === 2 ? 1 : null
  1305. }
  1306. FetchRestoreArchives(params).then((res) => {
  1307. if (res.code !== 500) {
  1308. localStorage.removeItem('currentPageSize')
  1309. localStorage.removeItem('currentPage')
  1310. if (res.includes('成功')) {
  1311. this.$message({ message: res, type: 'success', offset: 8 })
  1312. } else {
  1313. this.$message({ message: res, type: 'error', offset: 8 })
  1314. }
  1315. this.handleSearch(this.collectLevel)
  1316. } else {
  1317. this.$message({ message: '恢复所选档案失败', type: 'error', offset: 8 })
  1318. }
  1319. }).catch(err => {
  1320. console.log(err)
  1321. })
  1322. }).catch(() => {
  1323. })
  1324. },
  1325. // 回收站 - 彻底删除
  1326. toCompletelyDelete() {
  1327. if (this.selections.length === 0) {
  1328. this.$message({ message: '您还未勾选需要操作的条目,请先确认!', offset: 8 })
  1329. return false
  1330. }
  1331. this.$confirm('此删除将把会所选条目与其子集彻底删除' + '<span>你是否还要继续?</span>', '提示', {
  1332. confirmButtonText: '继续',
  1333. cancelButtonText: '取消',
  1334. type: 'warning',
  1335. dangerouslyUseHTMLString: true
  1336. }).then(() => {
  1337. const archivesIds = []
  1338. this.selections.forEach(val => {
  1339. archivesIds.push(val.id)
  1340. })
  1341. const params = {
  1342. 'categoryId': this.selectedCategory.id,
  1343. 'categoryLevel': this.collectLevel,
  1344. 'archivesIds': archivesIds
  1345. }
  1346. FetchCompleteDelArchives(params).then((res) => {
  1347. if (res.code !== 500) {
  1348. this.$message({ message: res, type: 'success', offset: 8 })
  1349. this.handleSearch(this.collectLevel)
  1350. } else {
  1351. this.$message({ message: '删除所选档案失败', type: 'error', offset: 8 })
  1352. }
  1353. }).catch(err => {
  1354. console.log(err)
  1355. })
  1356. }).catch(() => {
  1357. })
  1358. },
  1359. closeDialog(data) {
  1360. this.formVisible = false
  1361. this.quickPaper = false
  1362. setTimeout(() => {
  1363. this.handleSearch(this.collectLevel)
  1364. })
  1365. },
  1366. handleAiCategory() {
  1367. this.aIAssistEnterVisible = true
  1368. this.aiCategoryloading = true
  1369. const params = {
  1370. 'page': 0,
  1371. 'size': 10,
  1372. 'isHandle': 0
  1373. }
  1374. FetchInitAssistEnter(params).then(data => {
  1375. this.aiCategoryData = data
  1376. this.aiCategoryloading = false
  1377. setTimeout(() => {
  1378. this.getDoHandleEnterAnalysis()
  1379. }, 1000)
  1380. })
  1381. },
  1382. // 获取自动分析内容和提问
  1383. getDoHandleEnterAnalysis(row) {
  1384. this.isAiAutoCategory = true
  1385. this.aIAssistEnterVisible = false
  1386. const params = {
  1387. 'categoryId': this.selectedCategory.id,
  1388. 'anId': null
  1389. }
  1390. FetchDoHandleEnterAnalysis(params).then(data => {
  1391. console.log(data)
  1392. // const inputMessage = data.query + '需要提取得内容部分是' + data.context
  1393. this.sendMessage(data.query, data.context)
  1394. })
  1395. },
  1396. // 向deepseek发出提问和分析内容
  1397. async sendMessage(prompt, context) {
  1398. const linkSrc = process.env.NODE_ENV === 'production' ? window.g.AIDeepSeekUrl : process.env.VUE_APP_AIDEEPSEEK_API
  1399. this.displayedText = ''
  1400. this.isDialogClosed = false // 重置标志位
  1401. try {
  1402. // { 'role': 'system', 'content': '你是一个数据分析助手' },
  1403. const messages = [
  1404. { 'role': 'user', 'content': `${context}\n\n${prompt}` }
  1405. ]
  1406. const response = await fetch(linkSrc + '/api/generate', {
  1407. method: 'POST',
  1408. headers: {
  1409. 'Content-Type': 'application/json'
  1410. },
  1411. body: JSON.stringify({
  1412. model: 'deepseek-r1:14b',
  1413. // model: 'qwen:7b',
  1414. prompt: messages[0].content,
  1415. stream: true
  1416. })
  1417. })
  1418. if (!response.ok) {
  1419. throw new Error(`HTTP error! status: ${response.status}`)
  1420. }
  1421. this.reader = response.body.getReader() // 存储读取器
  1422. const decoder = new TextDecoder('utf-8')
  1423. let done = false
  1424. while (!done && !this.isDialogClosed) { // 检查标志位
  1425. this.aiResultCaLoading = false
  1426. const { done: isDone, value } = await this.reader.read()
  1427. done = isDone
  1428. if (done) break
  1429. const chunk = decoder.decode(value)
  1430. const lines = chunk.split('\n')
  1431. lines.forEach(line => {
  1432. if (line.trim() !== '') {
  1433. try {
  1434. const data = JSON.parse(line)
  1435. if (data.response && !this.isDialogClosed) { // 再次检查标志位
  1436. this.displayedText += data.response
  1437. }
  1438. } catch (error) {
  1439. console.error('解析JSON数据出错:', error)
  1440. }
  1441. }
  1442. })
  1443. // 滚动条始终保持在底部
  1444. const container = this.$refs.typingContainer
  1445. if (container) {
  1446. container.scrollTop = container.scrollHeight
  1447. }
  1448. }
  1449. } catch (error) {
  1450. console.error('请求出错:', error)
  1451. this.displayedText = '请求出错,请稍后再试。'
  1452. this.aiResultCaLoading = false
  1453. } finally {
  1454. this.aiResultCaLoading = false
  1455. if (!this.isDialogClosed) {
  1456. console.log('this.displayedText.', this.displayedText)
  1457. // 去除 <think> 和 </think> 之间的内容
  1458. const thinkStartIndex = this.displayedText.indexOf('<think>')
  1459. const thinkEndIndex = this.displayedText.indexOf('</think>')
  1460. let lastContent = this.displayedText
  1461. if (thinkStartIndex !== -1 && thinkEndIndex !== -1) {
  1462. lastContent = lastContent.slice(0, thinkStartIndex) + lastContent.slice(thinkEndIndex + '</think>'.length)
  1463. }
  1464. console.log('lastContent', lastContent)
  1465. // 提取 JSON 部分
  1466. const startIndex = lastContent.indexOf('{')
  1467. const endIndex = lastContent.lastIndexOf('}')
  1468. if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
  1469. const jsonStr = lastContent.slice(startIndex, endIndex + 1)
  1470. console.log('jsonStr', jsonStr)
  1471. const jsonData = JSON.parse(jsonStr)
  1472. console.log('提取并过滤后的 JSON 数据:', jsonData)
  1473. console.log('this.selectedCategory', this.selectedCategory)
  1474. jsonData.fonds_no = this.selectedCategory.fondsNo
  1475. jsonData.archival_category_code = this.selectedCategory.code
  1476. jsonData.is_entity = 1
  1477. console.log('jsonData', jsonData)
  1478. this.$refs.previewForm.addOrUpdateForm = jsonData
  1479. }
  1480. }
  1481. this.reader = null // 清空读取器
  1482. }
  1483. },
  1484. replaceSeparators(str) {
  1485. return str.replace(/[,,、]/g, ' ')
  1486. }
  1487. }
  1488. }
  1489. </script>
  1490. <style lang='scss' scoped>
  1491. ::v-deep .vue-treeselect__list-item{
  1492. width: 220px;
  1493. }
  1494. ::v-deep .vue-treeselect__menu {
  1495. padding: 20px 0;
  1496. }
  1497. ::v-deep .vue-treeselect__option--highlight{
  1498. background: #f5f9fc !important;
  1499. color: #0348f3 !important;
  1500. }
  1501. ::v-deep .vue-treeselect__option-arrow-container .vue-treeselect__option-arrow{
  1502. color: #1c1c1c !important;
  1503. }
  1504. ::v-deep .vue-treeselect__placeholder{
  1505. font-size: 14px;
  1506. }
  1507. ::v-deep .vue-treeselect__label-container{
  1508. font-size: 14px;
  1509. height: 34px;
  1510. line-height: 34px;
  1511. color: #1c1c1c;
  1512. }
  1513. ::v-deep .vue-treeselect__option.vue-treeselect__option--disabled{
  1514. .vue-treeselect__label-container{
  1515. color: #545b65 !important;
  1516. }
  1517. }
  1518. ::v-deep.vue-treeselect--has-value .vue-treeselect__single-value{
  1519. font-size: 14px;
  1520. }
  1521. .ai-preview-dialog{
  1522. ::v-deep .el-dialog{
  1523. width: 1300px !important;
  1524. .preview-content{
  1525. width: 728px !important;
  1526. }
  1527. }
  1528. }
  1529. .aiAssist-dialog{
  1530. ::v-deep .el-dialog{
  1531. width: 1000px !important;
  1532. }
  1533. }
  1534. pre {
  1535. background-color: #f4f4f4;
  1536. padding: 10px;
  1537. border: 1px solid #ccc;
  1538. border-radius: 4px;
  1539. white-space: pre-wrap;
  1540. word-wrap: break-word;
  1541. height: calc(100vh - 330px);
  1542. overflow: hidden;
  1543. overflow-y: auto;
  1544. }
  1545. </style>