阅行客电子档案
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.

390 lines
12 KiB

2 years ago
2 years ago
4 months ago
4 months ago
2 years ago
2 years ago
4 months ago
4 months ago
4 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
1 month 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
  1. <template>
  2. <el-dialog class="detail-dialog" title="详情" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="archivesInfoVisible" :before-close="handleClose">
  3. <!-- <span class="dialog-right-top" />
  4. <span class="dialog-left-bottom" /> -->
  5. <div class="setting-dialog">
  6. <div class="detail-tab tab-content">
  7. <!-- tab -->
  8. <ul class="tab-nav">
  9. <li :class="{'active-tab-nav': archivesTabIndex == 0}" @click="changeActiveTab(0)">基本信息</li>
  10. <li :class="{'active-tab-nav': archivesTabIndex == 1}" @click="changeActiveTab(1)">电子原件</li>
  11. <li :class="{'active-tab-nav': archivesTabIndex == 2}" @click="changeActiveTab(2)">元数据</li>
  12. </ul>
  13. <!-- 基本信息 -->
  14. <div v-if="archivesTabIndex===0" class="base-info item-content">
  15. <el-row>
  16. <el-col v-for="(item,index) in archivesDetailsData" :key="index" :span="item.isLine ? 24 : 12" class="base-info-item">
  17. <span>{{ item.fieldCnName }}</span>
  18. <p :style="{ width: ( item.editLength ? item.editLength+'px' : '' ), flex: ( !item.editLength ? 1 : '' )}">{{ item.context }}</p>
  19. </el-col>
  20. </el-row>
  21. </div>
  22. <!-- 电子原件 -->
  23. <div v-if="archivesTabIndex===1" class="item-content">
  24. <el-table
  25. ref="table"
  26. :data="tableData"
  27. style="min-width: 100%"
  28. height="calc(100vh - 382px)"
  29. @row-click="clickRowHandler"
  30. @selection-change="selectionChangeHandler"
  31. >
  32. <el-table-column prop="file_name" label="文件名称" show-overflow-tooltip min-width="140" align="center" />
  33. <el-table-column prop="file_type" label="格式" min-width="60" align="center" />
  34. <el-table-column prop="file_size" label="大小" min-width="85" align="right">
  35. <template slot-scope="scope">
  36. {{ getFileSize(scope.row.file_size) }}
  37. </template>
  38. </el-table-column>
  39. <!-- <el-table-column prop="file_dpi" label="分辨率" min-width="85" align="center">
  40. <template slot-scope="scope">
  41. <div v-if="!scope.row.file_dpi || scope.row.file_dpi === 'null'"> - </div>
  42. <div v-else> {{ scope.row.file_dpi }} </div>
  43. </template>
  44. </el-table-column> -->
  45. <el-table-column prop="file_thumbnail" label="缩略图" min-width="60" align="center">
  46. <template slot-scope="scope">
  47. <div :class="getFileIconClass(scope.row.file_type)">
  48. <i class="fileIcon" :class="getFileIconClass(scope.row.file_type)" />
  49. </div>
  50. </template>
  51. </el-table-column>
  52. <el-table-column label="操作" min-width="80" align="center">
  53. <template slot-scope="scope">
  54. <div class="handle-btn">
  55. <el-button class="iconfont icon-sulan" @click="toPreview(scope.row)" />
  56. <!-- <el-button class="iconfont icon-xiazai" @click="downloadFile(scope.row)" /> -->
  57. <!-- <el-button class="iconfont icon-dayin" /> -->
  58. </div>
  59. </template>
  60. </el-table-column>
  61. </el-table>
  62. </div>
  63. <!-- 元数据 -->
  64. <div v-if="archivesTabIndex==2" class="metadata-cont item-content">
  65. <pre v-highlightjs="xml_show">
  66. <code class="highlight_s">
  67. {[xml_show]}
  68. </code>
  69. </pre>
  70. </div>
  71. <!-- 点击缩略图看大图 -->
  72. <el-dialog class="preview-dialog" :append-to-body="true" :close-on-click-modal="false" :before-close="handleClose" :visible="showCoverVisible" title="查看大图">
  73. <span class="dialog-right-top" />
  74. <span class="dialog-left-bottom" />
  75. <div class="setting-dialog" style="max-height:calc(100vh - 230px); overflow:auto;">
  76. <img style="max-width:100%; object-fit: contain;" :src="previewSrc" :onerror="defaultImg">
  77. </div>
  78. </el-dialog>
  79. </div>
  80. </div>
  81. </el-dialog>
  82. </template>
  83. <script>
  84. import { form } from '@crud/crud'
  85. import { FetchArchivesDetails, FetchFileListByDocumentId, FetchArchivesMetadata } from '@/api/prearchiveLibrary/prearchiveLibrary'
  86. import { mapGetters } from 'vuex'
  87. import { downloadFile } from '@/utils/index'
  88. import { getToken } from '@/utils/auth'
  89. export default {
  90. name: 'PrearchiveLibraryDetail',
  91. components: { },
  92. mixins: [
  93. form({})
  94. ],
  95. props: {
  96. selectedDocument: {
  97. type: Object,
  98. default: function() {
  99. return {}
  100. }
  101. }
  102. },
  103. data() {
  104. return {
  105. defaultImg: 'this.src="' + require('@/assets/images/cover-bg.png') + '"',
  106. archivesInfoVisible: false,
  107. archivesTabIndex: 0,
  108. archivesDetailsData: [],
  109. archivesDetailsMetadata: [],
  110. xml_show: null,
  111. selections: [],
  112. tableData: [],
  113. showCoverVisible: false,
  114. previewSrc: '', // 查看大图src
  115. parentInfo: null
  116. }
  117. },
  118. computed: {
  119. ...mapGetters([
  120. 'baseApi'
  121. ])
  122. },
  123. created() {
  124. },
  125. mounted() {
  126. },
  127. methods: {
  128. getFileIconClass(fileType) {
  129. if (!fileType) return 'icon-other'
  130. const lowerFileType = fileType.toLowerCase()
  131. switch (lowerFileType) {
  132. case 'jpg':
  133. case 'jpeg':
  134. case 'png':
  135. case 'bmp':
  136. case 'gif':
  137. return 'icon-image'
  138. case 'xlsx':
  139. case 'xls':
  140. return 'icon-excel'
  141. case 'docx':
  142. case 'doc':
  143. return 'icon-word'
  144. case 'pdf':
  145. return 'icon-pdf'
  146. case 'ppt':
  147. case 'pptx':
  148. return 'icon-ppt'
  149. case 'zip':
  150. case 'rar':
  151. return 'icon-zip'
  152. case 'txt':
  153. return 'icon-txt'
  154. case 'ofd':
  155. return 'icon-ofd'
  156. // 其他未匹配的文件类型
  157. default:
  158. return 'icon-other'
  159. }
  160. },
  161. downloadFile(row) {
  162. // filePath 保存的文件路径
  163. // bucketType 1预归档 2档案
  164. const url = this.baseApi + '/api/minioUpload/getFile?filePath=' + row.file_path + '&bucketType=1'
  165. const fetchOptions = {
  166. method: 'GET',
  167. headers: {
  168. 'Authorization': getToken()
  169. }
  170. }
  171. fetch(url, fetchOptions).then(res => res.blob()).then(blob => {
  172. downloadFile(blob, row.file_name.split('.')[0], row.file_type)
  173. }).catch(() => {
  174. this.$message({ message: '下载文件失败', type: 'error', offset: 8 })
  175. })
  176. },
  177. toPreview(row) {
  178. const routeData = this.$router.resolve({
  179. path: '/preview',
  180. query: {
  181. 'archiveNo': this.parentInfo.maintitle
  182. }})
  183. window.open(routeData.href, '_blank')
  184. localStorage.setItem('documentId', JSON.stringify(this.selectedDocument.id))
  185. localStorage.setItem('fileParentInfo', JSON.stringify(this.parentInfo))
  186. localStorage.setItem('fileTables', JSON.stringify(this.tableData))
  187. localStorage.setItem('fileCurrent', JSON.stringify(row))
  188. },
  189. getFileSize(fileSize) {
  190. // 1. 先将接口返回的KB值转为数字,处理非数字/空值情况
  191. const sizeInKB = Number(fileSize)
  192. if (isNaN(sizeInKB) || sizeInKB < 0) {
  193. return '0 KB' // 异常值默认显示0 KB
  194. }
  195. // 2. 定义单位换算关系(1 MB = 1024 KB,1 GB = 1024 MB)
  196. const KB = 1
  197. const MB = 1024 * KB
  198. const GB = 1024 * MB
  199. // 3. 根据大小自动选择单位并格式化
  200. if (sizeInKB >= GB) {
  201. // 大于等于1GB,显示GB(保留2位小数)
  202. return (sizeInKB / GB).toFixed(2) + ' GB'
  203. } else if (sizeInKB >= MB) {
  204. // 大于等于1MB且小于1GB,显示MB(保留2位小数)
  205. return (sizeInKB / MB).toFixed(2) + ' MB'
  206. } else if (sizeInKB < 1) {
  207. // 不足1KB,统一显示1 KB(保持你之前的需求)
  208. return '1 KB'
  209. } else {
  210. // 1KB到1MB之间,显示KB(保留2位小数)
  211. return sizeInKB + ' KB'
  212. }
  213. },
  214. getDetial(rowId) {
  215. const params = {
  216. documentId: this.selectedDocument.id,
  217. archivesId: rowId
  218. }
  219. FetchArchivesDetails(params).then(data => {
  220. this.archivesDetailsData = data
  221. })
  222. FetchFileListByDocumentId(params).then(data => {
  223. this.tableData = data.returnlist
  224. })
  225. FetchArchivesMetadata(params).then(data => {
  226. this.archivesDetailsMetadata = data
  227. })
  228. },
  229. changeActiveTab(index) {
  230. this.archivesTabIndex = index
  231. if (this.archivesTabIndex === 2) {
  232. this.setXml()
  233. }
  234. },
  235. // table
  236. clickRowHandler(row) {
  237. this.$refs.table.toggleRowSelection(row)
  238. },
  239. // table
  240. selectionChangeHandler(val) {
  241. this.selections = val
  242. },
  243. // dialog - close
  244. handleClose(done) {
  245. this.showCoverVisible = false
  246. done()
  247. },
  248. // 查看大图
  249. showCoverPreview(row) {
  250. this.showCoverVisible = true
  251. this.previewSrc = this.baseApi + '/downloadFile' + row.file_path
  252. },
  253. setXml() {
  254. const xmlstr = this.archivesDetailsMetadata
  255. this.xml_show = this.showXml(xmlstr)
  256. },
  257. // xml格式化
  258. showXml(str) {
  259. var that = this
  260. var text = str
  261. // 去掉多余的空格
  262. text =
  263. '\n' +
  264. text
  265. .replace(/(<\w+)(\s.*?>)/g, function($0, name, props) {
  266. return name + ' ' + props.replace(/\s+(\w+=)/g, ' $1')
  267. })
  268. .replace(/>\s*?</g, '>\n<')
  269. // 把注释编码
  270. text = text
  271. .replace(/\n/g, '\r')
  272. .replace(/<!--(.+?)-->/g, function($0, text) {
  273. var ret = '<!--' + escape(text) + '-->'
  274. return ret
  275. })
  276. .replace(/\r/g, '\n')
  277. // 调整格式
  278. var rgx = /\n(<(([^\?]).+?)(?:\s|\s*?>|\s*?(\/)>)(?:.*?(?:(?:(\/)>)|(?:<(\/)\2>)))?)/gm
  279. var nodeStack = []
  280. var output = text.replace(rgx, function(
  281. $0,
  282. all,
  283. name,
  284. isBegin,
  285. isCloseFull1,
  286. isCloseFull2,
  287. isFull1,
  288. isFull2
  289. ) {
  290. var isClosed =
  291. isCloseFull1 === '/' ||
  292. isCloseFull2 === '/' ||
  293. isFull1 === '/' ||
  294. isFull2 === '/'
  295. var prefix = ''
  296. if (isBegin === '!') {
  297. prefix = that.getPrefix(nodeStack.length)
  298. } else {
  299. if (isBegin !== '/') {
  300. prefix = that.getPrefix(nodeStack.length)
  301. if (!isClosed) {
  302. nodeStack.push(name)
  303. }
  304. } else {
  305. nodeStack.pop()
  306. prefix = that.getPrefix(nodeStack.length)
  307. }
  308. }
  309. var ret = '\n' + prefix + all
  310. return ret
  311. })
  312. var outputText = output.substring(1)
  313. // 把注释还原并解码,调格式
  314. outputText = outputText
  315. .replace(/\n/g, '\r')
  316. .replace(/(\s*)<!--(.+?)-->/g, function($0, prefix, text) {
  317. if (prefix.charAt(0) === '\r') prefix = prefix.substring(1)
  318. text = unescape(text).replace(/\r/g, '\n')
  319. var ret =
  320. '\n' + prefix + '<!--' + text.replace(/^\s*/gm, prefix) + '-->'
  321. return ret
  322. })
  323. outputText = outputText.replace(/\s+$/g, '').replace(/\r/g, '\r\n')
  324. return outputText
  325. },
  326. getPrefix(prefixIndex) {
  327. var span = ' '
  328. var output = []
  329. for (var i = 0; i < prefixIndex; ++i) {
  330. output.push(span)
  331. }
  332. return output.join('')
  333. }
  334. }
  335. }
  336. </script>
  337. <style lang="scss" scoped>
  338. .base-info,
  339. .metadata-cont{
  340. background-color: #F6F8FC;
  341. }
  342. // 档案详情
  343. .base-info{
  344. padding: 20px 0;
  345. overflow: hidden;
  346. overflow-y: scroll;
  347. .base-info-item{
  348. display: flex;
  349. flex-direction: row;
  350. margin-bottom: 20px;
  351. color: #545B65;
  352. span{
  353. display: block;
  354. width: 160px;
  355. font-weight: bold;
  356. margin-right: 5px;
  357. text-align: right;
  358. color: #0C0E1E;
  359. }
  360. }
  361. }
  362. code.hljs {
  363. font-size: 12px;
  364. color: #0C0E1E !important;
  365. height: 530px !important;
  366. }
  367. ::v-deep .hljs-name{
  368. color: #0C0E1E !important;
  369. }
  370. .base-info .base-info-item span.el-tag{
  371. width: auto;
  372. color: #fff;
  373. }
  374. .svg-style{
  375. width: 60px;
  376. height: 32px;
  377. }
  378. </style>