salesmanQuotationViewer.vue 10.8 KB
<template>
    <view class="detail-page">
        <scroll-view class="scroll" scroll-y>
            <!-- 基础信息 -->
            <view class="section">
                <text class="row company">{{ safeText(form.code) }}</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.purchaseDepartmentName) }}</text></view>
                <view class="row"><text class="label">区域</text><text class="value">{{ safeText(form.regionName) }}</text></view>
                <view class="row"><text class="label">报价时效</text><text class="value">{{ safeText(form.validityPeriod) }}</text></view>
                <view class="row"><text class="label">报价人</text><text class="value">{{ safeText(form.quoterName) }}</text></view>
                <view class="row"><text class="label">是否长单操作</text><text class="value">{{ boolText(form.longTermOperation) }}</text></view>
                <view class="row"><text class="label">是否终端客户</text><text class="value">{{ boolText(form.terminalCustomer) }}</text></view>
                <view class="row"><text class="label">是否未点价</text><text class="value">{{ boolText(form.priced) }}</text></view>
                <view v-if="form.priced === true" class="row"><text class="label">点价截止日期</text><text class="value">{{ formatDateOnly(form.pricingDeadline) }}</text></view>
                <view v-if="form.priced === true" class="row"><text class="label">是否暂定价</text><text class="value">{{ boolText(form.temporaryPrice) }}</text></view>
                <view class="row"><text class="label">其他费用凭票到厂另行结算</text><text class="value">{{ boolText(form.otherExpenseSettlement) }}</text></view>
                <view class="row"><text class="label">交提货方式</text><text class="value">{{ getDeliveryMethodLabel() }}</text></view>
                <view class="row"><text class="label">是否通货买断</text><text class="value">{{ boolText(form.commodityBuyout) }}</text></view>
                <view class="row"><text class="label">是否质量买断</text><text class="value">{{ boolText(form.qualityBuyout) }}</text></view>
                <view class="row"><text class="label">是否数量买断</text><text class="value">{{ boolText(form.quantityBuyout) }}</text></view>
                <view class="row"><text class="label">是否送货上门</text><text class="value">{{ boolText(form.doorDelivery) }}</text></view>
                <view class="row"><text class="label">装车费</text><text class="value">{{ safeText(form.loadingFee) }}</text></view>
                <view class="row"><text class="label">开票品种</text><text class="value">{{ safeText(form.invoiceProductName) }}</text></view>
                <view class="row"><text class="label">交货日期</text><text class="value">{{ formatDateOnly(form.deliveryDate) }}</text></view>
                <view class="row"><text class="label">结算方式</text><text class="value">{{ safeText(form.settlementMethod) }}</text></view>
                <view class="row"><text class="label">结算比例(%)</text><text class="value">{{ safeText(form.settlementRatio) }}</text></view>
                <view class="row"><text class="label">协调事由</text><text class="value">{{ safeText(form.coordinationReason) }}</text></view>
                <view class="row"><text class="label">票类状况</text><text class="value">{{ safeText(form.invoiceTypeStatus) }}</text></view>
            </view>

            <!-- 明细信息 -->
            <ProductRel mode="view" :list="productLineList" />

            <!-- 料质状况 -->
            <view class="title-header">
                <image class="title-header_icon" src="/static/images/title.png" />
                <span>料质状况</span>
            </view>
            <view class="section">
                <view class="row"><text class="label">是否启用料质状况</text><text class="value">{{ boolText(form.materialConditionEnabled) }}</text></view>
                <template v-if="form.materialConditionEnabled">
                    <view v-for="mc in materialConditionConfigs" :key="mc.field" class="material-group">
                        <text class="material-label">{{ mc.label }}</text>
                        <view class="tag-list">
                            <view
                                v-for="opt in getDictOptions(mc.dictCode)"
                                :key="opt.code"
                                class="tag-btn"
                                :class="{ active: isTagSelected(mc.field, opt.code) }"
                            >{{ opt.name }}</view>
                        </view>
                    </view>
                </template>
            </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.remark) }}</text>
            </view>
        </scroll-view>
    </view>
</template>
<script>
import ProductRel from './productRel.vue'
import { salesmanQuotationDetailApi } from '@/api/procure-manage/salesmanQuotation.js'
import { getDicByCodes } from '@/utils/dic.js'

