laundry-flow-detail.vue 7.66 KB
<template>
	<view class="container">
		<!-- 详情卡片 -->
		<view class="detail-card">
			<view class="card-header">毛巾记录详情</view>
			<view class="detail-content">
				<!-- 加载状态 -->
				<view v-if="loading" class="loading">正在加载详情...</view>
				
				<!-- 错误状态 -->
				<view v-else-if="error" class="error-state">
					<view>{{ error }}</view>
					<u-button class="retry-btn" @click="retryLoad" type="primary" size="small">重试</u-button>
				</view>
				
				<!-- 详情内容 -->
				<view v-else-if="detailData" class="info-sections">
					<!-- 基本信息 -->
					<view class="info-section">
						<view class="section-title">
							<text class="section-icon">📋</text>
							<text>基本信息</text>
						</view>
						<view class="info-grid">
							<view class="info-item">
								<text class="info-label">流水类型</text>
								<view class="flow-type-badge" :class="detailData.flowType === 0 ? 'send-type' : 'return-type'">
									<text class="flow-type-icon">{{ detailData.flowType === 0 ? '📤' : '📥' }}</text>
									<text class="flow-type-text">{{ detailData.flowTypeName || '无' }}</text>
								</view>
							</view>
							<view class="info-item">
								<text class="info-label">批次号</text>
								<text class="info-value">{{ detailData.batchNumber || '无' }}</text>
							</view>
							<view class="info-item">
								<text class="info-label">门店名称</text>
								<text class="info-value">{{ detailData.storeName || '无' }}</text>
							</view>
							<view class="info-item">
								<text class="info-label">产品类型</text>
								<text class="info-value">{{ detailData.productType || '无' }}</text>
							</view>
							<view class="info-item">
								<text class="info-label">清洗商名称</text>
								<text class="info-value">{{ detailData.laundrySupplierName || '无' }}</text>
							</view>
							<view class="info-item">
								<text class="info-label">数量</text>
								<text class="info-value">{{ detailData.quantity || 0 }}</text>
							</view>
						</view>
					</view>
					
					<!-- 费用信息 -->
					<view class="info-section">
						<view class="section-title">
							<text class="section-icon">💰</text>
							<text>费用信息</text>
						</view>
						<view class="info-grid">
							<view class="info-item">
								<text class="info-label">清洗单价</text>
								<text class="info-value amount">¥{{ detailData.laundryPrice || 0 }}</text>
							</view>
							<view class="info-item">
								<text class="info-label">总费用</text>
								<text class="info-value amount total">¥{{ detailData.totalPrice || 0 }}</text>
							</view>
						</view>
					</view>
					
					<!-- 其他信息 -->
					<view class="info-section">
						<view class="section-title">
							<text class="section-icon">📝</text>
							<text>其他信息</text>
						</view>
						<view class="info-grid">
							<view class="info-item full-width">
								<text class="info-label">备注</text>
								<text class="info-value">{{ detailData.remark || '无' }}</text>
							</view>
							<view class="info-item">
								<text class="info-label">是否有效</text>
								<view class="status-badge" :class="detailData.isEffective === 1 ? 'effective' : 'ineffective'">
									{{ detailData.isEffective === 1 ? '有效' : '无效' }}
								</view>
							</view>
							<view class="info-item">
								<text class="info-label">创建人</text>
								<text class="info-value">{{ detailData.createUserName || '无' }}</text>
							</view>
							<view class="info-item">
								<text class="info-label">创建时间</text>
								<text class="info-value">{{ formatTime(detailData.createTime) }}</text>
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import laundryFlowApi from '@/apis/modules/laundry-flow.js'

	export default {
		data() {
			return {
				loading: false,
				error: null,
				detailData: null,
				flowId: null
			}
		},

		onLoad(options) {
			if (options.id) {
				this.flowId = options.id
				this.loadDetail()
			} else {
				this.error = '缺少记录ID'
			}
		},

		methods: {
			// 加载详情数据
			async loadDetail() {
				if (!this.flowId) return

				try {
					this.loading = true
					this.error = null

					const res = await laundryFlowApi.getLaundryFlowDetail(this.flowId)

					if (res.code === 200 && res.data) {
						this.detailData = res.data
					} else {
						this.error = res.msg || res.message || '加载详情失败'
					}
				} catch (error) {
					console.error('加载详情失败:', error)
					this.error = '加载详情失败,请重试'
				} finally {
					this.loading = false
				}
			},

			// 重试加载
			retryLoad() {
				this.loadDetail()
			},

			// 格式化时间
			formatTime(timestamp) {
				if (!timestamp) return '无'
				const date = new Date(timestamp)
				return date.toLocaleString('zh-CN', {
					year: 'numeric',
					month: '2-digit',
					day: '2-digit',
					hour: '2-digit',
					minute: '2-digit',
					second: '2-digit'
				})
			}
		}
	}
