修复询问卡发送后仍回闪:点发送即收起本轮卡,并避免 loading 用旧 waitingReason 重绘。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
35
web/app.js
35
web/app.js
@@ -866,10 +866,14 @@ async function sendText(text) {
|
|||||||
const qHost = $("questions-card-host");
|
const qHost = $("questions-card-host");
|
||||||
const activeQs = getActiveQuestions(lastView);
|
const activeQs = getActiveQuestions(lastView);
|
||||||
const reviewing = lastView?.waitingReason?.kind === "review_artifact";
|
const reviewing = lastView?.waitingReason?.kind === "review_artifact";
|
||||||
|
const cardOpen = Boolean(
|
||||||
|
activeQs?.questions?.length && qHost?.classList.contains("is-open"),
|
||||||
|
);
|
||||||
|
|
||||||
// 产物验收:底栏有字 ⇒ 按修改意见重做;接受走「接受目前产物」
|
// 产物验收:底栏有字 ⇒ 按修改意见重做;接受走「接受目前产物」
|
||||||
if (reviewing && trimmed) {
|
if (reviewing && trimmed) {
|
||||||
try {
|
try {
|
||||||
|
clearQuestionCardState(qHost, lastView);
|
||||||
renderSession(lastView, true);
|
renderSession(lastView, true);
|
||||||
const view = await api(`/api/sessions/${encodeURIComponent(sessionId)}/messages`, {
|
const view = await api(`/api/sessions/${encodeURIComponent(sessionId)}/messages`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -878,17 +882,18 @@ async function sendText(text) {
|
|||||||
clearQuestionCardState(qHost);
|
clearQuestionCardState(qHost);
|
||||||
renderSession(view, false);
|
renderSession(view, false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (qHost) qHost._qDismissed = null;
|
||||||
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeQs?.questions?.length && qHost?.classList.contains("is-open")) {
|
if (cardOpen) {
|
||||||
const collected = collectQuestionAnswers(qHost, lastView);
|
const collected = collectQuestionAnswers(qHost, lastView);
|
||||||
const answered = collected.ok
|
const answered = collected.ok
|
||||||
? collected.answers.filter((a) => a.text && a.text !== "(未答)")
|
? collected.answers.filter((a) => a.text && a.text !== "(未答)")
|
||||||
: [];
|
: [];
|
||||||
// 可选追问:未选任何选项时,允许直接发自由文本(或空操作交给下方逻辑)
|
// 必答题未选:拦住发送
|
||||||
if (!collected.ok && !activeQs.optional) {
|
if (!collected.ok && !activeQs.optional) {
|
||||||
if (typeof collected.page === "number" && qHost._qState) {
|
if (typeof collected.page === "number" && qHost._qState) {
|
||||||
qHost._qState.page = collected.page;
|
qHost._qState.page = collected.page;
|
||||||
@@ -899,8 +904,10 @@ async function sendText(text) {
|
|||||||
alert(collected.error);
|
alert(collected.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 有选中 → 问+答拼接发送,并收起卡
|
||||||
if (collected.ok && answered.length) {
|
if (collected.ok && answered.length) {
|
||||||
try {
|
try {
|
||||||
|
clearQuestionCardState(qHost, lastView);
|
||||||
renderSession(lastView, true);
|
renderSession(lastView, true);
|
||||||
const body = { answers: collected.answers };
|
const body = { answers: collected.answers };
|
||||||
if (trimmed) body.note = trimmed;
|
if (trimmed) body.note = trimmed;
|
||||||
@@ -911,10 +918,18 @@ async function sendText(text) {
|
|||||||
clearQuestionCardState(qHost);
|
clearQuestionCardState(qHost);
|
||||||
renderSession(view, false);
|
renderSession(view, false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (qHost) qHost._qDismissed = null;
|
||||||
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 未选中:不带问;点发送仍算答复 → 收起卡
|
||||||
|
if (!trimmed) {
|
||||||
|
clearQuestionCardState(qHost, lastView);
|
||||||
|
await runAction("skip_questions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearQuestionCardState(qHost, lastView);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!trimmed) return;
|
if (!trimmed) return;
|
||||||
@@ -924,26 +939,38 @@ async function sendText(text) {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ text: trimmed }),
|
body: JSON.stringify({ text: trimmed }),
|
||||||
});
|
});
|
||||||
|
clearQuestionCardState(qHost);
|
||||||
renderSession(view, false);
|
renderSession(view, false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (cardOpen && qHost) qHost._qDismissed = null;
|
||||||
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runAction(action) {
|
async function runAction(action) {
|
||||||
if (!sessionId) return;
|
if (!sessionId) return;
|
||||||
|
const qHost = $("questions-card-host");
|
||||||
try {
|
try {
|
||||||
|
// 接受 / 跳过:先收起询问卡,避免 loading 用旧 waitingReason 再画出来
|
||||||
|
if (action === "accept" || action === "skip_questions") {
|
||||||
|
clearQuestionCardState(qHost, lastView);
|
||||||
|
}
|
||||||
renderSession(lastView, true);
|
renderSession(lastView, true);
|
||||||
const view = await api(`/api/sessions/${encodeURIComponent(sessionId)}/actions`, {
|
const view = await api(`/api/sessions/${encodeURIComponent(sessionId)}/actions`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ action }),
|
body: JSON.stringify({ action }),
|
||||||
});
|
});
|
||||||
// 接受产物 = 不再完善 → 收起询问卡;跳过追问同理
|
|
||||||
if (action === "accept" || action === "skip_questions") {
|
if (action === "accept" || action === "skip_questions") {
|
||||||
clearQuestionCardState($("questions-card-host"));
|
clearQuestionCardState(qHost);
|
||||||
}
|
}
|
||||||
renderSession(view, false);
|
renderSession(view, false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (
|
||||||
|
(action === "accept" || action === "skip_questions") &&
|
||||||
|
qHost
|
||||||
|
) {
|
||||||
|
qHost._qDismissed = null;
|
||||||
|
}
|
||||||
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
if (lastView) renderSession({ ...lastView, hints: [err.message] }, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* 结构化询问卡:点字母选中,点文案编辑;左右分页。
|
* 结构化询问卡:点字母选中,点文案编辑;左右分页。
|
||||||
* 普通提问:提交走底栏 composer(问+答拼进上下文),卡上无独立发送钮。
|
* 询问是对同一次发送的可选增强:有选中则问+答拼接;未选中则不带问。
|
||||||
|
* 点发送即答复 → 收起本轮卡(卡上无独立发送钮)。
|
||||||
* 产物验收挂载题:底栏有字优先按「改产物」发送;无字时才提交所选答案。
|
* 产物验收挂载题:底栏有字优先按「改产物」发送;无字时才提交所选答案。
|
||||||
* 分页 / 跳过为悬浮控件,不占独立 header/footer 行。
|
* 分页 / 跳过为悬浮控件,不占独立 header/footer 行。
|
||||||
*/
|
*/
|
||||||
@@ -196,8 +197,29 @@ export function collectQuestionAnswers(host, view) {
|
|||||||
return { ok: true, answers };
|
return { ok: true, answers };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearQuestionCardState(host) {
|
/**
|
||||||
if (host) host._qState = null;
|
* 收起询问卡。传入 view 时标记本轮题已答复,避免 loading 用旧 waitingReason 把卡又画回来。
|
||||||
|
* @param {HTMLElement | null | undefined} host
|
||||||
|
* @param {object} [view]
|
||||||
|
*/
|
||||||
|
export function clearQuestionCardState(host, view) {
|
||||||
|
if (!host) return;
|
||||||
|
const active = view ? getActiveQuestions(view) : null;
|
||||||
|
if (active?.questions?.length && view?.id) {
|
||||||
|
host._qDismissed = {
|
||||||
|
sessionId: view.id,
|
||||||
|
key: JSON.stringify(active.questions.map((q) => q.id)),
|
||||||
|
};
|
||||||
|
} else if (host._qState?.sessionId && host._qState?.key) {
|
||||||
|
host._qDismissed = {
|
||||||
|
sessionId: host._qState.sessionId,
|
||||||
|
key: host._qState.key,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
host._qState = null;
|
||||||
|
host.hidden = true;
|
||||||
|
host.innerHTML = "";
|
||||||
|
host.classList.remove("is-open");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -209,6 +231,19 @@ export function renderQuestionsCard(host, view, _handlers = {}) {
|
|||||||
if (!host) return false;
|
if (!host) return false;
|
||||||
const active = getActiveQuestions(view);
|
const active = getActiveQuestions(view);
|
||||||
if (!active?.questions?.length) {
|
if (!active?.questions?.length) {
|
||||||
|
host.hidden = true;
|
||||||
|
host.innerHTML = "";
|
||||||
|
host.classList.remove("is-open");
|
||||||
|
host._qDismissed = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const qKey = JSON.stringify(active.questions.map((q) => q.id));
|
||||||
|
// 本轮已通过发送/跳过答复 → 在 waitingReason 清掉前也不再打开
|
||||||
|
if (
|
||||||
|
host._qDismissed?.sessionId === view.id &&
|
||||||
|
host._qDismissed?.key === qKey
|
||||||
|
) {
|
||||||
host.hidden = true;
|
host.hidden = true;
|
||||||
host.innerHTML = "";
|
host.innerHTML = "";
|
||||||
host.classList.remove("is-open");
|
host.classList.remove("is-open");
|
||||||
@@ -218,11 +253,11 @@ export function renderQuestionsCard(host, view, _handlers = {}) {
|
|||||||
host.hidden = false;
|
host.hidden = false;
|
||||||
host.classList.add("is-open");
|
host.classList.add("is-open");
|
||||||
|
|
||||||
const state = host._qState?.sessionId === view.id && host._qState?.key === JSON.stringify(active.questions.map((q) => q.id))
|
const state = host._qState?.sessionId === view.id && host._qState?.key === qKey
|
||||||
? host._qState
|
? host._qState
|
||||||
: {
|
: {
|
||||||
sessionId: view.id,
|
sessionId: view.id,
|
||||||
key: JSON.stringify(active.questions.map((q) => q.id)),
|
key: qKey,
|
||||||
page: 0,
|
page: 0,
|
||||||
// questionId -> { optionId?, text, otherText? }
|
// questionId -> { optionId?, text, otherText? }
|
||||||
answers: {},
|
answers: {},
|
||||||
|
|||||||
@@ -722,8 +722,8 @@ body[data-lifecycle="play"] .panel-agent { background: #f7fef9; }
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
.questions-card-host[hidden] { display: none !important; }
|
.questions-card-host[hidden] { display: none !important; }
|
||||||
/* 开启时占 feed 剩余高度的上限,不把整页撑出视口 */
|
/* 开启时占 feed 剩余高度的上限,不把整页撑出视口;勿与 [hidden] 并存抢 display */
|
||||||
.questions-card-host.is-open {
|
.questions-card-host.is-open:not([hidden]) {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-height: 48%;
|
max-height: 48%;
|
||||||
|
|||||||
Reference in New Issue
Block a user