接口获取任务详细
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>
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<text class="info-label">创建人:</text>
|
<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>
|
||||||
<view class="info-item">
|
<view class="info-item">
|
||||||
<text class="info-label">负责人:</text>
|
<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="submit-record-card" v-for="(record, index) in task.submitRecords" :key="index">
|
||||||
<view class="record-header">
|
<view class="record-header">
|
||||||
<view class="user-info">
|
<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>
|
<text class="user-name">{{ record.userName }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="record-header-right">
|
<view class="record-header-right">
|
||||||
|
|
@ -150,6 +164,7 @@ import { ref, onMounted, } from 'vue';
|
||||||
import { onLoad,onShow } from '@dcloudio/uni-app';
|
import { onLoad,onShow } from '@dcloudio/uni-app';
|
||||||
import { getStatusFromTagText, getTaskStatusType, getTaskStatusStyle } from '@/utils/taskConfig.js';
|
import { getStatusFromTagText, getTaskStatusType, getTaskStatusStyle } from '@/utils/taskConfig.js';
|
||||||
import { useTaskStore } from '@/store/task';
|
import { useTaskStore } from '@/store/task';
|
||||||
|
import { getTaskDetail } from '@/common/api.js';
|
||||||
|
|
||||||
// 当前激活的标签
|
// 当前激活的标签
|
||||||
const activeTab = ref('info');
|
const activeTab = ref('info');
|
||||||
|
|
@ -157,10 +172,12 @@ const showMenuIndex = ref(-1);
|
||||||
|
|
||||||
// 格式化时间为中文格式:年月日星期几时分秒
|
// 格式化时间为中文格式:年月日星期几时分秒
|
||||||
const formatTimeToChinese = (date) => {
|
const formatTimeToChinese = (date) => {
|
||||||
|
if (!date) return '';
|
||||||
if (typeof date === 'string') {
|
if (typeof date === 'string') {
|
||||||
// 如果是字符串,尝试解析
|
// 如果是字符串,尝试解析
|
||||||
date = new Date(date);
|
date = new Date(date);
|
||||||
}
|
}
|
||||||
|
if (isNaN(date.getTime())) return '';
|
||||||
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
|
@ -173,6 +190,152 @@ const formatTimeToChinese = (date) => {
|
||||||
return `${year}年${month}月${day}日 ${weekday} ${hour}:${minute}:${second}`;
|
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({
|
const task = ref({
|
||||||
|
|
||||||
|
|
@ -308,13 +471,59 @@ const applyDelay = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载任务数据(模拟)
|
// 加载任务数据
|
||||||
const loadTaskData = (taskId) => {
|
const loadTaskData = async (taskId) => {
|
||||||
// 这里可以根据 taskId 从 API 加载任务数据
|
if (!taskId) {
|
||||||
// 暂时使用模拟数据
|
uni.showToast({
|
||||||
if (taskId) {
|
title: '任务ID不能为空',
|
||||||
// 可以根据 taskId 加载不同的任务数据
|
icon: 'none'
|
||||||
console.log('加载任务数据:', taskId);
|
});
|
||||||
|
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;
|
const taskId = options.id || options.taskId;
|
||||||
if (taskId) {
|
if (taskId) {
|
||||||
task.value.id = taskId;
|
task.value.id = taskId;
|
||||||
|
// 优先从 API 加载数据
|
||||||
loadTaskData(taskId);
|
loadTaskData(taskId);
|
||||||
}
|
} else {
|
||||||
|
// 如果没有 taskId,尝试从 Pinia store 获取任务详情数据(兼容旧逻辑)
|
||||||
// 从 Pinia store 获取任务详情数据
|
|
||||||
const taskStore = useTaskStore();
|
const taskStore = useTaskStore();
|
||||||
const storedTask = taskStore.getTaskDetail;
|
const storedTask = taskStore.getTaskDetail;
|
||||||
if (storedTask) {
|
if (storedTask) {
|
||||||
|
|
@ -334,8 +543,15 @@ onLoad((options) => {
|
||||||
...task.value,
|
...task.value,
|
||||||
...storedTask
|
...storedTask
|
||||||
};
|
};
|
||||||
// 清除 store 中的数据(因为已经使用完毕)
|
} else {
|
||||||
// taskStore.clearTaskDetail();
|
uni.showToast({
|
||||||
|
title: '缺少任务ID',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateBack();
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -596,6 +812,29 @@ onShow(() => {
|
||||||
flex-shrink: 0;
|
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 {
|
.user-name {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user