| | |
| | | v-model="form.expireDate" |
| | | type="date" |
| | | placeholder="请选择有效期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | |
| | | <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%" |
| | | /> |
| | |
| | | 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 = { |
| | |
| | | tableLoading: false, |
| | | page: { |
| | | current: 1, |
| | | size: 100, |
| | | size: 20, |
| | | total: 0, |
| | | }, |
| | | tableData: [], |
| | |
| | | form: { |
| | | title: "", |
| | | type: "", |
| | | priority: "medium", |
| | | priority: "", |
| | | content: "", |
| | | departments: [], |
| | | expireDate: "", |
| | |
| | | fileList: [] |
| | | }); |
| | | |
| | | const { |
| | | searchForm, |
| | | tableLoading, |
| | | page, |
| | | tableData, |
| | | const { |
| | | searchForm, |
| | | tableLoading, |
| | | page, |
| | | tableData, |
| | | selectedIds, |
| | | form, |
| | | dialogVisible, |
| | |
| | | ] |
| | | } |
| | | ]); |
| | | |
| | | // 模拟数据 |
| | | 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}放假安排的通知", |
| | |
| | | employeesLoading.value = true; |
| | | // 优先使用系统用户接口(按租户获取) |
| | | const userResponse = await userListNoPageByTenantId(); |
| | | |
| | | |
| | | if (userResponse.data) { |
| | | employees.value = userResponse.data.map(user => ({ |
| | | label: user.nickName || user.userName || '未知姓名', |
| | |
| | | })).filter(user => user.status === '0'); // 只显示正常状态的用户 |
| | | } else { |
| | | // 如果系统用户接口失败,使用员工台账接口 |
| | | const response = await staffOnJobListPage({ |
| | | pageNum: 1, |
| | | pageSize: 1000, |
| | | 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 || '未知姓名', |
| | |
| | | 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" } |
| | | { 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; |
| | |
| | | } |
| | | groups[dept].push(employee); |
| | | }); |
| | | |
| | | |
| | | // 按部门名称排序,确保显示顺序一致 |
| | | return Object.keys(groups) |
| | | .sort() |
| | |
| | | const filterEmployees = (query) => { |
| | | if (query !== '') { |
| | | const lowerQuery = query.toLowerCase(); |
| | | return employees.value.filter(employee => |
| | | return employees.value.filter(employee => |
| | | employee.label.toLowerCase().includes(lowerQuery) || |
| | | employee.dept.toLowerCase().includes(lowerQuery) || |
| | | (employee.phone && employee.phone.includes(query)) || |
| | |
| | | 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 getEmployeeInfo = (employeeId) => { |
| | | const employee = employees.value.find(emp => emp.value === employeeId); |
| | | if (!employee) return null; |
| | | |
| | | |
| | | return { |
| | | name: employee.label, |
| | | dept: employee.dept, |
| | |
| | | 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('{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, |
| | |
| | | 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}`); |
| | | }; |
| | | |
| | |
| | | |
| | | 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; |
| | | listNotification({...page.value, ...searchForm.value}) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | }, 500); |
| | | tableData.value = res.data.records |
| | | page.value.total = res.data.total; |
| | | }).catch(err => { |
| | | tableLoading.value = false; |
| | | }) |
| | | }; |
| | | |
| | | // 分页处理 |
| | |
| | | dialogTitle.value = "新增通知"; |
| | | // 重置表单 |
| | | Object.assign(form.value, { |
| | | id: "", |
| | | title: "", |
| | | type: "", |
| | | priority: "medium", |
| | | 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 || [] |
| | | }); |
| | | } |
| | |
| | | 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("通知创建成功"); |
| | | addNotification({...form.value}).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("添加成功"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | } 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("通知更新成功"); |
| | | } |
| | | updateNotification({...form.value}).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("更新成功"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | } |
| | | |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | } catch (error) { |
| | | console.error("表单验证失败:", error); |
| | | } |
| | |
| | | const createMeeting = async () => { |
| | | try { |
| | | await meetingFormRef.value.validate(); |
| | | |
| | | |
| | | // 模拟创建会议 |
| | | const meetingInfo = { |
| | | title: meetingForm.value.title, |
| | |
| | | duration: meetingForm.value.duration, |
| | | participants: meetingForm.value.participants, |
| | | description: meetingForm.value.description, |
| | | platform: meetingForm.value.platform, |
| | | meetingId: `MTG${Date.now()}` |
| | | 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}发送通知`); |
| | | meetingDialogVisible.value = false; |
| | | |
| | | // 获取参会人员信息 |
| | | // 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); |
| | |
| | | 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}人`, |
| | | 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() |
| | | syncMethods: [meetingForm.value.platform] |
| | | }; |
| | | |
| | | mockData.unshift(meetingNotification); |
| | | getList(); |
| | | 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); |
| | | } |
| | |
| | | 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); |
| | | fileShareForm.value.files.push(fileInfo.name); |
| | | return false; // 阻止自动上传 |
| | | }; |
| | | |
| | |
| | | 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(`文件共享成功!共享ID: ${shareInfo.shareId},已通知相关部门`); |
| | | fileShareDialogVisible.value = false; |
| | | |
| | | 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 = { |
| | | id: (mockData.length + 1).toString(), |
| | | title: `[文件共享] ${shareInfo.title}`, |
| | | type: "temporary", |
| | | priority: "medium", |
| | |
| | | departments: shareInfo.departments, |
| | | expireDate: "", |
| | | syncMethods: ["wechat", "dingtalk"], |
| | | createTime: new Date().toLocaleString() |
| | | }; |
| | | |
| | | mockData.unshift(fileShareNotification); |
| | | getList(); |
| | | 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) => { |
| | | row.status = "published"; |
| | | ElMessage.success("通知发布成功"); |
| | | getList(); |
| | | 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 = "published"; |
| | | updateNotification({...form.value}).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("通知发布成功"); |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | }; |
| | | |
| | | // 撤回通知 |
| | | const revokeNotification = (row) => { |
| | | row.status = "draft"; |
| | | ElMessage.success("通知已撤回"); |
| | | getList(); |
| | | 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 handleDelete = () => { |
| | | if (selectedIds.value.length === 0) { |
| | | let ids = []; |
| | | if (selectedIds.value.length > 0) { |
| | | ids = selectedIds.value; |
| | | }else{ |
| | | ElMessage.warning("请选择要删除的通知"); |
| | | return; |
| | | } |
| | | |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | ElMessage.success("删除成功"); |
| | | selectedIds.value = []; |
| | | getList(); |
| | | delNotification(ids).then(res => { |
| | | if(res.code == 200){ |
| | | ElMessage.success("删除成功"); |
| | | selectedIds.value = []; |
| | | getList(); |
| | | } |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }) |
| | | }).catch(() => { |
| | | // 用户取消 |
| | | }); |