detail.vue 12.2 KB
<template>
  <view class="page">
    <scroll-view class="scroll" scroll-y>
      <view class="detail-page">
        <!-- 基础信息 -->
        <view class="section">
          <text class="row company">{{ safeText(form.code) }}</text>
          <view class="row"><text class="label">类型</text><text class="value">{{ safeText(form.type) }}</text></view>
          <view class="row"><text class="label">计划编号</text><text class="value">{{ safeText(form.unit) }}</text></view>
          <view class="row"><text class="label">时间</text><text class="value">{{ formatDate(form.firstGrossWeightTime) }}</text></view>
          <view class="row"><text class="label">供料单位</text><text class="value">{{ safeText(form.supplierName) }}</text></view>
          <view class="row"><text class="label">收料单位</text><text class="value">{{ safeText(form.companyShortName) }}</text></view>
          <view class="row"><text class="label">物料名称</text><text class="value">{{ safeText(form.materialName) }}</text></view>
          <view class="row"><text class="label">过磅总重</text><text class="value">{{ formatNumber(form.totalGrossWeight) }}</text></view>
          <view class="row"><text class="label">实际伙重</text><text class="value">{{ formatNumber(form.actualImpurityWeight) }}</text></view>
          <view class="row"><text class="label">货物净重</text><text class="value">{{ formatNumber(form.netWeight) }}</text></view>
          <view class="row"><text class="label">净重大写</text><text class="value">{{ safeText(form.netWeightUpper) }}</text></view>
          <view class="row"><text class="label">来料扣杂类型</text><text class="value">{{ safeText(form.deductionTypes) }}</text></view>
          <view class="row"><text class="label">供应存欠料</text><text class="value">{{ safeText(form.supplierStockMaterial) }}</text></view>
          <view class="row"><text class="label">物流存欠料</text><text class="value">{{ safeText(form.logisticsStockMaterial) }}</text></view>
          <view class="row"><text class="label">车牌号</text><text class="value">{{ safeText(form.plateNumber) }}</text></view>
        </view>

        <!-- 业务摘要 -->
        <view class="title-header">
          <image class="title-header_icon" src="/static/images/title.png" />
          <span>业务摘要</span>
        </view>
        <view class="section">
          <text class="remark-text">{{ safeText(form.businessSummary) }}</text>
        </view>

        <!-- 特别说明 -->
        <view class="title-header">
          <image class="title-header_icon" src="/static/images/title.png" />
          <span>特别说明</span>
        </view>
        <view class="section">
          <text class="remark-text">{{ safeText(form.specialNote) }}</text>
        </view>

        <!-- 单据备注 -->
        <view class="title-header">
          <image class="title-header_icon" src="/static/images/title.png" />
          <span>单据备注</span>
        </view>
        <view class="section">
          <text class="remark-text">{{ safeText(form.specialNote) }}</text>
        </view>

        <!-- 计划单明细 -->
        <view class="sub-table">
          <view class="sub-header">
            <image class="sub-bar" src="/static/images/title.png" />
            <text class="sub-title">计划单明细</text>
            <view class="sub-toggle" @click="toggle('plan')">
              <image class="sub-toggle_icon" :src="collapse.plan ? '/static/images/down.png' : '/static/images/up.png'" />
              <text class="sub-toggle_text">{{ collapse.plan ? '展开' : '收起' }}</text>
            </view>
          </view>
          <view v-if="!collapse.plan" class="sub-body">
            <view v-if="!planList.length" class="empty-tip">暂无明细</view>
            <view v-for="(item, idx) in planList" :key="'p-' + (item.id || idx)" class="card">
              <view class="card-index">第 {{ idx + 1 }} 行</view>
              <view class="row"><text class="label">计划品种</text><text class="value">{{ safeText(item.productName) }}</text></view>
              <view class="row"><text class="label">计划数量</text><text class="value">{{ formatNumber(item.quantity) }}</text></view>
              <view class="row"><text class="label">计划编号</text><text class="value">{{ safeText(item.planCode) }}</text></view>
            </view>
          </view>
        </view>

        <!-- 过磅明细 -->
        <view class="sub-table">
          <view class="sub-header">
            <image class="sub-bar" src="/static/images/title.png" />
            <text class="sub-title">过磅明细</text>
            <view class="sub-toggle" @click="toggle('weigh')">
              <image class="sub-toggle_icon" :src="collapse.weigh ? '/static/images/down.png' : '/static/images/up.png'" />
              <text class="sub-toggle_text">{{ collapse.weigh ? '展开' : '收起' }}</text>
            </view>
          </view>
          <view v-if="!collapse.weigh" class="sub-body">
            <view v-if="!weighList.length" class="empty-tip">暂无明细</view>
            <view v-for="(item, idx) in weighList" :key="'w-' + (item.id || idx)" class="card">
              <view class="card-index">第 {{ idx + 1 }} 行</view>
              <view class="row"><text class="label">过磅品种</text><text class="value">{{ safeText(item.productName) }}</text></view>
              <view class="row"><text class="label">开票品名</text><text class="value">{{ safeText(item.invoiceProductName) }}</text></view>
              <view class="row"><text class="label">过磅数量</text><text class="value">{{ formatNumber(item.quantity) }}</text></view>
              <view class="row"><text class="label">计划编号</text><text class="value">{{ safeText(item.planCode) }}</text></view>
            </view>
          </view>
        </view>

        <!-- 申请数量明细 -->
        <view class="sub-table">
          <view class="sub-header">
            <image class="sub-bar" src="/static/images/title.png" />
            <text class="sub-title">申请数量明细</text>
            <view class="sub-toggle" @click="toggle('apply')">
              <image class="sub-toggle_icon" :src="collapse.apply ? '/static/images/down.png' : '/static/images/up.png'" />
              <text class="sub-toggle_text">{{ collapse.apply ? '展开' : '收起' }}</text>
            </view>
          </view>
          <view v-if="!collapse.apply" class="sub-body">
            <view v-if="!applyList.length" class="empty-tip">暂无明细</view>
            <view v-for="(item, idx) in applyList" :key="'a-' + (item.id || idx)" class="card">
              <view class="card-index">第 {{ idx + 1 }} 行</view>
              <view class="row"><text class="label">类别</text><text class="value">{{ safeText(item.category) }}</text></view>
              <view class="row"><text class="label">数量</text><text class="value">{{ formatNumber(item.quantity) }}</text></view>
            </view>
          </view>
        </view>
      </view>
    </scroll-view>
  </view>
