任务管理0.6
This commit is contained in:
parent
1bd14c1e01
commit
04a897a22a
|
|
@ -467,171 +467,6 @@ onLoad((options) => {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.task-container {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.task-card {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.task-card:active {
|
||||
transform: scale(0.98);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
// 即将逾期卡片样式
|
||||
.task-card-imminent {
|
||||
border-left: 4px solid #ff9800;
|
||||
}
|
||||
|
||||
// 待完成卡片样式
|
||||
.task-card-pending {
|
||||
border-left: 4px solid #2885ff;
|
||||
}
|
||||
|
||||
// 已完成卡片样式
|
||||
.task-card-completed {
|
||||
border-left: 4px solid #909399;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
// 逾期卡片样式
|
||||
.task-card-overdue {
|
||||
background: linear-gradient(135deg, #fff5f5 0%, #ffe6e6 100%);
|
||||
border-left: 4px solid #f56c6c;
|
||||
box-shadow: 0 2px 12px rgba(255, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
.task-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.task-badge-wrapper {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.task-date-wrapper {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.task-date {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.task-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-project {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.task-description {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.task-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.task-owner {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.task-time-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-time {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.task-countdown {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.countdown-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.countdown-text {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.countdown-warning {
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
.countdown-primary {
|
||||
color: #2885ff;
|
||||
}
|
||||
|
||||
.countdown-error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.task-action {
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.load-more-tip {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.load-more-text {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
@import '@/styles/task-card.scss';
|
||||
</style>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,24 @@
|
|||
<view style="height: 5px;"></view>
|
||||
<img src="https://api.ccttiot.com/image-1763782244238.png" alt="" style="width: 20px !important; height: 20px !important;">
|
||||
</view>
|
||||
<view style="flex: 1;"></view>
|
||||
<view class="header-center">
|
||||
<view class="status-tabs">
|
||||
<view
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatusTab === 'pending' }"
|
||||
@click="selectStatusTab('pending')"
|
||||
>
|
||||
待完成
|
||||
</view>
|
||||
<view
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatusTab === 'all' }"
|
||||
@click="selectStatusTab('all')"
|
||||
>
|
||||
全部
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-btn" @click="showFilter = !showFilter">
|
||||
<text class="filter-text">筛选</text>
|
||||
</view>
|
||||
|
|
@ -108,70 +125,41 @@
|
|||
</view>
|
||||
</view>
|
||||
|
||||
<view class="filter-row">
|
||||
<view class="filter-item full-width">
|
||||
<text class="filter-label">排序方式</text>
|
||||
<view class="sort-options-filter">
|
||||
<view
|
||||
class="sort-option-filter"
|
||||
:class="{ active: sortBy === 'createTime' }"
|
||||
@click="selectSort('createTime')"
|
||||
>
|
||||
发布时间<text v-if="sortBy === 'createTime'" class="sort-arrow">{{ sortAsc ? '↑' : '↓' }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="sort-option-filter"
|
||||
:class="{ active: sortBy === 'expireTime' }"
|
||||
@click="selectSort('expireTime')"
|
||||
>
|
||||
到期时间<text v-if="sortBy === 'expireTime'" class="sort-arrow">{{ sortAsc ? '↑' : '↓' }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="sort-option-filter"
|
||||
:class="{ active: sortBy === 'passTime' }"
|
||||
@click="selectSort('passTime')"
|
||||
>
|
||||
通过时间<text v-if="sortBy === 'passTime'" class="sort-arrow">{{ sortAsc ? '↑' : '↓' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="filter-actions">
|
||||
<uv-button size="small" @click="handleReset">重置</uv-button>
|
||||
<uv-button type="primary" size="small" @click="handleSearch">确定</uv-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 状态标签和排序 -->
|
||||
<view class="status-sort-section" :class="{ 'with-filter': showFilter }">
|
||||
<view class="status-tabs">
|
||||
<view
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatusTab === 'pending' }"
|
||||
@click="selectStatusTab('pending')"
|
||||
>
|
||||
待完成
|
||||
</view>
|
||||
<view
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatusTab === 'completed' }"
|
||||
@click="selectStatusTab('completed')"
|
||||
>
|
||||
已完成
|
||||
</view>
|
||||
<view
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatusTab === 'cancelled' }"
|
||||
@click="selectStatusTab('cancelled')"
|
||||
>
|
||||
已取消
|
||||
</view>
|
||||
<view
|
||||
class="status-tab"
|
||||
:class="{ active: activeStatusTab === 'all' }"
|
||||
@click="selectStatusTab('all')"
|
||||
>
|
||||
全部任务
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sort-options">
|
||||
<view
|
||||
class="sort-option"
|
||||
:class="{ active: sortBy === 'createTime' }"
|
||||
@click="selectSort('createTime')"
|
||||
>
|
||||
发布时间<text v-if="sortBy === 'createTime'" class="sort-arrow">{{ sortAsc ? '↑' : '↓' }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="sort-option"
|
||||
:class="{ active: sortBy === 'expireTime' }"
|
||||
@click="selectSort('expireTime')"
|
||||
>
|
||||
到期时间<text v-if="sortBy === 'expireTime'" class="sort-arrow">{{ sortAsc ? '↑' : '↓' }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="sort-option"
|
||||
:class="{ active: sortBy === 'passTime' }"
|
||||
@click="selectSort('passTime')"
|
||||
>
|
||||
通过时间<text v-if="sortBy === 'passTime'" class="sort-arrow">{{ sortAsc ? '↑' : '↓' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 任务列表 -->
|
||||
<scroll-view
|
||||
class="task-scroll"
|
||||
|
|
@ -184,45 +172,50 @@
|
|||
class="task-card"
|
||||
v-for="task in tasks"
|
||||
:key="task.id"
|
||||
:class="getTaskCardClass(task)"
|
||||
@click="goToTaskDetail(task)"
|
||||
>
|
||||
<!-- 状态标签和日期 -->
|
||||
<view class="task-header">
|
||||
<view class="task-badge-wrapper">
|
||||
<uv-tags
|
||||
:text="getStatusText(task.status)"
|
||||
:type="getTaskStatusType(task.status)"
|
||||
size="mini"
|
||||
:plain="false"
|
||||
:custom-style="getTagCustomStyle(task.status)"
|
||||
></uv-tags>
|
||||
<uv-tags
|
||||
v-if="task.overdue && task.status !== '4' && task.status !== 4"
|
||||
text="逾期"
|
||||
type="error"
|
||||
size="mini"
|
||||
:plain="false"
|
||||
style="margin-left: 8px;"
|
||||
></uv-tags>
|
||||
</view>
|
||||
<view class="task-meta">
|
||||
<text class="task-project">{{ task.projectName || '未分配项目' }}</text>
|
||||
<text class="task-date">{{ formatDate(task.expireTime) }}</text>
|
||||
<view style="display: flex;align-items: center;gap: 12px">
|
||||
<view class="task-badge-wrapper">
|
||||
<uv-tags
|
||||
:text="getStatusText(task.status)"
|
||||
:type="getTaskStatusType(task.status)"
|
||||
size="mini"
|
||||
:plain="false"
|
||||
:custom-style="getTagCustomStyle(task.status)"
|
||||
></uv-tags>
|
||||
<uv-tags
|
||||
v-if="task.overdue && task.status !== '4' && task.status !== 4"
|
||||
text="逾期"
|
||||
type="error"
|
||||
size="mini"
|
||||
:plain="false"
|
||||
></uv-tags>
|
||||
</view>
|
||||
<view class="task-date-wrapper">
|
||||
<text class="task-date">{{ formatDate(task.expireTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 任务内容 -->
|
||||
<view class="task-content">
|
||||
<text class="task-project">所属项目: {{ task.projectName || '未分配项目' }}</text>
|
||||
<text class="task-description">{{ truncateText(task.description, 80) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="task-footer">
|
||||
<view class="task-users">
|
||||
<text class="task-user-label">创建人:</text>
|
||||
<text class="task-user-name">{{ task.createName || '未知' }}</text>
|
||||
<text class="task-user-label" style="margin-left: 12px;">负责人:</text>
|
||||
<text class="task-user-name">{{ getOwnerNames(task.memberList) || '未分配' }}</text>
|
||||
</view>
|
||||
<view class="task-times">
|
||||
<text class="task-time">发布时间: {{ formatDate(task.createTime) }}</text>
|
||||
<view class="task-meta">
|
||||
<text class="task-owner">负责人: {{ getOwnerNames(task.memberList) || '未分配' }}</text>
|
||||
<text class="task-owner">创建人: {{ task.createName || '未知' }}</text>
|
||||
<view class="task-time-row">
|
||||
<text class="task-time">发布时间: {{ formatDate(task.createTime) }}</text>
|
||||
<view class="task-countdown" v-if="task.cardStatus !== 'completed' && task.remainingDays !== null">
|
||||
<text class="countdown-icon">🕐</text>
|
||||
<text class="countdown-text" :class="getCountdownClass(task.cardStatus)">
|
||||
{{ task.remainingDays < 0 ? `已逾期${Math.abs(task.remainingDays)}天` : `剩余${task.remainingDays}天` }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<text v-if="task.passTime" class="task-time">通过时间: {{ formatDate(task.passTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -455,8 +448,67 @@ const {
|
|||
defaultParams: {}
|
||||
});
|
||||
|
||||
// 任务列表
|
||||
const tasks = computed(() => list.value);
|
||||
// 计算剩余天数
|
||||
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 determineTaskStatusForCard = (task) => {
|
||||
// 如果任务已完成(状态为4),直接返回 completed
|
||||
const taskStatus = task.status;
|
||||
if (taskStatus === 4 || taskStatus === '4') {
|
||||
return 'completed';
|
||||
}
|
||||
|
||||
// 如果没有过期时间,返回 pending
|
||||
const expireTime = task.expireTime;
|
||||
if (!expireTime) {
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
const expireDate = new Date(expireTime);
|
||||
const now = new Date();
|
||||
|
||||
// 如果已过期,标记为逾期
|
||||
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 tasks = computed(() => {
|
||||
return list.value.map(task => {
|
||||
const expireTime = task.expireTime || '';
|
||||
const remainingDays = calculateRemainingDays(expireTime);
|
||||
const cardStatus = determineTaskStatusForCard(task);
|
||||
|
||||
return {
|
||||
...task,
|
||||
remainingDays,
|
||||
cardStatus
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// 获取状态文本(根据数字状态)
|
||||
const getStatusText = (status) => {
|
||||
|
|
@ -538,6 +590,25 @@ const getTagCustomStyle = (status) => {
|
|||
return colorMap[statusItem.listClass] || defaultStyle;
|
||||
};
|
||||
|
||||
// 获取卡片样式类
|
||||
const getTaskCardClass = (task) => {
|
||||
return {
|
||||
'task-card-imminent': task.cardStatus === 'imminent',
|
||||
'task-card-pending': task.cardStatus === 'pending',
|
||||
'task-card-completed': task.cardStatus === 'completed',
|
||||
'task-card-overdue': task.cardStatus === 'overdue'
|
||||
};
|
||||
};
|
||||
|
||||
// 获取倒计时样式类
|
||||
const getCountdownClass = (cardStatus) => {
|
||||
return {
|
||||
'countdown-warning': cardStatus === 'imminent',
|
||||
'countdown-primary': cardStatus === 'pending',
|
||||
'countdown-error': cardStatus === 'overdue'
|
||||
};
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return '';
|
||||
|
|
@ -809,7 +880,7 @@ onMounted(() => {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 5px 24px;
|
||||
padding: 8px 24px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
position: fixed;
|
||||
|
|
@ -817,6 +888,15 @@ onMounted(() => {
|
|||
right: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.header-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
|
|
@ -842,7 +922,7 @@ onMounted(() => {
|
|||
padding: 16px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
position: fixed;
|
||||
top: 41px;
|
||||
top: 56px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
|
|
@ -947,28 +1027,10 @@ onMounted(() => {
|
|||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.status-sort-section {
|
||||
background: #fff;
|
||||
padding: 12px 16px;
|
||||
margin-bottom: 8px;
|
||||
position: fixed;
|
||||
top: 41px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 98;
|
||||
transition: top 0.3s ease;
|
||||
|
||||
&.with-filter {
|
||||
top: auto;
|
||||
position: relative;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.task-scroll {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding-top: 100px; /* header(41px) + status-sort-section(约60px) */
|
||||
padding-top: 56px; /* header高度 */
|
||||
transition: padding-top 0.3s ease;
|
||||
|
||||
&.with-filter {
|
||||
|
|
@ -979,20 +1041,25 @@ onMounted(() => {
|
|||
.status-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.status-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 12px;
|
||||
padding: 4px 12px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #2885ff;
|
||||
|
|
@ -1005,23 +1072,29 @@ onMounted(() => {
|
|||
}
|
||||
}
|
||||
|
||||
.sort-options {
|
||||
.sort-options-filter {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.sort-option {
|
||||
.sort-option-filter {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
border: 2px solid transparent;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.active {
|
||||
background: #e3f2fd;
|
||||
border-color: #2885ff;
|
||||
color: #2885ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
|
@ -1032,121 +1105,5 @@ onMounted(() => {
|
|||
}
|
||||
|
||||
|
||||
.task-container {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.task-card {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.task-card:active {
|
||||
transform: scale(0.98);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.task-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.task-badge-wrapper {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.task-meta {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.task-project {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.task-date {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.task-content {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.task-description {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.task-footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.task-users {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.task-user-label {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.task-user-name {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.task-times {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.task-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.load-more-tip {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.load-more-text {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
@import '@/styles/task-card.scss';
|
||||
</style>
|
||||
|
|
|
|||
173
styles/task-card.scss
Normal file
173
styles/task-card.scss
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// 任务卡片公共样式
|
||||
.task-card {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
// 即将逾期卡片样式
|
||||
&.task-card-imminent {
|
||||
border-left: 4px solid #ff9800;
|
||||
}
|
||||
|
||||
// 待完成卡片样式
|
||||
&.task-card-pending {
|
||||
border-left: 4px solid #2885ff;
|
||||
}
|
||||
|
||||
// 已完成卡片样式
|
||||
&.task-card-completed {
|
||||
border-left: 4px solid #909399;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
// 逾期卡片样式
|
||||
&.task-card-overdue {
|
||||
background: linear-gradient(135deg, #fff5f5 0%, #ffe6e6 100%);
|
||||
border-left: 4px solid #f56c6c;
|
||||
box-shadow: 0 2px 12px rgba(255, 68, 68, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.task-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.task-badge-wrapper {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-date-wrapper {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.task-date {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.task-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-project {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.task-description {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.task-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.task-owner {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.task-time-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-time {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.task-countdown {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.countdown-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.countdown-text {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.countdown-warning {
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
&.countdown-primary {
|
||||
color: #2885ff;
|
||||
}
|
||||
|
||||
&.countdown-error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
}
|
||||
|
||||
.task-action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
// 任务容器样式
|
||||
.task-container {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
// 空状态样式
|
||||
.empty-state {
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
// 加载更多提示样式
|
||||
.load-more-tip {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.load-more-text {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user