| | |
| | | <text class="info-title">申请信息</text> |
| | | </view> |
| | | <view class="info-content"> |
| | | <!-- 审批标题(仅 approveType=9 或 10 显示) --> |
| | | <view v-if="approvalData.approveType === 9 || approvalData.approveType === 10" class="info-row"> |
| | | <text class="info-label">审批标题</text> |
| | | <text class="info-value">{{ approvalData.approveTitle || '-' }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">申请人</text> |
| | | <text class="info-value">{{ approvalData.approveUserName }}</text> |
| | |
| | | <text class="info-value">{{ approvalData.approveDeptName }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">申请事由</text> |
| | | <text class="info-label">{{ getApproveReasonLabel() }}</text> |
| | | <text class="info-value">{{ approvalData.approveReason }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">申请日期</text> |
| | | <text class="info-value">{{ approvalData.approveTime }}</text> |
| | | </view> |
| | | |
| | | |
| | | <!-- approveType=2 请假相关字段 --> |
| | | <template v-if="approvalData.approveType === 2"> |
| | | <view class="info-row"> |
| | |
| | | <text class="info-value">{{ approvalData.endDate || '-' }}</text> |
| | | </view> |
| | | </template> |
| | | |
| | | |
| | | <!-- approveType=3 出差相关字段 --> |
| | | <view v-if="approvalData.approveType === 3" class="info-row"> |
| | | <text class="info-label">出差地点</text> |
| | | <text class="info-value">{{ approvalData.location || '-' }}</text> |
| | | </view> |
| | | |
| | | |
| | | <!-- approveType=4 报销相关字段 --> |
| | | <view v-if="approvalData.approveType === 4" class="info-row"> |
| | | <text class="info-label">报销金额</text> |
| | | <text class="info-value">{{ approvalData.price ? `¥${approvalData.price}` : '-' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 销售详情(approveType=9) --> |
| | | <view v-if="isSalesApproval && currentSales.salesContractNo" class="sales-detail"> |
| | | <view class="detail-header"> |
| | | <text class="detail-title">销售详情</text> |
| | | </view> |
| | | <view class="detail-content"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">销售合同号</text> |
| | | <text class="detail-value">{{ currentSales.salesContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客户名称</text> |
| | | <text class="detail-value">{{ currentSales.customerName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">业务员</text> |
| | | <text class="detail-value">{{ currentSales.salesman }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">录入人</text> |
| | | <text class="detail-value">{{ currentSales.entryPersonName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">签订日期</text> |
| | | <text class="detail-value">{{ currentSales.executionDate }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">付款方式</text> |
| | | <text class="detail-value">{{ currentSales.paymentMethod }}</text> |
| | | </view> |
| | | <view class="detail-row total-row"> |
| | | <text class="detail-label">合同金额</text> |
| | | <text class="detail-value highlight">¥{{ calculateSalesTotalAmount() }}</text> |
| | | </view> |
| | | <!-- 产品明细 --> |
| | | <view v-if="currentSales.productData && currentSales.productData.length > 0" class="product-list"> |
| | | <view class="product-header"> |
| | | <text class="product-title">产品明细</text> |
| | | </view> |
| | | <view v-for="(product, pIndex) in currentSales.productData" :key="pIndex" class="product-item"> |
| | | <view class="product-row"> |
| | | <text class="product-label">产品名称</text> |
| | | <text class="product-value">{{ product.productCategory }}</text> |
| | | </view> |
| | | <view class="product-row"> |
| | | <text class="product-label">规格型号</text> |
| | | <text class="product-value">{{ product.specificationModel }}</text> |
| | | </view> |
| | | <view class="product-row"> |
| | | <text class="product-label">数量</text> |
| | | <text class="product-value">{{ product.quantity }}</text> |
| | | </view> |
| | | <view class="product-row"> |
| | | <text class="product-label">含税单价</text> |
| | | <text class="product-value">¥{{ Number(product.taxInclusiveUnitPrice || 0).toFixed(2) }}</text> |
| | | </view> |
| | | <view class="product-row"> |
| | | <text class="product-label">含税总价</text> |
| | | <text class="product-value">¥{{ Number(product.taxInclusiveTotalPrice || 0).toFixed(2) }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 加载状态 --> |
| | | <view v-if="salesLoading" class="loading-state"> |
| | | <text>加载销售详情中...</text> |
| | | </view> |
| | | |
| | | <!-- 审批流程 --> |
| | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { approveProcessGetInfo, approveProcessDetails, updateApproveNode } from '@/api/collaborativeApproval/approvalProcess' |
| | | import { getSalesByCode } from '@/api/procurementManagement/procurementLedger.js' |
| | | import useUserStore from '@/store/modules/user' |
| | | |
| | | const showToast = (message) => { |
| | | uni.showToast({ |
| | | title: message, |
| | |
| | | const approvalSteps = ref([]) |
| | | const approvalOpinion = ref('') |
| | | const approveId = ref('') |
| | | const approveType = ref(0) |
| | | const isSalesApproval = computed(() => Number(approveType.value) === 9) |
| | | const currentSales = ref({}) |
| | | const salesLoading = ref(false) |
| | | |
| | | // 从详情接口字段对齐 canApprove:仅当有 isShen 的节点时可审批 |
| | | const canApprove = computed(() => { |
| | | return approvalSteps.value.some(step => step.isShen === true) |
| | | }) |
| | | |
| | | // 获取审批事由标签 |
| | | const getApproveReasonLabel = () => { |
| | | const type = Number(approveType.value) |
| | | if (type === 5) { |
| | | return '采购合同号' |
| | | } else if (type === 9) { |
| | | return '销售合同号' |
| | | } else if (type === 10) { |
| | | return '审批事由' |
| | | } |
| | | return '申请事由' |
| | | } |
| | | |
| | | // 计算销售合同金额(产品明细含税总价之和) |
| | | const calculateSalesTotalAmount = () => { |
| | | const products = currentSales.value?.productData || [] |
| | | const total = products.reduce((sum, item) => { |
| | | return sum + Number(item.taxInclusiveTotalPrice || 0) |
| | | }, 0) |
| | | return total.toFixed(2) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | approveId.value = uni.getStorageSync('approveId') |
| | | const storedApproveType = uni.getStorageSync('approveType') |
| | | if (storedApproveType) { |
| | | approveType.value = Number(storedApproveType) |
| | | } |
| | | if (approveId.value) { |
| | | loadApprovalData() |
| | | } |
| | |
| | | // 基本申请信息 |
| | | approveProcessGetInfo({ id: approveId.value }).then(res => { |
| | | approvalData.value = res.data || {} |
| | | // 设置审批类型 |
| | | if (res.data && res.data.approveType) { |
| | | approveType.value = Number(res.data.approveType) |
| | | } |
| | | // 销售审批:用审批事由字段承载的"销售合同号"去查销售详情 |
| | | if (isSalesApproval.value) { |
| | | const salesContractNo = res.data?.approveReason |
| | | if (salesContractNo) { |
| | | salesLoading.value = true |
| | | getSalesByCode({ salesContractNo }).then(salesRes => { |
| | | currentSales.value = salesRes || {} |
| | | }).catch((err) => { |
| | | console.error('查询销售详情失败:', err) |
| | | }).finally(() => { |
| | | salesLoading.value = false |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | // 审批节点详情 |
| | | approveProcessDetails(approveId.value).then(res => { |
| | |
| | | } |
| | | |
| | | /* 适配u-button样式 */ |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | /* 销售详情样式 */ |
| | | .sales-detail { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .detail-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .detail-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .detail-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .detail-value.highlight { |
| | | font-size: 18px; |
| | | color: #e6a23c; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .total-row { |
| | | padding-top: 8px; |
| | | border-top: 1px solid #f0f0f0; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .product-list { |
| | | margin-top: 16px; |
| | | padding-top: 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | .product-header { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .product-title { |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .product-item { |
| | | background: #f8f9fa; |
| | | border-radius: 8px; |
| | | padding: 12px; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .product-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 6px; |
| | | } |
| | | |
| | | .product-row:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .product-label { |
| | | font-size: 13px; |
| | | color: #666; |
| | | width: 70px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .product-value { |
| | | font-size: 13px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .loading-state { |
| | | text-align: center; |
| | | padding: 16px; |
| | | color: #999; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0% { |