domesticAgreementViewer.vue 7.1 KB
<template>
  <view class="detail-page">
    <scroll-view class="scroll" scroll-y>
      <view class="section">
        <text class="row company">{{ safeText(form.procurementPlanCode) }}</text>
        <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.companyFullName) }}</text>
        </view>
        <view class="row">
          <text class="label">签订地点</text>
          <text class="value">{{ safeText(form.signPlace, '芜湖市') }}</text>
        </view>
        <view class="row">
          <text class="label">签订时间</text>
          <text class="value">{{ formatDateOnly(form.signTime) }}</text>
        </view>
        <view class="row">
          <text class="label">投诉编码</text>
          <text class="value">{{ safeText(form.procurementPlanCode) }}</text>
        </view>
        <view class="row">
          <text class="label">结算比例</text>
          <text class="value">{{ formatPercent(form.settlementRatio) }}</text>
        </view>
        <view v-if="form.createUserName" class="row">
          <text class="label">发起人</text>
          <text class="value">{{ safeText(form.createUserName) }}</text>
        </view>
        <view v-if="approvalStatusVisible" class="row">
          <text class="label">审核状态</text>
          <text class="value">{{ getAuditStatusText(form.approvalStatus) }}</text>
        </view>
        <view v-if="attachmentList.length" class="row">
          <text class="label">附件</text>
          <view class="attach-list">
            <view v-for="(at, idx) in attachmentList" :key="idx" class="attach-item">
              <text class="attach-name">{{ at.name }}</text>
              <text class="attach-view" @click.stop="onPreviewAttachment(at)">查看</text>
            </view>
          </view>
        </view>
      </view>

      <ProductRel mode="view" :list="lineList" />

      <view v-if="form.specialAgreement" class="title-header">
        <image class="title-header_icon" src="/static/images/title.png" />
        <span>特殊约定</span>
      </view>
      <view v-if="form.specialAgreement" class="section">
        <text class="remark-text">{{ safeText(form.specialAgreement) }}</text>
      </view>
    </scroll-view>
  </view>
</template>

<script>
import ProductRel from './productRel.vue'
import { domesticAgreementDetailApi } from '@/api/procure-manage/domesticAgreement.js'
import { getDicByCodes, getDicName } from '@/utils/dic.js'

export default {
  name: 'DomesticAgreementViewer',
  components: { ProductRel },
  props: {
    id: { type: [String, Number], default: '' }
  },
  data() {
    return {
      form: {},
      lineList: [],
      attachmentList: [],
      dicOptions: {
        AUDIT_STATUS: []
      }
    }
  },
  computed: {
    approvalStatusVisible() {
      return !!(this.form && this.form.approvalStatus)
    }
  },
  created() {
    this.loadDicData()
  },
  watch: {
    id: {
      immediate: true,
      handler(val) {
        const v = (val !== undefined && val !== null) ? String(val) : ''
        if (v) this.loadDetail(v)
      }
    }
  },
  methods: {
    async loadDicData() {
      try {
        const results = await getDicByCodes(['AUDIT_STATUS'])
        this.dicOptions.AUDIT_STATUS = (results.AUDIT_STATUS && results.AUDIT_STATUS.data) || []
      } catch (e) {
        this.dicOptions.AUDIT_STATUS = []
      }
    },
    getAuditStatusText(status) {
      const v = status == null ? '' : String(status)
      if (!v) return '-'
      return getDicName('AUDIT_STATUS', v, this.dicOptions.AUDIT_STATUS) || v
    },
    safeText(v, def) {
      const s = v == null ? '' : String(v)
      if (s.trim()) return s
      return def != null ? def : '-'
    },
    formatDateOnly(v) {
      const s = v == null ? '' : String(v).trim()
      if (!s) return '-'
      if (s.length >= 10) return s.slice(0, 10)
      return s
    },
    formatPercent(v) {
      if (v === null || v === undefined || v === '') return '-'
      const n = Number(v)
      if (isNaN(n)) return String(v)
      return n + '%'
    },
    buildAttachmentList() {
      const ids = this.form.attachmentFileIds
      const names = this.form.attachmentFileNames
      const idArr = (typeof ids === 'string' && ids) ? ids.split(',').filter(Boolean) : (Array.isArray(ids) ? ids : [])
      const nameArr = (typeof names === 'string' && names) ? names.split(',').filter(Boolean) : (Array.isArray(names) ? names : [])
      const len = Math.max(idArr.length, nameArr.length)
      const list = []
      for (let i = 0; i < len; i++) {
        list.push({ id: idArr[i] || '', name: nameArr[i] || ('附件' + (i + 1)) })
      }
      this.attachmentList = list
    },
    getFormValues() {
      return JSON.parse(JSON.stringify(this.form || {}))
    },
    checkForm() {
      return true
    },
    async loadDetail(id) {
      try {
        const res = await domesticAgreementDetailApi({ id: id })
        const data = res && res.data ? (res.data.data || res.data) : {}
        this.form = Object.assign({}, data)
        const lines = data && Array.isArray(data.procurementContractLineList) ? data.procurementContractLineList : []
        this.lineList = lines.map(l => Object.assign({}, l))
        this.buildAttachmentList()
      } catch (e) {
        this.form = {}
        this.lineList = []
        this.attachmentList = []
      }
    },
    onPreviewAttachment(at) {
      if (!at || !at.id) {
        uni.showToast({ title: '无法查看', icon: 'none' })
        return
      }
      uni.showToast({ title: '查看附件 ' + at.name, icon: 'none' })
    }
  }
}
</script>

<style lang="scss" scoped>
.detail-page {
  background: #f3f3f3;
}
.scroll {
  flex: 1;
  padding: 8rpx 0 144rpx;
}
.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);
  }
}
.section {
  padding: 32rpx;
  background: #fff;
  margin-bottom: 20rpx;
}
.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;
  }
}
.attach-list {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8rpx;
}
.attach-item {
  display: flex;
  align-items: center;
  gap: 16rpx;
  .attach-name {
    font-size: 26rpx;
    color: rgba(0, 0, 0, 0.9);
  }
  .attach-view {
    font-size: 26rpx;
    color: $theme-primary;
  }
}
.remark-text {
  font-size: 28rpx;
  color: rgba(0, 0, 0, 0.9);
  line-height: 1.6;
  white-space: pre-wrap;
}
</style>