From 3c2365660b3e576278d5a7ae79071db46812f078 Mon Sep 17 00:00:00 2001
From: WindowBird <13870814+windows-bird@user.noreply.gitee.com>
Date: Thu, 6 Nov 2025 16:49:06 +0800
Subject: [PATCH] =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=9B=BE=E7=89=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/api.js | 20 +++
pages/submit-task/index.vue | 82 +++++-----
pages/task-detail/index.vue | 299 ++++++++++++++++++++++++++++--------
3 files changed, 295 insertions(+), 106 deletions(-)
diff --git a/common/api.js b/common/api.js
index 69e1b00..20bda64 100644
--- a/common/api.js
+++ b/common/api.js
@@ -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 认证
+ }
+ });
+};
+
diff --git a/pages/submit-task/index.vue b/pages/submit-task/index.vue
index fd827cf..d795f4c 100644
--- a/pages/submit-task/index.vue
+++ b/pages/submit-task/index.vue
@@ -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
+ });
+ }
};
diff --git a/pages/task-detail/index.vue b/pages/task-detail/index.vue
index c26dcdd..47767c0 100644
--- a/pages/task-detail/index.vue
+++ b/pages/task-detail/index.vue
@@ -72,8 +72,21 @@
{{ task.content }}
- {{ task.content }}
- {{ task.content }}
+
+
+
+
+
+
申请延期
@@ -120,23 +133,30 @@
任务进度:
{{ record.progress }}%
-
+
+
-
- 📄
- {{ attachment.name }}
-
+
+
+
+
+
+ 📄
+ {{ file.name }}
@@ -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 {