audit.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <script setup lang="ts" name="Experiment">
  2. import apis from "@a"
  3. import dayjs from "dayjs"
  4. import EDetail from "./_detail.vue"
  5. const experimentUsersOptions = ref([])
  6. const tableRef = ref()
  7. const modalRef = ref()
  8. const sampleSelectRef = ref()
  9. const opts = reactive({
  10. columns: [
  11. { field: "id", name: "实验ID", width: 100, isSort: true, visible: false, tooltip: true },
  12. {
  13. field: "experimentName",
  14. name: "实验名称",
  15. visible: true,
  16. isSort: false,
  17. width: "auto",
  18. tooltip: true
  19. },
  20. { field: "experimentType", name: "实验类型", visible: true, isSort: false, width: 200 },
  21. {
  22. field: "experimentManagerName",
  23. name: "实验负责人",
  24. visible: true,
  25. isSort: false,
  26. width: 120,
  27. tooltip: true
  28. },
  29. {
  30. field: "reviewManagerName",
  31. name: "审核负责人",
  32. visible: true,
  33. isSort: false,
  34. width: 120,
  35. tooltip: true
  36. },
  37. {
  38. field: "experimentStatus",
  39. name: "实验状态",
  40. visible: true,
  41. isSort: false,
  42. width: 100,
  43. tooltip: true
  44. },
  45. {
  46. field: "rawDataUrl",
  47. name: "原始数据",
  48. visible: true,
  49. isSort: false,
  50. width: 230,
  51. tooltip: true
  52. },
  53. { field: "reportUrl", name: "实验报告", visible: true, isSort: false, width: 230 },
  54. { field: "actions", name: `操作`, width: 150 }
  55. ] as any[],
  56. queryParams: {
  57. experimentName: undefined,
  58. experimentType: undefined,
  59. experimentStatus: 3
  60. },
  61. searchFormItems: [
  62. {
  63. field: "experimentName",
  64. label: "实验名称",
  65. class: "w-100",
  66. required: false,
  67. placeholder: "请输入实验名称",
  68. component: "I",
  69. listeners: {
  70. keyup: (e: KeyboardEvent) => {
  71. if (e.code == "Enter") {
  72. handleQuery()
  73. }
  74. }
  75. }
  76. },
  77. {
  78. field: "experimentType",
  79. label: "实验类型",
  80. class: "w-100",
  81. required: false,
  82. component: "Dict",
  83. props: {
  84. placeholder: "请选择实验类型",
  85. dictType: "experiment_type",
  86. valueIsNumber: 1,
  87. type: "select"
  88. },
  89. listeners: {
  90. change: () => {
  91. handleQuery()
  92. }
  93. }
  94. }
  95. ] as any,
  96. permission: "experiment:experiment",
  97. handleBtns: [],
  98. handleFuns: {
  99. handleCreate,
  100. handleUpdate: () => {
  101. const row = tableRef.value.getSelected()
  102. handleUpdate(row)
  103. },
  104. handleDelete: () => {
  105. const rows = tableRef.value.getSelecteds()
  106. handleDelete(rows)
  107. }
  108. },
  109. customBtns: [],
  110. tableListFun: apis.experiment.experimentApi.list,
  111. getEntityFun: apis.experiment.experimentApi.get,
  112. deleteEntityFun: apis.experiment.experimentApi.del,
  113. exportUrl: apis.experiment.experimentApi.exportUrl,
  114. exportName: "Experiment",
  115. modalTitle: "实验管理",
  116. formItems: [
  117. {
  118. field: "experimentName",
  119. label: "实验名称",
  120. class: "w-100",
  121. required: true,
  122. placeholder: "请输入实验名称",
  123. component: "I"
  124. },
  125. {
  126. field: "experimentType",
  127. label: "实验类型",
  128. class: "w-100",
  129. required: true,
  130. component: "Dict",
  131. props: {
  132. placeholder: "请选择实验类型",
  133. dictType: "experiment_type",
  134. type: "select",
  135. valueIsNumber: 1
  136. }
  137. },
  138. {
  139. field: "sampleNames",
  140. label: "实验样品",
  141. class: "w-100",
  142. required: true,
  143. placeholder: "请选择实验样品",
  144. data: () => [],
  145. props: {
  146. type: "select"
  147. },
  148. append: "icon",
  149. appendClickFunc: () => {
  150. sampleSelectRef.value.open()
  151. }
  152. },
  153. {
  154. field: "reviewManager",
  155. label: "审核负责人",
  156. class: "w-100",
  157. required: true,
  158. placeholder: "请选择审核负责人",
  159. component: "VS",
  160. data: () => experimentUsersOptions.value,
  161. props: {
  162. valueIsNumber: 1,
  163. type: "select"
  164. }
  165. },
  166. {
  167. field: "description",
  168. label: "实验描述",
  169. class: "w-100",
  170. required: false,
  171. placeholder: "请输入实验描述",
  172. component: "I",
  173. props: {
  174. type: "textarea"
  175. }
  176. }
  177. ] as any,
  178. resetForm: () => {
  179. form.value = emptyFormData.value
  180. },
  181. labelWidth: "80px",
  182. emptyFormData: {
  183. id: undefined,
  184. experimentName: undefined,
  185. experimentType: undefined,
  186. sampleIds: undefined,
  187. sampleNames: undefined,
  188. reviewManager: undefined
  189. }
  190. })
  191. const { queryParams, emptyFormData } = toRefs(opts)
  192. const form = ref<any>(emptyFormData.value)
  193. /** 搜索按钮操作 */
  194. function handleQuery(query?: any) {
  195. query = query || tableRef.value?.getQueryParams() || queryParams.value
  196. addDateRange(query, query.dateRangeCreateTime)
  197. addDateRange(query, query.dateRangeUpdateTime, "UpdateTime")
  198. tableRef.value?.query(query)
  199. }
  200. /** 重置按钮操作 */
  201. function resetQuery(query?: any) {
  202. query = query || tableRef.value?.getQueryParams() || queryParams.value
  203. query.dateRangeCreateTime = [] as any
  204. addDateRange(query, query.dateRangeCreateTime)
  205. query.dateRangeUpdateTime = [] as any
  206. addDateRange(query, query.dateRangeUpdateTime, "UpdateTime")
  207. //
  208. }
  209. function handleCreate() {
  210. tableRef.value.defaultHandleFuns.handleCreate()
  211. }
  212. /** 修改按钮操作 */
  213. function handleUpdate(row: any) {
  214. // tableRef.value.defaultHandleFuns.handleUpdate("", row)
  215. apis.experiment.experimentApi.get(row.id).then((res) => {
  216. form.value = res.data
  217. form.value.sampleIds = res.data.sampleList.map((item) => item.sampleId)
  218. form.value.sampleNames = res.data.sampleList.map((item) => item.sampleName)
  219. modalRef.value.show()
  220. })
  221. }
  222. /** 删除按钮操作 */
  223. function handleDelete(rows: any[]) {
  224. tableRef.value.defaultHandleFuns.handleDelete("", rows)
  225. }
  226. /** 提交按钮 */
  227. function submitForm() {
  228. apis.experiment.experimentApi.addOrUpdate(form.value).then(() => {
  229. handleQuery()
  230. })
  231. }
  232. function onSampleSelectConfirm(data: any) {
  233. console.log("data", data)
  234. form.value.sampleIds = data.map((item) => item.id)
  235. form.value.sampleNames = data.map((item) => item.sampleName)
  236. }
  237. function getExperimentUsersOptions() {
  238. apis.experiment.experimentApi.getExperimentUsers().then((res) => {
  239. experimentUsersOptions.value = res.data.map((item) => {
  240. return {
  241. label: `${item.nickname}(${item.username})`,
  242. value: item.userId
  243. }
  244. })
  245. })
  246. }
  247. function handleStart(row: any) {
  248. message.confirm("确定要开始实验吗?", "开始实验").then(() => {
  249. apis.experiment.experimentApi.start(row.id).then(() => {
  250. handleQuery()
  251. })
  252. })
  253. }
  254. const reportModalRef = ref()
  255. const reportForm = ref({
  256. id: undefined,
  257. rawDataUrl: undefined,
  258. reportUrl: undefined
  259. })
  260. const reportFormItems = [
  261. {
  262. field: "rawDataUrl",
  263. label: "原始数据",
  264. class: "w-100",
  265. required: true,
  266. placeholder: "请上传原始数据",
  267. component: "Vu",
  268. props: {
  269. uploadType: "file",
  270. uploadUrl: "resource/oss/upload/experiment",
  271. fileType: ["pdf", "doc", "docx", "xls", "xlsx", "zip"],
  272. fileSize: 10,
  273. limit: 5
  274. }
  275. },
  276. {
  277. field: "reportUrl",
  278. label: "实验报告",
  279. class: "w-100",
  280. required: true,
  281. placeholder: "请上传实验报告",
  282. component: "Vu",
  283. props: {
  284. uploadType: "file",
  285. uploadUrl: "resource/oss/upload/experiment",
  286. fileType: ["pdf", "doc", "docx", "xls", "xlsx", "zip"],
  287. fileSize: 10,
  288. limit: 5
  289. }
  290. }
  291. ]
  292. function handleReport(row: any) {
  293. reportForm.value = {
  294. id: row.id,
  295. rawDataUrl: undefined,
  296. reportUrl: undefined
  297. }
  298. reportModalRef.value.show()
  299. }
  300. function submitReport() {
  301. apis.experiment.experimentApi.submitExperiment(reportForm.value).then(() => {
  302. handleQuery()
  303. })
  304. }
  305. const pdfPreviewRef = ref()
  306. function handlePreviewPdf(file: string) {
  307. const fileId = file.split("$")[0],
  308. fileName = file.split("$")[1]
  309. pdfPreviewRef.value.open({
  310. fileId,
  311. fileName
  312. })
  313. }
  314. const detailRef = ref()
  315. function handleDetail(row: any) {
  316. apis.experiment.experimentApi.get(row.id).then((res) => {
  317. detailRef.value.open(res.data)
  318. })
  319. }
  320. function handleAudit(row: any, isAudit: boolean) {
  321. message
  322. .confirm(
  323. `确定要${isAudit ? "通过" : "拒绝"}审核,${isAudit ? "吗" : "发回重新报告"}?`,
  324. `${isAudit ? "通过" : "拒绝"}审核`
  325. )
  326. .then(() => {
  327. apis.experiment.experimentApi.auditExperiment({ id: row.id, pass: isAudit }).then(() => {
  328. handleQuery()
  329. })
  330. })
  331. }
  332. function init() {
  333. getExperimentUsersOptions()
  334. }
  335. onMounted(init)
  336. </script>
  337. <template>
  338. <div class="app-container">
  339. <VbDataTable
  340. ref="tableRef"
  341. keyField="id"
  342. :columns="opts.columns"
  343. :handle-perm="opts.permission"
  344. :handle-btns="opts.handleBtns"
  345. :handle-funs="opts.handleFuns"
  346. :search-form-items="opts.searchFormItems"
  347. :custom-btns="opts.customBtns"
  348. :remote-fun="opts.tableListFun"
  349. :get-entity-fun="opts.getEntityFun"
  350. :delete-entity-fun="opts.deleteEntityFun"
  351. :export-url="opts.exportUrl"
  352. :export-name="opts.exportName"
  353. :modal="modalRef"
  354. :reset-form-fun="opts.resetForm"
  355. v-model:form-data="form"
  356. v-model:query-params="queryParams"
  357. :check-multiple="true"
  358. :reset-search-form-fun="resetQuery"
  359. :custom-search-fun="handleQuery">
  360. <template #experimentType="{ row }">
  361. <DictTag type="experiment_type" :value-is-number="1" :value="row.experimentType"></DictTag>
  362. </template>
  363. <template #rawDataUrl="{ row }">
  364. <template v-if="row.rawDataUrl">
  365. <template v-for="(file, key) in row.rawDataUrl.split(',')" :key="key">
  366. <span
  367. v-if="file.split('$').length > 1"
  368. class="text-primary p-1"
  369. @click="handlePreviewPdf(file)">
  370. {{ file.split("$")[1] }}
  371. </span>
  372. </template>
  373. </template>
  374. <template v-else>-</template>
  375. </template>
  376. <template #reportUrl="{ row }">
  377. <template v-if="row.reportUrl">
  378. <template v-for="(file, key) in row.reportUrl.split(',')" :key="key">
  379. <span
  380. v-if="file.split('$').length > 1"
  381. class="text-primary p-1"
  382. @click="handlePreviewPdf(file)">
  383. {{ file.split("$")[1] }}
  384. </span>
  385. </template>
  386. </template>
  387. <template v-else>-</template>
  388. </template>
  389. <template #experimentStatus="{ row }">
  390. <DictTag
  391. type="experiment_status"
  392. :value-is-number="1"
  393. :value="row.experimentStatus"></DictTag>
  394. </template>
  395. <template #actions="{ row }">
  396. <vb-tooltip content="实验详情" placement="top">
  397. <el-button link type="primary" @click="handleDetail(row)">
  398. <template #icon>
  399. <VbIcon icon-name="book" icon-type="duotone" class="fs-3"></VbIcon>
  400. </template>
  401. </el-button>
  402. </vb-tooltip>
  403. <vb-tooltip v-if="row.experimentStatus === 3" content="审核通过" placement="top">
  404. <el-button
  405. link
  406. type="success"
  407. @click="handleAudit(row, true)"
  408. v-hasPermission="'experiment:experiment:edit'">
  409. <template #icon>
  410. <VbIcon icon-name="add-files" icon-type="duotone" class="fs-3"></VbIcon>
  411. </template>
  412. </el-button>
  413. </vb-tooltip>
  414. <vb-tooltip v-if="row.experimentStatus === 3" content="发回报告" placement="top">
  415. <el-button
  416. link
  417. type="danger"
  418. @click="handleAudit(row, false)"
  419. v-hasPermission="'experiment:experiment:edit'">
  420. <template #icon>
  421. <VbIcon icon-name="update-file" icon-type="duotone" class="fs-3"></VbIcon>
  422. </template>
  423. </el-button>
  424. </vb-tooltip>
  425. </template>
  426. </VbDataTable>
  427. <VbModal
  428. v-model:modal="modalRef"
  429. :title="opts.modalTitle"
  430. :form-data="form"
  431. :form-items="opts.formItems"
  432. :label-width="opts.labelWidth"
  433. append-to-body
  434. @confirm="submitForm"></VbModal>
  435. <VbModal
  436. v-model:modal="reportModalRef"
  437. title="上传报告"
  438. :form-data="reportForm"
  439. :form-items="reportFormItems as any"
  440. :label-width="opts.labelWidth"
  441. append-to-body
  442. @confirm="submitReport"></VbModal>
  443. <SampleSelect
  444. ref="sampleSelectRef"
  445. v-model="form.sampleIds"
  446. @confirm="onSampleSelectConfirm"></SampleSelect>
  447. <EDetail ref="detailRef"></EDetail>
  448. <VbPdfPreview ref="pdfPreviewRef" />
  449. </div>
  450. </template>