接口获取任务详细
This commit is contained in:
parent
3c83302384
commit
881f8b990e
|
|
@ -72,3 +72,16 @@ export const getTaskList = ({ overdue, statusList, expireTimeStart, expireTimeEn
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取任务详情
|
||||
* @param {string} id 任务ID
|
||||
* @returns {Promise} 返回任务详情
|
||||
*/
|
||||
export const getTaskDetail = (id) => {
|
||||
return uni.$uv.http.get(`bst/task/${id}`, {
|
||||
custom: {
|
||||
auth: true // 启用 token 认证
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,15 @@
|
|||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">创建人:</text>
|
||||
<text class="info-value">{{ task.creator }}</text>
|
||||
<view class="info-value-with-avatar">
|
||||
<image
|
||||
v-if="task.creatorAvatar"
|
||||
:src="task.creatorAvatar"
|
||||
class="creator-avatar"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<text>{{ task.creator }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">负责人:</text>
|
||||
|
|
@ -81,7 +89,13 @@
|
|||
<view class="submit-record-card" v-for="(record, index) in task.submitRecords" :key="index">
|
||||
<view class="record-header">
|
||||
<view class="user-info">
|
||||
<view class="avatar-placeholder"></view>
|
||||
<image
|
||||
v-if="record.userAvatar"
|
||||
:src="record.userAvatar"
|
||||
class="avatar-img"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view v-else class="avatar-placeholder"></view>
|
||||
<text class="user-name">{{ record.userName }}</text>
|
||||
</view>
|
||||
<view class="record-header-right">
|
||||
|
|
@ -150,6 +164,7 @@ import { ref, onMounted, } from 'vue';
|
|||
import { onLoad,onShow } from '@dcloudio/uni-app';
|
||||
import { getStatusFromTagText, getTaskStatusType, getTaskStatusStyle } from '@/utils/taskConfig.js';
|
||||
import { useTaskStore } from '@/store/task';
|
||||
import { getTaskDetail } from '@/common/api.js';
|
||||
|
||||
// 当前激活的标签
|
||||
const activeTab = ref('info');
|
||||
|
|
@ -157,10 +172,12 @@ const showMenuIndex = ref(-1);
|
|||
|
||||
// 格式化时间为中文格式:年月日星期几时分秒
|
||||
const formatTimeToChinese = (date) => {
|
||||
if (!date) return '';
|
||||
if (typeof date === 'string') {
|
||||
// 如果是字符串,尝试解析
|
||||
date = new Date(date);
|
||||
}
|
||||
if (isNaN(date.getTime())) return '';
|
||||
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
|
|
@ -173,6 +190,152 @@ const formatTimeToChinese = (date) => {
|
|||
return `${year}年${month}月${day}日 ${weekday} ${hour}:${minute}:${second}`;
|
||||
};
|
||||
|
||||
// 格式化日期:将 "2024-10-31 23:59:59" 转换为 "2024-10-31"
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return '';
|
||||
// 如果包含空格,取日期部分
|
||||
return dateStr.split(' ')[0];
|
||||
};
|
||||
|
||||
// 格式化日期时间:格式化为 yyyy-MM-dd HH:mm:ss
|
||||
const formatDateTime = (date) => {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
if (isNaN(d.getTime())) return '';
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
const hours = String(d.getHours()).padStart(2, '0');
|
||||
const minutes = String(d.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(d.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
// 计算剩余天数
|
||||
const calculateRemainingDays = (expireTime) => {
|
||||
if (!expireTime) return null;
|
||||
const expireDate = new Date(expireTime);
|
||||
const now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
expireDate.setHours(0, 0, 0, 0);
|
||||
const diffTime = expireDate.getTime() - now.getTime();
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
return diffDays;
|
||||
};
|
||||
|
||||
// 根据过期时间和状态判断任务状态
|
||||
const determineTaskStatus = (status, expireTime) => {
|
||||
// 如果任务已完成(状态为4),直接返回 completed
|
||||
const taskStatus = status !== undefined ? status : null;
|
||||
const isCompleted = taskStatus === 4 ||
|
||||
taskStatus === '4' ||
|
||||
taskStatus === 'completed' ||
|
||||
String(taskStatus) === '4';
|
||||
|
||||
if (isCompleted) {
|
||||
return 'completed';
|
||||
}
|
||||
|
||||
// 如果没有过期时间,返回待完成
|
||||
if (!expireTime) {
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
const expireDate = new Date(expireTime);
|
||||
const now = new Date();
|
||||
|
||||
// 设置时间到当天0点,便于日期比较
|
||||
now.setHours(0, 0, 0, 0);
|
||||
expireDate.setHours(23, 59, 59, 999);
|
||||
|
||||
// 如果已过期,标记为逾期
|
||||
if (expireDate.getTime() < now.getTime()) {
|
||||
return 'overdue';
|
||||
}
|
||||
|
||||
// 计算距离过期的天数
|
||||
const diffTime = expireDate.getTime() - now.getTime();
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
|
||||
// 如果3天内到期,标记为即将逾期
|
||||
if (diffDays <= 3 && diffDays > 0) {
|
||||
return 'imminent';
|
||||
}
|
||||
|
||||
// 否则返回待完成状态
|
||||
return 'pending';
|
||||
};
|
||||
|
||||
// 获取状态标签数组
|
||||
const getStatusTags = (status, expireTime) => {
|
||||
const taskStatus = determineTaskStatus(status, expireTime);
|
||||
const tags = [];
|
||||
|
||||
if (taskStatus === 'completed') {
|
||||
tags.push('已完成');
|
||||
} else if (taskStatus === 'overdue') {
|
||||
tags.push('已逾期', '紧急');
|
||||
} else if (taskStatus === 'imminent') {
|
||||
tags.push('即将逾期');
|
||||
} else {
|
||||
tags.push('待完成');
|
||||
}
|
||||
|
||||
return tags;
|
||||
};
|
||||
|
||||
// 提取负责人:从 memberList 中提取所有成员的名称
|
||||
const getOwnerNames = (memberList) => {
|
||||
if (!Array.isArray(memberList) || memberList.length === 0) return '';
|
||||
return memberList.map(member => member.userName || member.name || '').filter(name => name).join('、');
|
||||
};
|
||||
|
||||
// 转换提交记录数据
|
||||
const transformSubmitRecords = (submitList) => {
|
||||
if (!Array.isArray(submitList) || submitList.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return submitList.map(item => {
|
||||
// 处理附件
|
||||
let attachments = [];
|
||||
if (item.attaches) {
|
||||
try {
|
||||
// 如果 attaches 是字符串,尝试解析
|
||||
const attachData = typeof item.attaches === 'string' ? JSON.parse(item.attaches) : item.attaches;
|
||||
if (Array.isArray(attachData)) {
|
||||
attachments = attachData.map(att => {
|
||||
// 根据文件扩展名判断类型
|
||||
const fileName = att.name || att.fileName || '';
|
||||
const filePath = att.path || att.url || att.filePath || '';
|
||||
const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(fileName);
|
||||
|
||||
return {
|
||||
type: isImage ? 'image' : 'file',
|
||||
name: fileName,
|
||||
path: filePath
|
||||
};
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析附件数据失败:', e);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: item.id || '',
|
||||
userName: item.userName || '',
|
||||
userAvatar: item.userAvatar || '',
|
||||
time: formatTimeToChinese(item.createTime) || '',
|
||||
content: item.remark || item.description || item.taskDescription || '', // 如果没有提交内容,可能显示任务描述
|
||||
progress: null, // API 返回的数据中没有进度字段
|
||||
attachments: attachments,
|
||||
showDelayBtn: false, // 根据业务需求决定是否显示
|
||||
canEdit: true // 根据业务需求决定是否可以编辑
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// 任务数据
|
||||
const task = ref({
|
||||
|
||||
|
|
@ -308,13 +471,59 @@ const applyDelay = () => {
|
|||
});
|
||||
};
|
||||
|
||||
// 加载任务数据(模拟)
|
||||
const loadTaskData = (taskId) => {
|
||||
// 这里可以根据 taskId 从 API 加载任务数据
|
||||
// 暂时使用模拟数据
|
||||
if (taskId) {
|
||||
// 可以根据 taskId 加载不同的任务数据
|
||||
console.log('加载任务数据:', taskId);
|
||||
// 加载任务数据
|
||||
const loadTaskData = async (taskId) => {
|
||||
if (!taskId) {
|
||||
uni.showToast({
|
||||
title: '任务ID不能为空',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 显示加载提示
|
||||
uni.showLoading({
|
||||
title: '加载中...'
|
||||
});
|
||||
|
||||
// 调用 API 获取任务详情
|
||||
const res = await getTaskDetail(taskId);
|
||||
console.log('任务详情数据:', res);
|
||||
|
||||
// 转换数据格式
|
||||
const taskStatus = res.status !== undefined ? res.status : null;
|
||||
const expireTime = res.expireTime || null;
|
||||
const statusTags = getStatusTags(taskStatus, expireTime);
|
||||
|
||||
// 转换提交记录
|
||||
const submitRecords = transformSubmitRecords(res.submitList || []);
|
||||
|
||||
// 更新任务数据
|
||||
task.value = {
|
||||
id: res.id || taskId,
|
||||
name: res.description || '任务名称',
|
||||
project: res.projectName || '',
|
||||
statusTags: statusTags,
|
||||
deadline: expireTime ? expireTime : '无',
|
||||
creator: res.createName || '',
|
||||
creatorAvatar: res.createAvatar || '',
|
||||
responsible: getOwnerNames(res.memberList || []),
|
||||
publishTime: res.createTime ? formatTimeToChinese(res.createTime) : '',
|
||||
content: res.description || '',
|
||||
submitRecords: submitRecords,
|
||||
// 保存原始数据,供其他功能使用
|
||||
rawData: res
|
||||
};
|
||||
|
||||
uni.hideLoading();
|
||||
} catch (err) {
|
||||
console.error('加载任务详情失败:', err);
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '加载任务详情失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -323,10 +532,10 @@ onLoad((options) => {
|
|||
const taskId = options.id || options.taskId;
|
||||
if (taskId) {
|
||||
task.value.id = taskId;
|
||||
// 优先从 API 加载数据
|
||||
loadTaskData(taskId);
|
||||
}
|
||||
|
||||
// 从 Pinia store 获取任务详情数据
|
||||
} else {
|
||||
// 如果没有 taskId,尝试从 Pinia store 获取任务详情数据(兼容旧逻辑)
|
||||
const taskStore = useTaskStore();
|
||||
const storedTask = taskStore.getTaskDetail;
|
||||
if (storedTask) {
|
||||
|
|
@ -334,8 +543,15 @@ onLoad((options) => {
|
|||
...task.value,
|
||||
...storedTask
|
||||
};
|
||||
// 清除 store 中的数据(因为已经使用完毕)
|
||||
// taskStore.clearTaskDetail();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '缺少任务ID',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -596,6 +812,29 @@ onShow(() => {
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-value-with-avatar {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.creator-avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user