|
@@ -371,376 +371,3 @@ defineExpose({
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|
|
|
-<template>
|
|
|
|
|
- <div class="panel-wrap">
|
|
|
|
|
- <van-empty v-if="state.appointList.length === 0 && state.finished" description="暂无预约记录" />
|
|
|
|
|
- <van-list v-else v-model:loading="state.loading" :finished="state.finished" finished-text="没有更多了" @load="onLoad"
|
|
|
|
|
- class="data-list">
|
|
|
|
|
- <div class="inst-item mb20" v-for="(v, index) in state.appointList" :key="index">
|
|
|
|
|
- <div class="flex flex-between mb20">
|
|
|
|
|
- <div>
|
|
|
|
|
- <div class="mr10">
|
|
|
|
|
- <span class="fontSize14 primary-color bold">{{ v.instName }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <!-- Status Tag moved here -->
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="flex mb20">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">送样时间:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span class="fontSize14">{{ formatDate(new Date(v.deliverTime), 'YYYY-mm-dd HH:MM') }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex mb20">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">检测时间:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span class="fontSize14">{{ formatDate(new Date(v.testTime), 'YYYY-mm-dd HH:MM') }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex mb20">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">样品数:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span class="fontSize14">{{ v.sampleNum }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex mb20">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">申请人:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span class="fontSize14">{{ v.userName }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex mb20">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">状态:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <van-tag :type="getStatusType(v.deliverStatus)">{{ setStatus(v.deliverStatus) }}</van-tag>
|
|
|
|
|
- </div>
|
|
|
|
|
- <!-- Detection Info Clickable -->
|
|
|
|
|
- <div class="flex mb20" v-if="v.sampleItem !== '[]' || v.testSampleItem">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">检测信息:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span v-if="v.sampleItem" class="fontSize14 primary-color pointer mr10"
|
|
|
|
|
- @click="showSampleItem(v.sampleItem, '预约信息')">预约检测项目</span>
|
|
|
|
|
- <span v-if="v.testSampleItem" class="fontSize14 primary-color pointer"
|
|
|
|
|
- @click="showSampleItem(v.testSampleItem, '实测信息')">实测检测项目</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="flex mb20" v-if="v.testResultName">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">检测结果:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div style="flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
|
|
|
|
|
- <span class="fontSize14 primary-color pointer">
|
|
|
|
|
- <a :href="v.testResult" target="_blank" class="file-link">
|
|
|
|
|
- {{ v.testResultName }}
|
|
|
|
|
- </a>
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div v-if="v.order">
|
|
|
|
|
- <van-collapse v-model="activeNames">
|
|
|
|
|
- <van-collapse-item title="收费明细" :name="v.id">
|
|
|
|
|
- <div class="flex mb10">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">计费编号:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span class="fontSize14">{{ v.order.fboCode }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex mb10">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">收费:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span class="fontSize14 price">¥{{ v.order.fboActualAmount }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex mb10">
|
|
|
|
|
- <div class="equ-tit">
|
|
|
|
|
- <span class="fontSize14 bold">预估费用:</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
- <span class="fontSize14 price">¥{{ v.order.fboExpectedAmount }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </van-collapse-item>
|
|
|
|
|
- </van-collapse>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- Cancel Button moved to bottom -->
|
|
|
|
|
- <div class="flex mt20" style="justify-content: flex-end;"
|
|
|
|
|
- v-if="v.deliverStatus == '10'">
|
|
|
|
|
- <van-button class="scan-txt" plain type="danger" size="small" @click.stop="handleCancelAppoint(v)">
|
|
|
|
|
- 取消预约
|
|
|
|
|
- </van-button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </van-list>
|
|
|
|
|
-
|
|
|
|
|
- <!-- Dialog for Sample Items -->
|
|
|
|
|
- <van-dialog v-model:show="itemsDialogShow" :title="dialogTitle">
|
|
|
|
|
- <div class="dialog-content">
|
|
|
|
|
- <div class="flex mb10 flex-col" style="padding: 10px;">
|
|
|
|
|
- <div class="flex mb4" v-for="(test, idx) in currentSampleItems" :key="idx">
|
|
|
|
|
- <span class="fontSize14">{{ testItemInfo(test) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </van-dialog>
|
|
|
|
|
- </div>
|
|
|
|
|
-</template>
|
|
|
|
|
-
|
|
|
|
|
-<script lang="ts" setup>
|
|
|
|
|
-import { reactive, ref, onMounted } from 'vue'
|
|
|
|
|
-import { useSampleApi } from '/@/api/instr/sample'
|
|
|
|
|
-import to from 'await-to-js'
|
|
|
|
|
-import { formatDate } from '/@/utils/formatTime'
|
|
|
|
|
-import { showDialog, showNotify } from 'vant'
|
|
|
|
|
-
|
|
|
|
|
-const props = defineProps({
|
|
|
|
|
- instId: {
|
|
|
|
|
- type: Number,
|
|
|
|
|
- default: 0
|
|
|
|
|
- }
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const sampleApi = useSampleApi()
|
|
|
|
|
-const activeNames = ref([])
|
|
|
|
|
-
|
|
|
|
|
-const state = reactive({
|
|
|
|
|
- loading: false,
|
|
|
|
|
- finished: false,
|
|
|
|
|
- appointList: [] as any[],
|
|
|
|
|
- queryForm: {
|
|
|
|
|
- pageNum: 1,
|
|
|
|
|
- pageSize: 10,
|
|
|
|
|
- instId: props.instId
|
|
|
|
|
- },
|
|
|
|
|
- total: 0,
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const toParse = (str: string) => {
|
|
|
|
|
- try {
|
|
|
|
|
- return JSON.parse(str) || []
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- return []
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const testItemInfo = (test: any) => {
|
|
|
|
|
- return `检测项:${test.name},数量:${test.count}`
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const itemsDialogShow = ref(false)
|
|
|
|
|
-const currentSampleItems = ref<any[]>([])
|
|
|
|
|
-const dialogTitle = ref('检测信息')
|
|
|
|
|
-
|
|
|
|
|
-const showSampleItem = (itemsStr: string, title: string = '检测信息') => {
|
|
|
|
|
- currentSampleItems.value = toParse(itemsStr)
|
|
|
|
|
- dialogTitle.value = title
|
|
|
|
|
- itemsDialogShow.value = true
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const getStatusType = (key: string) => {
|
|
|
|
|
- let type = 'default'
|
|
|
|
|
- switch (key) {
|
|
|
|
|
- case '10': // 待审核
|
|
|
|
|
- type = 'warning'
|
|
|
|
|
- break
|
|
|
|
|
- case '20': // 已通过
|
|
|
|
|
- type = 'success'
|
|
|
|
|
- break
|
|
|
|
|
- case '30': // 已驳回
|
|
|
|
|
- type = 'danger'
|
|
|
|
|
- break
|
|
|
|
|
- case '50': // 已检测
|
|
|
|
|
- type = 'primary'
|
|
|
|
|
- break
|
|
|
|
|
- case '40': // 已取消
|
|
|
|
|
- case '11': // 已退回
|
|
|
|
|
- type = 'default'
|
|
|
|
|
- break
|
|
|
|
|
- }
|
|
|
|
|
- return type as 'primary' | 'success' | 'warning' | 'danger' | 'default'
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const setStatus = (key: string) => {
|
|
|
|
|
- let str = ''
|
|
|
|
|
- switch (key) {
|
|
|
|
|
- case '10':
|
|
|
|
|
- str = '待审核'
|
|
|
|
|
- break
|
|
|
|
|
- case '11':
|
|
|
|
|
- str = '已退回'
|
|
|
|
|
- break
|
|
|
|
|
- case '20':
|
|
|
|
|
- str = '已通过'
|
|
|
|
|
- break
|
|
|
|
|
- case '30':
|
|
|
|
|
- str = '已驳回'
|
|
|
|
|
- break
|
|
|
|
|
- case '40':
|
|
|
|
|
- str = '已取消'
|
|
|
|
|
- break
|
|
|
|
|
- case '50':
|
|
|
|
|
- str = '已检测'
|
|
|
|
|
- break
|
|
|
|
|
- }
|
|
|
|
|
- return str
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const handleCancelAppoint = (row: any) => {
|
|
|
|
|
- showDialog({
|
|
|
|
|
- title: '提示',
|
|
|
|
|
- message: '确认取消预约?',
|
|
|
|
|
- showCancelButton: true,
|
|
|
|
|
- })
|
|
|
|
|
- .then(async () => {
|
|
|
|
|
- const params = { id: row.id }
|
|
|
|
|
- const [err, res]: any = await to(sampleApi.userCancelAppoint(params))
|
|
|
|
|
- if (err) return
|
|
|
|
|
- if (res?.code === 200) {
|
|
|
|
|
- showNotify({ type: 'success', message: '取消成功' })
|
|
|
|
|
- state.queryForm.pageNum = 1
|
|
|
|
|
- state.appointList = []
|
|
|
|
|
- state.finished = false
|
|
|
|
|
- onLoad()
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- .catch(() => {
|
|
|
|
|
- // on cancel
|
|
|
|
|
- })
|
|
|
|
|
-}
|
|
|
|
|
-const onLoad = async () => {
|
|
|
|
|
- state.loading = true
|
|
|
|
|
- state.queryForm.instId = props.instId
|
|
|
|
|
-
|
|
|
|
|
- const [err, res]: any = await to(sampleApi.getList(state.queryForm))
|
|
|
|
|
- state.loading = false
|
|
|
|
|
- if (err) {
|
|
|
|
|
- state.finished = true
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (res?.code === 200) {
|
|
|
|
|
- const list = res?.data?.list || []
|
|
|
|
|
- if (state.queryForm.pageNum === 1) {
|
|
|
|
|
- state.appointList = list
|
|
|
|
|
- } else {
|
|
|
|
|
- state.appointList = [...state.appointList, ...list]
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- state.total = res?.data?.total || 0
|
|
|
|
|
- state.queryForm.pageNum++
|
|
|
|
|
-
|
|
|
|
|
- if (state.appointList.length >= state.total) {
|
|
|
|
|
- state.finished = true
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- state.finished = true
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-onMounted(() => {
|
|
|
|
|
- // onLoad will be triggered by van-list automatically initially
|
|
|
|
|
-})
|
|
|
|
|
-// Expose onLoad for parent component to call
|
|
|
|
|
-defineExpose({
|
|
|
|
|
- onLoad: () => {
|
|
|
|
|
- state.queryForm.pageNum = 1
|
|
|
|
|
- state.finished = false
|
|
|
|
|
- // Need to reset list? The onLoad usually appends...
|
|
|
|
|
- // If called from parent for refresh, we should probably reset.
|
|
|
|
|
- // Let's modify logic slightly or just set pageNum to 1 and empty list
|
|
|
|
|
- state.appointList = []
|
|
|
|
|
- onLoad()
|
|
|
|
|
- }
|
|
|
|
|
-})
|
|
|
|
|
-</script>
|
|
|
|
|
-
|
|
|
|
|
-<style lang="scss" scoped>
|
|
|
|
|
-* {
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.panel-wrap {
|
|
|
|
|
- height: 100%;
|
|
|
|
|
-
|
|
|
|
|
- .data-list {
|
|
|
|
|
- .inst-item {
|
|
|
|
|
- border-radius: 10px;
|
|
|
|
|
- padding: 15px;
|
|
|
|
|
- box-shadow: -2px 0px 9px rgba(0, 0, 0, 0.12);
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
- background-color: #fff;
|
|
|
|
|
-
|
|
|
|
|
- .equ-tit {
|
|
|
|
|
- width: 80px;
|
|
|
|
|
- min-width: 80px;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.fontSize14 {
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.bold {
|
|
|
|
|
- font-weight: bold;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.primary-color {
|
|
|
|
|
- color: #1989fa;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.price {
|
|
|
|
|
- color: #ee0a24;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.flex {
|
|
|
|
|
- display: flex;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.flex-between {
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.mb20 {
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.mb10 {
|
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.mr10 {
|
|
|
|
|
- margin-right: 10px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.mt20 {
|
|
|
|
|
- margin-top: 20px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.flex-col {
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.pointer {
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
-}
|
|
|
|
|
-</style>
|
|
|