| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- <template>
- <view class="related-items-page">
- <view class="nav-bar">
- <text class="nav-back" @click="goBack">←</text>
- <text class="nav-title">关注事宜</text>
- <view class="nav-right"></view>
- </view>
- <view class="tab-bar">
- <view v-for="(tab, idx) in tabs" :key="idx" :class="'tab-item ' + (activeTab === idx ? 'active' : '')" @click="switchTab(idx)">
- <text class="tab-text">{{ tab.label }}</text>
- <view v-if="activeTab === idx" class="tab-underline"></view>
- </view>
- </view>
- <view v-if="loading" class="loading-state"><text>加载中...</text></view>
- <view v-else-if="error" class="error-state"><text class="error-text">{{ error }}</text></view>
- <view v-else class="content">
- <view v-if="activeTab === 0" class="tab-content">
- <view v-if="!items.pendingTasks || items.pendingTasks.length === 0" class="empty-state"><text class="empty-text">暂无待办任务</text></view>
- <view v-else class="item-list">
- <view v-for="(item, idx) in items.pendingTasks" :key="idx" class="item-card" @click="goToTask(item)">
- <view class="item-header">
- <text class="item-title">{{ item.title }}</text>
- <text :class="'status-tag ' + statusClass(item.status)">{{ statusText(item.status) }}</text>
- </view>
- <view class="item-meta">
- <text class="meta-text" v-if="item.assignee">负责人: {{ item.assignee }}</text>
- <text class="meta-text" v-if="item.dueDate">截止: {{ item.dueDate }}</text>
- </view>
- </view>
- </view>
- </view>
- <view v-if="activeTab === 1" class="tab-content">
- <view v-if="!items.pendingAssessments || items.pendingAssessments.length === 0" class="empty-state"><text class="empty-text">暂无待测评</text></view>
- <view v-else class="item-list">
- <view v-for="(item, idx) in items.pendingAssessments" :key="idx" class="item-card">
- <view class="item-header">
- <text class="item-title">{{ item.childName }}的测评</text>
- <text :class="'status-tag ' + statusClass(item.status)">{{ statusText(item.status) }}</text>
- </view>
- <view class="item-meta">
- <text class="meta-text" v-if="item.appointmentDate">{{ item.appointmentDate }}</text>
- </view>
- </view>
- </view>
- </view>
- <view v-if="activeTab === 2" class="tab-content">
- <view v-if="!items.healthAlerts || items.healthAlerts.length === 0" class="empty-state"><text class="empty-text">暂无健康提醒</text></view>
- <view v-else class="item-list">
- <view v-for="(item, idx) in items.healthAlerts" :key="idx" class="item-card">
- <view class="item-header">
- <text class="item-title">{{ item.message }}</text>
- <text :class="'alert-level ' + alertLevelClass(item.severity)">{{ item.severity }}</text>
- </view>
- <view class="item-meta">
- <text class="meta-text" v-if="item.members && item.members.length > 0">成员: {{ item.members.join(', ') }}</text>
- </view>
- </view>
- </view>
- </view>
- <view v-if="activeTab === 3" class="tab-content">
- <view v-if="!items.upcomingMilestones || items.upcomingMilestones.length === 0" class="empty-state"><text class="empty-text">暂无里程碑</text></view>
- <view v-else class="item-list">
- <view v-for="(item, idx) in items.upcomingMilestones" :key="idx" class="item-card">
- <view class="item-header">
- <text class="item-title">{{ item.description }}</text>
- </view>
- <view class="item-meta">
- <text class="meta-text" v-if="item.targetDate">目标: {{ item.targetDate }}</text>
- <text class="meta-text" v-if="item.daysAway !== undefined">{{ item.daysAway }}天后</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- export default {
- data: function() {
- return {
- activeTab: 0,
- tabs: [{ label: '任务' }, { label: '测评' }, { label: '健康' }, { label: '里程碑' }],
- items: { pendingTasks: [], pendingAssessments: [], healthAlerts: [], upcomingMilestones: [] },
- loading: false, error: null
- }
- },
- onLoad: function() { this.loadRelatedItems() },
- methods: {
- switchTab: function(idx) { this.activeTab = idx },
- loadRelatedItems: function() {
- var self = this
- self.loading = true; self.error = null
- self.$store.dispatch('tianpan/loadRelatedItems', { daysAhead: 7 })
- .then(function(data) { self.items = data || self.items })
- .catch(function(e) { self.error = e.message || '加载失败' })
- .finally(function() { self.loading = false })
- },
- goBack: function() { uni.navigateBack() },
- statusText: function(s) { var map = { pending: '待处理', in_progress: '进行中', completed: '已完成', cancelled: '已取消' }; return map[s] || s || '' },
- statusClass: function(s) { var map = { pending: 'pending', in_progress: 'in-progress', completed: 'completed', cancelled: 'cancelled' }; return map[s] || 'pending' },
- alertLevelClass: function(l) { var map = { low: 'alert-low', medium: 'alert-medium', high: 'alert-high' }; return map[l] || 'alert-low' },
- goToTask: function(item) { if (item.id) { uni.navigateTo({ url: '/pages/tasks/detail?id=' + item.id }) } }
- }
- }
- </script>
- <style scoped>
- .related-items-page { min-height: 100vh; background: #F3F4F6; }
- .nav-bar { display: flex; align-items: center; justify-content: space-between; padding: 20px 16px 10px; background: #F97316; }
- .nav-back { font-size: 18px; color: #FFF; }
- .nav-title { font-size: 17px; font-weight: bold; color: #FFF; }
- .nav-right { width: 40px; }
- .tab-bar { display: flex; background: #FFF; border-bottom: 1px solid #E5E7EB; position: sticky; top: 0; z-index: 10; }
- .tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 12px 0; position: relative; }
- .tab-text { font-size: 14px; color: #6B7280; }
- .tab-item.active .tab-text { color: #F97316; font-weight: 500; }
- .tab-underline { position: absolute; bottom: 0; width: 40px; height: 2px; background: #F97316; border-radius: 1px; }
- .loading-state, .error-state, .empty-state { padding: 60px 20px; display: flex; justify-content: center; align-items: center; }
- .error-text, .empty-text { font-size: 14px; color: #9CA3AF; }
- .content { padding: 12px; }
- .tab-content { min-height: 300px; }
- .item-list { display: flex; flex-direction: column; }
- .item-card { background: #FFF; border-radius: 12px; padding: 14px; margin-bottom: 10px; }
- .item-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
- .item-title { font-size: 14px; font-weight: 500; color: #1F2937; flex: 1; }
- .status-tag { font-size: 11px; padding: 2px 8px; border-radius: 10px; }
- .status-tag.pending { background: #FEF3C7; color: #92400E; }
- .status-tag.in-progress { background: #DBEAFE; color: #1E40AF; }
- .status-tag.completed { background: #DCFCE7; color: #166534; }
- .status-tag.cancelled { background: #F3F4F6; color: #6B7280; }
- .alert-level { font-size: 11px; padding: 2px 8px; border-radius: 10px; }
- .alert-low { background: #DCFCE7; color: #166534; }
- .alert-medium { background: #FEF3C7; color: #92400E; }
- .alert-high { background: #FEE2E2; color: #991B1B; }
- .item-meta { display: flex; gap: 12px; margin-bottom: 4px; }
- .meta-text { font-size: 12px; color: #9CA3AF; }
- </style>
|