| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- 页颿 é¢ --> |
| | | <div class="page-header"> |
| | | <h2>ä¼è®®çæ¿</h2> |
| | | <!-- <el-button type="primary" @click="createMeeting">å建ä¼è®®</el-button>--> |
| | | </div> |
| | | |
| | | <!-- ä¼è®®ç»è®¡å¡ç --> |
| | | <div class="stats-cards"> |
| | | <el-card class="stat-card"> |
| | | <div class="stat-content"> |
| | | <div class="stat-number">{{ stats.total }}</div> |
| | | <div class="stat-label">æ»ä¼è®®æ°</div> |
| | | </div> |
| | | </el-card> |
| | | <el-card class="stat-card"> |
| | | <div class="stat-content"> |
| | | <div class="stat-number">{{ stats.underWay }}</div> |
| | | <div class="stat-label">è¿è¡ä¸</div> |
| | | </div> |
| | | </el-card> |
| | | <el-card class="stat-card"> |
| | | <div class="stat-content"> |
| | | <div class="stat-number">{{ stats.completed }}</div> |
| | | <div class="stat-label">已宿</div> |
| | | </div> |
| | | </el-card> |
| | | <el-card class="stat-card"> |
| | | <div class="stat-content"> |
| | | <div class="stat-number">{{ stats.toStart }}</div> |
| | | <div class="stat-label">å³å°å¼å§</div> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | |
| | | <!-- ä¼è®®å表 --> |
| | | <div class="meeting-list"> |
| | | <el-card v-for="meeting in meetings" :key="meeting.id" class="meeting-card"> |
| | | <div class="meeting-header"> |
| | | <div class="meeting-title"> |
| | | <h3>{{ meeting.title }}</h3> |
| | | <el-tag :type="getStatusType(meeting.status)" size="small"> |
| | | {{ getStatusText(meeting.status) }} |
| | | </el-tag> |
| | | </div> |
| | | <div class="meeting-time"> |
| | | {{dayjs(meeting.startTime).format("YYYY-MM-DD")}}<el-icon><Clock /></el-icon> |
| | | {{ formatTime(meeting.startTime) }} - {{ formatTime(meeting.endTime) }} |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="meeting-info"> |
| | | <div class="info-item"> |
| | | <el-icon><Location /></el-icon> |
| | | <span>{{ meeting.location }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <el-icon><User /></el-icon> |
| | | <span>主æäºº: {{ meeting.host }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <el-icon><UserFilled /></el-icon> |
| | | <span>åä¼äººæ°: {{ meeting.participants.length }}人</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="meeting-agenda"> |
| | | <h4>ä¼è®®çºªè¦</h4> |
| | | <div class="agenda-list"> |
| | | <div class="editor-container"> |
| | | <div |
| | | v-html="meeting.content" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue' |
| | | import { Clock, Location, User, UserFilled } from '@element-plus/icons-vue' |
| | | import {getMeetSummaryItems,getMeetSummary} from '@/api/collaborativeApproval/meeting.js' |
| | | import dayjs from "dayjs"; |
| | | |
| | | // ç»è®¡æ°æ® |
| | | const stats = ref({ |
| | | total: 0, |
| | | underWay: 0, |
| | | completed: 0, |
| | | toStart: 0 |
| | | }) |
| | | |
| | | // ä¼è®®æ°æ® |
| | | const meetings = ref([ |
| | | |
| | | ]) |
| | | |
| | | // å¯¹è¯æ¡ç¸å
³ |
| | | const dialogVisible = ref(false) |
| | | const meetingForm = reactive({ |
| | | title: '', |
| | | timeRange: [], |
| | | location: '', |
| | | host: '', |
| | | description: '' |
| | | }) |
| | | |
| | | // è·åç¶æç±»å |
| | | const getStatusType = (status) => { |
| | | const statusMap = { |
| | | '2': 'success', |
| | | '1': 'warning', |
| | | '0': 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | // è·åç¶æææ¬ |
| | | const getStatusText = (status) => { |
| | | const statusMap = { |
| | | '2': 'è¿è¡ä¸', |
| | | '1': 'å³å°å¼å§', |
| | | '0': '已宿' |
| | | } |
| | | return statusMap[status] || 'æªç¥' |
| | | } |
| | | |
| | | // è·åè®®ç¨ç¶æç±»å |
| | | const getAgendaStatusType = (status) => { |
| | | const statusMap = { |
| | | 'completed': 'success', |
| | | 'active': 'warning', |
| | | 'pending': 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | // è·åè®®ç¨ç¶æææ¬ |
| | | const getAgendaStatusText = (status) => { |
| | | const statusMap = { |
| | | 'completed': '已宿', |
| | | 'active': 'è¿è¡ä¸', |
| | | 'pending': 'å¾
å¼å§' |
| | | } |
| | | return statusMap[status] || 'æªç¥' |
| | | } |
| | | |
| | | // æ ¼å¼åæ¶é´ |
| | | const formatTime = (timeStr) => { |
| | | const date = new Date(timeStr) |
| | | return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }) |
| | | } |
| | | |
| | | |
| | | onMounted( async () => { |
| | | let [resp1,resp2] = await Promise.all([getMeetSummary(),getMeetSummaryItems()]) |
| | | stats.value = resp1.data |
| | | meetings.value = resp2.data.map(item => { |
| | | return { |
| | | ...item, |
| | | participants: JSON.parse(item.participants) |
| | | } |
| | | }) |
| | | console.log('ä¼è®®çæ¿é¡µé¢å è½½å®æ') |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .page-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .page-header h2 { |
| | | margin: 0; |
| | | color: #303133; |
| | | } |
| | | |
| | | .stats-cards { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
| | | gap: 20px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .stat-card { |
| | | text-align: center; |
| | | } |
| | | |
| | | .stat-content { |
| | | padding: 10px; |
| | | } |
| | | |
| | | .stat-number { |
| | | font-size: 32px; |
| | | font-weight: bold; |
| | | color: #409eff; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .meeting-list { |
| | | display: grid; |
| | | gap: 20px; |
| | | } |
| | | |
| | | .meeting-card { |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .meeting-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .meeting-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .meeting-title h3 { |
| | | margin: 0; |
| | | color: #303133; |
| | | } |
| | | |
| | | .meeting-time { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 5px; |
| | | color: #606266; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .meeting-info { |
| | | display: flex; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 5px; |
| | | color: #606266; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .meeting-agenda { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .meeting-agenda h4 { |
| | | margin: 0 0 15px 0; |
| | | color: #303133; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .agenda-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .agenda-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 15px; |
| | | padding: 10px; |
| | | border-radius: 6px; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .agenda-item.active { |
| | | background-color: #fdf6ec; |
| | | border-left: 3px solid #e6a23c; |
| | | } |
| | | |
| | | .agenda-item.completed { |
| | | background-color: #f0f9ff; |
| | | border-left: 3px solid #409eff; |
| | | } |
| | | |
| | | .agenda-time { |
| | | font-weight: bold; |
| | | color: #606266; |
| | | min-width: 80px; |
| | | } |
| | | |
| | | .agenda-content { |
| | | flex: 1; |
| | | color: #303133; |
| | | } |
| | | |
| | | .meeting-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 10px; |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .stats-cards { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | } |
| | | |
| | | .meeting-header { |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .meeting-info { |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .meeting-actions { |
| | | flex-direction: column; |
| | | } |
| | | } |
| | | </style> |