<template>
|
<u-popup v-model="dialogVisitable"
|
mode="center"
|
:round="10"
|
:closeable="true"
|
@close="cancel">
|
<view class="popup-content">
|
<view class="popup-header">
|
<text class="popup-title">巡检记录上传</text>
|
</view>
|
<view class="upload-container">
|
<!-- 异常状态选择 -->
|
<view class="form-container">
|
<view class="title">巡检状态</view>
|
<view class="exception-section">
|
<view class="exception-options">
|
<view class="exception-option"
|
:class="{ active: hasException === false }"
|
@click="setExceptionStatus(false)">
|
<u-icon name="checkmark-circle"
|
size="20"
|
color="#52c41a"></u-icon>
|
<text class="option-text">正常</text>
|
</view>
|
<view class="exception-option"
|
:class="{ active: hasException === true }"
|
@click="setExceptionStatus(true)">
|
<u-icon name="close-circle"
|
size="20"
|
color="#ff4d4f"></u-icon>
|
<text class="option-text">存在异常</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
<!-- 异常描述(仅在异常时显示) -->
|
<view class="form-container"
|
v-if="hasException === true">
|
<view class="title">异常描述</view>
|
<u-input v-model="exceptionDescription"
|
type="textarea"
|
:maxlength="500"
|
placeholder="请描述异常情况..."
|
:customStyle="{ padding: '10px', backgroundColor: '#f5f5f5' }" />
|
</view>
|
<!-- 上传区域(仅在异常时显示) -->
|
<template v-if="hasException === true">
|
<view class="form-container">
|
<view class="title">巡检照片</view>
|
<u-upload :fileList="beforeModelValue"
|
@afterRead="afterRead"
|
@delete="deleteFile"
|
name="before"
|
multiple
|
:maxCount="10"
|
:maxSize="5 * 1024 * 1024"
|
accept="image/*"
|
:previewFullImage="true"></u-upload>
|
</view>
|
</template>
|
<!-- 正常状态提示 -->
|
<view class="form-container normal-tip"
|
v-if="hasException === false">
|
<u-icon name="info-circle"
|
size="40"
|
color="#52c41a"></u-icon>
|
<text class="tip-text">设备运行正常,无需上传照片</text>
|
</view>
|
</view>
|
<view class="popup-footer">
|
<u-button @click="cancel"
|
:customStyle="{ marginRight: '10px' }">取消</u-button>
|
<u-button type="primary"
|
@click="submitForm">保存</u-button>
|
</view>
|
</view>
|
</u-popup>
|
</template>
|
|
<script setup>
|
import { ref, computed } from "vue";
|
import { submitInspectionRecord } from "@/api/equipmentManagement/inspection.js";
|
import { getToken } from "@/utils/auth";
|
import config from "@/config";
|
|
const emit = defineEmits(["closeDia"]);
|
|
const dialogVisitable = ref(false);
|
const beforeModelValue = ref([]);
|
const infoData = ref(null);
|
|
// 异常状态:null=未选择, false=正常, true=异常
|
const hasException = ref(null);
|
// 异常描述
|
const exceptionDescription = ref("");
|
|
// 计算上传URL
|
const uploadFileUrl = computed(() => {
|
let baseUrl = "";
|
|
if (process.env.VUE_APP_BASE_API) {
|
baseUrl = process.env.VUE_APP_BASE_API;
|
} else {
|
baseUrl = config.baseUrl;
|
}
|
|
return baseUrl + "/file/upload";
|
});
|
|
const uploadSingleFile = async (fileItem, typeValue) => {
|
const token = getToken();
|
if (!token) throw new Error("用户未登录");
|
|
// H5: u-upload 可能给原生 File(fileItem.file)
|
const rawFile = fileItem?.file;
|
if (rawFile) {
|
const formData = new FormData();
|
formData.append("file", rawFile, rawFile.name || "image.jpg");
|
formData.append("type", String(typeValue));
|
const res = await fetch(uploadFileUrl.value, {
|
method: "POST",
|
headers: { Authorization: "Bearer " + token },
|
body: formData,
|
});
|
const data = await res.json();
|
if (data?.code !== 200) throw new Error(data?.msg || "上传失败");
|
return {
|
url: data?.data?.url,
|
name: rawFile.name || "image.jpg",
|
status: "success",
|
};
|
}
|
|
// 非 H5 / 兼容:走 uni.uploadFile
|
return await new Promise((resolve, reject) => {
|
uni.uploadFile({
|
url: uploadFileUrl.value,
|
filePath: fileItem.url,
|
name: "file",
|
header: {
|
Authorization: `Bearer ${token}`,
|
},
|
formData: {
|
type: typeValue,
|
},
|
success: res => {
|
try {
|
const data = JSON.parse(res.data);
|
if (data.code === 200) {
|
resolve({
|
url: data.data.url,
|
name: fileItem.name,
|
status: "success",
|
});
|
} else {
|
reject(new Error(data.msg || "上传失败"));
|
}
|
} catch (e) {
|
reject(e);
|
}
|
},
|
fail: err => reject(err),
|
});
|
});
|
};
|
|
// 文件上传处理
|
const afterRead = event => {
|
const { file } = event;
|
|
// 仅保留生产前(typeValue=10)
|
let typeValue = 10;
|
|
const files = Array.isArray(file) ? file : [file];
|
Promise.resolve()
|
.then(async () => {
|
for (const f of files) {
|
const uploaded = await uploadSingleFile(f, typeValue);
|
beforeModelValue.value.push(uploaded);
|
}
|
uni.showToast({ title: "上传成功", icon: "success" });
|
})
|
.catch(err => {
|
console.error("上传失败:", err);
|
uni.showToast({ title: "上传失败", icon: "error" });
|
});
|
};
|
|
// 删除文件
|
const deleteFile = event => {
|
const { index } = event;
|
beforeModelValue.value.splice(index, 1);
|
};
|
|
// 设置异常状态
|
const setExceptionStatus = status => {
|
hasException.value = status;
|
};
|
|
// 提交表单
|
const submitForm = async () => {
|
try {
|
// 检查是否选择了巡检状态
|
if (hasException.value === null) {
|
uni.showToast({
|
title: "请选择巡检状态",
|
icon: "none",
|
});
|
return;
|
}
|
|
// 如果是异常状态,检查是否有上传文件
|
if (hasException.value === true) {
|
if (beforeModelValue.value.length === 0) {
|
uni.showToast({
|
title: "请上传异常照片",
|
icon: "none",
|
});
|
return;
|
}
|
// 检查是否填写了异常描述
|
if (!exceptionDescription.value.trim()) {
|
uni.showToast({
|
title: "请填写异常描述",
|
icon: "none",
|
});
|
return;
|
}
|
}
|
|
let arr = [];
|
if (beforeModelValue.value.length > 0) {
|
arr.push(
|
...beforeModelValue.value.map(item => ({ ...item, statusType: 0 }))
|
);
|
}
|
|
// 提交数据
|
infoData.value.storageBlobDTO = arr;
|
infoData.value.hasException = hasException.value;
|
infoData.value.exceptionDescription = exceptionDescription.value;
|
await submitInspectionRecord({ ...infoData.value });
|
|
uni.showToast({
|
title: "提交成功",
|
icon: "success",
|
});
|
|
cancel();
|
} catch (error) {
|
console.error("提交失败:", error);
|
uni.showToast({
|
title: "提交失败",
|
icon: "error",
|
});
|
}
|
};
|
|
// 打开弹框
|
const openDialog = async row => {
|
infoData.value = row;
|
dialogVisitable.value = true;
|
|
// 清空之前的数据
|
beforeModelValue.value = [];
|
hasException.value = null;
|
exceptionDescription.value = "";
|
};
|
|
// 关闭弹框
|
const cancel = () => {
|
dialogVisitable.value = false;
|
emit("closeDia");
|
};
|
|
defineExpose({ openDialog });
|
</script>
|
|
<style scoped lang="scss">
|
.popup-content {
|
width: 90vw;
|
max-width: 400px;
|
background-color: #fff;
|
border-radius: 10px;
|
overflow: hidden;
|
}
|
|
.popup-header {
|
padding: 20px 20px 10px;
|
text-align: center;
|
border-bottom: 1px solid #f0f0f0;
|
}
|
|
.popup-title {
|
font-size: 18px;
|
font-weight: 600;
|
color: #333;
|
}
|
|
.upload-container {
|
padding: 20px;
|
max-height: 60vh;
|
overflow-y: auto;
|
}
|
|
.form-container {
|
margin-bottom: 20px;
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
}
|
|
.title {
|
font-size: 14px;
|
color: #1890ff;
|
line-height: 20px;
|
font-weight: 600;
|
padding-left: 10px;
|
position: relative;
|
margin: 6px 0 10px;
|
|
&::before {
|
content: "";
|
position: absolute;
|
left: 0;
|
top: 3px;
|
width: 4px;
|
height: 14px;
|
background-color: #1890ff;
|
}
|
}
|
|
.popup-footer {
|
display: flex;
|
justify-content: center;
|
padding: 15px 20px;
|
border-top: 1px solid #f0f0f0;
|
background-color: #fafafa;
|
}
|
|
// 异常状态选择样式
|
.exception-section {
|
padding: 10px 0;
|
}
|
|
.exception-options {
|
display: flex;
|
gap: 15px;
|
}
|
|
.exception-option {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
gap: 8px;
|
padding: 15px 20px;
|
border: 2px solid #e0e0e0;
|
border-radius: 8px;
|
cursor: pointer;
|
transition: all 0.3s;
|
background-color: #fff;
|
|
&.active {
|
border-color: #1890ff;
|
background-color: #e6f7ff;
|
}
|
|
&:active {
|
opacity: 0.8;
|
}
|
}
|
|
.option-text {
|
font-size: 14px;
|
color: #333;
|
font-weight: 500;
|
}
|
|
// 正常状态提示样式
|
.normal-tip {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 40px 20px;
|
background-color: #f6ffed;
|
border: 1px dashed #b7eb8f;
|
border-radius: 8px;
|
|
.tip-text {
|
margin-top: 15px;
|
font-size: 14px;
|
color: #52c41a;
|
}
|
}
|
</style>
|