Ver código fonte

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

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 2 meses atrás
pai
commit
387e82426d

+ 1 - 0
mobile-h5/App.vue

@@ -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 - 0
mobile-h5/components/OaTaskCard.vue

@@ -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>

+ 168 - 0
mobile-h5/styles/components/oa-task-list.scss

@@ -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);
+}