feat: 病历模块优化
This commit is contained in:
@@ -37,6 +37,13 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
width: 160,
|
||||
slots: { default: 'online_consultation_config' },
|
||||
},
|
||||
{
|
||||
field: 'prescription_types_config',
|
||||
align: 'left',
|
||||
title: '开方种类',
|
||||
width: 200,
|
||||
slots: { default: 'prescription_types_config' },
|
||||
},
|
||||
{
|
||||
field: 'store_config_1',
|
||||
align: 'left',
|
||||
|
||||
@@ -35,6 +35,7 @@ import StoreBasicInfoCell from '#/views/system/store/components/cells/StoreBasic
|
||||
import StoreConfigTogglesCell from '#/views/system/store/components/cells/StoreConfigTogglesCell.vue';
|
||||
// 导入绑定在线复诊配置弹窗(使用store的组件)
|
||||
import BindConsultationModal from '#/views/system/store/components/BindConsultationModal.vue';
|
||||
import BindPrescriptionTypesModal from '#/views/system/store/components/BindPrescriptionTypesModal.vue';
|
||||
import DrugPriceModal from '#/views/system/store/components/DrugPriceModal.vue';
|
||||
import StoreExternalFieldModal from '#/views/system/store/components/StoreExternalFieldModal.vue';
|
||||
import StoreCardModal from '#/components/store-card/StoreCardModal.vue';
|
||||
@@ -46,6 +47,7 @@ import { getStoreBankCardReportDetail } from '#/views/system/store-bank-card/api
|
||||
import { formOptions } from './config/search';
|
||||
// 导入表格配置
|
||||
import { gridOptions } from './config/table';
|
||||
import { prescriptionTypeLabel } from '#/views/system/store/config/prescription-type-constants';
|
||||
import { canManageStoreBankCard } from '#/views/system/admin/_shared/platform-admin-role';
|
||||
|
||||
const userStore = useUserStore();
|
||||
@@ -128,6 +130,10 @@ const [BindConsultationModalComponent, bindConsultationModalApi] = useVbenModal(
|
||||
connectedComponent: BindConsultationModal,
|
||||
});
|
||||
|
||||
const [BindPrescriptionTypesModalComponent, bindPrescriptionTypesModalApi] = useVbenModal({
|
||||
connectedComponent: BindPrescriptionTypesModal,
|
||||
});
|
||||
|
||||
const [StoreExternalFieldModalComponent, storeExternalFieldModalApi] = useVbenModal({
|
||||
connectedComponent: StoreExternalFieldModal,
|
||||
});
|
||||
@@ -247,6 +253,26 @@ const showBindConsultationModal = (row: any) => {
|
||||
bindConsultationModalApi.open();
|
||||
};
|
||||
|
||||
/** 打开绑定开方种类弹窗 */
|
||||
const showBindPrescriptionTypesModal = (row: any) => {
|
||||
bindPrescriptionTypesModalApi.setData({
|
||||
values: row,
|
||||
gridApi,
|
||||
});
|
||||
bindPrescriptionTypesModalApi.open();
|
||||
};
|
||||
|
||||
/** 列表摘要:已绑种类数 + 默认种类名 */
|
||||
function prescriptionTypesSummary(row: any) {
|
||||
const allowed = Array.isArray(row?.allowed_prescription_types)
|
||||
? row.allowed_prescription_types
|
||||
: [];
|
||||
if (!allowed.length) return '未绑定';
|
||||
const def = Number(row?.default_prescription_type) || 0;
|
||||
const defLabel = def ? prescriptionTypeLabel(def) : '';
|
||||
return defLabel ? `${allowed.length}种 · 默认${defLabel}` : `${allowed.length}种`;
|
||||
}
|
||||
|
||||
// 显示表单弹窗(新增或编辑)
|
||||
const showModal = (data = {}, isUpdate = false) => {
|
||||
formModalApi.setData({
|
||||
@@ -391,6 +417,7 @@ const batchSyncDrugPrice = () => {
|
||||
<QrCodePreviewModal />
|
||||
<DrugPriceModalComponent />
|
||||
<BindConsultationModalComponent />
|
||||
<BindPrescriptionTypesModalComponent />
|
||||
<StoreExternalFieldModalComponent />
|
||||
<Grid>
|
||||
<template #toolbar-buttons>
|
||||
@@ -532,6 +559,23 @@ const batchSyncDrugPrice = () => {
|
||||
绑定
|
||||
</Button>
|
||||
</template>
|
||||
<template #prescription_types_config="{ row }">
|
||||
<div
|
||||
class="cursor-pointer hover:text-blue-500"
|
||||
@click="showBindPrescriptionTypesModal(row)"
|
||||
>
|
||||
<Tag
|
||||
:color="
|
||||
Array.isArray(row.allowed_prescription_types) &&
|
||||
row.allowed_prescription_types.length
|
||||
? 'success'
|
||||
: 'default'
|
||||
"
|
||||
>
|
||||
{{ prescriptionTypesSummary(row) }}
|
||||
</Tag>
|
||||
</div>
|
||||
</template>
|
||||
<template #start-time="{ row }">
|
||||
早:<Tag color="success">{{ row.start_time }}</Tag>
|
||||
<br />
|
||||
|
||||
@@ -32,6 +32,17 @@ export async function bindOnlineConsultationApi(data: {
|
||||
return requestClient.post<any>(`${prefix}bind-online-consultation`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定门店可开方药品种类与默认种类
|
||||
*/
|
||||
export async function bindPrescriptionTypesApi(data: {
|
||||
id: number;
|
||||
allowed_prescription_types: number[];
|
||||
default_prescription_type: number;
|
||||
}) {
|
||||
return requestClient.post<any>(`${prefix}bind-prescription-types`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定特色方默认挂号医生
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
<script lang="ts" setup>
|
||||
/**
|
||||
* 绑定门店可开方药品种类与默认种类
|
||||
* 为什么独立弹窗:诊所/药店列表共用,整表替换中间表绑定
|
||||
*/
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { Checkbox, CheckboxGroup, Form, FormItem, message, Radio, RadioGroup } from 'ant-design-vue';
|
||||
|
||||
import { bindPrescriptionTypesApi } from '../api';
|
||||
import {
|
||||
STORE_PRESCRIPTION_TYPE_OPTIONS,
|
||||
} from '../config/prescription-type-constants';
|
||||
|
||||
const formState = ref({
|
||||
id: undefined as number | undefined,
|
||||
allowed_prescription_types: [] as number[],
|
||||
default_prescription_type: undefined as number | undefined,
|
||||
});
|
||||
|
||||
const gridApiRef = ref<any>(null);
|
||||
const loading = ref(false);
|
||||
|
||||
/** 默认种类只能从已勾选里选 */
|
||||
const defaultOptions = computed(() =>
|
||||
STORE_PRESCRIPTION_TYPE_OPTIONS.filter((o) =>
|
||||
formState.value.allowed_prescription_types.includes(o.value),
|
||||
),
|
||||
);
|
||||
|
||||
function onAllowedChange(values: number[]) {
|
||||
const next = (values || []) as number[];
|
||||
formState.value.allowed_prescription_types = next;
|
||||
// 默认种类若不在已选中,自动落到第一项
|
||||
if (
|
||||
formState.value.default_prescription_type &&
|
||||
!next.includes(formState.value.default_prescription_type)
|
||||
) {
|
||||
formState.value.default_prescription_type = next[0];
|
||||
}
|
||||
if (!formState.value.default_prescription_type && next.length) {
|
||||
formState.value.default_prescription_type = next[0];
|
||||
}
|
||||
}
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
fullscreenButton: false,
|
||||
draggable: true,
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
onConfirm: async () => {
|
||||
if (!formState.value.id) {
|
||||
message.error('门店ID无效');
|
||||
return;
|
||||
}
|
||||
if (!formState.value.allowed_prescription_types.length) {
|
||||
message.error('请至少选择一种可开方种类');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!formState.value.default_prescription_type ||
|
||||
!formState.value.allowed_prescription_types.includes(
|
||||
formState.value.default_prescription_type,
|
||||
)
|
||||
) {
|
||||
message.error('请选择默认开方种类');
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
modalApi.setState({ confirmLoading: true });
|
||||
try {
|
||||
await bindPrescriptionTypesApi({
|
||||
id: formState.value.id,
|
||||
allowed_prescription_types: formState.value.allowed_prescription_types,
|
||||
default_prescription_type: formState.value.default_prescription_type,
|
||||
});
|
||||
message.success('绑定成功');
|
||||
gridApiRef.value?.reload();
|
||||
modalApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
message.error('绑定失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
modalApi.setState({ confirmLoading: false });
|
||||
}
|
||||
},
|
||||
async onOpenChange(isOpen: boolean) {
|
||||
if (!isOpen) return;
|
||||
const { values, gridApi } = modalApi.getData<Record<string, any>>();
|
||||
gridApiRef.value = gridApi;
|
||||
const allowed = Array.isArray(values?.allowed_prescription_types)
|
||||
? values.allowed_prescription_types.map((n: any) => Number(n))
|
||||
: [];
|
||||
let def = Number(values?.default_prescription_type) || 0;
|
||||
if (def && !allowed.includes(def)) {
|
||||
def = allowed[0] || 0;
|
||||
}
|
||||
formState.value = {
|
||||
id: values?.id,
|
||||
allowed_prescription_types: allowed,
|
||||
default_prescription_type: def || undefined,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal title="绑定开方种类" class="w-[520px]">
|
||||
<Form :model="formState" layout="vertical">
|
||||
<FormItem label="可开方种类" required>
|
||||
<CheckboxGroup
|
||||
v-model:value="formState.allowed_prescription_types"
|
||||
@change="onAllowedChange"
|
||||
>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<Checkbox
|
||||
v-for="opt in STORE_PRESCRIPTION_TYPE_OPTIONS"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</Checkbox>
|
||||
</div>
|
||||
</CheckboxGroup>
|
||||
</FormItem>
|
||||
<FormItem label="进入开方页默认种类" required>
|
||||
<RadioGroup
|
||||
v-model:value="formState.default_prescription_type"
|
||||
:disabled="!defaultOptions.length"
|
||||
>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<Radio
|
||||
v-for="opt in defaultOptions"
|
||||
:key="opt.value"
|
||||
:value="opt.value"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</Radio>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
<div v-if="!defaultOptions.length" class="mt-1 text-gray-400 text-sm">
|
||||
请先勾选可开方种类
|
||||
</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</template>
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 门店开方种类选项(与 ProductTypeEnum 开方 Tab 对齐,不含特色方)
|
||||
*/
|
||||
export const STORE_PRESCRIPTION_TYPE_OPTIONS = [
|
||||
{ label: '中药', value: 1 },
|
||||
{ label: '西(中成)药', value: 2 },
|
||||
{ label: '保健食品', value: 3 },
|
||||
{ label: '产品服务包', value: 5 },
|
||||
{ label: '非药品', value: 6 },
|
||||
{ label: '医疗器械', value: 7 },
|
||||
];
|
||||
|
||||
/** 按 value 取中文名 */
|
||||
export function prescriptionTypeLabel(value: number): string {
|
||||
const hit = STORE_PRESCRIPTION_TYPE_OPTIONS.find((o) => o.value === Number(value));
|
||||
return hit?.label || `类型${value}`;
|
||||
}
|
||||
@@ -51,6 +51,13 @@ export const gridOptions: VxeGridProps<RowType> = {
|
||||
width: 180,
|
||||
slots: { default: 'special_prescription_config' },
|
||||
},
|
||||
{
|
||||
field: 'prescription_types_config',
|
||||
align: 'left',
|
||||
title: '开方种类',
|
||||
width: 200,
|
||||
slots: { default: 'prescription_types_config' },
|
||||
},
|
||||
{
|
||||
field: 'store_config_1',
|
||||
align: 'left',
|
||||
|
||||
@@ -37,6 +37,7 @@ import StoreConfigTogglesCell from './components/cells/StoreConfigTogglesCell.vu
|
||||
import DrugPriceModal from './components/DrugPriceModal.vue';
|
||||
import BindConsultationModal from './components/BindConsultationModal.vue';
|
||||
import BindSpecialPrescriptionDoctorModal from './components/BindSpecialPrescriptionDoctorModal.vue';
|
||||
import BindPrescriptionTypesModal from './components/BindPrescriptionTypesModal.vue';
|
||||
import StoreExternalFieldModal from './components/StoreExternalFieldModal.vue';
|
||||
import SalespersonCommissionDrawer from './components/SalespersonCommissionDrawer.vue';
|
||||
import AddDoctorFromStoreModal from './components/AddDoctorFromStoreModal.vue';
|
||||
@@ -49,6 +50,7 @@ import BankCardStoreEditModal from '#/views/system/store-bank-card/components/Ba
|
||||
import { getStoreBankCardReportDetail } from '#/views/system/store-bank-card/api';
|
||||
import { formOptions } from './config/search';
|
||||
import { gridOptions } from './config/table';
|
||||
import { prescriptionTypeLabel } from './config/prescription-type-constants';
|
||||
import {
|
||||
canAddStoreDoctor,
|
||||
canManageStoreBankCard,
|
||||
@@ -174,6 +176,10 @@ const [BindSpecialPrescriptionDoctorModalComponent, bindSpecialPrescriptionDocto
|
||||
connectedComponent: BindSpecialPrescriptionDoctorModal,
|
||||
});
|
||||
|
||||
const [BindPrescriptionTypesModalComponent, bindPrescriptionTypesModalApi] = useVbenModal({
|
||||
connectedComponent: BindPrescriptionTypesModal,
|
||||
});
|
||||
|
||||
const [StoreExternalFieldModalComponent, storeExternalFieldModalApi] = useVbenModal({
|
||||
connectedComponent: StoreExternalFieldModal,
|
||||
});
|
||||
@@ -310,6 +316,26 @@ const showBindSpecialPrescriptionDoctorModal = (row: any) => {
|
||||
bindSpecialPrescriptionDoctorModalApi.open();
|
||||
};
|
||||
|
||||
/** 打开绑定开方种类弹窗 */
|
||||
const showBindPrescriptionTypesModal = (row: any) => {
|
||||
bindPrescriptionTypesModalApi.setData({
|
||||
values: row,
|
||||
gridApi,
|
||||
});
|
||||
bindPrescriptionTypesModalApi.open();
|
||||
};
|
||||
|
||||
/** 列表摘要:已绑种类数 + 默认种类名 */
|
||||
function prescriptionTypesSummary(row: any) {
|
||||
const allowed = Array.isArray(row?.allowed_prescription_types)
|
||||
? row.allowed_prescription_types
|
||||
: [];
|
||||
if (!allowed.length) return '未绑定';
|
||||
const def = Number(row?.default_prescription_type) || 0;
|
||||
const defLabel = def ? prescriptionTypeLabel(def) : '';
|
||||
return defLabel ? `${allowed.length}种 · 默认${defLabel}` : `${allowed.length}种`;
|
||||
}
|
||||
|
||||
const deleteApi = (row: any) => {
|
||||
let ids = [];
|
||||
if (row) {
|
||||
@@ -468,6 +494,7 @@ const handleSwitchClinicType = (row: any) => {
|
||||
<DrugPriceModalComponent />
|
||||
<BindConsultationModalComponent />
|
||||
<BindSpecialPrescriptionDoctorModalComponent />
|
||||
<BindPrescriptionTypesModalComponent />
|
||||
<StoreExternalFieldModalComponent />
|
||||
<SalespersonCommissionDrawer ref="salespersonDrawerRef" />
|
||||
<Grid>
|
||||
@@ -637,6 +664,23 @@ const handleSwitchClinicType = (row: any) => {
|
||||
绑定
|
||||
</Button>
|
||||
</template>
|
||||
<template #prescription_types_config="{ row }">
|
||||
<div
|
||||
class="cursor-pointer hover:text-blue-500"
|
||||
@click="showBindPrescriptionTypesModal(row)"
|
||||
>
|
||||
<Tag
|
||||
:color="
|
||||
Array.isArray(row.allowed_prescription_types) &&
|
||||
row.allowed_prescription_types.length
|
||||
? 'success'
|
||||
: 'default'
|
||||
"
|
||||
>
|
||||
{{ prescriptionTypesSummary(row) }}
|
||||
</Tag>
|
||||
</div>
|
||||
</template>
|
||||
<template #start-time="{ row }">
|
||||
早:<Tag color="success">{{ row.start_time }}</Tag>
|
||||
<br />
|
||||
|
||||
Reference in New Issue
Block a user