Files
zhyc-sheep-ui/src/views/biosafety/prescription/index.vue
2026-01-13 21:45:32 +08:00

515 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<!-- 搜索表单 -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="处方编号" prop="no">
<el-input v-model="queryParams.no" placeholder="请输入处方编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="处方名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入处方名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="类型" prop="persType">
<el-select v-model="queryParams.persType" placeholder="请选择类型" clearable style="width: 150px">
<el-option v-for="dict in pres_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 150px">
<el-option v-for="dict in pres_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 按钮组 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="prescriptionList" @selection-change="handleSelectionChange" max-height="650px">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="处方编号" align="center" prop="no" />
<el-table-column label="处方名称" align="center" prop="name" />
<el-table-column label="类型" align="center" prop="persType">
<template #default="scope">
<dict-tag :options="pres_type" :value="scope.row.persType" />
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="createBy" />
<el-table-column label="备注" align="center" prop="comment" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="pres_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="300px">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleView(scope.row)">详情</el-button>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link :type="scope.row.status ? 'warning' : 'primary'" @click="handleStatus(scope.row)">{{
scope.row.status?"禁用":"启用" }}</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" :page-sizes="[20, 50, 100, 200, 500, 1000, 2000]" @pagination="getList" />
<!-- 弹框详情/修改 -->
<el-dialog :title="title" v-model="open" width="60%" append-to-body s>
<!-- 详情页只读展示 -->
<div v-if="isView" style="padding-bottom:20px ;">
<el-descriptions :column="2" border>
<el-descriptions-item label="处方编号">{{ form.no }}</el-descriptions-item>
<el-descriptions-item label="处方名称">{{ form.name }}</el-descriptions-item>
<el-descriptions-item label="类型">
<dict-tag :options="pres_type" :value="form.persType" />
</el-descriptions-item>
<el-descriptions-item label="状态">
<dict-tag :options="pres_status" :value="form.status" />
</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">
{{ form.comment || '无' }}
</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">处方详情</el-divider>
<el-table :data="swPresDetailList" stripe border style="width: 100%" max-height="300">
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="药品" prop="mediId" align="center" :formatter="formatMedicine" />
<el-table-column label="用量" prop="dosage" />
<el-table-column label="使用方法" align="center" prop="usageId" :formatter="formatUsage" />
<el-table-column label="单位" prop="unitId" align="center" :formatter="formatUnit" />
</el-table>
</div>
<!-- 修改页可编辑表单 -->
<div v-else>
<el-form ref="prescriptionRef" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="处方编号" prop="no">
<el-input v-model="form.no" placeholder="请输入处方编号" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="处方名称" prop="name">
<el-input v-model="form.name" placeholder="请输入处方名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型" prop="persType">
<el-select v-model="form.persType" placeholder="请选择类型" style="width: 100%">
<el-option v-for="dict in pres_type" :key="dict.value" :label="dict.label"
:value="parseInt(dict.value)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="status">
<el-select v-model="form.status" placeholder="请选择状态" style="width: 100%">
<el-option v-for="dict in pres_status" :key="dict.value" :label="dict.label"
:value="parseInt(dict.value)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="comment">
<el-input type="textarea" :rows="2" v-model="form.comment" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">处方详情</el-divider>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" icon="Plus" @click="handleAddSwPresDetail()">添加</el-button>
</el-col>
</el-row>
<el-table :data="swPresDetailList" :row-class-name="rowSwPresDetailIndex"
@selection-change="handleSwPresDetailSelectionChange" ref="swPresDetail" border stripe>
<el-table-column label="序号" align="center" prop="index" width="60" />
<el-table-column label="药品" prop="mediId">
<template #default="scope">
<el-select v-model="scope.row.mediId" filterable placeholder="请选择药品" style="width: 100%">
<el-option v-for="item in medicines" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="用量" prop="dosage">
<template #default="scope">
<el-input-number v-model="scope.row.dosage" placeholder="请输入用量" :min="0" :precision="1"
controls-position="right" />
</template>
</el-table-column>
<el-table-column label="单位" prop="unitId">
<template #default="scope">
<el-select v-model="scope.row.unitId" placeholder="请选择单位">
<el-option v-for="item in units" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="使用方法" prop="usageId">
<template #default="scope">
<el-select v-model="scope.row.usageId" placeholder="请选择使用方法">
<el-option v-for="item in usages" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Delete" @click="deletePresDetail(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form>
</div>
<!-- 底部按钮仅修改页显示 -->
<template #footer v-if="!isView">
<div class="dialog-footer">
<el-button @click="cancel"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Prescription">
import { listPrescription, getPrescription, delPrescription, addPrescription, updatePrescription } from "@/api/biosafety/prescription"
import { getCurrentInstance, ref, reactive, toRefs } from 'vue'
import { listUnit } from "@/api/biosafety/unit"
import { listUsage } from "@/api/biosafety/usage"
import { listMedicine } from "@/api/biosafety/medicine"
const { proxy } = getCurrentInstance()
const { pres_status, pres_type } = proxy.useDict('pres_status', 'pres_type')
const prescriptionList = ref([]) // 主表数据
const swPresDetailList = ref([]) // 子表(处方详情)数据
const open = ref(false) // 弹窗显隐
const loading = ref(true) // 列表加载状态
const showSearch = ref(true) // 搜索栏显隐
const ids = ref([]) // 主表选中的 id 数组
const checkedSwPresDetail = ref([]) // 子表选中的行序号数组
const single = ref(true) // 是否仅选一条(控制“修改”按钮禁用)
const multiple = ref(true) // 是否至少选一条(控制“删除”按钮禁用)
const total = ref(0) // 总条数
const title = ref("") // 弹窗标题
const isView = ref(false) // 当前弹窗是否为“查看详情”模式
/* 响应式数据form、queryParams、rules */
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 20,
no: null,
name: null,
persType: null,
status: null,
},
rules: {}
})
const { queryParams, form, rules } = toRefs(data)
const units = ref([]) // 单位下拉选项
const usages = ref([]) // 使用方法下拉选项
const medicines = ref([]) // 药品下拉选项
/**
* 获取药品下拉数据源
* 将返回数据转换成 { value, label } 结构,供 el-option 使用
*/
function getMedicines() {
listMedicine().then(response => {
medicines.value = response.rows.map(item => ({
value: item.id,
label: item.name
}))
})
}
/**
* 获取单位下拉数据源(单位字典)
* 将返回数据转换成 { value, label } 结构,供 el-option 使用
*/
function getUnit() {
listUnit().then(response => {
units.value = response.rows.map(item => ({
value: item.id,
label: item.name
}))
})
}
/**
* 获取处方使用方法下拉数据源
* 将返回数据转换成 { value, label } 结构,供 el-option 使用
*/
function getUsageOptions() {
listUsage().then(response => {
usages.value = response.rows.map(item => ({
value: item.id,
label: item.name
}))
})
}
/**
* 格式化使用方法
* 根据 usageId 查找对应的使用方法名称
*/
function formatUsage(row) {
const usage = usages.value.find(item => item.value === row.usageId)
return usage ? usage.label : '未知'
}
/**
* 格式化药品
* 根据 mediId 查找对应的药品名称
*/
function formatMedicine(row) {
const medicine = medicines.value.find(item => item.value === row.mediId)
return medicine ? medicine.label : '未知'
}
/**
* 格式化单位
* 根据 unitId 查找对应的单位名称
*/
function formatUnit(row) {
const unit = units.value.find(item => item.value === row.unitId)
return unit ? unit.label : '未知'
}
/**
* 查询处方列表
* loading 状态开始时置 true接口返回后更新列表数据与总数loading 置 false
*/
function getList() {
loading.value = true
listPrescription(queryParams.value).then(response => {
prescriptionList.value = response.rows
total.value = response.total
loading.value = false
})
}
/**
* 表单/子表重置
* 将 form、swPresDetailList 重置为初始状态,并清空校验提示
*/
function reset() {
form.value = {
id: null,
no: null,
name: null,
persType: null,
comment: null,
status: null
}
swPresDetailList.value = []
proxy.resetForm("prescriptionRef")
isView.value = false
}
/**
* 搜索按钮
* 将分页重置到第一页后重新拉取数据
*/
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/**
* 重置搜索条件
* 清空 queryRef 表单后重新触发查询
*/
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
}
/**
* 主表多选回调
* 更新 ids 数组,并设置 single / multiple 按钮禁用状态
*/
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id)
single.value = selection.length !== 1 // 只有一条时才允许“修改”
multiple.value = !selection.length // 至少一条时才允许“删除”
}
/**
* 新增按钮
* 重置表单、打开弹窗、设置标题为“添加处方”
*/
function handleAdd() {
reset()
form.value.no = `P${Date.now()}` // 自动生成处方编号
open.value = true
title.value = "添加处方"
}
/**
* 查看详情
* 根据 id 拉取单条记录及子表数据,弹窗只读展示
*/
function handleView(row) {
reset()
const _id = row.id || ids.value
getPrescription(_id).then(response => {
form.value = response.data
swPresDetailList.value = response.data.swPresDetailList
open.value = true
title.value = "处方详情"
isView.value = true
})
}
/**
* 修改按钮
* 与查看详情共用接口,但弹窗可编辑
*/
function handleUpdate(row) {
reset()
const _id = row.id || ids.value
getPrescription(_id).then(response => {
form.value = response.data
swPresDetailList.value = response.data.swPresDetailList
open.value = true
title.value = "修改处方"
isView.value = false
})
}
// 提交按钮
function handleStatus(row) {
const _id = row.id || ids.value
const newStatus = row.status ? 0 : 1 // 切换状态
proxy.$modal.confirm(`是否确认将 ${row.name }处方${row.status ? '禁用' : '启用'}`).then(() => {
return updatePrescription({ id: _id, status: newStatus })
}).then(() => {
proxy.$modal.msgSuccess(`处方${row.status ? '禁用' : '启用'}成功`)
getList() // 刷新列表
}).catch(() => {
loading.value = false
})
}
/**
* 提交表单(新增/修改)
* 先校验,再把子表数据合并到 form 中,最后根据 id 判断是新增还是更新
*/
function submitForm() {
proxy.$refs["prescriptionRef"].validate(valid => {
if (valid) {
form.value.swPresDetailList = swPresDetailList.value
if (form.value.id) {
updatePrescription(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addPrescription(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/**
* 删除按钮(单条/批量)
* 弹出确认框后调用接口删除,成功后刷新列表
*/
function handleDelete(row) {
const _ids = row.id || ids.value
proxy.$modal.confirm(`是否确认删除处方编号为"${_ids}"的数据项?`).then(() => {
return delPrescription(_ids)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
})
}
/**
* 子表行序号计算
* 通过 el-table 的 row-class-name 钩子给每一行写入 index从 1 开始)
*/
function rowSwPresDetailIndex({ row, rowIndex }) {
row.index = rowIndex + 1
}
/**
* 子表“添加”按钮
* 往 swPresDetailList 追加一条空记录
*/
function handleAddSwPresDetail() {
swPresDetailList.value.push({ mediId: '', dosage: '', unitId: '', usageId: '' })
}
/**
* 子表“删除”按钮
*
*/
function deletePresDetail(row) {
const index = swPresDetailList.value.findIndex(item => item.index === row.index)
if (index !== -1) {
swPresDetailList.value.splice(index, 1)
}
}
/**
* 子表多选回调
* 记录被选中的行序号数组
*/
function handleSwPresDetailSelectionChange(selection) {
checkedSwPresDetail.value = selection.map(item => item.index)
}
function cancel() {
open.value = false
reset()
}
/**
* 导出按钮
* 调用后端通用导出接口,文件名带时间戳
*/
function handleExport() {
proxy.download('biosafety/prescription/export', { ...queryParams.value }, `处方_${Date.now()}.xlsx`)
}
// 初始化:加载列表
getList()
getUnit() // 获取单位下拉数据源
getUsageOptions() // 获取使用方法下拉数据源
getMedicines() // 获取药品下拉数据源
</script>