优化排车装车照片上传布局
This commit is contained in:
@@ -1,18 +1,31 @@
|
||||
<template>
|
||||
<view class="loading-documents">
|
||||
<view class="heading"><text>装车资料</text><button :disabled="busy" @tap="load">刷新</button></view>
|
||||
<text v-if="snapshot?.stage === 'LOADING'">可边装车边上传 5 张装车照片;确认装车完成且照片齐全后自动进入派送中。</text>
|
||||
<text v-if="snapshot?.stage === 'AFTER_LOADING'">上传并保存 5 张装车照片后,本车自动进入派送中。</text>
|
||||
<view class="heading">
|
||||
<view class="heading-main"><text class="heading-title">装车照片</text><text class="heading-subtitle">每类 1 张,上传后自动保存,可更换</text></view>
|
||||
<text class="heading-progress">{{ busy ? '同步中' : snapshot ? `${snapshot.photos.length}/5 已保存` : '待同步' }}</text>
|
||||
<button class="heading-refresh" :disabled="busy" @tap="load">刷新</button>
|
||||
</view>
|
||||
<text v-if="snapshot?.stage === 'LOADING'" class="section-hint">可边装车边上传;确认装车完成且照片齐全后自动进入派送中。</text>
|
||||
<text v-if="snapshot?.stage === 'AFTER_LOADING'" class="section-hint">上传并保存 5 张装车照片后,本车自动进入派送中。</text>
|
||||
<view v-if="error" class="error" role="alert"><text>{{ error.message }}</text><text v-if="error.requestId">requestId:{{ error.requestId }}</text><text v-if="error.traceId">traceId:{{ error.traceId }}</text></view>
|
||||
<view v-if="pending"><text>有装车照片尚未确认保存。</text><button :disabled="busy || !editable" @tap="recover">{{ pending.conflict ? '刷新并重试保存' : '核对原请求并继续保存' }}</button></view>
|
||||
<view v-for="(slot, index) in slots" :key="slot" class="photo-card">
|
||||
<text>装车照片 {{ index + 1 }}</text>
|
||||
<template v-for="photo in snapshot?.photos.filter(item => item.slot === slot) || []" :key="photo.fileId">
|
||||
<image v-if="images[photo.fileId]" :src="images[photo.fileId]" mode="aspectFit" @tap="preview(images[photo.fileId])" />
|
||||
<button v-else :disabled="busy" @tap="load">图片读取失败,重试</button>
|
||||
</template>
|
||||
<text v-if="!snapshot?.photos.some(item => item.slot === slot)" class="empty">未上传</text>
|
||||
<button v-if="editable" :disabled="busy || Boolean(pending)" @tap="choose(slot)">上传/替换图片</button>
|
||||
<view v-if="pending" class="pending-notice"><text>有装车照片尚未确认保存。</text><button class="recover-button" :disabled="busy || !editable" @tap="recover">{{ pending.conflict ? '刷新并重试保存' : '核对原请求并继续保存' }}</button></view>
|
||||
<view class="photo-list">
|
||||
<view v-for="(slot, index) in slots" :key="slot" class="photo-card" :class="{ filled: snapshot?.photos.some(item => item.slot === slot) }">
|
||||
<view class="photo-card-header">
|
||||
<view class="photo-card-main">
|
||||
<text class="photo-number">{{ snapshot?.photos.some(item => item.slot === slot) ? '✓' : index + 1 }}</text>
|
||||
<view class="photo-card-title"><text class="photo-label">装车照片 {{ index + 1 }}</text><text class="photo-status">{{ snapshot?.photos.some(item => item.slot === slot) ? '已保存 1 张' : '待上传' }}</text></view>
|
||||
</view>
|
||||
<button v-if="editable" class="photo-upload" :disabled="busy || Boolean(pending)" @tap="choose(slot)">{{ snapshot?.photos.some(item => item.slot === slot) ? '更换图片' : '+ 上传图片' }}</button>
|
||||
</view>
|
||||
<view v-if="snapshot?.photos.some(item => item.slot === slot)" class="photo-preview-list">
|
||||
<view v-for="photo in snapshot.photos.filter(item => item.slot === slot)" :key="photo.fileId" class="photo-preview">
|
||||
<image v-if="images[photo.fileId]" class="photo-thumbnail" :src="images[photo.fileId]" mode="aspectFill" :aria-label="`预览装车照片 ${index + 1}`" @tap="preview(images[photo.fileId])" />
|
||||
<button v-else class="photo-read-retry" :disabled="busy" @tap="load">图片读取失败,重试</button>
|
||||
<text v-if="images[photo.fileId]" class="photo-preview-caption" @tap="preview(images[photo.fileId])">查看大图</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -99,11 +112,35 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.loading-documents { padding: 24rpx; margin-top: 20rpx; background: #fff; border-radius: 16rpx; color: #334155; font-size: 28rpx; }
|
||||
.heading { display: flex; align-items: center; justify-content: space-between; font-weight: 600; }
|
||||
.heading button { margin: 0; font-size: 26rpx; }
|
||||
.photo-card { padding: 20rpx; margin-top: 20rpx; border: 1rpx solid #dbe5f0; border-radius: 12rpx; }
|
||||
.photo-card image { width: 100%; height: 260rpx; display: block; margin: 16rpx 0; }
|
||||
.photo-card .empty { display: block; text-align: center; padding: 50rpx 0; color: #64748b; }
|
||||
.error text { display: block; margin-top: 12rpx; color: #b91c1c; }
|
||||
.loading-documents { padding: 24rpx; margin-top: 20rpx; border: 2rpx solid #d9e5f4; border-radius: 20rpx; color: #24364d; font-size: 24rpx; background: #fff; }
|
||||
.heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 16rpx; }
|
||||
.heading-main { flex: 1; min-width: 0; }
|
||||
.heading-title { display: block; font-size: 30rpx; font-weight: 700; }
|
||||
.heading-subtitle, .section-hint { display: block; margin-top: 8rpx; color: #64748b; font-size: 22rpx; line-height: 34rpx; }
|
||||
.heading-progress { flex-shrink: 0; padding: 8rpx 12rpx; border-radius: 40rpx; color: #087443; font-size: 20rpx; line-height: 30rpx; background: #e8f8ef; }
|
||||
.heading-refresh { flex-shrink: 0; min-width: 100rpx; min-height: 80rpx; margin: 0; padding: 0 18rpx; border: 2rpx solid #9db7d9; border-radius: 14rpx; color: #174d91; font-size: 24rpx; line-height: 80rpx; background: #fff; }
|
||||
.photo-list { margin-top: 20rpx; }
|
||||
.photo-card { margin-bottom: 16rpx; padding: 14rpx 18rpx; border: 2rpx solid #d7e1ed; border-radius: 18rpx; background: #f8fafc; }
|
||||
.photo-card:last-child { margin-bottom: 0; }
|
||||
.photo-card.filled { border-color: #a7d6ba; background: #f4fbf6; }
|
||||
.photo-card-header { display: flex; min-height: 88rpx; align-items: center; justify-content: space-between; gap: 20rpx; }
|
||||
.photo-card-main { display: flex; min-width: 0; align-items: center; gap: 18rpx; }
|
||||
.photo-number { display: flex; width: 56rpx; height: 56rpx; flex-shrink: 0; align-items: center; justify-content: center; border-radius: 50%; color: #47617f; font-size: 22rpx; font-weight: 700; background: #e8eef6; }
|
||||
.filled .photo-number { color: #fff; background: #16a34a; }
|
||||
.photo-card-title { display: flex; min-width: 0; flex-direction: column; gap: 2rpx; }
|
||||
.photo-label { display: block; color: #24364d; font-size: 24rpx; font-weight: 700; }
|
||||
.photo-status { color: #64748b; font-size: 20rpx; line-height: 30rpx; }
|
||||
.filled .photo-status { color: #087443; }
|
||||
.photo-upload { flex-shrink: 0; min-width: 152rpx; min-height: 84rpx; margin: 0; padding: 0 18rpx; border: 2rpx solid #9db7d9; border-radius: 14rpx; color: #174d91; font-size: 24rpx; line-height: 84rpx; background: #fff; }
|
||||
.photo-preview-list { display: flex; flex-wrap: wrap; gap: 16rpx; margin-top: 18rpx; }
|
||||
.photo-preview { box-sizing: border-box; width: calc(33.333% - 12rpx); min-width: 128rpx; padding: 8rpx; border: 2rpx solid #dbe5ef; border-radius: 16rpx; background: #fff; }
|
||||
.photo-thumbnail { display: block; width: 100%; height: 136rpx; border-radius: 12rpx; background: #e7edf5; }
|
||||
.photo-preview-caption { display: block; overflow: hidden; margin-top: 8rpx; color: #64748b; font-size: 18rpx; line-height: 28rpx; text-align: center; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.photo-read-retry { display: flex; box-sizing: border-box; width: 100%; min-height: 136rpx; margin: 0; padding: 12rpx; align-items: center; justify-content: center; border: 0; border-radius: 12rpx; color: #174d91; font-size: 20rpx; line-height: 30rpx; background: #e7edf5; }
|
||||
.pending-notice { margin-top: 16rpx; padding: 16rpx; border: 2rpx solid #f2d398; border-radius: 14rpx; color: #8a5a00; font-size: 22rpx; line-height: 34rpx; background: #fff7df; }
|
||||
.recover-button { min-height: 80rpx; margin: 12rpx 0 0; padding: 0 18rpx; border: 2rpx solid #d4aa54; border-radius: 14rpx; color: #8a5a00; font-size: 24rpx; line-height: 80rpx; background: #fff; }
|
||||
.error { margin-top: 16rpx; padding: 12rpx 16rpx; border-radius: 14rpx; color: #b91c1c; background: #fff1f0; }
|
||||
.error text { display: block; font-size: 22rpx; line-height: 34rpx; overflow-wrap: anywhere; }
|
||||
.heading-refresh::after, .photo-upload::after, .photo-read-retry::after, .recover-button::after { border: 0; }
|
||||
.loading-documents button[disabled] { opacity: .55; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user