Add smart ACK provider for WeChat MP replies

Replace fixed ackText with a rule-based AckProvider that picks
response templates by message type and intent (translate, summary,
rewrite, poster, ppt, mindmap, code, search, schedule). Pure sync,
zero I/O, auto-falls back to config.ackText on any error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
john
2026-06-26 15:19:03 +08:00
parent 9ed4fd48d7
commit 9b4a25799f
162 changed files with 17276 additions and 2054 deletions
+95
View File
@@ -11,6 +11,7 @@
// createOpsApi -> /api/ops/v1/* plaza operations console (ops_role)
import express from 'express';
import { sendData, sendError } from './api-response.mjs';
import { PLAN_CATALOG, tokensToCallsApprox } from './billing-subscription.mjs';
import { hasOpsRole } from './plaza-ops.mjs';
import { mapPlazaError } from './plaza-posts.mjs';
@@ -42,6 +43,7 @@ export function createAdminApi({
plazaPosts,
plazaOps,
wechatAdmin,
subscriptionService,
}) {
function requireAdmin(req, res, next) {
if (!req.currentUser || req.currentUser.role !== 'admin') {
@@ -272,6 +274,44 @@ export function createAdminApi({
res.json(await wechatAdmin.listDeliveries(req.query));
});
adminApi.get('/wechat/balance-alerts', requireAdmin, async (req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
res.json(await wechatAdmin.listBalanceAlerts(req.query));
});
adminApi.post('/wechat/balance-alerts', requireAdmin, async (req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
const result = await wechatAdmin.createBalanceAlert(req.body ?? {});
if (!result.ok) return res.status(400).json({ message: result.message });
res.status(201).json(result);
});
adminApi.post('/wechat/balance-alerts/:id/cancel', requireAdmin, async (req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
const result = await wechatAdmin.cancelBalanceAlert(req.params.id);
if (!result.ok) return res.status(404).json({ message: result.message ?? '取消失败' });
res.json(result);
});
adminApi.post('/wechat/balance-alerts/:id/resume', requireAdmin, async (req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
const result = await wechatAdmin.resumeBalanceAlert(req.params.id);
if (!result.ok) return res.status(404).json({ message: result.message ?? '恢复失败' });
res.json(result);
});
adminApi.get('/wechat/web-notifications', requireAdmin, async (req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
res.json(await wechatAdmin.listWebNotifications(req.query));
});
adminApi.post('/wechat/web-notifications', requireAdmin, async (req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
const result = await wechatAdmin.createWebNotification(req.body ?? {});
if (!result.ok) return res.status(400).json({ message: result.message });
res.status(201).json(result);
});
adminApi.post('/wechat/users/:userId/route/clear', requireAdmin, async (req, res) => {
if (!wechatAdmin) return res.status(503).json({ message: '服务号管理未启用' });
const result = await wechatAdmin.clearRouteForUser(req.params.userId);
@@ -407,6 +447,61 @@ export function createAdminApi({
}
});
// ── Subscription management ───────────────────────────────────────────────
adminApi.get('/subscriptions', requireAdmin, async (req, res) => {
if (!subscriptionService) return res.status(503).json({ message: '订阅服务未启用' });
const { userId, status, page, pageSize } = req.query;
const result = await subscriptionService.listSubscriptions({ userId, status, page, pageSize });
res.json(result);
});
adminApi.get('/subscriptions/plans', requireAdmin, (_req, res) => {
res.json(
Object.entries(PLAN_CATALOG).map(([planType, def]) => ({
planType,
...def,
approxCalls: tokensToCallsApprox(def.periodTokens),
})),
);
});
adminApi.get('/users/:userId/subscription', requireAdmin, async (req, res) => {
if (!subscriptionService) return res.status(503).json({ message: '订阅服务未启用' });
const sub = await subscriptionService.getActiveSubscription(req.params.userId);
res.json({ subscription: sub });
});
adminApi.post('/users/:userId/subscription', requireAdmin, async (req, res) => {
if (!subscriptionService) return res.status(503).json({ message: '订阅服务未启用' });
const { planType, durationDays, note } = req.body ?? {};
if (!planType) return res.status(400).json({ message: '缺少 planType' });
const result = await subscriptionService.grantSubscription(
req.params.userId,
planType,
durationDays ? Number(durationDays) : undefined,
req.currentUser.id,
note,
);
if (!result.ok) return res.status(400).json({ message: result.message });
res.json(result);
});
adminApi.delete('/users/:userId/subscription', requireAdmin, async (req, res) => {
if (!subscriptionService) return res.status(503).json({ message: '订阅服务未启用' });
const result = await subscriptionService.cancelSubscription(
req.params.userId,
req.currentUser.id,
);
res.json(result);
});
adminApi.post('/subscriptions/expire-stale', requireAdmin, async (_req, res) => {
if (!subscriptionService) return res.status(503).json({ message: '订阅服务未启用' });
const count = await subscriptionService.expireStaleSubscriptions();
res.json({ expiredCount: count });
});
return adminApi;
}