From 92e145f36615d7b17216f978d9b2259239c4a3d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Fri, 3 Jul 2026 10:41:52 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BC=98=E5=8C=96=E5=8C=BB=E7=94=9F?= =?UTF-8?q?=E3=80=81=E8=AF=8A=E6=89=80=E7=9A=84=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../form/components/doctor-picker.vue | 335 ++++++++++++++++++ .../form/components/store-picker.vue | 308 ++++++++++++++++ apps/web-antd/src/utils/formatPrice.ts | 68 ++++ .../special-prescription/api/index.ts | 8 + .../components/EditPrescriptionModal.vue | 104 ++++++ .../special-prescription/config/table.ts | 10 +- .../business/special-prescription/index.vue | 51 ++- .../utils/buildPayload.ts | 35 ++ .../views/doctor/doctor-reception/index.vue | 68 ++-- .../src/views/doctor/doctor/api/card.ts | 10 + .../doctor/components/DoctorCardModal.vue | 139 +++++++- .../views/system/admin/_shared/admin-page.vue | 47 ++- .../system/admin/_shared/form-schemas.ts | 31 +- .../admin/_shared/platform-admin-role.ts | 20 ++ .../system/admin/_shared/table-config.ts | 21 +- .../src/views/system/pharmacy/index.vue | 31 ++ .../components/BankCardReportModal.vue | 12 +- .../components/BankCardStoreEditModal.vue | 226 ++++++++++++ .../store-bank-card/config/constants.ts | 13 + .../store-bank-card/utils/bankCardImport.ts | 64 ++++ .../src/views/system/store/api/index.ts | 14 + .../BindSpecialPrescriptionDoctorModal.vue | 38 +- .../cells/StoreConfigTogglesCell.vue | 24 +- .../src/views/system/store/config/table.ts | 2 +- .../web-antd/src/views/system/store/index.vue | 42 ++- 25 files changed, 1616 insertions(+), 105 deletions(-) create mode 100644 apps/web-antd/src/components/form/components/doctor-picker.vue create mode 100644 apps/web-antd/src/components/form/components/store-picker.vue create mode 100644 apps/web-antd/src/utils/formatPrice.ts create mode 100644 apps/web-antd/src/views/business/special-prescription/components/EditPrescriptionModal.vue create mode 100644 apps/web-antd/src/views/business/special-prescription/utils/buildPayload.ts create mode 100644 apps/web-antd/src/views/system/admin/_shared/platform-admin-role.ts create mode 100644 apps/web-antd/src/views/system/store-bank-card/components/BankCardStoreEditModal.vue create mode 100644 apps/web-antd/src/views/system/store-bank-card/utils/bankCardImport.ts diff --git a/apps/web-antd/src/components/form/components/doctor-picker.vue b/apps/web-antd/src/components/form/components/doctor-picker.vue new file mode 100644 index 00000000..b0e050b5 --- /dev/null +++ b/apps/web-antd/src/components/form/components/doctor-picker.vue @@ -0,0 +1,335 @@ + + + + + + + diff --git a/apps/web-antd/src/components/form/components/store-picker.vue b/apps/web-antd/src/components/form/components/store-picker.vue new file mode 100644 index 00000000..34a3dbe1 --- /dev/null +++ b/apps/web-antd/src/components/form/components/store-picker.vue @@ -0,0 +1,308 @@ + + + + + + + diff --git a/apps/web-antd/src/utils/formatPrice.ts b/apps/web-antd/src/utils/formatPrice.ts new file mode 100644 index 00000000..04cc9500 --- /dev/null +++ b/apps/web-antd/src/utils/formatPrice.ts @@ -0,0 +1,68 @@ +/** + * 与后端 format_price / PrescriptionService 中药计价口径一致 + */ + +export function parsePriceValue(value: unknown): number { + if (value === null || value === undefined || value === '') { + return 0; + } + const num = Number(value); + return Number.isFinite(num) ? num : 0; +} + +/** + * 与后端 format_price 一致:第三位小数非 0 则分位进 1,再保留两位小数 + */ +export function formatPriceLikeBackend(value: unknown): number { + const price = parsePriceValue(value); + let milli = Math.round(price * 1000); + if (milli % 10 > 0) { + milli += 10; + } + milli -= milli % 10; + return Math.round((milli / 1000) * 100) / 100; +} + +/** 模拟 PHP bcmul 在指定 scale 下向零截断 */ +function bcmulScale(a: unknown, b: unknown, scale: number): number { + const product = parsePriceValue(a) * parsePriceValue(b); + const factor = 10 ** scale; + return Math.trunc(product * factor) / factor; +} + +/** 模拟 PHP bcadd 在指定 scale 下向零截断 */ +function bcaddScale(a: number, b: number, scale: number): number { + const sum = a + b; + const factor = 10 ** scale; + return Math.trunc(sum * factor) / factor; +} + +type ChineseDrugLine = { + number?: number | string; + price?: number | string; +}; + +/** + * 中药商品总价(与 PrescriptionService::createChineseReprice 一致) + * 每行:bcmul(dosage, bcmul(price, number, 3), 3),累加后 format_price + */ +export function calculateChineseProductPriceLikeBackend( + drugs: ChineseDrugLine[], + dosage = 7, +): number { + if (!drugs?.length) { + return 0; + } + const dose = parsePriceValue(dosage); + let total = 0; + for (const drug of drugs) { + const linePerDose = bcmulScale(drug.price, drug.number ?? 1, 3); + const lineTotal = bcmulScale(dose, linePerDose, 3); + total = bcaddScale(total, lineTotal, 3); + } + return formatPriceLikeBackend(total); +} + +export function formatPriceDisplay(value: unknown): string { + return formatPriceLikeBackend(value).toFixed(2); +} diff --git a/apps/web-antd/src/views/business/special-prescription/api/index.ts b/apps/web-antd/src/views/business/special-prescription/api/index.ts index a7d15583..d3994d45 100644 --- a/apps/web-antd/src/views/business/special-prescription/api/index.ts +++ b/apps/web-antd/src/views/business/special-prescription/api/index.ts @@ -18,6 +18,14 @@ export async function updateSpecialPrescription(data: Record) { return requestClient.post(`${prefix}update`, data); } +/** 上下架状态切换(列表 Tag 点击) */ +export async function updateSpecialPrescriptionStatus(data: { + id: number; + status: number; +}) { + return requestClient.post(`${prefix}update-status`, data); +} + export async function deleteSpecialPrescription(data: Record) { return requestClient.post(`${prefix}delete`, data); } diff --git a/apps/web-antd/src/views/business/special-prescription/components/EditPrescriptionModal.vue b/apps/web-antd/src/views/business/special-prescription/components/EditPrescriptionModal.vue new file mode 100644 index 00000000..b7ca63e7 --- /dev/null +++ b/apps/web-antd/src/views/business/special-prescription/components/EditPrescriptionModal.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/business/special-prescription/config/table.ts b/apps/web-antd/src/views/business/special-prescription/config/table.ts index 67a02276..3f57efc8 100644 --- a/apps/web-antd/src/views/business/special-prescription/config/table.ts +++ b/apps/web-antd/src/views/business/special-prescription/config/table.ts @@ -66,9 +66,15 @@ export const gridOptions: VxeGridProps = { { field: 'price_per_dose', align: 'left', title: '每剂价格', width: 100 }, { field: 'sales_count', align: 'left', title: '销量', width: 80 }, { field: 'sort', align: 'left', title: '排序', width: 80 }, - { field: 'status_txt', align: 'left', title: '状态', width: 80 }, + { + field: 'status', + align: 'left', + title: '状态', + width: 90, + slots: { default: 'status' }, + }, { field: 'created_at', title: '创建时间', width: 180 }, - { type: 'html', title: '操作', slots: { default: 'action' }, width: 160 }, + { type: 'html', title: '操作', slots: { default: 'action' }, width: 220 }, ], keepSource: true, pagerConfig: {}, diff --git a/apps/web-antd/src/views/business/special-prescription/index.vue b/apps/web-antd/src/views/business/special-prescription/index.vue index 794b9644..5de9d24d 100644 --- a/apps/web-antd/src/views/business/special-prescription/index.vue +++ b/apps/web-antd/src/views/business/special-prescription/index.vue @@ -10,12 +10,17 @@ import { Button, Image, message, Tag } from 'ant-design-vue'; import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { TableAction } from '#/components/table-action'; -import { deleteSpecialPrescription } from './api'; +import { + deleteSpecialPrescription, + updateSpecialPrescriptionStatus, +} from './api'; +import EditPrescriptionModal from './components/EditPrescriptionModal.vue'; import SpecialPrescriptionModal from './components/modal.vue'; import { formOptions as searchFormOptions } from './config/search'; import { gridOptions } from './config/table'; const hasTopTableDropDownActions = ref(false); +const statusLoadingId = ref(null); const gridEvents: VxeGridListeners = { checkboxChange() { @@ -38,6 +43,10 @@ const [FormModal, formModalApi] = useVbenModal({ connectedComponent: SpecialPrescriptionModal, }); +const [EditPrescriptionModalComp, editPrescriptionModalApi] = useVbenModal({ + connectedComponent: EditPrescriptionModal, +}); + const showModal = (data = {}, isUpdate = false) => { formModalApi.setData({ values: data, @@ -47,6 +56,30 @@ const showModal = (data = {}, isUpdate = false) => { formModalApi.open(); }; +const showEditPrescriptionModal = (row: any) => { + editPrescriptionModalApi.setData({ + values: row, + gridApi, + }); + editPrescriptionModalApi.open(); +}; + +/** 点击状态 Tag 切换上下架 */ +const toggleStatus = async (row: any) => { + if (statusLoadingId.value === row.id) { + return; + } + const newStatus = row.status === 1 ? 0 : 1; + statusLoadingId.value = row.id; + try { + await updateSpecialPrescriptionStatus({ id: row.id, status: newStatus }); + message.success(newStatus === 1 ? '已上架' : '已下架'); + gridApi.query(); + } finally { + statusLoadingId.value = null; + } +}; + const deleteApi = (row: any) => { let ids: (string | number)[] = []; if (row) { @@ -64,6 +97,7 @@ const deleteApi = (row: any) => { + +