Initial commit of akmon project
This commit is contained in:
868
pages/ec/tasks/list.uvue
Normal file
868
pages/ec/tasks/list.uvue
Normal file
@@ -0,0 +1,868 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user