perf(admin-web): 长列表虚拟滚动 + 专属页只读配置卡(裁决 16.4.3/16.4.6)+ 修限流读写成对的数据丢失
- 16.4.3(效率最高):AdminTable 超阈值走窗口化(DOM 行数与数据量解耦,上下占位行撑滚动条);
新增可复用 VirtualList;适配器消息日志换成窗口化版
- 16.4.6(操作更便利):保留列表页内联编辑,同时把「专属页只读展示该平台完整字段」真正实现
(AdapterConfigSummary,此前专属页一个配置字段都不显示)
- 🔴 顺带修一条静默数据丢失:列表页限流三项原从 acct.config.* 读,而后端把它们存**账号顶层**
⇒ 表单永远回显空、保存时 undefined→0 会把已设限流清空。现改从顶层读、留空则不发该键、非法输入报错中止;
并顺手改正用户可见的错误文案(0 = 保护性默认 6条/分,负值才是关闭)
- 复核:tsc 0 错 + vite build 成功;channel limits 27 / admin virtual scroll 8023 项断言;3 条变异反证
This commit is contained in:
1 parent
b480b04dd0
commit
c1a98d7c01
9 files changed
+976
-22
No files matched your search
@@ -6,6 +6,7 @@ import { useAuditStore } from "../audit";
|
||||
import { Button, Surface, Tag } from "../../components/primitives";
|
||||
import { Icon } from "../../components/Icon";
|
||||
import { withChannelPersona } from "./channels/channelPersona";
|
||||
import { limitRequestBody } from "./channels/channelUtils";
|
||||
import { PLATFORM_FIELDS, PLATFORM_GUIDE, PLATFORM_LABEL } from "./channelFields";
|
||||
|
||||
/** Prefill bundle computed by the module's openConfig from the backend record
|
||||
@@ -98,6 +99,14 @@ export function ChannelConfigForm({
|
||||
} else if (Object.keys(specificMap).length) {
|
||||
configMap = specificMap;
|
||||
}
|
||||
// 限流三键:留空的**不进请求体**(后端 int 契约下省略 = 0 = 未设置),非法输入整单
|
||||
// 拒绝 —— 已设限额只可能被「没回显出来」或「NaN → null」清掉,两条路都在这里封死。
|
||||
const limits = limitRequestBody({ groupMsgPerMin, msgPerMin, maxMessages });
|
||||
if (!limits.ok) {
|
||||
onError(limits.error);
|
||||
setBusy(null);
|
||||
return;
|
||||
}
|
||||
adminSaveChannelConfig(
|
||||
platform,
|
||||
withChannelPersona(
|
||||
@@ -110,9 +119,7 @@ export function ChannelConfigForm({
|
||||
denyGroups: toList(denyGroups),
|
||||
allowUsers: toList(allowUsers),
|
||||
denyUsers: toList(denyUsers),
|
||||
groupMsgPerMin: groupMsgPerMin ? Number(groupMsgPerMin) : undefined,
|
||||
msgPerMin: msgPerMin ? Number(msgPerMin) : undefined,
|
||||
maxMessages: maxMessages ? Number(maxMessages) : undefined,
|
||||
...limits.body,
|
||||
},
|
||||
{ id: personaId, dirty: personaDirty },
|
||||
),
|
||||
@@ -227,14 +234,23 @@ export function ChannelConfigForm({
|
||||
业务策略(黑白名单 / 群聊限流——不参与连接配置)
|
||||
</button>
|
||||
{polOpen ? (
|
||||
<div className="grid grid-cols-1 gap-2 px-3 pb-3 pt-1 sm:grid-cols-2">
|
||||
<Field label="allowGroups(逗号分隔白名单)" value={allowGroups} onChange={setAllowGroups} />
|
||||
<Field label="denyGroups(黑名单)" value={denyGroups} onChange={setDenyGroups} />
|
||||
<Field label="allowUsers(白名单)" value={allowUsers} onChange={setAllowUsers} />
|
||||
<Field label="denyUsers(黑名单)" value={denyUsers} onChange={setDenyUsers} />
|
||||
<Field label="groupMsgPerMin(群聊限流,≤0 关闭)" value={groupMsgPerMin} onChange={setGroupMsgPerMin} inputMode="numeric" />
|
||||
<Field label="msgPerMin" value={msgPerMin} onChange={setMsgPerMin} inputMode="numeric" />
|
||||
<Field label="maxMessages" value={maxMessages} onChange={setMaxMessages} inputMode="numeric" />
|
||||
<div className="space-y-2 px-3 pb-3 pt-1">
|
||||
{/* 数值语义按 internal/services/channelbridge/flowgate.go 的 flowOrDefault:
|
||||
0 = 保护性默认(群 6 条/分、待处理上限 50),负值 = 关闭限制;msgPerMin 只认正值。 */}
|
||||
<p className="text-[11px] leading-relaxed text-[var(--mu-text-lo)]">
|
||||
留空 = 未设置(不动盘上的值);<code>groupMsgPerMin</code>/<code>maxMessages</code> 填
|
||||
<strong className="font-medium"> 0 = 该渠道的保护性默认</strong>(群 6 条/分、待处理 50 条),
|
||||
<strong className="font-medium">负值 = 关闭该限制</strong>;<code>msgPerMin</code> 只认正值(留空/0 = 不限)。
|
||||
</p>
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
|
||||
<Field label="allowGroups(逗号分隔白名单)" value={allowGroups} onChange={setAllowGroups} />
|
||||
<Field label="denyGroups(黑名单)" value={denyGroups} onChange={setDenyGroups} />
|
||||
<Field label="allowUsers(白名单)" value={allowUsers} onChange={setAllowUsers} />
|
||||
<Field label="denyUsers(黑名单)" value={denyUsers} onChange={setDenyUsers} />
|
||||
<Field label="groupMsgPerMin(每群每分钟上限)" value={groupMsgPerMin} onChange={setGroupMsgPerMin} inputMode="numeric" />
|
||||
<Field label="msgPerMin(每分钟总上限)" value={msgPerMin} onChange={setMsgPerMin} inputMode="numeric" />
|
||||
<Field label="maxMessages(待处理消息上限)" value={maxMessages} onChange={setMaxMessages} inputMode="numeric" />
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user