</template>

<script>
import { weighTicketDetailApi } from '@/api/procure-manage/weighTicket.js'

export default {
  name: 'WeightTicketDetail',
  data() {
    return {
      id: '',
      form: {},
      planList: [],
      weighList: [],
      applyList: [],
      collapse: { plan: false, weigh: false, apply: false }
    }
  },
  onLoad(query) {
    this.id = (query && query.id) || ''
    this.loadDetail()
  },
  onShow() {
    let needRefresh = ''
    try { needRefresh = uni.getStorageSync('WEIGHT_TICKET_DETAIL_NEED_REFRESH') } catch (e) {}
    if (!needRefresh) return
    try { uni.removeStorageSync('WEIGHT_TICKET_DETAIL_NEED_REFRESH') } catch (e) {}
    this.loadDetail()
  },
  methods: {
    toggle(key) {
      this.collapse = { ...this.collapse, [key]: !this.collapse[key] }
    },
    loadDetail() {
      if (!this.id) {
        uni.showToast({ title: '缺少单据ID', icon: 'none' })
        return
      }
      uni.showLoading && uni.showLoading({ title: '加载中...', mask: true })
      weighTicketDetailApi({ id: this.id })
        .then(res => {
          const data = res && res.data ? (res.data.data || res.data) : {}
          this.form = Object.assign({}, data)
          this.planList = this.pickList(data, ['planDetailList', 'planLineList', 'procurementPlanLineList'])
          this.weighList = this.pickList(data, ['weighDetailList', 'weighLineList', 'grossWeightList'])
          this.applyList = this.pickList(data, ['applyQuantityList', 'applyDetailList', 'applyLineList'])
        })
        .catch(() => {
          uni.showToast({ title: '详情加载失败', icon: 'none' })
        })
        .finally(() => {
          uni.hideLoading && uni.hideLoading()
        })
    },
    pickList(data, keys) {
      if (!data) return []
      for (const k of keys) {
        if (Array.isArray(data[k])) return data[k].map(x => Object.assign({}, x))
      }
      return []
    },
    safeText(v) {
      const s = v == null ? '' : String(v)
      return s.trim() ? s : '-'
    },
    formatNumber(v) {
      if (v === null || v === undefined || v === '') return '-'
      const n = Number(v)
      if (isNaN(n)) return String(v)
      return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 })
    },
    formatDate(v) {
      const s = v == null ? '' : String(v).trim()
      if (!s) return '-'
      return s
    }
  }
}
</script>

