<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="正式通知" :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="正式通知" 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: "正式通知"
|
};
|
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: "正式通知", 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 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(`会议创建成功!会议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
|
};
|
|
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(`文件共享成功!共享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(() => {
|
// 用户取消
|
});
|
};
|
</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>
|