显示图片
This commit is contained in:
parent
74c2fda0ef
commit
3c2365660b
|
|
@ -97,3 +97,23 @@ export const getQiniuUploadToken = () => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 提交任务
|
||||
* @param {Object} params 请求参数
|
||||
* @param {string} params.id 任务ID
|
||||
* @param {string} params.submitAttaches 附件, 逗号分隔的URL字符串
|
||||
* @param {string} params.submitRemark 备注
|
||||
* @returns {Promise} 返回提交结果
|
||||
*/
|
||||
export const submitTask = ({ id, submitAttaches, submitRemark }) => {
|
||||
return uni.$uv.http.put('/bst/task/submit', {
|
||||
id: id,
|
||||
submitAttaches: submitAttaches || '',
|
||||
submitRemark: submitRemark || ''
|
||||
}, {
|
||||
custom: {
|
||||
auth: true // 启用 token 认证
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@
|
|||
import { ref, computed, onMounted } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { chooseAndUploadImages } from '@/utils/qiniu.js';
|
||||
import { submitTask } from '@/common/api.js';
|
||||
|
||||
// 表单数据
|
||||
const formData = ref({
|
||||
|
|
@ -416,7 +417,7 @@ const formatTimeToChinese = (date) => {
|
|||
};
|
||||
|
||||
// 提交任务
|
||||
const handleSubmit = () => {
|
||||
const handleSubmit = async () => {
|
||||
if (!canSubmit.value) {
|
||||
uni.showToast({
|
||||
title: '请至少填写提交说明或添加附件',
|
||||
|
|
@ -425,51 +426,48 @@ const handleSubmit = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!taskId.value) {
|
||||
uni.showToast({
|
||||
title: '任务ID不能为空',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.showLoading({
|
||||
title: isEditMode.value ? '更新中...' : '提交中...'
|
||||
});
|
||||
|
||||
// 准备提交数据
|
||||
const submitData = {
|
||||
taskId: taskId.value,
|
||||
description: formData.value.description.trim(),
|
||||
progress: formData.value.progress,
|
||||
images: formData.value.images,
|
||||
files: formData.value.files.map(file => ({
|
||||
name: file.name,
|
||||
path: file.path,
|
||||
size: file.size
|
||||
}))
|
||||
};
|
||||
try {
|
||||
// 合并所有附件URL(图片和文件)
|
||||
const allAttaches = [
|
||||
...formData.value.images, // 图片已经是七牛云URL
|
||||
...formData.value.files.map(file => file.path) // 文件路径(如果是URL则直接使用,如果是本地路径可能需要先上传)
|
||||
].filter(url => url && url.trim() !== ''); // 过滤空值
|
||||
|
||||
// TODO: 调用提交接口
|
||||
// 实际使用时,应该调用API接口上传数据
|
||||
// uni.request({
|
||||
// url: isEditMode.value ? '/api/task/submit/update' : '/api/task/submit',
|
||||
// method: isEditMode.value ? 'PUT' : 'POST',
|
||||
// data: submitData,
|
||||
// success: (res) => {
|
||||
// // 处理成功响应
|
||||
// },
|
||||
// fail: (err) => {
|
||||
// // 处理错误
|
||||
// }
|
||||
// });
|
||||
// 将附件数组转换为逗号分隔的字符串
|
||||
const submitAttaches = allAttaches.join(',');
|
||||
|
||||
// 调用提交接口
|
||||
await submitTask({
|
||||
id: taskId.value,
|
||||
submitAttaches: submitAttaches,
|
||||
submitRemark: formData.value.description.trim()
|
||||
});
|
||||
|
||||
// 模拟提交请求
|
||||
setTimeout(() => {
|
||||
uni.hideLoading();
|
||||
|
||||
|
||||
// 提交成功后的处理
|
||||
if (isEditMode.value) {
|
||||
// 编辑模式:更新现有记录
|
||||
const updatedRecord = {
|
||||
userName: editRecordData.value?.userName || '当前用户', // 保持原用户名
|
||||
time: formatTimeToChinese(new Date()), // 更新时间
|
||||
content: submitData.description || '',
|
||||
progress: submitData.progress,
|
||||
content: formData.value.description.trim() || '',
|
||||
progress: formData.value.progress,
|
||||
attachments: [
|
||||
...submitData.images.map(img => ({ type: 'image', path: img })),
|
||||
...submitData.files.map(file => ({ type: 'file', name: file.name, path: file.path }))
|
||||
...formData.value.images.map(img => ({ type: 'image', path: img })),
|
||||
...formData.value.files.map(file => ({ type: 'file', name: file.name, path: file.path }))
|
||||
],
|
||||
canEdit: true, // 保持可编辑权限
|
||||
showDelayBtn: editRecordData.value?.showDelayBtn || false
|
||||
|
|
@ -490,11 +488,11 @@ const handleSubmit = () => {
|
|||
const submitRecord = {
|
||||
userName: '当前用户', // TODO: 从用户信息获取
|
||||
time: formatTimeToChinese(new Date()),
|
||||
content: submitData.description || '',
|
||||
progress: submitData.progress,
|
||||
content: formData.value.description.trim() || '',
|
||||
progress: formData.value.progress,
|
||||
attachments: [
|
||||
...submitData.images.map(img => ({ type: 'image', path: img })),
|
||||
...submitData.files.map(file => ({ type: 'file', name: file.name, path: file.path }))
|
||||
...formData.value.images.map(img => ({ type: 'image', path: img })),
|
||||
...formData.value.files.map(file => ({ type: 'file', name: file.name, path: file.path }))
|
||||
],
|
||||
canEdit: true,
|
||||
showDelayBtn: false
|
||||
|
|
@ -513,7 +511,15 @@ const handleSubmit = () => {
|
|||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
console.error('提交任务失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '提交失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -72,8 +72,21 @@
|
|||
</view>
|
||||
<view class="task-content-wrapper">
|
||||
<text class="task-content-text">{{ task.content }}</text>
|
||||
<text class="task-content-text">{{ task.content }}</text>
|
||||
<text class="task-content-text">{{ task.content }}</text>
|
||||
</view>
|
||||
<!-- 任务图片展示 -->
|
||||
<view class="task-images-wrapper" v-if="task.pictures && task.pictures.length > 0">
|
||||
<view
|
||||
class="task-image-item"
|
||||
v-for="(imageUrl, imgIndex) in task.pictures"
|
||||
:key="imgIndex"
|
||||
@click="previewTaskImages(task.pictures, imgIndex)"
|
||||
>
|
||||
<image
|
||||
:src="imageUrl"
|
||||
mode="aspectFill"
|
||||
class="task-image"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="delay-btn-wrapper">
|
||||
<uv-button type="error" size="small" @click="applyDelay">申请延期</uv-button>
|
||||
|
|
@ -120,23 +133,30 @@
|
|||
<text class="progress-label">任务进度:</text>
|
||||
<text class="progress-value">{{ record.progress }}%</text>
|
||||
</view>
|
||||
<view class="record-attachments" v-if="record.attachments && record.attachments.length > 0">
|
||||
<!-- 图片附件展示(一行三个) -->
|
||||
<view class="record-images-wrapper" v-if="record.imageAttachments && record.imageAttachments.length > 0">
|
||||
<view
|
||||
class="attachment-item"
|
||||
v-for="(attachment, attIndex) in record.attachments"
|
||||
:key="attIndex"
|
||||
class="record-image-item"
|
||||
v-for="(imageUrl, imgIndex) in record.imageAttachments"
|
||||
:key="imgIndex"
|
||||
@click="previewRecordImages(record.imageAttachments, imgIndex)"
|
||||
>
|
||||
<image
|
||||
v-if="attachment.type === 'image'"
|
||||
:src="attachment.path"
|
||||
:src="imageUrl"
|
||||
mode="aspectFill"
|
||||
class="attachment-image"
|
||||
@click="previewAttachmentImage(record.attachments, attIndex)"
|
||||
class="record-image"
|
||||
/>
|
||||
<view v-else class="file-attachment">
|
||||
<text class="file-icon">📄</text>
|
||||
<text class="file-name">{{ attachment.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 文件附件展示 -->
|
||||
<view class="record-files-wrapper" v-if="record.fileAttachments && record.fileAttachments.length > 0">
|
||||
<view
|
||||
class="file-attachment-item"
|
||||
v-for="(file, fileIndex) in record.fileAttachments"
|
||||
:key="fileIndex"
|
||||
>
|
||||
<text class="file-icon">📄</text>
|
||||
<text class="file-name">{{ file.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="delay-btn-wrapper" v-if="record.showDelayBtn">
|
||||
|
|
@ -290,6 +310,21 @@ const getOwnerNames = (memberList) => {
|
|||
return memberList.map(member => member.userName || member.name || '').filter(name => name).join('、');
|
||||
};
|
||||
|
||||
// 解析逗号分隔的URL字符串
|
||||
const parseAttachUrls = (attachStr) => {
|
||||
if (!attachStr) return [];
|
||||
if (typeof attachStr !== 'string') return [];
|
||||
|
||||
// 按逗号分割,过滤空值
|
||||
return attachStr.split(',').map(url => url.trim()).filter(url => url);
|
||||
};
|
||||
|
||||
// 判断URL是否为图片
|
||||
const isImageUrl = (url) => {
|
||||
if (!url || typeof url !== 'string') return false;
|
||||
return /\.(jpg|jpeg|png|gif|bmp|webp)(\?|$)/i.test(url);
|
||||
};
|
||||
|
||||
// 转换提交记录数据
|
||||
const transformSubmitRecords = (submitList) => {
|
||||
if (!Array.isArray(submitList) || submitList.length === 0) {
|
||||
|
|
@ -297,28 +332,62 @@ const transformSubmitRecords = (submitList) => {
|
|||
}
|
||||
|
||||
return submitList.map(item => {
|
||||
// 处理附件
|
||||
let attachments = [];
|
||||
// 处理附件:可能是逗号分隔的URL字符串
|
||||
let imageAttachments = [];
|
||||
let fileAttachments = [];
|
||||
|
||||
if (item.attaches) {
|
||||
try {
|
||||
// 如果 attaches 是字符串,尝试解析
|
||||
const attachData = typeof item.attaches === 'string' ? JSON.parse(item.attaches) : item.attaches;
|
||||
// 先尝试作为JSON解析
|
||||
let attachData = null;
|
||||
try {
|
||||
attachData = typeof item.attaches === 'string' ? JSON.parse(item.attaches) : item.attaches;
|
||||
} catch (e) {
|
||||
// 如果不是JSON,则作为逗号分隔的URL字符串处理
|
||||
attachData = null;
|
||||
}
|
||||
|
||||
if (Array.isArray(attachData)) {
|
||||
attachments = attachData.map(att => {
|
||||
// 根据文件扩展名判断类型
|
||||
const fileName = att.name || att.fileName || '';
|
||||
// 如果是数组格式
|
||||
attachData.forEach(att => {
|
||||
const filePath = att.path || att.url || att.filePath || '';
|
||||
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(fileName);
|
||||
const fileName = att.name || att.fileName || '';
|
||||
const isImage = fileName ? /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(fileName) : isImageUrl(filePath);
|
||||
|
||||
return {
|
||||
type: isImage ? 'image' : 'file',
|
||||
name: fileName,
|
||||
path: filePath
|
||||
};
|
||||
if (isImage && filePath) {
|
||||
imageAttachments.push(filePath);
|
||||
} else if (filePath) {
|
||||
fileAttachments.push({
|
||||
name: fileName || '文件',
|
||||
path: filePath
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 作为逗号分隔的URL字符串处理
|
||||
const urls = parseAttachUrls(item.attaches);
|
||||
urls.forEach(url => {
|
||||
if (isImageUrl(url)) {
|
||||
imageAttachments.push(url);
|
||||
} else {
|
||||
// 从URL中提取文件名
|
||||
const fileName = url.split('/').pop().split('?')[0] || '文件';
|
||||
fileAttachments.push({
|
||||
name: fileName,
|
||||
path: url
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析附件数据失败:', e);
|
||||
// 如果解析失败,尝试作为逗号分隔的URL字符串处理
|
||||
const urls = parseAttachUrls(item.attaches);
|
||||
urls.forEach(url => {
|
||||
if (isImageUrl(url)) {
|
||||
imageAttachments.push(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +398,8 @@ const transformSubmitRecords = (submitList) => {
|
|||
time: formatTimeToChinese(item.createTime) || '',
|
||||
content: item.remark || item.description || item.taskDescription || '', // 如果没有提交内容,可能显示任务描述
|
||||
progress: null, // API 返回的数据中没有进度字段
|
||||
attachments: attachments,
|
||||
imageAttachments: imageAttachments,
|
||||
fileAttachments: fileAttachments,
|
||||
showDelayBtn: false, // 根据业务需求决定是否显示
|
||||
canEdit: true // 根据业务需求决定是否可以编辑
|
||||
};
|
||||
|
|
@ -402,17 +472,22 @@ const deleteRecord = (index) => {
|
|||
});
|
||||
};
|
||||
|
||||
// 预览附件图片
|
||||
const previewAttachmentImage = (attachments, index) => {
|
||||
const imageUrls = attachments
|
||||
.filter(att => att.type === 'image')
|
||||
.map(att => att.path);
|
||||
const currentIndex = attachments.slice(0, index).filter(att => att.type === 'image').length;
|
||||
|
||||
if (imageUrls.length > 0) {
|
||||
// 预览任务图片
|
||||
const previewTaskImages = (imageUrls, index) => {
|
||||
if (imageUrls && imageUrls.length > 0) {
|
||||
uni.previewImage({
|
||||
urls: imageUrls,
|
||||
current: currentIndex
|
||||
current: index
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 预览提交记录图片
|
||||
const previewRecordImages = (imageUrls, index) => {
|
||||
if (imageUrls && imageUrls.length > 0) {
|
||||
uni.previewImage({
|
||||
urls: imageUrls,
|
||||
current: index
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -427,7 +502,7 @@ const getTagType = (tagText) => {
|
|||
const getTagStyle = (tagText) => {
|
||||
const status = getStatusFromTagText(tagText);
|
||||
const styleConfig = getTaskStatusStyle(status);
|
||||
return {
|
||||
return {
|
||||
backgroundColor: styleConfig.backgroundColor,
|
||||
color: styleConfig.color,
|
||||
borderColor: styleConfig.borderColor
|
||||
|
|
@ -499,6 +574,9 @@ const loadTaskData = async (taskId) => {
|
|||
// 转换提交记录
|
||||
const submitRecords = transformSubmitRecords(res.submitList || []);
|
||||
|
||||
// 解析任务图片(逗号分隔的URL字符串)
|
||||
const taskPictures = res.picture ? parseAttachUrls(res.picture) : [];
|
||||
|
||||
// 更新任务数据
|
||||
task.value = {
|
||||
id: res.id || taskId,
|
||||
|
|
@ -511,6 +589,7 @@ const loadTaskData = async (taskId) => {
|
|||
responsible: getOwnerNames(res.memberList || []),
|
||||
publishTime: res.createTime ? formatTimeToChinese(res.createTime) : '',
|
||||
content: res.description || '',
|
||||
pictures: taskPictures, // 任务图片数组
|
||||
submitRecords: submitRecords,
|
||||
// 保存原始数据,供其他功能使用
|
||||
rawData: res
|
||||
|
|
@ -555,13 +634,52 @@ onLoad((options) => {
|
|||
}
|
||||
});
|
||||
|
||||
// 转换旧格式的提交记录为新格式(兼容本地存储的数据)
|
||||
const convertOldFormatRecord = (record) => {
|
||||
// 如果已经是新格式(有 imageAttachments 和 fileAttachments),直接返回
|
||||
if (record.imageAttachments !== undefined || record.fileAttachments !== undefined) {
|
||||
return record;
|
||||
}
|
||||
|
||||
// 如果是旧格式(有 attachments 数组),转换为新格式
|
||||
if (record.attachments && Array.isArray(record.attachments)) {
|
||||
const imageAttachments = [];
|
||||
const fileAttachments = [];
|
||||
|
||||
record.attachments.forEach(att => {
|
||||
if (att.type === 'image' && att.path) {
|
||||
imageAttachments.push(att.path);
|
||||
} else if (att.type === 'file') {
|
||||
fileAttachments.push({
|
||||
name: att.name || '文件',
|
||||
path: att.path || ''
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
...record,
|
||||
imageAttachments: imageAttachments,
|
||||
fileAttachments: fileAttachments
|
||||
};
|
||||
}
|
||||
|
||||
// 如果都没有,返回空数组
|
||||
return {
|
||||
...record,
|
||||
imageAttachments: [],
|
||||
fileAttachments: []
|
||||
};
|
||||
};
|
||||
|
||||
// 页面显示时检查是否有新的提交记录或更新的记录
|
||||
onShow(() => {
|
||||
// 检查是否有新的提交记录
|
||||
const newSubmitRecord = uni.getStorageSync('newSubmitRecord');
|
||||
if (newSubmitRecord) {
|
||||
// 将新提交记录添加到列表开头
|
||||
task.value.submitRecords.unshift(newSubmitRecord);
|
||||
// 转换格式并添加到列表开头
|
||||
const convertedRecord = convertOldFormatRecord(newSubmitRecord);
|
||||
task.value.submitRecords.unshift(convertedRecord);
|
||||
// 切换到提交记录标签页
|
||||
activeTab.value = 'records';
|
||||
// 清除存储的记录
|
||||
|
|
@ -573,8 +691,9 @@ onShow(() => {
|
|||
if (updatedSubmitRecord) {
|
||||
const { recordIndex, record } = updatedSubmitRecord;
|
||||
if (recordIndex !== undefined && recordIndex >= 0 && recordIndex < task.value.submitRecords.length) {
|
||||
// 更新指定索引的记录
|
||||
task.value.submitRecords[recordIndex] = record;
|
||||
// 转换格式并更新指定索引的记录
|
||||
const convertedRecord = convertOldFormatRecord(record);
|
||||
task.value.submitRecords[recordIndex] = convertedRecord;
|
||||
// 切换到提交记录标签页
|
||||
activeTab.value = 'records';
|
||||
}
|
||||
|
|
@ -935,38 +1054,82 @@ onShow(() => {
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
.record-attachments {
|
||||
/* 任务图片展示(一行最多三张) */
|
||||
.task-images-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.task-image-item {
|
||||
/* 一行三个:每个图片宽度 = (100% - 2个gap) / 3 */
|
||||
width: calc((100% - 16px) / 3);
|
||||
aspect-ratio: 1;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
background-color: #e0e0e0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.task-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* 提交记录图片展示(一行三个) */
|
||||
.record-images-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.attachment-item {
|
||||
.attachment-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 4px;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.file-attachment {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
.record-image-item {
|
||||
/* 一行三个:每个图片宽度 = (100% - 2个gap) / 3 */
|
||||
width: calc((100% - 16px) / 3);
|
||||
aspect-ratio: 1;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
background-color: #e0e0e0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.record-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* 文件附件展示 */
|
||||
.record-files-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.file-attachment-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.no-record {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user