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