<template>
|
<view class="content">
|
<view class="card">
|
<text class="title">项目详情</text>
|
<view class="info-row">
|
<text class="label">节点ID:</text><text class="value">{{ id }}</text>
|
</view>
|
<view class="info-row" v-if="name">
|
<text class="label">名称:</text><text class="value">{{ name }}</text>
|
</view>
|
</view>
|
<view class="card">
|
<text class="title">任务统计</text>
|
<view class="stats">
|
<view class="stats-item" @click="changeType('completed')">
|
<text class="stats-num text-green">{{ stats.completed }}</text>
|
<text class="stats-label">已完成</text>
|
</view>
|
<view class="stats-item" @click="changeType('pending')">
|
<text class="stats-num text-blue">{{ stats.pending }}</text>
|
<text class="stats-label">待处理</text>
|
</view>
|
<view class="stats-item" @click="changeType('skipped')">
|
<text class="stats-num text-gray">{{ stats.skipped }}</text>
|
<text class="stats-label">跳过</text>
|
</view>
|
<view class="stats-item" @click="changeType('rejected')">
|
<text class="stats-num text-red">{{ stats.rejected }}</text>
|
<text class="stats-label">驳回</text>
|
</view>
|
<view class="stats-item" @click="changeType('tolerated')">
|
<text class="stats-num text-orange">{{ stats.tolerated }}</text>
|
<text class="stats-label">容缺</text>
|
</view>
|
</view>
|
<view class="actions">
|
<button class="btn" @click="goBack">返回</button>
|
</view>
|
</view>
|
<view class="card">
|
<text class="title">任务列表</text>
|
<view class="tabs">
|
<view class="tab" :class="{ active: selectedType === 'completed' }" @click="changeType('completed')">已完成</view>
|
<view class="tab" :class="{ active: selectedType === 'pending' }" @click="changeType('pending')">待处理</view>
|
<view class="tab" :class="{ active: selectedType === 'skipped' }" @click="changeType('skipped')">跳过</view>
|
<view class="tab" :class="{ active: selectedType === 'rejected' }" @click="changeType('rejected')">驳回</view>
|
<view class="tab" :class="{ active: selectedType === 'tolerated' }" @click="changeType('tolerated')">容缺</view>
|
</view>
|
<view class="list-container">
|
<view v-if="currentList.length === 0" class="empty">暂无该类任务</view>
|
<view v-else class="task-item" v-for="t in currentList" :key="t.id">
|
<view class="task-left">
|
<text class="task-title">{{ t.title }}</text>
|
<text class="task-meta">{{ t.due }} · {{ t.assignee }}</text>
|
</view>
|
<view class="task-right">
|
<button class="proc-btn" v-if="selectedType === 'pending'" @click.stop="processTask(t)">跳过</button>
|
<button class="proc-btn" v-if="selectedType === 'pending'" @click.stop="processTask(t)">转办</button>
|
<button class="proc-btn" v-if="selectedType === 'pending'" @click.stop="processTask(t)">容缺</button>
|
<button class="proc-btn" v-if="selectedType === 'pending'" @click.stop="processTask(t)">处理</button>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
export default {
|
name: 'ProjectDetail',
|
data() {
|
return {
|
id: '',
|
name: '',
|
stats: { completed: 0, pending: 0, skipped: 0, rejected: 0, tolerated: 0 },
|
selectedType: 'pending',
|
tasks: { completed: [], pending: [], skipped: [], rejected: [], tolerated: [] }
|
}
|
},
|
onLoad(query) {
|
this.id = query.id || ''
|
this.name = query.name || ''
|
this.fetchStats()
|
this.fetchTasks()
|
},
|
methods: {
|
fetchStats() {
|
const base = Number(this.id) || 0
|
const completed = (base * 3) % 20 + 10
|
const pending = (base * 5) % 12 + 2
|
const skipped = (base * 7) % 6
|
const rejected = (base * 11) % 5
|
const tolerated = (base * 13) % 4
|
this.stats = { completed, pending, skipped, rejected, tolerated }
|
},
|
fetchTasks() {
|
const base = Number(this.id) || 0
|
const gen = (count, type) => {
|
const mapLabel = { completed: '已完成', pending: '待处理', skipped: '跳过', rejected: '驳回', tolerated: '容缺' }
|
const res = []
|
for (let i = 0; i < count; i++) {
|
const idx = i + 1
|
const id = base * 1000 + idx
|
const title = `${mapLabel[type]}任务${idx}`
|
const assignee = ['张三', '李四', '王五', '赵六'][idx % 4]
|
const due = `2025-12-${String((base + idx) % 28 + 1).padStart(2, '0')}`
|
res.push({ id, title, assignee, due, statusLabel: mapLabel[type] })
|
}
|
return res
|
}
|
this.tasks.completed = gen(this.stats.completed, 'completed')
|
this.tasks.pending = gen(this.stats.pending, 'pending')
|
this.tasks.skipped = gen(this.stats.skipped, 'skipped')
|
this.tasks.rejected = gen(this.stats.rejected, 'rejected')
|
this.tasks.tolerated = gen(this.stats.tolerated, 'tolerated')
|
},
|
changeType(type) {
|
this.selectedType = type
|
},
|
processTask(t) {
|
const url = `/subpackage/manager/task-process?id=${t.id}&pid=${this.id}`
|
uni.navigateTo({ url })
|
},
|
goBack() {
|
uni.navigateBack()
|
}
|
}
|
,
|
computed: {
|
currentList() {
|
return this.tasks[this.selectedType] || []
|
}
|
}
|
}
|
</script>
|
|
<style scoped>
|
.content { width: 100%; min-height: 100vh; background-color: #f5f7fa; padding-bottom: 120rpx; }
|
.card { background-color: #fff; margin: 20rpx; border-radius: 16rpx; padding: 24rpx; box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05); }
|
.title { font-size: 32rpx; font-weight: 600; color: #333; margin-bottom: 16rpx; }
|
.info-row { display: flex; margin: 10rpx 0; }
|
.label { width: 160rpx; font-size: 28rpx; color: #666; }
|
.value { flex: 1; font-size: 28rpx; color: #333; }
|
.stats { display: flex; justify-content: space-around; padding: 20rpx 0; }
|
.stats-item { display: flex; flex-direction: column; align-items: center; }
|
.stats-num { font-size: 40rpx; font-weight: 700; margin-bottom: 8rpx; }
|
.stats-label { font-size: 24rpx; color: #666; }
|
.text-blue { color: #1E88E5; }
|
.text-green { color: #26A69A; }
|
.text-red { color: #EE6666; }
|
.text-orange { color: #FF9800; }
|
.text-gray { color: #9E9E9E; }
|
.actions { margin-top: 20rpx; display: flex; }
|
.btn { flex: 1; height: 72rpx; line-height: 72rpx; border-radius: 12rpx; font-size: 28rpx; border: none; background-color: #1E88E5; color: #fff; }
|
.tabs { display: flex; padding: 10rpx; gap: 10rpx; }
|
.tab { padding: 12rpx 20rpx; border-radius: 24rpx; background: #f0f3f7; font-size: 26rpx; color: #333; }
|
.tab.active { background: #E3F2FD; color: #1E88E5; }
|
.list-container { margin-top: 10rpx; }
|
.task-item { display: flex; align-items: center; justify-content: space-between; padding: 16rpx 0; border-bottom: 1rpx solid #eee; }
|
.task-left { display: flex; flex-direction: column; }
|
.task-title { font-size: 28rpx; color: #333; }
|
.task-meta { font-size: 24rpx; color: #999; margin-top: 6rpx; }
|
.task-status { font-size: 24rpx; color: #1E88E5; }
|
.task-right { display: flex; align-items: center; gap: 16rpx; }
|
.proc-btn { height: 60rpx; line-height: 60rpx; padding: 0 20rpx; border-radius: 10rpx; font-size: 26rpx; color: #fff; background: #26A69A; border: none; }
|
.empty { font-size: 26rpx; color: #999; padding: 10rpx 0; }
|
</style>
|