2025-10-26 22:48:14 +08:00

422 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<BasicLayout>
<!-- 巡查记录列表 -->
<view class="inspection-list">
<BasicListLayout
@register="registerInspection"
style="position: absolute"
>
<template v-slot="{ data, index }">
<view class="inspection-record bg-white r-md p-15 mb-15 timeline-item">
<!-- 时间轴连接线 -->
<view class="timeline-line" v-if="index < 10"></view>
<!-- 时间轴节点 -->
<view class="timeline-dot">
<view class="dot-inner"></view>
</view>
<view class="record-header">
<view class="record-time">
<u-icon name="clock" color="#4080ff" size="16"></u-icon>
<text class="time-text">{{ formatTime(data.xctime) }}</text>
</view>
<view class="record-status">
<text class="status-text">已巡查</text>
</view>
</view>
<view class="record-content">
<view class="content-item">
<text class="item-label">巡查教师</text>
<text class="item-value">{{ data.jsxm }}</text>
</view>
<view class="content-item">
<text class="item-label">值周周次</text>
<text class="item-value">{{ data.zbzc }}</text>
</view>
<view class="content-item">
<text class="item-label">值周星期</text>
<text class="item-value">{{ data.zbxq || '全周' }}</text>
</view>
<view class="content-item">
<text class="item-label">值周区域</text>
<text class="item-value">{{ data.zbqy || '暂无' }}</text>
</view>
<view class="content-item">
<text class="item-label">值周位置</text>
<text class="item-value">{{ data.zbwz || '暂无' }}</text>
</view>
<view class="content-item flex-col">
<text class="item-label" style="flex: 0 0 25px">巡查项目</text>
<view class="item-value" style="width: 100%">
<template v-if="data.zbXcXmList && data.zbXcXmList.length > 0">
<view
v-for="(xm, idx) in data.zbXcXmList"
:key="xm.xcXmId"
style="margin-bottom: 4px"
>
<view>
<view style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px;">
<view style="display: flex; align-items: center; flex: 1;">
<text style="margin-right: 8px;">{{ idx + 1 }}{{ xm.xcMc }}</text>
<view style="display: flex; align-items: center;">
<u-icon
:name="xm.xcJg === 'B' ? 'checkmark-circle-fill' : 'close-circle-fill'"
:color="xm.xcJg === 'B' ? '#67c23a' : '#f56c6c'"
size="18"
></u-icon>
</view>
</view>
<view style="font-size: 12px; color: #666;">
<text v-if="xm.xcJg === 'A'" style="color: #f56c6c;">
扣分-{{ xm.xmFz }}
</text>
<text v-else style="color: #67c23a;">
不扣分
</text>
</view>
</view>
<view v-if="xm.xcPj" style="font-size: 12px; color: #666; margin-top: 4px; padding-left: 20px; line-height: 1.5;">
<text style="color: #999;">评价</text>
<text style="color: #666;">{{ xm.xcPj }}</text>
</view>
</view>
</view>
</template>
<template v-else> 无巡查项目 </template>
</view>
</view>
<view class="content-item" v-if="data.zp && data.zp.length > 0">
<text class="item-label">巡查图片</text>
<view class="item-value" style="display: flex; flex-wrap: wrap; gap: 8px">
<image
v-for="(img, imgIdx) in getImageArray(data.zp)"
:key="imgIdx"
:src="imagUrl(img)"
mode="aspectFill"
style="
width: 60px;
height: 60px;
border-radius: 4px;
border: 1px solid #eee;
cursor: pointer;
"
@click="handlePreviewImage(img, getImageArray(data.zp))"
/>
</view>
</view>
<view class="content-item" v-if="data.sp && data.sp.length > 0">
<text class="item-label">巡查视频</text>
<view class="item-value" style="display: flex; flex-wrap: wrap; gap: 8px">
<view
v-for="(video, vIdx) in getVideoArray(data.sp)"
:key="vIdx"
style="
width: 80px;
height: 60px;
position: relative;
border-radius: 4px;
overflow: hidden;
border: 1px solid #eee;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
background: #000;
"
@click="handlePreviewVideo(getVideoArray(data.sp), vIdx)"
>
<video
:src="video"
style="width: 100%; height: 100%; object-fit: cover"
:controls="false"
:show-center-play-btn="false"
:show-play-btn="false"
:show-fullscreen-btn="false"
:show-progress="false"
:show-mute-btn="false"
:enable-progress-gesture="false"
:enable-play-gesture="false"
:loop="false"
:muted="true"
:poster="''"
></video>
<view
style="
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
"
>
<u-icon name="play-right-fill" color="#fff" size="28"></u-icon>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
</BasicListLayout>
</view>
</BasicLayout>
</template>
<script setup lang="ts">
import { zbXcFindPageApi } from "@/api/base/zbXcApi";
import BasicLayout from "@/components/BasicLayout/Layout.vue";
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
import { useDataStore } from "@/store/modules/data";
import { useUserStore } from "@/store/modules/user";
import { computed, onMounted } from "vue";
import dayjs from "dayjs";
import { imagUrl } from "@/utils";
const { getJs } = useUserStore();
const { getData } = useDataStore();
const js = computed(() => getJs);
const zb = computed(() => getData);
// 巡查记录列表参数
let inspectionParams = {
rows: 10,
pbZbId: zb.value.id,
};
console.log('值周巡查记录查询参数:', inspectionParams);
// 巡查记录列表
const [registerInspection, { reload }] = useLayout({
api: zbXcFindPageApi,
componentProps: {},
param: inspectionParams,
});
// 图片预览
const handlePreviewImage = (img: string, images: string[]) => {
const processedImages = images.map(image => imagUrl(image));
uni.previewImage({
current: imagUrl(img),
urls: processedImages,
});
};
// 视频预览
const handlePreviewVideo = (videos: string[], index: number) => {
uni.previewMedia({
current: index,
sources: videos.map((url) => ({
url: imagUrl(url),
type: "video",
})),
});
};
// 格式化时间
const formatTime = (timestamp: string) => {
const date = dayjs(timestamp);
const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const weekDay = weekDays[date.day()];
return `${weekDay} ${date.format("YYYY-MM-DD HH:mm")}`;
};
// 将逗号分隔的字符串转换为数组
const getImageArray = (str: string) => {
if (!str) return [];
return str.split(",").map((item) => item.trim());
};
// 将逗号分隔的字符串转换为数组
const getVideoArray = (str: string) => {
if (!str) return [];
return str.split(",").map((item) => item.trim());
};
// 页面加载时重新加载巡查记录
onMounted(() => {
reload();
});
</script>
<style scoped lang="scss">
.inspection-list {
position: relative;
height: calc(100vh - 50px);
padding-left: 12px;
.inspection-record {
position: relative;
margin-left: 0;
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
border: 1px solid #e8f4fd;
transition: all 0.3s ease;
overflow: hidden;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
border-color: #4080ff;
}
.timeline-line {
position: absolute;
left: -12px;
top: 0;
width: 2px;
height: 100%;
background: linear-gradient(180deg, #4080ff 0%, #e8f4fd 100%);
z-index: 1;
}
.timeline-dot {
position: absolute;
left: -18px;
top: 20px;
width: 12px;
height: 12px;
background: #4080ff;
border-radius: 50%;
z-index: 2;
box-shadow: 0 0 0 4px #ffffff, 0 0 0 6px #e8f4fd;
.dot-inner {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #4080ff 0%, #66b3ff 100%);
border-radius: 50%;
animation: pulse 2s infinite;
}
}
.record-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding: 12px 8px;
background: linear-gradient(135deg, #f0f7ff 0%, #e8f4fd 100%);
border-radius: 8px 8px 0 0;
border-bottom: 1px solid #d1e7ff;
.record-time {
display: flex;
align-items: center;
font-size: 15px;
color: #2c5aa0;
font-weight: 600;
.time-text {
margin-left: 8px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
}
.record-status {
padding: 6px 12px;
border-radius: 20px;
background: linear-gradient(135deg, #4080ff 0%, #66b3ff 100%);
color: #ffffff;
font-size: 12px;
font-weight: 600;
box-shadow: 0 2px 8px rgba(64, 128, 255, 0.3);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
}
.record-content {
padding: 0 8px 12px 8px;
.content-item {
display: flex;
margin-bottom: 6px;
font-size: 14px;
color: #333;
padding: 6px 8px;
background: #fafbfc;
border-radius: 6px;
border-left: 3px solid #e8f4fd;
transition: all 0.2s ease;
&:hover {
background: #f0f7ff;
border-left-color: #4080ff;
}
.item-label {
font-weight: 600;
flex: 0 0 80px;
color: #2c5aa0;
}
.item-value {
color: #4a5568;
}
}
}
}
.inspection-record:first-child {
.timeline-dot {
background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
box-shadow: 0 0 0 4px #ffffff, 0 0 0 6px #f0f9ff;
}
}
.inspection-record:last-child {
.timeline-line {
display: none;
}
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.1);
opacity: 0.8;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.timeline-item {
animation: fadeInUp 0.6s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
::v-deep .zp-loading-fixed {
position: absolute;
}
::v-deep .d-load-main {
position: absolute;
}
}
</style>