药房查询医生列表

This commit is contained in:
zoujiandong
2026-09-07 15:26:40 +08:00
parent 04b2bd280e
commit c3866e1134
5 changed files with 452 additions and 3 deletions
+26
View File
@@ -90,3 +90,29 @@ export function deletePharmacy(pharmacy_id) {
method: 'delete', method: 'delete',
}); });
} }
/**
* 获取药房绑定的医生列表-分页
* @param {Object} data - { pharmacy_id: string, page?: number, page_size?: number, doctor_name?: string, mobile?: string }
* @returns {Promise}
*/
export function getPharmacyDoctorPage(data) {
return request({
url: '/admin/basic/pharmacy/doctor/page',
method: 'post',
data,
});
}
/**
* 获取药房绑定的医生列表(全部/不分页)
* @param {String} pharmacy_id - 药房 ID
* @returns {Promise}
*/
export function getPharmacyDoctorList(pharmacy_id) {
return request({
url: `/admin/basic/pharmacy/doctor/${pharmacy_id}`,
method: 'get',
});
}
@@ -0,0 +1,400 @@
<template>
<a-drawer
v-model:visible="visible"
:title="drawerTitle"
:width="920"
:footer="false"
@cancel="handleClose"
>
<!-- 药房信息摘要卡片 -->
<a-card :bordered="false" class="pharmacy-summary-card">
<div class="pharmacy-info-box">
<div class="pharmacy-icon-box">
<icon-home style="font-size: 28px; color: #165dff" />
</div>
<div class="pharmacy-meta">
<div class="pharmacy-meta-title">
<span class="name">{{ currentPharmacy?.pharmacy_name || '-' }}</span>
<a-tag color="blue" size="small" style="margin-left: 8px">
{{ currentPharmacy?.pharmacy_code || '-' }}
</a-tag>
<a-tag v-if="currentPharmacy?.status === 1" color="green" size="small" style="margin-left: 4px">
运营中
</a-tag>
<a-tag v-else color="red" size="small" style="margin-left: 4px">
已停用
</a-tag>
</div>
<div class="pharmacy-meta-desc">
<span><strong>基础邮费:</strong>¥{{ Number(currentPharmacy?.postage || 0).toFixed(2) }}</span>
<span style="margin-left: 20px">
<strong>包邮门槛:</strong>
{{ Number(currentPharmacy?.free_shipping_threshold) > 0 ? `¥${Number(currentPharmacy.free_shipping_threshold).toFixed(2)}` : '不设门槛' }}
</span>
<span style="margin-left: 20px">
<strong>支持自提:</strong>{{ currentPharmacy?.is_pickup === 1 ? '是' : '否' }}
</span>
<span style="margin-left: 20px">
<strong>联系电话:</strong>{{ currentPharmacy?.telephone || '-' }}
</span>
</div>
<div class="pharmacy-meta-address">
<strong>详细地址:</strong>{{ currentPharmacy?.full_address || currentPharmacy?.address || '-' }}
</div>
</div>
</div>
</a-card>
<a-divider style="margin: 16px 0" />
<!-- 筛选表单 -->
<a-form :model="queryForm" ref="queryFormRef" layout="inline" class="search-form">
<a-form-item field="doctor_name" label="医生姓名">
<a-input
v-model="queryForm.doctor_name"
placeholder="请输入医生姓名"
allow-clear
style="width: 170px"
@press-enter="handleQuery"
/>
</a-form-item>
<a-form-item field="mobile" label="手机号码">
<a-input
v-model="queryForm.mobile"
placeholder="请输入手机号码"
allow-clear
style="width: 170px"
@press-enter="handleQuery"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" size="small" @click="handleQuery">
<template #icon><icon-search /></template>
搜索
</a-button>
<a-button size="small" @click="handleResetQuery">
<template #icon><icon-loop /></template>
重置
</a-button>
</a-space>
</a-form-item>
</a-form>
<!-- 医生列表表格 -->
<a-table
:columns="columns"
:data="tableData"
:loading="loading"
:pagination="paginationProps"
row-key="doctor_pharmacy_id"
:scroll="{ x: 860 }"
style="margin-top: 14px"
@page-change="handlePageChange"
@page-size-change="handlePageSizeChange"
>
<!-- 序号 -->
<template #index="{ rowIndex }">
{{ (pager.page - 1) * pager.page_size + rowIndex + 1 }}
</template>
<!-- 医生信息 -->
<template #doctor="{ record }">
<div class="doctor-cell">
<a-avatar :size="36" shape="circle">
<img v-if="record.avatar" :src="record.avatar" alt="avatar" />
<icon-user v-else />
</a-avatar>
<div class="doctor-cell-info">
<div class="doctor-name">{{ record.user_name || '-' }}</div>
<a-tag size="mini" color="blue">{{ record.doctor_title_name || '医生' }}</a-tag>
</div>
</div>
</template>
<!-- 所属医院与科室 -->
<template #hospital="{ record }">
<div>{{ record.hospital_name || '-' }}</div>
<div style="font-size: 12px; color: #86909c">{{ record.department_custom_name || '-' }}</div>
</template>
<!-- 是否默认 -->
<template #is_default="{ record }">
<a-tag v-if="record.is_default === 1" color="arcoblue" size="small">
<template #icon><icon-check-circle-fill /></template>
首选默认
</a-tag>
<a-tag v-else color="gray" size="small">普通关联</a-tag>
</template>
<!-- 操作列 -->
<template #action="{ record }">
<a-space :size="4">
<a-button type="text" size="small" @click="handleViewDoctor(record)">
<template #icon><icon-eye /></template>
档案
</a-button>
<a-popconfirm
v-if="hasPermission('admin:doctorPharmacy:remove')"
content="确定解除该医生与当前药房的绑定关系?"
type="warning"
@ok="handleRemoveBinding(record)"
>
<a-button type="text" status="danger" size="small">
<template #icon><icon-delete /></template>
解绑
</a-button>
</a-popconfirm>
</a-space>
</template>
</a-table>
<!-- 公共医生详情模态弹窗 -->
<DoctorModal
:doctorVisible="doctorModalVisible"
:doctor_id="selectedDoctorId"
@doctorVisibleChange="() => { doctorModalVisible = false; selectedDoctorId = ''; }"
/>
</a-drawer>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { Message } from '@arco-design/web-vue';
import { usePermissionStore } from '@/store/permission';
import { getPharmacyDoctorPage } from '@/api/basic/pharmacy';
import { removeDoctorPharmacy } from '@/api/doctor/pharmacy';
import DoctorModal from '@/components/doctorModal.vue';
const permissionStore = usePermissionStore();
// 权限校验
const hasPermission = (permission) => {
const perms = permissionStore.buttonPermissions || [];
return perms.includes('*') || perms.includes(permission);
};
const visible = ref(false);
const loading = ref(false);
const currentPharmacy = ref(null);
const tableData = ref([]);
// 医生弹窗查看状态
const doctorModalVisible = ref(false);
const selectedDoctorId = ref('');
const queryFormRef = ref(null);
const queryForm = reactive({
doctor_name: '',
mobile: '',
});
const pager = reactive({
page: 1,
page_size: 10,
total: 0,
});
const paginationProps = computed(() => ({
total: pager.total,
current: pager.page,
pageSize: pager.page_size,
showTotal: true,
showJumper: true,
showPageSize: true,
pageSizeOptions: [10, 20, 50],
}));
const drawerTitle = computed(() => {
const name = currentPharmacy.value?.pharmacy_name || '';
return name ? `关联医生列表 - ${name}` : '关联医生列表';
});
// 表格列配置
const columns = [
{ title: '#', slotName: 'index', width: 50, align: 'center' },
{ title: '医生信息', slotName: 'doctor', width: 170 },
{ title: '手机号码', dataIndex: 'mobile', width: 130 },
{ title: '执业机构与科室', slotName: 'hospital', minWidth: 180 },
{ title: '默认状态', slotName: 'is_default', width: 110, align: 'center' },
{ title: '绑定时间', dataIndex: 'bind_time', width: 170 },
{ title: '操作', slotName: 'action', width: 130, align: 'center', fixed: 'right' },
];
// 获取药房绑定的医生列表数据
const fetchTableData = async () => {
if (!currentPharmacy.value?.pharmacy_id) return;
loading.value = true;
try {
const params = {
pharmacy_id: String(currentPharmacy.value.pharmacy_id),
page: pager.page,
page_size: pager.page_size,
};
if (queryForm.doctor_name) params.doctor_name = queryForm.doctor_name;
if (queryForm.mobile) params.mobile = queryForm.mobile;
const res = await getPharmacyDoctorPage(params);
if (res.code === 200 && res.data) {
tableData.value = res.data.data || [];
pager.total = res.data.total || 0;
pager.page = res.data.page || 1;
pager.page_size = res.data.page_size || 10;
} else {
Message.error(res.message || '获取药房关联医生列表失败');
}
} catch (error) {
console.error('获取关联医生列表异常:', error);
} finally {
loading.value = false;
}
};
// 搜索
const handleQuery = () => {
pager.page = 1;
fetchTableData();
};
// 重置搜索
const handleResetQuery = () => {
queryForm.doctor_name = '';
queryForm.mobile = '';
pager.page = 1;
fetchTableData();
};
// 分页变化
const handlePageChange = (page) => {
pager.page = page;
fetchTableData();
};
const handlePageSizeChange = (pageSize) => {
pager.page_size = pageSize;
pager.page = 1;
fetchTableData();
};
// 查看医生档案
const handleViewDoctor = (record) => {
selectedDoctorId.value = String(record.doctor_id);
doctorModalVisible.value = true;
};
// 解绑医生
const handleRemoveBinding = async (record) => {
try {
const res = await removeDoctorPharmacy(
record.doctor_pharmacy_id || record.pharmacy_id
);
if (res.code === 200) {
Message.success('已解除医生绑定');
if (tableData.value.length === 1 && pager.page > 1) {
pager.page -= 1;
}
fetchTableData();
} else {
Message.error(res.message || '解除绑定失败');
}
} catch (error) {
Message.error('解除绑定出现异常');
}
};
// 打开抽屉
const open = (pharmacy) => {
currentPharmacy.value = pharmacy;
queryForm.doctor_name = '';
queryForm.mobile = '';
pager.page = 1;
visible.value = true;
fetchTableData();
};
const handleClose = () => {
visible.value = false;
};
defineExpose({
open,
});
</script>
<style lang="scss" scoped>
.pharmacy-summary-card {
background-color: #f7f8fa;
border-radius: 6px;
:deep(.arco-card-body) {
padding: 12px 16px;
}
}
.pharmacy-info-box {
display: flex;
align-items: flex-start;
.pharmacy-icon-box {
width: 48px;
height: 48px;
border-radius: 8px;
background-color: #e8f3ff;
display: flex;
justify-content: center;
align-items: center;
margin-right: 14px;
flex-shrink: 0;
}
.pharmacy-meta {
flex: 1;
.pharmacy-meta-title {
display: flex;
align-items: center;
.name {
font-size: 16px;
font-weight: 600;
color: #1d2129;
}
}
.pharmacy-meta-desc {
margin-top: 6px;
font-size: 13px;
color: #4e5969;
}
.pharmacy-meta-address {
margin-top: 4px;
font-size: 13px;
color: #86909c;
}
}
}
.search-form {
:deep(.arco-form-item) {
margin-bottom: 8px;
}
}
.doctor-cell {
display: flex;
align-items: center;
.doctor-cell-info {
margin-left: 10px;
.doctor-name {
font-weight: 500;
color: #1d2129;
margin-bottom: 2px;
}
}
}
</style>
+20 -1
View File
@@ -219,6 +219,15 @@
<template #icon><icon-edit /></template> <template #icon><icon-edit /></template>
修改 修改
</a-button> </a-button>
<a-button
v-if="hasPermission('admin:sysPharmacy:doctor')"
type="text"
size="small"
@click="handleOpenDoctorDrawer(record)"
>
<template #icon><icon-user-group /></template>
关联医生
</a-button>
<a-popconfirm <a-popconfirm
v-if="hasPermission('admin:sysPharmacy:remove')" v-if="hasPermission('admin:sysPharmacy:remove')"
content="确定要删除此药房吗?删除后不可恢复!" content="确定要删除此药房吗?删除后不可恢复!"
@@ -236,6 +245,9 @@
<!-- 新增 / 编辑 / 详情 弹窗 --> <!-- 新增 / 编辑 / 详情 弹窗 -->
<PharmacyModal ref="modalRef" @success="handleQuery" /> <PharmacyModal ref="modalRef" @success="handleQuery" />
<!-- 关联医生列表抽屉 -->
<PharmacyDoctorDrawer ref="doctorDrawerRef" />
</div> </div>
</template> </template>
@@ -246,6 +258,7 @@ import { usePermissionStore } from '@/store/permission';
import { getPharmacyPage, updatePharmacyStatus, deletePharmacy } from '@/api/basic/pharmacy'; import { getPharmacyPage, updatePharmacyStatus, deletePharmacy } from '@/api/basic/pharmacy';
import { getAdminAreaList } from '@/api/basic/list'; import { getAdminAreaList } from '@/api/basic/list';
import PharmacyModal from './components/pharmacyModal.vue'; import PharmacyModal from './components/pharmacyModal.vue';
import PharmacyDoctorDrawer from './components/pharmacyDoctorDrawer.vue';
const permissionStore = usePermissionStore(); const permissionStore = usePermissionStore();
@@ -257,6 +270,7 @@ const hasPermission = (permission) => {
const queryFormRef = ref(null); const queryFormRef = ref(null);
const modalRef = ref(null); const modalRef = ref(null);
const doctorDrawerRef = ref(null);
const tableLoading = ref(false); const tableLoading = ref(false);
const tableData = ref([]); const tableData = ref([]);
@@ -306,7 +320,7 @@ const columns = [
{ title: '地址', slotName: 'full_address', minWidth: 240 }, { title: '地址', slotName: 'full_address', minWidth: 240 },
{ title: '状态', slotName: 'status', width: 100, align: 'center' }, { title: '状态', slotName: 'status', width: 100, align: 'center' },
{ title: '创建时间', dataIndex: 'created_at', width: 180 }, { title: '创建时间', dataIndex: 'created_at', width: 180 },
{ title: '操作', slotName: 'action', width: 260, fixed: 'right', align: 'center' }, { title: '操作', slotName: 'action', width: 280, fixed: 'right', align: 'center' },
]; ];
// 获取区域信息 // 获取区域信息
@@ -445,6 +459,11 @@ const handleEdit = (record) => {
modalRef.value?.open('edit', record.pharmacy_id); modalRef.value?.open('edit', record.pharmacy_id);
}; };
// 关联医生
const handleOpenDoctorDrawer = (record) => {
doctorDrawerRef.value?.open(record);
};
// 状态切换 // 状态切换
const handleStatusToggle = async (record, val) => { const handleStatusToggle = async (record, val) => {
const newStatus = val ? 1 : 0; const newStatus = val ? 1 : 0;
@@ -299,11 +299,13 @@ const open = async (doctor) => {
currentDoctor.value = doctor; currentDoctor.value = doctor;
visible.value = true; visible.value = true;
await fetchDoctorPharmacies(); await fetchDoctorPharmacies();
fetchAllPharmacies();
}; };
// 打开新增绑定弹窗 // 打开新增绑定弹窗
const openAddModal = () => { const openAddModal = () => {
if (allPharmacies.value.length === 0) {
fetchAllPharmacies();
}
addForm.pharmacy_id = undefined; addForm.pharmacy_id = undefined;
// 若当前尚未绑定任何药房,默认勾选设为默认 // 若当前尚未绑定任何药房,默认勾选设为默认
addForm.is_default = pharmacyList.value.length === 0 ? 1 : 0; addForm.is_default = pharmacyList.value.length === 0 ? 1 : 0;
+3 -1
View File
@@ -832,6 +832,7 @@ const handleOpenPharmacyDrawer = (record) => {
pharmacyDrawerRef.value?.open(record); pharmacyDrawerRef.value?.open(record);
}; };
const loadPharmacyOptions = async () => { const loadPharmacyOptions = async () => {
if (pharmacyOptions.value.length > 0) return;
try { try {
const res = await getPharmacyList({ status: 1 }); const res = await getPharmacyList({ status: 1 });
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
@@ -1183,6 +1184,7 @@ const changeSelect = (value) => {
// 新增Satus // 新增Satus
const handleAdd = () => { const handleAdd = () => {
loadPharmacyOptions();
modalVisible.value = true; modalVisible.value = true;
modalTitle.value = '新增医生'; modalTitle.value = '新增医生';
modalSatus.value = 'add'; modalSatus.value = 'add';
@@ -1279,6 +1281,7 @@ const handleDetail = async (record) => {
}; };
// 修改 // 修改
const handleUpdate = async (record) => { const handleUpdate = async (record) => {
loadPharmacyOptions();
modalVisible.value = true; modalVisible.value = true;
modalTitle.value = '修改医生'; modalTitle.value = '修改医生';
modalSatus.value = 'edit'; modalSatus.value = 'edit';
@@ -1868,7 +1871,6 @@ onMounted(() => {
handlExpertiseList(); handlExpertiseList();
handelAreaList("", "", 2); handelAreaList("", "", 2);
handleBankList(); handleBankList();
loadPharmacyOptions();
}); });
</script> </script>