From cd6eb9089e893cf7fa998543af1125dbef81a355 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 15 八月 2025 14:29:28 +0800
Subject: [PATCH] 电表采集页面添加

---
 src/views/collaborativeApproval/notificationManagement/index.vue | 1187 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1,187 insertions(+), 0 deletions(-)

diff --git a/src/views/collaborativeApproval/notificationManagement/index.vue b/src/views/collaborativeApproval/notificationManagement/index.vue
new file mode 100644
index 0000000..288acf1
--- /dev/null
+++ b/src/views/collaborativeApproval/notificationManagement/index.vue
@@ -0,0 +1,1187 @@
+<template>
+  <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="'holiday'" />
+          <el-option label="澶勭綒閫氱煡" :value="'penalty'" />
+          <el-option label="寮�浼氶�氱煡" :value="'meeting'" />
+          <el-option label="涓存椂閫氱煡" :value="'temporary'" />
+          <el-option label="姝e紡閫氱煡" :value="'formal'" />
+        </el-select>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
+          鎼滅储
+        </el-button>
+      </div>
+      <div>
+        <el-button type="primary" @click="openForm('add')">鏂板閫氱煡</el-button>
+        <el-button type="success" @click="openMeetingDialog">鍦ㄧ嚎浼氳</el-button>
+        <el-button type="warning" @click="openFileShareDialog">鏂囦欢鍏变韩</el-button>
+        <!-- <el-button type="info" @click="refreshEmployees">鍒锋柊鍛樺伐</el-button> -->
+        <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <PIMTable
+        rowKey="id"
+        :column="tableColumn"
+        :tableData="tableData"
+        :page="page"
+        :isSelection="true"
+        @selection-change="handleSelectionChange"
+        :tableLoading="tableLoading"
+        @pagination="pagination"
+        :total="page.total"
+      ></PIMTable>
+    </div>
+
+    <!-- 鏂板/缂栬緫閫氱煡寮圭獥 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="800px"
+      :close-on-click-modal="false"
+    >
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="閫氱煡鏍囬" prop="title">
+              <el-input v-model="form.title" placeholder="璇疯緭鍏ラ�氱煡鏍囬" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閫氱煡绫诲瀷" prop="type">
+              <el-select v-model="form.type" placeholder="璇烽�夋嫨閫氱煡绫诲瀷" style="width: 100%">
+                <el-option label="鏀惧亣閫氱煡" value="holiday" />
+                <el-option label="澶勭綒閫氱煡" value="penalty" />
+                <el-option label="寮�浼氶�氱煡" value="meeting" />
+                <el-option label="涓存椂閫氱煡" value="temporary" />
+                <el-option label="姝e紡閫氱煡" value="formal" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="浼樺厛绾�" prop="priority">
+              <el-select v-model="form.priority" placeholder="璇烽�夋嫨浼樺厛绾�" style="width: 100%">
+                <el-option label="鏅��" value="low" />
+                <el-option label="閲嶈" value="medium" />
+                <el-option label="绱ф��" value="high" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏈夋晥鏈熻嚦" prop="expireDate">
+              <el-date-picker
+                v-model="form.expireDate"
+                type="date"
+                placeholder="璇烽�夋嫨鏈夋晥鏈�"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="鎺ユ敹閮ㄩ棬" prop="departments">
+          <el-select
+            v-model="form.departments"
+            multiple
+            placeholder="璇烽�夋嫨鎺ユ敹閮ㄩ棬"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="dept in departments"
+              :key="dept"
+              :label="dept"
+              :value="dept"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鍚屾鏂瑰紡" prop="syncMethods">
+          <el-checkbox-group v-model="form.syncMethods">
+            <el-checkbox
+              v-for="method in syncMethods"
+              :key="method.value"
+              :label="method.value"
+            >
+              {{ method.label }}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="閫氱煡鍐呭" prop="content">
+          <el-input
+            v-model="form.content"
+            type="textarea"
+            :rows="4"
+            placeholder="璇疯緭鍏ラ�氱煡鍐呭"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary" @click="submitForm">纭畾</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <!-- 鍦ㄧ嚎浼氳寮圭獥 -->
+    <el-dialog
+      v-model="meetingDialogVisible"
+      title="鍒涘缓鍦ㄧ嚎浼氳"
+      width="700px"
+      :close-on-click-modal="false"
+    >
+      <el-form ref="meetingFormRef" :model="meetingForm" :rules="meetingRules" label-width="120px">
+        <el-form-item label="浼氳鏍囬" prop="title">
+          <el-input v-model="meetingForm.title" placeholder="璇疯緭鍏ヤ細璁爣棰�" />
+        </el-form-item>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="寮�濮嬫椂闂�" prop="startTime">
+              <el-date-picker
+                v-model="meetingForm.startTime"
+                type="datetime"
+                placeholder="璇烽�夋嫨寮�濮嬫椂闂�"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浼氳鏃堕暱" prop="duration">
+              <el-input-number
+                v-model="meetingForm.duration"
+                :min="15"
+                :max="480"
+                :step="15"
+                style="width: 100%"
+              />
+              <span style="margin-left: 10px">鍒嗛挓</span>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="浼氳骞冲彴" prop="platform">
+          <el-select v-model="meetingForm.platform" placeholder="璇烽�夋嫨浼氳骞冲彴" style="width: 100%">
+            <el-option
+              v-for="platform in meetingPlatforms"
+              :key="platform.value"
+              :label="platform.label"
+              :value="platform.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鍙備細浜哄憳" prop="participants">
+          <el-select
+            v-model="meetingForm.participants"
+            multiple
+            filterable
+            remote
+            :remote-method="filterEmployees"
+            :loading="employeesLoading"
+            placeholder="璇烽�夋嫨鍙備細浜哄憳"
+            style="width: 100%"
+          >
+            <el-option-group
+              v-for="group in employeeGroups"
+              :key="group.label"
+              :label="group.label"
+            >
+                             <el-option
+                 v-for="employee in group.options"
+                 :key="employee.value"
+                 :label="`${employee.label} (${employee.dept})`"
+                 :value="employee.value"
+               >
+                 <div style="display: flex; justify-content: space-between; align-items: center;">
+                   <div>
+                     <div style="font-weight: 500;">{{ employee.label }}</div>
+                     <div style="color: #909399; font-size: 12px;">{{ employee.dept }}</div>
+                   </div>
+                   <div style="text-align: right; font-size: 12px; color: #909399;">
+                     <div v-if="employee.phone">{{ employee.phone }}</div>
+                     <div v-if="employee.email">{{ employee.email }}</div>
+                   </div>
+                 </div>
+               </el-option>
+            </el-option-group>
+          </el-select>
+          <div style="margin-top: 8px; color: #909399; font-size: 12px;">
+            宸查�夋嫨 {{ meetingForm.participants.length }} 浜�
+          </div>
+          <!-- 宸查�夋嫨浜哄憳璇︽儏 -->
+          <div v-if="meetingForm.participants.length > 0" style="margin-top: 10px;">
+            <el-tag
+              v-for="participantId in meetingForm.participants"
+              :key="participantId"
+              closable
+              @close="removeParticipant(participantId)"
+              style="margin-right: 8px; margin-bottom: 8px;"
+            >
+              {{ getEmployeeName(participantId) }}
+            </el-tag>
+          </div>
+        </el-form-item>
+        <el-form-item label="浼氳鎻忚堪" prop="description">
+          <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="meetingDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary" @click="createMeeting">鍒涘缓浼氳</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
+    <!-- 鏂囦欢鍏变韩寮圭獥 -->
+    <el-dialog
+      v-model="fileShareDialogVisible"
+      title="鏂囦欢鍏变韩"
+      width="700px"
+      :close-on-click-modal="false"
+    >
+      <el-form ref="fileShareFormRef" :model="fileShareForm" :rules="fileShareRules" label-width="120px">
+        <el-form-item label="鍏变韩鏍囬" prop="title">
+          <el-input v-model="fileShareForm.title" placeholder="璇疯緭鍏ュ叡浜爣棰�" />
+        </el-form-item>
+        <el-form-item label="鍏变韩鎻忚堪" prop="description">
+          <el-input
+            v-model="fileShareForm.description"
+            type="textarea"
+            :rows="3"
+            placeholder="璇疯緭鍏ュ叡浜弿杩�"
+          />
+        </el-form-item>
+        <el-form-item label="鎺ユ敹閮ㄩ棬" prop="departments">
+          <el-select
+            v-model="fileShareForm.departments"
+            multiple
+            placeholder="璇烽�夋嫨鎺ユ敹閮ㄩ棬"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="dept in departments"
+              :key="dept"
+              :label="dept"
+              :value="dept"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="涓婁紶鏂囦欢" prop="files">
+          <el-upload
+            ref="uploadRef"
+            :auto-upload="false"
+            :on-change="handleFileChange"
+            :on-remove="removeFile"
+            :file-list="fileList"
+            multiple
+            :limit="10"
+            accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.txt,.jpg,.jpeg,.png,.gif"
+          >
+            <el-button type="primary">閫夋嫨鏂囦欢</el-button>
+            <template #tip>
+              <div class="el-upload__tip">
+                鏀寔涓婁紶鏂囨。銆佸浘鐗囩瓑鏍煎紡锛屽崟涓枃浠朵笉瓒呰繃10MB锛屾渶澶�10涓枃浠�
+              </div>
+            </template>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="fileShareDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary" @click="shareFiles">鍏变韩鏂囦欢</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { Search } from "@element-plus/icons-vue";
+import { onMounted, ref, reactive, toRefs, computed } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import PIMTable from "@/components/PIMTable/PIMTable.vue";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+import { staffOnJobListPage } from "@/api/personnelManagement/employeeRecord.js";
+
+// 琛ㄥ崟楠岃瘉瑙勫垯
+const rules = {
+  title: [
+    { required: true, message: "璇疯緭鍏ラ�氱煡鏍囬", trigger: "blur" }
+  ],
+  type: [
+    { required: true, message: "璇烽�夋嫨閫氱煡绫诲瀷", trigger: "change" }
+  ],
+  content: [
+    { required: true, message: "璇疯緭鍏ラ�氱煡鍐呭", trigger: "blur" }
+  ]
+};
+
+const meetingRules = {
+  title: [
+    { required: true, message: "璇疯緭鍏ヤ細璁爣棰�", trigger: "blur" }
+  ],
+  startTime: [
+    { required: true, message: "璇烽�夋嫨浼氳寮�濮嬫椂闂�", trigger: "change" }
+  ],
+  participants: [
+    { required: true, message: "璇烽�夋嫨鍙備細浜哄憳", trigger: "change" }
+  ]
+};
+
+const fileShareRules = {
+  title: [
+    { required: true, message: "璇疯緭鍏ュ叡浜爣棰�", trigger: "blur" }
+  ],
+  description: [
+    { required: true, message: "璇疯緭鍏ュ叡浜弿杩�", trigger: "blur" }
+  ]
+};
+
+// 鍝嶅簲寮忔暟鎹�
+const data = reactive({
+  searchForm: {
+    title: "",
+    type: "",
+    status: "",
+  },
+  tableLoading: false,
+  page: {
+    current: 1,
+    size: 100,
+    total: 0,
+  },
+  tableData: [],
+  selectedIds: [],
+  // 鏂板閫氱煡鐩稿叧
+  form: {
+    title: "",
+    type: "",
+    priority: "medium",
+    content: "",
+    departments: [],
+    expireDate: "",
+    syncMethods: []
+  },
+  dialogVisible: false,
+  dialogTitle: "",
+  dialogType: "add",
+  // 鍦ㄧ嚎浼氳鐩稿叧
+  meetingDialogVisible: false,
+  meetingForm: {
+    title: "",
+    startTime: "",
+    duration: 60,
+    participants: [],
+    description: "",
+    platform: "wechat"
+  },
+  // 鏂囦欢鍏变韩鐩稿叧
+  fileShareDialogVisible: false,
+  fileShareForm: {
+    title: "",
+    description: "",
+    departments: [],
+    files: []
+  },
+  fileList: []
+});
+
+const { 
+  searchForm, 
+  tableLoading, 
+  page, 
+  tableData, 
+  selectedIds,
+  form,
+  dialogVisible,
+  dialogTitle,
+  dialogType,
+  meetingDialogVisible,
+  meetingForm,
+  fileShareDialogVisible,
+  fileShareForm,
+  fileList
+} = toRefs(data);
+
+// 琛ㄥ崟寮曠敤
+const formRef = ref();
+const meetingFormRef = ref();
+const fileShareFormRef = ref();
+
+// 琛ㄦ牸鍒楅厤缃�
+const tableColumn = ref([
+  {
+    label: "閫氱煡鏍囬",
+    prop: "title",
+    showOverflowTooltip: true,
+  },
+  {
+    label: "閫氱煡绫诲瀷",
+    prop: "type",
+    dataType: "tag",
+    formatData: (params) => {
+      const typeMap = {
+        holiday: "鏀惧亣閫氱煡",
+        penalty: "澶勭綒閫氱煡",
+        meeting: "寮�浼氶�氱煡",
+        temporary: "涓存椂閫氱煡",
+        formal: "姝e紡閫氱煡"
+      };
+      return typeMap[params] || params;
+    },
+    formatType: (params) => {
+      const typeMap = {
+        holiday: "success",
+        penalty: "danger",
+        meeting: "warning",
+        temporary: "info",
+        formal: "primary"
+      };
+      return typeMap[params] || "info";
+    }
+  },
+  {
+    label: "浼樺厛绾�",
+    prop: "priority",
+    dataType: "tag",
+    formatData: (params) => {
+      const priorityMap = {
+        low: "鏅��",
+        medium: "閲嶈",
+        high: "绱ф��"
+      };
+      return priorityMap[params] || params;
+    },
+    formatType: (params) => {
+      const typeMap = {
+        low: "info",
+        medium: "warning",
+        high: "danger"
+      };
+      return typeMap[params] || "info";
+    }
+  },
+  {
+    label: "鐘舵��",
+    prop: "status",
+    dataType: "tag",
+    formatData: (params) => {
+      const statusMap = {
+        draft: "鑽夌",
+        published: "宸插彂甯�",
+        expired: "宸茶繃鏈�"
+      };
+      return statusMap[params] || params;
+    },
+    formatType: (params) => {
+      const typeMap = {
+        draft: "info",
+        published: "success",
+        expired: "danger"
+      };
+      return typeMap[params] || "info";
+    }
+  },
+  {
+    label: "鎺ユ敹閮ㄩ棬",
+    prop: "departments",
+    width: 150,
+    showOverflowTooltip: true,
+    formatData: (params) => {
+      if (!params || params.length === 0) return "鍏ㄩ儴閮ㄩ棬";
+      return params.join(", ");
+    }
+  },
+  {
+    label: "鏈夋晥鏈熻嚦",
+    prop: "expireDate",
+    width: 150,
+    formatData: (params) => {
+      if (!params) return "姘镐箙鏈夋晥";
+      return params;
+    }
+  },
+  {
+    label: "鍒涘缓鏃堕棿",
+    prop: "createTime",
+    width: 180,
+  },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: "right",
+    width: 280,
+    operation: [
+      {
+        name: "缂栬緫",
+        type: "text",
+        clickFun: (row) => {
+          openForm("edit", row);
+        }
+      },
+      {
+        name: "鍙戝竷",
+        type: "text",
+        clickFun: (row) => {
+          publishNotification(row);
+        },
+        // disabled: (row) => row.status === "published"
+      },
+      {
+        name: "鎾ゅ洖",
+        type: "text",
+        clickFun: (row) => {
+          revokeNotification(row);
+        },
+        // disabled: (row) => row.status !== "published"
+      }
+    ]
+  }
+]);
+
+// 妯℃嫙鏁版嵁
+let mockData = [
+  {
+    id: "1",
+    title: "2024骞存槬鑺傛斁鍋囬�氱煡",
+    type: "holiday",
+    priority: "high",
+    status: "published",
+    content: "鏍规嵁鍥藉瑙勫畾锛岀粨鍚堝叕鍙稿疄闄呮儏鍐碉紝鐜板皢2024骞存槬鑺傛斁鍋囧畨鎺掗�氱煡濡備笅...",
+    departments: ["鎶�鏈儴", "閿�鍞儴", "浜轰簨閮�", "璐㈠姟閮�", "杩愯惀閮�", "甯傚満閮�", "瀹㈡湇閮�"],
+    expireDate: "2024-02-15",
+    syncMethods: ["wechat", "dingtalk", "email"],
+    createTime: "2024-01-15 10:30:00"
+  },
+  {
+    id: "2",
+    title: "鎶�鏈儴鍛ㄤ緥浼氶�氱煡",
+    type: "meeting",
+    priority: "medium",
+    status: "published",
+    content: "鎶�鏈儴瀹氫簬姣忓懆浜斾笅鍗�2鐐瑰彫寮�鍛ㄤ緥浼氾紝璇峰悇浣嶅悓浜嬪噯鏃跺弬鍔�...",
+    departments: ["鎶�鏈儴"],
+    expireDate: "2024-01-20",
+    syncMethods: ["wechat", "dingtalk"],
+    createTime: "2024-01-14 15:20:00"
+  },
+  {
+    id: "3",
+    title: "鍛樺伐琛屼负瑙勮寖澶勭綒閫氱煡",
+    type: "penalty",
+    priority: "high",
+    status: "draft",
+    content: "涓虹淮鎶ゅ叕鍙告甯哥З搴忥紝瑙勮寖鍛樺伐琛屼负锛岀幇瀵硅繚鍙嶅叕鍙歌瀹氱殑琛屼负杩涜澶勭綒...",
+    departments: ["浜轰簨閮�", "鎶�鏈儴", "閿�鍞儴"],
+    expireDate: "2024-02-13",
+    syncMethods: ["wechat", "email"],
+    createTime: "2024-01-13 09:15:00"
+  }
+];
+
+// 閫氱煡鏍囬妯℃澘
+const titleTemplates = [
+  "鍏充簬{year}骞磠holiday}鏀惧亣瀹夋帓鐨勯�氱煡",
+  "{dept}閮ㄩ棬{meeting}浼氳閫氱煡",
+  "鍛樺伐{behavior}琛屼负瑙勮寖鎻愰啋",
+  "{company}閲嶈浜嬮」閫氱煡",
+  "{dept}閮ㄩ棬宸ヤ綔瀹夋帓閫氱煡",
+  "鍏充簬{project}椤圭洰杩涘害鐨勯�氱煡",
+  "{dept}閮ㄩ棬浜哄憳璋冩暣閫氱煡",
+  "鍏徃{policy}鏀跨瓥鏇存柊閫氱煡"
+];
+
+// 閫氱煡绫诲瀷閰嶇疆
+const notificationTypes = [
+  { type: "holiday", label: "鏀惧亣閫氱煡", priority: "high" },
+  { type: "meeting", label: "寮�浼氶�氱煡", priority: "medium" },
+  { type: "penalty", label: "澶勭綒閫氱煡", priority: "high" },
+  { type: "temporary", label: "涓存椂閫氱煡", priority: "low" },
+  { type: "formal", label: "姝e紡閫氱煡", priority: "medium" }
+];
+
+// 閮ㄩ棬鍒楄〃
+const departments = ["鎶�鏈儴", "閿�鍞儴", "浜轰簨閮�", "璐㈠姟閮�", "杩愯惀閮�", "甯傚満閮�", "瀹㈡湇閮�"];
+
+// 浜哄憳鍒楄〃
+const employees = ref([]);
+const employeesLoading = ref(false);
+
+// 鑾峰彇鍦ㄨ亴鍛樺伐鍒楄〃
+const getEmployeesList = async () => {
+  try {
+    employeesLoading.value = true;
+    // 浼樺厛浣跨敤绯荤粺鐢ㄦ埛鎺ュ彛锛堟寜绉熸埛鑾峰彇锛�
+    const userResponse = await userListNoPageByTenantId();
+    
+    if (userResponse.data) {
+      employees.value = userResponse.data.map(user => ({
+        label: user.nickName || user.userName || '鏈煡濮撳悕',
+        value: user.userId || user.id,
+        dept: user.dept?.deptName || '鏈煡閮ㄩ棬',
+        phone: user.phonenumber || '',
+        email: user.email || '',
+        status: user.status || '0'
+      })).filter(user => user.status === '0'); // 鍙樉绀烘甯哥姸鎬佺殑鐢ㄦ埛
+    } else {
+      // 濡傛灉绯荤粺鐢ㄦ埛鎺ュ彛澶辫触锛屼娇鐢ㄥ憳宸ュ彴璐︽帴鍙�
+      const response = await staffOnJobListPage({ 
+        pageNum: 1, 
+        pageSize: 1000, 
+        staffState: 1 // 鍦ㄨ亴鐘舵��
+      });
+      
+      if (response.data && response.data.records) {
+        employees.value = response.data.records.map(employee => ({
+          label: employee.staffName || employee.name || '鏈煡濮撳悕',
+          value: employee.staffNo || employee.id || employee.staffId,
+          dept: employee.deptName || employee.department || '鏈煡閮ㄩ棬',
+          phone: employee.phone || employee.mobile || '',
+          email: employee.email || '',
+          status: '0'
+        }));
+      }
+    }
+  } catch (error) {
+    console.error('鑾峰彇鍛樺伐鍒楄〃澶辫触:', error);
+    // 濡傛灉鎺ュ彛閮藉け璐ワ紝浣跨敤榛樿鏁版嵁
+    employees.value = [
+      { label: "寮犱笁", value: "001", dept: "鎶�鏈儴", phone: "13800138001", email: "zhangsan@company.com", status: "0" },
+      { label: "鏉庡洓", value: "002", dept: "閿�鍞儴", phone: "13800138002", email: "lisi@company.com", status: "0" },
+      { label: "鐜嬩簲", value: "003", dept: "浜轰簨閮�", phone: "13800138003", email: "wangwu@company.com", status: "0" }
+    ];
+  } finally {
+    employeesLoading.value = false;
+  }
+};
+
+// 鍛樺伐鍒嗙粍
+const employeeGroups = computed(() => {
+  const groups = {};
+  employees.value.forEach(employee => {
+    const dept = employee.dept || '鍏朵粬閮ㄩ棬';
+    if (!groups[dept]) {
+      groups[dept] = [];
+    }
+    groups[dept].push(employee);
+  });
+  
+  // 鎸夐儴闂ㄥ悕绉版帓搴忥紝纭繚鏄剧ず椤哄簭涓�鑷�
+  return Object.keys(groups)
+    .sort()
+    .map(dept => ({
+      label: dept,
+      options: groups[dept].sort((a, b) => a.label.localeCompare(b.label, 'zh-CN'))
+    }));
+});
+
+// 杩囨护鍛樺伐锛堣繙绋嬫悳绱級
+const filterEmployees = (query) => {
+  if (query !== '') {
+    const lowerQuery = query.toLowerCase();
+    return employees.value.filter(employee => 
+      employee.label.toLowerCase().includes(lowerQuery) ||
+      employee.dept.toLowerCase().includes(lowerQuery) ||
+      (employee.phone && employee.phone.includes(query)) ||
+      (employee.email && employee.email.toLowerCase().includes(lowerQuery))
+    );
+  } else {
+    return employees.value;
+  }
+};
+
+// 鍒锋柊鍛樺伐鍒楄〃
+const refreshEmployees = async () => {
+  ElMessage.info("姝e湪鍒锋柊鍛樺伐鍒楄〃...");
+  await getEmployeesList();
+  
+  // 缁熻鍚勯儴闂ㄤ汉鏁�
+  const deptStats = {};
+  employees.value.forEach(emp => {
+    const dept = emp.dept || '鍏朵粬閮ㄩ棬';
+    deptStats[dept] = (deptStats[dept] || 0) + 1;
+  });
+  
+  const deptInfo = Object.entries(deptStats)
+    .map(([dept, count]) => `${dept}: ${count}浜篳)
+    .join(', ');
+  
+  ElMessage.success(`鍛樺伐鍒楄〃鍒锋柊瀹屾垚锛屽叡 ${employees.value.length} 浜� (${deptInfo})`);
+};
+
+// 鑾峰彇鍛樺伐濮撳悕
+const getEmployeeName = (employeeId) => {
+  const employee = employees.value.find(emp => emp.value === employeeId);
+  return employee ? employee.label : '鏈煡浜哄憳';
+};
+
+// 鑾峰彇鍛樺伐璇︾粏淇℃伅
+const getEmployeeInfo = (employeeId) => {
+  const employee = employees.value.find(emp => emp.value === employeeId);
+  if (!employee) return null;
+  
+  return {
+    name: employee.label,
+    dept: employee.dept,
+    phone: employee.phone,
+    email: employee.email
+  };
+};
+
+// 绉婚櫎鍙備細浜哄憳
+const removeParticipant = (participantId) => {
+  const index = meetingForm.value.participants.indexOf(participantId);
+  if (index > -1) {
+    meetingForm.value.participants.splice(index, 1);
+  }
+};
+
+// 鍚屾鏂瑰紡閫夐」
+const syncMethods = [
+  { label: "浼佷笟寰俊", value: "wechat" },
+  { label: "閽夐拤", value: "dingtalk" },
+  { label: "閭欢", value: "email" },
+  { label: "鐭俊", value: "sms" }
+];
+
+// 浼氳骞冲彴閫夐」
+const meetingPlatforms = [
+  { label: "浼佷笟寰俊浼氳", value: "wechat" },
+  { label: "閽夐拤浼氳", value: "dingtalk" },
+  { label: "鑵捐浼氳", value: "tencent" },
+  { label: "Zoom", value: "zoom" }
+];
+
+// 鑷姩鐢熸垚鏂版暟鎹�
+const generateNewData = () => {
+  const newId = (mockData.length + 1).toString();
+  const now = new Date();
+  const randomType = notificationTypes[Math.floor(Math.random() * notificationTypes.length)];
+  const randomDept = departments[Math.floor(Math.random() * departments.length)];
+  
+  // 鐢熸垚闅忔満鏍囬
+  let title = titleTemplates[Math.floor(Math.random() * titleTemplates.length)];
+  title = title
+    .replace('{year}', now.getFullYear())
+    .replace('{holiday}', ['鏄ヨ妭', '鍥藉簡', '涓', '鍏冩棪'][Math.floor(Math.random() * 4)])
+    .replace('{dept}', randomDept)
+    .replace('{meeting}', ['鍛ㄤ緥浼�', '鏈堝害鎬荤粨', '椤圭洰璇勫', '鍩硅浼氳'][Math.floor(Math.random() * 4)])
+    .replace('{behavior}', ['鑰冨嫟', '鐫�瑁�', '宸ヤ綔鎬佸害', '鍥㈤槦鍗忎綔'][Math.floor(Math.random() * 4)])
+    .replace('{company}', ['鍏徃', '闆嗗洟', '鎬婚儴'][Math.floor(Math.random() * 4)])
+    .replace('{project}', ['鏁板瓧鍖栬浆鍨�', '浜у搧鍗囩骇', '甯傚満鎷撳睍', '浜烘墠鍩瑰吇'][Math.floor(Math.random() * 4)])
+    .replace('{policy}', ['鑰冨嫟', '钖叕', '绂忓埄', '鏅嬪崌'][Math.floor(Math.random() * 4)]);
+  
+  // 闅忔満鐘舵��
+  const statuses = ['draft', 'published'];
+  const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
+  
+  // 闅忔満浼樺厛绾�
+  const priorities = ['low', 'medium', 'high'];
+  const randomPriority = priorities[Math.floor(Math.random() * priorities.length)];
+  
+  const newNotification = {
+    id: newId,
+    title: title,
+    type: randomType.type,
+    priority: randomPriority,
+    status: randomStatus,
+    content: `杩欐槸${title}鐨勮缁嗗唴瀹癸紝璇风浉鍏充汉鍛樻敞鎰忔煡鐪�...`,
+    departments: [randomDept],
+    expireDate: new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], // 30澶╁悗杩囨湡
+    syncMethods: ["wechat", "dingtalk"],
+    createTime: now.toLocaleString()
+  };
+  
+  // 娣诲姞鍒版暟鎹紑澶�
+  mockData.unshift(newNotification);
+  
+  // 淇濇寔鏁版嵁閲忓湪鍚堢悊鑼冨洿鍐咃紙鏈�澶氫繚鐣�20鏉★級
+  if (mockData.length > 20) {
+    mockData = mockData.slice(0, 20);
+  }
+  
+  console.log(`[${new Date().toLocaleString()}] 鑷姩鐢熸垚鏂伴�氱煡: ${title}`);
+};
+
+// 鐢熷懡鍛ㄦ湡
+onMounted(() => {
+  getList();
+  getEmployeesList(); // 鑾峰彇鍛樺伐鍒楄〃
+  startAutoRefresh();
+});
+
+// 寮�濮嬭嚜鍔ㄥ埛鏂�
+const startAutoRefresh = () => {
+  setInterval(() => {
+    generateNewData();
+    getList();
+  }, 600000); // 10鍒嗛挓鍒锋柊涓�娆� (10 * 60 * 1000 = 600000ms)
+};
+
+// 鏌ヨ鏁版嵁
+const handleQuery = () => {
+  page.value.current = 1;
+  getList();
+};
+
+const getList = () => {
+  tableLoading.value = true;
+  
+  setTimeout(() => {
+    let filteredData = [...mockData];
+    
+    if (searchForm.value.title) {
+      filteredData = filteredData.filter(item => 
+        item.title.toLowerCase().includes(searchForm.value.title.toLowerCase())
+      );
+    }
+    
+    if (searchForm.value.type) {
+      filteredData = filteredData.filter(item => item.type === searchForm.value.type);
+    }
+    
+    tableData.value = filteredData;
+    page.value.total = filteredData.length;
+    tableLoading.value = false;
+  }, 500);
+};
+
+// 鍒嗛〉澶勭悊
+const pagination = (obj) => {
+  page.value.current = obj.page;
+  page.value.size = obj.limit;
+  handleQuery();
+};
+
+// 閫夋嫨鍙樺寲澶勭悊
+const handleSelectionChange = (selection) => {
+  selectedIds.value = selection.map(item => item.id);
+};
+
+// 鎵撳紑琛ㄥ崟
+const openForm = (type, row = null) => {
+  dialogType.value = type;
+  if (type === "add") {
+    dialogTitle.value = "鏂板閫氱煡";
+    // 閲嶇疆琛ㄥ崟
+    Object.assign(form.value, {
+      title: "",
+      type: "",
+      priority: "medium",
+      content: "",
+      departments: [],
+      expireDate: "",
+      syncMethods: []
+    });
+  } else if (type === "edit" && row) {
+    dialogTitle.value = "缂栬緫閫氱煡";
+    Object.assign(form.value, {
+      title: row.title,
+      type: row.type,
+      priority: row.priority,
+      content: row.content || "",
+      departments: row.departments || [],
+      expireDate: row.expireDate || "",
+      syncMethods: row.syncMethods || []
+    });
+  }
+  dialogVisible.value = true;
+};
+
+// 鎵撳紑鍦ㄧ嚎浼氳寮圭獥
+const openMeetingDialog = () => {
+  // 閲嶇疆琛ㄥ崟
+  Object.assign(meetingForm.value, {
+    title: "",
+    startTime: "",
+    duration: 60,
+    participants: [],
+    description: "",
+    platform: "wechat"
+  });
+  meetingDialogVisible.value = true;
+};
+
+// 鎵撳紑鏂囦欢鍏变韩寮圭獥
+const openFileShareDialog = () => {
+  // 閲嶇疆琛ㄥ崟
+  Object.assign(fileShareForm.value, {
+    title: "",
+    description: "",
+    departments: [],
+    files: []
+  });
+  fileList.value = [];
+  fileShareDialogVisible.value = true;
+};
+
+// 鎵嬪姩鍒锋柊鏁版嵁
+const manualRefresh = () => {
+  generateNewData();
+  getList();
+  ElMessage.success("鎵嬪姩鍒锋柊瀹屾垚锛屽凡鐢熸垚鏂伴�氱煡");
+};
+
+// 鎻愪氦閫氱煡琛ㄥ崟
+const submitForm = async () => {
+  try {
+    await formRef.value.validate();
+    
+    if (dialogType.value === "add") {
+      // 鏂板閫氱煡
+      const newNotification = {
+        id: (mockData.length + 1).toString(),
+        title: form.value.title,
+        type: form.value.type,
+        priority: form.value.priority,
+        status: "draft",
+        content: form.value.content,
+        departments: form.value.departments,
+        expireDate: form.value.expireDate,
+        syncMethods: form.value.syncMethods,
+        createTime: new Date().toLocaleString()
+      };
+      
+      mockData.unshift(newNotification);
+      ElMessage.success("閫氱煡鍒涘缓鎴愬姛");
+    } else {
+      // 缂栬緫閫氱煡
+      const index = mockData.findIndex(item => item.id === selectedIds.value[0]);
+      if (index !== -1) {
+        Object.assign(mockData[index], {
+          title: form.value.title,
+          type: form.value.type,
+          priority: form.value.priority,
+          content: form.value.content,
+          departments: form.value.departments,
+          expireDate: form.value.expireDate,
+          syncMethods: form.value.syncMethods
+        });
+        ElMessage.success("閫氱煡鏇存柊鎴愬姛");
+      }
+    }
+    
+    dialogVisible.value = false;
+    getList();
+  } catch (error) {
+    console.error("琛ㄥ崟楠岃瘉澶辫触:", error);
+  }
+};
+
+// 鍒涘缓浼氳
+const createMeeting = async () => {
+  try {
+    await meetingFormRef.value.validate();
+    
+    // 妯℃嫙鍒涘缓浼氳
+    const meetingInfo = {
+      title: meetingForm.value.title,
+      startTime: meetingForm.value.startTime,
+      duration: meetingForm.value.duration,
+      participants: meetingForm.value.participants,
+      description: meetingForm.value.description,
+      platform: meetingForm.value.platform,
+      meetingId: `MTG${Date.now()}`
+    };
+    
+    // 妯℃嫙鍙戦�佸埌浼佷笟寰俊/閽夐拤
+    const platformName = meetingPlatforms.find(p => p.value === meetingForm.value.platform)?.label || "鏈煡骞冲彴";
+    
+    ElMessage.success(`浼氳鍒涘缓鎴愬姛锛佷細璁甀D: ${meetingInfo.meetingId}锛屽皢閫氳繃${platformName}鍙戦�侀�氱煡`);
+    meetingDialogVisible.value = false;
+    
+         // 鑾峰彇鍙備細浜哄憳淇℃伅
+     const participantNames = meetingForm.value.participants.map(participantId => {
+       const employee = employees.value.find(emp => emp.value === participantId);
+       return employee ? employee.label : '鏈煡浜哄憳';
+     }).join('銆�');
+     
+     // 鑾峰彇鍙備細浜哄憳璇︾粏淇℃伅
+     const participantDetails = meetingForm.value.participants.map(participantId => {
+       const employee = employees.value.find(emp => emp.value === participantId);
+       return employee ? {
+         name: employee.label,
+         dept: employee.dept,
+         phone: employee.phone,
+         email: employee.email
+       } : null;
+     }).filter(Boolean);
+    
+    // 灏嗕細璁俊鎭坊鍔犲埌閫氱煡鍒楄〃
+    const meetingNotification = {
+      id: (mockData.length + 1).toString(),
+      title: `[浼氳閫氱煡] ${meetingInfo.title}`,
+      type: "meeting",
+      priority: "high",
+      status: "published",
+             content: `浼氳鏃堕棿: ${meetingInfo.startTime}锛屾椂闀�: ${meetingInfo.duration}鍒嗛挓锛屽钩鍙�: ${meetingPlatforms.find(p => p.value === meetingForm.value.platform)?.label || "鏈煡骞冲彴"}锛屽弬浼氫汉鍛�: ${participantNames}锛屽叡${participantDetails.length}浜篳,
+      departments: [],
+      expireDate: "",
+      syncMethods: [meetingForm.value.platform],
+      createTime: new Date().toLocaleString()
+    };
+    
+    mockData.unshift(meetingNotification);
+    getList();
+  } catch (error) {
+    console.error("浼氳琛ㄥ崟楠岃瘉澶辫触:", error);
+  }
+};
+
+// 鏂囦欢涓婁紶澶勭悊
+const handleFileChange = (file) => {
+  const isLt10M = file.size / 1024 / 1024 < 10;
+  if (!isLt10M) {
+    ElMessage.error("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 10MB!");
+    return false;
+  }
+  
+  const fileInfo = {
+    name: file.name,
+    size: file.size,
+    type: file.type,
+    uid: file.uid
+  };
+  
+  fileList.value.push(fileInfo);
+  fileShareForm.value.files.push(fileInfo);
+  return false; // 闃绘鑷姩涓婁紶
+};
+
+// 绉婚櫎鏂囦欢
+const removeFile = (file) => {
+  const index = fileList.value.findIndex(item => item.uid === file.uid);
+  if (index !== -1) {
+    const index2 = fileShareForm.value.files.findIndex(item => item.uid === file.uid);
+    if (index2 !== -1) {
+      fileShareForm.value.files.splice(index2, 1);
+    }
+    fileList.value.splice(index, 1);
+  }
+};
+
+// 鍏变韩鏂囦欢
+const shareFiles = async () => {
+  try {
+    await fileShareFormRef.value.validate();
+    
+    if (fileShareForm.value.files.length === 0) {
+      ElMessage.warning("璇疯嚦灏戦�夋嫨涓�涓枃浠�");
+      return;
+    }
+    
+    // 妯℃嫙鏂囦欢鍏变韩
+    const shareInfo = {
+      title: fileShareForm.value.title,
+      description: fileShareForm.value.description,
+      departments: fileShareForm.value.departments,
+      files: fileShareForm.value.files,
+      shareId: `FILE${Date.now()}`
+    };
+    
+    ElMessage.success(`鏂囦欢鍏变韩鎴愬姛锛佸叡浜獻D: ${shareInfo.shareId}锛屽凡閫氱煡鐩稿叧閮ㄩ棬`);
+    fileShareDialogVisible.value = false;
+    
+    // 灏嗘枃浠跺叡浜俊鎭坊鍔犲埌閫氱煡鍒楄〃
+    const fileShareNotification = {
+      id: (mockData.length + 1).toString(),
+      title: `[鏂囦欢鍏变韩] ${shareInfo.title}`,
+      type: "temporary",
+      priority: "medium",
+      status: "published",
+      content: `鍏变韩鎻忚堪: ${shareInfo.description}锛屾枃浠舵暟閲�: ${shareInfo.files.length}涓猔,
+      departments: shareInfo.departments,
+      expireDate: "",
+      syncMethods: ["wechat", "dingtalk"],
+      createTime: new Date().toLocaleString()
+    };
+    
+    mockData.unshift(fileShareNotification);
+    getList();
+  } catch (error) {
+    console.error("鏂囦欢鍏变韩琛ㄥ崟楠岃瘉澶辫触:", error);
+  }
+};
+
+// 鍙戝竷閫氱煡
+const publishNotification = (row) => {
+  row.status = "published";
+  ElMessage.success("閫氱煡鍙戝竷鎴愬姛");
+  getList();
+};
+
+// 鎾ゅ洖閫氱煡
+const revokeNotification = (row) => {
+  row.status = "draft";
+  ElMessage.success("閫氱煡宸叉挙鍥�");
+  getList();
+};
+
+// 鍒犻櫎閫氱煡
+const handleDelete = () => {
+  if (selectedIds.value.length === 0) {
+    ElMessage.warning("璇烽�夋嫨瑕佸垹闄ょ殑閫氱煡");
+    return;
+  }
+  
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
+    confirmButtonText: "纭",
+    cancelButtonText: "鍙栨秷",
+    type: "warning",
+  }).then(() => {
+    ElMessage.success("鍒犻櫎鎴愬姛");
+    selectedIds.value = [];
+    getList();
+  }).catch(() => {
+    // 鐢ㄦ埛鍙栨秷
+  });
+};
+</script>
+
+<style scoped>
+.auto-refresh-info {
+  margin-bottom: 15px;
+}
+
+.auto-refresh-info .el-alert {
+  border-radius: 8px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+
+.el-upload__tip {
+  color: #909399;
+  font-size: 12px;
+  margin-top: 8px;
+}
+
+.el-checkbox-group {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.el-checkbox {
+  margin-right: 0;
+}
+</style>

--
Gitblit v1.9.3