| | |
| | | <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" |
| | | /> |
| | | <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="正式通知" :value="'formal'" /> |
| | | <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="正式通知" |
| | | :value="'formal'" /> |
| | | </el-select> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px"> |
| | | <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="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> |
| | | <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> |
| | | <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-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 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="正式通知" value="formal" /> |
| | | <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="正式通知" |
| | | 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-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 label="有效期至" |
| | | prop="expireDate"> |
| | | <el-date-picker v-model="form.expireDate" |
| | | type="date" |
| | | placeholder="请选择有效期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | 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-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-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" |
| | | > |
| | | <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 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 type="primary" |
| | | @click="submitForm">确定</el-button> |
| | | <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-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 label="开始时间" |
| | | prop="startTime"> |
| | | <el-date-picker v-model="meetingForm.startTime" |
| | | type="datetime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | 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%" |
| | | /> |
| | | <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-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-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;" |
| | | > |
| | | <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 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 type="primary" |
| | | @click="createMeeting">创建会议</el-button> |
| | | <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-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 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-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-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"> |
| | |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="shareFiles">共享文件</el-button> |
| | | <el-button @click="fileShareDialogVisible = false">取消</el-button> |
| | | <el-button type="primary" @click="shareFiles">共享文件</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | </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"; |
| | | 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"; |
| | | import { |
| | | listNotification, |
| | | addNotification, |
| | | updateNotification, |
| | | delNotification, |
| | | addOnlineMeeting, |
| | | addFileSharing, |
| | | } from "@/api/collaborativeApproval/notificationManagement.js"; |
| | | import { id } from "element-plus/es/locales.mjs"; |
| | | |
| | | // 表单验证规则 |
| | | 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: "正式通知" |
| | | }; |
| | | 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: "2025-02-15", |
| | | syncMethods: ["wechat", "dingtalk", "email"], |
| | | createTime: "2025-01-15 10:30:00" |
| | | }, |
| | | { |
| | | id: "2", |
| | | title: "技术部周例会通知", |
| | | type: "meeting", |
| | | priority: "medium", |
| | | status: "published", |
| | | content: "技术部定于每周五下午2点召开周例会,请各位同事准时参加...", |
| | | departments: ["技术部"], |
| | | expireDate: "2025-01-20", |
| | | syncMethods: ["wechat", "dingtalk"], |
| | | createTime: "2025-01-14 15:20:00" |
| | | }, |
| | | { |
| | | id: "3", |
| | | title: "员工行为规范处罚通知", |
| | | type: "penalty", |
| | | priority: "high", |
| | | status: "draft", |
| | | content: "为维护公司正常秩序,规范员工行为,现对违反公司规定的行为进行处罚...", |
| | | departments: ["人事部", "技术部", "销售部"], |
| | | expireDate: "2025-02-13", |
| | | syncMethods: ["wechat", "email"], |
| | | createTime: "2025-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: "正式通知", 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: "chenzhiqiang@company.com", status: "0" }, |
| | | { label: "刘雅婷", value: "002", dept: "销售部", phone: "13800138002", email: "liuyating@company.com", status: "0" }, |
| | | { label: "王建国", value: "003", dept: "人事部", phone: "13800138003", email: "wangjianguo@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("正在刷新员工列表..."); |
| | | 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 rules = { |
| | | title: [{ required: true, message: "请输入通知标题", trigger: "blur" }], |
| | | type: [{ required: true, message: "请选择通知类型", trigger: "change" }], |
| | | content: [{ required: true, message: "请输入通知内容", trigger: "blur" }], |
| | | }; |
| | | }; |
| | | |
| | | // 移除参会人员 |
| | | 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() |
| | | const meetingRules = { |
| | | title: [{ required: true, message: "请输入会议标题", trigger: "blur" }], |
| | | startTime: [ |
| | | { required: true, message: "请选择会议开始时间", trigger: "change" }, |
| | | ], |
| | | participants: [ |
| | | { required: true, message: "请选择参会人员", trigger: "change" }, |
| | | ], |
| | | }; |
| | | |
| | | // 添加到数据开头 |
| | | mockData.unshift(newNotification); |
| | | |
| | | // 保持数据量在合理范围内(最多保留20条) |
| | | if (mockData.length > 20) { |
| | | mockData = mockData.slice(0, 20); |
| | | } |
| | | |
| | | console.log(`[${new Date().toLocaleString()}] 自动生成新通知: ${title}`); |
| | | }; |
| | | |
| | | // 生命周期 |
| | | onMounted(() => { |
| | | getList(); |
| | | getEmployeesList(); // 获取员工列表 |
| | | startAutoRefresh(); |
| | | }); |
| | | const fileShareRules = { |
| | | title: [{ required: true, message: "请输入共享标题", trigger: "blur" }], |
| | | description: [{ required: true, message: "请输入共享描述", trigger: "blur" }], |
| | | }; |
| | | |
| | | // 开始自动刷新 |
| | | 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, { |
| | | // 响应式数据 |
| | | const data = reactive({ |
| | | searchForm: { |
| | | title: "", |
| | | type: "", |
| | | priority: "medium", |
| | | status: "", |
| | | }, |
| | | tableLoading: false, |
| | | page: { |
| | | current: 1, |
| | | size: 20, |
| | | total: 0, |
| | | }, |
| | | tableData: [], |
| | | selectedIds: [], |
| | | // 新增通知相关 |
| | | form: { |
| | | title: "", |
| | | type: "", |
| | | priority: "", |
| | | content: "", |
| | | departments: [], |
| | | expireDate: "", |
| | | syncMethods: [] |
| | | 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: "正式通知", |
| | | }; |
| | | 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" |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | // 通知标题模板 |
| | | 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: "正式通知", 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); |
| | | }); |
| | | } else if (type === "edit" && row) { |
| | | dialogTitle.value = "编辑通知"; |
| | | |
| | | // 按部门名称排序,确保显示顺序一致 |
| | | 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("正在刷新员工列表..."); |
| | | 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; |
| | | listNotification({ ...page.value, ...searchForm.value }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.value.total = res.data.total; |
| | | }) |
| | | .catch(err => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // 分页处理 |
| | | 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, { |
| | | id: "", |
| | | title: "", |
| | | type: "", |
| | | priority: "", |
| | | content: "", |
| | | departments: [], |
| | | expireDate: "", |
| | | status: "draft", |
| | | syncMethods: [], |
| | | }); |
| | | } else if (type === "edit" && row) { |
| | | dialogTitle.value = "编辑通知"; |
| | | Object.assign(form.value, { |
| | | id: row.id, |
| | | title: row.title, |
| | | type: row.type, |
| | | priority: row.priority, |
| | | content: row.content || "", |
| | | departments: row.departments || [], |
| | | expireDate: row.expireDate || "", |
| | | status: row.status, |
| | | 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") { |
| | | // 新增通知 |
| | | addNotification({ ...form.value }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("添加成功"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } else { |
| | | // 编辑通知 |
| | | updateNotification({ ...form.value }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("更新成功"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | } |
| | | } 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, |
| | | }; |
| | | // 新增会议 |
| | | addOnlineMeeting({ ...meetingInfo }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("会议添加成功"); |
| | | meetingDialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | // 模拟发送到企业微信/钉钉 |
| | | // const platformName = meetingPlatforms.find(p => p.value === meetingForm.value.platform)?.label || "未知平台"; |
| | | // ElMessage.success(`会议创建成功!会议ID: ${meetingInfo.meetingId},将通过${platformName}发送通知`); |
| | | |
| | | // 获取参会人员信息 |
| | | 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 = { |
| | | 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], |
| | | }; |
| | | addNotification({ ...meetingNotification }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | // 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.name); |
| | | 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, |
| | | }; |
| | | addFileSharing({ ...shareInfo }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("文件共享成功"); |
| | | fileShareDialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | |
| | | // ElMessage.success(`文件共享成功!共享ID: ${shareInfo.shareId},已通知相关部门`); |
| | | |
| | | // 将文件共享信息添加到通知列表 |
| | | const fileShareNotification = { |
| | | title: `[文件共享] ${shareInfo.title}`, |
| | | type: "temporary", |
| | | priority: "medium", |
| | | status: "published", |
| | | content: `共享描述: ${shareInfo.description},文件数量: ${shareInfo.files.length}个`, |
| | | departments: shareInfo.departments, |
| | | expireDate: "", |
| | | syncMethods: ["wechat", "dingtalk"], |
| | | }; |
| | | addNotification({ ...fileShareNotification }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("添加成功"); |
| | | // dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | |
| | | // mockData.unshift(fileShareNotification); |
| | | // getList(); |
| | | } catch (error) { |
| | | console.error("文件共享表单验证失败:", error); |
| | | } |
| | | }; |
| | | |
| | | // 发布通知 |
| | | const publishNotification = row => { |
| | | Object.assign(form.value, { |
| | | id: row.id, |
| | | title: row.title, |
| | | type: row.type, |
| | | priority: row.priority, |
| | | content: row.content || "", |
| | | departments: row.departments || [], |
| | | expireDate: row.expireDate || "", |
| | | syncMethods: row.syncMethods || [] |
| | | status: row.status, |
| | | 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(`会议创建成功!会议ID: ${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 |
| | | form.value.status = "published"; |
| | | updateNotification({ ...form.value }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("通知发布成功"); |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | }; |
| | | |
| | | 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 revokeNotification = row => { |
| | | Object.assign(form.value, { |
| | | id: row.id, |
| | | title: row.title, |
| | | type: row.type, |
| | | priority: row.priority, |
| | | content: row.content || "", |
| | | departments: row.departments || [], |
| | | expireDate: row.expireDate || "", |
| | | status: row.status, |
| | | syncMethods: row.syncMethods || [], |
| | | }); |
| | | form.value.status = "draft"; |
| | | updateNotification({ ...form.value }) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("通知已撤回"); |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | }; |
| | | |
| | | // 共享文件 |
| | | const shareFiles = async () => { |
| | | try { |
| | | await fileShareFormRef.value.validate(); |
| | | |
| | | if (fileShareForm.value.files.length === 0) { |
| | | ElMessage.warning("请至少选择一个文件"); |
| | | // 删除通知 |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedIds.value.length > 0) { |
| | | ids = selectedIds.value; |
| | | } else { |
| | | 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(`文件共享成功!共享ID: ${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(() => { |
| | | // 用户取消 |
| | | }); |
| | | }; |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delNotification(ids) |
| | | .then(res => { |
| | | if (res.code == 200) { |
| | | ElMessage.success("删除成功"); |
| | | selectedIds.value = []; |
| | | getList(); |
| | | } |
| | | }) |
| | | .catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | // 用户取消 |
| | | }); |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .auto-refresh-info { |
| | | margin-bottom: 15px; |
| | | } |
| | | .auto-refresh-info { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .auto-refresh-info .el-alert { |
| | | border-radius: 8px; |
| | | } |
| | | .auto-refresh-info .el-alert { |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | .el-upload__tip { |
| | | color: #909399; |
| | | font-size: 12px; |
| | | margin-top: 8px; |
| | | } |
| | | .el-upload__tip { |
| | | color: #909399; |
| | | font-size: 12px; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .el-checkbox-group { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | .el-checkbox-group { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .el-checkbox { |
| | | margin-right: 0; |
| | | } |
| | | .el-checkbox { |
| | | margin-right: 0; |
| | | } |
| | | </style> |