Refactor frontend workspaces and centralize API contracts
Organize domain APIs and types under common/apis, shared components under named folders, and private workspace logic alongside each page. Use Bearer sessions, explicit response envelopes, session-aware routing and streams, and configurable login captcha presentation for the deployed backend contract. Preserve news, economic calendar, crawler, market, chat, Skills, settings, and demo trading workflows with responsive layouts and explicit configuration saves. Validate with frontend lint, type checking, 22 test groups, production builds, and deployed desktop/mobile page checks.
This commit is contained in:
1 parent
77b33e5e77
commit
bc480fb806
102 files changed
+4716
-1707
No files matched your search
@@ -0,0 +1,46 @@
|
||||
import type { ChatStreamHandler, SendChatRequestData } from "@@/apis/chat/type"
|
||||
import { sendChatApi } from "@@/apis/chat"
|
||||
import { streamCanceled } from "@/http/stream"
|
||||
import { useUserStore } from "@/pinia/stores/user"
|
||||
|
||||
/** Chat POST 只发送一次;失败由聊天区显示,拒绝 Promise 阻止后续成功处理。 */
|
||||
export function useChatStream() {
|
||||
const streaming = ref(false)
|
||||
const user = useUserStore()
|
||||
let controller: AbortController | undefined
|
||||
|
||||
async function send(body: SendChatRequestData, onEvent: ChatStreamHandler) {
|
||||
if (streaming.value)
|
||||
throw new Error("正在生成")
|
||||
const version = user.sessionVersion
|
||||
const request = new AbortController()
|
||||
controller = request
|
||||
streaming.value = true
|
||||
try {
|
||||
let finished = false
|
||||
await sendChatApi(body, request.signal, version, (event) => {
|
||||
if (event.name === "error")
|
||||
throw new Error(event.data.message)
|
||||
if (event.name === "done") finished = true
|
||||
onEvent(event)
|
||||
})
|
||||
if (!finished) throw new Error("生成连接提前中断,请核对已保存的回复")
|
||||
} catch (error) {
|
||||
if (!streamCanceled(error) && version === user.sessionVersion)
|
||||
onEvent({ name: "error", data: { message: error instanceof Error ? error.message : "生成失败" } })
|
||||
throw error
|
||||
} finally {
|
||||
if (controller === request) {
|
||||
streaming.value = false
|
||||
controller = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
controller?.abort()
|
||||
}
|
||||
watch(() => user.sessionVersion, stop, { flush: "sync" })
|
||||
onBeforeUnmount(stop)
|
||||
return { streaming, send, stop }
|
||||
}
|
||||
Reference in new issue
Block a user