From 6f1bd54c8ea5327f09e077af3d16272987c48e40 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期三, 17 九月 2025 16:22:17 +0800
Subject: [PATCH] Merge branch 'dev_meet' into dev

---
 src/views/collaborativeApproval/notificationManagement/summary/index.vue         |  403 +++++++
 src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue     |  418 +++++++
 src/views/collaborativeApproval/meetingBoard/index.vue                           |  228 ---
 src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue     |  416 +++++++
 src/views/collaborativeApproval/notificationManagement/meetSetting/index.vue     |  306 +++++
 src/api/collaborativeApproval/meeting.js                                         |  118 ++
 src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue |  398 +++++++
 src/views/collaborativeApproval/notificationManagement/meetDraft/index.vue       |  495 +++++++++
 src/views/collaborativeApproval/notificationManagement/meetIndex/index.vue       |  371 +++++++
 9 files changed, 2,963 insertions(+), 190 deletions(-)

diff --git a/src/api/collaborativeApproval/meeting.js b/src/api/collaborativeApproval/meeting.js
new file mode 100644
index 0000000..20df8b1
--- /dev/null
+++ b/src/api/collaborativeApproval/meeting.js
@@ -0,0 +1,118 @@
+import request from "@/utils/request";
+
+export function getMeetingRoomList(data) {
+    return request({
+        url: "/meeting/roomList",
+        method: "post",
+        data: data,
+    });
+}
+
+export function saveRoom(data) {
+    return request({
+        url: "/meeting/saveRoom",
+        method: "post",
+        data: data,
+    });
+}
+
+export function delRoom(id) {
+    return request({
+        url: "/meeting/delRoom/"+id,
+        method: "delete",
+    });
+}
+
+export function getRoomEnum() {
+    return request({
+        url: "/meeting/roomEnum",
+        method: "get",
+    });
+}
+
+export function getDraftList(data){
+    return request({
+        url: "/meeting/draftList",
+        method: "post",
+        data: data,
+    });
+}
+
+export function saveDraft(data) {
+    return request({
+        url: "/meeting/saveDraft",
+        method: "post",
+        data: data,
+    });
+}
+
+export function delDraft(id) {
+    return request({
+        url: "/meeting/delDraft/"+id,
+        method: "delete",
+    });
+}
+
+export function saveMeetingApplication(data){
+    return request({
+        url: "/meeting/saveMeetingApplication",
+        method: "post",
+        data: data,
+    });
+}
+
+export function getExamineList(data) {
+    return request({
+        url: "/meeting/applicationList",
+        method: "post",
+        data: data,
+    });
+}
+
+
+export function getMeetingUseList(data){
+    return request({
+        url: "/meeting/meetingUseList",
+        method: "post",
+        data: data,
+    });
+}
+
+export function getMeetingPublish(data){
+    return request({
+        url: "/meeting/meetingPublishList",
+        method: "post",
+        data: data
+    });
+}
+
+
+export function getMeetingMinutesByMeetingId(id){
+    return request({
+        url: "/meeting/getMeetingMinutesByMeetingId/"+id,
+        method: "get",
+    });
+}
+
+export function saveMeetingMinutes(data){
+    return request({
+        url: "/meeting/saveMeetingMinutes",
+        method: "post",
+        data: data,
+    });
+}
+
+
+export function getMeetSummary(){
+    return request({
+        url: "/meeting/getMeetSummary",
+        method: "get",
+    });
+}
+
+export function getMeetSummaryItems(){
+    return request({
+        url: "/meeting/getMeetSummaryItems",
+        method: "get",
+    });
+}
diff --git a/src/views/collaborativeApproval/meetingBoard/index.vue b/src/views/collaborativeApproval/meetingBoard/index.vue
index b6b803b..dfbb922 100644
--- a/src/views/collaborativeApproval/meetingBoard/index.vue
+++ b/src/views/collaborativeApproval/meetingBoard/index.vue
@@ -16,7 +16,7 @@
       </el-card>
       <el-card class="stat-card">
         <div class="stat-content">
-          <div class="stat-number">{{ stats.ongoing }}</div>
+          <div class="stat-number">{{ stats.underWay }}</div>
           <div class="stat-label">杩涜涓�</div>
         </div>
       </el-card>
@@ -28,7 +28,7 @@
       </el-card>
       <el-card class="stat-card">
         <div class="stat-content">
-          <div class="stat-number">{{ stats.upcoming }}</div>
+          <div class="stat-number">{{ stats.toStart }}</div>
           <div class="stat-label">鍗冲皢寮�濮�</div>
         </div>
       </el-card>
@@ -45,11 +45,11 @@
             </el-tag>
           </div>
           <div class="meeting-time">
