<template>
|
<u-popup
|
:show="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="upload-buttons">
|
<u-button type="primary" size="small" @click="chooseVideo('before')" :disabled="beforeModelValue.length >= 10">
|
<u-icon name="video" size="16" color="#fff" style="margin-right: 5px;"></u-icon>
|
选择视频
|
</u-button>
|
<text class="file-count">{{ beforeModelValue.length }}/10</text>
|
</view>
|
<view class="file-list" v-if="beforeModelValue.length > 0">
|
<view v-for="(file, index) in beforeModelValue" :key="index" class="file-item">
|
<text class="file-name">视频{{ index + 1 }}</text>
|
<u-button
|
type="error"
|
size="mini"
|
:customStyle="{ minWidth: '120rpx', width: 'auto', padding: '0 20rpx', height: '60rpx' }"
|
@click="deleteFile(index, 'before')"
|
>删除</u-button>
|
</view>
|
</view>
|
</view>
|
|
<view class="form-container">
|
<view class="title">生产后</view>
|
<view class="upload-buttons">
|
<u-button type="primary" size="small" @click="chooseVideo('after')" :disabled="afterModelValue.length >= 10">
|
<u-icon name="video" size="16" color="#fff" style="margin-right: 5px;"></u-icon>
|
选择视频
|
</u-button>
|
<text class="file-count">{{ afterModelValue.length }}/10</text>
|
</view>
|
<view class="file-list" v-if="afterModelValue.length > 0">
|
<view v-for="(file, index) in afterModelValue" :key="index" class="file-item">
|
<text class="file-name">视频{{ index + 1 }}</text>
|
<u-button
|
type="error"
|
size="mini"
|
:customStyle="{ minWidth: '120rpx', width: 'auto', padding: '0 20rpx', height: '60rpx' }"
|
@click="deleteFile(index, 'after')"
|
>删除</u-button>
|
</view>
|
</view>
|
</view>
|
|
<view class="form-container">
|
<view class="title">生产问题</view>
|
<view class="upload-buttons">
|
<u-button type="primary" size="small" @click="chooseVideo('issue')" :disabled="issueModelValue.length >= 10">
|
<u-icon name="video" size="16" color="#fff" style="margin-right: 5px;"></u-icon>
|
选择视频
|
</u-button>
|
<text class="file-count">{{ issueModelValue.length }}/10</text>
|
</view>
|
<view class="file-list" v-if="issueModelValue.length > 0">
|
<view v-for="(file, index) in issueModelValue" :key="index" class="file-item">
|
<text class="file-name">视频{{ index + 1 }}</text>
|
<u-button
|
type="error"
|
size="mini"
|
:customStyle="{ minWidth: '120rpx', width: 'auto', padding: '0 20rpx', height: '60rpx' }"
|
@click="deleteFile(index, 'issue')"
|
>删除</u-button>
|
</view>
|
</view>
|
</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.js'
|
|
const emit = defineEmits(['closeDia'])
|
|
// 上传接口URL
|
const uploadFileUrl = computed(() => {
|
return config.baseUrl + '/common/minioUploads'
|
})
|
|
// 上传请求头
|
const uploadHeaders = computed(() => {
|
const token = getToken()
|
return token ? { Authorization: 'Bearer ' + token } : {}
|
})
|
|
const dialogVisitable = ref(false)
|
const beforeModelValue = ref([])
|
const afterModelValue = ref([])
|
const issueModelValue = ref([])
|
const infoData = ref(null)
|
|
// 选择视频
|
const chooseVideo = (type) => {
|
const currentList = type === 'before' ? beforeModelValue : type === 'after' ? afterModelValue : issueModelValue;
|
|
if (currentList.value.length >= 10) {
|
uni.showToast({
|
title: '最多只能选择10个视频',
|
icon: 'none'
|
});
|
return;
|
}
|
|
uni.chooseVideo({
|
sourceType: ['camera', 'album'],
|
maxDuration: 60,
|
camera: 'back',
|
success: (res) => {
|
try {
|
if (!res.tempFilePath) {
|
throw new Error('未获取到视频文件');
|
}
|
|
// 从临时路径中提取文件名,做为初始展示
|
const tempName = res.tempFilePath.split('/').pop() || `video_${Date.now()}.mp4`
|
const fileItem = {
|
url: res.tempFilePath,
|
name: tempName,
|
originalFilename: tempName,
|
size: res.size || 0,
|
duration: res.duration || 0,
|
status: 'pending' // 待上传状态
|
};
|
|
// 添加到对应的数组
|
currentList.value.push(fileItem);
|
|
// 自动上传
|
uploadFile(fileItem, type, currentList.value.length - 1);
|
} catch (error) {
|
console.error('处理视频失败:', error);
|
uni.showToast({
|
title: '处理视频失败',
|
icon: 'error'
|
});
|
}
|
},
|
fail: (err) => {
|
console.error('选择视频失败:', err);
|
uni.showToast({
|
title: '选择视频失败: ' + (err.errMsg || '未知错误'),
|
icon: 'error'
|
});
|
}
|
});
|
}
|
|
// 上传文件到服务器
|
const uploadFile = (fileItem, type, index) => {
|
fileItem.status = 'uploading';
|
|
// 确保token存在
|
const token = getToken();
|
if (!token) {
|
fileItem.status = 'failed';
|
uni.showToast({
|
title: '用户未登录',
|
icon: 'error'
|
});
|
return;
|
}
|
|
uni.uploadFile({
|
url: uploadFileUrl.value,
|
filePath: fileItem.url,
|
name: 'files', // 注意:接口使用的是 'files' 而不是 'file'
|
header: {
|
'Authorization': `Bearer ${token}`
|
},
|
success: (res) => {
|
try {
|
if (res.statusCode === 200) {
|
const response = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
|
if (response.code === 200) {
|
// 响应数据是数组格式,取第一个元素
|
const uploadedFile = Array.isArray(response.data) ? response.data[0] : response.data;
|
|
console.log('上传成功,返回的文件信息:', uploadedFile);
|
console.log('原始文件名:', uploadedFile.originalFilename);
|
|
// 更新文件信息 - 使用 Object.assign 确保响应式更新
|
const displayName = uploadedFile.originalFilename
|
|| uploadedFile.bucketFilename
|
|| fileItem.name
|
|| '未命名文件';
|
Object.assign(fileItem, {
|
url: uploadedFile.url || uploadedFile.downloadUrl,
|
status: 'success',
|
id: uploadedFile.id,
|
name: displayName,
|
originalFilename: uploadedFile.originalFilename || displayName, // 保存原始文件名
|
bucketFilename: uploadedFile.bucketFilename,
|
downloadUrl: uploadedFile.downloadUrl || uploadedFile.url,
|
size: uploadedFile.byteSize || fileItem.size,
|
createTime: uploadedFile.createTime || new Date().getTime()
|
});
|
|
console.log('更新后的文件项:', fileItem);
|
|
uni.showToast({
|
title: '上传成功',
|
icon: 'success'
|
});
|
} else {
|
fileItem.status = 'failed';
|
uni.showToast({
|
title: response.msg || '上传失败',
|
icon: 'error'
|
});
|
}
|
} else {
|
fileItem.status = 'failed';
|
uni.showToast({
|
title: `服务器错误,状态码: ${res.statusCode}`,
|
icon: 'error'
|
});
|
}
|
} catch (e) {
|
fileItem.status = 'failed';
|
console.error('解析响应失败:', e);
|
console.error('原始响应数据:', res.data);
|
uni.showToast({
|
title: '解析响应失败',
|
icon: 'error'
|
});
|
}
|
},
|
fail: (err) => {
|
fileItem.status = 'failed';
|
console.error('上传失败:', err);
|
let errorMessage = '上传失败';
|
if (err.errMsg) {
|
if (err.errMsg.includes('statusCode: null')) {
|
errorMessage = '网络连接失败,请检查网络设置';
|
} else if (err.errMsg.includes('timeout')) {
|
errorMessage = '上传超时,请重试';
|
} else {
|
errorMessage = err.errMsg;
|
}
|
}
|
uni.showToast({
|
title: errorMessage,
|
icon: 'error'
|
});
|
}
|
});
|
}
|
|
// 删除文件
|
const deleteFile = (index, type) => {
|
if (type === 'before') {
|
beforeModelValue.value.splice(index, 1);
|
} else if (type === 'after') {
|
afterModelValue.value.splice(index, 1);
|
} else if (type === 'issue') {
|
issueModelValue.value.splice(index, 1);
|
}
|
}
|
|
// 提交表单
|
const submitForm = async () => {
|
try {
|
let arr = []
|
if (beforeModelValue.value.length > 0) {
|
arr.push(...beforeModelValue.value.map(item => ({ ...item, statusType: 0 })))
|
}
|
if (afterModelValue.value.length > 0) {
|
arr.push(...afterModelValue.value.map(item => ({ ...item, statusType: 1 })))
|
}
|
if (issueModelValue.value.length > 0) {
|
arr.push(...issueModelValue.value.map(item => ({ ...item, statusType: 2 })))
|
}
|
|
// 提交数据
|
infoData.value.storageBlobDTO = arr
|
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 = []
|
afterModelValue.value = []
|
issueModelValue.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;
|
}
|
|
.upload-buttons {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
margin-bottom: 10px;
|
}
|
|
.file-count {
|
font-size: 12px;
|
color: #999;
|
}
|
|
.file-list {
|
margin-top: 10px;
|
}
|
|
.file-item {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
padding: 8px 0;
|
border-bottom: 1px solid #f0f0f0;
|
}
|
|
.file-item:last-child {
|
border-bottom: none;
|
}
|
|
.file-name {
|
font-size: 14px;
|
color: #333;
|
flex: 1;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
margin-right: 10px;
|
}
|
</style>
|