| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- <script setup lang="ts" name="Sample">
- import apis from "@a"
- import dayjs from "dayjs"
- import ChickenModal from "@v/common/modal/chickenModal.vue"
- import type { ToolBtn } from "@@@/table/models"
- import EDetail from "../experiment/_detail.vue"
- import { Vue3NextQrcode } from "vue3-next-qrcode"
- const props = withDefaults(
- defineProps<{
- actions: ("update" | "delete" | "sample" | "destroy" | "flow" | "qrCode" | "audit" | "reject")[]
- customBtns?: ToolBtn[]
- status?: number
- createBy?: number
- }>(),
- {
- customBtns: () => {
- return []
- }
- }
- )
- const tableRef = ref()
- const modalRef = ref()
- const modalType = ref("C")
- const opts = reactive({
- columns: () =>
- [
- { field: "id", name: "样本ID", width: 100, isSort: true, visible: false, tooltip: true },
- {
- field: "sampleName",
- name: "样本名称",
- visible: true,
- isSort: false,
- width: "200",
- tooltip: true
- },
- {
- field: "description",
- name: "样本描述",
- visible: true,
- isSort: false,
- width: "auto",
- tooltip: true
- },
- // {
- // field: "batchId",
- // name: "取样批次",
- // visible: true,
- // isSort: false,
- // width: "auto",
- // tooltip: true
- // },
- {
- field: "electronicId",
- name: "取样个体电子ID",
- visible: true,
- isSort: false,
- width: "120",
- tooltip: true
- },
- // {field: "description", name: "样本描述", visible: true, isSort: false, width: "auto", tooltip: true},
- { field: "sampleType", name: "样品类型", visible: true, isSort: false, width: 120 },
- { field: "sampleTime", name: "取样时间", visible: true, isSort: false, width: 140 },
- { field: "sampleStatus", name: "样品状态", visible: true, isSort: false, width: 120 },
- { field: "actions", name: `操作`, width: 150 }
- ] as any[],
- queryParams: {
- sampleName: undefined,
- batchId: undefined,
- chickenId: undefined,
- electronicId: undefined,
- description: undefined,
- sampleType: undefined,
- sampleStatus: props.status
- },
- searchFormItems: [
- {
- field: "sampleName",
- label: "样本名称",
- class: "w-100",
- required: false,
- placeholder: "请输入样本名称",
- component: "I",
- listeners: {
- keyup: (e: KeyboardEvent) => {
- if (e.code == "Enter") {
- handleQuery()
- }
- }
- }
- },
- {
- field: "electronicId",
- disabled: true,
- label: "取样个体电子ID",
- class: "w-100",
- required: false,
- placeholder: "请选择个体电子ID",
- component: "I",
- append: "icon",
- appendClickFunc: () => {
- handleOpenChickenModal("search")
- }
- },
- {
- field: "sampleType",
- label: "样品类型",
- class: "w-100",
- required: false,
- component: "Dict",
- props: {
- placeholder: "请选择样品类型",
- dictType: "experiment_sample_type",
- valueIsNumber: 1,
- type: "select"
- },
- listeners: {
- change: () => {
- handleQuery()
- }
- }
- },
- {
- show: () => props.status == undefined,
- field: "sampleStatus",
- label: "样品状态",
- class: "w-100",
- required: false,
- component: "Dict",
- props: {
- placeholder: "请选择样品状态",
- dictType: "experiment_sample_status",
- valueIsNumber: 1,
- type: "select"
- },
- listeners: {
- change: () => {
- handleQuery()
- }
- }
- }
- ] as any,
- permission: "",
- handleBtns: [],
- handleFuns: {
- handleCreate,
- handleUpdate: () => {
- const row = tableRef.value.getSelected()
- handleUpdate(row)
- },
- handleDelete: () => {
- const rows = tableRef.value.getSelecteds()
- handleDelete(rows)
- }
- },
- customBtns: props.customBtns,
- tableListFun: apis.experiment.sampleApi.list,
- getEntityFun: apis.experiment.sampleApi.get,
- deleteEntityFun: apis.experiment.sampleApi.del,
- exportUrl: apis.experiment.sampleApi.exportUrl,
- exportName: "Sample",
- modalTitle: "实验样本",
- formItems: [
- {
- field: "sampleName",
- label: "样本名称",
- class: "w-100",
- required: true,
- placeholder: "请输入样本名称",
- component: "I"
- },
- // {
- // field: "batchId",
- // label: "取样批次",
- // class: "w-100",
- // required: false,
- // placeholder: "请输入取样批次",
- // component: "I"
- // },
- {
- show: () => modalType.value == "S",
- field: "electronicId",
- label: "取样个体电子ID",
- class: "w-100",
- required: true,
- placeholder: "请选择取样个体电子ID",
- component: "I",
- append: "icon",
- appendClickFunc: () => {
- handleOpenChickenModal("form")
- }
- },
- {
- show: () => modalType.value == "S",
- field: "sampleType",
- label: "样品类型",
- class: "w-100",
- required: true,
- component: "Dict",
- props: {
- placeholder: "请选择样品类型",
- dictType: "experiment_sample_type",
- type: "select",
- valueIsNumber: 1
- }
- },
- {
- field: "description",
- label: "样本描述",
- class: "w-100",
- required: false,
- placeholder: "请输入样本描述",
- component: "I",
- props: {
- type: "textarea",
- rows: 5
- }
- }
- ] as any,
- resetForm: () => {
- form.value = emptyFormData.value
- },
- labelWidth: "80px",
- emptyFormData: {
- id: undefined,
- sampleName: undefined,
- batchId: undefined,
- chickenId: undefined,
- electronicId: undefined,
- description: undefined,
- sampleType: undefined,
- sampleStatus: undefined
- }
- })
- const { queryParams, emptyFormData } = toRefs(opts)
- const form = ref<any>(emptyFormData.value)
- const modalTitle = computed(() => {
- return modalType.value == "C" || modalType.value == "U"
- ? "样本"
- : modalType.value == "S"
- ? "个体取样"
- : ""
- })
- /** 搜索按钮操作 */
- function handleQuery(query?: any) {
- query = query || tableRef.value?.getQueryParams() || queryParams.value
- addDateRange(query, query.dateRangeCreateTime)
- tableRef.value?.query(query)
- }
- /** 重置按钮操作 */
- function resetQuery(query?: any) {
- query = query || tableRef.value?.getQueryParams() || queryParams.value
- query.dateRangeCreateTime = [] as any
- addDateRange(query, query.dateRangeCreateTime)
- //
- }
- function handleCreate() {
- modalType.value = "C"
- tableRef.value.defaultHandleFuns.handleCreate()
- }
- /** 修改按钮操作 */
- function handleUpdate(row: any) {
- modalType.value = "U"
- tableRef.value.defaultHandleFuns.handleUpdate("", row)
- }
- function handleSample(row: any) {
- modalType.value = "S"
- apis.experiment.sampleApi.get(row.id).then((res: any) => {
- form.value = res.data
- form.value.sampleStatus = 2
- modalRef.value.changePrefixTitle("")
- modalRef.value.show()
- })
- }
- /** 删除按钮操作 */
- function handleDelete(rows: any[]) {
- tableRef.value.defaultHandleFuns.handleDelete("", rows)
- }
- /** 提交按钮 */
- function submitForm() {
- if (modalType.value == "C" || modalType.value == "U") {
- apis.experiment.sampleApi.addOrUpdate(form.value).then(() => {
- handleQuery()
- })
- } else if (modalType.value == "S") {
- apis.experiment.sampleApi.smaple(form.value).then(() => {
- message.msgSuccess("取样成功")
- handleQuery()
- })
- }
- }
- function checkBtnShow(btn: any, row: any) {
- if (props.actions.includes(btn)) {
- return true
- }
- return false
- }
- const chickenModalRef = ref()
- const chickenModalSelectType = ref()
- function handleOpenChickenModal(type: string) {
- chickenModalSelectType.value = type
- if (chickenModalSelectType.value == "search") {
- queryParams.value.chickenId = undefined
- queryParams.value.electronicId = ""
- tableRef.value.setQueryParams(queryParams.value)
- }
- chickenModalRef.value.open()
- }
- function onChickenConfirm(data: any) {
- if (chickenModalSelectType.value == "search") {
- queryParams.value.chickenId = data[0].id
- queryParams.value.electronicId = data[0].electronicId
- handleQuery(queryParams.value)
- } else if (chickenModalSelectType.value === "form") {
- console.log("data", data)
- form.value.chickenId = data[0].id
- form.value.electronicId = data[0].electronicId
- form.value.batchNum = data[0].batchNum
- }
- }
- function handleDestory(row) {
- message.confirm("确定要销毁该样本吗?").then(() => {
- apis.experiment.sampleApi.destroy(row.id).then(() => {
- handleQuery()
- })
- })
- }
- const flowModalRef = ref()
- const flowData = ref()
- function handleFlow(row) {
- apis.experiment.sampleApi.queryFlowLogs(row.id).then((res: any) => {
- flowData.value = res.data
- flowModalRef.value.show()
- })
- }
- const qrModalRef = ref()
- const qrModalData = ref()
- const qrCode = ref({
- logo: "/media/logo.png",
- size: 300,
- // colorDark: "#0e9489",
- colorDark: "#000000",
- text: ""
- })
- function handleQrCode(row) {
- qrModalData.value = row
- qrCode.value.text = `vb@sample@/sample/${row.id}`
- qrModalRef.value.show()
- }
- function handleDownloadQr(id: string) {
- // 获取整个元素,包括标题和二维码
- const element = document.querySelector("#" + id) as HTMLElement
- if (!element) return
- // 使用html2canvas将整个元素转换为图片
- import("html2canvas").then((html2canvas) => {
- html2canvas.default(element).then((canvas) => {
- // 将canvas转换为图片blob
- canvas.toBlob((blob) => {
- if (!blob) return
- // 创建下载链接
- const url = URL.createObjectURL(blob)
- const a = document.createElement("a")
- a.href = url
- a.download = `${qrModalData.value.sampleName}样品二维码`
- document.body.appendChild(a)
- a.click()
- document.body.removeChild(a)
- URL.revokeObjectURL(url)
- })
- })
- })
- }
- const detailRef = ref()
- function handleDetail(row: any) {
- apis.experiment.sampleApi.queryExperiment(row.id).then((res) => {
- detailRef.value.open(res.data)
- })
- }
- const pdfPreviewRef = ref()
- function handlePreviewPdf(file: string) {
- const fileId = file.split("$")[0],
- fileName = file.split("$")[1]
- pdfPreviewRef.value.open({
- fileId,
- fileName
- })
- }
- // function handlePrintQr(id: string) {
- // const printContent = document.querySelector("#" + id)
- // if (!printContent) return
- // // 创建打印样式
- // const style = document.createElement("style")
- // style.innerHTML = `
- // @media print {
- // body * {
- // display: none !important;
- // }
- // #print-area, #print-area * {
- // display: block !important;
- // }
- // #print-area {
- // position: absolute;
- // top: 0;
- // left: 0;
- // width: 100vw;
- // height: 600px;
- // display: flex !important;
- // flex-direction: column;
- // align-items: center;
- // justify-content: center;
- // font-family: Arial, sans-serif;
- // }
- // }
- // `
- // document.head.appendChild(style)
- // // 创建打印区域
- // const printArea = document.createElement("div")
- // printArea.id = "print-area"
- // // printArea.innerHTML = `
- // // <div style="width:100%;display:flex;flex-direction: column;align-items: center;justify-content: center;">${printContent.innerHTML}</div>
- // // `
- // printArea.innerHTML = printContent.innerHTML
- // document.body.appendChild(printArea)
- // // 打印
- // window.print()
- // // 清理
- // setTimeout(() => {
- // document.head.removeChild(style)
- // document.body.removeChild(printArea)
- // }, 500)
- // }
- </script>
- <template>
- <div class="app-container">
- <VbDataTable
- ref="tableRef"
- keyField="id"
- :columns="[]"
- :columns-fun="opts.columns"
- :handle-perm="opts.permission"
- :handle-btns="opts.handleBtns"
- :handle-funs="opts.handleFuns"
- :search-form-items="opts.searchFormItems"
- :custom-btns="opts.customBtns"
- :remote-fun="opts.tableListFun"
- :get-entity-fun="opts.getEntityFun"
- :delete-entity-fun="opts.deleteEntityFun"
- :export-url="opts.exportUrl"
- :export-name="opts.exportName"
- :modal="modalRef"
- :reset-form-fun="opts.resetForm"
- v-model:form-data="form"
- v-model:query-params="queryParams"
- :check-multiple="true"
- :reset-search-form-fun="resetQuery"
- :custom-search-fun="handleQuery">
- <template #sampleType="{ row }">
- <DictTag
- type="experiment_sample_type"
- :value-is-number="1"
- :value="row.sampleType"></DictTag>
- </template>
- <template #sampleStatus="{ row }">
- <DictTag
- type="experiment_sample_status"
- :value-is-number="1"
- :value="row.sampleStatus"></DictTag>
- </template>
- <template #sampleTime="{ row }">
- <template v-if="row.sampleTime">
- {{ dayjs(row.sampleTime).format("YYYY/MM/DD HH:mm:ss") }}
- </template>
- <template v-else>-</template>
- </template>
- <template #actions="{ row }">
- <template v-if="row.sampleStatus == 1">
- <vb-tooltip v-if="checkBtnShow('update', row)" content="修改" placement="top">
- <el-button
- link
- type="primary"
- @click="handleUpdate(row)"
- v-hasPermission="'experiment:sample:edit'">
- <template #icon>
- <VbIcon icon-name="notepad-edit" icon-type="duotone" class="fs-3"></VbIcon>
- </template>
- </el-button>
- </vb-tooltip>
- <vb-tooltip v-if="checkBtnShow('sample', row)" content="取样" placement="top">
- <el-button link type="success" @click="handleSample(row)">
- <template #icon>
- <VbIcon icon-name="shield-tick" icon-type="duotone" class="fs-3"></VbIcon>
- </template>
- </el-button>
- </vb-tooltip>
- </template>
- <template v-if="row.sampleStatus == 2 || row.sampleStatus == 3">
- <vb-tooltip v-if="checkBtnShow('flow', row)" content="流转记录" placement="top">
- <el-button link type="primary" @click="handleFlow(row)">
- <template #icon>
- <VbIcon icon-name="book" icon-type="duotone" class="fs-3"></VbIcon>
- </template>
- </el-button>
- </vb-tooltip>
- <vb-tooltip v-if="checkBtnShow('qrCode', row)" content="生成二维码" placement="top">
- <el-button link type="success" @click="handleQrCode(row)">
- <template #icon>
- <VbIcon icon-name="scan-barcode" icon-type="duotone" class="fs-3"></VbIcon>
- </template>
- </el-button>
- </vb-tooltip>
- </template>
- <template v-if="row.sampleStatus == 2">
- <vb-tooltip v-if="checkBtnShow('destroy', row)" content="销毁" placement="top">
- <el-button
- link
- type="danger"
- @click="handleDestory(row)"
- v-hasPermission="'experiment:sample:destroy'">
- <template #icon>
- <VbIcon icon-name="trash-square" icon-type="duotone" class="fs-3"></VbIcon>
- </template>
- </el-button>
- </vb-tooltip>
- </template>
- <template v-if="row.sampleStatus == 3">
- <vb-tooltip v-if="checkBtnShow('destroy', row)" content="实验详情" placement="top">
- <el-button link type="warning" @click="handleDetail(row)">
- <template #icon>
- <VbIcon icon-name="book-open" icon-type="duotone" class="fs-3"></VbIcon>
- </template>
- </el-button>
- </vb-tooltip>
- </template>
- <template v-if="row.sampleStatus == 1 || row.sampleStatus == 4">
- <vb-tooltip v-if="checkBtnShow('delete', row)" content="删除" placement="top">
- <el-button
- link
- type="danger"
- @click="handleDelete([row])"
- v-hasPermission="'experiment:sample:remove'">
- <template #icon>
- <VbIcon icon-name="trash-square" icon-type="duotone" class="fs-3"></VbIcon>
- </template>
- </el-button>
- </vb-tooltip>
- </template>
- </template>
- </VbDataTable>
- <VbModal
- v-model:modal="modalRef"
- :title="modalTitle"
- :form-data="form"
- :form-items="opts.formItems"
- :label-width="opts.labelWidth"
- append-to-body
- @confirm="submitForm"></VbModal>
- <ChickenModal
- ref="chickenModalRef"
- modal-title="请选择电子ID"
- :multiple="false"
- @confirm="onChickenConfirm"></ChickenModal>
- <VbModal
- v-model:modal="qrModalRef"
- title="样品二维码"
- :confirm-btn="false"
- :close-btn-class="'btn btn-danger'"
- append-to-body>
- <template #body>
- <div class="w-100 d-flex justify-content-center align-items-center">
- <div id="qr" class="d-flex flex-column align-items-center">
- <span class="fs-5 fw-bold mt-5 mb-0 qr-title">
- {{ qrModalData?.sampleName }} 样品二维码
- </span>
- <Vue3NextQrcode
- :text="qrCode.text"
- :size="qrCode.size"
- :color-dark="qrCode.colorDark"
- :logo-image="qrCode.logo"
- :logo-scale="0.15"
- :logo-margin="0"
- :logo-corner-radius="20"
- :margin="20" />
- </div>
- </div>
- <div class="text-center">
- <el-button type="primary" class="mx-5 w-150px" @click="handleDownloadQr('qr')">
- 保存
- </el-button>
- <!-- <el-button type="primary" class="mx-5 w-150px" @click="handlePrintQr('qr')">
- 打印
- </el-button> -->
- </div>
- </template>
- </VbModal>
- <VbModal
- v-model:modal="flowModalRef"
- title="样品流转记录"
- modal-dialog-style="max-width: 500px"
- :confirm-btn="false"
- :close-btn-class="'btn btn-danger'"
- append-to-body>
- <template #body>
- <el-table :data="flowData" stripe :show-header="false">
- <!-- <el-table-column label="序号" type="index" width="60" align="center"></el-table-column> -->
- <el-table-column label="序号" width="100" type="index" align="center"></el-table-column>
- <el-table-column label="操作人" prop="handlerName" align="center"></el-table-column>
- <el-table-column label="操作时间" prop="handleTime" align="center">
- <template #default="{ row }">
- <span>{{ dayjs(row.handleTime).format("YYYY/MM/DD HH:mm:ss") }}</span>
- </template>
- </el-table-column>
- </el-table>
- </template>
- </VbModal>
- <EDetail ref="detailRef"></EDetail>
- <VbPdfPreview ref="pdfPreviewRef" />
- </div>
- </template>
|