feat: 金方相关

feat: 患者信息身份证改成非必填
This commit is contained in:
李琦
2026-08-08 18:36:26 +08:00
parent c4e833a1c4
commit 335b3535d5
11 changed files with 1184 additions and 283 deletions

View File

@@ -18,13 +18,21 @@ export async function getDeliveryWarehouseProductInfo(id: number) {
}
/**
* 平台审核:status 必为 2 下架或 3 上架;需填 zone_id
* 平台审核(一次提交):
* 主数据审过 + 总仓供货价/售价同步门店 + 绑仓三费 + 可选初始入库
*/
export async function auditDeliveryWarehouseProduct(data: {
id: number;
status: 2 | 3;
zone_id: number;
category_id?: number;
drug_number: string;
market_price: number;
price: number;
quote: number;
promo_fee: number;
platform_fee: number;
initial_stock?: number;
}) {
return requestClient.post<any>(`${prefix}audit`, data);
}

View File

@@ -1,16 +1,24 @@
<script lang="ts" setup>
/**
* 平台仓品审核弹窗
* 必选上架/下架 + 所属分区;审核成功后由列表页打开仓药绑定弹窗
* 平台仓品审核弹窗(单次提交)
* 分区/分类/上下架 + ERP + 总仓供货价/售价 + 绑仓三费 + 可选初始库存
* 提交后由后端一次性完成主数据审过、总仓同步门店、绑仓与入库
*/
import { nextTick, ref } from 'vue';
import { h, onUnmounted, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Descriptions, Image, message, Tag } from 'ant-design-vue';
import { Button, Descriptions, Image, message, Tag } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { getDrugCategoriesTree, getZoneOptions } from '#/views/business/product/drug-categories/api';
import {
calcFeeSum,
isFeeOverSalePrice,
registerFeeOverTipHandler,
resetAutoPromoFeeKey,
syncFeeSumDisplay,
} from '#/views/system/delivery-warehouse-drug/config/form';
import {
auditDeliveryWarehouseProduct,
@@ -19,8 +27,10 @@ import {
const gridApi = ref();
const detail = ref<Record<string, any> | null>(null);
/** 审核成功后回传给列表页,用于打开绑仓弹窗 */
const onBindPreset = ref<((preset: Record<string, any>) => void) | null>(null);
/** 三费超售价红色提示 */
const feeOverTip = ref('');
/** 记录已按售价自动填过平台费的售价,避免反复覆盖手改 */
const lastAutoPlatformSale = ref(0);
const [Form, formApi] = useVbenForm({
wrapperClass: 'grid-cols-12',
@@ -96,12 +106,153 @@ const [Form, formApi] = useVbenForm({
fieldName: 'status',
label: '审核结果',
rules: 'selectRequired',
help: '审核通过后按所选结果上架或下架,并打开绑仓弹窗',
help: '主数据上下架;总仓/绑仓状态同步跟随',
},
{
component: 'VbenInput',
componentProps: {
placeholder: '请输入 ERP 编号,无则点右侧「非erp」',
allowClear: true,
},
fieldName: 'drug_number',
label: 'ERP编号',
rules: 'required',
help: '可填真实编号;无 ERP 点「非erp」填入 -1',
// 渲染时再点选,此时 formApi 已就绪
suffix: () =>
h(
Button,
{
size: 'small',
type: 'link',
onClick: (e: MouseEvent) => {
e.preventDefault();
e.stopPropagation();
formApi.setFieldValue('drug_number', '-1');
},
},
{ default: () => '非erp' },
),
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入仓库供货价',
min: 0,
precision: 4,
class: 'w-full',
},
fieldName: 'market_price',
label: '仓库供货价',
rules: 'required',
help: '写入总仓并同步到门店供货价',
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入售价',
min: 0,
precision: 4,
class: 'w-full',
},
fieldName: 'price',
label: '售价',
rules: 'required',
help: '写入总仓销售价;三费合计不得超过该值',
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入绑定仓库报价',
min: 0,
precision: 4,
class: 'w-full',
},
fieldName: 'quote',
label: '绑仓报价',
rules: 'required',
help: '默认取仓侧上传报价,可修改',
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入平台费',
min: 0,
precision: 4,
class: 'w-full',
},
fieldName: 'platform_fee',
label: '平台费',
rules: 'required',
help: '默认售价的 5%,可改',
},
{
component: 'InputNumber',
componentProps: {
placeholder: '自动=售价−报价−平台费',
min: 0,
precision: 4,
class: 'w-full',
},
fieldName: 'promo_fee',
label: '推广费',
rules: 'required',
help: '有售价时自动计算,可微调',
},
{
component: 'VbenInput',
componentProps: {
disabled: true,
placeholder: '报价+推广费+平台费',
},
fieldName: '_fee_sum',
label: '费用合计',
// 把 price 映射为仓药绑定逻辑里的 sale_price,复用三费联动
dependencies: {
async trigger(values, formApiInst) {
const sale = Number(values.price) || 0;
// 售价变化时默认平台费 = 售价 * 5%(仅该售价首次自动填)
if (sale > 0 && lastAutoPlatformSale.value !== sale) {
const platform = Number((sale * 0.05).toFixed(4));
await formApiInst.setFieldValue('platform_fee', platform);
lastAutoPlatformSale.value = sale;
values = { ...values, platform_fee: platform };
}
syncFeeSumDisplay(
{
...values,
sale_price: sale,
},
formApiInst,
);
},
triggerFields: ['quote', 'promo_fee', 'platform_fee', 'price'],
},
},
{
component: 'InputNumber',
componentProps: {
placeholder: '选填,默认 0',
min: 0,
precision: 0,
class: 'w-full',
},
fieldName: 'initial_stock',
label: '初始库存',
help: '大于 0 时绑仓后自动入库并记流水',
defaultValue: 0,
},
],
showDefaultActions: false,
});
registerFeeOverTipHandler((tip) => {
feeOverTip.value = tip;
});
onUnmounted(() => {
registerFeeOverTipHandler(null);
});
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
draggable: true,
@@ -121,21 +272,45 @@ const [Modal, modalApi] = useVbenModal({
message.warning('请选择所属分区');
return;
}
const drugNumber = String(values.drug_number || '').trim();
if (!drugNumber) {
message.warning('请填写 ERP 编号(无 ERP 可点「非erp」填 -1)');
return;
}
const feeValues = {
quote: values.quote,
promo_fee: values.promo_fee,
platform_fee: values.platform_fee,
sale_price: values.price,
};
if (isFeeOverSalePrice(feeValues)) {
message.warning(
`三费合计已超过售价 ¥${Number(values.price).toFixed(4)}`,
);
return;
}
if (Number(calcFeeSum(feeValues)) <= 0) {
message.warning('报价/推广费/平台费合计必须大于0');
return;
}
modalApi.setState({ loading: true, confirmLoading: true });
auditDeliveryWarehouseProduct({
id: Number(values.id),
status: status as 2 | 3,
zone_id: Number(values.zone_id),
category_id: Number(values.category_id || 0),
drug_number: drugNumber,
market_price: Number(values.market_price),
price: Number(values.price),
quote: Number(values.quote),
promo_fee: Number(values.promo_fee),
platform_fee: Number(values.platform_fee),
initial_stock: Number(values.initial_stock || 0),
})
.then((res: any) => {
message.success('审核成功,请完成仓药绑定');
.then(() => {
message.success('审核成功,已完成总仓同步与仓药绑定');
gridApi.value?.query?.() ?? gridApi.value?.reload?.();
const preset = res?.bind_preset || res?.data?.bind_preset;
modalApi.close();
if (preset && onBindPreset.value) {
nextTick(() => onBindPreset.value?.(preset));
}
})
.finally(() => {
modalApi.setState({ loading: false, confirmLoading: false });
@@ -145,31 +320,53 @@ const [Modal, modalApi] = useVbenModal({
await formApi.validateAndSubmitForm();
},
async onOpenChange(isOpen: boolean) {
gridApi.value = isOpen ? modalApi.getData()?.gridApi : null;
onBindPreset.value = isOpen ? modalApi.getData()?.onBindPreset || null : null;
if (!isOpen) {
detail.value = null;
feeOverTip.value = '';
return;
}
await formApi.resetForm();
const data = modalApi.getData<Record<string, any>>() || {};
gridApi.value = data.gridApi ?? null;
resetAutoPromoFeeKey();
lastAutoPlatformSale.value = 0;
feeOverTip.value = '';
await formApi.resetForm();
const id = Number(data.id || data.values?.id || 0);
await formApi.setValues({ id, status: undefined, zone_id: undefined, category_id: undefined });
let row = data.values || { id };
if (id > 0) {
const row = data.values || { id };
try {
const info = await getDeliveryWarehouseProductInfo(id);
detail.value = { ...row, ...(info || {}) };
row = { ...row, ...(info || {}) };
} catch {
detail.value = row;
// 详情失败仍用列表行
}
}
detail.value = row;
const uploadQuote = Number(row.upload_quote || 0);
await formApi.setValues({
id,
status: undefined,
zone_id: undefined,
category_id: undefined,
// 仓侧默认常为 -1,保留回填,也可点「非erp」重填
drug_number:
row.drug_number != null && String(row.drug_number) !== ''
? String(row.drug_number)
: '',
market_price: undefined,
price: undefined,
quote: uploadQuote > 0 ? uploadQuote : undefined,
platform_fee: undefined,
promo_fee: undefined,
initial_stock: 0,
_fee_sum: uploadQuote > 0 ? String(uploadQuote.toFixed(4)) : '',
});
},
});
</script>
<template>
<Modal title="仓品审核" class="w-[80%] md:w-[50%] lg:w-[40%]">
<Modal title="仓品审核" class="w-[80%] md:w-[560px] lg:w-[520px]">
<div v-if="detail" class="mb-4">
<Descriptions :column="1" size="small" bordered>
<Descriptions.Item label="药品名称">
@@ -196,5 +393,12 @@ const [Modal, modalApi] = useVbenModal({
</Descriptions>
</div>
<Form />
<div
v-if="feeOverTip"
class="mt-2 text-sm"
style="color: hsl(var(--destructive))"
>
{{ feeOverTip }}
</div>
</Modal>
</template>

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup>
/**
* 平台「仓品审核」列表页
* 审核通过后自动打开仓药绑定弹窗,预填本仓+药品+报价
* 审核弹窗一次提交:主数据 + 总仓同步 + 绑仓三费/入库
*/
import { Page, useVbenModal } from '@vben/common-ui';
@@ -9,7 +9,6 @@ import { Image, Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { TableAction } from '#/components/table-action';
import BindModalDemo from '#/views/system/delivery-warehouse-drug/components/modal.vue';
import AuditModalDemo from './components/audit-modal.vue';
import { formOptions } from './config/search';
@@ -26,37 +25,6 @@ const [AuditModal, auditModalApi] = useVbenModal({
connectedComponent: AuditModalDemo,
});
const [BindModal, bindModalApi] = useVbenModal({
connectedComponent: BindModalDemo,
});
/**
* 审核成功后打开仓药绑定:锁定药品、预填仓库与报价
*/
function openBindFromPreset(preset: Record<string, any>) {
if (!preset?.drug_id || !preset?.warehouse_id) {
return;
}
bindModalApi.setData({
update: false,
lockDrug: true,
presetDrug: preset.presetDrug || {
id: preset.drug_id,
drug_name: preset.drug_name,
specification: preset.specification,
image: preset.image,
},
values: {
warehouse_id: preset.warehouse_id,
drug_id: preset.drug_id,
quote: preset.quote,
status: 2,
},
gridApi,
});
bindModalApi.open();
}
/**
* 打开审核弹窗(仅待审可点)
*/
@@ -68,7 +36,6 @@ function openAudit(row: Record<string, any>) {
id: row.id,
values: row,
gridApi,
onBindPreset: openBindFromPreset,
});
auditModalApi.open();
}
@@ -81,7 +48,6 @@ function auditTagColor(status: number) {
<template>
<Page auto-content-height title="仓品审核">
<AuditModal />
<BindModal />
<Grid>
<template #toolbar-buttons>
<TableAction :actions="[]" :drop-down-actions="[]" />