From 0a9cbe6987b2d7e237a011f8a45f6f09cf7e6bce Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期二, 13 一月 2026 11:02:55 +0800
Subject: [PATCH] fix: 公告类型字段,另加一个配置功能(类似字典功能),并且也作为消息通知通知到每个人

---
 src/views/collaborativeApproval/noticeManagement/index.vue |  705 ++++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 483 insertions(+), 222 deletions(-)

diff --git a/src/views/collaborativeApproval/noticeManagement/index.vue b/src/views/collaborativeApproval/noticeManagement/index.vue
index 16cee35..6b0ea98 100644
--- a/src/views/collaborativeApproval/noticeManagement/index.vue
+++ b/src/views/collaborativeApproval/noticeManagement/index.vue
@@ -2,162 +2,91 @@
   <div class="app-container">
     <!-- 鎼滅储琛ㄥ崟 -->
     <div class="search_form">
-      <!--      <div>-->
-      <!--        <span class="search_title">鍏憡鏍囬锛�</span>-->
-      <!--        <el-input-->
-      <!--            v-model="searchForm.title"-->
-      <!--            style="width: 240px"-->
-      <!--            placeholder="璇疯緭鍏ュ叕鍛婃爣棰樻悳绱�"-->
-      <!--            @change="handleQuery"-->
-      <!--            clearable-->
-      <!--            :prefix-icon="Search"-->
-      <!--        />-->
-      <!--        <span class="search_title ml10">鍏憡绫诲瀷锛�</span>-->
-      <!--        <el-select v-model="searchForm.type" clearable @change="handleQuery" style="width: 240px">-->
-      <!--          <el-option label="鏀惧亣閫氱煡" :value="1"/>-->
-      <!--          <el-option label="璁惧缁翠慨閫氱煡" :value="2"/>-->
-      <!--        </el-select>-->
-      <!--        <span class="search_title ml10">鐘舵�侊細</span>-->
-      <!--        <el-select v-model="searchForm.status" clearable @change="handleQuery" style="width: 240px">-->
-      <!--          <el-option label="鑽夌" :value="0"/>-->
-      <!--          <el-option label="宸插彂甯�" :value="1"/>-->
-      <!--          <el-option label="宸蹭笅绾�" :value="2"/>-->
-      <!--        </el-select>-->
-      <!--        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>-->
-      <!--        <el-button @click="resetQuery" style="margin-left: 10px">閲嶇疆</el-button>-->
-      <!--      </div>-->
       <div>
         <el-button type="primary" @click="openForm('add')">鏂板鍏憡</el-button>
-        <el-button type="danger" plain @click="handleDelete" :disabled="!selectedIds.length">鍒犻櫎</el-button>
+        <el-button type="info" @click="openNoticeTypeDialog">鍏憡绫诲瀷閰嶇疆</el-button>
       </div>
     </div>
 
     <!-- 閫氱煡鍏憡鏉� -->
     <div class="notice-board">
