This commit is contained in:
wuyy 2026-09-08 18:02:01 +08:00
parent 2e00ada8cd
commit 09f1900b7f
7 changed files with 339 additions and 84 deletions

View File

@ -314,6 +314,46 @@ export function txsaveData(query?: Object) {
data: query
})
}
// 临床发血退血查询列表
export function txqueryList(query?: Object) {
return request({
url: '/bus/bloodbank/backin/queryList',
method: 'get',
params: query
})
}
// 临床发血退血查询单个申请单信息
export function txqueryInfo(query?: Object) {
return request({
url: '/bus/bloodbank/backin/queryInfo',
method: 'get',
params: query
})
}
// 临床发血退血 删除血液信息
export function deleteBloodInfo(query?: Object) {
return request({
url: '/bus/bloodbank/backin/deleteBloodInfo',
method: 'post',
data: query
})
}
// 临床发血退血 审核数据
export function txauditData(query?: Object) {
return request({
url: '/bus/bloodbank/backin/auditData',
method: 'get',
params: query
})
}
// 临床发血退血 打印单据
export function txPrint(query?: Object) {
return request({
url: '/bus/bloodbank/backin/print',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,56 @@
<template>
<div>
<el-table :data="counts" border>
<el-table-column prop="A" label="A" align="center" />
<el-table-column prop="B" label="B" align="center" />
<el-table-column prop="O" label="O" align="center" />
<el-table-column prop="AB" label="AB" align="center" />
</el-table>
<div class="total">
扫描总数:{{ total }}
</div>
</div>
</template>
<script setup lang="ts">
const props = withDefaults(
defineProps<{
data?: Array<{ blood_no: string, blood_type: string }>
}>(),
{
data: () => [],
}
)
// 根据 props.data 明细自动统计各个血型数量
const counts = computed(() => {
const stat = { A: 0, B: 0, O: 0, AB: 0 }
props.data.forEach(item => {
const type = item.blood_type
// 只统计合法血型,其他脏数据直接跳过
if (type === 'A' || type === 'B' || type === 'O' || type === 'AB') {
stat[type]++
}
})
return [stat]
})
// 计算总和,数据变化自动更新
const total = computed(() => {
const row = counts.value[0]
return row.A + row.B + row.O + row.AB
})
</script>
<style scoped lang="scss">
.total {
color: #409eff;
font-weight: 700;
margin-top: 10px;
}
</style>

View File

@ -161,14 +161,27 @@ export function useAutoSize() {
/**
* 字节转 MB,保留n位小数
* @param size 字节 string|number
* @param digits 保留小数,默认2
* @returns {string} "0.03 MB"
* 字节强制转为指定单位
* @param size 字节
* @param targetUnit 目标单位 'B'|'KB'|'MB'|'GB'
* @param digits 保留小数
* @returns "0.03 MB"
*/
export function formatByteToMB(size: string | number, digits = 2): string {
export function formatByteToUnit(
size: string | number,
targetUnit: 'B' | 'KB' | 'MB' | 'GB',
digits = 2
): string {
const byte = Number(size)
if (isNaN(byte) || byte <= 0) return '0 MB'
const mb = byte / 1024 / 1024
return `${mb.toFixed(digits)} MB`
if (isNaN(byte) || byte <= 0) return `0 ${targetUnit}`
const unitMap: Record<string, number> = {
B: 1,
KB: 1024,
MB: 1024 * 1024,
GB: 1024 * 1024 * 1024,
}
const divisor = unitMap[targetUnit]
const val = byte / divisor
return `${val.toFixed(digits)} ${targetUnit}`
}

View File

@ -560,6 +560,7 @@ const bloodEnter = () => {
} else {
ElMessage.warning('该血液流水号不存在,请检查!')
}
bloodNo.value = ''
} else {
if (index > -1) return ElMessage.warning('该血液流水号已存在,请检查!')
queryBloodInfoByBloodNo({ bloodNo: bloodNo.value }).then(res => {
@ -726,7 +727,7 @@ const saveBloodApply = (type: number) => { // 1保存 2审核
if (res.code == 0) {
if (type == 1) {
ElMessage.success('保存成功!')
addMatch()
bloodInfo.value.bill_no = res.data
return false
} else {
return true

View File

@ -11,14 +11,14 @@
<el-button type="primary" plain @click="searchHandle">检索</el-button>
<el-button type="primary" plain @click="addHandle">新增单据</el-button>
<el-button type="success" plain :loading="saveLoading" @click="saveHandle">保存</el-button>
<el-button type="primary" plain @click="auditHandle">审核</el-button>
<el-button type="warning" plain @click="printHandle">打印</el-button>
<el-button type="primary" plain :loading="auditLoading" @click="auditHandle">审核</el-button>
<el-button type="warning" plain :loading="printLoading" @click="printHandle">打印</el-button>
</div>
<el-form :model="formData" label-width="auto" class="retreat-form">
<el-form :model="formData" label-width="auto" class="retreat-form" :disabled="!!formData.audit_person">
<div class="card-box retreat-info">
<div class="section-title"> 退血主信息 </div>
<div class="status">未审核</div>
<div class="status">{{ formData.audit_person ? "已审核" : "未审核" }}</div>
<el-row :gutter="10">
<el-col :span="4">
<el-form-item label="退血单号">
@ -27,7 +27,8 @@
</el-col>
<el-col :span="4">
<el-form-item label="经手人">
<SelectTable v-model:data="formData.handle_person" :tableData="userList" placeholder="" />
<SelectTable v-model:data="formData.handle_person" :tableData="userList" placeholder=""
:disabled="!!formData.audit_person" />
</el-form-item>
</el-col>
<el-col :span="4">
@ -72,10 +73,19 @@
format="YYYY-MM-DD HH:mm" disabled style="width:100%" />
</el-form-item>
<el-form-item label="退血原因">
<el-select v-model="reason" placeholder="请选择退血原因">
<el-select v-model="reason" placeholder="">
<el-option v-for="item in dictData.lctxyy" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="">
<!-- <div class="cancel-box">
<el-checkbox v-model="cancelBlood">取消血液</el-checkbox>
<el-input v-model="bloodNo" :disabled="!cancelBlood" @keyup.enter="cancelHandle"
style="margin-left: 10px;width:100%" />
</div> -->
</el-form-item>
<el-form-item label="统计信息"></el-form-item>
<BloodTypeStatTable :data="bloodList" />
</div>
<div class="card-box patient-panel">
@ -118,7 +128,8 @@
</el-row>
<div class="table-title">已扫描列表</div>
<el-table :data="scannedList" border height="calc(100% - 130px)" show-overflow-tooltip>
<el-table :data="bloodList" border height="calc(100% - 130px)" show-overflow-tooltip highlight-current-row
@row-click="bloodClick">
<el-table-column prop="blood_no" label="血液流水号" min-width="140" align="center" />
<el-table-column prop="product_no" label="产品码" min-width="120" align="center" />
<el-table-column prop="blood_breed" label="血液品种" min-width="120" align="center">
@ -129,12 +140,18 @@
<el-table-column prop="blood_type" label="血型" width="70" align="center" />
<el-table-column prop="capacity" label="容量" width="80" align="center" />
<el-table-column prop="unit" label="单位" width="60" align="center" />
<el-table-column prop="validDate" label="有效日期" min-width="130" align="center" />
<el-table-column prop="valid_date" label="有效日期" min-width="130" align="center" />
<el-table-column prop="reason" label="退血原因" min-width="120" align="center">
<template #default="{ row }">
{{dictData.lctxyy.find(v => v.value == row.reason)?.label || row.reason}}
</template>
</el-table-column>
<!-- 删除血液 -->
<el-table-column label="操作" align="center" :show-overflow-tooltip="false">
<template #default="{ row, $index }">
<el-button type="primary" text @click="delBlood(row, $index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
@ -161,7 +178,7 @@
</el-col>
<el-col :span="6">
<el-form-item label="单号">
<el-input v-model="searchForm.applyNo" placeholder="" />
<el-input v-model="searchForm.billNo" placeholder="" clearable />
</el-form-item>
</el-col>
</el-row>
@ -170,29 +187,34 @@
<el-table :data="tableData" border height="450" @row-click="jsRowclick" @row-dblclick="dblClickRow"
highlight-current-row show-overflow-tooltip>
<el-table-column prop="bill_no" label="出库单号" align="center" />
<el-table-column prop="occur_date" label="退血日期" align="center" width="150" />
<el-table-column prop="back_date" label="退血日期" align="center" width="150" />
<el-table-column prop="handle_person" label="经手人" align="center">
<template #default="scope">
{{userList.find(v => v.value == scope.row.handle_person)?.label || scope.row.handle_person}}
</template>
</el-table-column>
<el-table-column label="总金额" prop="money" align="center" />
<el-table-column label="总金额" prop="total_money" align="center" />
<el-table-column prop="beinhos_id" label="住院号/ID号" align="center" width="150" />
<el-table-column label="患者姓名" prop="patient_name" align="center" />
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="searchForm.pageNum"
v-model:limit="searchForm.pageSize" @pagination="getTxList" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="Retreat">
import dayjs from 'dayjs'
import { ElMessage } from 'element-plus'
import { getDictData, formatDict, dictData, useCommonDict } from '@/hooks'
import { getBloodBreed, queryBloodInfoByBloodNo } from '@/api/common'
import { queryBloodInfo, txsaveData } from '@/api/blood'
import { deleteBloodInfo, queryBloodInfo, txauditData, txPrint, txqueryInfo, txqueryList, txsaveData } from '@/api/blood'
import { printBase64PDF } from "@/utils/classCom"
const { userList, getUserData, getServerTime, bloodBreed, getBloodList, } = useCommonDict()
import useUserStore from '@/store/modules/user'
import { ElMessageBox } from 'element-plus'
import BloodTypeStatTable from "@/components/BloodTypeStatTable/index.vue"
const userInfo = useUserStore()
const bloodInfo = ref({})
@ -203,24 +225,134 @@ const formData = ref({
})
const reason = ref('')
const cancelBlood = ref(false)
const bloodNo = ref('')
const patientInfo = ref({})
const tableData = ref([])
const selectRow = ref({})
const saveLoading = ref(false)
const auditLoading = ref(false)
const printLoading = ref(false)
const searchForm = ref({
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
pageNum: 1,
pageSize: 10
})
const total = ref(0)
const scannedList = ref<Array<Record<string, string>>>([])
const bloodList = ref([])
const visible = ref(false)
const searchHandle = () => {
getTxList()
visible.value = true
}
const getTxList = () => {
searchForm.value.stime = dayjs(searchForm.value.stime).format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.etime = dayjs(searchForm.value.etime).format('YYYY-MM-DD') + ' 23:59:59'
txqueryList(searchForm.value).then(res => {
tableData.value = res.rows
total.value = res.total
})
}
const handleSearch = () => {
getTxList()
}
const jsRowclick = (row) => {
selectRow.value = row
}
const dblClickRow = (row) => {
selectRow.value = row
handleConfirm()
}
const handleConfirm = () => {
if (!selectRow.value.bill_no) return ElMessage.warning('请选择单据')
getTxInfo(selectRow.value.bill_no)
visible.value = false
}
const getTxInfo = (billNo) => {
txqueryInfo({ billNo }).then(res => {
formData.value = res.data.xkBackinMain
bloodList.value = res.data.xkBackinDetailList.map(item => {
return {
...item.xkBackinDetail,
...item.xkBloodInfo,
}
})
scannedList.value = res.data.xkBackinDetailList
})
}
const handleClose = () => {
tableData.value = []
selectRow.value = {}
searchForm.value = {
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
pageNum: 1,
pageSize: 10
}
}
const scanHandle = () => {
if (!reason.value) return ElMessage.warning('请选择退血原因')
if (!bloodInfo.value.blood_no) return
const index = bloodList.value.findIndex(item => item.blood_no == bloodInfo.value.blood_no)
if (index > -1) return ElMessage.warning("该血液流水号已被扫描过")
queryBloodInfoByBloodNo({ bloodNo: bloodInfo.value.blood_no }).then(res => {
if (res.data.length) {
const row = res.data[0]
getBloodInfo(row)
}
})
}
const getBloodInfo = (row) => {
queryBloodInfo({ bloodNo: row.blood_no, productNo: row.product_no }).then(res => {
if (!res.data) {
ElMessage.warning(res.msg)
bloodInfo.value.blood_no = ''
return
}
bloodInfo.value = res.data.xkBloodInfo || {}
patientInfo.value = res.data.patientInfoList[0] || {}
const row = {
flag: '1',
patientInfo: patientInfo.value,
xkBackinDetail: {
bill_no: formData.value.bill_no,
blood_no: bloodInfo.value.blood_no,
product_no: bloodInfo.value.product_no,
blood_breed: bloodInfo.value.blood_breed,
blood_type: bloodInfo.value.blood_type,
capacity: bloodInfo.value.capacity,
unit: bloodInfo.value.unit,
valid_date: bloodInfo.value.valid_date,
reason: reason.value,
}
}
bloodList.value.push(row.xkBackinDetail)
scannedList.value.push(row)
bloodInfo.value.blood_no = ''
})
}
const saveHandle = () => {
scannedList.value.forEach((item, i) => {
item.xkBackinDetail.sid = i + 1
})
const data = {
xkBackinMain: {
...formData.value,
@ -233,6 +365,7 @@ const saveHandle = () => {
txsaveData(data).then(res => {
if (res.code == 0) {
formData.value.bill_no = res.data
ElMessage.success("保存成功!")
}
}).finally(() => {
@ -240,75 +373,77 @@ const saveHandle = () => {
})
}
const auditHandle = () => {
if (!formData.value.bill_no) return ElMessage.warning("请选择单据!")
auditLoading.value = true
txauditData({ billNo: formData.value.bill_no }).then(res => {
if (res.code == 0) {
ElMessage.success(res.msg)
getTxInfo(formData.value.bill_no)
}
}).finally(() => {
auditLoading.value = false
})
}
const printHandle = () => {
if (!formData.value.bill_no) return ElMessage.warning("请选择单据!")
printLoading.value = true
txPrint({ billNo: formData.value.bill_no, templateName: "BLOOD_OUT_BACK" }).then(res => {
if (res.code == 0 && res.data) {
printBase64PDF(res.data)
}
}).finally(() => {
printLoading.value = false
})
}
const addHandle = () => {
formData.value = {}
formData.value = {
handle_person: userInfo.name,
back_date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
}
bloodInfo.value = {}
bloodList.value = []
scannedList.value = []
}
const getTxList = () => {
searchForm.value.stime = dayjs(searchForm.value.stime).format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.etime = dayjs(searchForm.value.etime).format('YYYY-MM-DD') + ' 23:59:59'
}
const handleSearch = () => {
getTxList()
}
const handleConfirm = () => {
if (!searchForm.value.billNo) return ElMessage.warning('请输入退血单号进行检索')
}
const jsRowclick = (row) => {
if (!row) return
getBloodInfo(row)
}
const dblClickRow = (row) => {
if (!row) return
getBloodInfo(row)
visible.value = false
}
const handleClose = () => {
}
const scanHandle = () => {
if (!reason.value) return ElMessage.warning('请选择退血原因')
if (!bloodInfo.value.blood_no) return
queryBloodInfoByBloodNo({ bloodNo: bloodInfo.value.blood_no }).then(res => {
if (res.data.length) {
const row = res.data[0]
getBloodInfo(row)
const delBlood = (row, index) => {
ElMessageBox.confirm(`确定删除${row.blood_no}血液吗?`,
'提示',
{ type: 'warning', }
).then(() => {
const data = {
bill_no: row.bill_no,
blood_no: row.blood_no,
charge_billno: row.charge_billno,
product_no: row.product_no
}
if (row.bill_no) {
deleteBloodInfo(data).then(res => {
if (res.code == 0) {
scannedList.value.splice(index, 1)
bloodList.value.splice(index, 1)
}
})
} else {
scannedList.value.splice(index, 1)
bloodList.value.splice(index, 1)
}
})
}
const getBloodInfo = (row) => {
queryBloodInfo({ bloodNo: row.blood_no, productNo: row.product_no }).then(res => {
bloodInfo.value = res.data.xkBloodInfo || {}
patientInfo.value = res.data.patientInfoList[0] || {}
const bloodClick = (row) => {
patientInfo.value = scannedList.value.find(item => item.xkBloodInfo.blood_no == row.blood_no)?.patientInfo
}
const row = {
blood_no: bloodInfo.value.blood_no,
product_no: bloodInfo.value.product_no,
blood_breed: bloodInfo.value.blood_breed,
blood_type: bloodInfo.value.blood_type,
capacity: bloodInfo.value.capacity,
unit: bloodInfo.value.unit,
validDate: bloodInfo.value.valid_date,
reason: reason.value,
sid: scannedList.value.length + 1,
}
scannedList.value.push(row)
bloodInfo.value.blood_no = ''
})
const cancelHandle = () => {
const index = scannedList.value.findIndex(item => item.blood_no == bloodNo.value)
if (index > -1) {
ElMessageBox.confirm(`确定取消血液${scannedList.value[index].blood_no}数据吗?`, '提示', { type: 'warning' }).then(() => {
scannedList.value.splice(index, 1)
bloodList.value.splice(index, 1)
})
} else {
ElMessage.warning('该血液流水号不存在,请检查!')
}
}
onMounted(() => {
@ -421,4 +556,8 @@ onMounted(() => {
:deep(.el-form-item) {
margin-bottom: 8px;
}
.cancel-box {
display: flex;
}
</style>

View File

@ -1088,6 +1088,12 @@ const deleteSingleBlood = (index: number) => {
})
}
const breedChange = (value: string) => {
const index = bloodList.value.findIndex(item => item.blood_breed === bloodForm.blood_breed)
if (index > -1) {
ElMessage.warning('该血液品种已存在')
bloodForm.blood_breed = ''
return
}
bloodForm.unit = bloodBreed.value.find(item => item.value === value)?.unit
}
// 保存血液品种表单

View File

@ -29,7 +29,7 @@
</div>
</template>
<template #report_size="{ row }">
{{ formatByteToMB(row.report_size) }}
{{ formatByteToUnit(row.report_size, 'KB') }}
</template>
<template #action="{ row }">
<el-button type="primary" text @click="handleEdit(row)">编辑</el-button>
@ -69,7 +69,7 @@
import dayjs from 'dayjs'
import { queryList, addTemplate, updateTemplate, delTemplate } from '@/api/system/template'
import { getDictData, formatDict, dictData, useCommonDict } from '@/hooks'
import { formatByteToMB } from '@/utils/classCom'
import { formatByteToUnit } from '@/utils/classCom'
import { ElMessage, ElMessageBox } from 'element-plus'
const { userList, getUserData, } = useCommonDict()
import Download from '@/plugins/download'