export default {
    name: 'SalesmanQuotationViewer',
    components: { ProductRel },
    props: { id: { type: [String, Number], default: '' } },
    data() {
        return {
            form: {},
            productLineList: [],
            materialConditionConfigs: [
                { field: 'materialConditionCopperRice', label: '铜米', dictCode: 'COPPER_RICE' },
                { field: 'materialConditionBrightCopper', label: '光亮铜', dictCode: 'BRIGHT_COPPER' },
                { field: 'materialConditionFirstClass', label: '一特', dictCode: 'FIRST_CLASS' },
                { field: 'materialConditionSecondClass', label: '二特', dictCode: 'SECOND_CLASS' },
                { field: 'materialConditionTinCoated', label: '镀锡紫', dictCode: 'TIN_COATED' },
                { field: 'materialConditionScrap', label: '角料', dictCode: 'SCRAP' },
                { field: 'materialConditionWhiteYellow', label: '镀白黄', dictCode: 'WHITE_YELLOW' },
                { field: 'materialConditionPhosphorCopper', label: '磷铜', dictCode: 'PHOSPHOR_COPPER' }
            ],
            dictData: {}
        }
    },
    created() {
        this.loadDictData()
    },
    watch: {
        id: {
            immediate: true,
            handler(val) {
                const v = (val !== undefined && val !== null) ? String(val) : ''
                if (v) this.loadDetail(v)
            }
        }
    },
    methods: {
        async loadDictData() {
            try {
                const codes = [...this.materialConditionConfigs.map(mc => mc.dictCode), 'DELIVERY_METHOD']
                const res = await getDicByCodes(codes)
                this.dictData = res || {}
            } catch (e) {
                this.dictData = {}
            }
        },
        getDictOptions(dictCode) {
            const data = this.dictData[dictCode]
            return (data && data.data) ? data.data : []
        },
        isTagSelected(field, code) {
            const selected = this.form[field]
            return Array.isArray(selected) && selected.includes(code)
        },
        boolText(v) {
            if (typeof v !== 'boolean') return '-'
            return v ? '是' : '否'
        },
        getDeliveryMethodLabel() {
            const opts = this.getDictOptions('DELIVERY_METHOD') || []
            const m = opts.find(o => String(o.code != null ? o.code : o.value) === String(this.form.deliveryMode))
            return m ? (m.name || m.label || '-') : '-'
        },
        formatDateOnly(v) {
            const s = v == null ? '' : String(v).trim()
            if (!s) return '-'
            if (s.length >= 10) return s.slice(0, 10)
            return s
        },
        safeText(v) {
            const s = v == null ? '' : String(v)
            return s.trim() ? s : '-'
        },
        async loadDetail(id) {
            // 审核详情接口不可用时回退到普通详情接口
            try {
                const res = await salesmanQuotationDetailApi({ id })
                const d = (res && res.data) ? res.data : {}
                const materialFields = this.materialConditionConfigs.map(mc => mc.field)
                materialFields.forEach(f => {
                    const v = d[f]
                    d[f] = (typeof v === 'string' && v) ? v.split(',').filter(Boolean) : (Array.isArray(v) ? v : [])
                })
                this.form = d
                this.productLineList = Array.isArray(d.quotationLineList) ? d.quotationLineList : (Array.isArray(d.salesmanQuotationLineList) ? d.salesmanQuotationLineList : [])
            } catch (err) {
                this.form = {}
                this.productLineList = []
            }
        }
    }
}
</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;
    }
}

.material-group {
    margin-top: 32rpx;

    &:first-child {
        margin-top: 0;
    }
}

.material-label {
    display: block;
    font-size: 28rpx;
    color: rgba(0, 0, 0, 0.6);
    margin-bottom: 20rpx;
}

.tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: 16rpx;
}

.tag-btn {
    padding: 12rpx 24rpx;
    border: 1rpx solid #ddd;
    border-radius: 8rpx;
    font-size: 28rpx;
    color: #999;
    background: #f5f5f5;
}

.tag-btn.active {
    background: $theme-primary;
    border-color: $theme-primary;
    color: #fff;
}

.remark-text {
    font-size: 28rpx;
    color: rgba(0, 0, 0, 0.9);
    line-height: 1.6;
    white-space: pre-wrap;
}
</style>