spring
10 小时以前 ebe3507d1382bb124c1fb895a5e27f7063fdffdc
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">正式发布</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 存储,key 为类型 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;
  }
  // 如果有id,调用后端接口删除
  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 {