Archived
人手改的那一手真正落得下去;界面不撒谎那几处补齐
手改是**兜 AI 的错**的那一手 —— 这一轮把它从「摆在那儿但落不了地」做成真的: 件上就地改 · 保存**按地址收**,不看当下那张卡:载荷从前借道工单的 `blocks[i]` 取列名, 于是熔断卡(没有 blocks)在屏上时,人补的那一格一个字都送不出去 —— 而他要补的恰恰是把这一单卡住的那个必填格。授权面改由活动清单的台账声明把关。 · **能增删行**:错不止「这一格填错了」,还有「这一行不该在」与「漏了一行」。 删挂记号不当场抹掉(看得见、可后悔),且**删要说出来**(`drops`)—— 「没回传就是删了」会把一次不完整的回传变成一次删表。 · **必填没填按不下提交**:与放行门 L1 同一个数同一套算法;闸上摆出差在哪一行哪一格。 · 只写真改了的那几行 —— 改一格却留「修订 4 行」的痕,那句话是假的。 判据与门 · 裁量判据带谓词时**谓词说了算**:「选填缺口已补齐」基座数得出来, 人填好的目标价它照样判「客户未提供」的毛病由此消掉。 · 验收卡判据**读时现算** —— 人在成果件上补一格,判据跟着变。 · 放行门认「**办完了没有**」不认「有人写过」:从前写个 `false` 就把门推开, 于是一单没打标就进了放行门。三个数全由基座现数。 · 拒回把「活没干完」说成「数或行对不上」的毛病:判据点名的表一行都没写时直说那一步没办。 **指向两扇打不开的门,比不指还糟。** 界面不撒谎 · 日志只有三色:负责人绿 · 智能体蓝 · 系统灰(归侧五种是度量的分法,不是给人看的)。 · 验收收口答两件事:落了什么(按**交付物**点名,一份成果的几张表并成一行)、 往哪儿去(转出哪一口、带过去哪些字段);一个口都没发就直说到此为止。 · 签完到收尾之间那一段有自己的话「字已签下,正在落地」—— 中间态本来就该说出来,只是要说对。 · 消息不再被内部事件刷屏:只有从通道进来的件才谈得上「无人认领」。 · 建客户公司与联系人**一次确认落两行**;联系人编码自增不问人;卡面摆表的人读名。 A1 三案例端到端全 released:全 A 类直通 12 拍 / 客户点名跳一条 10 拍 / 新客户缺必填 14 拍。 五道门禁全绿(971 passed)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
This commit is contained in:
@@ -23,13 +23,29 @@ export type ViewBlocksProps = {
|
||||
/** 报告级「修改」态:表 / 邮件就地进入编辑(存与弃由外层报告统一管) */
|
||||
readonly editing?: boolean | undefined;
|
||||
readonly onOpenFile?: ((file: FileDoc) => void) | undefined;
|
||||
/**
|
||||
* 表被改了 —— **改完的行要交出去**(第几块、整张表的行)。
|
||||
*
|
||||
* 从前没有这个口子:可编辑表的修改只活在 `TableBlock` 自己的 `setRows` 里,
|
||||
* 人填完提交,回传载荷里一个格子都没有。实测后果最难看 ——
|
||||
* 活动派了一张「空的地方标红待填写」的执行单,人老老实实填了 13 个格子、提交,
|
||||
* Agent 收到的回传是空的,于是认为没人答,**又发了一张一模一样的单**。
|
||||
* 人以为自己白填了一遍,而系统看起来在原地打转。
|
||||
*/
|
||||
readonly onTableChange?: ((index: number, rows: readonly (readonly string[])[]) => void) | undefined;
|
||||
};
|
||||
|
||||
export function ViewBlocks({ blocks, editing = false, onOpenFile }: ViewBlocksProps) {
|
||||
export function ViewBlocks({ blocks, editing = false, onOpenFile, onTableChange }: ViewBlocksProps) {
|
||||
return (
|
||||
<>
|
||||
{blocks.map((block, i) => (
|
||||
<Block key={i} b={block} editing={editing} onOpenFile={onOpenFile} />
|
||||
<Block
|
||||
key={i}
|
||||
b={block}
|
||||
editing={editing}
|
||||
onOpenFile={onOpenFile}
|
||||
{...(onTableChange === undefined ? {} : { onTableChange: (rows: readonly (readonly string[])[]) => onTableChange(i, rows) })}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
@@ -39,10 +55,12 @@ function Block({
|
||||
b,
|
||||
editing,
|
||||
onOpenFile,
|
||||
onTableChange,
|
||||
}: {
|
||||
b: ViewBlock;
|
||||
editing: boolean;
|
||||
onOpenFile?: ((file: FileDoc) => void) | undefined;
|
||||
onTableChange?: ((rows: readonly (readonly string[])[]) => void) | undefined;
|
||||
}) {
|
||||
switch (b.t) {
|
||||
case 'callout':
|
||||
@@ -82,7 +100,7 @@ function Block({
|
||||
);
|
||||
|
||||
case 'table':
|
||||
return <TableBlock b={b} editing={editing} />;
|
||||
return <TableBlock b={b} editing={editing} {...(onTableChange === undefined ? {} : { onChange: onTableChange })} />;
|
||||
|
||||
case 'bars':
|
||||
return (
|
||||
@@ -218,13 +236,26 @@ function Section({ title, children }: { title?: string | undefined; children: Re
|
||||
}
|
||||
|
||||
/** 可编辑表:报告「修改」态下就地编辑;数据源一换即复位(渲染期调整 state,不用 effect) */
|
||||
function TableBlock({ b, editing }: { b: Extract<ViewBlock, { t: 'table' }>; editing: boolean }) {
|
||||
function TableBlock({
|
||||
b,
|
||||
editing,
|
||||
onChange,
|
||||
}: {
|
||||
b: Extract<ViewBlock, { t: 'table' }>;
|
||||
editing: boolean;
|
||||
onChange?: ((rows: readonly (readonly string[])[]) => void) | undefined;
|
||||
}) {
|
||||
const [rows, setRows] = useState<readonly (readonly string[])[]>(b.rows);
|
||||
const [srcRows, setSrcRows] = useState(b.rows);
|
||||
if (srcRows !== b.rows) {
|
||||
setSrcRows(b.rows);
|
||||
setRows(b.rows);
|
||||
}
|
||||
/** 改一格就往外交一次 —— 外层报告拿它拼回传载荷,不必等「保存」那一下 */
|
||||
const put = (next: readonly (readonly string[])[]): void => {
|
||||
setRows(next);
|
||||
onChange?.(next);
|
||||
};
|
||||
|
||||
const live = editing && b.editable === true;
|
||||
const canEditCol = (c: number) => b.editableCols === undefined || b.editableCols.includes(c);
|
||||
@@ -259,12 +290,26 @@ function TableBlock({ b, editing }: { b: Extract<ViewBlock, { t: 'table' }>; edi
|
||||
{r.map((cell, ci) => (
|
||||
<td key={ci} className={ci === 0 ? 'jc-mono' : ''}>
|
||||
{live && canEditCol(ci) ? (
|
||||
/*
|
||||
* 空格子**自己喊「待填写」**(红字占位)。
|
||||
*
|
||||
* 一张全可编辑的表摆在人面前,哪几格是空的、哪几格本来就没有,
|
||||
* 光看是分不出来的 —— 尤其这份表大半列都填着值,空的那两格
|
||||
* 在一片文字里根本不显眼。人于是签完了才发现漏填。
|
||||
* 占位字 + 红边把「这里等你」摆到脸上,填上就恢复常态。
|
||||
*/
|
||||
<input
|
||||
className={cell.trim() === '' ? 'jc-tbl-todo' : undefined}
|
||||
placeholder="待填写"
|
||||
aria-label={`${b.cols[ci] ?? ''}${cell.trim() === '' ? '(待填写)' : ''}`}
|
||||
value={cell}
|
||||
onChange={(e) =>
|
||||
setRows(rows.map((x, i) => (i === ri ? x.map((y, j) => (j === ci ? e.target.value : y)) : x)))
|
||||
put(rows.map((x, i) => (i === ri ? x.map((y, j) => (j === ci ? e.target.value : y)) : x)))
|
||||
}
|
||||
/>
|
||||
) : cell.trim() === '' ? (
|
||||
/* 只读态也别留一片空白:没填就是没填,如实说 */
|
||||
<em className="jc-tbl-empty">未填</em>
|
||||
) : (
|
||||
cell
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user