feat: 催办分层(超期升级+交互卡片)与超期自动释放开关

This commit is contained in:
ABAPPLO
2026-09-01 17:37:35 +08:00
parent bca524417e
commit 3e4269729c
7 changed files with 654 additions and 3 deletions

View File

@@ -1775,6 +1775,41 @@ function PartnersPage({
}
};
const triggerOverdueEscalation = async () => {
try {
setPartnerWorkingId("escalation");
const response = await fetch("/api/action", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "trigger_wecom_overdue_escalation" }),
});
const result = await readApiResponse<{
escalation?: {
overdueTasks?: number;
overdueDistributions?: number;
robotSent?: boolean;
cardSent?: number;
cardFailed?: number;
};
autoRelease?: { enabled?: boolean; released?: number; blocked?: number; failed?: number };
error?: string;
}>(response, "触发超期升级失败");
if (!response.ok) throw new Error(result.error || "触发超期升级失败");
const esc = result.escalation ?? {};
const release = result.autoRelease ?? {};
const releaseText = release.enabled
? `;自动释放 ${release.released ?? 0} 条(跳过 ${release.blocked ?? 0},失败 ${release.failed ?? 0})`
: ";自动释放未开启(WECOM_AUTO_RELEASE_DAYS)";
setToast(
`超期升级完成:${esc.overdueTasks ?? 0} 个任务 / ${esc.overdueDistributions ?? 0} 条超期,卡片已发 ${esc.cardSent ?? 0} 人${releaseText}`,
);
} catch (reason) {
setToast(reason instanceof Error ? reason.message : "触发超期升级失败");
} finally {
setPartnerWorkingId(null);
}
};
const testAppMessage = async (partner: Partner) => {
if (!partner.wecom_external_user_id) {
setToast("请先保存企业微信外部联系人 ID");
@@ -1940,8 +1975,16 @@ function PartnersPage({
>
{partnerWorkingId === "due-soon" ? "执行中…" : "立即跑一次催办"}
</button>
<button
type="button"
className="ghost-button"
disabled={partnerWorkingId === "escalation" || working || statusLoading}
onClick={() => void triggerOverdueEscalation()}
>
{partnerWorkingId === "escalation" ? "执行中…" : "跑一次超期升级"}
</button>
<p className="wecom-status-hint">
立即跑一次 daily 09:00 的催办链路:按 partner 聚合发应用消息,再向群机器人发当日汇总。
立即跑一次 daily 09:00 的催办链路:按 partner 聚合发应用消息,再向群机器人发当日汇总。超期升级会向运营群推送超期清单,并向任务所属项目总群成员发催办卡片。
</p>
{(!status?.robotConfigured || !status?.appConfigured) && (
<p className="wecom-status-hint">