</script>

<style lang="scss" scoped>
	.container {
		min-height: 100vh;
		background: linear-gradient(135deg, #e8f5e9 0%, #b2dfdb 100%);
		padding: 40rpx;
		box-sizing: border-box;
	}

	.detail-card {
		background: #fff;
		border-radius: 32rpx;
		box-shadow: 0 8rpx 32rpx rgba(76, 175, 80, 0.1);
		overflow: hidden;
	}

	.card-header {
		background: linear-gradient(120deg, #43e97b 0%, #38f9d7 100%);
		padding: 32rpx 40rpx;
		color: #fff;
		font-size: 36rpx;
		font-weight: 600;
		letter-spacing: 2rpx;
		text-align: center;
	}

	.detail-content {
		padding: 40rpx;
	}

	.loading {
		text-align: center;
		padding: 80rpx 40rpx;
		color: #6a9c6a;
		font-size: 28rpx;
	}

	.error-state {
		text-align: center;
		padding: 80rpx 40rpx;
		color: #f56c6c;
		font-size: 28rpx;
	}

	.retry-btn {
		margin-top: 32rpx;
	}

	.info-sections {
		display: flex;
		flex-direction: column;
		gap: 32rpx;
	}

	.info-section {
		background: #f9fff9;
		border-radius: 24rpx;
		padding: 32rpx;
		border: 2rpx solid #e8f5e9;
	}

	.section-title {
		display: flex;
		align-items: center;
		gap: 12rpx;
		font-size: 32rpx;
		font-weight: 600;
		color: #2e7d32;
		margin-bottom: 24rpx;
		padding-bottom: 16rpx;
		border-bottom: 2rpx solid #c8e6c9;
	}

	.section-icon {
		font-size: 32rpx;
	}

	.info-grid {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: 24rpx;
	}

	.info-item {
		display: flex;
		flex-direction: column;
		gap: 8rpx;
	}

	.info-item.full-width {
		grid-column: 1 / -1;
	}

	.info-label {
		font-size: 24rpx;
		color: #6a9c6a;
		font-weight: 500;
	}

	.info-value {
		font-size: 28rpx;
		color: #2e7d32;
		font-weight: 500;
		word-break: break-all;
	}

	.info-value.amount {
		color: #f57c00;
		font-weight: 600;
		font-size: 32rpx;
	}

	.info-value.amount.total {
		font-size: 36rpx;
		color: #e65100;
	}

	.flow-type-badge {
		display: flex;
		align-items: center;
		padding: 8rpx 24rpx;
		border-radius: 40rpx;
		font-size: 24rpx;
		font-weight: 500;
		width: fit-content;
	}

	.flow-type-badge.send-type {
		background: #e3f2fd;
		color: #1976d2;
		border: 2rpx solid #90caf9;
	}

	.flow-type-badge.return-type {
		background: #e8f5e9;
		color: #388e3c;
		border: 2rpx solid #a5d6a7;
	}

	.flow-type-icon {
		margin-right: 8rpx;
		font-size: 28rpx;
	}

	.flow-type-text {
		font-size: 24rpx;
	}

	.status-badge {
		display: inline-block;
		padding: 8rpx 24rpx;
		border-radius: 40rpx;
		font-size: 24rpx;
		font-weight: 500;
		text-align: center;
		width: fit-content;
	}

	.status-badge.effective {
		background: #e8f5e9;
		color: #2e7d32;
		border: 2rpx solid #c8e6c9;
	}

	.status-badge.ineffective {
		background: #ffebee;
		color: #c62828;
		border: 2rpx solid #ffcdd2;
	}
</style>