Files
im-uniapp/pages/workbench/task/components/TaskList.vue
砂糖 8ebdb221c0 feat(任务): 完善任务验收流程和状态管理
- 在任务列表组件中添加验收按钮选项
- 根据任务类型区分验收状态(1表示待验收,2表示已完成)
- 更新任务状态显示文本为更清晰的描述
- 移除任务页面图标的固定颜色
- 修复更新检查中的APK下载链接问题
- 更新版本记录至5.1.1
2025-11-11 10:33:15 +08:00

401 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="task-list-container">
<!-- 任务列表 -->
<view class="task-list">
<uni-swipe-action>
<uni-swipe-action-item
v-for="(task, index) in taskList"
:key="task.taskId"
:right-options="getSwipeOptions(task)"
@click="handleSwipeClick($event, index)"
>
<view
class="task-item"
@click="handleTaskClick(task)"
>
<!-- 任务完成checkbox -->
<view v-if="config.showCheckbox && task.status === 0" class="task-checkbox">
<view v-if="task.state === 0" class="checkbox-container" @click.stop="handleTaskComplete(task)">
<view
class="custom-checkbox"
:class="{ 'checked': checkboxStates[task.taskId] }"
>
<uni-icons
v-if="checkboxStates[task.taskId]"
type="checkmarkempty"
size="16"
color="#fff"
></uni-icons>
</view>
</view>
<view v-else-if="task.state === 1" class="checkbox-container">
<uni-icons type="checkmarkempty" size="20" color="#999"></uni-icons>
</view>
<view v-else-if="task.state === 2" class="checkbox-container">
<uni-icons type="checkmarkempty" size="20" color="#52c41a"></uni-icons>
</view>
<view v-else class="checkbox-container">
<view class="custom-checkbox disabled">
<uni-icons type="checkmarkempty" size="16" color="#999"></uni-icons>
</view>
</view>
</view>
<!-- 任务内容 -->
<view class="task-content">
<view class="task-title" :class="{ 'single-line': isSingleLine(task.taskTitle) }">{{ task.taskTitle || '未命名任务' }}</view>
<view class="task-status" :class="getStatusClass(task.state)">
{{ getStatusText(task.state) }}
</view>
</view>
<!-- 置顶标识 -->
<view v-if="task.ownRank === 1" class="top-badge">
<uni-icons type="arrow-up" size="12" color="#007aff"></uni-icons>
</view>
</view>
</uni-swipe-action-item>
</uni-swipe-action>
</view>
<!-- 空状态 -->
<view v-if="taskList.length === 0 && !loading" class="empty-state">
<u-empty :text="config.emptyText || '暂无任务'" mode="list"></u-empty>
</view>
<!-- 加载更多 -->
<u-load-more
:status="loadMoreStatus"
@loadmore="$emit('loadMore')"
></u-load-more>
</view>
</template>
<script>
export default {
name: 'TaskList',
props: {
// 任务列表数据
taskList: {
type: Array,
default: () => []
},
// 加载状态
loading: {
type: Boolean,
default: false
},
// 加载更多状态
loadMoreStatus: {
type: String,
default: 'more' // more, loading, noMore
},
// 配置对象
config: {
type: Object,
default: () => ({
showCheckbox: true, // 是否显示checkbox
canComplete: true, // 是否可以完成任务
canDelete: true, // 是否可以删除任务
canTop: true, // 是否可以置顶任务
emptyText: '暂无任务', // 空状态文本
detailPage: '/pages/workbench/task/reportTaskDetail' // 详情页面路径
})
}
},
data() {
return {
checkboxStates: {} // 存储checkbox的状态
}
},
methods: {
// 获取左划操作选项
getSwipeOptions(task) {
const options = []
// 置顶功能
if (this.config.canTop) {
if (task.ownRank === 1) {
// 已置顶,显示取消置顶
options.push({
text: '取消置顶',
style: {
backgroundColor: '#999',
color: '#fff'
}
})
} else {
// 未置顶,显示置顶
options.push({
text: '置顶',
style: {
backgroundColor: '#007aff',
color: '#fff'
}
})
}
}
// 删除功能
if (this.config.canDelete) {
options.push({
text: '删除',
style: {
backgroundColor: '#ff4757',
color: '#fff'
}
})
if (task.state !== 2) {
options.push({
text: '验收',
style: {
backgroundColor: '#00b300',
color: '#fff'
}
})
}
}
return options
},
// 处理左划操作点击
handleSwipeClick(e, index) {
const { content, position } = e
if (!content) {
console.error('Invalid swipe event:', e)
return
}
const task = this.taskList[index]
if (!task) {
console.error('Task not found at index:', index)
return
}
if (content.text === '置顶') {
this.$emit('setTaskTop', task, 1)
} else if (content.text === '取消置顶') {
this.$emit('setTaskTop', task, 0)
} else if (content.text === '删除') {
this.$emit('deleteTask', task)
} else if (content.text == '验收') {
this.$emit('completeTask', task)
}
},
// 处理任务完成
handleTaskComplete(task) {
if (!this.config.canComplete) return
console.log('handleTaskComplete called, task:', task)
console.log('task.status:', task.status, 'task.state:', task.state)
// 只有单任务status为0且状态为0进行中的任务才能完成
if (task.status !== 0 && (task.state == 0 || task.state == 1)) {
console.log('Task cannot be completed, status:', task.status, 'state:', task.state)
uni.showModal({
title: '提示',
content: '该任务当前状态无法完成',
showCancel: false
})
return
}
// 先设置checkbox为选中状态
this.$set(this.checkboxStates, task.taskId, true)
console.log('Showing confirmation modal')
uni.showModal({
title: '确认完成',
content: `确定要将任务"${task.taskTitle}"标记为完成吗?`,
success: (res) => {
if (res.confirm) {
this.$emit('completeTask', task)
// 清除checkbox状态
this.$set(this.checkboxStates, task.taskId, false)
} else {
// 用户取消重置checkbox状态为false
console.log('用户取消重置checkbox状态')
this.$set(this.checkboxStates, task.taskId, false)
console.log('checkbox状态已重置:', this.checkboxStates[task.taskId])
}
}
})
},
// 跳转到任务详情页面
handleTaskClick(task) {
this.$emit('taskClick', task)
},
// 获取状态文本
getStatusText(state) {
const statusMap = {
15: '申请延期',
0: '进行中',
1: '待验收',
2: '已完成'
}
return statusMap[state] || '未知状态'
},
// 获取状态样式类
getStatusClass(state) {
const classMap = {
15: 'status-pending',
0: 'status-processing',
1: 'status-waiting',
2: 'status-completed'
}
return classMap[state] || 'status-unknown'
},
// 判断是否为单行文字
isSingleLine(text) {
if (!text) return true
// 估算文字长度假设每个中文字符约等于2个英文字符
const estimatedLength = text.replace(/[\u4e00-\u9fa5]/g, 'aa').length
// 如果估算长度小于等于20个字符认为是单行
return estimatedLength <= 20
}
}
}
</script>
<style lang="scss" scoped>
.task-list-container {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 120rpx;
}
.task-list {
padding: 20rpx;
}
.task-item {
box-sizing: border-box;
padding: 24rpx;
display: flex;
align-items: center;
position: relative;
transition: all 0.3s ease;
}
.task-checkbox {
margin-right: 20rpx;
flex-shrink: 0;
}
.checkbox-container {
display: flex;
align-items: center;
justify-content: center;
width: 40rpx;
height: 40rpx;
cursor: pointer;
}
.custom-checkbox {
width: 36rpx;
height: 36rpx;
border: 2rpx solid #ddd;
border-radius: 6rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
transition: all 0.2s ease;
&.checked {
background-color: $im-primary;
border-color: $im-primary;
}
&.disabled {
background-color: #f5f5f5;
border-color: #ddd;
}
}
.task-content {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
}
.task-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
flex: 1;
margin-right: 20rpx;
line-height: 1.4;
height: 88rpx; /* 固定高度 */
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
/* 单行文字时垂直居中 */
&.single-line {
display: flex;
flex-direction: column;
justify-content: center;
-webkit-line-clamp: 1;
}
}
.task-status {
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 24rpx;
font-weight: 500;
box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1);
&.status-pending {
background-color: #fff2e8;
color: #fa8c16;
}
&.status-processing {
background-color: #e6f7ff;
color: #1890ff;
}
&.status-waiting {
background-color: #fff7e6;
color: #fa8c16;
}
&.status-completed {
background-color: #f6ffed;
color: #52c41a;
}
}
.top-badge {
position: absolute;
top: 8rpx;
right: 8rpx;
background-color: rgba($im-primary, 0.1);
border: 1rpx solid $im-primary;
border-radius: 50%;
width: 28rpx;
height: 28rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 6rpx rgba($im-primary, 0.2);
}
.empty-state {
padding: 100rpx 20rpx;
text-align: center;
}
</style>