|
|
@@ -60,7 +60,7 @@ const groupHasRejected = (rejectedList, group, period) =>
|
|
|
|
|
|
const buildRoute = (tab, query = {}) => buildManageRoute({ tab, ...query });
|
|
|
|
|
|
-/** 通知 id 仅依赖账期 + 集团,避免 record.id 因字段补全而变化 */
|
|
|
+/** 通知 id 仅依赖类型 + 账期 + 集团,保证同一条通知不会重复入库 */
|
|
|
const notifyRecordId = (type, record) => {
|
|
|
const qingpuGroup = (record.qingpuGroup ?? '').trim() || 'unknown';
|
|
|
const group = (record.group ?? '').trim() || 'unknown';
|
|
|
@@ -68,13 +68,17 @@ const notifyRecordId = (type, record) => {
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
+ * 生成当前时刻所有适用的通知(幂等,同 id 不会重复入库)
|
|
|
* @param {{ pendingList: object[], approvedList: object[], rejectedList: object[] }} lists
|
|
|
- * @returns {Array<{ id: string, time: string, type: string, title: string, timestamp: number, route?: object }>}
|
|
|
+ * @param {{ currentGroup?: string }} options - 可选,限定集团范围
|
|
|
+ * @returns {Array<{ id: string, time: string, type: string, title: string, timestamp: number, route?: object, group: string }>}
|
|
|
*/
|
|
|
export const buildNotifications = ({
|
|
|
pendingList = [],
|
|
|
approvedList = [],
|
|
|
rejectedList = [],
|
|
|
+} = {}, {
|
|
|
+ currentGroup = '',
|
|
|
} = {}) => {
|
|
|
const notifications = [];
|
|
|
const now = Date.now();
|
|
|
@@ -82,8 +86,11 @@ export const buildNotifications = ({
|
|
|
const deadline = getPeriodDeadlineDate(currentPeriod);
|
|
|
const daysLeft = Math.ceil((deadline.getTime() - now) / (86400000));
|
|
|
|
|
|
+ // ── 待审核(来自 pendingList)─────────────────────────────
|
|
|
aggregateReportRecords(pendingList, { fallbackPeriod: currentPeriod }).forEach((record) => {
|
|
|
- const group = record.group || record.qingpuGroup;
|
|
|
+ const group = record.qingpuGroup || record.group;
|
|
|
+ if (currentGroup && group !== currentGroup) return;
|
|
|
+
|
|
|
const latest = record.items?.reduce((best, item) => {
|
|
|
const t = toTimestamp(getFillTime(item));
|
|
|
return t >= toTimestamp(getFillTime(best)) ? item : best;
|
|
|
@@ -94,6 +101,7 @@ export const buildNotifications = ({
|
|
|
type: '待审核',
|
|
|
title: `${group} ${record.period} 资产月报(${record.count} 条)待审核`,
|
|
|
timestamp: toTimestamp(getFillTime(latest)),
|
|
|
+ group,
|
|
|
route: buildRoute('audit', {
|
|
|
sub: 'pending',
|
|
|
group: record.qingpuGroup || group,
|
|
|
@@ -102,8 +110,11 @@ export const buildNotifications = ({
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ // ── 已通过(来自 approvedList)────────────────────────────
|
|
|
aggregateReportRecords(approvedList, { fallbackPeriod: currentPeriod }).forEach((record) => {
|
|
|
- const group = record.group || record.qingpuGroup;
|
|
|
+ const group = record.qingpuGroup || record.group;
|
|
|
+ if (currentGroup && group !== currentGroup) return;
|
|
|
+
|
|
|
const latest = record.items?.reduce((best, item) => {
|
|
|
const t = toTimestamp(getAuditTime(item));
|
|
|
return t >= toTimestamp(getAuditTime(best)) ? item : best;
|
|
|
@@ -114,6 +125,7 @@ export const buildNotifications = ({
|
|
|
type: '审核结果',
|
|
|
title: `${record.period} 月报已通过(${group},${record.count} 条)`,
|
|
|
timestamp: toTimestamp(getAuditTime(latest)),
|
|
|
+ group,
|
|
|
route: buildRoute('archive', {
|
|
|
sub: 'history',
|
|
|
group: record.qingpuGroup || group,
|
|
|
@@ -123,8 +135,11 @@ export const buildNotifications = ({
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ // ── 已驳回(来自 rejectedList)────────────────────────────
|
|
|
aggregateReportRecords(rejectedList, { fallbackPeriod: currentPeriod }).forEach((record) => {
|
|
|
- const group = record.group || record.qingpuGroup;
|
|
|
+ const group = record.qingpuGroup || record.group;
|
|
|
+ if (currentGroup && group !== currentGroup) return;
|
|
|
+
|
|
|
const latest = record.items?.reduce((best, item) => {
|
|
|
const t = toTimestamp(getAuditTime(item));
|
|
|
return t >= toTimestamp(getAuditTime(best)) ? item : best;
|
|
|
@@ -136,6 +151,7 @@ export const buildNotifications = ({
|
|
|
type: '审核结果',
|
|
|
title: `${record.period} 月报已被驳回(${group})${reason ? `:${reason}` : ''}`,
|
|
|
timestamp: toTimestamp(getAuditTime(latest)),
|
|
|
+ group,
|
|
|
route: buildRoute('archive', {
|
|
|
sub: 'history',
|
|
|
group: record.qingpuGroup || group,
|
|
|
@@ -145,9 +161,11 @@ export const buildNotifications = ({
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ // ── 填报提醒(当前账期截止前 7 天,尚未提交的集团)────────
|
|
|
if (daysLeft > 0 && daysLeft <= 7) {
|
|
|
const allLists = [pendingList, approvedList, rejectedList];
|
|
|
GROUP_ORDER.forEach((group) => {
|
|
|
+ if (currentGroup && group !== currentGroup) return;
|
|
|
if (groupHasAnySubmission(allLists, group, currentPeriod)) return;
|
|
|
notifications.push({
|
|
|
id: `reminder:${currentPeriod}:${group}`,
|
|
|
@@ -155,15 +173,19 @@ export const buildNotifications = ({
|
|
|
type: '填报提醒',
|
|
|
title: `${currentPeriod} 月报截止倒计时 ${daysLeft} 天(${group})`,
|
|
|
timestamp: now,
|
|
|
+ group,
|
|
|
route: buildRoute('archive'),
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ // ── 逾期催办(上月截止后未通过/未提交的集团)──────────────
|
|
|
const prevPeriod = getPreviousPeriod(currentPeriod);
|
|
|
const prevDeadline = getPeriodDeadlineDate(prevPeriod);
|
|
|
if (now > prevDeadline.getTime()) {
|
|
|
GROUP_ORDER.forEach((group) => {
|
|
|
+ if (currentGroup && group !== currentGroup) return;
|
|
|
+
|
|
|
if (groupHasApproved(approvedList, group, prevPeriod)) return;
|
|
|
|
|
|
const rejected = groupHasRejected(rejectedList, group, prevPeriod);
|
|
|
@@ -180,6 +202,7 @@ export const buildNotifications = ({
|
|
|
type: '逾期催办',
|
|
|
title: `${prevPeriod} 月报已逾期,请补报(${group})`,
|
|
|
timestamp: prevDeadline.getTime(),
|
|
|
+ group,
|
|
|
route: buildRoute('archive'),
|
|
|
});
|
|
|
return;
|
|
|
@@ -192,12 +215,14 @@ export const buildNotifications = ({
|
|
|
type: '逾期催办',
|
|
|
title: `${prevPeriod} 月报被驳回且未重报,请尽快处理(${group})`,
|
|
|
timestamp: now,
|
|
|
+ group,
|
|
|
route: buildRoute('archive', { sub: 'history', group, period: prevPeriod, status: '已驳回' }),
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ // ── 租约到期/预警(来自已通过资产的 status 字段)──────────
|
|
|
const expiryItems = approvedList
|
|
|
.filter((item) => item.status === 'red' || item.status === 'orange')
|
|
|
.slice(0, 8);
|
|
|
@@ -205,12 +230,16 @@ export const buildNotifications = ({
|
|
|
expiryItems.forEach((item) => {
|
|
|
const label = item.c_bh || item.c_qymc || '资产';
|
|
|
const withinOneMonth = item.status === 'red';
|
|
|
+ const group = normalizeGroupName(item.c_ssqpjt) || '未知';
|
|
|
+ if (currentGroup && group !== currentGroup) return;
|
|
|
+
|
|
|
notifications.push({
|
|
|
id: `expiry:${item.id}`,
|
|
|
time: formatDateTime(item.update_time || now),
|
|
|
type: withinOneMonth ? '租约到期' : '租约预警',
|
|
|
title: `${label} 租约${withinOneMonth ? '将于一个月内到期' : '将于三个月内到期'},请关注`,
|
|
|
timestamp: toTimestamp(item.update_time || now),
|
|
|
+ group,
|
|
|
route: buildRoute('assets'),
|
|
|
});
|
|
|
});
|