fix: show work capture context before actions

This commit is contained in:
2026-07-21 05:01:43 +08:00
parent 4536d607e3
commit 11250811a6
2 changed files with 28 additions and 3 deletions
+23 -2
View File
@@ -32,7 +32,13 @@
<text class="today-result-arrow">查看 ›</text>
</button>
<scroll-view scroll-y class="chat-thread" :scroll-top="threadScrollTop" :scroll-with-animation="true">
<scroll-view
scroll-y
class="chat-thread"
:scroll-top="threadScrollTop"
:scroll-into-view="threadScrollIntoView"
:scroll-with-animation="true"
>
<view class="thread-inner">
<view class="bubble-row left">
<image class="avatar master-avatar" src="/static/mentor-female-avatar.png" mode="aspectFill" />
@@ -61,7 +67,7 @@
</view>
</view>
<view v-else class="bubble-row left">
<view v-else :id="`chat-message-${msg.id}`" class="bubble-row left">
<image class="avatar master-avatar" src="/static/mentor-female-avatar.png" mode="aspectFill" />
<view class="master-col">
<view v-if="msg.voiceStatus !== 'unavailable'" class="voice-line">
@@ -428,6 +434,7 @@ const quickQuestionPlaceholder = computed(() => `例如: ${quickQuestions.value[
const messages = ref<ChatMsg[]>([]);
const threadScrollTop = ref(0);
const threadScrollIntoView = ref('');
const composerRef = ref<InstanceType<typeof ChatComposer> | null>(null);
const summaryCard = ref<SummaryCardResponse | null>(null);
const loading = ref(false);
@@ -496,10 +503,20 @@ const speechPlayback = createSpeechPlaybackController(
const scrollToBottom = () => {
void nextTick(() => {
threadScrollIntoView.value = '';
threadScrollTop.value = 100000 + (++scrollSeq * 200);
});
};
const scrollToMessageStart = (messageId: number) => {
void nextTick(() => {
threadScrollIntoView.value = '';
void nextTick(() => {
threadScrollIntoView.value = `chat-message-${messageId}`;
});
});
};
const pushMsg = <T extends ChatMsg>(msg: Omit<T, 'id'>): T => {
const withId = { ...msg, id: ++msgSeq } as T;
messages.value = [...messages.value, withId];
@@ -511,6 +528,10 @@ const replaceMsg = (id: number, next: ChatMsg | null) => {
messages.value = next
? messages.value.map((item) => (item.id === id ? next : item))
: messages.value.filter((item) => item.id !== id);
if (next?.role === 'master' && next.result.memoryCandidate) {
scrollToMessageStart(id);
return;
}
scrollToBottom();
};
+5 -1
View File
@@ -48,10 +48,14 @@ test('工作助手按项目名称选择并为文字、媒体和工具请求携
assert.match(auth, /reconcileCurrentProject/);
});
test('项目选择面板避开底栏且确认卡内容增长后重新滚到底部', async () => {
test('项目选择面板避开底栏,普通消息滚底且确认卡从识别结论处展示', async () => {
const page = await read('../src/pages/user/sop/index.vue');
assert.match(page, /inset:\s*0 0 var\(--window-bottom, 0px\)/);
assert.match(page, /let scrollSeq = 0/);
assert.match(page, /threadScrollTop\.value = 100000 \+ \(\+\+scrollSeq \* 200\)/);
assert.match(page, /:scroll-into-view="threadScrollIntoView"/);
assert.match(page, /:id="`chat-message-\$\{msg\.id\}`"/);
assert.match(page, /next\?\.role === 'master' && next\.result\.memoryCandidate/);
assert.match(page, /scrollToMessageStart\(id\)/);
});