|
|
|
@ -4,17 +4,17 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { getPendingApplyList } from '@/api/erf/erf' |
|
|
|
import { getPendingApplyList, getPendingTriConfirmList } from '@/api/erf/erf' |
|
|
|
import approvalConfig from '@/config/approval-notification.config' |
|
|
|
|
|
|
|
/** |
|
|
|
* 全局审批通知管理器 |
|
|
|
* |
|
|
|
* 功能: |
|
|
|
* 1. 登录后自动检查待审批项 |
|
|
|
* 1. 登录后自动检查待审批项(经理审批、计划员排产、三方确认) |
|
|
|
* 2. 定时轮询检查新的待审批项(默认5分钟,可在配置文件中修改) |
|
|
|
* 3. 在浏览器右下角弹出通知提示 |
|
|
|
* 4. 点击通知跳转到审批页面 |
|
|
|
* 3. 在浏览器右下角弹出合并通知提示 |
|
|
|
* 4. 点击不同类型的提醒跳转到对应页面 |
|
|
|
* |
|
|
|
* 配置文件:src/config/approval-notification.config.js |
|
|
|
*/ |
|
|
|
@ -33,6 +33,12 @@ export default { |
|
|
|
isChecking: false, // 是否正在检查中(防止重复调用) |
|
|
|
firstCheckTimeout: null, // 首次检查的定时器 |
|
|
|
activeNotifications: [], // 当前显示的所有通知实例 |
|
|
|
// 上一次各类型待办数量(用于轮询时检测新增) |
|
|
|
lastCounts: { |
|
|
|
manager: 0, |
|
|
|
planner: 0, |
|
|
|
triConfirm: 0 |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
@ -175,6 +181,7 @@ export default { |
|
|
|
this.isChecking = false |
|
|
|
this.notifiedApplications.clear() |
|
|
|
this.lastCheckTime = null |
|
|
|
this.lastCounts = { manager: 0, planner: 0, triConfirm: 0 } |
|
|
|
|
|
|
|
console.log('[审批通知] 通知系统已停止') |
|
|
|
}, |
|
|
|
@ -242,7 +249,8 @@ export default { |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 检查待审批的申请单 |
|
|
|
* 检查所有类型的待办事项(经理审批、计划员排产、三方确认) |
|
|
|
* 三个接口并行调用,结果合并后显示一个通知 |
|
|
|
* @param {boolean} isFirstCheck - 是否首次检查 |
|
|
|
*/ |
|
|
|
checkPendingApprovals(isFirstCheck = false) { |
|
|
|
@ -258,221 +266,208 @@ export default { |
|
|
|
} |
|
|
|
|
|
|
|
this.isChecking = true |
|
|
|
console.log(`[审批通知] 开始检查待审批申请单... (首次检查: ${isFirstCheck})`) |
|
|
|
console.log(`[审批通知] 开始检查所有待办事项... (首次检查: ${isFirstCheck})`) |
|
|
|
|
|
|
|
const requestData = { |
|
|
|
// 1. 经理审批查询 |
|
|
|
const managerRequest = getPendingApplyList({ |
|
|
|
site: this.currentSite, |
|
|
|
currentUserId: this.currentUserId, |
|
|
|
userName: this.currentUserName, |
|
|
|
pageType : 'MANAGER', // 经理审批页面,只查询经理审批节点 |
|
|
|
pendingStatus: '已下达', // 审批节点只查询已下达状态 |
|
|
|
page :1, |
|
|
|
limit :20 |
|
|
|
} |
|
|
|
pageType: 'MANAGER', |
|
|
|
pendingStatus: '已下达', |
|
|
|
page: 1, |
|
|
|
limit: 20 |
|
|
|
}).then(({data}) => { |
|
|
|
if (data && data.code === 0) { |
|
|
|
const list = data.rows || (data.page && data.page.list) || [] |
|
|
|
return { count: data.totalCount || (data.page && data.page.totalCount) || list.length, list: list } |
|
|
|
} |
|
|
|
return { count: 0, list: [] } |
|
|
|
}).catch(() => ({ count: 0, list: [] })) |
|
|
|
|
|
|
|
// 2. 计划员排产查询 |
|
|
|
const plannerRequest = getPendingApplyList({ |
|
|
|
site: this.currentSite, |
|
|
|
currentUserId: this.currentUserId, |
|
|
|
userName: this.currentUserName, |
|
|
|
pageType: 'PLANNER', |
|
|
|
pendingStatus: '已批准', |
|
|
|
page: 1, |
|
|
|
limit: 20 |
|
|
|
}).then(({data}) => { |
|
|
|
if (data && data.code === 0) { |
|
|
|
const list = data.rows || (data.page && data.page.list) || [] |
|
|
|
return { count: data.totalCount || (data.page && data.page.totalCount) || list.length, list: list } |
|
|
|
} |
|
|
|
return { count: 0, list: [] } |
|
|
|
}).catch(() => ({ count: 0, list: [] })) |
|
|
|
|
|
|
|
getPendingApplyList(requestData).then(({data}) => { |
|
|
|
// 3. 三方确认查询 |
|
|
|
const triConfirmRequest = getPendingTriConfirmList({ |
|
|
|
currentUserId: this.currentUserId, |
|
|
|
site: this.currentSite |
|
|
|
}).then(({data}) => { |
|
|
|
if (data && data.code === 0) { |
|
|
|
const pendingList = data.rows || data.page.list || [] |
|
|
|
const list = data.list || [] |
|
|
|
return { count: list.length, list: list } |
|
|
|
} |
|
|
|
return { count: 0, list: [] } |
|
|
|
}).catch(() => ({ count: 0, list: [] })) |
|
|
|
|
|
|
|
// 并行执行三个查询 |
|
|
|
Promise.all([managerRequest, plannerRequest, triConfirmRequest]).then(([managerResult, plannerResult, triConfirmResult]) => { |
|
|
|
const counts = { |
|
|
|
manager: managerResult.count, |
|
|
|
planner: plannerResult.count, |
|
|
|
triConfirm: triConfirmResult.count |
|
|
|
} |
|
|
|
|
|
|
|
console.log(`[审批通知] 查询结果 - 经理审批: ${counts.manager}, 计划员排产: ${counts.planner}, 三方确认: ${counts.triConfirm}`) |
|
|
|
|
|
|
|
console.log(`[审批通知] 发现 ${pendingList.length} 个待审批申请单`) |
|
|
|
const totalCount = counts.manager + counts.planner + counts.triConfirm |
|
|
|
|
|
|
|
if (pendingList.length > 0) { |
|
|
|
if (isFirstCheck) { |
|
|
|
// 首次检查:显示汇总通知 |
|
|
|
this.showSummaryNotification(pendingList) |
|
|
|
} else { |
|
|
|
// 轮询检查:只通知新的申请单 |
|
|
|
this.showNewApprovalNotifications(pendingList) |
|
|
|
if (totalCount > 0) { |
|
|
|
if (isFirstCheck) { |
|
|
|
// 首次检查:显示合并通知 |
|
|
|
this.showCombinedNotification(counts) |
|
|
|
} else { |
|
|
|
// 轮询检查:只在有新增时显示通知 |
|
|
|
const hasNewItems = counts.manager > this.lastCounts.manager || |
|
|
|
counts.planner > this.lastCounts.planner || |
|
|
|
counts.triConfirm > this.lastCounts.triConfirm |
|
|
|
|
|
|
|
if (hasNewItems) { |
|
|
|
// 关闭旧通知,显示新通知 |
|
|
|
this.closeAllNotifications() |
|
|
|
this.showCombinedNotification(counts) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this.lastCheckTime = new Date() |
|
|
|
} |
|
|
|
|
|
|
|
// 更新上次的数量记录 |
|
|
|
this.lastCounts = { ...counts } |
|
|
|
this.lastCheckTime = new Date() |
|
|
|
this.isChecking = false |
|
|
|
}).catch(error => { |
|
|
|
console.error('[审批通知] 检查待审批申请单失败:', error) |
|
|
|
console.error('[审批通知] 检查待办事项失败:', error) |
|
|
|
this.isChecking = false |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 显示汇总通知(首次登录时) |
|
|
|
* @param {Array} approvalList - 待审批列表 |
|
|
|
* 显示合并通知(包含经理审批、计划员排产、三方确认) |
|
|
|
* 使用 VNode 创建可点击的分区通知 |
|
|
|
* @param {Object} counts - 各类型待办数量 { manager, planner, triConfirm } |
|
|
|
*/ |
|
|
|
showSummaryNotification(approvalList) { |
|
|
|
const count = approvalList.length |
|
|
|
|
|
|
|
// 记录所有申请单号(避免重复通知) |
|
|
|
approvalList.forEach(item => { |
|
|
|
this.notifiedApplications.add(item.applyNo || item.applicationNo) |
|
|
|
}) |
|
|
|
|
|
|
|
// 创建通知实例 |
|
|
|
const notificationInstance = this.$notify({ |
|
|
|
title: '待审批提醒', |
|
|
|
customClass: this.config.style.summaryClass, |
|
|
|
dangerouslyUseHTMLString: true, |
|
|
|
message: ` |
|
|
|
<div style="line-height: 1.6;"> |
|
|
|
<p style="margin: 0 0 8px 0;"> |
|
|
|
您有 <span class="count-highlight">${count}</span> 个工程实验申请单待审批 |
|
|
|
</p> |
|
|
|
<p style="margin: 0; font-size: 12px; color: #909399;"> |
|
|
|
点击此通知查看详情 |
|
|
|
</p> |
|
|
|
</div> |
|
|
|
`, |
|
|
|
type: 'warning', |
|
|
|
position: this.config.notification.position, |
|
|
|
duration: this.config.notification.summaryDuration, |
|
|
|
showClose: this.config.notification.showClose, |
|
|
|
onClick: () => { |
|
|
|
// 点击后立即关闭通知并从列表中移除 |
|
|
|
this.removeNotification(notificationInstance) |
|
|
|
notificationInstance.close() |
|
|
|
// 跳转到审批列表 |
|
|
|
this.navigateToApprovalList() |
|
|
|
}, |
|
|
|
onClose: () => { |
|
|
|
// 通知关闭时从列表中移除 |
|
|
|
this.removeNotification(notificationInstance) |
|
|
|
showCombinedNotification(counts) { |
|
|
|
const h = this.$createElement |
|
|
|
let notificationRef = null |
|
|
|
|
|
|
|
// 关闭通知并跳转的辅助函数 |
|
|
|
const navigateAndClose = (path) => { |
|
|
|
if (notificationRef) { |
|
|
|
this.removeNotification(notificationRef) |
|
|
|
notificationRef.close() |
|
|
|
} |
|
|
|
}) |
|
|
|
this.$router.push({ path: path }).catch(err => { |
|
|
|
this.log('路由跳转失败: ' + err.message, 'warn') |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// 保存通知实例 |
|
|
|
this.activeNotifications.push(notificationInstance) |
|
|
|
console.log(`[审批通知] 已创建汇总通知,当前活动通知数: ${this.activeNotifications.length}`) |
|
|
|
// 构建通知内容的各个区块 |
|
|
|
const sections = [] |
|
|
|
|
|
|
|
// 经理审批区块 |
|
|
|
if (counts.manager > 0) { |
|
|
|
sections.push( |
|
|
|
h('div', { |
|
|
|
class: 'notification-item manager-item', |
|
|
|
on: { click: (e) => { e.stopPropagation(); navigateAndClose('erf-expApplyApproval') } } |
|
|
|
}, [ |
|
|
|
h('div', { class: 'notification-item-icon' }, [ |
|
|
|
h('i', { class: 'el-icon-s-check', style: { color: '#E6A23C', fontSize: '18px' } }) |
|
|
|
]), |
|
|
|
h('div', { class: 'notification-item-content' }, [ |
|
|
|
h('p', { class: 'notification-item-text' }, [ |
|
|
|
'您有 ', |
|
|
|
h('span', { class: 'count-highlight', style: { color: '#E6A23C' } }, counts.manager), |
|
|
|
' 个工程实验申请单待审批' |
|
|
|
]), |
|
|
|
h('p', { class: 'notification-item-link' }, '点击此通知查看详情') |
|
|
|
]) |
|
|
|
]) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// 播放提示音 |
|
|
|
// this.playNotificationSound() |
|
|
|
}, |
|
|
|
// 计划员排产区块 |
|
|
|
if (counts.planner > 0) { |
|
|
|
sections.push( |
|
|
|
h('div', { |
|
|
|
class: 'notification-item planner-item', |
|
|
|
on: { click: (e) => { e.stopPropagation(); navigateAndClose('erf-plannerSchedule') } } |
|
|
|
}, [ |
|
|
|
h('div', { class: 'notification-item-icon' }, [ |
|
|
|
h('i', { class: 'el-icon-date', style: { color: '#409EFF', fontSize: '18px' } }) |
|
|
|
]), |
|
|
|
h('div', { class: 'notification-item-content' }, [ |
|
|
|
h('p', { class: 'notification-item-text' }, [ |
|
|
|
'您有 ', |
|
|
|
h('span', { class: 'count-highlight', style: { color: '#409EFF' } }, counts.planner), |
|
|
|
' 个工程实验申请单待排产' |
|
|
|
]), |
|
|
|
h('p', { class: 'notification-item-link' }, '点击此通知查看详情') |
|
|
|
]) |
|
|
|
]) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 显示新的审批通知(轮询时) |
|
|
|
* @param {Array} approvalList - 待审批列表 |
|
|
|
*/ |
|
|
|
showNewApprovalNotifications(approvalList) { |
|
|
|
// 筛选出新的申请单 |
|
|
|
const newApprovals = approvalList.filter(item => { |
|
|
|
const applyNo = item.applyNo || item.applicationNo |
|
|
|
return !this.notifiedApplications.has(applyNo) |
|
|
|
}) |
|
|
|
// 三方确认区块 |
|
|
|
if (counts.triConfirm > 0) { |
|
|
|
sections.push( |
|
|
|
h('div', { |
|
|
|
class: 'notification-item tri-confirm-item', |
|
|
|
on: { click: (e) => { e.stopPropagation(); navigateAndClose('erf-triConfirm') } } |
|
|
|
}, [ |
|
|
|
h('div', { class: 'notification-item-icon' }, [ |
|
|
|
h('i', { class: 'el-icon-finished', style: { color: '#67C23A', fontSize: '18px' } }) |
|
|
|
]), |
|
|
|
h('div', { class: 'notification-item-content' }, [ |
|
|
|
h('p', { class: 'notification-item-text' }, [ |
|
|
|
'您有 ', |
|
|
|
h('span', { class: 'count-highlight', style: { color: '#67C23A' } }, counts.triConfirm), |
|
|
|
' 个三方确认工序待确认' |
|
|
|
]), |
|
|
|
h('p', { class: 'notification-item-link' }, '点击此通知查看详情') |
|
|
|
]) |
|
|
|
]) |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
if (newApprovals.length === 0) { |
|
|
|
// 如果没有任何待办,不显示通知 |
|
|
|
if (sections.length === 0) { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
console.log(`[审批通知] 发现 ${newApprovals.length} 个新的待审批申请单`) |
|
|
|
|
|
|
|
// 显示每个新申请单的通知 |
|
|
|
newApprovals.forEach((item, index) => { |
|
|
|
// 延迟显示,避免多个通知同时弹出 |
|
|
|
setTimeout(() => { |
|
|
|
this.showSingleApprovalNotification(item) |
|
|
|
}, index * 500) |
|
|
|
}) |
|
|
|
|
|
|
|
// 播放提示音 |
|
|
|
//this.playNotificationSound() |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 显示单个审批通知 |
|
|
|
* @param {Object} approvalItem - 审批项信息 |
|
|
|
*/ |
|
|
|
showSingleApprovalNotification(approvalItem) { |
|
|
|
const applyNo = approvalItem.applyNo || approvalItem.applicationNo |
|
|
|
const applicant = approvalItem.creatorName || approvalItem.applyUserName || '未知' |
|
|
|
const applyType = approvalItem.experimentType || approvalItem.applicationType || '未知' |
|
|
|
const createdDate = approvalItem.createTime || approvalItem.applyDate || '' |
|
|
|
|
|
|
|
// 记录已通知 |
|
|
|
this.notifiedApplications.add(applyNo) |
|
|
|
// 创建完整的通知消息 VNode |
|
|
|
const message = h('div', { class: 'combined-notification-body' }, sections) |
|
|
|
|
|
|
|
// 创建通知实例 |
|
|
|
const notificationInstance = this.$notify({ |
|
|
|
title: '新的审批申请', |
|
|
|
customClass: this.config.style.singleClass, |
|
|
|
dangerouslyUseHTMLString: true, |
|
|
|
message: ` |
|
|
|
<div style="line-height: 1.8;"> |
|
|
|
<p style="margin: 0 0 5px 0;"> |
|
|
|
<strong style="color: #303133;">申请单号:</strong> |
|
|
|
<span style="color: #409EFF;">${applyNo}</span> |
|
|
|
</p> |
|
|
|
<p style="margin: 0 0 5px 0;"> |
|
|
|
<strong style="color: #303133;">申请人:</strong>${applicant} |
|
|
|
</p> |
|
|
|
<p style="margin: 0 0 5px 0;"> |
|
|
|
<strong style="color: #303133;">申请类型:</strong>${applyType} |
|
|
|
</p> |
|
|
|
${createdDate ? ` |
|
|
|
<p style="margin: 0 0 5px 0;"> |
|
|
|
<strong style="color: #303133;">申请时间:</strong> |
|
|
|
<span style="font-size: 12px;">${createdDate}</span> |
|
|
|
</p> |
|
|
|
` : ''} |
|
|
|
<p style="margin: 8px 0 0 0; font-size: 12px; color: #909399; border-top: 1px dashed #DCDFE6; padding-top: 8px;"> |
|
|
|
点击处理审批 |
|
|
|
</p> |
|
|
|
</div> |
|
|
|
`, |
|
|
|
type: 'info', |
|
|
|
notificationRef = this.$notify({ |
|
|
|
title: '待审批提醒', |
|
|
|
customClass: 'approval-notification combined-notification', |
|
|
|
message: message, |
|
|
|
type: 'warning', |
|
|
|
position: this.config.notification.position, |
|
|
|
duration: this.config.notification.singleDuration, |
|
|
|
duration: this.config.notification.summaryDuration, |
|
|
|
showClose: this.config.notification.showClose, |
|
|
|
onClick: () => { |
|
|
|
// 点击后立即关闭通知并从列表中移除 |
|
|
|
this.removeNotification(notificationInstance) |
|
|
|
notificationInstance.close() |
|
|
|
// 跳转到审批详情 |
|
|
|
this.navigateToApprovalDetail(approvalItem) |
|
|
|
}, |
|
|
|
onClose: () => { |
|
|
|
// 通知关闭时从列表中移除 |
|
|
|
this.removeNotification(notificationInstance) |
|
|
|
this.removeNotification(notificationRef) |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
// 保存通知实例 |
|
|
|
this.activeNotifications.push(notificationInstance) |
|
|
|
console.log(`[审批通知] 已创建单个通知 (${applyNo}),当前活动通知数: ${this.activeNotifications.length}`) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 跳转到审批列表页面 |
|
|
|
*/ |
|
|
|
navigateToApprovalList() { |
|
|
|
// 根据配置文件中的路由进行跳转 |
|
|
|
this.$router.push({ |
|
|
|
path: 'erf-expApplyApproval' |
|
|
|
}).catch(err => { |
|
|
|
this.log('路由跳转失败:', err.message, 'warn') |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* 跳转到审批详情页面 |
|
|
|
* @param {Object} approvalItem - 审批项信息 |
|
|
|
*/ |
|
|
|
navigateToApprovalDetail(approvalItem) { |
|
|
|
const applyNo = approvalItem.applyNo || approvalItem.applicationNo |
|
|
|
|
|
|
|
// 根据配置文件中的路由进行跳转 |
|
|
|
const queryParam = this.config.routes.detailQueryParam |
|
|
|
const query = { |
|
|
|
[queryParam]: applyNo, |
|
|
|
mode: 'approve' |
|
|
|
} |
|
|
|
|
|
|
|
this.$router.push({ |
|
|
|
path: 'erf-expApplyApproval', |
|
|
|
query: query |
|
|
|
}).catch(err => { |
|
|
|
// 如果没有专门的审批详情页,跳转到列表页 |
|
|
|
this.log('路由跳转失败,尝试跳转到列表页: ' + err.message, 'warn') |
|
|
|
this.navigateToApprovalList() |
|
|
|
}) |
|
|
|
this.activeNotifications.push(notificationRef) |
|
|
|
console.log(`[审批通知] 已创建合并通知(经理:${counts.manager}, 排产:${counts.planner}, 三方:${counts.triConfirm}),当前活动通知数: ${this.activeNotifications.length}`) |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
|