Files
zyt/admin/src/views/consumer/prescription/list.vue
T
2026-06-04 15:11:16 +08:00

417 lines
16 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="prescription-library">
<el-card class="!border-none" shadow="never">
<el-form class="mb-[-16px]" :model="formData" inline>
<el-form-item class="w-[280px]" label="处方名称">
<el-input
v-model="formData.prescription_name"
placeholder="请输入处方名称"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item class="w-[200px]" label="处方类型">
<el-select v-model="formData.formula_type" placeholder="全部" clearable>
<el-option label="全部" :value="''" />
<el-option label="主方" value="主方" />
<el-option label="辅方" value="辅方" />
</el-select>
</el-form-item>
<el-form-item class="w-[200px]" label="是否公开">
<el-select v-model="formData.is_public" placeholder="全部" clearable>
<el-option label="全部" :value="''" />
<el-option label="仅自己可见" :value="0" />
<el-option label="所有人可见" :value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card v-loading="pager.loading" class="mt-4 !border-none" shadow="never">
<el-button type="primary" @click="handleAdd" v-perms="['wcf.prescription/add']">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增处方
</el-button>
<div class="mt-4">
<el-table :data="pager.lists" size="large">
<el-table-column label="ID" prop="id" min-width="60" />
<el-table-column label="处方名称" prop="prescription_name" min-width="200" show-overflow-tooltip />
<el-table-column label="处方类型" min-width="100">
<template #default="{ row }">
<el-tag :type="row.formula_type === '辅方' ? 'warning' : 'primary'" size="small">
{{ row.formula_type || '主方' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="药材数量" min-width="100">
<template #default="{ row }">
{{ row.herbs?.length || 0 }}
</template>
</el-table-column>
<el-table-column label="药材明细" min-width="300" show-overflow-tooltip>
<template #default="{ row }">
<span v-if="row.herbs && row.herbs.length > 0">
{{ row.herbs.map((h: any) => `${h.name} ${h.dosage}g`).join('、') }}
</span>
<span v-else class="text-gray-400">暂无药材</span>
</template>
</el-table-column>
<el-table-column label="是否公开" min-width="120">
<template #default="{ row }">
<el-tag :type="row.is_public ? 'success' : 'info'">
{{ row.is_public ? '所有人可见' : '仅自己可见' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="禁用修改" min-width="100">
<template #default="{ row }">
<el-tag :type="row.disable_edit ? 'danger' : 'info'">
{{ row.disable_edit ? '已禁用' : '可修改' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="创建人" prop="creator_name" min-width="100" />
<el-table-column label="创建时间" prop="create_time" min-width="160" />
<el-table-column label="操作" width="180" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleView(row)" v-perms="['wcf.prescription/read']">
查看
</el-button>
<el-button
v-if="canEditPrescription(row)"
type="primary"
link
@click="handleEdit(row)"
v-perms="['wcf.prescription/edit']"
>
编辑
</el-button>
<el-button
v-if="canDeletePrescription(row)"
type="danger"
link
@click="handleDelete(row.id)"
v-perms="['wcf.prescription/delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex mt-4 justify-end">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<!-- 新增/编辑弹窗 -->
<el-dialog
v-model="showEdit"
:title="editMode === 'add' ? '新增处方' : editMode === 'edit' ? '编辑处方' : '查看处方'"
width="800px"
:close-on-click-modal="false"
>
<el-form
ref="formRef"
:model="editForm"
:rules="rules"
label-width="120px"
:disabled="editMode === 'view'"
>
<el-form-item label="处方名称" prop="prescription_name">
<el-input
v-model="editForm.prescription_name"
placeholder="请输入处方名称,例如:六味地黄丸、补中益气汤"
maxlength="100"
show-word-limit
/>
</el-form-item>
<el-form-item label="处方类型" prop="formula_type">
<el-radio-group v-model="editForm.formula_type">
<el-radio value="主方">主方</el-radio>
<el-radio value="辅方">辅方</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="药材配方" prop="herbs" required>
<div class="w-full">
<el-button
type="primary"
size="small"
@click="addHerb"
:disabled="editMode === 'view'"
>
添加药材
</el-button>
<el-table :data="editForm.herbs" class="mt-2" border>
<el-table-column label="序号" type="index" width="60" />
<el-table-column label="药材名称" min-width="220">
<template #default="{ row }">
<MedicineNameSelect v-model="row.name" :disabled="editMode === 'view'" />
</template>
</el-table-column>
<el-table-column label="剂量(克)" min-width="150">
<template #default="{ row }">
<el-input-number
v-model="row.dosage"
:min="0"
:precision="1"
:step="0.5"
placeholder="剂量"
class="w-full"
:disabled="editMode === 'view'"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="80" v-if="editMode !== 'view'">
<template #default="{ $index }">
<el-button
type="danger"
link
@click="removeHerb($index)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-form-item>
<el-form-item label="是否公开" prop="is_public">
<el-switch
v-model="editForm.is_public"
:active-value="1"
:inactive-value="0"
active-text="所有人可见"
inactive-text="仅自己可见"
/>
<div class="text-xs text-gray-400 mt-1">
勾选后所有医生都可以查看和使用此处方模板
</div>
</el-form-item>
<el-form-item label="禁用修改" prop="disable_edit">
<div class="flex flex-col gap-1 leading-none">
<el-switch
v-model="editForm.disable_edit"
:active-value="1"
:inactive-value="0"
active-text="开启"
inactive-text="关闭"
/>
<div class="text-xs text-gray-400 leading-relaxed">
开启后导入此模板到处方时将锁定整张处方的药材不可增删改只能再次导入覆盖
</div>
</div>
</el-form-item>
</el-form>
<template #footer v-if="editMode !== 'view'">
<el-button @click="showEdit = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">
确定
</el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="prescriptionLibrary">
import {
prescriptionLibraryLists,
prescriptionLibraryAdd,
prescriptionLibraryEdit,
prescriptionLibraryDelete
} from '@/api/tcm'
import { usePaging } from '@/hooks/usePaging'
import useUserStore from '@/stores/modules/user'
import feedback from '@/utils/feedback'
import type { FormInstance, FormRules } from 'element-plus'
import MedicineNameSelect from '@/components/medicine-name-select/index.vue'
// 表单数据
const formData = reactive({
prescription_name: '',
formula_type: '',
is_public: ''
})
const showEdit = ref(false)
const editMode = ref<'add' | 'edit' | 'view'>('add')
const submitLoading = ref(false)
const formRef = ref<FormInstance>()
// 编辑表单
const editForm = reactive({
id: 0,
prescription_name: '',
formula_type: '主方',
herbs: [] as Array<{ name: string; dosage: number }>,
is_public: 0,
disable_edit: 0
})
// 表单验证规则
const rules: FormRules = {
prescription_name: [
{ required: true, message: '请输入处方名称', trigger: 'blur' }
]
}
const userStore = useUserStore()
/** 与 server/config/project.php prescription_library_manage_all_roles 保持一致 */
const PRESCRIPTION_MANAGE_ALL_ROLE_IDS = [0, 3]
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: prescriptionLibraryLists,
params: formData
})
const isPrescriptionOwner = (row: { creator_id?: number | string }) =>
Number(row.creator_id) === Number(userStore.userInfo?.id)
/** 超管或管理员角色:可编辑/删除任意处方(与后端 canManageAllPrescriptions 一致) */
const userCanManageAllPrescriptions = () => {
const u = userStore.userInfo
if (!u) return false
if (Number(u.root) === 1) return true
const ids = Array.isArray(u.role_ids) ? u.role_ids.map((n: unknown) => Number(n)) : []
return PRESCRIPTION_MANAGE_ALL_ROLE_IDS.some((rid) => ids.includes(rid))
}
const canEditPrescription = (row: { creator_id?: number | string }) =>
userCanManageAllPrescriptions() || isPrescriptionOwner(row)
const canDeletePrescription = canEditPrescription
// 添加药材
const addHerb = () => {
editForm.herbs.push({
name: '',
dosage: 0
})
}
// 删除药材
const removeHerb = (index: number) => {
editForm.herbs.splice(index, 1)
}
// 重置表单
const resetForm = () => {
editForm.id = 0
editForm.prescription_name = ''
editForm.formula_type = '主方'
editForm.herbs = []
editForm.is_public = 0
editForm.disable_edit = 0
}
// 新增处方
const handleAdd = () => {
resetForm()
editMode.value = 'add'
showEdit.value = true
}
// 查看处方
const handleView = (row: any) => {
editMode.value = 'view'
editForm.id = row.id
editForm.prescription_name = row.prescription_name || ''
editForm.formula_type = row.formula_type || '主方'
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
editForm.is_public = row.is_public ?? 0
editForm.disable_edit = row.disable_edit ?? 0
showEdit.value = true
}
// 编辑处方
const handleEdit = (row: any) => {
editMode.value = 'edit'
editForm.id = row.id
editForm.prescription_name = row.prescription_name || ''
editForm.formula_type = row.formula_type || '主方'
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
editForm.is_public = row.is_public ?? 0
editForm.disable_edit = row.disable_edit ?? 0
showEdit.value = true
}
// 提交表单
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate()
// 验证药材
if (!editForm.herbs || editForm.herbs.length === 0) {
feedback.msgError('请至少添加一味药材')
return
}
for (let i = 0; i < editForm.herbs.length; i++) {
const herb = editForm.herbs[i]
if (!herb.name || !herb.name.trim()) {
feedback.msgError(`第${i + 1}味药材名称不能为空`)
return
}
if (!herb.dosage || herb.dosage <= 0) {
feedback.msgError(`第${i + 1}味药材剂量必须大于0`)
return
}
}
submitLoading.value = true
try {
const params = { ...editForm }
if (editMode.value === 'add') {
await prescriptionLibraryAdd(params)
feedback.msgSuccess('添加成功')
} else {
await prescriptionLibraryEdit(params)
feedback.msgSuccess('编辑成功')
}
showEdit.value = false
getLists()
} catch (error) {
console.error(error)
} finally {
submitLoading.value = false
}
}
// 删除处方
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除该处方吗?')
await prescriptionLibraryDelete({ id })
feedback.msgSuccess('删除成功')
getLists()
}
onMounted(() => {
getLists()
})
</script>
<style scoped lang="scss">
.prescription-library {
padding: 20px;
}
</style>