experimental-data.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <template>
  2. <div class="info-container">
  3. <div class="experimental-data info-item">
  4. <div class="title">
  5. <i class="ibps-icon-star" />
  6. <span>实验数据</span>
  7. </div>
  8. <div class="operate">
  9. <template v-for="btn in toolbars">
  10. <el-button
  11. v-if="!btn.hidden"
  12. :key="btn.key"
  13. :type="btn.type"
  14. :icon="btn.icon"
  15. :size="btn.size || 'mini'"
  16. plain
  17. @click="handleActionEvent(btn.key)"
  18. >
  19. {{ btn.label }}
  20. </el-button>
  21. </template>
  22. </div>
  23. <div class="content">
  24. <template v-if="expData && $utils.isNotEmpty(expData.dataDTO)">
  25. <el-table
  26. :data="expData.dataDTO.list"
  27. border
  28. stripe
  29. highlight-current-row
  30. style="width: 100%"
  31. :max-height="pdf=='pdf'?'100%':'250px'"
  32. >
  33. <el-table-column
  34. v-for="(h, hIndex) in expData.dataDTO.header"
  35. :key="h.children && h.children.length ? hIndex : h.prop"
  36. :prop="h.prop"
  37. :label="h.label"
  38. width="80"
  39. header-align="center"
  40. align="center"
  41. >
  42. <template slot="header" slot-scope="scope">
  43. <span v-html="scope.column.label" />
  44. </template>
  45. <el-table-column
  46. v-for="c in h.children"
  47. :key="c.prop"
  48. :prop="c.prop"
  49. :label="c.label"
  50. header-align="center"
  51. align="center"
  52. >
  53. <template slot="header" slot-scope="scope">
  54. <span v-html="scope.column.label" />
  55. </template>
  56. </el-table-column>
  57. </el-table-column>
  58. </el-table>
  59. <div class="note" v-html="expData.dataDTO.note" />
  60. </template>
  61. <el-empty v-else description="暂无数据,请导出模板填写后导入" />
  62. </div>
  63. </div>
  64. <!-- <import-table
  65. :visible="showImportTable"
  66. title="导入"
  67. @close="visible => (showImportTable = visible)"
  68. @action-event="handleImport"
  69. /> -->
  70. </div>
  71. </template>
  72. <script>
  73. // import IbpsImport from '@/plugins/import'
  74. import ActionUtils from '@/utils/action'
  75. import { exportTemplate, importTemplate } from '@/api/business/pv'
  76. export default {
  77. components: {
  78. ImportTable: () => import('@/business/platform/form/formrender/dynamic-form/components/import-table')
  79. },
  80. props: {
  81. exp: {
  82. type: Object,
  83. default: () => {}
  84. },
  85. formId: {
  86. type: String,
  87. default: ''
  88. },
  89. readonly: {
  90. type: Boolean,
  91. default: false
  92. },
  93. pdf: {
  94. type: String,
  95. default: ''
  96. }
  97. },
  98. data () {
  99. return {
  100. expData: this.exp,
  101. showImportTable: false,
  102. toolbars: [
  103. { key: 'export', icon: 'ibps-icon-cloud-download', label: '导出模板', type: 'info', hidden: this.readonly },
  104. { key: 'import', icon: 'ibps-icon-cloud-upload', label: '导入数据', type: 'warning', hidden: this.readonly },
  105. { key: 'generate', icon: 'ibps-icon-file-text-o', label: '查看实验报告', type: 'success', hidden: true }
  106. ]
  107. }
  108. },
  109. watch: {
  110. exp: {
  111. handler (val) {
  112. this.expData = val
  113. },
  114. deep: true
  115. }
  116. },
  117. methods: {
  118. handleActionEvent (key) {
  119. switch (key) {
  120. case 'generate':
  121. this.handleGenerate()
  122. break
  123. case 'export':
  124. // this.handleExport()
  125. this.$emit('export')
  126. break
  127. case 'import':
  128. // this.showImportTable = true
  129. // this.handleImport()
  130. this.$emit('import')
  131. break
  132. }
  133. },
  134. handleGenerate () {
  135. this.$message.info('waiting...')
  136. },
  137. handleExport () {
  138. if (!this.formId) {
  139. return this.$message.error('请先保存数据!')
  140. }
  141. exportTemplate({ id: this.formId }).then(res => {
  142. ActionUtils.download(res.data, '实验数据模板.xlsx')
  143. })
  144. },
  145. objectSpanMethod ({ row, column, rowIndex, columnIndex }) {
  146. // 判断当前列是否需要进行同值合并
  147. if (column.merge) {
  148. const firstSameRowIndex = this.getFirstSameRowIndex(this.tableData, rowIndex, column.property)
  149. const firstSameColIndex = this.getFirstSameColIndex(this.tableData, columnIndex, rowIndex)
  150. return {
  151. rowspan: firstSameRowIndex === -1 ? 1 : rowIndex - firstSameRowIndex + 1,
  152. colspan: firstSameColIndex === -1 ? 1 : columnIndex - firstSameColIndex + 1
  153. }
  154. }
  155. },
  156. // 获取行同值合并的起始下标
  157. getFirstSameRowIndex (data, rowIndex, prop) {
  158. for (let i = rowIndex; i >= 0; i--) {
  159. if (data[i][prop] === data[rowIndex][prop]) {
  160. return i
  161. }
  162. }
  163. return -1
  164. },
  165. // 获取列同值合并的起始下标
  166. getFirstSameColIndex (data, colIndex, rowIndex) {
  167. for (let i = colIndex; i >= 0; i--) {
  168. if (data[rowIndex][i] === data[rowIndex][colIndex]) {
  169. return i
  170. }
  171. }
  172. return -1
  173. },
  174. // handleImport (file, options) {
  175. // this.loading = false
  176. // IbpsImport.xlsx(file, options).then(res => {
  177. // console.log(res)
  178. // })
  179. // },
  180. handleImport () {
  181. if (!this.formId) {
  182. return this.$message.error('请先保存数据!')
  183. }
  184. const input = document.createElement('input')
  185. input.type = 'file'
  186. input.accept = '.xlsx'
  187. input.onchange = event => {
  188. const file = event.target.files[0]
  189. const reader = new FileReader()
  190. reader.onload = event => {
  191. const data = new FormData()
  192. data.append('id', this.formId)
  193. data.append('applyFiles', file)
  194. importTemplate(data).then(res => {
  195. this.$message.success('实验数据导入成功')
  196. this.expData = res.data
  197. }).catch(({ state, cause }) => {
  198. const errMsg = JSON.parse(cause)
  199. let msgContent = ''
  200. Object.keys(errMsg).forEach(key => {
  201. let msgItem = '<div >'
  202. errMsg[key].forEach(item => {
  203. msgItem += `<div>${item}</div>`
  204. })
  205. msgContent += `<div><div style="font-weight: bold;">${key}:</div>${msgItem}<div>`
  206. })
  207. this.$confirm(`<div style="font-size: 14px;">${msgContent}</div>`, '数据校验失败,请根据以下提示完善您的数据!', {
  208. confirmButtonText: '确认',
  209. showClose: false,
  210. showCancelButton: false,
  211. closeOnClickModal: false,
  212. dangerouslyUseHTMLString: true,
  213. customClass: 'errorTips',
  214. type: 'error'
  215. }).then(() => {}).catch(() => {})
  216. })
  217. }
  218. reader.readAsBinaryString(file)
  219. }
  220. input.click()
  221. }
  222. }
  223. }
  224. </script>
  225. <style lang="scss" scoped>
  226. .info-container {
  227. .experimental-data {
  228. position: relative;
  229. .operate {
  230. position: absolute;
  231. right: 0;
  232. top: -2px;
  233. }
  234. .content {
  235. padding: 10px;
  236. position: relative;
  237. .note {
  238. margin-top: 10px;
  239. }
  240. }
  241. }
  242. }
  243. </style>