Files
xk-admin/apps/web-antd/src/views/system/pharmacy/index.vue
李琦 d93e465d3c
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
1. 特色方功能迭代(固定价格),固定价格目前统一使用药品id(-102),后期会考虑新增特色方的时候自动添加一个特色方药品
2. 退款的时候可以退回分成
2026-07-09 15:45:39 +08:00

627 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.
<script lang="ts" setup>
import type { VxeGridListeners } from '#/adapter/vxe-table';
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { useUserStore } from '@vben/stores';
import { useClipboard } from '@vueuse/core';
import { Button, Image, message, Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { Icon } from '#/components/icon';
import QrCodePreview from '#/components/modal/QrCodePreview.vue';
import PromoterInfoCard from '#/components/promoter/PromoterInfoCard.vue';
import SensitiveText from '#/components/sensitive-text/SensitiveText.vue';
import { TableAction } from '#/components/table-action';
// 导入药店管理相关的API(直接使用store的API)
import {
batchSyncDrugPriceApi,
deleteStore,
openPcWindowsApiByStore,
openQrCodeApi,
updateStoreShippingFree,
updateStoreSeeRateStatus,
updateStoreSubscribeStatus,
updateStoreOrderPricePercentAdjust,
updateAllowInsuranceCategoryApi,
toggleSalespersonSeePriceApi,
} from '#/views/system/store/api';
import FormModalDemo from './components/modal.vue';
import StoreBasicInfoCell from '#/views/system/store/components/cells/StoreBasicInfoCell.vue';
import StoreConfigTogglesCell from '#/views/system/store/components/cells/StoreConfigTogglesCell.vue';
// 导入绑定在线复诊配置弹窗(使用store的组件)
import BindConsultationModal from '#/views/system/store/components/BindConsultationModal.vue';
import DrugPriceModal from '#/views/system/store/components/DrugPriceModal.vue';
import StoreExternalFieldModal from '#/views/system/store/components/StoreExternalFieldModal.vue';
import BankCardReportModal from '#/views/system/store-bank-card/components/BankCardReportModal.vue';
import BankCardStatusModal from '#/views/system/store-bank-card/components/BankCardStatusModal.vue';
import BankCardStoreEditModal from '#/views/system/store-bank-card/components/BankCardStoreEditModal.vue';
import { getStoreBankCardReportDetail } from '#/views/system/store-bank-card/api';
// 导入搜索表单配置
import { formOptions } from './config/search';
// 导入表格配置
import { gridOptions } from './config/table';
import { canManageStoreBankCard } from '#/views/system/admin/_shared/platform-admin-role';
const userStore = useUserStore();
const router = useRouter();
// 判断是否为平台管理员(user_type === 2)
const isPlatformAdmin = computed(() => {
return userStore?.userInfo?.roles?.user_type === 2;
});
const canManageBankCard = computed(() =>
canManageStoreBankCard(userStore.userInfo),
);
// 跳转到审核页面
const goToAudit = () => {
router.push('/system/store-input/audit');
};
// 是否有选中的表格行(用于控制批量操作按钮显示)
const hasTopTableDropDownActions = ref(false);
// 表格事件监听器
const gridEvents: VxeGridListeners<any> = {
// 复选框变化事件
checkboxChange() {
// eslint-disable-next-line no-use-before-define
const records = gridApi.grid.getCheckboxRecords();
// 根据是否有选中的记录来控制批量操作按钮显示
hasTopTableDropDownActions.value = records.length > 0;
},
// 全选/取消全选事件
checkboxAll() {
// eslint-disable-next-line no-use-before-define
const records = gridApi.grid.getCheckboxRecords();
// 根据是否有选中的记录来控制批量操作按钮显示
hasTopTableDropDownActions.value = records.length > 0;
},
};
// 初始化表格组件
const [Grid, gridApi] = useVbenVxeGrid({
formOptions, // 搜索表单配置
gridOptions, // 表格配置(已包含type=1过滤)
gridEvents, // 表格事件
});
// 初始化二维码预览弹窗
const [QrCodePreviewModal, QrCodePreviewApi] = useVbenModal({
connectedComponent: QrCodePreview,
});
// 打开二维码预览弹窗
const openQrCodeModal = (url, title, address) => {
QrCodePreviewApi.setData({
values: url, // 二维码图片URL
title, // 标题
address, // 地址
});
QrCodePreviewApi.open();
};
// 初始化表单弹窗
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: FormModalDemo,
});
// 初始化绑定在线复诊配置弹窗
const [BindConsultationModalComponent, bindConsultationModalApi] = useVbenModal({
connectedComponent: BindConsultationModal,
});
const [StoreExternalFieldModalComponent, storeExternalFieldModalApi] = useVbenModal({
connectedComponent: StoreExternalFieldModal,
});
const [DrugPriceModalComponent, drugPriceModalApi] = useVbenModal({
connectedComponent: DrugPriceModal,
});
const [BankCardReportModalComponent, bankCardReportModalApi] = useVbenModal({
connectedComponent: BankCardReportModal,
});
const [BankCardStatusModalComponent, bankCardStatusModalApi] = useVbenModal({
connectedComponent: BankCardStatusModal,
});
const [BankCardStoreEditModalComponent, bankCardStoreEditModalApi] = useVbenModal({
connectedComponent: BankCardStoreEditModal,
});
const openBankCardStoreEdit = (row: any) => {
bankCardStoreEditModalApi.setData({
storeId: row.id,
storeName: row.name,
gridApi,
});
bankCardStoreEditModalApi.open();
};
const openBankCardReport = async (row: any, update = false) => {
let report = null;
try {
report = await getStoreBankCardReportDetail(row.id);
} catch {
report = null;
}
const reportStatus = Number(report?.report_status ?? 0);
const useUpdate =
(update || [3, 4].includes(reportStatus)) && Boolean(report?.id);
bankCardReportModalApi.setData({
storeId: row.id,
storeName: row.name,
mode: useUpdate ? 'update' : 'report',
report,
gridApi,
});
bankCardReportModalApi.open();
};
const openBankCardStatus = (row: any) => {
bankCardStatusModalApi.setData({
storeId: row.id,
storeName: row.name,
});
bankCardStatusModalApi.open();
};
function getBankCardReportTagColor(status: number) {
switch (Number(status)) {
case 1:
return 'processing';
case 2:
return 'success';
case 3:
case 4:
return 'error';
default:
return 'default';
}
}
function getBankCardReportTagText(row: any) {
return Number(row.bank_card_report_status) === 0
? '报备'
: row.bank_card_report_status_text || '未报备';
}
function handleBankCardReportColumnClick(row: any) {
if (!canManageBankCard.value) return;
const status = Number(row.bank_card_report_status ?? 0);
if (status === 1 || status === 2) {
openBankCardStatus(row);
return;
}
openBankCardReport(row, status !== 0);
}
const showDrugPriceModal = (row: any) => {
drugPriceModalApi.setData({
store_id: row.id,
});
drugPriceModalApi.open();
};
const showStoreExternalFieldModal = (
row: any,
field: 'erp_id' | 'mes_id',
label: string,
) => {
storeExternalFieldModalApi.setData({
values: row,
field,
label,
gridApi,
});
storeExternalFieldModalApi.open();
};
/**
* 打开绑定在线复诊配置弹窗
*/
const showBindConsultationModal = (row: any) => {
bindConsultationModalApi.setData({
values: row,
gridApi,
});
bindConsultationModalApi.open();
};
// 显示表单弹窗(新增或编辑)
const showModal = (data = {}, isUpdate = false) => {
formModalApi.setData({
values: data, // 表单数据
update: isUpdate, // 是否为更新模式
gridApi, // 表格API引用(用于刷新表格)
});
formModalApi.open();
};
// 删除药店
const deleteApi = (row: any) => {
let ids = [];
// 如果传入的是单个ID,则删除单个;否则删除选中的多个
if (row) {
ids.push(row);
} else {
// 获取所有选中的记录ID
ids = gridApi.grid.getCheckboxRecords().map((item) => item.id);
}
// 调用删除API
deleteStore({ ids }).then(() => {
message.success('删除成功!');
// 刷新表格
gridApi.query();
});
};
/**
* 开通后台账号
* @param id 药店ID
*/
function openPcWindows(id) {
openPcWindowsApiByStore(id).then(() => {
message.success('操作成功!');
// 刷新表格
gridApi.query();
});
}
/**
* 生成药店二维码
* @param id 药店ID
*/
function openQrCode(id) {
openQrCodeApi(id).then(() => {
message.success('操作成功!');
// 刷新表格
gridApi.query();
});
}
// 复制文本到剪贴板
function copyText(source) {
copy(source);
message.success('复制成功');
}
const { copy } = useClipboard({ legacy: true });
/**
* 更新药店包邮状态
* @param id 药店ID
*/
const updateShippingFree = (id: number) => {
updateStoreShippingFree({ id }).then(() => {
message.success('修改成功!');
// 重新查询表格数据
gridApi.query();
});
};
/**
* 更新药店价格波动订阅状态
* @param id 药店ID
*/
const updateSubscribe = (id: number) => {
updateStoreSubscribeStatus({ id }).then(() => {
message.success('修改成功!');
gridApi.query();
});
};
/**
* 切换是否可查看毛利率
*/
const updateSeeRate = (id: number) => {
updateStoreSeeRateStatus({ id }).then(() => {
message.success('修改成功!');
gridApi.query();
});
};
const updateOrderPricePercentAdjust = (id: number) => {
updateStoreOrderPricePercentAdjust({ id }).then(() => {
message.success('修改成功!');
gridApi.query();
});
};
const updateAllowInsurance = (id: number) => {
updateAllowInsuranceCategoryApi({ id }).then(() => {
message.success('修改成功!');
gridApi.query();
});
};
const updateSalespersonSeePrice = (storeId: number) => {
toggleSalespersonSeePriceApi({ store_id: storeId }).then(() => {
message.success('修改成功!');
gridApi.query();
});
};
/**
* 批量同步总仓库药品
*/
const batchSyncDrugPrice = () => {
const records = gridApi.grid.getCheckboxRecords();
if (records.length === 0) {
message.warning('请至少选择一条记录!');
return;
}
const ids = records.map((item) => item.id);
batchSyncDrugPriceApi(ids)
.then((res) => {
message.success(`批量同步任务已创建,共 ${res.data.success} 个门店的任务已提交!`);
gridApi.query();
})
.catch(() => {
message.error('批量同步失败!');
});
};
</script>
<template>
<Page auto-content-height title="药店管理">
<FormModal />
<BankCardReportModalComponent />
<BankCardStatusModalComponent />
<BankCardStoreEditModalComponent />
<QrCodePreviewModal />
<DrugPriceModalComponent />
<BindConsultationModalComponent />
<StoreExternalFieldModalComponent />
<Grid>
<template #toolbar-buttons>
<TableAction
:actions="[
{
label: '新增',
type: 'primary',
icon: 'ant-design:plus-outlined',
auth: ['Super Admin', 'Admin'],
onClick: showModal.bind(null),
},
{
label: '审核',
type: 'default',
icon: 'ant-design:audit-outlined',
auth: ['Super Admin', 'Admin'],
ifShow: isPlatformAdmin,
onClick: goToAudit,
},
]"
:drop-down-actions="[
{
label: '删除',
icon: 'ant-design:delete-outlined',
ifShow: hasTopTableDropDownActions,
auth: ['Super Admin', 'Admin'],
popConfirm: {
title: '确定删除吗?',
confirm: deleteApi.bind(null, false),
},
},
{
label: '同步总仓库药品',
icon: 'ant-design:sync-outlined',
ifShow: hasTopTableDropDownActions,
popConfirm: {
title: '确定要同步选中门店的总仓库药品吗?同步将更新价格、上架下架状态,并自动添加新药品。',
confirm: batchSyncDrugPrice,
},
},
]"
>
<template #more>
<Button style="margin-left: 16px">
批量操作
<Icon icon="ant-design:down-outlined" />
</Button>
</template>
</TableAction>
</template>
<template #store_basic_info="{ row }">
<StoreBasicInfoCell
:row="row"
variant="pharmacy"
:on-copy="copyText"
:on-edit-external-field="showStoreExternalFieldModal"
/>
</template>
<template #store_config_1="{ row }">
<StoreConfigTogglesCell
:row="row"
section="switches"
:can-manage-bank-card="canManageBankCard"
:get-bank-card-report-tag-color="getBankCardReportTagColor"
:get-bank-card-report-tag-text="getBankCardReportTagText"
:on-shipping-free="updateShippingFree"
:on-subscribe="updateSubscribe"
:on-see-rate="updateSeeRate"
:on-order-price-adjust="updateOrderPricePercentAdjust"
:on-bank-card-report="handleBankCardReportColumnClick"
/>
</template>
<template #store_config_2="{ row }">
<StoreConfigTogglesCell
:row="row"
section="business"
show-insurance
show-salesperson-see-price
:can-manage-bank-card="canManageBankCard"
:get-bank-card-report-tag-color="getBankCardReportTagColor"
:get-bank-card-report-tag-text="getBankCardReportTagText"
:on-shipping-free="updateShippingFree"
:on-subscribe="updateSubscribe"
:on-see-rate="updateSeeRate"
:on-order-price-adjust="updateOrderPricePercentAdjust"
:on-bank-card-report="handleBankCardReportColumnClick"
:on-allow-insurance="updateAllowInsurance"
:on-salesperson-see-price="updateSalespersonSeePrice"
/>
</template>
<template #sales_admin="{ row }">
<PromoterInfoCard :admin="row.new_admin" size="compact" />
</template>
<template #mobile="{ row }">
<div>
药店联系人:{{ row.contact }}
<Button type="link" @click="copyText(row.contact)">复制</Button>
</div>
<div>
号码:<SensitiveText :record="row" field="mobile" />
</div>
</template>
<template #qr_code="{ row }">
<div class="qr_code">
<Image
:preview="false"
:src="row.qr_code"
height="30"
width="30"
@click="
openQrCodeModal(
row.qr_code,
row.name,
`${row.province.name}${row.city.name}${row.position}`,
)
"
/>
</div>
</template>
<template #online_consultation_config="{ row }">
<div
v-if="row.is_internet_medical === 1 && row.online_consultation_doctor_name"
class="cursor-pointer hover:text-blue-500"
@click="showBindConsultationModal(row)"
>
<div>负责人:{{ row.online_consultation_doctor_name }}</div>
</div>
<div
v-else-if="row.delegate_store_name || row.online_consultation_doctor_name"
class="cursor-pointer hover:text-blue-500"
@click="showBindConsultationModal(row)"
>
<div v-if="row.delegate_store_name">委托:{{ row.delegate_store_name }}</div>
<div v-if="row.online_consultation_doctor_name">负责人:{{ row.online_consultation_doctor_name }}</div>
</div>
<Button v-else type="link" size="small" @click="showBindConsultationModal(row)">
绑定
</Button>
</template>
<template #start-time="{ row }">
早:<Tag color="success">{{ row.start_time }}</Tag>
<br />
<br />
晚:<Tag color="error">{{ row.end_time }}</Tag>
</template>
<template #toolbar-tools></template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '编辑',
type: 'link',
icon: 'uil:edit',
size: 'small',
auth: ['Super Admin', 'Admin'],
onClick: showModal.bind(null, row, true),
},
{
label: '删除',
type: 'link',
icon: 'ant-design:delete-outlined',
size: 'small',
auth: ['Super Admin', 'Admin'],
popConfirm: {
title: '确定删除吗?',
confirm: deleteApi.bind(null, row.id),
},
},
]"
:drop-down-actions="[
{
label: '开通后台',
type: 'link',
icon: 'uil:edit',
auth: ['Super Admin', 'Admin'],
size: 'small',
popConfirm: {
title: '确定开通后台吗?',
confirm: openPcWindows.bind(null, row.id),
},
},
{
label: '生成药店二维码',
type: 'link',
icon: 'uil:edit',
auth: ['Super Admin', 'Admin'],
size: 'small',
popConfirm: {
title: '确定生成药店二维码吗?',
confirm: openQrCode.bind(null, row.id),
},
},
{
label: '修改药品价格',
type: 'link',
icon: 'ant-design:edit-outlined',
size: 'small',
ifShow: isPlatformAdmin,
onClick: showDrugPriceModal.bind(null, row),
},
{
label: '查看卡状态',
type: 'link',
icon: 'ant-design:eye-outlined',
size: 'small',
auth: ['Super Admin', 'Admin'],
onClick: () => openBankCardStatus(row),
},
{
label: '银行卡报备',
type: 'link',
icon: 'ant-design:bank-outlined',
size: 'small',
auth: ['Super Admin', 'Admin'],
onClick: () => openBankCardReport(row, false),
},
{
label: '修改银行卡',
type: 'link',
icon: 'ant-design:credit-card-outlined',
size: 'small',
auth: ['Super Admin', 'Admin'],
onClick: () => openBankCardStoreEdit(row),
},
{
label: '修改报备银行卡',
type: 'link',
icon: 'ant-design:file-protect-outlined',
size: 'small',
auth: ['Super Admin', 'Admin'],
onClick: () => openBankCardReport(row, true),
},
]"
/>
</template>
</Grid>
</Page>
</template>
<style scoped>
.qr_code:hover {
cursor: pointer;
}
</style>