-      <!-- 鏀惧亣閫氱煡鍖哄煙 -->
-      <div class="notice-section" v-if="holidayNoticeCount > 0">
-        <div class="section-header">
-          <h3>馃搮 鏀惧亣閫氱煡</h3>
-          <span class="section-count">{{ holidayNoticeCount }}鏉�</span>
-        </div>
-        <div class="notice-cards">
-          <div
-              v-for="notice in holidayNotices"
-              :key="notice.id"
-              class="notice-card holiday-card"
-              :class="{ 'urgent': notice.priority === '3' }"
-          >
-            <div class="card-header">
-              <div class="card-title">
-                <el-icon class="holiday-icon">
-                  <Calendar/>
-                </el-icon>
-                {{ notice.title }}
-              </div>
-              <div class="card-actions">
-                <el-button link type="primary" @click="handleEdit(notice)">缂栬緫</el-button>
-                <el-button link type="danger" @click="handleDelete(notice.id)">鍒犻櫎</el-button>
+      <el-tabs v-model="activeNoticeTypeTab" @tab-change="handleNoticeTypeTabChange">
+        <el-tab-pane
+            v-for="noticeType in noticeTypeList"
+            :key="noticeType.id"
+            :label="noticeType.noticeType"
+            :name="String(noticeType.id)"
+        >
+          <template #label>
+            <span>{{ noticeType.noticeType }}
+              <span class="tab-count" v-if="getNoticeCountByType(noticeType.id) > 0">
+                ({{ getNoticeCountByType(noticeType.id) }})
+              </span>
+            </span>
+          </template>
+          
+          <div class="notice-section">
+            <div class="notice-cards">
+              <div
+                  v-for="notice in getNoticesByType(noticeType.id)"
+                  :key="notice.id"
+                  class="notice-card"
+                  :class="{ 'urgent': notice.priority === '3' }"
+              >
+                <div class="card-header">
+                  <div class="card-title">
+                    <el-icon class="notice-icon">
+                      <Calendar/>
+                    </el-icon>
+                    {{ notice.title }}
+                  </div>
+                  <div class="card-actions">
+                    <el-button link type="primary" @click="handleEdit(notice)" :disabled="isNoticeExpired(notice)" v-if="notice.status !== 1">缂栬緫</el-button>
+                    <el-button link type="success" @click="handlePublish(notice)" v-if="notice.status === 0">鍙戝竷</el-button>
+                    <el-button link type="danger" @click="handleDelete(notice.id)" v-if="notice.status !== 1">鍒犻櫎</el-button>
+                  </div>
+                </div>
+                <div class="card-content">
+                  <p>{{ notice.content }}</p>
+                </div>
+                <div class="card-footer">
+                  <div class="card-meta">
+                    <span class="priority" :class="'priority-' + notice.priority">
+                      {{ getPriorityText(notice.priority) }}
+                    </span>
+                    <span class="status" :class="'status-' + getNoticeStatus(notice)">
+                      {{ getStatusText(getNoticeStatus(notice)) }}
+                    </span>
+                  </div>
+                  <div class="card-info">
+                    <span class="creator">{{ notice.createUserName }}</span>
+                    <span class="expiration" v-if="notice.expirationDate">鎴鏃ユ湡锛歿{ notice.expirationDate }}</span>
+                  </div>
+                </div>
+                <div class="card-remark" v-if="notice.remark">
+                  <el-icon>
+                    <InfoFilled/>
+                  </el-icon>
+                  <span>{{ notice.remark }}</span>
+                </div>
               </div>
             </div>
-            <div class="card-content">
-              <p>{{ notice.content }}</p>
-            </div>
-            <div class="card-footer">
-              <div class="card-meta">
-                <span class="priority" :class="'priority-' + notice.priority">
-                  {{ getPriorityText(notice.priority) }}
-                </span>
-                <span class="status" :class="'status-' + notice.status">
-                  {{ getStatusText(notice.status) }}
-                </span>
-              </div>
-              <div class="card-info">
-                <span class="creator">{{ notice.createUserName }}</span>
-                <span class="time">{{ notice.createTime }}</span>
-              </div>
-            </div>
-            <div class="card-remark" v-if="notice.remark">
-              <el-icon>
-                <InfoFilled/>
-              </el-icon>
-              <span>{{ notice.remark }}</span>
+            
+            <pagination
+                v-if="getNoticePageByType(noticeType.id).total > 0"
+                :total="getNoticePageByType(noticeType.id).total"
+                :page="getNoticePageByType(noticeType.id).current"
+                :limit="getNoticePageByType(noticeType.id).size"
+                @pagination="(val) => handleNoticeCurrentChange(noticeType.id, val)"
+            />
+            
+            <!-- 绌虹姸鎬� -->
+            <div class="empty-state" v-if="getNoticesByType(noticeType.id).length === 0">
+              <el-empty description="鏆傛棤閫氱煡鍏憡"/>
             </div>
           </div>