<style lang="scss" scoped>
.page {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.scroll {
  flex: 1;
  padding: 8rpx 0 32rpx;
}
.detail-page {
  background: #f3f3f3;
}
.section {
  padding: 32rpx;
  background: #fff;
  margin-bottom: 20rpx;
}
.title-header {
  display: flex;
  align-items: center;
  padding: 24rpx 32rpx 12rpx;
  background-color: #ffffff;
  .title-header_icon { width: 36rpx; height: 36rpx; margin-right: 12rpx; }
  span { font-size: 34rpx; font-weight: 600; color: rgba(0, 0, 0, 0.9); }
}
.row {
  display: flex;
  margin-bottom: 28rpx;
  &:last-child { margin-bottom: 0; }
  &.company {
    font-size: 36rpx;
    font-weight: 600;
    color: rgba(0, 0, 0, 0.9);
    padding-top: 8rpx;
    line-height: 50rpx;
  }
  .label {
    max-width: 420rpx;
    margin-right: 20rpx;
    line-height: 32rpx;
    font-size: 28rpx;
    color: rgba(0, 0, 0, 0.6);
  }
  .value {
    flex: 1;
    line-height: 32rpx;
    font-size: 28rpx;
    color: rgba(0, 0, 0, 0.9);
    text-align: right;
    word-break: break-all;
  }
}
.remark-text {
  font-size: 28rpx;
  color: rgba(0, 0, 0, 0.9);
  line-height: 1.6;
  white-space: pre-wrap;
}
.sub-table {
  background: #fff;
  margin-bottom: 20rpx;
}
.sub-header {
  display: flex;
  align-items: center;
  padding: 16rpx 0 16rpx 32rpx;
  .sub-bar { width: 6rpx; height: 32rpx; margin-right: 14rpx; }
  .sub-title { font-size: 30rpx; font-weight: 600; color: rgba(0, 0, 0, 0.9); flex: 1; line-height: 42rpx; }
  .sub-toggle {
    display: flex;
    align-items: center;
    padding: 0 12rpx;
    height: 56rpx;
    .sub-toggle_icon { width: 24rpx; height: 24rpx; margin-right: 8rpx; }
    .sub-toggle_text { font-size: 26rpx; color: rgba(0, 0, 0, 0.6); }
  }
}
.sub-body {
  padding: 0 32rpx 24rpx;
  .empty-tip {
    text-align: center;
    padding: 60rpx 0;
    color: rgba(0, 0, 0, 0.4);
    font-size: 28rpx;
  }
  .card {
    position: relative;
    background: #fafafa;
    border-radius: 12rpx;
    padding: 32rpx 28rpx 20rpx;
    margin-bottom: 24rpx;
    .card-index {
      position: absolute;
      top: 0;
      right: 0;
      background: rgba(24, 144, 255, 0.08);
      color: $theme-primary;
      font-size: 22rpx;
      line-height: 36rpx;
      padding: 0 16rpx;
      border-bottom-left-radius: 12rpx;
      border-top-right-radius: 12rpx;
    }
    .row {
      align-items: center;
      justify-content: space-between;
      padding: 14rpx 0;
      margin-bottom: 0;
      border-bottom: 1rpx dashed #f2f2f2;
      &:last-child { border-bottom: none; }
      .label {
        flex-shrink: 0;
        width: 220rpx;
        max-width: none;
        margin-right: 0;
        font-size: 28rpx;
        color: rgba(0, 0, 0, 0.6);
        line-height: 40rpx;
      }
      .value {
        flex: 1;
        text-align: right;
        font-size: 28rpx;
        color: rgba(0, 0, 0, 0.9);
        line-height: 40rpx;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
}
</style>