<template>
|
<view class="upkeep-detail">
|
<!-- 使用通用页面头部组件 -->
|
<PageHeader title="保养详情"
|
@back="goBack" />
|
<!-- 详情内容 -->
|
<view class="detail-section"
|
v-if="detailData">
|
<view class="detail-card">
|
<view class="card-header">
|
<view class="header-icon">
|
<up-icon name="file-text"
|
size="20"
|
color="#ffffff"></up-icon>
|
</view>
|
<text class="header-title">{{ detailData.deviceName || '-' }}</text>
|
<view class="status-tag">
|
<u-tag v-if="detailData.status === 1"
|
type="success">完结</u-tag>
|
<u-tag v-else-if="detailData.status === 0"
|
type="error">待保养</u-tag>
|
<u-tag v-else-if="detailData.status === 2"
|
type="warning">失败</u-tag>
|
</view>
|
</view>
|
<up-divider></up-divider>
|
<view class="detail-content">
|
<view class="detail-row">
|
<text class="detail-label">设备名称</text>
|
<text class="detail-value">{{ detailData.deviceName || '-' }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">规格型号</text>
|
<text class="detail-value">{{ detailData.deviceModel || '-' }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">计划保养日期</text>
|
<text class="detail-value">{{ formatDate(detailData.maintenancePlanTime) || '-' }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">实际保养人</text>
|
<text class="detail-value">{{ detailData.maintenanceActuallyName || '-' }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">实际保养日期</text>
|
<text class="detail-value">{{ formatDateTime(detailData.maintenanceActuallyTime) || '-' }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">保养结果</text>
|
<text class="detail-value">{{detailData.maintenanceResult || '-'}}
|
</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">录入人</text>
|
<text class="detail-value">{{ detailData.createUserName || '-' }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">录入日期</text>
|
<text class="detail-value">{{ formatDateTime(detailData.createTime) || '-' }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">备注</text>
|
<text class="detail-value">{{ detailData.remark || '-' }}</text>
|
</view>
|
</view>
|
</view>
|
<!-- 设备备件 -->
|
<view class="detail-card">
|
<view class="card-header">
|
<view class="header-icon secondary">
|
<up-icon name="setting"
|
size="20"
|
color="#ffffff"></up-icon>
|
</view>
|
<text class="header-title">设备备件</text>
|
</view>
|
<up-divider></up-divider>
|
<view class="spare-parts-list"
|
v-if="sparePartsList.length > 0">
|
<view v-for="(item, index) in sparePartsList"
|
:key="index"
|
class="spare-part-item">
|
<text class="spare-part-name">{{ item.sparePartName || item.name || '-' }}</text>
|
<text class="spare-part-code">{{ item.sparePartCode || item.code || '-' }}</text>
|
</view>
|
</view>
|
<view v-else
|
class="empty-content">
|
<text class="empty-text">暂无设备备件</text>
|
</view>
|
</view>
|
<!-- 保养附件 -->
|
<view class="detail-card">
|
<view class="card-header">
|
<view class="header-icon tertiary">
|
<up-icon name="photo"
|
size="20"
|
color="#ffffff"></up-icon>
|
</view>
|
<text class="header-title">保养附件</text>
|
</view>
|
<up-divider></up-divider>
|
<view class="file-list"
|
v-if="fileList.length > 0">
|
<view v-for="(file, index) in fileList"
|
:key="index"
|
class="file-item"
|
@click="previewFile(file)">
|
<image v-if="file.type.includes('image')"
|
:src="file.url"
|
class="file-preview"
|
mode="aspectFill" />
|
<view v-else
|
class="file-placeholder">
|
<up-icon name="play-circle"
|
size="32"
|
color="#999"></up-icon>
|
</view>
|
</view>
|
</view>
|
<view v-else
|
class="empty-content">
|
<text class="empty-text">暂无保养附件</text>
|
</view>
|
</view>
|
</view>
|
<view v-else
|
class="no-data">
|
<up-icon name="info-circle"
|
size="48"
|
color="#ccc"></up-icon>
|
<text class="no-data-text">暂无保养详情数据</text>
|
</view>
|
<!-- 底部按钮 -->
|
<view class="footer-btns"
|
v-if="detailData">
|
<u-button type="primary"
|
class="action-btn"
|
:disabled="detailData.status === 1"
|
@click="goMaintain">
|
保养
|
</u-button>
|
<u-button type="error"
|
plain
|
class="action-btn"
|
@click="deleteUpkeep">
|
删除
|
</u-button>
|
</view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, onMounted } from "vue";
|
import { onShow } from "@dcloudio/uni-app";
|
import PageHeader from "@/components/PageHeader.vue";
|
import { delUpkeep } from "@/api/equipmentManagement/upkeep";
|
import config from "@/config";
|
import dayjs from "dayjs";
|
|
// 显示提示信息
|
const showToast = message => {
|
uni.showToast({
|
title: message,
|
icon: "none",
|
});
|
};
|
|
defineOptions({
|
name: "保养详情",
|
});
|
|
// 详情数据
|
const detailData = ref(null);
|
// 设备备件列表
|
const sparePartsList = ref([]);
|
// 附件列表
|
const fileList = ref([]);
|
// 页面ID
|
const pageId = ref(null);
|
|
// 格式化日期
|
const formatDate = dateStr => {
|
if (!dateStr) return "";
|
return dayjs(dateStr).format("YYYY-MM-DD");
|
};
|
|
// 格式化日期时间
|
const formatDateTime = dateStr => {
|
if (!dateStr) return "";
|
return dayjs(dateStr).format("YYYY-MM-DD HH:mm:ss");
|
};
|
|
// 格式化文件URL
|
const formatFileUrl = url => {
|
if (!url) return "";
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
return url;
|
}
|
const uploadsIndex = url.indexOf("uploads");
|
if (uploadsIndex !== -1) {
|
const relativePath = url.substring(uploadsIndex);
|
return `${config.baseUrl}/profile/${relativePath}`;
|
}
|
return `${config.baseUrl}/profile/${url}`;
|
};
|
|
// 判断是否为图片文件
|
const isImageFile = file => {
|
if (file.contentType && file.contentType.startsWith("image/")) {
|
return true;
|
}
|
if (file.type === "image") return true;
|
const name = file.bucketFilename || file.originalFilename || file.name || "";
|
const ext = name.split(".").pop()?.toLowerCase();
|
return ["jpg", "jpeg", "png", "gif", "webp"].includes(ext);
|
};
|
|
// 预览文件
|
const previewFile = file => {
|
if (file.type.includes("image")) {
|
uni.previewImage({
|
urls: [file.url],
|
current: file.url,
|
});
|
} else {
|
// 视频预览
|
const videoUrl = formatFileUrl(file.url || file.downloadUrl);
|
uni.navigateTo({
|
url: `/pages/common/videoPreview?url=${encodeURIComponent(videoUrl)}`,
|
});
|
}
|
};
|
|
// 获取详情数据
|
const getDetailData = () => {
|
try {
|
const dataStr = uni.getStorageSync("upkeepDetailData");
|
if (!dataStr) {
|
showToast("参数错误");
|
return null;
|
}
|
return JSON.parse(dataStr);
|
} catch (e) {
|
showToast("数据解析失败");
|
return null;
|
}
|
};
|
|
// 获取保养详情
|
const getDetail = () => {
|
const data = getDetailData();
|
if (!data) {
|
return;
|
}
|
|
detailData.value = data;
|
pageId.value = data.id;
|
// 处理备件数据 - 支持多种数据结构
|
sparePartsList.value = data.spareParts || data.sparePartList || [];
|
// 处理附件数据 - 支持多种数据结构
|
console.log(data.imagesFile);
|
fileList.value = data.imagesFile;
|
};
|
|
// 返回上一页
|
const goBack = () => {
|
uni.removeStorageSync("upkeepDetailData");
|
uni.navigateBack();
|
};
|
|
// 跳转到保养页面
|
const goMaintain = () => {
|
if (detailData.value.status === 1) {
|
showToast("该保养任务已完结");
|
return;
|
}
|
uni.setStorageSync("repairId", pageId.value);
|
uni.navigateTo({
|
url: "/pages/equipmentManagement/upkeep/maintain",
|
});
|
};
|
|
// 删除保养
|
const deleteUpkeep = () => {
|
uni.showModal({
|
title: "警告",
|
content: "确认删除保养数据, 此操作不可逆?",
|
confirmText: "确定",
|
cancelText: "取消",
|
success: async res => {
|
if (!res.confirm) return;
|
try {
|
const response = await delUpkeep(pageId.value);
|
if (response.code === 200) {
|
showToast("删除成功");
|
setTimeout(() => {
|
goBack();
|
}, 1500);
|
} else {
|
showToast(response.msg || "删除失败");
|
}
|
} catch (e) {
|
showToast("删除失败");
|
}
|
},
|
});
|
};
|
|
onShow(() => {
|
getDetail();
|
});
|
|
onMounted(() => {
|
getDetail();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.upkeep-detail {
|
min-height: 100vh;
|
background: #f5f5f5;
|
padding-bottom: 80px;
|
}
|
|
.detail-section {
|
padding: 15px;
|
}
|
|
.detail-card {
|
background: #fff;
|
border-radius: 12px;
|
padding: 16px;
|
margin-bottom: 12px;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
}
|
|
.card-header {
|
display: flex;
|
align-items: center;
|
margin-bottom: 12px;
|
}
|
|
.header-icon {
|
width: 40px;
|
height: 40px;
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
border-radius: 8px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
margin-right: 12px;
|
}
|
|
.header-icon.secondary {
|
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
}
|
|
.header-icon.tertiary {
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
}
|
|
.header-title {
|
flex: 1;
|
font-size: 16px;
|
font-weight: 600;
|
color: #333;
|
}
|
|
.status-tag {
|
margin-left: auto;
|
}
|
|
.detail-content {
|
padding-top: 8px;
|
}
|
|
.detail-row {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 10px 0;
|
border-bottom: 1px solid #f0f0f0;
|
}
|
|
.detail-row:last-child {
|
border-bottom: none;
|
}
|
|
.detail-label {
|
font-size: 14px;
|
color: #666;
|
min-width: 100px;
|
}
|
|
.detail-value {
|
font-size: 14px;
|
color: #333;
|
text-align: right;
|
flex: 1;
|
}
|
|
// 备件列表
|
.spare-parts-list {
|
padding-top: 8px;
|
}
|
|
.spare-part-item {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 10px 0;
|
border-bottom: 1px solid #f0f0f0;
|
}
|
|
.spare-part-item:last-child {
|
border-bottom: none;
|
}
|
|
.spare-part-name {
|
font-size: 14px;
|
color: #333;
|
}
|
|
.spare-part-code {
|
font-size: 12px;
|
color: #999;
|
}
|
|
// 文件列表
|
.file-list {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 10px;
|
padding-top: 8px;
|
}
|
|
.file-item {
|
width: calc(33.33% - 7px);
|
aspect-ratio: 1;
|
border-radius: 8px;
|
overflow: hidden;
|
background: #f5f5f5;
|
}
|
|
.file-preview {
|
width: 100%;
|
height: 100%;
|
}
|
|
.file-placeholder {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
background: #f0f0f0;
|
}
|
|
// 空状态
|
.no-data {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 60px 20px;
|
}
|
|
.no-data-text {
|
margin-top: 16px;
|
font-size: 14px;
|
color: #999;
|
}
|
|
// 空内容提示
|
.empty-content {
|
padding: 30px 0;
|
text-align: center;
|
}
|
|
.empty-text {
|
font-size: 14px;
|
color: #999;
|
}
|
|
// 底部按钮
|
.footer-btns {
|
position: fixed;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
background: #fff;
|
display: flex;
|
justify-content: space-around;
|
align-items: center;
|
padding: 12px 20px;
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
z-index: 1000;
|
}
|
|
.action-btn {
|
flex: 1;
|
margin: 0 8px;
|
}
|
</style>
|