-        </div>
-      </div>
-
-      <pagination
-          v-if="holidayNoticePage.total > 0"
-          :total="holidayNoticePage.total"
-          :page="holidayNoticePage.current"
-          :limit="holidayNoticePage.size"
-          @pagination="handleHolidayNoticeCurrentChange"
-      />
-
-      <!-- 璁惧缁翠慨閫氱煡鍖哄煙 -->
-      <div class="notice-section" v-if="maintenanceNoticeCount > 0">
-        <div class="section-header">
-          <h3>馃敡 璁惧缁翠慨閫氱煡</h3>
-          <span class="section-count">{{ maintenanceNoticeCount }}鏉�</span>
-        </div>
-        <div class="notice-cards">
-          <div
-              v-for="notice in maintenanceNotices"
-              :key="notice.id"
-              class="notice-card maintenance-card"
-              :class="{ 'urgent': notice.priority === '3' }"
-          >
-            <div class="card-header">
-              <div class="card-title">
-                <el-icon class="maintenance-icon">
-                  <Tools/>
-                </el-icon>
-                {{ notice.title }}
-              </div>
-              <div class="card-actions">
-                <el-button link type="primary" @click="handleEdit(notice)">缂栬緫</el-button>
-                <el-button link type="danger" @click="handleDelete(notice.id)">鍒犻櫎</el-button>
-              </div>
-            </div>
-            <div class="card-content">
-              <p>{{ notice.content }}</p>
-            </div>
-            <div class="card-footer">
-              <div class="card-meta">
-                <span class="priority" :class="'priority-' + notice.priority">
-                  {{ getPriorityText(notice.priority) }}
-                </span>
-                <span class="status" :class="'status-' + notice.status">
-                  {{ getStatusText(notice.status) }}
-                </span>
-              </div>
-              <div class="card-info">
-                <span class="creator">{{ notice.createUserName }}</span>
-                <span class="time">{{ notice.createTime }}</span>
-              </div>
-            </div>
-            <div class="card-remark" v-if="notice.remark">
-              <el-icon>
-                <InfoFilled/>
-              </el-icon>
-              <span>{{ notice.remark }}</span>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      <pagination
-          v-if="maintenanceNoticePage.total > 0"
-          :total="maintenanceNoticePage.total"
-          :page="maintenanceNoticePage.current"
-          :limit="maintenanceNoticePage.size"
-          @pagination="handleMaintenanceNoticeCurrentChange"
-      />
-
-      <!-- 绌虹姸鎬� -->
-      <div class="empty-state" v-if="holidayNotices.length === 0 && maintenanceNotices.length === 0">
-        <el-empty description="鏆傛棤閫氱煡鍏憡"/>
-      </div>
+        </el-tab-pane>
+      </el-tabs>
     </div>
 
     <!-- 鏂板/缂栬緫瀵硅瘽妗� -->
@@ -178,8 +107,12 @@
           <el-col :span="12">
             <el-form-item label="鍏憡绫诲瀷" prop="type">
               <el-select v-model="form.type" placeholder="璇烽�夋嫨鍏憡绫诲瀷" style="width: 100%">
-                <el-option label="鏀惧亣閫氱煡" :value="1"/>
-                <el-option label="璁惧缁翠慨閫氱煡" :value="2"/>
+                <el-option
+                    v-for="item in noticeTypeList"
+                    :key="item.id"
+                    :label="item.noticeType"
+                    :value="item.id"
+                />
               </el-select>
             </el-form-item>
           </el-col>
@@ -189,8 +122,7 @@
             <el-form-item label="鐘舵��">
               <el-radio-group v-model="form.status">
                 <el-radio :value="0">鑽夌</el-radio>
-                <el-radio :value="1">宸插彂甯�</el-radio>
-                <el-radio :value="2">宸蹭笅绾�</el-radio>
+                <el-radio :value="1">姝e紡鍙戝竷</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -205,8 +137,16 @@
           </el-col>
         </el-row>
         <el-row>
+          <el-col :span="12">
+            <el-form-item label="杩囨湡鏃堕棿" prop="expirationDate">
+							<el-date-picker  v-model="form.expirationDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date"
+															 placeholder="璇烽�夋嫨" clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
           <el-col :span="24">
