1. 配送仓库
This commit is contained in:
@@ -3,7 +3,7 @@ import { computed, nextTick, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
import { Button, Descriptions, Image, Tag, Timeline } from 'ant-design-vue';
|
||||
import { Button, Descriptions, Image, Tabs, Tag, Timeline } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
expressDetailByOrderId,
|
||||
@@ -21,9 +21,23 @@ const logisticsAnchorRef = ref<HTMLElement | null>(null);
|
||||
/** 待发货时由列表传入,点击后关详情并打开发货弹窗 */
|
||||
const onShipFn = ref<null | (() => void)>(null);
|
||||
|
||||
const canShip = computed(
|
||||
() => Number(data.value.status) === 1 && typeof onShipFn.value === 'function',
|
||||
);
|
||||
const canShip = computed(() => {
|
||||
const packages = Array.isArray(data.value.packages) ? data.value.packages : [];
|
||||
const mineUnsent = packages.some((p: any) => Number(p.is_send) === 0);
|
||||
const legacy =
|
||||
Number(data.value.warehouse_is_send ?? 0) === 0 &&
|
||||
Number(data.value.status) === 1;
|
||||
return (mineUnsent || legacy) && typeof onShipFn.value === 'function';
|
||||
});
|
||||
const packageTabs = computed(() => {
|
||||
const packages = Array.isArray(data.value.packages)
|
||||
? data.value.packages
|
||||
: Array.isArray(expressDetail.value.packages)
|
||||
? expressDetail.value.packages
|
||||
: [];
|
||||
return packages;
|
||||
});
|
||||
const activePkg = ref('0');
|
||||
|
||||
const statusMap: Record<number, { text: string; color: string }> = {
|
||||
0: { text: '待支付', color: 'default' },
|
||||
@@ -219,8 +233,50 @@ const [Modal, modalApi] = useVbenModal({
|
||||
|
||||
<section ref="logisticsAnchorRef">
|
||||
<h3 class="section-title">物流信息</h3>
|
||||
<Tabs v-if="packageTabs.length" v-model:active-key="activePkg" type="card">
|
||||
<Tabs.TabPane
|
||||
v-for="(pkg, idx) in packageTabs"
|
||||
:key="String(idx)"
|
||||
:tab="`包裹${pkg.package_no || idx + 1}(${pkg.warehouse_name || '本仓'})`"
|
||||
>
|
||||
<template v-if="Number(pkg.is_send) === 1 && pkg.express">
|
||||
<Descriptions
|
||||
:column="{ xxl: 2, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }"
|
||||
bordered
|
||||
size="small"
|
||||
>
|
||||
<Descriptions.Item label="物流公司">
|
||||
{{ pkg.express.express_company_name || '-' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="运单号">
|
||||
{{ pkg.express.express_no || '-' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="最新状态">
|
||||
{{ pkg.express.state_txt || '-' }}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<div
|
||||
v-if="Array.isArray(pkg.express.detail) && pkg.express.detail.length"
|
||||
class="mt-4"
|
||||
>
|
||||
<Timeline>
|
||||
<Timeline.Item
|
||||
v-for="(detail, dIdx) in pkg.express.detail"
|
||||
:key="dIdx"
|
||||
>
|
||||
<Tag :color="getColor(detail.status)">{{ detail.status }}</Tag>
|
||||
<p>{{ detail.detail_at }}</p>
|
||||
<p>{{ detail.detail }}</p>
|
||||
</Timeline.Item>
|
||||
</Timeline>
|
||||
</div>
|
||||
<div v-else class="empty-tip mt-3">暂无物流轨迹</div>
|
||||
</template>
|
||||
<div v-else class="empty-tip">本包裹尚未发货</div>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
<template
|
||||
v-if="
|
||||
v-else-if="
|
||||
Number(data.is_send) === 1 ||
|
||||
Number(data.status) >= 2 ||
|
||||
expressNoRow().express_no ||
|
||||
@@ -249,21 +305,17 @@ const [Modal, modalApi] = useVbenModal({
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<div v-if="Array.isArray(expressDetail.detail) && expressDetail.detail.length" class="mt-4">
|
||||
<h4 class="mb-2 text-sm font-medium">物流追踪</h4>
|
||||
<Timeline>
|
||||
<Timeline.Item
|
||||
v-for="(detail, index) in expressDetail.detail"
|
||||
:key="index"
|
||||
>
|
||||
<Tag :color="getColor(detail.status)">
|
||||
{{ detail.status }}
|
||||
</Tag>
|
||||
<Tag :color="getColor(detail.status)">{{ detail.status }}</Tag>
|
||||
<p>{{ detail.detail_at }}</p>
|
||||
<p>{{ detail.detail }}</p>
|
||||
</Timeline.Item>
|
||||
</Timeline>
|
||||
</div>
|
||||
<div v-else class="empty-tip mt-3">暂无物流轨迹</div>
|
||||
</template>
|
||||
<div v-else class="empty-tip">暂无物流</div>
|
||||
</section>
|
||||
|
||||
@@ -120,7 +120,7 @@ function openDetail(row: Record<string, any>, scrollToLogistics = false) {
|
||||
id: row?.id,
|
||||
scrollToLogistics,
|
||||
onShip:
|
||||
Number(row?.status) === 1
|
||||
Number(row?.warehouse_is_send ?? 0) === 0 || Number(row?.status) === 1
|
||||
? () => {
|
||||
detailModalApi.close();
|
||||
wareSend(row);
|
||||
@@ -284,7 +284,7 @@ onMounted(() => {
|
||||
物流
|
||||
</Button>
|
||||
<Button
|
||||
v-if="Number(row.status) === 1"
|
||||
v-if="Number(row.warehouse_is_send ?? 0) === 0"
|
||||
size="small"
|
||||
type="link"
|
||||
@click="wareSend(row)"
|
||||
|
||||
@@ -31,14 +31,28 @@ const newQuickName = ref('');
|
||||
const newQuickValue = ref<number | null>(null);
|
||||
const inputAutoAuditPass = ref(true);
|
||||
const miniprogramEmptyImage = ref('');
|
||||
/** 患者端物流是否显示配送仓名(默认否) */
|
||||
const logisticsShowWhNameUser = ref(false);
|
||||
/** 诊所端物流是否显示配送仓名(默认是) */
|
||||
const logisticsShowWhNameClinic = ref(true);
|
||||
|
||||
function readStoredTab() {
|
||||
const stored = localStorage.getItem(TAB_STORAGE_KEY);
|
||||
if (stored === 'price_adjust' || stored === 'input_audit' || stored === 'miniprogram') {
|
||||
if (
|
||||
stored === 'price_adjust' ||
|
||||
stored === 'input_audit' ||
|
||||
stored === 'miniprogram' ||
|
||||
stored === 'logistics'
|
||||
) {
|
||||
activeKey.value = stored;
|
||||
}
|
||||
}
|
||||
|
||||
function parseBoolConfig(val: unknown, defaultVal: boolean): boolean {
|
||||
if (val === undefined || val === null || val === '') return defaultVal;
|
||||
return val === '1' || val === 1 || val === true || val === 'true';
|
||||
}
|
||||
|
||||
function handleTabChange(key: string | number) {
|
||||
activeKey.value = String(key);
|
||||
localStorage.setItem(TAB_STORAGE_KEY, String(key));
|
||||
@@ -84,6 +98,12 @@ async function load() {
|
||||
if (row.config_key === 'miniprogram_empty_image') {
|
||||
miniprogramEmptyImage.value = String(row.config_value || '');
|
||||
}
|
||||
if (row.config_key === 'logistics_show_warehouse_name_user') {
|
||||
logisticsShowWhNameUser.value = parseBoolConfig(row.config_value, false);
|
||||
}
|
||||
if (row.config_key === 'logistics_show_warehouse_name_clinic') {
|
||||
logisticsShowWhNameClinic.value = parseBoolConfig(row.config_value, true);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
@@ -125,6 +145,14 @@ async function handleSave() {
|
||||
config_key: 'miniprogram_empty_image',
|
||||
config_value: miniprogramEmptyImage.value,
|
||||
},
|
||||
{
|
||||
config_key: 'logistics_show_warehouse_name_user',
|
||||
config_value: logisticsShowWhNameUser.value ? '1' : '0',
|
||||
},
|
||||
{
|
||||
config_key: 'logistics_show_warehouse_name_clinic',
|
||||
config_value: logisticsShowWhNameClinic.value ? '1' : '0',
|
||||
},
|
||||
]);
|
||||
message.success('保存成功');
|
||||
} finally {
|
||||
@@ -188,6 +216,33 @@ onMounted(() => {
|
||||
<FormAvatar v-model:value="miniprogramEmptyImage" />
|
||||
</div>
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane key="logistics" tab="物流展示">
|
||||
<div class="py-4 space-y-6">
|
||||
<div>
|
||||
<div class="mb-2 font-medium">患者端:物流多包裹是否显示配送仓名称</div>
|
||||
<div class="mb-2 text-sm text-gray-500">
|
||||
关闭后患者端仅显示「包裹1」「包裹2」,不展示仓名
|
||||
</div>
|
||||
<Switch
|
||||
v-model:checked="logisticsShowWhNameUser"
|
||||
checked-children="显示"
|
||||
un-checked-children="隐藏"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-2 font-medium">诊所端:物流多包裹是否显示配送仓名称</div>
|
||||
<div class="mb-2 text-sm text-gray-500">
|
||||
关闭后诊所/商家小程序订单物流仅显示包裹序号;平台后台产品订单不受影响
|
||||
</div>
|
||||
<Switch
|
||||
v-model:checked="logisticsShowWhNameClinic"
|
||||
checked-children="显示"
|
||||
un-checked-children="隐藏"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
|
||||
<div class="mt-4">
|
||||
|
||||
Reference in New Issue
Block a user