|
|
@@ -3,6 +3,14 @@ import type { CardInstance, ChatMessage, TaskState } from '../api/types';
|
|
|
import { connectChatStream, type ParsedSseEvent } from '../api/sse';
|
|
|
import { fetchCard, submitCardAction } from '../api/client';
|
|
|
|
|
|
+function randomUUID(): string {
|
|
|
+ try { return randomUUID(); } catch { /* HTTP */ }
|
|
|
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
|
+ const r = (Math.random() * 16) | 0;
|
|
|
+ return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
export type ContextPanelMode = 'idle' | 'loading' | 'task' | 'error' | 'completed';
|
|
|
export type ConnectionStatus = 'online' | 'disconnected';
|
|
|
|
|
|
@@ -41,6 +49,7 @@ export const useTerminalStore = defineStore('terminal', {
|
|
|
pendingActionKey: '',
|
|
|
demoMode: import.meta.env.VITE_DEMO_MODE === 'true',
|
|
|
sending: false,
|
|
|
+ cardActionSubmitting: false,
|
|
|
selection: {} as Record<string, string>,
|
|
|
}),
|
|
|
getters: {
|
|
|
@@ -72,7 +81,7 @@ export const useTerminalStore = defineStore('terminal', {
|
|
|
return;
|
|
|
}
|
|
|
this.messages.push({
|
|
|
- id: crypto.randomUUID(),
|
|
|
+ id: randomUUID(),
|
|
|
role: 'assistant',
|
|
|
content: text,
|
|
|
streaming: true,
|
|
|
@@ -187,7 +196,7 @@ export const useTerminalStore = defineStore('terminal', {
|
|
|
|
|
|
async sendMessage(text: string): Promise<void> {
|
|
|
if (this.sending) return; // 防重入:正在发送中不允许重复调用
|
|
|
- this.addMessage({ id: crypto.randomUUID(), role: 'user', content: text });
|
|
|
+ this.addMessage({ id: randomUUID(), role: 'user', content: text });
|
|
|
this.errorMessage = '';
|
|
|
this.sending = true;
|
|
|
this.streaming = true;
|
|
|
@@ -215,13 +224,22 @@ export const useTerminalStore = defineStore('terminal', {
|
|
|
},
|
|
|
|
|
|
async submitCard(payload: Record<string, unknown>): Promise<void> {
|
|
|
- if (!this.activeCard) return;
|
|
|
+ if (!this.activeCard || this.cardActionSubmitting) return;
|
|
|
|
|
|
const actionName = this.activeCard.actions[0]?.actionName;
|
|
|
if (!actionName) return;
|
|
|
|
|
|
this.pendingActionKey = `${this.activeCard.cardInstanceId}-${actionName}`;
|
|
|
this.errorMessage = '';
|
|
|
+ this.cardActionSubmitting = true;
|
|
|
+
|
|
|
+ // 15 秒超时兜底,防止网络异常导致按钮永久禁用
|
|
|
+ const timeoutId = setTimeout(() => {
|
|
|
+ if (this.cardActionSubmitting) {
|
|
|
+ this.setError('请求超时,请重试');
|
|
|
+ this.cardActionSubmitting = false;
|
|
|
+ }
|
|
|
+ }, 15_000);
|
|
|
|
|
|
try {
|
|
|
const result = await submitCardAction(
|
|
|
@@ -230,13 +248,18 @@ export const useTerminalStore = defineStore('terminal', {
|
|
|
payload,
|
|
|
);
|
|
|
|
|
|
+ clearTimeout(timeoutId);
|
|
|
+
|
|
|
if (result.nextCard?.cardInstanceId) {
|
|
|
const fullCard = await fetchCard(result.nextCard.cardInstanceId);
|
|
|
this.setActiveCard(fullCard);
|
|
|
}
|
|
|
} catch (err) {
|
|
|
+ clearTimeout(timeoutId);
|
|
|
this.setError((err as Error).message);
|
|
|
throw err;
|
|
|
+ } finally {
|
|
|
+ this.cardActionSubmitting = false;
|
|
|
}
|
|
|
},
|
|
|
},
|