-            <el-form-item label="鍏憡鍐呭" prop="noticeContent">
+            <el-form-item label="鍏憡鍐呭" prop="content">
               <el-input
                   v-model="form.content"
                   type="textarea"
@@ -240,24 +180,96 @@
         </div>
       </template>
     </el-dialog>
+
+    <!-- 鍏憡绫诲瀷閰嶇疆寮规 -->
+    <el-dialog
+        v-model="noticeTypeDialogVisible"
+        title="鍏憡绫诲瀷閰嶇疆"
+        width="800px"
+        @close="handleNoticeTypeDialogClose"
+    >
+      <div class="notice-type-container">
+        <div class="notice-type-header">
+          <el-button type="primary" @click="handleAddNoticeType">鏂板绫诲瀷</el-button>
+        </div>
+        <el-table :data="noticeTypeList" border style="width: 100%">
+          <el-table-column prop="id" label="ID" width="80" align="center"/>
+          <el-table-column prop="noticeType" label="鍏憡绫诲瀷" align="center">
+            <template #default="scope">
+              <el-input
+                  v-if="scope.row.editing"
+                  v-model="scope.row.noticeType"
+                  placeholder="璇疯緭鍏ュ叕鍛婄被鍨�"
+              />
+              <span v-else>{{ scope.row.noticeType }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="鎿嶄綔" width="200" align="center">
+            <template #default="scope">
+              <el-button
+                  v-if="scope.row.editing"
+                  link
+                  type="primary"
+                  size="small"
+                  @click="handleSaveNoticeType(scope.row)"
+              >
+                淇濆瓨
+              </el-button>
+              <el-button
+                  v-if="scope.row.editing"
+                  link
+                  type="info"
+                  size="small"
+                  @click="handleCancelEdit(scope.row)"
+              >
+                鍙栨秷
+              </el-button>
+              <el-button
+                  v-if="!scope.row.editing"
+                  link
+                  type="primary"
+                  size="small"
+                  @click="handleEditNoticeType(scope.row)"
+              >
+                缂栬緫
+              </el-button>
+              <el-button
+                  v-if="!scope.row.editing"
+                  link
+                  type="danger"
+                  size="small"
+                  @click="handleDeleteNoticeType(scope.row)"
+              >
+                鍒犻櫎
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import {Search, Calendar, Tools, InfoFilled} from "@element-plus/icons-vue";
+import {Calendar, InfoFilled} from "@element-plus/icons-vue";
 import {onMounted, ref, reactive, toRefs, computed} from "vue";
 import {ElMessage, ElMessageBox} from "element-plus";
+import {useRoute} from "vue-router";
 import useUserStore from "@/store/modules/user";
 import {
   addNotice,
   delNotice,
   getCount,
   listNotice,
-  updateNotice
+  updateNotice,
+  listNoticeType,
+  addNoticeType,
+  delNoticeType
 } from "../../../api/collaborativeApproval/noticeManagement.js";
 import pagination from "../../../components/PIMTable/Pagination.vue";
 
 const userStore = useUserStore();
+const route = useRoute();
 
 // 鍝嶅簲寮忔暟鎹�
 const data = reactive({
@@ -274,6 +286,7 @@
     status: 0,
     priority: 1,
     remark: "",
+		expirationDate: "",
   },
   rules: {
     title: [
@@ -284,6 +297,9 @@
     ],
     content: [
       {required: true, message: "鍏憡鍐呭涓嶈兘涓虹┖", trigger: "blur"}
+    ],
+		expirationDate: [
+      {required: true, message: "璇烽�夋嫨鏃ユ湡", trigger: "change"}
     ]
   }
 });
@@ -293,8 +309,16 @@
 // 椤甸潰鐘舵��
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
-const selectedIds = ref([]);
 const formRef = ref();
