869 lines
19 KiB
Plaintext
869 lines
19 KiB
Plaintext
<template>
|
||
<view class="task-management">
|
||
<view class="header">
|
||
<text class="title">护理任务</text>
|
||
<button class="add-btn" @click="addNewTask">
|
||
<text class="btn-text">➕ 新建</text>
|
||
</button>
|
||
</view>
|
||
|
||
<!-- 任务统计 -->
|
||
<view class="task-stats">
|
||
<view class="stat-item">
|
||
<text class="stat-number">{{ taskStats.pending }}</text>
|
||
<text class="stat-label">待处理</text>
|
||
</view>
|
||
<view class="stat-item">
|
||
<text class="stat-number">{{ taskStats.in_progress }}</text>
|
||
<text class="stat-label">进行中</text>
|
||
</view>
|
||
<view class="stat-item">
|
||
<text class="stat-number">{{ taskStats.completed }}</text>
|
||
<text class="stat-label">已完成</text>
|
||
</view>
|
||
<view class="stat-item">
|
||
<text class="stat-number">{{ taskStats.overdue }}</text>
|
||
<text class="stat-label">已逾期</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 筛选器 -->
|
||
<view class="filter-section">
|
||
<scroll-view class="filter-scroll" direction="horizontal" :show-scrollbar="false">
|
||
<view class="filter-item" :class="{ active: selectedStatus === 'all' }" @click="filterByStatus('all')">
|
||
全部
|
||
</view>
|
||
<view class="filter-item" :class="{ active: selectedStatus === 'pending' }" @click="filterByStatus('pending')">
|
||
待处理
|
||
</view>
|
||
<view class="filter-item" :class="{ active: selectedStatus === 'in_progress' }" @click="filterByStatus('in_progress')">
|
||
进行中
|
||
</view>
|
||
<view class="filter-item" :class="{ active: selectedStatus === 'completed' }" @click="filterByStatus('completed')">
|
||
已完成
|
||
</view>
|
||
<view class="filter-item" :class="{ active: selectedPriority === 'urgent' }" @click="filterByPriority('urgent')">
|
||
紧急任务
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<!-- 任务列表 -->
|
||
<view class="tasks-section">
|
||
<scroll-view class="tasks-list" direction="vertical" :refresher-enabled="true"
|
||
:refresher-triggered="isRefreshing" @refresherrefresh="refreshTasks">
|
||
<view class="task-card" v-for="task in filteredTasks" :key="task.id"
|
||
:class="getTaskCardClass(task)" @click="viewTaskDetail(task)">
|
||
<view class="task-header">
|
||
<view class="task-priority" :class="task.priority">
|
||
<text class="priority-text">{{ getPriorityText(task.priority) }}</text>
|
||
</view>
|
||
<view class="task-status" :class="task.status">
|
||
<text class="status-text">{{ getTaskStatusText(task.status) }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="task-content">
|
||
<text class="task-title">{{ task.title }}</text>
|
||
<view class="task-info">
|
||
<view class="info-item">
|
||
<text class="info-icon">👤</text>
|
||
<text class="info-text">{{ task.elder_name || '未分配' }}</text>
|
||
</view>
|
||
<view class="info-item">
|
||
<text class="info-icon">🕐</text>
|
||
<text class="info-text">{{ formatDateTime(task.scheduled_time) }}</text>
|
||
</view>
|
||
<view class="info-item" v-if="task.assigned_to_name">
|
||
<text class="info-icon">👩⚕️</text>
|
||
<text class="info-text">{{ task.assigned_to_name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="task-actions">
|
||
<button class="action-btn" v-if="task.status === 'pending'" @click.stop="startTask(task)">
|
||
<text class="btn-text">开始</text>
|
||
</button>
|
||
<button class="action-btn" v-if="task.status === 'in_progress'" @click.stop="completeTask(task)">
|
||
<text class="btn-text">完成</text>
|
||
</button>
|
||
<button class="action-btn secondary" @click.stop="editTask(task)">
|
||
<text class="btn-text">编辑</text>
|
||
</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view class="empty-state" v-if="filteredTasks.length === 0 && !isLoading">
|
||
<text class="empty-icon">📋</text>
|
||
<text class="empty-title">暂无任务</text>
|
||
<text class="empty-description">{{ getEmptyStateText() }}</text>
|
||
<button class="empty-action" @click="addNewTask">创建第一个任务</button>
|
||
</view>
|
||
|
||
<!-- 加载状态 -->
|
||
<view class="loading-state" v-if="isLoading">
|
||
<text class="loading-text">加载中...</text>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script lang="uts">
|
||
import { CareTask, TaskStats } from '../types.uts'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
tasks: [] as CareTask[],
|
||
taskStats: {
|
||
pending: 0,
|
||
in_progress: 0,
|
||
completed: 0,
|
||
overdue: 0
|
||
} as TaskStats,
|
||
selectedStatus: 'all',
|
||
selectedPriority: '',
|
||
isLoading: false,
|
||
isRefreshing: false
|
||
}
|
||
},
|
||
computed: {
|
||
filteredTasks(): CareTask[] {
|
||
let filtered = this.tasks
|
||
|
||
// 按状态筛选
|
||
if (this.selectedStatus !== 'all') {
|
||
filtered = filtered.filter(task => task.status === this.selectedStatus)
|
||
}
|
||
|
||
// 按优先级筛选
|
||
if (this.selectedPriority === 'urgent') {
|
||
filtered = filtered.filter(task => task.priority === 'urgent' || task.priority === 'high')
|
||
}
|
||
|
||
// 按时间排序,逾期的优先显示
|
||
return filtered.sort((a, b) => {
|
||
const now = new Date()
|
||
const aScheduled = new Date(a.scheduled_time)
|
||
const bScheduled = new Date(b.scheduled_time)
|
||
|
||
// 逾期任务优先
|
||
const aOverdue = aScheduled < now && a.status !== 'completed'
|
||
const bOverdue = bScheduled < now && b.status !== 'completed'
|
||
|
||
if (aOverdue && !bOverdue) return -1
|
||
if (!aOverdue && bOverdue) return 1
|
||
|
||
// 按计划时间排序
|
||
return aScheduled.getTime() - bScheduled.getTime()
|
||
})
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.loadTasks()
|
||
},
|
||
onShow() {
|
||
this.loadTasks()
|
||
},
|
||
methods: {
|
||
async loadTasks() {
|
||
this.isLoading = true
|
||
|
||
try {
|
||
const [tasksResult, statsResult] = await Promise.all([
|
||
supa.executeAs('care_tasks', {}),
|
||
supa.executeAs('task_stats', {})
|
||
])
|
||
|
||
if (tasksResult.success) {
|
||
this.tasks = tasksResult.data as CareTask[]
|
||
}
|
||
|
||
if (statsResult.success && statsResult.data.length > 0) {
|
||
this.taskStats = statsResult.data[0] as TaskStats
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('加载任务失败:', error)
|
||
uni.showToast({
|
||
title: '加载失败',
|
||
icon: 'error'
|
||
})
|
||
} finally {
|
||
this.isLoading = false
|
||
}
|
||
},
|
||
|
||
async refreshTasks() {
|
||
this.isRefreshing = true
|
||
await this.loadTasks()
|
||
this.isRefreshing = false
|
||
},
|
||
|
||
filterByStatus(status: string) {
|
||
this.selectedStatus = status
|
||
this.selectedPriority = ''
|
||
},
|
||
|
||
filterByPriority(priority: string) {
|
||
this.selectedPriority = priority
|
||
this.selectedStatus = 'all'
|
||
},
|
||
|
||
async startTask(task: CareTask) {
|
||
try {
|
||
const result = await supa.executeAs('update_task_status', {
|
||
task_id: task.id,
|
||
status: 'in_progress',
|
||
started_at: new Date().toISOString()
|
||
})
|
||
|
||
if (result.success) {
|
||
uni.showToast({
|
||
title: '任务已开始',
|
||
icon: 'success'
|
||
})
|
||
this.loadTasks()
|
||
}
|
||
} catch (error) {
|
||
console.error('开始任务失败:', error)
|
||
uni.showToast({
|
||
title: '操作失败',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
},
|
||
|
||
async completeTask(task: CareTask) {
|
||
try {
|
||
const result = await supa.executeAs('update_task_status', {
|
||
task_id: task.id,
|
||
status: 'completed',
|
||
completed_at: new Date().toISOString()
|
||
})
|
||
|
||
if (result.success) {
|
||
uni.showToast({
|
||
title: '任务已完成',
|
||
icon: 'success'
|
||
})
|
||
this.loadTasks()
|
||
}
|
||
} catch (error) {
|
||
console.error('完成任务失败:', error)
|
||
uni.showToast({
|
||
title: '操作失败',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
},
|
||
|
||
addNewTask() {
|
||
uni.navigateTo({
|
||
url: '/pages/ec/tasks/form'
|
||
})
|
||
},
|
||
|
||
editTask(task: CareTask) {
|
||
uni.navigateTo({
|
||
url: `/pages/ec/tasks/form?id=${task.id}`
|
||
})
|
||
},
|
||
|
||
viewTaskDetail(task: CareTask) {
|
||
uni.navigateTo({
|
||
url: `/pages/ec/tasks/detail?id=${task.id}`
|
||
})
|
||
},
|
||
|
||
getTaskCardClass(task: CareTask): string {
|
||
const classes = ['task-card']
|
||
|
||
if (task.status === 'overdue' || this.isTaskOverdue(task)) {
|
||
classes.push('overdue')
|
||
}
|
||
|
||
if (task.priority === 'urgent') {
|
||
classes.push('urgent')
|
||
}
|
||
|
||
return classes.join(' ')
|
||
},
|
||
|
||
isTaskOverdue(task: CareTask): boolean {
|
||
const now = new Date()
|
||
const scheduled = new Date(task.scheduled_time)
|
||
return scheduled < now && task.status !== 'completed'
|
||
},
|
||
|
||
getPriorityText(priority: string): string {
|
||
const priorityMap = {
|
||
'low': '低',
|
||
'normal': '普通',
|
||
'high': '高',
|
||
'urgent': '紧急'
|
||
}
|
||
return priorityMap[priority] || '普通'
|
||
},
|
||
|
||
getTaskStatusText(status: string): string {
|
||
const statusMap = {
|
||
'pending': '待处理',
|
||
'in_progress': '进行中',
|
||
'completed': '已完成',
|
||
'cancelled': '已取消',
|
||
'overdue': '已逾期'
|
||
}
|
||
return statusMap[status] || '未知'
|
||
},
|
||
|
||
formatDateTime(timestamp: string): string {
|
||
if (!timestamp) return ''
|
||
|
||
const date = new Date(timestamp)
|
||
const now = new Date()
|
||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
||
const taskDate = new Date(date.getFullYear(), date.getMonth(), date.getDate())
|
||
|
||
const time = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
|
||
|
||
if (taskDate.getTime() === today.getTime()) {
|
||
return `今天 ${time}`
|
||
} else if (taskDate.getTime() === today.getTime() - 24 * 60 * 60 * 1000) {
|
||
return `昨天 ${time}`
|
||
} else if (taskDate.getTime() === today.getTime() + 24 * 60 * 60 * 1000) {
|
||
return `明天 ${time}`
|
||
} else {
|
||
return `${date.getMonth() + 1}/${date.getDate()} ${time}`
|
||
}
|
||
},
|
||
|
||
getEmptyStateText(): string {
|
||
if (this.selectedStatus !== 'all') {
|
||
const statusMap = {
|
||
'pending': '没有待处理的任务',
|
||
'in_progress': '没有进行中的任务',
|
||
'completed': '没有已完成的任务'
|
||
}
|
||
return statusMap[this.selectedStatus] || '没有相关任务'
|
||
}
|
||
|
||
if (this.selectedPriority === 'urgent') {
|
||
return '没有紧急任务'
|
||
}
|
||
|
||
return '还没有创建任何任务'
|
||
}
|
||
}
|
||
}
|
||
const tasks = ref<Array<CareTask>>([])
|
||
const filteredTasks = ref<Array<CareTask>>([])
|
||
const selectedStatus = ref<string>('all')
|
||
const selectedPriority = ref<string>('all')
|
||
const isLoading = ref<boolean>(false)
|
||
const isRefreshing = ref<boolean>(false)
|
||
|
||
// 任务统计
|
||
const taskStats = ref({
|
||
pending: 0,
|
||
in_progress: 0,
|
||
completed: 0,
|
||
overdue: 0
|
||
})
|
||
|
||
// 加载任务数据
|
||
const loadTasks = async () => {
|
||
try {
|
||
isLoading.value = true
|
||
|
||
const result = await supa
|
||
.from('ec_care_tasks')
|
||
.select(`
|
||
id,
|
||
task_name,
|
||
elder_name,
|
||
scheduled_time,
|
||
status,
|
||
priority,
|
||
caregiver_name,
|
||
due_date,
|
||
created_at
|
||
`)
|
||
.order('scheduled_time', { ascending: true })
|
||
.executeAs<Array<CareTask>>()
|
||
|
||
if (result.error === null && result.data !== null) {
|
||
tasks.value = result.data
|
||
applyFilters()
|
||
updateTaskStats()
|
||
}
|
||
} catch (error) {
|
||
console.error('加载任务数据失败:', error)
|
||
} finally {
|
||
isLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 更新任务统计
|
||
const updateTaskStats = () => {
|
||
const now = new Date()
|
||
|
||
taskStats.value = {
|
||
pending: tasks.value.filter(task => task.status === 'pending').length,
|
||
in_progress: tasks.value.filter(task => task.status === 'in_progress').length,
|
||
completed: tasks.value.filter(task => task.status === 'completed').length,
|
||
overdue: tasks.value.filter(task => {
|
||
const dueDate = new Date(task.scheduled_time)
|
||
return task.status !== 'completed' && dueDate < now
|
||
}).length
|
||
}
|
||
}
|
||
|
||
// 应用筛选
|
||
const applyFilters = () => {
|
||
let filtered = tasks.value
|
||
|
||
// 状态筛选
|
||
if (selectedStatus.value !== 'all') {
|
||
filtered = filtered.filter(task => task.status === selectedStatus.value)
|
||
}
|
||
|
||
// 优先级筛选
|
||
if (selectedPriority.value === 'urgent') {
|
||
filtered = filtered.filter(task => task.priority === 'urgent')
|
||
}
|
||
|
||
filteredTasks.value = filtered
|
||
}
|
||
|
||
// 状态筛选
|
||
const filterByStatus = (status: string) => {
|
||
selectedStatus.value = status
|
||
selectedPriority.value = 'all' // 重置优先级筛选
|
||
applyFilters()
|
||
}
|
||
|
||
// 优先级筛选
|
||
const filterByPriority = (priority: string) => {
|
||
selectedPriority.value = priority
|
||
selectedStatus.value = 'all' // 重置状态筛选
|
||
applyFilters()
|
||
}
|
||
|
||
// 刷新任务
|
||
const refreshTasks = async () => {
|
||
isRefreshing.value = true
|
||
await loadTasks()
|
||
isRefreshing.value = false
|
||
}
|
||
|
||
// 获取优先级文本
|
||
const getPriorityText = (priority: string): string => {
|
||
switch (priority) {
|
||
case 'urgent': return '紧急'
|
||
case 'high': return '高'
|
||
case 'normal': return '普通'
|
||
case 'low': return '低'
|
||
default: return priority
|
||
}
|
||
}
|
||
|
||
// 获取任务卡片样式类
|
||
const getTaskCardClass = (task: CareTask): string => {
|
||
const classes = ['task-card']
|
||
|
||
// 优先级样式
|
||
if (task.priority === 'urgent') {
|
||
classes.push('urgent')
|
||
} else if (task.priority === 'high') {
|
||
classes.push('high-priority')
|
||
}
|
||
|
||
// 逾期样式
|
||
const now = new Date()
|
||
const dueDate = new Date(task.scheduled_time)
|
||
if (task.status !== 'completed' && dueDate < now) {
|
||
classes.push('overdue')
|
||
}
|
||
|
||
return classes.join(' ')
|
||
}
|
||
|
||
// 开始任务
|
||
const startTask = async (task: CareTask) => {
|
||
try {
|
||
await supa
|
||
.from('ec_care_tasks')
|
||
.update({
|
||
status: 'in_progress',
|
||
updated_at: new Date().toISOString()
|
||
})
|
||
.eq('id', task.id)
|
||
.executeAs<any>()
|
||
|
||
// 更新本地数据
|
||
task.status = 'in_progress'
|
||
updateTaskStats()
|
||
|
||
uni.showToast({
|
||
title: '任务已开始',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 导航到任务执行页面
|
||
uni.navigateTo({
|
||
url: `/pages/ec/tasks/execute?id=${task.id}`
|
||
})
|
||
} catch (error) {
|
||
console.error('开始任务失败:', error)
|
||
uni.showToast({
|
||
title: '操作失败',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 完成任务
|
||
const completeTask = async (task: CareTask) => {
|
||
try {
|
||
await supa
|
||
.from('ec_care_tasks')
|
||
.update({
|
||
status: 'completed',
|
||
updated_at: new Date().toISOString()
|
||
})
|
||
.eq('id', task.id)
|
||
.executeAs<any>()
|
||
|
||
// 更新本地数据
|
||
task.status = 'completed'
|
||
updateTaskStats()
|
||
|
||
uni.showToast({
|
||
title: '任务已完成',
|
||
icon: 'success'
|
||
})
|
||
} catch (error) {
|
||
console.error('完成任务失败:', error)
|
||
uni.showToast({
|
||
title: '操作失败',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 查看任务详情
|
||
const viewTaskDetail = (task: CareTask) => {
|
||
uni.navigateTo({
|
||
url: `/pages/ec/tasks/detail?id=${task.id}`
|
||
})
|
||
}
|
||
|
||
// 编辑任务
|
||
const editTask = (task: CareTask) => {
|
||
uni.navigateTo({
|
||
url: `/pages/ec/tasks/edit?id=${task.id}`
|
||
})
|
||
}
|
||
|
||
// 新建任务
|
||
const addNewTask = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/ec/tasks/add'
|
||
})
|
||
}
|
||
|
||
// 获取空状态文本
|
||
const getEmptyStateText = (): string => {
|
||
if (selectedStatus.value !== 'all') {
|
||
return `没有${getTaskStatusText(selectedStatus.value)}的任务`
|
||
}
|
||
if (selectedPriority.value === 'urgent') {
|
||
return '没有紧急任务'
|
||
}
|
||
return '还没有创建任何任务,点击下方按钮创建第一个任务'
|
||
}
|
||
|
||
// 生命周期
|
||
onMounted(() => {
|
||
loadTasks()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.task-management {
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 100vh;
|
||
background-color: #f5f5f5;
|
||
padding: 20px;
|
||
}
|
||
|
||
.header {
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.title {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.add-btn {
|
||
background-color: #1890ff;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 6px;
|
||
padding: 10px 16px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 任务统计 */
|
||
.task-stats {
|
||
display: flex;
|
||
flex-direction: row;
|
||
background-color: #fff;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.stat-item {
|
||
flex: 1;
|
||
text-align: center;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
color: #1890ff;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
/* 筛选器 */
|
||
.filter-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.filter-scroll {
|
||
height: 50px;
|
||
}
|
||
|
||
.filter-item {
|
||
display: inline-block;
|
||
padding: 8px 16px;
|
||
margin-right: 10px;
|
||
background-color: #fff;
|
||
border: 1px solid #d9d9d9;
|
||
border-radius: 20px;
|
||
font-size: 14px;
|
||
color: #666;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.filter-item.active {
|
||
background-color: #1890ff;
|
||
color: #fff;
|
||
border-color: #1890ff;
|
||
}
|
||
|
||
/* 任务列表 */
|
||
.tasks-section {
|
||
flex: 1;
|
||
}
|
||
|
||
.tasks-list {
|
||
height: 100%;
|
||
}
|
||
|
||
.task-card {
|
||
background-color: #fff;
|
||
border-radius: 8px;
|
||
padding: 16px;
|
||
margin-bottom: 12px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
border-left: 4px solid #d9d9d9;
|
||
}
|
||
|
||
.task-card.urgent {
|
||
border-left-color: #ff4d4f;
|
||
}
|
||
|
||
.task-card.high-priority {
|
||
border-left-color: #fa8c16;
|
||
}
|
||
|
||
.task-card.overdue {
|
||
background-color: #fff2f0;
|
||
border-left-color: #ff4d4f;
|
||
}
|
||
|
||
.task-header {
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.task-priority {
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.task-priority.urgent {
|
||
background-color: #ff4d4f;
|
||
color: #fff;
|
||
}
|
||
|
||
.task-priority.high {
|
||
background-color: #fa8c16;
|
||
color: #fff;
|
||
}
|
||
|
||
.task-priority.normal {
|
||
background-color: #1890ff;
|
||
color: #fff;
|
||
}
|
||
|
||
.task-priority.low {
|
||
background-color: #52c41a;
|
||
color: #fff;
|
||
}
|
||
|
||
.task-status {
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.task-status.pending {
|
||
background-color: #fff7e6;
|
||
color: #d48806;
|
||
}
|
||
|
||
.task-status.in_progress {
|
||
background-color: #e6f7ff;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.task-status.completed {
|
||
background-color: #f6ffed;
|
||
color: #52c41a;
|
||
}
|
||
|
||
.task-content {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.task-title {
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.task-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.info-item {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.info-icon {
|
||
margin-right: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.info-text {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.task-actions {
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 6px 12px;
|
||
border-radius: 4px;
|
||
border: none;
|
||
font-size: 12px;
|
||
margin-left: 8px;
|
||
background-color: #1890ff;
|
||
color: #fff;
|
||
}
|
||
|
||
.action-btn.secondary {
|
||
background-color: #fff;
|
||
color: #666;
|
||
border: 1px solid #d9d9d9;
|
||
}
|
||
|
||
/* 空状态 */
|
||
.empty-state {
|
||
text-align: center;
|
||
padding: 60px 20px;
|
||
}
|
||
|
||
.empty-icon {
|
||
font-size: 64px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.empty-title {
|
||
font-size: 18px;
|
||
color: #333;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.empty-description {
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.empty-action {
|
||
background-color: #1890ff;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 6px;
|
||
padding: 12px 24px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 加载状态 */
|
||
.loading-state {
|
||
text-align: center;
|
||
padding: 40px 20px;
|
||
}
|
||
|
||
.loading-text {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
</style>
|