241 lines
5.8 KiB
Vue
241 lines
5.8 KiB
Vue
<template>
|
||
<view class="page">
|
||
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||
<uni-nav-bar title="巡检详情" backgroundColor="transparent" :border="false" left-icon="left"
|
||
@click-left="goBack" />
|
||
<scroll-view scroll-y class="scroll">
|
||
<!-- 加载中 -->
|
||
<view class="loading-wrap" v-if="loading">
|
||
<uni-load-more status="loading" :content-text="{ contentdown: '上拉加载更多', contentrefresh: '加载中...', contentnomore: '没有更多了' }" />
|
||
</view>
|
||
|
||
<template v-if="!loading && detail">
|
||
<!-- 第一块:基本信息 -->
|
||
<view class="card">
|
||
<view class="row-title">
|
||
<text>{{ detail.locationName }}</text>
|
||
<text class="status">{{ detail.status }}</text>
|
||
</view>
|
||
<view class="text-item">巡检项目:{{ detail.inspectionType }}</view>
|
||
<view class="text-item">巡检时间:{{ detail.taskTime }}</view>
|
||
<view class="text-item">巡检小区:{{ detail.villageName }}</view>
|
||
<view class="text-item">巡检路线:{{ detail.routeName }}</view>
|
||
<view class="text-item">巡检点:{{ detail.pointNames }}</view>
|
||
</view>
|
||
|
||
<!-- 第二块:巡检结果 -->
|
||
<view class="card">
|
||
<view class="card-subtitle">巡检结果</view>
|
||
<view class="text-item">巡检人:{{ detail.inspectorName }}</view>
|
||
<view class="text-item">手机号码:{{ detail.phoneNumber }}</view>
|
||
<view class="text-item">巡检时间:{{ detail.inspectTime }}</view>
|
||
<view class="text-item">巡检结果:</view>
|
||
<view class="result-desc">
|
||
<text v-for="(r, idx) in detail.results" :key="idx">{{ idx + 1 }}.{{ r }}</text>
|
||
</view>
|
||
<view class="text-item">巡检照片:</view>
|
||
<view class="img-wrap">
|
||
<view class="img-box" v-for="(img, idx) in detail.photos" :key="idx" @click="previewImage(img)">
|
||
<image class="img" :src="img" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="empty-img-tip" v-if="!detail.photos || detail.photos.length === 0">暂无照片</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 第三块:巡检明细列表 -->
|
||
<view class="card" v-for="(sub, idx) in detail.details" :key="sub.id">
|
||
<view class="card-subtitle">{{ sub.pointName }}</view>
|
||
<view class="text-item">巡检时间:{{ sub.checkTime }}</view>
|
||
<view class="text-item">巡检结果:{{ sub.checkResult }}</view>
|
||
<view class="text-item" v-if="sub.remark">备注:{{ sub.remark }}</view>
|
||
<view class="text-item" v-if="sub.photos">巡检照片:</view>
|
||
<view class="img-wrap" v-if="sub.photos">
|
||
<view class="img-box" v-for="(img, i) in sub.photos.split(',')" :key="i" @click="previewImage(img)">
|
||
<image class="img" :src="img" mode="aspectFill"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<!-- 加载失败 -->
|
||
<view class="error-wrap" v-if="!loading && !detail">
|
||
<text class="empty-text">数据加载失败</text>
|
||
<view class="retry-btn" @click="fetchDetail">点击重试</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { inspectionDetails } from '../api/apiSub.js'
|
||
|
||
const statusBarHeight = ref(uni.getSystemInfoSync().statusBarHeight || 0)
|
||
const loading = ref(false)
|
||
const detail = ref(null)
|
||
let recordId = ''
|
||
|
||
onLoad((options) => {
|
||
if (options.id) {
|
||
recordId = options.id
|
||
fetchDetail()
|
||
}
|
||
})
|
||
|
||
const fetchDetail = async () => {
|
||
if (!recordId) return
|
||
loading.value = true
|
||
detail.value = null
|
||
try {
|
||
const res = await inspectionDetails({ id: recordId })
|
||
if (res.code === 200) {
|
||
detail.value = res.data
|
||
} else {
|
||
uni.showToast({ title: res.msg || '获取详情失败', icon: 'none' })
|
||
}
|
||
} catch (err) {
|
||
console.error('获取巡检详情失败', err)
|
||
uni.showToast({ title: '网络异常,请重试', icon: 'none' })
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const goBack = () => {
|
||
uni.navigateBack()
|
||
}
|
||
|
||
const previewImage = (url) => {
|
||
if (!url) return
|
||
// 收集当前所有可预览图片
|
||
const allPhotos = []
|
||
if (detail.value.photos) allPhotos.push(...detail.value.photos)
|
||
if (detail.value.details) {
|
||
detail.value.details.forEach(d => {
|
||
if (d.photos) allPhotos.push(...d.photos.split(','))
|
||
})
|
||
}
|
||
uni.previewImage({
|
||
current: url,
|
||
urls: allPhotos
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
page {
|
||
background-color: #f7f8fa;
|
||
}
|
||
|
||
.status-bar {
|
||
width: 100%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.page {
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.scroll {
|
||
flex: 1;
|
||
padding: 24rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.card {
|
||
background: #fff;
|
||
border-radius: 20rpx;
|
||
padding: 36rpx;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.row-title {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 32rpx;
|
||
color: #222;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.status {
|
||
font-size: 24rpx;
|
||
color: #555;
|
||
}
|
||
|
||
.card-subtitle {
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
color: #222;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.text-item {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
line-height: 2;
|
||
}
|
||
|
||
.result-desc {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
display: flex;
|
||
flex-direction: column;
|
||
line-height: 1.8;
|
||
margin: 12rpx 0;
|
||
}
|
||
|
||
/* 图片容器 flex-wrap换行 */
|
||
.img-wrap {
|
||
margin-top: 16rpx;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.img-box {
|
||
width: 140rpx;
|
||
height: 140rpx;
|
||
background-color: #d8d9db;
|
||
border-radius: 8rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.empty-img-tip {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.loading-wrap {
|
||
padding-top: 200rpx;
|
||
}
|
||
|
||
.error-wrap {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding-top: 200rpx;
|
||
}
|
||
|
||
.empty-text {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.retry-btn {
|
||
margin-top: 24rpx;
|
||
padding: 12rpx 48rpx;
|
||
border: 2rpx solid #2F77FD;
|
||
border-radius: 8rpx;
|
||
color: #2F77FD;
|
||
font-size: 28rpx;
|
||
}
|
||
</style>
|