+
+// 鍏憡绫诲瀷閰嶇疆鐩稿叧
+const noticeTypeDialogVisible = ref(false);
+const noticeTypeList = ref([]);
+const activeNoticeTypeTab = ref('');
+
+// 閫氱煡鏁版嵁 - 浣跨敤 Map 瀛樺偍锛宬ey 涓虹被鍨� id
+const noticesMap = ref({});
+const noticePagesMap = ref({});
 
 
 // 璁$畻灞炴��
@@ -339,8 +363,32 @@
 };
 
 const getStatusText = (status) => {
-  const statusMap = {"0": "鑽夌", "1": "宸插彂甯�", "2": "宸蹭笅绾�"};
+  const statusMap = {"0": "鑽夌", "1": "宸插彂甯�", "2": "宸茶繃鏈�"};
   return statusMap[status] || "鏈煡";
+};
+
+const isNoticeExpired = (notice) => {
+  if (!notice || !notice.expirationDate) {
+    return false;
+  }
+
+  const expiration = new Date(notice.expirationDate);
+
+  if (Number.isNaN(expiration.getTime())) {
+    return false;
+  }
+
+  expiration.setHours(23, 59, 59, 999);
+
+  return new Date() > expiration;
+};
+
+const getNoticeStatus = (notice) => {
+  const normalizedStatus = notice && notice.status !== undefined && notice.status !== null
+      ? String(notice.status)
+      : "0";
+
+  return isNoticeExpired(notice) ? "2" : normalizedStatus;
 };
 
 const openForm = (type) => {
@@ -354,12 +402,17 @@
       status: 0,
       priority: 1,
       remark: "",
+      expirationDate: "",
     };
   }
   dialogVisible.value = true;
 };
 
 const handleEdit = (row) => {
+  if (isNoticeExpired(row)) {
+    ElMessage.warning("宸茶繃鏈熺殑鍏憡涓嶅彲缂栬緫");
+    return;
+  }
   dialogTitle.value = "缂栬緫鍏憡";
   form.value = {...row};
   dialogVisible.value = true;
@@ -378,6 +431,28 @@
     delNotice(id).then(res => {
       ElMessage.success("鍒犻櫎鎴愬姛");
       resetTable()
+    })
+  });
+};
+
+const handlePublish = (notice) => {
+  ElMessageBox.confirm(
+      "纭鍙戝竷杩欐潯鍏憡鍚楋紵",
+      "鎻愮ず",
+      {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "info"
+      }
+  ).then(() => {
+    updateNotice({
+      ...notice,
+      status: 1
+    }).then(res => {
+      if (res.code === 200) {
+        ElMessage.success("鍙戝竷鎴愬姛");
+        resetTable()
+      }
     })
   });
 };
@@ -403,78 +478,257 @@
   });
 };
 
-const holidayNoticeCount = ref()
-const maintenanceNoticeCount = ref()
-const fetchCount = () => {
-  getCount().then(res => {
-    holidayNoticeCount.value = res.data.filter(item => {
-      return item.type === 1
-    })[0].count;
-    maintenanceNoticeCount.value = res.data.filter(item => {
-      return item.type === 2
-    })[0].count;
-  });
-}
+// 鍒濆鍖栨煇涓被鍨嬬殑鍒嗛〉鏁版嵁
+const initNoticePage = (typeId) => {
+  if (!noticePagesMap.value[typeId]) {
+    noticePagesMap.value[typeId] = {
+      total: 0,
+      current: 1,
+      size: 10
+    };
+  }
+  if (!noticesMap.value[typeId]) {
+    noticesMap.value[typeId] = [];
+  }
+};
 
-const holidayNotices = ref([])
-const maintenanceNotices = ref([])
-const holidayNoticePage = ref({
-  total: 0,
-  current: 1,
-  size: 6
-})
+// 鑾峰彇鏌愪釜绫诲瀷鐨勯�氱煡鍒楄〃
+const getNoticesByType = (typeId) => {
+  return noticesMap.value[typeId] || [];
+};
 
-const maintenanceNoticePage = ref({
-  total: 0,
-  current: 1,
-  size: 6
-})
+// 鑾峰彇鏌愪釜绫诲瀷鐨勫垎椤垫暟鎹�
+const getNoticePageByType = (typeId) => {
+  return noticePagesMap.value[typeId] || { total: 0, current: 1, size: 10 };
+};
 
