|
@@ -77,11 +77,20 @@
|
|
|
:key="i"
|
|
:key="i"
|
|
|
class="photo-thumb"
|
|
class="photo-thumb"
|
|
|
>
|
|
>
|
|
|
- <image :src="p" mode="aspectFill" class="photo-img" />
|
|
|
|
|
|
|
+ <!-- H5 端 image 必须显式 width/height,否则可能 0×0 不显示 -->
|
|
|
|
|
+ <image
|
|
|
|
|
+ :src="ossUrl(p)"
|
|
|
|
|
+ mode="aspectFill"
|
|
|
|
|
+ class="photo-img"
|
|
|
|
|
+ @error="onPhotoError(p, i)"
|
|
|
|
|
+ />
|
|
|
<view v-if="!readonly" class="photo-del" @tap="delPhoto(item, i)">×</view>
|
|
<view v-if="!readonly" class="photo-del" @tap="delPhoto(item, i)">×</view>
|
|
|
</view>
|
|
</view>
|
|
|
<view v-if="!readonly" class="photo-add" @tap="choosePhoto(item)">
|
|
<view v-if="!readonly" class="photo-add" @tap="choosePhoto(item)">
|
|
|
<text class="photo-add-icon">📷</text>
|
|
<text class="photo-add-icon">📷</text>
|
|
|
|
|
+ <text class="photo-view-count" v-if="item.photos && item.photos.length">
|
|
|
|
|
+ {{ item.photos.length }}
|
|
|
|
|
+ </text>
|
|
|
<text class="photo-add-text">添加照片</text>
|
|
<text class="photo-add-text">添加照片</text>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -115,6 +124,7 @@ import { getInspectionTaskDetail, submitPunch, uploadPhoto } from '@/api/inspect
|
|
|
import { request } from '@/utils/request'
|
|
import { request } from '@/utils/request'
|
|
|
import { getToken } from '@/utils/auth'
|
|
import { getToken } from '@/utils/auth'
|
|
|
import { getCurrentLocation, ensureLocationAuth, pickLocationFallback } from '@/utils/location'
|
|
import { getCurrentLocation, ensureLocationAuth, pickLocationFallback } from '@/utils/location'
|
|
|
|
|
+import { ossUrl } from '@/utils/oss'
|
|
|
|
|
|
|
|
const taskId = ref<string>('')
|
|
const taskId = ref<string>('')
|
|
|
const readonly = ref<boolean>(false)
|
|
const readonly = ref<boolean>(false)
|
|
@@ -249,10 +259,23 @@ async function choosePhoto(item: InspectionItem) {
|
|
|
// 4. 全部成功:写入 item.photos
|
|
// 4. 全部成功:写入 item.photos
|
|
|
if (!item.photos) item.photos = []
|
|
if (!item.photos) item.photos = []
|
|
|
item.photos.push(...uploaded.map((u) => u.url))
|
|
item.photos.push(...uploaded.map((u) => u.url))
|
|
|
- items.value = [...items.value]
|
|
|
|
|
|
|
+ // 强制刷新(items 本身是 ref,数组内对象也应该是 reactive,这里保险起见重新赋值)
|
|
|
|
|
+ // 注意:不要用 items.value = [...items.value],会丢失其他项的 photos 引用变更追踪
|
|
|
|
|
+ // 改用整个数组的浅拷贝 + 重新赋值
|
|
|
|
|
+ items.value = items.value.map((it) =>
|
|
|
|
|
+ it === item ? { ...it, photos: [...(it.photos || [])] } : it
|
|
|
|
|
+ )
|
|
|
uni.showToast({ title: `已上传 ${uploaded.length} 张`, icon: 'success' })
|
|
uni.showToast({ title: `已上传 ${uploaded.length} 张`, icon: 'success' })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 图片加载失败回调(H5 端常见:跨域、URL 失效、网络问题)
|
|
|
|
|
+ * 仅 console.warn,不影响主流程
|
|
|
|
|
+ */
|
|
|
|
|
+function onPhotoError(url: string, idx: number) {
|
|
|
|
|
+ console.warn(`[check] 照片加载失败 idx=${idx} url=${url}`)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 回滚已上传但最终未使用的对象(调后端删除接口)
|
|
* 回滚已上传但最终未使用的对象(调后端删除接口)
|
|
|
* - 失败不重试:MinIO 端有定时清理,这里只做尽力而为
|
|
* - 失败不重试:MinIO 端有定时清理,这里只做尽力而为
|
|
@@ -351,14 +374,21 @@ async function onSubmit() {
|
|
|
let lng = 0
|
|
let lng = 0
|
|
|
let lat = 0
|
|
let lat = 0
|
|
|
if (pickedCoord.value) {
|
|
if (pickedCoord.value) {
|
|
|
|
|
+ // 用户已在地图上选过点,优先用
|
|
|
lng = pickedCoord.value.lng
|
|
lng = pickedCoord.value.lng
|
|
|
lat = pickedCoord.value.lat
|
|
lat = pickedCoord.value.lat
|
|
|
} else {
|
|
} else {
|
|
|
- const auth = await ensureLocationAuth()
|
|
|
|
|
- if (auth) {
|
|
|
|
|
- const loc = await getCurrentLocation()
|
|
|
|
|
- lng = loc.longitude
|
|
|
|
|
- lat = loc.latitude
|
|
|
|
|
|
|
+ // H5 端 try-catch:uni.authorize/getLocation 在浏览器可能不存在/被拒/超时
|
|
|
|
|
+ // 失败也不阻塞提交,经纬度传 0,0
|
|
|
|
|
+ try {
|
|
|
|
|
+ const auth = await ensureLocationAuth()
|
|
|
|
|
+ if (auth) {
|
|
|
|
|
+ const loc = await getCurrentLocation()
|
|
|
|
|
+ lng = loc.longitude
|
|
|
|
|
+ lat = loc.latitude
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (locErr: any) {
|
|
|
|
|
+ console.warn('[check] 获取位置失败(非阻塞):', locErr?.message || locErr)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -581,14 +611,17 @@ const hasAbnormal = computed(() => items.value.some((it) => it.result === 'ABNOR
|
|
|
}
|
|
}
|
|
|
.photo-thumb {
|
|
.photo-thumb {
|
|
|
position: relative;
|
|
position: relative;
|
|
|
- width: 160rpx;
|
|
|
|
|
- height: 160rpx;
|
|
|
|
|
|
|
+ width: 90px; /* 显式 px,避免 H5 端 rpx 计算问题 */
|
|
|
|
|
+ height: 90px;
|
|
|
border-radius: $radius-md;
|
|
border-radius: $radius-md;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
|
|
+ background: #f5f5f5;
|
|
|
}
|
|
}
|
|
|
.photo-img {
|
|
.photo-img {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
height: 100%;
|
|
height: 100%;
|
|
|
|
|
+ display: block; /* 避免 inline-image 底部 3px 空隙 */
|
|
|
|
|
+ object-fit: cover; /* 兜底 H5 端 image 组件 aspectFill 失效 */
|
|
|
}
|
|
}
|
|
|
.photo-del {
|
|
.photo-del {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
@@ -604,8 +637,9 @@ const hasAbnormal = computed(() => items.value.some((it) => it.result === 'ABNOR
|
|
|
font-size: 24rpx;
|
|
font-size: 24rpx;
|
|
|
}
|
|
}
|
|
|
.photo-add {
|
|
.photo-add {
|
|
|
- width: 160rpx;
|
|
|
|
|
- height: 160rpx;
|
|
|
|
|
|
|
+ position: relative; /* 让 .photo-view-count 角标能绝对定位 */
|
|
|
|
|
+ width: 90px;
|
|
|
|
|
+ height: 90px;
|
|
|
border: 2rpx dashed $border-color;
|
|
border: 2rpx dashed $border-color;
|
|
|
border-radius: $radius-md;
|
|
border-radius: $radius-md;
|
|
|
display: flex;
|
|
display: flex;
|
|
@@ -618,6 +652,18 @@ const hasAbnormal = computed(() => items.value.some((it) => it.result === 'ABNOR
|
|
|
font-size: 48rpx;
|
|
font-size: 48rpx;
|
|
|
margin-bottom: 8rpx;
|
|
margin-bottom: 8rpx;
|
|
|
}
|
|
}
|
|
|
|
|
+.photo-view-count {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 4rpx;
|
|
|
|
|
+ right: 8rpx;
|
|
|
|
|
+ background: #409EFF; /* 用主色硬编码,scoped 不会继承全局 Sass 变量 */
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 20rpx;
|
|
|
|
|
+ padding: 2rpx 8rpx;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ min-width: 28rpx;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
.photo-add-text {
|
|
.photo-add-text {
|
|
|
font-size: $font-xs;
|
|
font-size: $font-xs;
|
|
|
}
|
|
}
|