191 lines
7.0 KiB
Vue
191 lines
7.0 KiB
Vue
<script setup>
|
|
import { ref, computed } from 'vue'
|
|
import { onLoad, onShow } from '@dcloudio/uni-app'
|
|
import { getPlan, getPlanArrangeInfo, archivePlan } from '@/api/pl'
|
|
import {
|
|
dash,
|
|
planTypeLabel,
|
|
followStatusLabel,
|
|
transportStatusLabel,
|
|
archiveStatusLabel,
|
|
planCardSub,
|
|
formatQty
|
|
} from '@/utils/plLabels'
|
|
import { PAGE_PATHS } from '@/config/api'
|
|
|
|
const id = ref('')
|
|
const readonly = ref(false)
|
|
const detail = ref(null)
|
|
const arrange = ref(null)
|
|
const acting = ref(false)
|
|
|
|
const phaseFollow = computed(() => followStatusLabel(detail.value?.followStatus))
|
|
const phaseTransport = computed(() => transportStatusLabel(detail.value?.transportStatus))
|
|
const phaseArchive = computed(() => archiveStatusLabel(detail.value?.archiveStatus))
|
|
const products = computed(() =>
|
|
Array.isArray(detail.value?.products) ? detail.value.products : []
|
|
)
|
|
const canArrange = computed(
|
|
() =>
|
|
!readonly.value &&
|
|
detail.value?.transportStatus === 'pending' &&
|
|
detail.value?.followStatus !== 'cancelled' &&
|
|
detail.value?.followStatus !== 'completed'
|
|
)
|
|
const canArchive = computed(
|
|
() =>
|
|
!readonly.value &&
|
|
detail.value?.archiveStatus !== 'archived' &&
|
|
detail.value?.transportStatus === 'arranged' &&
|
|
detail.value?.followStatus !== 'cancelled'
|
|
)
|
|
|
|
const goBack = () => {
|
|
uni.navigateBack({
|
|
fail: () =>
|
|
uni.navigateTo({
|
|
url: readonly.value ? PAGE_PATHS.plArchiveList : PAGE_PATHS.plPlanList
|
|
})
|
|
})
|
|
}
|
|
|
|
const goArrange = () =>
|
|
uni.navigateTo({ url: `${PAGE_PATHS.plPlanArrange}?id=${id.value}` })
|
|
|
|
const load = async () => {
|
|
if (!id.value) return
|
|
try {
|
|
detail.value = await getPlan(id.value)
|
|
if (detail.value?.transportStatus === 'arranged') {
|
|
try {
|
|
arrange.value = await getPlanArrangeInfo(id.value)
|
|
} catch {
|
|
arrange.value = null
|
|
}
|
|
} else {
|
|
arrange.value = null
|
|
}
|
|
} catch (e) {
|
|
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
|
|
}
|
|
}
|
|
|
|
const onArchive = () => {
|
|
const list = products.value
|
|
if (!list.length) {
|
|
uni.showToast({ title: '无产品明细,无法归档', icon: 'none' })
|
|
return
|
|
}
|
|
uni.showModal({
|
|
title: '确认归档',
|
|
content: '将按计划数量写入实际数量并归档。复杂调整请在 Web 端操作。',
|
|
success: async (r) => {
|
|
if (!r.confirm) return
|
|
acting.value = true
|
|
try {
|
|
await archivePlan(id.value, {
|
|
products: list.map((p) => ({
|
|
id: p.id,
|
|
actualQty: Number(p.actualQty != null ? p.actualQty : p.quantity) || 0
|
|
}))
|
|
})
|
|
uni.showToast({ title: '已归档', icon: 'success' })
|
|
load()
|
|
} catch (e) {
|
|
uni.showToast({ title: e.message || '归档失败', icon: 'none' })
|
|
} finally {
|
|
acting.value = false
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
onLoad((q) => {
|
|
id.value = q?.id || ''
|
|
readonly.value = q?.readonly === '1' || q?.mode === 'archive'
|
|
})
|
|
onShow(() => load())
|
|
</script>
|
|
|
|
<template>
|
|
<view class="mp-page mp-page--sub mp-page--with-bottom">
|
|
<view class="mp-header mp-header--pl">
|
|
<text class="mp-subpage-back" @click="goBack">← 返回</text>
|
|
<text class="mp-header__title" style="margin-top: 16rpx">
|
|
{{ readonly ? '归档详情' : '计划详情' }}
|
|
</text>
|
|
</view>
|
|
|
|
<view v-if="detail" class="mp-detail-hero">
|
|
<view class="mp-detail-hero__top">
|
|
<view>
|
|
<text class="mp-detail-hero__title">{{ dash(detail.planNo) }}</text>
|
|
<text class="mp-detail-hero__sub">{{ planCardSub(detail) }}</text>
|
|
</view>
|
|
<text class="mp-tag" :class="'mp-tag--' + phaseTransport.tag">{{ phaseTransport.text }}</text>
|
|
</view>
|
|
<view class="mp-detail-hero__meta">
|
|
<text class="mp-detail-hero__chip">{{ planTypeLabel(detail.planType) }}</text>
|
|
<text class="mp-detail-hero__chip">{{ phaseFollow.text }}</text>
|
|
<text class="mp-detail-hero__chip">{{ phaseArchive.text }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="mp-block">
|
|
<text class="mp-block__title">基本信息</text>
|
|
<view class="mp-block__panel">
|
|
<view class="mp-kv"><text class="mp-kv__label">计划日期</text><text class="mp-kv__value">{{ dash(detail?.planDate) }}</text></view>
|
|
<view class="mp-kv"><text class="mp-kv__label">客户</text><text class="mp-kv__value">{{ dash(detail?.customerName) }}</text></view>
|
|
<view class="mp-kv"><text class="mp-kv__label">供应商</text><text class="mp-kv__value">{{ dash(detail?.supplierName) }}</text></view>
|
|
<view class="mp-kv"><text class="mp-kv__label">取货地址</text><text class="mp-kv__value">{{ dash(detail?.pickupAddress) }}</text></view>
|
|
<view class="mp-kv"><text class="mp-kv__label">送货地址</text><text class="mp-kv__value">{{ dash(detail?.destinationAddress) }}</text></view>
|
|
<view class="mp-kv"><text class="mp-kv__label">联系人</text><text class="mp-kv__value">{{ dash(detail?.contactName) }} {{ dash(detail?.contactPhone) }}</text></view>
|
|
<view class="mp-kv"><text class="mp-kv__label">跟进人</text><text class="mp-kv__value">{{ dash(detail?.followUserName) }}</text></view>
|
|
<view class="mp-kv"><text class="mp-kv__label">备注</text><text class="mp-kv__value">{{ dash(detail?.remark) }}</text></view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="mp-block">
|
|
<text class="mp-block__title">产品明细</text>
|
|
<mp-empty v-if="!products.length" compact title="暂无明细" />
|
|
<view v-else class="mp-block__panel">
|
|
<view v-for="p in products" :key="p.id" class="mp-kv">
|
|
<text class="mp-kv__label">{{ dash(p.productName) }}</text>
|
|
<text class="mp-kv__value">{{ formatQty(p.quantity, p.unit) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="detail?.transportStatus === 'arranged'" class="mp-block">
|
|
<text class="mp-block__title">运输安排</text>
|
|
<view class="mp-block__panel">
|
|
<view class="mp-kv">
|
|
<text class="mp-kv__label">车牌</text>
|
|
<text class="mp-kv__value">{{ dash(arrange?.licensePlate || detail.licensePlate) }}</text>
|
|
</view>
|
|
<view class="mp-kv">
|
|
<text class="mp-kv__label">司机</text>
|
|
<text class="mp-kv__value">{{ dash(detail.driverName) }}</text>
|
|
</view>
|
|
<view class="mp-kv">
|
|
<text class="mp-kv__label">承运商</text>
|
|
<text class="mp-kv__value">{{ dash(detail.carrierName) }}</text>
|
|
</view>
|
|
<view v-if="arrange?.driverUrl" class="mp-kv">
|
|
<text class="mp-kv__label">司机扫码</text>
|
|
<text class="mp-kv__value">已生成链接</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-if="canArrange || canArchive" class="mp-bottom-bar">
|
|
<button v-if="canArrange" class="mp-btn mp-btn--primary mp-btn--block" :disabled="acting" @click="goArrange">
|
|
安排运输
|
|
</button>
|
|
<button v-if="canArchive" class="mp-btn mp-btn--primary mp-btn--block" :disabled="acting" @click="onArchive">
|
|
归档
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</template>
|