-const fetchHolidayNotices = () => {
-  listNotice({...holidayNoticePage.value, type: 1}).then(res => {
-    holidayNotices.value = res.data.records
-    holidayNoticePage.value.total = res.data.total
+// 鑾峰彇鏌愪釜绫诲瀷鐨勬暟閲�
+const getNoticeCountByType = (typeId) => {
+  return getNoticePageByType(typeId).total || 0;
+};
+
+// 鑾峰彇鏌愪釜绫诲瀷鐨勯�氱煡鏁版嵁
+const fetchNoticesByType = (typeId) => {
+  initNoticePage(typeId);
+  const pageData = noticePagesMap.value[typeId];
+  listNotice({...pageData, type: typeId}).then(res => {
+    if (res.code === 200) {
+      noticesMap.value[typeId] = res.data.records || [];
+      noticePagesMap.value[typeId].total = res.data.total || 0;
+    }
   });
 };
 
-const fetchMaintenanceNotices = () => {
-  listNotice({...holidayNoticePage.value, type: 2}).then(res => {
-    maintenanceNotices.value = res.data.records
-    maintenanceNoticePage.value.total = res.data.total
-  });
+// 澶勭悊鍒嗛〉鍙樺寲
+const handleNoticeCurrentChange = (typeId, val) => {
+  initNoticePage(typeId);
+  noticePagesMap.value[typeId].size = val.limit;
+  noticePagesMap.value[typeId].current = val.page;
+  fetchNoticesByType(typeId);
 };
 
-const handleHolidayNoticeCurrentChange = (val) => {
-  holidayNoticePage.value.size = val.limit
-  holidayNoticePage.value.current = val.page
-  fetchHolidayNotices()
-};
-
-const handleMaintenanceNoticeCurrentChange = (val) => {
-  maintenanceNoticePage.value.size = val.limit
-  maintenanceNoticePage.value.current = val.page
-  fetchMaintenanceNotices()
+// 澶勭悊 tab 鍒囨崲
+const handleNoticeTypeTabChange = (tabName) => {
+  activeNoticeTypeTab.value = tabName;
+  const typeId = Number(tabName);
+  fetchNoticesByType(typeId);
 };
 
 const resetTable = () => {
-  holidayNoticePage.value.current = 1
-  holidayNoticePage.value.size = 6
-  maintenanceNoticePage.value.current = 1
-  maintenanceNoticePage.value.size = 6
-  fetchHolidayNotices()
-  fetchMaintenanceNotices()
-  fetchCount()
+  // 閲嶇疆鎵�鏈夌被鍨嬬殑鍒嗛〉骞堕噸鏂拌幏鍙栨暟鎹�
+  noticeTypeList.value.forEach(type => {
+    initNoticePage(type.id);
+    noticePagesMap.value[type.id].current = 1;
+    noticePagesMap.value[type.id].size = 10;
+    fetchNoticesByType(type.id);
+  });
 };
 
 const resetForm = () => {
   formRef.value?.resetFields();
 };
 
+// 鍏憡绫诲瀷閰嶇疆鐩稿叧鏂规硶
+const openNoticeTypeDialog = () => {
+  noticeTypeDialogVisible.value = true;
+  fetchNoticeTypeList();
+};
+
+const fetchNoticeTypeList = () => {
+  return listNoticeType().then(res => {
+    if (res.code === 200) {
+      noticeTypeList.value = res.data.map(item => ({
+        ...item,
+        editing: false
+      }));
+      
+      // 妫�鏌ヨ矾鐢卞弬鏁颁腑鐨� type
+      const routeType = route.query.type;
+      let targetTypeId = null;
+      
+      if (routeType) {
+        // 濡傛灉璺敱鍙傛暟涓湁 type锛屾煡鎵惧搴旂殑绫诲瀷
+        const typeId = Number(routeType);
+        const foundType = noticeTypeList.value.find(item => item.id === typeId);
+        if (foundType) {
+          targetTypeId = typeId;
+        }
+      }
+      
+      // 濡傛灉鏈夌被鍨嬫暟鎹�
+      if (noticeTypeList.value.length > 0) {
+        // 濡傛灉璺敱鍙傛暟鎸囧畾浜嗙被鍨嬩笖瀛樺湪锛屼娇鐢ㄨ矾鐢卞弬鏁扮殑绫诲瀷
+        // 鍚﹀垯濡傛灉娌℃湁閫変腑 tab锛岄粯璁ら�変腑绗竴涓�
+        if (targetTypeId !== null) {
+          activeNoticeTypeTab.value = String(targetTypeId);
+          fetchNoticesByType(targetTypeId);
+        } else if (!activeNoticeTypeTab.value) {
+          activeNoticeTypeTab.value = String(noticeTypeList.value[0].id);
+          fetchNoticesByType(noticeTypeList.value[0].id);
+        }
+      }
+    }
+  });
+};
+
+const handleAddNoticeType = () => {
+  const newItem = {
+    id: undefined,
+    noticeType: '',
+    editing: true
+  };
+  noticeTypeList.value.push(newItem);
+};
+
+const handleEditNoticeType = (row) => {
+  // 淇濆瓨鍘熷鍊�
+  row.originalNoticeType = row.noticeType;
+  row.editing = true;
+};
+
+const handleSaveNoticeType = (row) => {
+  if (!row.noticeType || row.noticeType.trim() === '') {
+    ElMessage.warning('鍏憡绫诲瀷涓嶈兘涓虹┖');
+    return;
+  }
+  
+  const data = {
+    noticeType: row.noticeType.trim()
+  };
+  
+  if (row.id) {
+    // 缂栬緫妯″紡 - 鍏堝垹闄ゅ啀娣诲姞锛堝洜涓哄彧鏈� add 鍜� del 鎺ュ彛锛�
+    delNoticeType(row.id).then(res => {
+      if (res.code === 200) {
+        addNoticeType(data).then(addRes => {
+          if (addRes.code === 200) {
+            ElMessage.success('缂栬緫鎴愬姛');
+            row.editing = false;
+            delete row.originalNoticeType;
+            fetchNoticeTypeList().then(() => {
+              // 濡傛灉褰撳墠閫変腑鐨勭被鍨嬭缂栬緫锛岄渶瑕侀噸鏂拌幏鍙栨暟鎹�
+              if (activeNoticeTypeTab.value === String(row.id)) {
+                fetchNoticesByType(addRes.data?.id || row.id);
+              }
+            });
+          }
+        });
+      }
+    });
+  } else {
+    // 鏂板妯″紡
+    addNoticeType(data).then(res => {
+      if (res.code === 200) {
+        ElMessage.success('鏂板鎴愬姛');
+        row.editing = false;
+        fetchNoticeTypeList();
+      }
+    });
+  }
+};
+
+const handleDeleteNoticeType = (row) => {
+  // 濡傛灉娌℃湁id锛岃鏄庢槸鏂板浣嗘湭淇濆瓨鐨勮锛岀洿鎺ヤ粠鍓嶇鍒犻櫎
+  if (!row.id) {
+    const index = noticeTypeList.value.indexOf(row);
+    if (index > -1) {
+      noticeTypeList.value.splice(index, 1);
+    }
+    return;
+  }
+  
+  // 濡傛灉鏈塱d锛岃皟鐢ㄥ悗绔帴鍙e垹闄�
+  ElMessageBox.confirm(
+      "纭鍒犻櫎杩欎釜鍏憡绫诲瀷鍚楋紵",
+      "鎻愮ず",
+      {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning"
+      }
+  ).then(() => {
+    delNoticeType(row.id).then(res => {
+      if (res.code === 200) {
+        ElMessage.success("鍒犻櫎鎴愬姛");
+        // 濡傛灉鍒犻櫎鐨勬槸褰撳墠閫変腑鐨勭被鍨嬶紝鍒囨崲鍒扮涓�涓被鍨�
+        if (activeNoticeTypeTab.value === String(row.id)) {
+          fetchNoticeTypeList().then(() => {
+            if (noticeTypeList.value.length > 0) {
+              activeNoticeTypeTab.value = String(noticeTypeList.value[0].id);
+              fetchNoticesByType(noticeTypeList.value[0].id);
+            } else {
+              activeNoticeTypeTab.value = '';
+            }
+          });
+        } else {
+          fetchNoticeTypeList();
+        }
+      }
+    });
+  });
+};
+
+const handleCancelEdit = (row) => {
+  if (!row.id) {
+    // 濡傛灉鏄柊澧炰絾鏈繚瀛樼殑琛岋紝绉婚櫎瀹�
+    const index = noticeTypeList.value.indexOf(row);
+    if (index > -1) {
+      noticeTypeList.value.splice(index, 1);
+    }
+  } else {
+    // 濡傛灉鏄紪杈戜腑鐨勮锛屽彇娑堢紪杈戠姸鎬佸苟鎭㈠鍘熷��
+    row.editing = false;
+    if (row.originalNoticeType !== undefined) {
+      row.noticeType = row.originalNoticeType;
+      delete row.originalNoticeType;
+    }
+  }
+};
+
+const handleNoticeTypeDialogClose = () => {
+  // 鍏抽棴寮规鏃讹紝鍙栨秷鎵�鏈夌紪杈戠姸鎬�
+  noticeTypeList.value.forEach(item => {
+    if (item.editing && !item.id) {
+      // 濡傛灉鏄柊澧炰絾鏈繚瀛樼殑琛岋紝绉婚櫎瀹�
+      const index = noticeTypeList.value.indexOf(item);
+      if (index > -1) {
+        noticeTypeList.value.splice(index, 1);
+      }
+    } else if (item.editing) {
+      // 濡傛灉鏄紪杈戜腑鐨勮锛屽彇娑堢紪杈戠姸鎬佸苟鎭㈠鍘熷��
+      item.editing = false;
+      if (item.originalNoticeType !== undefined) {
+        item.noticeType = item.originalNoticeType;
+        delete item.originalNoticeType;
+      }
+    }
+  });
+};
+
 // 鐢熷懡鍛ㄦ湡
 onMounted(() => {
-  fetchCount()
-  fetchHolidayNotices()
-  fetchMaintenanceNotices()
+  // 鍏堣幏鍙栧叕鍛婄被鍨嬪垪琛紝鐒跺悗鏍规嵁绫诲瀷鑾峰彇閫氱煡鏁版嵁
+  fetchNoticeTypeList();
 });
 </script>
 
@@ -553,12 +807,16 @@
   box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
 }
 
-.holiday-card {
-  border-left-color: #67c23a;
+.notice-icon {
+  color: #409eff;
+  margin-right: 8px;
+  font-size: 18px;
 }
 
-.maintenance-card {
-  border-left-color: #e6a23c;
+.tab-count {
+  color: #909399;
+  font-size: 12px;
+  margin-left: 4px;
 }
 
 .urgent {
@@ -582,17 +840,6 @@
   flex: 1;
 }
 
-.holiday-icon {
-  color: #67c23a;
-  margin-right: 8px;
-  font-size: 18px;
-}
-
-.maintenance-icon {
-  color: #e6a23c;
-  margin-right: 8px;
-  font-size: 18px;
-}
 
 .card-actions {
   display: flex;
@@ -672,6 +919,10 @@
   margin-bottom: 2px;
 }
 
+.expiration {
+  margin-top: 2px;
+}
+
 .card-remark {
   display: flex;
   align-items: center;
@@ -693,6 +944,16 @@
   text-align: right;
 }
 
+.notice-type-container {
+  padding: 10px 0;
+}
+
+.notice-type-header {
+  margin-bottom: 15px;
+  display: flex;
+  justify-content: flex-end;
+}
+
 /* 鍝嶅簲寮忚璁� */
 @media (max-width: 768px) {
   .notice-cards {

--
Gitblit v1.9.3