1. 修复了接诊页面的剂量、天数输入框过窄

This commit is contained in:
李琦
2026-07-15 08:46:37 +08:00
parent 8eca0bd84d
commit 5ff6f0d837
10 changed files with 358 additions and 108 deletions

View File

@@ -19,7 +19,8 @@ export async function getOrderTraceApi(params: {
export async function getOrderLedgerDetailApi(params: {
order_id: number;
order_type: number;
scope?: 'all' | 'platform' | 'store';
/** 平台端可按受益方类型筛选:全部/门店/平台/供应商/配送仓库 */
scope?: 'all' | 'platform' | 'store' | 'supplier' | 'warehouse';
}) {
return requestClient.get<any>(`${prefix}ledger-detail`, { params });
}

View File

@@ -29,7 +29,8 @@ import ReconciliationDetailTable from './reconciliation-detail-table.vue';
defineOptions({ name: 'OrderTraceDrawer' });
type LedgerScope = 'all' | 'platform' | 'store';
/** 分账明细 scope与后端 allowed_scopes 对齐 */
type LedgerScope = 'all' | 'platform' | 'store' | 'supplier' | 'warehouse';
const router = useRouter();
const userStore = useUserStore();
@@ -57,7 +58,8 @@ const ledgerColumns = [
{ title: '药品编号', dataIndex: 'drug_number', key: 'drug_number' },
{ title: '药品规格', dataIndex: 'specification', key: 'specification' },
{ title: '分账对象', dataIndex: 'user_type_txt', key: 'user_type_txt' },
{ title: '门店', dataIndex: ['store', 'name'], key: 'store_name' },
// 受益方名称:门店/供应商/配送仓库实体名,平台为「平台」
{ title: '受益方名称', dataIndex: 'party_name', key: 'party_name' },
{ title: '分账金额', dataIndex: 'money', key: 'money' },
{ title: '结算状态', dataIndex: 'status_txt', key: 'status_txt' },
{ title: '创建时间', dataIndex: 'created_at', key: 'created_at' },
@@ -360,6 +362,8 @@ watch(isPlatformAdmin, (val) => {
<Tabs.TabPane key="all" tab="全部" />
<Tabs.TabPane key="store" tab="门店" />
<Tabs.TabPane key="platform" tab="平台" />
<Tabs.TabPane key="supplier" tab="供应商" />
<Tabs.TabPane key="warehouse" tab="配送仓库" />
</Tabs>
<Tabs v-model:active-key="ledgerSubTab" type="card">
@@ -389,7 +393,8 @@ watch(isPlatformAdmin, (val) => {
v-else-if="
column.key === 'drug_name' ||
column.key === 'drug_number' ||
column.key === 'specification'
column.key === 'specification' ||
column.key === 'party_name'
"
>
{{ formatDrugCell(text) }}
@@ -429,7 +434,8 @@ watch(isPlatformAdmin, (val) => {
v-else-if="
column.key === 'drug_name' ||
column.key === 'drug_number' ||
column.key === 'specification'
column.key === 'specification' ||
column.key === 'party_name'
"
>
{{ formatDrugCell(text) }}

View File

@@ -17,7 +17,7 @@ export const gridOptions: VxeGridProps<RowType> = {
},
columns: [
{ field: 'id', align: 'left', title: 'ID', width: 50 },
{ field: 'user_info', title: '申请诊所/供应商/平台', slots: { default: 'user-info'} },
{ field: 'user_info', title: '申请诊所/供应商/平台/配送仓', slots: { default: 'user-info'} },
{ field: 'order_no', title: '订单号' },
{ field: 'apply_cash', title: '申请金额' },
{ field: 'true_cash', title: '打款金额' },

View File

@@ -57,7 +57,13 @@ const infoModal = (id, modalType = 0) => {
<template #user-info="{ row }">
<div>
<Tag color="green">{{ row?.user_type_txt || '平台' }}</Tag>
<Tag class="mt-3" color="#455cda">{{ row.store?.name || row.supplier?.name || '萧康云医' }}</Tag>
<Tag class="mt-3" color="#455cda">{{
row.store?.name ||
row.supplier?.name ||
row.delivery_warehouse?.name ||
row.deliveryWarehouse?.name ||
'萧康云医'
}}</Tag>
</div>
</template>
<template #check-id="{ row }">

View File

@@ -18,6 +18,23 @@ export const accountChangeSearchOptions: VbenFormProps = {
fieldName: 'source_type',
label: '来源类型',
},
{
component: 'VbenSelect',
componentProps: {
placeholder: '变更字段',
allowClear: true,
options: [
{ label: '可提现金额', value: 'able_cash' },
{ label: '可提现余额', value: 'balance' },
{ label: '冻结金额(用户未确认收货)', value: 'frozen' },
{ label: '审核中金额', value: 'frozen_cash' },
{ label: '审核中金额(余额账户)', value: 'withdrawn_frozen' },
],
},
defaultValue: '',
fieldName: 'field_name',
label: '变更字段',
},
{
component: 'VbenInput',
componentProps: {

View File

@@ -23,7 +23,8 @@ export const accountChangeGridOptions: VxeGridProps = {
slots: { default: 'change_amount' },
},
{ field: 'order_no', title: '订单号', minWidth: 160 },
{ field: 'source_table', title: '来源表', width: 140 },
// 后端 formatListItem 返回 source_table_txt中文缺省时回退英文表名
{ field: 'source_table_txt', title: '来源表', width: 140 },
{ field: 'remark', title: '备注', minWidth: 180 },
{ type: 'html', title: '操作', slots: { default: 'action' }, width: 100 },
],

View File

@@ -74,6 +74,7 @@ export const modalCardFormProps: VbenFormProps = {
{ label: '诊所', value: 1 },
{ label: '平台', value: 2 },
{ label: '供应商', value: 3 },
{ label: '配送仓库', value: 4 },
],
disabled: true,
},

View File

@@ -104,60 +104,67 @@ function updateShowStatus() {
>
<OrderDetailModal />
<Statistics v-show="isShow" :grid-api="GridApi" />
<AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
<template #trends>
<div style="min-height: 500px">
<Grid>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #user_id="{ row }">
<span v-if="row.user_type === 1">{{ row.store.name }}</span>
<span v-else-if="row.user_type === 2">萧康平台</span>
<span v-else-if="row.user_type === 3">{{
row.supplier.name
}}</span>
</template>
<template #check_status="{ row }">
<Tag v-if="row.check_status === 1" color="blue">待审核</Tag>
<Tag v-else-if="row.check_status === 2" color="green">
审核成功
</Tag>
<Tag v-else-if="row.check_status === 3" color="red">拒绝</Tag>
</template>
<template #check_result="{ row }">
<Tag v-if="row.check_status === 2" color="green">
{{ row.check_result }}
</Tag>
<Tag v-else-if="row.check_status === 3" color="red">
{{ row.check_result }}
</Tag>
</template>
<template #dakuan_status="{ row }">
<span v-if="row.dakuan_status === -1">打款失败</span>
<span v-else-if="row.dakuan_status === 0">处理中</span>
<span v-else-if="row.dakuan_status === 1">打款成功</span>
</template>
<template #check_id="{ row }">
<div style="min-height: 500px">
<AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
<template #trends>
<div style="min-height: 500px">
<Grid>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #user_id="{ row }">
<span v-if="row.user_type === 1">{{ row.store?.name }}</span>
<span v-else-if="row.user_type === 2">萧康平台</span>
<span v-else-if="row.user_type === 3">{{
row.supplier?.name
}}</span>
<span v-else-if="row.user_type === 4">{{
row.delivery_warehouse?.name || row.deliveryWarehouse?.name
}}</span>
<span v-else>-</span>
</template>
<template #check_status="{ row }">
<Tag v-if="row.check_status === 1" color="blue">待审核</Tag>
<Tag v-else-if="row.check_status === 2" color="green">
审核成功
</Tag>
<Tag v-else-if="row.check_status === 3" color="red">拒绝</Tag>
</template>
<template #check_result="{ row }">
<Tag v-if="row.check_status === 2" color="green">
{{ row.check_result }}
</Tag>
<Tag v-else-if="row.check_status === 3" color="red">
{{ row.check_result }}
</Tag>
</template>
<template #dakuan_status="{ row }">
<span v-if="row.dakuan_status === -1">打款失败</span>
<span v-else-if="row.dakuan_status === 0">处理中</span>
<span v-else-if="row.dakuan_status === 1">打款成功</span>
</template>
<template #check_id="{ row }">
<span>{{
row.check_admin?.username ||
row.check_admin?.nick_name ||
'暂无'
}}</span>
</template>
<template #action="{ row }">
<TableAction :actions="[]" :drop-down-actions="[]" />
</template>
</Grid>
</div>
</template>
<template #visits>
<div style="min-height: 500px">
<Grid3>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #action="{ row }">
<TableAction
:actions="[
row.check_admin?.username ||
row.check_admin?.nick_name ||
'暂无'
}}</span>
</template>
<template #action="{ row }">
<TableAction :actions="[]" :drop-down-actions="[]" />
</template>
</Grid>
</div>
</template>
<template #visits>
<div style="min-height: 500px">
<Grid3>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '查看明细',
type: 'link',
@@ -171,37 +178,41 @@ function updateShowStatus() {
onClick: openOrderDetail.bind(null, row),
},
]"
:drop-down-actions="[]"
/>
</template>
</Grid3>
<SettlementDetailDrawer ref="settlementDetailDrawerRef" />
</div>
</template>
<template #visitsItems>
<div style="min-height: 500px">
<Grid2>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #user_id="{ row }">
<span v-if="row.user_type === 1">{{ row.store.name }}</span>
<span v-else-if="row.user_type === 2">萧康平台</span>
<span v-else-if="row.user_type === 3">{{
row.supplier.name
}}</span>
</template>
<template #action="{ row }">
<TableAction :actions="[]" :drop-down-actions="[]" />
</template>
</Grid2>
</div>
</template>
<template #accountChange>
<div style="min-height: 500px">
<Grid4>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #change_amount="{ row }">
:drop-down-actions="[]"
/>
</template>
</Grid3>
<SettlementDetailDrawer ref="settlementDetailDrawerRef" />
</div>
</template>
<template #visitsItems>
<div style="min-height: 500px">
<Grid2>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #user_id="{ row }">
<span v-if="row.user_type === 1">{{ row.store?.name }}</span>
<span v-else-if="row.user_type === 2">萧康平台</span>
<span v-else-if="row.user_type === 3">{{
row.supplier?.name
}}</span>
<span v-else-if="row.user_type === 4">{{
row.delivery_warehouse?.name || row.deliveryWarehouse?.name
}}</span>
<span v-else>-</span>
</template>
<template #action="{ row }">
<TableAction :actions="[]" :drop-down-actions="[]" />
</template>
</Grid2>
</div>
</template>
<template #accountChange>
<div style="min-height: 500px">
<Grid4>
<template #toolbar-buttons></template>
<template #toolbar-tools></template>
<template #change_amount="{ row }">
<span
v-if="Number(row.change_amount) > 0"
style="
@@ -215,24 +226,24 @@ function updateShowStatus() {
+{{ Number(row.change_amount).toFixed(2) }}
</span>
<span
v-else-if="Number(row.change_amount) < 0"
style="
<span
v-else-if="Number(row.change_amount) < 0"
style="
color: #ff4d4f;
display: flex;
align-items: center;
gap: 4px;
"
>
>
<ArrowDownOutlined />
{{ Number(row.change_amount).toFixed(2) }}
</span>
<span v-else style="color: #999">0</span>
</template>
<template #action="{ row }">
<TableAction
:actions="[
<span v-else style="color: #999">0</span>
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: '订单详情',
type: 'link',
@@ -241,13 +252,14 @@ function updateShowStatus() {
onClick: openOrderDetail.bind(null, row),
},
]"
:drop-down-actions="[]"
/>
</template>
</Grid4>
</div>
</template>
</AnalysisChartsTabs>
:drop-down-actions="[]"
/>
</template>
</Grid4>
</div>
</template>
</AnalysisChartsTabs>
</div>
<FloatButtonGroup :style="{ right: '24px', bottom: '84px' }" shape="circle">
<Popover placement="left" title="显示余额卡片">
<template #content>

View File

@@ -0,0 +1,96 @@
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { Form, Input, InputNumber, message } from 'ant-design-vue';
import {
stockInDeliveryWarehouseDrug,
stockOutDeliveryWarehouseDrug,
} from '#/views/system/delivery-warehouse-stock/api';
defineOptions({ name: 'DeliveryWarehouseStockIoModal' });
const mode = ref<'in' | 'out'>('in');
const row = ref<Record<string, any>>({});
const qty = ref<number>(1);
const remark = ref('');
const reloadFn = ref<null | (() => void)>(null);
const title = computed(() =>
mode.value === 'in' ? '手动入库' : '手动出库',
);
const [Modal, modalApi] = useVbenModal({
fullscreenButton: false,
onConfirm: async () => {
const id = Number(row.value?.id);
const n = Number(qty.value);
if (!id || n <= 0) {
message.error('请填写正确的数量');
return;
}
modalApi.setState({ confirmLoading: true });
try {
if (mode.value === 'in') {
await stockInDeliveryWarehouseDrug({
id,
qty: n,
remark: remark.value?.trim() || undefined,
});
message.success('入库成功');
} else {
await stockOutDeliveryWarehouseDrug({
id,
qty: n,
remark: remark.value?.trim() || undefined,
});
message.success('出库成功');
}
reloadFn.value?.();
modalApi.close();
} finally {
modalApi.setState({ confirmLoading: false });
}
},
onOpenChange(isOpen) {
if (!isOpen) {
return;
}
const data = modalApi.getData<{
mode: 'in' | 'out';
row: Record<string, any>;
onSuccess?: () => void;
}>();
mode.value = data?.mode === 'out' ? 'out' : 'in';
row.value = data?.row || {};
qty.value = 1;
remark.value = '';
reloadFn.value = data?.onSuccess || null;
},
});
</script>
<template>
<Modal :title="title" class="w-[480px]">
<div class="mb-3 text-sm text-[hsl(var(--muted-foreground))]">
{{ row.drug?.drug_name || '-' }} /
可用 {{ row.available_stock ?? Math.max((row.stock || 0) - (row.frozen_number || 0), 0) }}
/ 冻结 {{ row.frozen_number ?? 0 }}
/ 库存 {{ row.stock ?? 0 }}
</div>
<Form layout="vertical">
<Form.Item :label="mode === 'in' ? '入库数量' : '出库数量'" required>
<InputNumber v-model:value="qty" :min="1" class="w-full" />
</Form.Item>
<Form.Item label="备注">
<Input.TextArea
v-model:value="remark"
:rows="3"
placeholder="可选,便于追溯"
/>
</Form.Item>
</Form>
</Modal>
</template>

View File

@@ -0,0 +1,110 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { Empty, Spin, Table, Tag } from 'ant-design-vue';
import { getDeliveryWarehouseStockLogList } from '#/views/system/delivery-warehouse-stock/api';
defineOptions({ name: 'DeliveryWarehouseStockLogDrawer' });
const loading = ref(false);
const rows = ref<Record<string, any>[]>([]);
const drugName = ref('');
const pager = reactive({
current: 1,
pageSize: 20,
total: 0,
});
const filter = reactive({
warehouse_drug_id: 0 as number,
drug_id: 0 as number,
});
const columns = [
{ title: '时间', dataIndex: 'created_at', key: 'created_at', width: 170 },
{ title: '类型', dataIndex: 'biz_type_txt', key: 'biz_type_txt', width: 120 },
{ title: '数量', dataIndex: 'qty', key: 'qty', width: 80 },
{ title: '库存前→后', key: 'stock_chg', width: 120 },
{ title: '冻结前→后', key: 'frozen_chg', width: 120 },
{ title: '订单ID', dataIndex: 'order_id', key: 'order_id', width: 90 },
{ title: '备注', dataIndex: 'remark', key: 'remark' },
];
async function loadLogs() {
if (!filter.warehouse_drug_id && !filter.drug_id) {
rows.value = [];
return;
}
loading.value = true;
try {
const res = await getDeliveryWarehouseStockLogList({
page: pager.current,
pageSize: pager.pageSize,
warehouse_drug_id: filter.warehouse_drug_id || undefined,
drug_id: filter.drug_id || undefined,
});
rows.value = res?.items ?? res?.list ?? [];
pager.total = Number(res?.total ?? 0);
} finally {
loading.value = false;
}
}
const [Drawer, drawerApi] = useVbenDrawer({
class: 'w-[720px]',
showConfirmButton: false,
onOpenChange(isOpen) {
if (!isOpen) {
return;
}
const data = drawerApi.getData<{ row: Record<string, any> }>();
const row = data?.row || {};
drugName.value = row.drug?.drug_name || '';
filter.warehouse_drug_id = Number(row.id || 0);
filter.drug_id = Number(row.drug_id || 0);
pager.current = 1;
void loadLogs();
},
});
</script>
<template>
<Drawer :title="`出入库记录${drugName ? ` - ${drugName}` : ''}`">
<Spin :spinning="loading">
<Table
v-if="rows.length"
:columns="columns"
:data-source="rows"
:pagination="{
current: pager.current,
pageSize: pager.pageSize,
total: pager.total,
onChange: (p: number) => {
pager.current = p;
void loadLogs();
},
}"
row-key="id"
size="small"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'biz_type_txt'">
<Tag>{{ record.biz_type_txt || record.biz_type }}</Tag>
</template>
<template v-else-if="column.key === 'stock_chg'">
{{ record.stock_before }} {{ record.stock_after }}
</template>
<template v-else-if="column.key === 'frozen_chg'">
{{ record.frozen_before }} {{ record.frozen_after }}
</template>
<template v-else-if="column.key === 'order_id'">
{{ record.order_id > 0 ? record.order_id : '-' }}
</template>
</template>
</Table>
<Empty v-else class="py-10" description="暂无出入库记录" />
</Spin>
</Drawer>
</template>