feat(oa): add mobile OA task card for center lists

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-12 16:03:38 +08:00
1 parent cf4994ef53
commit 387e82426d
3 files changed
+237

No files matched your search

+1
View File
@@ -18,6 +18,7 @@
@import './styles/components/menu-grid.scss';
@import './styles/components/todo.scss';
@import './styles/components/list.scss';
@import './styles/components/oa-task-list.scss';
@import './styles/components/detail.scss';
@import './styles/components/attach.scss';
@import './styles/components/flow.scss';
+68
View File
@@ -0,0 +1,68 @@
<template>
<view class="oa-task-card" :class="'tone-' + normalizedTone">
<view class="oa-task-card__body" @click="$emit('open')">
<view class="oa-task-card__top">
<view class="oa-task-card__title-row">
<view v-if="unread" class="oa-task-card__unread" aria-hidden="true" />
<text class="oa-task-card__title">{{ title }}</text>
</view>
<text
v-if="statusText"
class="oa-task-card__status"
:class="'is-' + normalizedTone"
>
{{ statusText }}
</text>
</view>
<view v-if="metaLines && metaLines.length" class="oa-task-card__meta">
<view
v-for="(line, idx) in metaLines"
:key="idx"
class="oa-task-card__meta-line"
>
<text class="oa-task-card__meta-label">{{ line.label }}</text>
<text class="oa-task-card__meta-value">{{ line.value }}</text>
</view>
</view>
</view>
<view v-if="actions && actions.length" class="oa-task-card__footer">
<view
v-for="act in actions"
:key="act.key"
class="oa-task-card__btn"
:class="{
'is-primary': !!act.primary,
'is-danger': !!act.danger && !act.primary
}"
@click.stop="$emit('action', act)"
>
{{ act.label }}
</view>
</view>
</view>
</template>
<script>
const TONES = ['warn', 'success', 'danger', 'info']
export default {
name: 'OaTaskCard',
props: {
title: { type: String, default: '' },
statusText: { type: String, default: '' },
statusTone: { type: String, default: 'info' },
metaLines: { type: Array, default: () => [] },
unread: { type: Boolean, default: false },
actions: { type: Array, default: () => [] }
},
emits: ['open', 'action'],
computed: {
normalizedTone() {
const t = String(this.statusTone || 'info').toLowerCase()
return TONES.includes(t) ? t : 'info'
}
}
}
</script>
@@ -0,0 +1,168 @@
// OA 任务中心列表壳 + OaTaskCard(对齐 list.scss 卡片节奏与 start 页间距)
.oa-task-list {
padding: 24rpx 24rpx 0;
}
.oa-task-list__empty,
.oa-task-list__end {
padding: 48rpx 16rpx 56rpx;
text-align: center;
font-size: 24rpx;
color: var(--text-muted, #5f7a6d);
letter-spacing: 0.04em;
}
.oa-task-list__empty {
padding-top: 96rpx;
font-size: 28rpx;
}
.oa-task-card {
position: relative;
margin-bottom: 24rpx;
border-radius: var(--radius-card, 28rpx);
background: var(--surface, #fff);
border: 1rpx solid var(--border, #d8f3e5);
box-shadow: var(--shadow-soft, 0 8rpx 32rpx rgba(22, 163, 74, 0.07));
overflow: hidden;
}
.oa-task-card__body {
padding: 28rpx 28rpx 24rpx;
}
.oa-task-card__top {
display: flex;
align-items: flex-start;
gap: 16rpx;
}
.oa-task-card__title-row {
flex: 1;
min-width: 0;
display: flex;
align-items: flex-start;
gap: 12rpx;
}
.oa-task-card__unread {
flex-shrink: 0;
width: 16rpx;
height: 16rpx;
margin-top: 12rpx;
border-radius: 50%;
background: var(--danger, #ef4444);
}
.oa-task-card__title {
flex: 1;
min-width: 0;
font-size: 30rpx;
font-weight: 700;
line-height: 1.4;
color: var(--text-primary, #0f291e);
word-break: break-word;
}
.oa-task-card__status {
flex-shrink: 0;
max-width: 40%;
font-size: 22rpx;
font-weight: 650;
line-height: 1.2;
padding: 8rpx 18rpx;
border-radius: 999rpx;
text-align: center;
box-sizing: border-box;
}
.oa-task-card__status.is-warn {
background: rgba(217, 119, 6, 0.12);
color: var(--warning, #d97706);
}
.oa-task-card__status.is-success {
background: rgba(16, 185, 129, 0.12);
color: var(--success, #10b981);
}
.oa-task-card__status.is-danger {
background: rgba(239, 68, 68, 0.12);
color: var(--danger, #ef4444);
}
.oa-task-card__status.is-info {
background: rgba(95, 122, 109, 0.12);
color: var(--text-muted, #5f7a6d);
}
.oa-task-card__meta {
margin-top: 20rpx;
display: flex;
flex-direction: column;
gap: 12rpx;
}
.oa-task-card__meta-line {
display: flex;
align-items: flex-start;
gap: 16rpx;
font-size: 24rpx;
line-height: 1.45;
}
.oa-task-card__meta-label {
flex-shrink: 0;
min-width: 120rpx;
color: var(--text-muted, #5f7a6d);
}
.oa-task-card__meta-value {
flex: 1;
min-width: 0;
color: var(--text-primary, #0f291e);
word-break: break-word;
}
.oa-task-card__footer {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 16rpx;
padding: 16rpx 24rpx 24rpx;
border-top: 1rpx dashed rgba(140, 170, 155, 0.28);
}
.oa-task-card__btn {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 72rpx;
min-width: 128rpx;
padding: 0 28rpx;
box-sizing: border-box;
border-radius: 16rpx;
font-size: 26rpx;
font-weight: 600;
line-height: 1;
color: var(--text-primary, #0f291e);
background: #fff;
border: 1rpx solid var(--border, #d8f3e5);
}
.oa-task-card__btn:active {
opacity: 0.78;
}
.oa-task-card__btn.is-primary {
color: #fff;
background: var(--brand-green, #22c55e);
border-color: var(--brand-green, #22c55e);
}
.oa-task-card__btn.is-danger {
color: var(--danger, #ef4444);
background: rgba(239, 68, 68, 0.06);
border-color: rgba(239, 68, 68, 0.35);
}