-            <el-icon><Clock /></el-icon>
-            {{ formatTime(meeting.startTime) }} - {{ formatTime(meeting.endTime) }}
+             {{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>
@@ -66,79 +66,18 @@
         </div>
 
         <div class="meeting-agenda">
-          <h4>璁▼瀹夋帓</h4>
+          <h4>浼氳绾</h4>
           <div class="agenda-list">
-            <div 
-              v-for="(agenda, index) in meeting.agenda" 
-              :key="index"
-              class="agenda-item"
-              :class="{ 'active': agenda.status === 'active', 'completed': agenda.status === 'completed' }"
-            >
-              <span class="agenda-time">{{ agenda.time }}</span>
-              <span class="agenda-content">{{ agenda.content }}</span>
-              <el-tag 
-                :type="getAgendaStatusType(agenda.status)" 
-                size="small"
-              >
-                {{ getAgendaStatusText(agenda.status) }}
-              </el-tag>
+            <div class="editor-container">
+              <div
+                  v-html="meeting.content"
+              />
             </div>
           </div>
         </div>
-
-<!--        <div class="meeting-actions">-->
-<!--          <el-button type="primary" size="small" @click="joinMeeting(meeting)">-->
-<!--            鍔犲叆浼氳-->
-<!--          </el-button>-->
-<!--          <el-button type="info" size="small" @click="viewDetails(meeting)">-->
-<!--            鏌ョ湅璇︽儏-->
-<!--          </el-button>-->
-<!--          <el-button type="warning" size="small" @click="editMeeting(meeting)">-->
-<!--            缂栬緫-->
-<!--          </el-button>-->
-<!--        </div>-->
       </el-card>
     </div>
 
-    <!-- 鍒涘缓浼氳瀵硅瘽妗� -->
-    <el-dialog v-model="dialogVisible" title="鍒涘缓浼氳" width="600px">
-      <el-form :model="meetingForm" label-width="100px">
-        <el-form-item label="浼氳鏍囬">
-          <el-input v-model="meetingForm.title" placeholder="璇疯緭鍏ヤ細璁爣棰�" />
-        </el-form-item>
-        <el-form-item label="浼氳鏃堕棿">
-          <el-date-picker
-            v-model="meetingForm.timeRange"
-            type="datetimerange"
-            range-separator="鑷�"
-            start-placeholder="寮�濮嬫椂闂�"
-            end-placeholder="缁撴潫鏃堕棿"
-            format="YYYY-MM-DD HH:mm"
-            value-format="YYYY-MM-DD HH:mm:ss"
-          />
-        </el-form-item>
-        <el-form-item label="浼氳鍦扮偣">
-          <el-input v-model="meetingForm.location" placeholder="璇疯緭鍏ヤ細璁湴鐐�" />
-        </el-form-item>
-        <el-form-item label="涓绘寔浜�">
-          <el-input v-model="meetingForm.host" placeholder="璇疯緭鍏ヤ富鎸佷汉濮撳悕" />
-        </el-form-item>
-        <el-form-item label="浼氳鎻忚堪">
-          <el-input
-            v-model="meetingForm.description"
-            type="textarea"
-            :rows="3"
-            placeholder="璇疯緭鍏ヤ細璁弿杩�"
-          />
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary" @click="submitMeeting">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
   </div>
 </template>
 
@@ -146,63 +85,21 @@
 import { ref, reactive, onMounted } from 'vue'
 import { ElMessage } from 'element-plus'
 import { Clock, Location, User, UserFilled } from '@element-plus/icons-vue'
+import Editor from "@/components/Editor/index.vue";
+import {getMeetSummaryItems,getMeetSummary} from '@/api/collaborativeApproval/meeting.js'
+import dayjs from "dayjs";
 
 // 缁熻鏁版嵁
-const stats = reactive({
-  total: 12,
-  ongoing: 3,
-  completed: 7,
-  upcoming: 2
+const stats = ref({
+  total: 0,
+  underWay: 0,
+  completed: 0,
+  toStart: 0
 })
 
 // 浼氳鏁版嵁
 const meetings = ref([
-  {
-    id: 1,
-    title: '浜у搧寮�鍙戝懆浼�',
-    status: 'ongoing',
-    startTime: '2025-01-15 09:00:00',
-    endTime: '2025-01-15 10:30:00',
-    location: '浼氳瀹',
-    host: '闄堝織寮�',
-    participants: ['闄堝織寮�', '鍒橀泤濠�', '鐜嬪缓鍥�', '璧典附鍗�'],
-    agenda: [
-      { time: '09:00-09:15', content: '涓婂懆宸ヤ綔鎬荤粨', status: 'completed' },
-      { time: '09:15-09:45', content: '鏈懆寮�鍙戣鍒�', status: 'active' },
-      { time: '09:45-10:00', content: '鎶�鏈毦鐐硅璁�', status: 'pending' },
-      { time: '10:00-10:30', content: '闂鍙嶉涓庤В鍐�', status: 'pending' }
-    ]
-  },
-  {
-    id: 2,
-    title: '瀹㈡埛闇�姹傝瘎瀹′細',
-    status: 'upcoming',
-    startTime: '2025-01-15 14:00:00',
-    endTime: '2025-01-15 15:00:00',
-    location: '绾夸笂浼氳',
-    host: '闄堝織寮�',
-    participants: ['闄堝織寮�', '鍒橀泤濠�', '瀛欐槑鍗�', '瀹㈡埛浠h〃'],
-    agenda: [
-      { time: '14:00-14:20', content: '闇�姹傝儗鏅粙缁�', status: 'pending' },
-      { time: '14:20-14:40', content: '鍔熻兘闇�姹傚垎鏋�', status: 'pending' },
-      { time: '14:40-15:00', content: '鎶�鏈彲琛屾�ц瘎浼�', status: 'pending' }
-    ]
-  },
-  {
-    id: 3,
-    title: '鍥㈤槦寤鸿娲诲姩',
-    status: 'completed',
-    startTime: '2025-01-14 16:00:00',
-    endTime: '2025-01-14 18:00:00',
-    location: '鍏徃澶у巺',
-    host: '浜轰簨閮�',
-    participants: ['鍏ㄤ綋鍛樺伐'],
-    agenda: [
-      { time: '16:00-16:30', content: '鍥㈤槦娓告垙', status: 'completed' },
-      { time: '16:30-17:00', content: '缁忛獙鍒嗕韩', status: 'completed' },
-      { time: '17:00-18:00', content: '鑷敱浜ゆ祦', status: 'completed' }
-    ]
-  }
+
 ])
 
 // 瀵硅瘽妗嗙浉鍏�
@@ -218,9 +115,9 @@
 // 鑾峰彇鐘舵�佺被鍨�
 const getStatusType = (status) => {
   const statusMap = {
-    'ongoing': 'success',
-    'upcoming': 'warning',
-    'completed': 'info'
+    '2': 'success',
+    '1': 'warning',
+    '0': 'info'
   }
   return statusMap[status] || 'info'
 }
@@ -228,9 +125,9 @@
 // 鑾峰彇鐘舵�佹枃鏈�
 const getStatusText = (status) => {
   const statusMap = {
-    'ongoing': '杩涜涓�',
-    'upcoming': '鍗冲皢寮�濮�',
-    'completed': '宸插畬鎴�'
+    '2': '杩涜涓�',
+    '1': '鍗冲皢寮�濮�',
+    '0': '宸插畬鎴�'
   }
   return statusMap[status] || '鏈煡'
 }
@@ -261,65 +158,16 @@
   return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
 }
 
-// 鍒涘缓浼氳
-const createMeeting = () => {
-  dialogVisible.value = true
-  // 閲嶇疆琛ㄥ崟
-  Object.assign(meetingForm, {
-    title: '',
-    timeRange: [],
-    location: '',
-    host: '',
-    description: ''
+
+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)
+    }
   })
-}
-
-// 鎻愪氦浼氳
-const submitMeeting = () => {
-  if (!meetingForm.title || !meetingForm.timeRange.length || !meetingForm.location || !meetingForm.host) {
-    ElMessage.warning('璇峰~鍐欏畬鏁寸殑浼氳淇℃伅')
-    return
-  }
-  
-  // 鍒涘缓鏂颁細璁�
-  const newMeeting = {
-    id: Date.now(),
-    title: meetingForm.title,
-    status: 'upcoming',
-    startTime: meetingForm.timeRange[0],
-    endTime: meetingForm.timeRange[1],
-    location: meetingForm.location,
-    host: meetingForm.host,
-    participants: [meetingForm.host],
-    agenda: [
-      { time: '寰呭畾', content: '璁▼寰呭畾', status: 'pending' }
-    ]
-  }
-  
-  meetings.value.unshift(newMeeting)
-  stats.total++
-  stats.upcoming++
-  
-  ElMessage.success('浼氳鍒涘缓鎴愬姛')
-  dialogVisible.value = false
-}
-
-// 鍔犲叆浼氳
-const joinMeeting = (meeting) => {
-  ElMessage.success(`宸插姞鍏ヤ細璁細${meeting.title}`)
-}
-
-// 鏌ョ湅璇︽儏
-const viewDetails = (meeting) => {
-  ElMessage.info(`鏌ョ湅浼氳璇︽儏锛�${meeting.title}`)
-}
-
-// 缂栬緫浼氳
-const editMeeting = (meeting) => {
-  ElMessage.info(`缂栬緫浼氳锛�${meeting.title}`)
-}
-
-onMounted(() => {
   console.log('浼氳鐪嬫澘椤甸潰鍔犺浇瀹屾垚')
 })
 </script>
@@ -480,19 +328,19 @@
   .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>
\ No newline at end of file
+</style>
diff --git a/src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue b/src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue
new file mode 100644
index 0000000..1a2859a
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue
@@ -0,0 +1,398 @@
+<template>
+  <div class="app-container">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <h2>浼氳鐢宠</h2>
+    </div>
+
+    <!-- 鐢宠绫诲瀷閫夋嫨 -->
+    <el-card class="type-card">
+      <div class="type-selector">
+        <div
+            v-for="type in applicationTypes"
+            :key="type.value"
+            class="type-item"
+            :class="{ active: currentType === type.value }"
+            @click="changeType(type.value)"
+        >
+          <div class="type-icon">
+            <el-icon :size="24"><component :is="type.icon"/></el-icon>
+          </div>
+          <div class="type-info">
+            <div class="type-name">{{ type.name }}</div>
+            <div class="type-desc">{{ type.desc }}</div>
+          </div>
+        </div>
+      </div>
+    </el-card>
+
+    <!-- 浼氳鐢宠琛ㄥ崟 -->
+    <el-card>
+      <div class="form-header">
+        <h3>{{ getCurrentTypeName() }}鐢宠</h3>
+      </div>
+
+      <el-form
+          ref="meetingFormRef"
+          :model="meetingForm"
+          :rules="rules"
+          label-width="100px"
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浼氳涓婚" prop="title">
+              <el-input v-model="meetingForm.title" placeholder="璇疯緭鍏ヤ細璁富棰�"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浼氳瀹�" prop="roomId">
+              <el-select v-model="meetingForm.roomId" placeholder="璇烽�夋嫨浼氳瀹�" style="width: 100%">
+                <el-option
+                    v-for="room in meetingRooms"
+                    :key="room.id"
+                    :label="`${room.name} (${room.location})`"
+                    :value="room.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="涓绘寔浜�" prop="host">
+              <el-input v-model="meetingForm.host" placeholder="璇疯緭鍏ヤ富鎸佷汉濮撳悕"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浼氳鏃ユ湡" prop="meetingDate">
+              <el-date-picker
+                  v-model="meetingForm.meetingDate"
+                  type="date"
+                  placeholder="璇烽�夋嫨浼氳鏃ユ湡"
+                  value-format="YYYY-MM-DD"
+                  format="YYYY-MM-DD"
+                  :disabled-date="disabledDate"
+                  style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <!-- 绌哄垪锛屼繚鎸佸竷灞� -->
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="寮�濮嬫椂闂�" prop="startTime">
+              <el-select
+                  v-model="meetingForm.startTime"
+                  placeholder="璇烽�夋嫨寮�濮嬫椂闂�"
+                  style="width: 100%"
+              >
+                <el-option
+                    v-for="time in timeOptions"
+                    :key="time.value"
+                    :label="time.label"
+                    :value="time.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁撴潫鏃堕棿" prop="endTime">
+              <el-select
+                  v-model="meetingForm.endTime"
+                  placeholder="璇烽�夋嫨缁撴潫鏃堕棿"
+                  style="width: 100%"
+              >
+                <el-option
+                    v-for="time in timeOptions"
+                    :key="time.value"
+                    :label="time.label"
+                    :value="time.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-form-item label="鍙備細浜哄憳" prop="participants">
+          <el-select
+              v-model="meetingForm.participants"
+              multiple
+              filterable
+              placeholder="璇烽�夋嫨鍙備細浜哄憳"
+              style="width: 100%"
+          >
+            <el-option
+                v-for="person in employees"
+                :key="person.id"
+                :label="`${person.staffName} (${person.postJob})`"
+                :value="person.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="浼氳璇存槑" prop="description">
+          <el-input
+              v-model="meetingForm.description"
+              type="textarea"
+              :rows="4"
+              placeholder="璇疯緭鍏ヤ細璁鏄�"
+          />
+        </el-form-item>
+      </el-form>
+
+      <div class="form-footer">
+        <el-button @click="resetForm">閲嶇疆</el-button>
+        <el-button type="primary" @click="submitForm">鎻愪氦</el-button>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import {ref, reactive, onMounted} from 'vue'
+import {ElMessage} from 'element-plus'
+import {Plus, Document, Promotion, Bell} from '@element-plus/icons-vue'
+import {getRoomEnum, saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js'
+import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
+
+// 褰撳墠鐢宠绫诲瀷
+const currentType = ref('department') // approval: 瀹℃壒娴佺▼, department: 閮ㄩ棬绾�, notification: 閫氱煡鍙戝竷
+
+// 鐢宠绫诲瀷閫夐」
+const applicationTypes = ref([
+  {
+    value: 'approval',
+    name: '瀹℃壒娴佺▼浼氳',
+    desc: '闇�瑕佺粡杩囧绾у鎵圭殑浼氳鐢宠',
+    icon: Document
+  },
+  {
+    value: 'department',
+    name: '閮ㄩ棬绾т細璁�',
+    desc: '閮ㄩ棬鍐呴儴浼氳鐢宠娴佺▼',
+    icon: Promotion
+  },
+  {
+    value: 'notification',
+    name: '浼氳閫氱煡',
+    desc: '鏃犻渶瀹℃壒鐩存帴鍙戝竷鐨勪細璁�氱煡',
+    icon: Bell
+  }
+])
+
+// 琛ㄥ崟鏁版嵁
+const meetingForm = reactive({
+  title: '',
+  type: '',
+  roomId: '',
+  host: '',
+  meetingDate: '',
+  startTime: '',
+  endTime: '',
+  participants: [],
+  description: ''
+})
+
+// 琛ㄥ崟鏍¢獙瑙勫垯
+const rules = {
+  title: [{required: true, message: '璇疯緭鍏ヤ細璁富棰�', trigger: 'blur'}],
+  roomId: [{required: true, message: '璇烽�夋嫨浼氳瀹�', trigger: 'change'}],
+  host: [{required: true, message: '璇疯緭鍏ヤ富鎸佷汉', trigger: 'blur'}],
+  meetingDate: [{required: true, message: '璇烽�夋嫨浼氳鏃ユ湡', trigger: 'change'}],
+  startTime: [{required: true, message: '璇烽�夋嫨寮�濮嬫椂闂�', trigger: 'change'}],
+  endTime: [{required: true, message: '璇烽�夋嫨缁撴潫鏃堕棿', trigger: 'change'}],
+  participants: [{required: true, message: '璇烽�夋嫨鍙備細浜哄憳', trigger: 'change'}]
+}
+
+// 琛ㄥ崟寮曠敤
+const meetingFormRef = ref(null)
+
+// 浼氳瀹ゅ垪琛�
+const meetingRooms = ref([])
+
+// 鍛樺伐鍒楄〃
+const employees = ref([])
+
+// 鏃堕棿閫夐」锛堜互鍗婂皬鏃朵负闂撮殧锛�
+const timeOptions = ref([])
+
+// 鍒濆鍖栨椂闂撮�夐」
+const initTimeOptions = () => {
+  const options = []
+  for (let hour = 8; hour <= 18; hour++) {
+    // 姣忎釜灏忔椂娣诲姞涓や釜閫夐」锛氭暣鐐瑰拰鍗婄偣
+    options.push({
+      value: `${hour.toString().padStart(2, '0')}:00`,
+      label: `${hour.toString().padStart(2, '0')}:00`
+    })
+
+    if (hour < 18) { // 18:00涔嬪悗娌℃湁鍗婄偣閫夐」
+      options.push({
+        value: `${hour.toString().padStart(2, '0')}:30`,
+        label: `${hour.toString().padStart(2, '0')}:30`
+      })
+    }
+  }
+  timeOptions.value = options
+}
+
+// 绂佺敤鏃ユ湡锛堢鐢ㄤ粖澶╀箣鍓嶇殑鏃ユ湡锛�
+const disabledDate = (time) => {
+  // 绂佺敤浠婂ぉ涔嬪墠鐨勬棩鏈�
+  return time.getTime() < Date.now() - 86400000
+}
+
+// 鍒囨崲鐢宠绫诲瀷
+const changeType = (type) => {
+  currentType.value = type
+}
+
+// 鑾峰彇褰撳墠绫诲瀷鍚嶇О
+const getCurrentTypeName = () => {
+  const type = applicationTypes.value.find(t => t.value === currentType.value)
+  return type ? type.name : ''
+}
+
+// 閲嶇疆琛ㄥ崟
+const resetForm = () => {
+  meetingFormRef.value?.resetFields()
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  meetingFormRef.value?.validate((valid) => {
+    if (valid) {
+
+      let formData = {...meetingForm}
+      formData.applicationType = currentType.value
+      formData.startTime = `${meetingForm.meetingDate} ${meetingForm.startTime}:00`
+      formData.endTime = `${meetingForm.meetingDate} ${meetingForm.endTime}:00`
+      formData.participants = JSON.stringify(formData.participants)
+      console.log(formData)
+      saveMeetingApplication(formData).then(() => {
+
+        // 妯℃嫙鎻愪氦鎿嶄綔
+        ElMessage.success(`${getCurrentTypeName()}鎻愪氦鎴愬姛`)
+
+        // 鏍规嵁涓嶅悓绫诲瀷鎵ц涓嶅悓鎿嶄綔
+        switch (currentType.value) {
+          case 'approval':
+            ElMessage.info('浼氳宸叉彁浜ゅ鎵规祦绋�')
+            break
+          case 'department':
+            ElMessage.info('閮ㄩ棬绾т細璁敵璇峰凡鎻愪氦')
+            break
+          case 'notification':
+            ElMessage.info('浼氳閫氱煡宸插彂甯�')
+            break
+        }
+        resetForm()
+      })
+
+    }
+  })
+}
+
+// 椤甸潰鍔犺浇鏃跺垵濮嬪寲
+onMounted(() => {
+  initTimeOptions()
+  getRoomEnum().then(res => {
+    meetingRooms.value = res.data
+  })
+  getStaffOnJob().then(res => {
+    employees.value = res.data.sort((a, b) => a.postJob.localeCompare(b.postJob))
+  })
+})
+</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;
+}
+
+.type-card {
+  margin-bottom: 20px;
+}
+
+.type-selector {
+  display: flex;
+  gap: 20px;
+}
+
+.type-item {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  padding: 20px;
+  border: 1px solid #ebeef5;
+  border-radius: 8px;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.type-item:hover {
+  border-color: #409eff;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+
+.type-item.active {
+  border-color: #409eff;
+  background-color: #ecf5ff;
+}
+
+.type-icon {
+  margin-right: 15px;
+  color: #409eff;
+}
+
+.type-name {
+  font-size: 16px;
+  font-weight: 500;
+  color: #303133;
+  margin-bottom: 5px;
+}
+
+.type-desc {
+  font-size: 14px;
+  color: #909399;
+}
+
+.form-header {
+  margin-bottom: 20px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.form-header h3 {
+  margin: 0;
+  color: #303133;
+}
+
+.form-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+  margin-top: 30px;
+  padding-top: 20px;
+  border-top: 1px solid #ebeef5;
+}
+</style>
diff --git a/src/views/collaborativeApproval/notificationManagement/meetDraft/index.vue b/src/views/collaborativeApproval/notificationManagement/meetDraft/index.vue
new file mode 100644
index 0000000..0c62b8b
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/meetDraft/index.vue
@@ -0,0 +1,495 @@
+<template>
+  <div class="app-container">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <h2>浼氳鑽夌</h2>
+      <el-button type="primary" @click="handleAdd">
+        <el-icon><Plus /></el-icon>
+        鏂板缓鑽夌
+      </el-button>
+    </div>
+
+    <!-- 鎼滅储鍖哄煙 -->
+    <el-card class="search-card">
+      <el-form :model="searchForm" label-width="100px" inline>
+        <el-form-item label="浼氳涓婚">
+          <el-input v-model="searchForm.title" placeholder="璇疯緭鍏ヤ細璁富棰�" clearable />
+        </el-form-item>
+        <el-form-item label="浼氳鏃ユ湡">
+          <el-date-picker
+            v-model="searchForm.meetingDate"
+            type="date"
+            placeholder="璇烽�夋嫨浼氳鏃ユ湡"
+            value-format="YYYY-MM-DD"
+            format="YYYY-MM-DD"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 鑽夌鍒楄〃 -->
+    <el-card>
+      <el-table v-loading="loading" :data="draftList" border>
+        <el-table-column prop="title" label="浼氳涓婚" align="center" min-width="200" show-overflow-tooltip />
+        <el-table-column prop="room" label="浼氳瀹�" align="center" width="120" />
+        <el-table-column prop="host" label="涓绘寔浜�" align="center" width="120" />
+        <el-table-column prop="meetingTime" label="浼氳鏃堕棿" align="center" width="180">
+          <template #default="scope">
+            {{ formatDateTime(scope.row.meetingTime) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="participants" label="鍙備細浜烘暟" align="center" width="100">
+          <template #default="scope">
+            {{ scope.row.participants }}浜�
+          </template>
+        </el-table-column>
+        <el-table-column prop="createTime" label="鍒涘缓鏃堕棿" align="center" width="180" />
+        <el-table-column label="鎿嶄綔" align="center" width="200" fixed="right">
+          <template #default="scope">
+            <el-button type="primary" link @click="viewDraft(scope.row)">鏌ョ湅</el-button>
+            <el-button type="primary" link @click="editDraft(scope.row)">缂栬緫</el-button>
+            <el-button type="danger" link @click="deleteDraft(scope.row)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 鍒嗛〉 -->
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.current"
+        v-model:limit="queryParams.size"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 浼氳鑽夌璇︽儏瀵硅瘽妗� -->
+    <el-dialog
+      title="浼氳鑽夌璇︽儏"
+      v-model="detailDialogVisible"
+      width="800px"
+    >
+      <div v-if="currentDraft">
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="浼氳涓婚">{{ currentDraft.title }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳缂栧彿">{{ currentDraft.meetingId }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳瀹�">{{ currentDraft.room }}</el-descriptions-item>
+          <el-descriptions-item label="涓绘寔浜�">{{ currentDraft.host }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿" :span="2">
+            {{ formatDateTime(currentDraft.meetingTime) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="鍒涘缓鏃堕棿">{{ currentDraft.createTime }}</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="content-section mt-20">
+          <h4>鍙備細浜哄憳</h4>
+          <div class="participants-list">
+            {{ currentDraft.participantList }}
+          </div>
+        </div>
+
+        <div class="content-section mt-20">
+          <h4>浼氳璇存槑</h4>
+          <div class="meeting-description">{{ currentDraft.description }}</div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="detailDialogVisible = false">鍏� 闂�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 鏂板缓/缂栬緫鑽夌瀵硅瘽妗� -->
+    <el-dialog
+      :title="dialogTitle"
+      v-model="editDialogVisible"
+      width="700px"
+    >
+      <el-form :model="meetingForm" :rules="rules" ref="meetingFormRef" label-width="100px">
+        <el-form-item label="浼氳涓婚" prop="title">
+          <el-input v-model="meetingForm.title" placeholder="璇疯緭鍏ヤ細璁富棰�" />
+        </el-form-item>
+        <el-form-item label="浼氳瀹�" prop="room">
+          <el-select v-model="meetingForm.roomId" placeholder="璇烽�夋嫨浼氳瀹�" style="width: 100%">
+            <el-option v-for="(v,k) in roomList" :label="v.name" :value="v.id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="涓绘寔浜�" prop="host">
+          <el-input v-model="meetingForm.host" placeholder="璇疯緭鍏ヤ富鎸佷汉" />
+        </el-form-item>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浼氳鏃ユ湡" prop="meetingDate">
+              <el-date-picker
+                v-model="meetingForm.meetingDate"
+                type="date"
+                placeholder="璇烽�夋嫨浼氳鏃ユ湡"
+                value-format="YYYY-MM-DD"
+                format="YYYY-MM-DD"
+                :disabled-date="disabledDate"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <!-- 绌哄垪锛屼繚鎸佸竷灞� -->
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="寮�濮嬫椂闂�" prop="startTime">
+              <el-select
+                v-model="meetingForm.startTime"
+                placeholder="璇烽�夋嫨寮�濮嬫椂闂�"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="time in timeOptions"
+                  :key="time.value"
+                  :label="time.label"
+                  :value="time.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="缁撴潫鏃堕棿" prop="endTime">
+              <el-select
+                v-model="meetingForm.endTime"
+                placeholder="璇烽�夋嫨缁撴潫鏃堕棿"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="time in timeOptions"
+                  :key="time.value"
+                  :label="time.label"
+                  :value="time.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="鍙備細浜烘暟" prop="participants">
+          <el-input
+              v-model="meetingForm.participants"
+              type="number"
+              placeholder="璇疯緭鍏ュ弬浼氫汉鏁�"
+          />
+        </el-form-item>
+        <el-form-item label="鍙備細浜哄憳" prop="participants">
+          <el-input
+            v-model="meetingForm.participantList"
+            type="textarea"
+            :rows="3"
+            placeholder="璇疯緭鍏ュ弬浼氫汉鍛橈紝鐢ㄩ�楀彿鍒嗛殧"
+          />
+        </el-form-item>
+        <el-form-item label="浼氳璇存槑">
+          <el-input
+            v-model="meetingForm.description"
+            type="textarea"
+            :rows="4"
+            placeholder="璇疯緭鍏ヤ細璁鏄�"
+          />
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="editDialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="submitForm">淇� 瀛�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Plus } from '@element-plus/icons-vue'
+import Pagination from '@/components/Pagination/index.vue'
+import {getRoomEnum,getDraftList,saveDraft,delDraft} from '@/api/collaborativeApproval/meeting.js'
+import dayjs from "dayjs";
+// 鏁版嵁鍒楄〃鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 鎬绘潯鏁�
+const total = ref(0)
+
+// 鑽夌鍒楄〃鏁版嵁
+const draftList = ref([])
+
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+  current: 1,
+  size: 10
+})
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  title: '',
+  meetingDate: ''
+})
+
+// 鏄惁鏄剧ず瀵硅瘽妗�
+const detailDialogVisible = ref(false)
+const editDialogVisible = ref(false)
+
+const roomList = ref([])
+
+// 瀵硅瘽妗嗘爣棰�
+const dialogTitle = ref('')
+
+// 褰撳墠鏌ョ湅鐨勮崏绋�
+const currentDraft = ref(null)
+
+// 琛ㄥ崟寮曠敤
+const meetingFormRef = ref(null)
+
+// 鏃堕棿閫夐」锛堜互鍗婂皬鏃朵负闂撮殧锛屽伐浣滄椂闂�8:00-18:00锛�
+const timeOptions = ref([])
+
+// 琛ㄥ崟鏁版嵁
+const meetingForm = reactive({
+  id: '',
+  meetingId: '',
+  title: '',
+  roomId: '',
+  host: '',
+  meetingDate: '',
+  startTime: '',
+  endTime: '',
+  participants: 0,
+  participantList: '',
+  description: '',
+  createTime: ''
+})
+
+// 琛ㄥ崟鏍¢獙瑙勫垯
+const rules = {
+  title: [{ required: true, message: '璇疯緭鍏ヤ細璁富棰�', trigger: 'blur' }],
+  roomId: [{ required: true, message: '璇烽�夋嫨浼氳瀹�', trigger: 'change' }],
+  host: [{ required: true, message: '璇疯緭鍏ヤ富鎸佷汉', trigger: 'blur' }],
+  meetingDate: [{ required: true, message: '璇烽�夋嫨浼氳鏃ユ湡', trigger: 'change' }],
+  startTime: [{ required: true, message: '璇烽�夋嫨寮�濮嬫椂闂�', trigger: 'change' }],
+  endTime: [{ required: true, message: '璇烽�夋嫨缁撴潫鏃堕棿', trigger: 'change' }]
+}
+
+// 鍒濆鍖栨椂闂撮�夐」锛堜互鍗婂皬鏃朵负闂撮殧锛屽伐浣滄椂闂�8:00-18:00锛�
+const initTimeOptions = () => {
+  const options = []
+  for (let hour = 8; hour <= 18; hour++) {
+    // 姣忎釜灏忔椂娣诲姞涓や釜閫夐」锛氭暣鐐瑰拰鍗婄偣
+    options.push({
+      value: `${hour.toString().padStart(2, '0')}:00`,
+      label: `${hour.toString().padStart(2, '0')}:00`
+    })
+
+    if (hour < 18) { // 18:00涔嬪悗娌℃湁鍗婄偣閫夐」
+      options.push({
+        value: `${hour.toString().padStart(2, '0')}:30`,
+        label: `${hour.toString().padStart(2, '0')}:30`
+      })
+    }
+  }
+  timeOptions.value = options
+}
+
+// 绂佺敤鏃ユ湡锛堢鐢ㄤ粖澶╀箣鍓嶇殑鏃ユ湡锛�
+const disabledDate = (time) => {
+  // 绂佺敤浠婂ぉ涔嬪墠鐨勬棩鏈�
+  return time.getTime() < Date.now() - 86400000
+}
+
+// 鏌ヨ鏁版嵁
+const getList = async () => {
+  loading.value = true
+
+  let resp = await getDraftList({...queryParams,...searchForm})
+  queryParams.current = resp.data.current
+  draftList.value = resp.data.records.map(it=>{
+    it.room = roomList.value.find(room=>it.roomId===room.id).name ?? ""
+    it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format("HH:mm")} ~ ${dayjs(it.endTime).format("HH:mm")}`
+    return it
+  })
+
+  loading.value = false
+
+}
+
+// 鎼滅储鎸夐挳鎿嶄綔
+const handleSearch = () => {
+  queryParams.pageNum = 1
+  getList()
+}
+
+// 閲嶇疆鎼滅储琛ㄥ崟
+const resetSearch = () => {
+  Object.assign(searchForm, {
+    title: '',
+    createTime: []
+  })
+  handleSearch()
+}
+
+// 娣诲姞鎸夐挳鎿嶄綔
+const handleAdd = () => {
+  dialogTitle.value = '鏂板缓鑽夌'
+  resetForm()
+  editDialogVisible.value = true
+}
+
+// 鏌ョ湅鑽夌璇︽儏
+const viewDraft = (row) => {
+  currentDraft.value = row
+  detailDialogVisible.value = true
+}
+
+// 缂栬緫鑽夌
+const editDraft = (row) => {
+  dialogTitle.value = '缂栬緫鑽夌'
+  Object.assign(meetingForm, {
+    id: row.id,
+    meetingId: row.meetingId,
+    title: row.title,
+    room: row.room,
+    roomId: row.id,
+    host: row.host,
+    meetingDate: row.meetingTime.split(' ')[0],
+    startTime: row.meetingTime.split(' ')[1],
+    endTime: row.meetingTime.split(' ')[3],
+    participants: row.participants,
+    participantList: row.participantList,
+    description: row.description,
+    createTime: row.createTime
+  })
+  editDialogVisible.value = true
+}
+
+// 鍒犻櫎鑽夌
+const deleteDraft = (row) => {
+  ElMessageBox.confirm(
+    `纭鍒犻櫎浼氳鑽夌 "${row.title}"?`,
+    '鍒犻櫎鑽夌',
+    {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    }
+  ).then(() => {
+    delDraft(row.id).then(resp=>{
+      ElMessage.success('鑽夌鍒犻櫎鎴愬姛')
+      getList()
+    })
+
+  }).catch(() => {})
+}
+
+// 閲嶇疆琛ㄥ崟
+const resetForm = () => {
+  Object.assign(meetingForm, {
+    id: '',
+    meetingId: '',
+    title: '',
+    room: '',
+    host: '',
+    meetingDate: '',
+    startTime: '',
+    endTime: '',
+    participants: 0,
+    participantList: '',
+    description: '',
+    createTime: ''
+  })
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  meetingFormRef.value.validate((valid) => {
+    if (valid) {
+      let formData = {...meetingForm}
+      formData.startTime = dayjs(meetingForm.meetingDate + ' ' + meetingForm.startTime).format("YYYY-MM-DD HH:mm:ss")
+      formData.endTime = dayjs(meetingForm.meetingDate + ' ' + meetingForm.endTime).format("YYYY-MM-DD HH:mm:ss")
+      saveDraft(formData).then(()=>{
+        ElMessage.success('淇濆瓨鎴愬姛')
+        editDialogVisible.value = false
+        getList()
+      })
+    }
+  })
+}
+
+// 鏍煎紡鍖栨棩鏈熸椂闂�
+const formatDateTime = (dateTime) => {
+  if (!dateTime) return ''
+  return dateTime.replace(' ', '\n')
+}
+
+// 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
+onMounted(() => {
+  initTimeOptions()
+  getList()
+  getRoomEnum().then((res) => {
+    roomList.value = res.data
+  })
+})
+</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;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.content-section h4 {
+  margin: 0 0 15px 0;
+  color: #303133;
+}
+
+.mt-20 {
+  margin-top: 20px;
+}
+
+.participants-list {
+  min-height: 40px;
+  padding: 15px;
+  border-radius: 4px;
+  line-height: 1.6;
+}
+
+.meeting-description {
+  padding: 15px;
+  border-radius: 4px;
+  line-height: 1.6;
+  white-space: pre-wrap;
+}
+</style>
diff --git a/src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue b/src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue
new file mode 100644
index 0000000..0883ec3
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/meetExamine/index.vue
@@ -0,0 +1,418 @@
+<template>
+  <div class="app-container">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <h2>浼氳瀹℃壒</h2>
+    </div>
+
+    <!-- 鎼滅储鍖哄煙 -->
+    <el-card class="search-card">
+      <el-form :model="searchForm" inline>
+        <el-form-item label="浼氳涓婚">
+          <el-input v-model="searchForm.title" placeholder="璇疯緭鍏ヤ細璁富棰�" clearable/>
+        </el-form-item>
+        <el-form-item label="鐢宠浜�">
+          <el-input v-model="searchForm.applicant" placeholder="璇疯緭鍏ョ敵璇蜂汉" clearable/>
+        </el-form-item>
+        <el-form-item label="瀹℃壒鐘舵��">
+          <el-select style="width: 100px" v-model="searchForm.status" placeholder="璇烽�夋嫨瀹℃壒鐘舵��" clearable>
+            <el-option label="寰呭鎵�" value="0"/>
+            <el-option label="宸查�氳繃" value="1"/>
+            <el-option label="鏈鎵�" value="2"/>
+            <el-option label="宸插彇娑�" value="3"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 浼氳瀹℃壒鍒楄〃 -->
+    <el-card>
+      <el-table v-loading="loading" :data="approvalList" border>
+        <el-table-column prop="title" label="浼氳涓婚" align="center" min-width="200" show-overflow-tooltip/>
+        <el-table-column prop="applicant" label="鐢宠浜�" align="center" width="120"/>
+        <el-table-column prop="host" label="涓荤悊浜�" align="center" width="120"/>
+        <el-table-column prop="meetingTime" label="浼氳鏃堕棿" align="center" width="180">
+          <template #default="scope">
+            {{ formatDateTime(scope.row.meetingTime) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="location" label="浼氳鍦扮偣" align="center" width="150"/>
+        <el-table-column prop="participants" label="鍙備細浜烘暟" align="center" width="100">
+          <template #default="scope">
+            {{ scope.row.participants.length }}浜�
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="瀹℃壒鐘舵��" align="center" width="120">
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.status)">
+              {{ getStatusText(scope.row.status) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" align="center" width="200" fixed="right">
+          <template #default="scope">
+            <el-button type="primary" link @click="viewDetail(scope.row)">鏌ョ湅</el-button>
+            <el-button
+                v-if="scope.row.status == '0'"
+                type="primary"
+                link
+                @click="handleApproval(scope.row)"
+            >
+              瀹℃壒
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 鍒嗛〉 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.current"
+          v-model:limit="queryParams.size"
+          @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 浼氳璇︽儏瀵硅瘽妗� -->
+    <el-dialog
+        title="浼氳璇︽儏"
+        v-model="detailDialogVisible"
+        width="800px"
+    >
+      <div v-if="currentMeeting">
+         <el-descriptions label-width="100px" class="meeting-desc" :column="2" border>
+          <el-descriptions-item label="浼氳涓婚" label-class-name="nowrap-label">{{
+              currentMeeting.title
+            }}</el-descriptions-item>
+          <el-descriptions-item label="鐢宠浜�" label-class-name="nowrap-label">{{
+              currentMeeting.applicant
+            }}</el-descriptions-item>
+          <el-descriptions-item label="涓荤悊浜�" label-class-name="nowrap-label">{{
+              currentMeeting.host
+            }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿" :span="2" label-class-name="nowrap-label">
+            {{ formatDateTime(currentMeeting.meetingTime) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="浼氳鍦扮偣" label-class-name="nowrap-label">{{
+              currentMeeting.location
+            }}</el-descriptions-item>
+          <el-descriptions-item label="鍙備細浜烘暟" label-class-name="nowrap-label">{{
+              currentMeeting.participants.length
+            }}浜�</el-descriptions-item>
+          <el-descriptions-item label="瀹℃壒鐘舵��" label-class-name="nowrap-label">
+            <el-tag :type="getStatusType(currentMeeting.status)">
+              {{ getStatusText(currentMeeting.status) }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="鐢宠鏃堕棿" label-class-name="nowrap-label">{{
+              currentMeeting.createTime
+            }}</el-descriptions-item>
+          <el-descriptions-item style="max-height: 400px" label="浼氳璇存槑" :span="2"
+                                label-class-name="nowrap-label">{{ currentMeeting.description }}</el-descriptions-item>
+        </el-descriptions>
+
+
+        <div class="content-section mt-20">
+          <h4>鍙備細浜哄憳</h4>
+          <div class="participants-list">
+            <el-tag
+                v-for="participant in currentMeeting.participants"
+                :key="participant.id"
+                style="margin-right: 10px; margin-bottom: 10px;"
+            >
+              {{ participant.name }}
+            </el-tag>
+          </div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="detailDialogVisible = false">鍏� 闂�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 浼氳瀹℃壒瀵硅瘽妗� -->
+    <el-dialog
+        title="浼氳瀹℃壒"
+        v-model="approvalDialogVisible"
+    >
+      <div v-if="currentMeeting">
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="浼氳涓婚">{{ currentMeeting.title }}</el-descriptions-item>
+          <el-descriptions-item label="鐢宠浜�">{{ currentMeeting.applicant }}</el-descriptions-item>
+          <el-descriptions-item label="涓荤悊浜�">{{ currentMeeting.host }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿" :span="2">
+            {{ formatDateTime(currentMeeting.meetingTime) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="浼氳鍦扮偣">{{ currentMeeting.location }}</el-descriptions-item>
+          <el-descriptions-item label="鍙備細浜烘暟">{{ currentMeeting.participants.length }}浜�</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="content-section mt-20">
+          <h4>鍙備細浜哄憳</h4>
+          <div class="participants-list">
+            <el-tag
+                v-for="participant in currentMeeting.participants"
+                :key="participant.id"
+                style="margin-right: 10px; margin-bottom: 10px;"
+            >
+              {{ participant.name }}
+            </el-tag>
+          </div>
+        </div>
+
+        <div v-show="false" class="approval-opinion mt-20">
+          <h4>瀹℃壒鎰忚</h4>
+          <el-input
+              v-model="approvalOpinion"
+              type="textarea"
+              placeholder="璇疯緭鍏ュ鎵规剰瑙�"
+              :rows="4"
+          />
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="approvalDialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="danger" @click="submitApproval('2')">涓嶉�氳繃</el-button>
+          <el-button type="primary" @click="submitApproval('1')">閫� 杩�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref, reactive, onMounted} from 'vue'
+import {ElMessage, ElMessageBox} from 'element-plus'
+import Pagination from '@/components/Pagination/index.vue'
+import {getRoomEnum, getExamineList,saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js'
+import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
+import dayjs from "dayjs";
+
+// 鏁版嵁鍒楄〃鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 鎬绘潯鏁�
+const total = ref(0)
+const roomEnum = ref([])
+const staffList = ref([])
+// 瀹℃壒鍒楄〃鏁版嵁
+const approvalList = ref([])
+
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+  current: 1,
+  size: 10
+})
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  title: '',
+  applicant: '',
+  status: ''
+})
+
+// 鏄惁鏄剧ず瀵硅瘽妗�
+const detailDialogVisible = ref(false)
+const approvalDialogVisible = ref(false)
+
+// 褰撳墠鏌ョ湅鐨勪細璁�
+const currentMeeting = ref(null)
+
+// 瀹℃壒鎰忚
+const approvalOpinion = ref('')
+
+// 鏌ヨ鏁版嵁
+const getList = async () => {
+  loading.value = true
+  let resp = await getExamineList({...searchForm, ...queryParams})
+  approvalList.value = resp.data.records.map(it => {
+    let room = roomEnum.value.find(room => it.roomId === room.id)
+    it.location = `${room.name}(${room.location})`
+    let staffs = JSON.parse(it.participants)
+    it.staffCount = staffs.size
+    it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}`
+    it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => {
+      return {
+        id: staff.id,
+        name: `${staff.staffName}(${staff.postJob})`
+      }
+    })
+
+
+    return it
+  })
+  total.value = resp.data.total
+  loading.value = false
+}
+
+// 鎼滅储鎸夐挳鎿嶄綔
+const handleSearch = () => {
+  queryParams.pageNum = 1
+  getList()
+}
+
+// 閲嶇疆鎼滅储琛ㄥ崟
+const resetSearch = () => {
+  Object.assign(searchForm, {
+    title: '',
+    applicant: '',
+    status: ''
+  })
+  handleSearch()
+}
+
+// 鏌ョ湅璇︽儏
+const viewDetail = (row) => {
+  currentMeeting.value = row
+  detailDialogVisible.value = true
+}
+
+// 澶勭悊瀹℃壒
+const handleApproval = (row) => {
+  currentMeeting.value = row
+  approvalOpinion.value = ''
+  approvalDialogVisible.value = true
+}
+
+// 鑾峰彇鐘舵�佺被鍨�
+const getStatusType = (status) => {
+  const statusMap = {
+    '0': 'info',     // 寰呭鎵�
+    '1': 'success',  // 宸查�氳繃
+    '2': 'warning',  // 鏈�氳繃
+    '3': 'danger'   // 鍙栨秷
+  }
+  return statusMap[status] || 'info'
+}
+
+// 鑾峰彇鐘舵�佹枃鏈�
+const getStatusText = (status) => {
+  const statusMap = {
+    '0': '寰呭鎵�',
+    '1': '宸查�氳繃',
+    '2': '鏈�氳繃',
+    '3': '宸插彇娑�'
+  }
+  return statusMap[status] || '鏈煡'
+}
+
+// 鏍煎紡鍖栨棩鏈熸椂闂�
+const formatDateTime = (dateTime) => {
+  if (!dateTime) return ''
+  return dateTime.replace(' ', '\n')
+}
+
+// 鎻愪氦瀹℃壒
+const submitApproval = (status) => {
+  // if (status === 'approved' && !approvalOpinion.value.trim()) {
+  //   ElMessage.warning('璇峰~鍐欏鎵规剰瑙�')
+  //   return
+  // }
+
+  ElMessageBox.confirm(
+      `纭${status === '1' ? '閫氳繃' : '涓嶉�氳繃'}璇ヤ細璁敵璇凤紵`,
+      '瀹℃壒纭',
+      {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }
+  ).then(() => {
+    saveMeetingApplication({
+      id: currentMeeting.value.id,
+      status: status
+    }).then(resp=>{
+      // 鏇存柊浼氳鐘舵��
+      currentMeeting.value.status = status
+
+      ElMessage.success('瀹℃壒鎻愪氦鎴愬姛')
+      approvalDialogVisible.value = false
+      getList()
+    })
+
+  }).catch(() => {
+  })
+}
+
+// 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
+onMounted(async () => {
+  const [resp1, resp2]= await Promise.all([getRoomEnum(), getStaffOnJob()])
+  roomEnum.value = resp1.data
+  staffList.value = resp2.data
+
+  await getList()
+})
+</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;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.content-section h4 {
+  margin: 0 0 15px 0;
+  color: #303133;
+}
+
+.mt-20 {
+  margin-top: 20px;
+}
+
+.participants-list {
+  min-height: 40px;
+  padding: 15px;
+  border-radius: 4px;
+  line-height: 1.6;
+}
+
+.approval-opinion h4 {
+  margin: 0 0 15px 0;
+  color: #303133;
+}
+
+.nowrap-label {
+  white-space: nowrap !important;
+}
+
+.description-content {
+  white-space: pre-wrap;
+  word-wrap: break-word;
+  line-height: 1.6;
+  padding: 10px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  min-height: 60px;
+}
+</style>
diff --git a/src/views/collaborativeApproval/notificationManagement/meetIndex/index.vue b/src/views/collaborativeApproval/notificationManagement/meetIndex/index.vue
new file mode 100644
index 0000000..2e9d9a9
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/meetIndex/index.vue
@@ -0,0 +1,371 @@
+<template>
+  <div class="app-container">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <h2>浼氳瀹や娇鐢ㄦ煡璇�</h2>
+    </div>
+
+    <!-- 鏌ヨ鏉′欢 -->
+    <el-card class="search-card">
+      <el-form :model="queryForm" label-width="80px" inline>
+        <el-form-item label="鏌ヨ鏃ユ湡">
+          <el-date-picker
+              v-model="queryForm.meetingDate"
+              type="date"
+              placeholder="璇烽�夋嫨鏃ユ湡"
+              value-format="YYYY-MM-DD"
+              format="YYYY-MM-DD"
+              :clearable="false"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鏌ヨ</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 浼氳瀹や娇鐢ㄦ儏鍐� -->
+    <el-card class="table-container" :loading="loading">
+      <div class="time-table">
+        <!-- 琛ㄥご -->
+        <div class="table-header">
+          <div class="header-cell room-header">浼氳瀹�</div>
+          <div
+              v-for="timeSlot in timeSlots"
+              :key="timeSlot.value"
+              class="header-cell time-header"
+          >
+            {{ timeSlot.label }}
+          </div>
+        </div>
+
+        <!-- 琛ㄦ牸鍐呭 -->
+        <div class="table-body">
+          <div
+              v-for="room in roomUsage"
+              :key="room.id"
+              class="table-row"
+          >
+            <div class="cell room-cell">{{ room.name }}</div>
+            <div class="cells-container">
+              <template v-for="(cell, index) in generateMeetingCells(room)" :key="index">
+                <div
+                    class="cell content-cell"
+                    :class="[cell.type, `status-${cell.meeting?.status || '0'}`]"
+                    :style="{ flex: cell.span-0.2 }"
+                    @click="viewMeetingDetails(cell)"
+                >
+                  <div v-if="cell.type === 'meeting'" class="meeting-content">
+                    <div class="meeting-title">{{ cell.meeting.title }}</div>
+                    <div class="meeting-time">{{ cell.startTime }}-{{ cell.endTime }}</div>
+                  </div>
+                  <div v-else class="free-content">
+                    绌洪棽
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-card>
+
+    <!-- 浼氳璇︽儏瀵硅瘽妗� -->
+    <el-dialog
+        title="浼氳璇︽儏"
+        v-model="detailDialogVisible"
+        width="800px"
+    >
+      <div v-if="currentMeeting">
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="浼氳涓婚">{{ currentMeeting.title }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳瀹�">{{ currentMeeting.room }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿">{{ currentMeeting.time }}</el-descriptions-item>
+          <el-descriptions-item label="涓绘寔浜�">{{ currentMeeting.host }}</el-descriptions-item>
+          <el-descriptions-item label="鍙備細浜烘暟">{{ currentMeeting.participants }}浜�</el-descriptions-item>
+          <el-descriptions-item label="浼氳璇存槑">{{ currentMeeting.description }}</el-descriptions-item>
+        </el-descriptions>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="detailDialogVisible = false">鍏� 闂�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref, reactive, onMounted} from 'vue'
+import {ElMessage} from 'element-plus'
+import {getMeetingUseList} from "@/api/collaborativeApproval/meeting.js"
+import dayjs from "dayjs";
+
+// 鏌ヨ琛ㄥ崟
+const queryForm = reactive({
+  meetingDate: dayjs().format('YYYY-MM-DD')
+})
+let loading = ref(false)
+// 鏃堕棿娈碉紙浠ュ崐灏忔椂涓洪棿闅旓級
+const timeSlots = ref([])
+
+// 浼氳瀹や娇鐢ㄦ儏鍐�
+const roomUsage = ref([])
+
+// 褰撳墠鏌ョ湅鐨勪細璁�
+const currentMeeting = ref(null)
+
+// 鏄惁鏄剧ず璇︽儏瀵硅瘽妗�
+const detailDialogVisible = ref(false)
+
+// 鍒濆鍖栨椂闂存Ы锛堜互鍗婂皬鏃朵负闂撮殧锛屼粠8:00鍒�18:00锛�
+const initTimeSlots = () => {
+  const slots = []
+  for (let hour = 8; hour < 18; hour++) {
+    // 姣忎釜灏忔椂娣诲姞涓や釜鏃堕棿娈碉細鏁寸偣鍜屽崐鐐�
+    slots.push({
+      label: `${hour.toString().padStart(2, '0')}:00`,
+      value: `${hour.toString().padStart(2, '0')}:00`
+    })
+
+    if (hour < 18) { // 鍒�17:30涓烘
+      slots.push({
+        label: `${hour.toString().padStart(2, '0')}:30`,
+        value: `${hour.toString().padStart(2, '0')}:30`
+      })
+    }
+  }
+  timeSlots.value = slots
+}
+
+// 鐢熸垚浼氳瀹ょ殑鏃堕棿鍗曞厓鏍�
+const generateMeetingCells = (room) => {
+  const cells = []
+  const meetings = room.meetings || []
+  const occupiedSlots = new Set()
+
+  // 澶勭悊姣忎釜浼氳
+  for (const meeting of meetings) {
+
+    const startIdx = timeSlots.value.findIndex(slot => slot.value === meeting.startTime)
+    let endIdx = timeSlots.value.findIndex(slot => slot.value === meeting.endTime)
+    if (endIdx === -1) {
+      endIdx = timeSlots.value.length
+    }
+    console.log('endIdx111', endIdx)
+    if (startIdx !== -1 && endIdx !== -1) {
+      // 鏍囪琚崰鐢ㄧ殑鏃堕棿娈�
+      for (let i = startIdx; i < endIdx; i++) {
+        occupiedSlots.add(timeSlots.value[i].value)
+      }
+
+      // 鍒涘缓浼氳鍗曞厓鏍�
+      cells.push({
+        type: 'meeting',
+        meeting: meeting,
+        span: endIdx - startIdx,
+        startTime: meeting.startTime,
+        endTime: meeting.endTime
+      })
+    }
+  }
+
+  // 澶勭悊绌洪棽鏃堕棿娈�
+  for (let i = 0; i < timeSlots.value.length; i++) {
+    const slot = timeSlots.value[i]
+    if (!occupiedSlots.has(slot.value)) {
+      // 鏌ユ壘杩炵画鐨勭┖闂叉椂闂存
+      let span = 1
+      while (i + span < timeSlots.value.length &&
+      !occupiedSlots.has(timeSlots.value[i + span].value)) {
+        occupiedSlots.add(timeSlots.value[i + span].value)
+        span++
+      }
+
+      cells.push({
+        type: 'free',
+        span: span,
+        time: slot.value
+      })
+    }
+  }
+
+  // 鎸夋椂闂存帓搴�
+  cells.sort((a, b) => {
+    const timeA = a.startTime || a.time
+    const timeB = b.startTime || b.time
+    return timeSlots.value.findIndex(s => s.value === timeA) -
+        timeSlots.value.findIndex(s => s.value === timeB)
+  })
+  console.log('cells', cells)
+  return cells
+}
+
+// 鏌ョ湅浼氳璇︽儏
+const viewMeetingDetails = (cell) => {
+  if (cell && cell.type === 'meeting') {
+    currentMeeting.value = cell.meeting
+    detailDialogVisible.value = true
+  } else {
+    ElMessage.info('璇ユ椂闂存浼氳瀹ょ┖闂�')
+  }
+}
+
+// 鏌ヨ鎸夐挳鎿嶄綔
+const handleSearch = async () => {
+  loading.value = true
+  let resp = await getMeetingUseList({...queryForm})
+  roomUsage.value = resp.data
+  loading.value = false
+}
+
+// 閲嶇疆鎼滅储琛ㄥ崟
+const resetSearch = () => {
+  queryForm.date = dayjs().format('YYYY-MM-DD')
+}
+
+// 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
+onMounted(() => {
+  // 鍒濆鍖栨椂闂存Ы
+  initTimeSlots()
+
+  // 榛樿鏌ヨ浠婂ぉ鐨勬暟鎹�
+  const today = new Date()
+  queryForm.date = today.toISOString().split('T')[0]
+  handleSearch()
+})
+</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;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.table-container {
+  padding: 0;
+}
+
+.time-table {
+  width: 100%;
+  border-collapse: collapse;
+}
+
+.table-header {
+  display: flex;
+  border: 1px solid;
+}
+
+.table-row {
+  display: flex;
+  border: 1px solid #ebeef5;
+  border-top: none;
+}
+
+.header-cell {
+  padding: 12px 5px;
+  text-align: center;
+  font-weight: bold;
+  border-right: 1px solid;
+  min-height: 20px;
+}
+
+.room-header {
+  width: 120px;
+}
+
+.time-header {
+  flex: 1;
+}
+
+.cell {
+  padding: 15px 5px;
+  text-align: center;
+  border-right: 1px solid;
+  min-height: 20px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  word-break: break-word;
+  line-height: 1.2;
+}
+
+.room-cell {
+  width: 120px;
+  font-weight: bold;
+}
+
+.cells-container {
+  flex: 1;
+  display: flex;
+}
+
+.content-cell {
+  min-height: 60px;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.content-cell:hover {
+  opacity: 0.8;
+}
+
+.free {
+  color: #f56c6c;
+}
+
+.meeting {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.status-1 {
+  background-color: #fef0f0;
+  color: #d14646;
+}
+
+.status-0 {
+  background-color: #c7ddc8;
+  color: rgba(230, 162, 60, 0.29);
+}
+
+.meeting-content {
+  width: 100%;
+}
+
+.meeting-title {
+  font-weight: bold;
+  margin-bottom: 5px;
+}
+
+.meeting-time {
+  font-size: 12px;
+}
+
+.free-content {
+  color: #909399;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>
diff --git a/src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue b/src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue
new file mode 100644
index 0000000..3f0fc69
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/meetPublish/index.vue
@@ -0,0 +1,416 @@
+<template>
+  <div class="app-container">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <h2>浼氳鍙戝竷</h2>
+    </div>
+
+    <!-- 鎼滅储鍖哄煙 -->
+    <el-card class="search-card">
+      <el-form :model="searchForm" inline>
+        <el-form-item label="浼氳涓婚">
+          <el-input v-model="searchForm.title" placeholder="璇疯緭鍏ヤ細璁富棰�" clearable/>
+        </el-form-item>
+        <el-form-item label="鐢宠浜�">
+          <el-input v-model="searchForm.applicant" placeholder="璇疯緭鍏ョ敵璇蜂汉" clearable/>
+        </el-form-item>
+        <el-form-item label="鍙戝竷鐘舵��">
+          <el-select style="width: 100px" v-model="searchForm.status" placeholder="璇烽�夋嫨鍙戝竷鐘舵��" clearable>
+            <el-option label="寰呭彂甯�" value="0"/>
+            <el-option label="宸插彂甯�" value="1"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 浼氳鍙戝竷鍒楄〃 -->
+    <el-card>
+      <el-table v-loading="loading" :data="approvalList" border>
+        <el-table-column prop="title" label="浼氳涓婚" align="center" min-width="200" show-overflow-tooltip/>
+        <el-table-column prop="applicant" label="鐢宠浜�" align="center" width="120"/>
+        <el-table-column prop="host" label="涓荤悊浜�" align="center" width="120"/>
+        <el-table-column prop="meetingTime" label="浼氳鏃堕棿" align="center" width="180">
+          <template #default="scope">
+            {{ formatDateTime(scope.row.meetingTime) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="location" label="浼氳鍦扮偣" align="center" width="150"/>
+        <el-table-column prop="participants" label="鍙備細浜烘暟" align="center" width="100">
+          <template #default="scope">
+            {{ scope.row.participants.length }}浜�
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="鍙戝竷鐘舵��" align="center" width="120">
+          <template #default="scope">
+            <el-tag :type="getStatusType(scope.row.status)">
+              {{ getStatusText(scope.row.status) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" align="center" width="200" fixed="right">
+          <template #default="scope">
+            <el-button type="primary" link @click="viewDetail(scope.row)">鏌ョ湅</el-button>
+            <el-button
+                v-if="scope.row.status == '0'"
+                type="primary"
+                link
+                @click="handleApproval(scope.row)"
+            >
+              鍙戝竷
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 鍒嗛〉 -->
+      <pagination
+          v-show="total > 0"
+          :total="total"
+          v-model:page="queryParams.current"
+          v-model:limit="queryParams.size"
+          @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 浼氳璇︽儏瀵硅瘽妗� -->
+    <el-dialog
+        title="浼氳璇︽儏"
+        v-model="detailDialogVisible"
+        width="800px"
+    >
+      <div v-if="currentMeeting">
+         <el-descriptions label-width="100px" class="meeting-desc" :column="2" border>
+          <el-descriptions-item label="浼氳涓婚" label-class-name="nowrap-label">{{
+              currentMeeting.title
+            }}</el-descriptions-item>
+          <el-descriptions-item label="鐢宠浜�" label-class-name="nowrap-label">{{
+              currentMeeting.applicant
+            }}</el-descriptions-item>
+          <el-descriptions-item label="涓荤悊浜�" label-class-name="nowrap-label">{{
+              currentMeeting.host
+            }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿" :span="2" label-class-name="nowrap-label">
+            {{ formatDateTime(currentMeeting.meetingTime) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="浼氳鍦扮偣" label-class-name="nowrap-label">{{
+              currentMeeting.location
+            }}</el-descriptions-item>
+          <el-descriptions-item label="鍙備細浜烘暟" label-class-name="nowrap-label">{{
+              currentMeeting.participants.length
+            }}浜�</el-descriptions-item>
+          <el-descriptions-item label="鍙戝竷鐘舵��" label-class-name="nowrap-label">
+            <el-tag :type="getStatusType(currentMeeting.status)">
+              {{ getStatusText(currentMeeting.status) }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="鐢宠鏃堕棿" label-class-name="nowrap-label">{{
+              currentMeeting.createTime
+            }}</el-descriptions-item>
+          <el-descriptions-item style="max-height: 400px" label="浼氳璇存槑" :span="2"
+                                label-class-name="nowrap-label">{{ currentMeeting.description }}</el-descriptions-item>
+        </el-descriptions>
+
+
+        <div class="content-section mt-20">
+          <h4>鍙備細浜哄憳</h4>
+          <div class="participants-list">
+            <el-tag
+                v-for="participant in currentMeeting.participants"
+                :key="participant.id"
+                style="margin-right: 10px; margin-bottom: 10px;"
+            >
+              {{ participant.name }}
+            </el-tag>
+          </div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="detailDialogVisible = false">鍏� 闂�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 浼氳鍙戝竷瀵硅瘽妗� -->
+    <el-dialog
+        title="浼氳鍙戝竷"
+        v-model="approvalDialogVisible"
+    >
+      <div v-if="currentMeeting">
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="浼氳涓婚">{{ currentMeeting.title }}</el-descriptions-item>
+          <el-descriptions-item label="鐢宠浜�">{{ currentMeeting.applicant }}</el-descriptions-item>
+          <el-descriptions-item label="涓荤悊浜�">{{ currentMeeting.host }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿" :span="2">
+            {{ formatDateTime(currentMeeting.meetingTime) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="浼氳鍦扮偣">{{ currentMeeting.location }}</el-descriptions-item>
+          <el-descriptions-item label="鍙備細浜烘暟">{{ currentMeeting.participants.length }}浜�</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="content-section mt-20">
+          <h4>鍙備細浜哄憳</h4>
+          <div class="participants-list">
+            <el-tag
+                v-for="participant in currentMeeting.participants"
+                :key="participant.id"
+                style="margin-right: 10px; margin-bottom: 10px;"
+            >
+              {{ participant.name }}
+            </el-tag>
+          </div>
+        </div>
+
+        <div class="approval-opinion mt-20">
+          <h4>鍙戝竷鎰忚</h4>
+          <el-input
+              v-model="publishComment"
+              type="textarea"
+              placeholder="璇疯緭鍏ュ彂甯冩剰瑙�"
+              :rows="4"
+          />
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="approvalDialogVisible = false">鍙� 娑�</el-button>
+<!--          <el-button type="danger" @click="submitApproval('2')">涓嶉�氳繃</el-button>-->
+          <el-button type="primary" @click="submitApproval('1')">鍙� 甯�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref, reactive, onMounted} from 'vue'
+import {ElMessage, ElMessageBox} from 'element-plus'
+import Pagination from '@/components/Pagination/index.vue'
+import {getRoomEnum, getMeetingPublish,saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js'
+import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js";
+import dayjs from "dayjs";
+
+// 鏁版嵁鍒楄〃鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 鎬绘潯鏁�
+const total = ref(0)
+const roomEnum = ref([])
+const staffList = ref([])
+// 鍙戝竷鍒楄〃鏁版嵁
+const approvalList = ref([])
+
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+  current: 1,
+  size: 10
+})
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  title: '',
+  applicant: '',
+  status: ''
+})
+
+// 鏄惁鏄剧ず瀵硅瘽妗�
+const detailDialogVisible = ref(false)
+const approvalDialogVisible = ref(false)
+
+// 褰撳墠鏌ョ湅鐨勪細璁�
+const currentMeeting = ref(null)
+
+// 鍙戝竷鎰忚
+const publishComment = ref('')
+
+// 鏌ヨ鏁版嵁
+const getList = async () => {
+  loading.value = true
+  let resp = await getMeetingPublish({...searchForm, ...queryParams})
+  approvalList.value = resp.data.records.map(it => {
+    let room = roomEnum.value.find(room => it.roomId === room.id)
+    it.location = `${room.name}(${room.location})`
+    let staffs = JSON.parse(it.participants)
+    it.staffCount = staffs.size
+    it.status = it.publishStatus
+    it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}`
+    it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => {
+      return {
+        id: staff.id,
+        name: `${staff.staffName}(${staff.postJob})`
+      }
+    })
+
+
+    return it
+  })
+  total.value = resp.data.total
+  loading.value = false
+}
+
+// 鎼滅储鎸夐挳鎿嶄綔
+const handleSearch = () => {
+  queryParams.pageNum = 1
+  getList()
+}
+
+// 閲嶇疆鎼滅储琛ㄥ崟
+const resetSearch = () => {
+  Object.assign(searchForm, {
+    title: '',
+    applicant: '',
+    status: ''
+  })
+  handleSearch()
+}
+
+// 鏌ョ湅璇︽儏
+const viewDetail = (row) => {
+  currentMeeting.value = row
+  detailDialogVisible.value = true
+}
+
+// 澶勭悊鍙戝竷
+const handleApproval = (row) => {
+  currentMeeting.value = row
+  publishComment.value = ''
+  approvalDialogVisible.value = true
+}
+
+// 鑾峰彇鐘舵�佺被鍨�
+const getStatusType = (status) => {
+  const statusMap = {
+    '0': 'info',     // 寰呭彂甯�
+    '1': 'success',  // 宸查�氳繃
+    '2': 'danger',  // 鏈�氳繃
+  }
+  return statusMap[status] || 'info'
+}
+
+// 鑾峰彇鐘舵�佹枃鏈�
+const getStatusText = (status) => {
+  const statusMap = {
+    '0': '寰呭彂甯�',
+    '1': '宸插彂甯�',
+    '2': '宸插彇娑�',
+  }
+  return statusMap[status] || '鏈煡'
+}
+
+// 鏍煎紡鍖栨棩鏈熸椂闂�
+const formatDateTime = (dateTime) => {
+  if (!dateTime) return ''
+  return dateTime.replace(' ', '\n')
+}
+
+// 鎻愪氦鍙戝竷
+const submitApproval = (status) => {
+  // if (status === 'approved' && !publishComment.value.trim()) {
+  //   ElMessage.warning('璇峰~鍐欏彂甯冩剰瑙�')
+  //   return
+  // }
+
+  ElMessageBox.confirm(
+      `纭${status === '1' ? '鍙戝竷' : '鍙栨秷'}璇ヤ細璁紵`,
+      '鍙戝竷纭',
+      {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }
+  ).then(() => {
+    saveMeetingApplication({
+      id: currentMeeting.value.id,
+      publishStatus: status,
+      publishComment: publishComment.value
+    }).then(resp=>{
+      // 鏇存柊浼氳鐘舵��
+      currentMeeting.value.status = status
+
+      ElMessage.success('鍙戝竷鎻愪氦鎴愬姛')
+      approvalDialogVisible.value = false
+      getList()
+    })
+
+  }).catch(() => {
+  })
+}
+
+// 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
+onMounted(async () => {
+  const [resp1, resp2]= await Promise.all([getRoomEnum(), getStaffOnJob()])
+  roomEnum.value = resp1.data
+  staffList.value = resp2.data
+
+  await getList()
+})
+</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;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.content-section h4 {
+  margin: 0 0 15px 0;
+  color: #303133;
+}
+
+.mt-20 {
+  margin-top: 20px;
+}
+
+.participants-list {
+  min-height: 40px;
+  padding: 15px;
+  border-radius: 4px;
+  line-height: 1.6;
+}
+
+.approval-opinion h4 {
+  margin: 0 0 15px 0;
+  color: #303133;
+}
+
+.nowrap-label {
+  white-space: nowrap !important;
+}
+
+.description-content {
+  white-space: pre-wrap;
+  word-wrap: break-word;
+  line-height: 1.6;
+  padding: 10px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  min-height: 60px;
+}
+</style>
diff --git a/src/views/collaborativeApproval/notificationManagement/meetSetting/index.vue b/src/views/collaborativeApproval/notificationManagement/meetSetting/index.vue
new file mode 100644
index 0000000..c290be4
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/meetSetting/index.vue
@@ -0,0 +1,306 @@
+<template>
+  <div class="app-container">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <h2>浼氳瀹よ缃�</h2>
+      <el-button type="primary" @click="handleAdd">
+        <el-icon><Plus /></el-icon>
+        鏂板浼氳瀹�
+      </el-button>
+    </div>
+
+    <!-- 鎼滅储鍖哄煙 -->
+    <el-card class="search-card">
+      <el-form :model="searchForm" label-width="100px" inline>
+        <el-form-item label="浼氳瀹ゅ悕绉�">
+          <el-input v-model="searchForm.name" placeholder="璇疯緭鍏ヤ細璁鍚嶇О" clearable />
+        </el-form-item>
+        <el-form-item label="浣嶇疆">
+          <el-input v-model="searchForm.location" placeholder="璇疯緭鍏ヤ綅缃�" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 浼氳瀹ゅ垪琛� -->
+    <el-card>
+      <el-table v-loading="loading" :data="meetingRoomList" border>
+        <el-table-column prop="name" label="浼氳瀹ゅ悕绉�" align="center" />
+        <el-table-column prop="location" label="浣嶇疆" align="center" />
+        <el-table-column prop="capacity" label="瀹圭撼浜烘暟" align="center" />
+        <el-table-column prop="equipment" label="璁惧閰嶇疆" align="center">
+          <template #default="scope">
+            <el-tag v-for="item in scope.row.equipment" :key="item" style="margin-right: 5px; margin-bottom: 5px;">
+              {{ item }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="鐘舵��" align="center" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
+              {{ scope.row.status === 1 ? '鍚敤' : '绂佺敤' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" align="center" width="200">
+          <template #default="scope">
+            <el-button type="primary" link @click="handleEdit(scope.row)">缂栬緫</el-button>
+            <el-button type="danger" link @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 鍒嗛〉 -->
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.current"
+        v-model:limit="queryParams.size"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 娣诲姞/缂栬緫瀵硅瘽妗� -->
+    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="600px" @close="cancel">
+      <el-form ref="meetingRoomFormRef" :model="meetingRoomForm" :rules="rules" label-width="100px">
+        <el-form-item label="浼氳瀹ゅ悕绉�" prop="name">
+          <el-input v-model="meetingRoomForm.name" placeholder="璇疯緭鍏ヤ細璁鍚嶇О" />
+        </el-form-item>
+        <el-form-item label="浣嶇疆" prop="location">
+          <el-input v-model="meetingRoomForm.location" placeholder="璇疯緭鍏ヤ細璁浣嶇疆" />
+        </el-form-item>
+        <el-form-item label="瀹圭撼浜烘暟" prop="capacity">
+          <el-input-number v-model="meetingRoomForm.capacity" :min="1" placeholder="璇疯緭鍏ュ绾充汉鏁�" />
+        </el-form-item>
+        <el-form-item label="璁惧閰嶇疆" prop="equipment">
+          <el-select v-model="meetingRoomForm.equipment" multiple placeholder="璇烽�夋嫨璁惧閰嶇疆" style="width: 100%">
+            <el-option
+              v-for="item in equipmentOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鐘舵��" prop="status">
+          <el-radio-group v-model="meetingRoomForm.status">
+            <el-radio :label="1">鍚敤</el-radio>
+            <el-radio :label="0">绂佺敤</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="meetingRoomForm.remark" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="cancel">鍙� 娑�</el-button>
+          <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Plus } from '@element-plus/icons-vue'
+import Pagination from '@/components/Pagination/index.vue'
+import {getMeetingRoomList,saveRoom,delRoom} from '@/api/collaborativeApproval/meeting.js'
+
+// 鏁版嵁鍒楄〃鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 鎬绘潯鏁�
+const total = ref(0)
+
+// 浼氳瀹ゅ垪琛ㄦ暟鎹�
+const meetingRoomList = ref([])
+
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+  current: 1,
+  size: 10
+})
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  name: '',
+  location: ''
+})
+
+// 瀵硅瘽妗嗘爣棰�
+const dialogTitle = ref('')
+
+// 鏄惁鏄剧ず瀵硅瘽妗�
+const dialogVisible = ref(false)
+
+// 璁惧閰嶇疆閫夐」
+const equipmentOptions = ref([
+  { value: '鎶曞奖浠�', label: '鎶曞奖浠�' },
+  { value: '鐢佃', label: '鐢佃' },
+  { value: '闊冲搷', label: '闊冲搷' },
+  { value: '鐢佃瘽', label: '鐢佃瘽' },
+  { value: '瑙嗛浼氳绯荤粺', label: '瑙嗛浼氳绯荤粺' },
+  { value: '鐧芥澘', label: '鐧芥澘' },
+  { value: '鍐欏瓧鏉�', label: '鍐欏瓧鏉�' },
+  { value: '鏃犵嚎缃戠粶', label: '鏃犵嚎缃戠粶' }
+])
+
+// 琛ㄥ崟鏁版嵁
+const meetingRoomForm = reactive({
+  id: undefined,
+  name: '',
+  location: '',
+  capacity: 10,
+  equipment: [],
+  status: 1,
+  remark: ''
+})
+
+// 琛ㄥ崟鏍¢獙瑙勫垯
+const rules = {
+  name: [{ required: true, message: '浼氳瀹ゅ悕绉颁笉鑳戒负绌�', trigger: 'blur' }],
+  location: [{ required: true, message: '浣嶇疆涓嶈兘涓虹┖', trigger: 'blur' }],
+  capacity: [{ required: true, message: '瀹圭撼浜烘暟涓嶈兘涓虹┖', trigger: 'blur' }]
+}
+
+// 琛ㄥ崟寮曠敤
+const meetingRoomFormRef = ref(null)
+
+// 鏌ヨ鏁版嵁
+const getList = async () => {
+  loading.value = true
+
+  let resp = await getMeetingRoomList({...searchForm,...queryParams})
+  meetingRoomList.value = resp.data.records.map(it=>{
+    it.equipment = it.equipment.split(',')
+    return it;
+  })
+  total.value = resp.data.total
+  loading.value = false
+
+}
+
+// 鎼滅储鎸夐挳鎿嶄綔
+const handleSearch = () => {
+  queryParams.current = 1
+  getList()
+}
+
+// 閲嶇疆鎼滅储琛ㄥ崟
+const resetSearch = () => {
+  Object.assign(searchForm, {
+    name: '',
+    location: ''
+  })
+  handleSearch()
+}
+
+// 娣诲姞鎸夐挳鎿嶄綔
+const handleAdd = () => {
+  dialogTitle.value = '娣诲姞浼氳瀹�'
+  dialogVisible.value = true
+}
+
+// 淇敼鎸夐挳鎿嶄綔
+const handleEdit = (row) => {
+  dialogTitle.value = '淇敼浼氳瀹�'
+  Object.assign(meetingRoomForm, row)
+  dialogVisible.value = true
+}
+
+// 鍒犻櫎鎸夐挳鎿嶄綔
+const handleDelete = (row) => {
+  ElMessageBox.confirm(
+    `鏄惁纭鍒犻櫎浼氳瀹� "${row.name}"?`,
+    '璀﹀憡',
+    {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: 'warning'
+    }
+  ).then(() => {
+    // 妯℃嫙鍒犻櫎鎿嶄綔
+    delRoom(row.id).then(resp=>{
+      ElMessage.success('鍒犻櫎鎴愬姛')
+      getList()
+    })
+
+  }).catch(() => {})
+}
+
+// 鍙栨秷鎸夐挳
+const cancel = () => {
+  dialogVisible.value = false
+  reset()
+}
+
+// 琛ㄥ崟閲嶇疆
+const reset = () => {
+  Object.assign(meetingRoomForm, {
+    id: undefined,
+    name: '',
+    location: '',
+    capacity: 10,
+    equipment: [],
+    status: 1,
+    remark: ''
+  })
+  meetingRoomFormRef.value?.resetFields()
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  meetingRoomFormRef.value?.validate((valid) => {
+    if (valid) {
+      // 妯℃嫙鎻愪氦鎿嶄綔
+
+      let formData = {...  meetingRoomForm}
+      formData.equipment = formData.equipment.join(',')
+      saveRoom(formData).then(resp=>{
+        ElMessage.success('淇濆瓨鎴愬姛')
+        dialogVisible.value = false
+        getList()
+      })
+    }
+  })
+}
+
+// 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
+onMounted(() => {
+  getList()
+})
+</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;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>
diff --git a/src/views/collaborativeApproval/notificationManagement/summary/index.vue b/src/views/collaborativeApproval/notificationManagement/summary/index.vue
new file mode 100644
index 0000000..04eaa4a
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/summary/index.vue
@@ -0,0 +1,403 @@
+<template>
+  <div class="app-container">
+    <!-- 椤甸潰鏍囬 -->
+    <div class="page-header">
+      <h2>浼氳绾</h2>
+    </div>
+
+    <!-- 鎼滅储鍖哄煙 -->
+    <el-card class="search-card">
+      <el-form :model="searchForm" inline>
+        <el-form-item label="浼氳涓婚">
+          <el-input v-model="searchForm.title" placeholder="璇疯緭鍏ヤ細璁富棰�" clearable />
+        </el-form-item>
+        <el-form-item label="鐢宠浜�">
+          <el-input v-model="searchForm.applicant" placeholder="璇疯緭鍏ョ敵璇蜂汉" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">鎼滅储</el-button>
+          <el-button @click="resetSearch">閲嶇疆</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 浼氳鍒楄〃 -->
+    <el-card>
+      <el-table v-loading="loading" :data="meetingList" border>
+        <el-table-column prop="title" label="浼氳涓婚" align="center" min-width="200" show-overflow-tooltip />
+        <el-table-column prop="applicant" label="鐢宠浜�" align="center" width="120" />
+        <el-table-column prop="host" label="涓绘寔浜�" align="center" width="120" />
+        <el-table-column prop="meetingTime" label="浼氳鏃堕棿" align="center" width="180">
+          <template #default="scope">
+            {{ formatDateTime(scope.row.meetingTime) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="location" label="浼氳鍦扮偣" align="center" width="150" />
+        <el-table-column prop="participants" label="鍙備細浜烘暟" align="center" width="100">
+          <template #default="scope">
+            {{ scope.row.participants.length }}浜�
+          </template>
+        </el-table-column>
+        <el-table-column label="鎿嶄綔" align="center" width="200" fixed="right">
+          <template #default="scope">
+            <el-button type="primary" link @click="viewDetail(scope.row)">鏌ョ湅</el-button>
+            <el-button
+              type="primary"
+              link
+              @click="addMinutes(scope.row)"
+            >
+              娣诲姞绾
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 鍒嗛〉 -->
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.current"
+        v-model:limit="queryParams.size"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 浼氳璇︽儏瀵硅瘽妗� -->
+    <el-dialog
+      title="浼氳璇︽儏"
+      v-model="detailDialogVisible"
+      width="800px"
+    >
+      <div v-if="currentMeeting">
+        <el-descriptions label-width="100px" class="meeting-desc" :column="2" border>
+          <el-descriptions-item label="浼氳涓婚" label-class-name="nowrap-label">{{
+            currentMeeting.title
+          }}</el-descriptions-item>
+          <el-descriptions-item label="鐢宠浜�" label-class-name="nowrap-label">{{
+            currentMeeting.applicant
+          }}</el-descriptions-item>
+          <el-descriptions-item label="涓绘寔浜�" label-class-name="nowrap-label">{{
+            currentMeeting.host
+          }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿" :span="2" label-class-name="nowrap-label">
+            {{ formatDateTime(currentMeeting.meetingTime) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="浼氳鍦扮偣" label-class-name="nowrap-label">{{
+            currentMeeting.location
+          }}</el-descriptions-item>
+          <el-descriptions-item label="鍙備細浜烘暟" label-class-name="nowrap-label">{{
+            currentMeeting.participants.length
+          }}浜�</el-descriptions-item>
+          <el-descriptions-item label="瀹℃壒鐘舵��" label-class-name="nowrap-label">
+            <el-tag :type="getStatusType(currentMeeting.status)">
+              {{ getStatusText(currentMeeting.status) }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="鐢宠鏃堕棿" label-class-name="nowrap-label">{{
+            currentMeeting.createTime
+          }}</el-descriptions-item>
+          <el-descriptions-item style="max-height: 400px" label="浼氳璇存槑" :span="2"
+            label-class-name="nowrap-label">{{ currentMeeting.description }}</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="content-section mt-20">
+          <h4>鍙備細浜哄憳</h4>
+          <div class="participants-list">
+            <el-tag
+              v-for="participant in currentMeeting.participants"
+              :key="participant.id"
+              style="margin-right: 10px; margin-bottom: 10px;"
+            >
+              {{ participant.name }}
+            </el-tag>
+          </div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="detailDialogVisible = false">鍏� 闂�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 娣诲姞浼氳绾瀵硅瘽妗� -->
+    <el-dialog
+      title="娣诲姞浼氳绾"
+      v-model="minutesDialogVisible"
+      width="80%"
+      @close="handleCloseMinutesDialog"
+    >
+      <div v-if="currentMeeting">
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="浼氳涓婚">{{ currentMeeting.title }}</el-descriptions-item>
+          <el-descriptions-item label="鐢宠浜�">{{ currentMeeting.applicant }}</el-descriptions-item>
+          <el-descriptions-item label="涓绘寔浜�">{{ currentMeeting.host }}</el-descriptions-item>
+          <el-descriptions-item label="浼氳鏃堕棿" :span="2">
+            {{ formatDateTime(currentMeeting.meetingTime) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="浼氳鍦扮偣">{{ currentMeeting.location }}</el-descriptions-item>
+          <el-descriptions-item label="鍙備細浜烘暟">{{ currentMeeting.participants.length }}浜�</el-descriptions-item>
+        </el-descriptions>
+
+        <div class="content-section mt-20">
+          <h4>浼氳绾鍐呭</h4>
+          <div class="editor-container">
+            <Editor
+              v-model="minutesContent"
+              :min-height="400"
+            />
+          </div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="minutesDialogVisible = false">鍙� 娑�</el-button>
+          <el-button type="primary" @click="submitMinutes">淇� 瀛�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage } from 'element-plus'
+import Pagination from '@/components/Pagination/index.vue'
+import Editor from '@/components/Editor/index.vue'
+import { getRoomEnum, getMeetingPublish ,getMeetingMinutesByMeetingId,saveMeetingMinutes} from '@/api/collaborativeApproval/meeting.js'
+import { getStaffOnJob } from "@/api/personnelManagement/onboarding.js"
+import dayjs from "dayjs"
+
+// 鏁版嵁鍒楄〃鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 鎬绘潯鏁�
+const total = ref(0)
+const roomEnum = ref([])
+const staffList = ref([])
+
+// 浼氳鍒楄〃鏁版嵁
+const meetingList = ref([])
+
+// 鏌ヨ鍙傛暟
+const queryParams = reactive({
+  current: 1,
+  size: 10
+})
+
+// 鎼滅储琛ㄥ崟
+const searchForm = reactive({
+  title: '',
+  applicant: '',
+  // status: '1' // 榛樿鍙樉绀哄凡閫氳繃瀹℃壒鐨勪細璁�
+})
+
+// 鏄惁鏄剧ず瀵硅瘽妗�
+const detailDialogVisible = ref(false)
+const minutesDialogVisible = ref(false)
+
+// 褰撳墠鏌ョ湅鐨勪細璁�
+const currentMeeting = ref(null)
+
+// 浼氳绾鍐呭
+const minutesContent = ref('')
+const minutesContentId = ref('')
+
+// 鏌ヨ鏁版嵁
+const getList = async () => {
+  loading.value = true
+  let resp = await getMeetingPublish({ ...searchForm, ...queryParams })
+  meetingList.value = resp.data.records.map(it => {
+    let room = roomEnum.value.find(room => it.roomId === room.id)
+    it.location = `${room.name}(${room.location})`
+    let staffs = JSON.parse(it.participants)
+    it.staffCount = staffs.size
+    it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}`
+    it.participants = staffList.value.filter(staff => staffs.some(id => id === staff.id)).map(staff => {
+      return {
+        id: staff.id,
+        name: `${staff.staffName}(${staff.postJob})`
+      }
+    })
+
+    return it
+  })
+  total.value = resp.data.total
+  loading.value = false
+}
+
+// 鎼滅储鎸夐挳鎿嶄綔
+const handleSearch = () => {
+  queryParams.current = 1
+  getList()
+}
+
+// 閲嶇疆鎼滅储琛ㄥ崟
+const resetSearch = () => {
+  Object.assign(searchForm, {
+    title: '',
+    applicant: '',
+    // status: '1'
+  })
+  handleSearch()
+}
+
+// 鏌ョ湅璇︽儏
+const viewDetail = (row) => {
+  currentMeeting.value = row
+  detailDialogVisible.value = true
+}
+
+// 娣诲姞浼氳绾
+const addMinutes = async (row) => {
+  let resp = await getMeetingMinutesByMeetingId(row.id)
+  currentMeeting.value = row
+  if (resp.data){
+    minutesContent.value = resp.data.content
+    minutesContentId.value = resp.data.id
+  }else {
+    minutesContent.value = `<h2>${row.title}浼氳绾</h2>
+<p><strong>浼氳鏃堕棿锛�</strong>${row.meetingTime}</p>
+<p><strong>浼氳鍦扮偣锛�</strong>${row.location}</p>
+<p><strong>涓绘寔浜猴細</strong>${row.host}</p>
+<p><strong>鍙備細浜哄憳锛�</strong></p>
+<ol>
+  ${row.participants.map(p => `<li>${p.name}</li>`).join('')}
+</ol>
+<p><strong>浼氳鍐呭锛�</strong></p>
+<ol>
+  <li>璁涓�锛�
+    <ul>
+      <li>璁ㄨ鍐呭锛�</li>
+      <li>鍐宠浜嬮」锛�</li>
+    </ul>
+  </li>
+  <li>璁浜岋細
+    <ul>
+      <li>璁ㄨ鍐呭锛�</li>
+      <li>鍐宠浜嬮」锛�</li>
+    </ul>
+  </li>
+</ol>
+<p><strong>澶囨敞锛�</strong></p>`
+  }
+
+  minutesDialogVisible.value = true
+}
+
+// 鎻愪氦浼氳绾
+const submitMinutes = () => {
+  if (!minutesContent.value) {
+    ElMessage.warning('璇疯緭鍏ヤ細璁邯瑕佸唴瀹�')
+    return
+  }
+  saveMeetingMinutes({
+    id: minutesContentId.value,
+    content: minutesContent.value,
+    meetingId: currentMeeting.value.id,
+    title: currentMeeting.value.title
+  }).then(resp=>{
+    console.log('浼氳绾鍐呭:', minutesContent.value)
+    ElMessage.success('浼氳绾淇濆瓨鎴愬姛')
+    minutesDialogVisible.value = false
+  })
+
+}
+
+// 鍏抽棴浼氳绾瀵硅瘽妗�
+const handleCloseMinutesDialog = () => {
+  minutesContent.value = ''
+}
+
+// 鑾峰彇鐘舵�佺被鍨�
+const getStatusType = (status) => {
+  const statusMap = {
+    '0': 'info',     // 寰呭鎵�
+    '1': 'success',  // 宸查�氳繃
+    '2': 'warning',  // 鏈�氳繃
+    '3': 'danger'   // 鍙栨秷
+  }
+  return statusMap[status] || 'info'
+}
+
+// 鑾峰彇鐘舵�佹枃鏈�
+const getStatusText = (status) => {
+  const statusMap = {
+    '0': '寰呭鎵�',
+    '1': '宸查�氳繃',
+    '2': '鏈�氳繃',
+    '3': '宸插彇娑�'
+  }
+  return statusMap[status] || '鏈煡'
+}
+
+// 鏍煎紡鍖栨棩鏈熸椂闂�
+const formatDateTime = (dateTime) => {
+  if (!dateTime) return ''
+  return dateTime.replace(' ', '\n')
+}
+
+// 椤甸潰鍔犺浇鏃惰幏鍙栨暟鎹�
+onMounted(async () => {
+  const [resp1, resp2] = await Promise.all([getRoomEnum(), getStaffOnJob()])
+  roomEnum.value = resp1.data
+  staffList.value = resp2.data
+
+  await getList()
+})
+</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;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.content-section h4 {
+  margin: 0 0 15px 0;
+  color: #303133;
+}
+
+.mt-20 {
+  margin-top: 20px;
+}
+
+.participants-list {
+  min-height: 40px;
+  padding: 15px;
+  border-radius: 4px;
+  line-height: 1.6;
+}
+
+.nowrap-label {
+  white-space: nowrap !important;
+}
+
+.editor-container {
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+}
+</style>

--
Gitblit v1.9.3