diff --git a/frontend/src/layouts/components/Tabs/components/MoreButton.vue b/frontend/src/layouts/components/Tabs/components/MoreButton.vue index ef785f5..c187d0b 100644 --- a/frontend/src/layouts/components/Tabs/components/MoreButton.vue +++ b/frontend/src/layouts/components/Tabs/components/MoreButton.vue @@ -45,6 +45,7 @@ import { useTabsStore } from '@/stores/modules/tabs' import { useGlobalStore } from '@/stores/modules/global' import { useKeepAliveStore } from '@/stores/modules/keepAlive' import { useRoute, useRouter } from 'vue-router' +import mittBus, { TAB_CLOSED_EVENT } from '@/utils/mittBus' const route = useRoute() const router = useRouter() @@ -73,6 +74,7 @@ const maximize = () => { // Close Current const closeCurrentTab = () => { if (route.meta.isAffix) return + mittBus.emit(TAB_CLOSED_EVENT, route.fullPath) tabStore.removeTabs(route.fullPath) } diff --git a/frontend/src/layouts/components/Tabs/index.vue b/frontend/src/layouts/components/Tabs/index.vue index 181b5a9..e9e0fef 100644 --- a/frontend/src/layouts/components/Tabs/index.vue +++ b/frontend/src/layouts/components/Tabs/index.vue @@ -31,6 +31,7 @@ import { useTabsStore } from '@/stores/modules/tabs' import { useAuthStore } from '@/stores/modules/auth' import { TabPaneName, TabsPaneContext } from 'element-plus' import MoreButton from './components/MoreButton.vue' +import mittBus, { TAB_CLOSED_EVENT } from '@/utils/mittBus' const route = useRoute() const router = useRouter() @@ -110,6 +111,7 @@ const tabClick = (tabItem: TabsPaneContext) => { // Remove Tab const tabRemove = (fullPath: TabPaneName) => { + mittBus.emit(TAB_CLOSED_EVENT, fullPath as string) tabStore.removeTabs(fullPath as string, fullPath == route.fullPath || '/machine/testScriptAdd' == route.fullPath) } diff --git a/frontend/src/utils/mittBus.ts b/frontend/src/utils/mittBus.ts index 688f39b..d36c9f4 100644 --- a/frontend/src/utils/mittBus.ts +++ b/frontend/src/utils/mittBus.ts @@ -1,10 +1,12 @@ import mitt from "mitt"; export const STOP_DETECTION_TIMER_EVENT = "stopDetectionTimer"; +export const TAB_CLOSED_EVENT = "tabClosed"; type MittBusEvents = { openThemeDrawer: undefined; [STOP_DETECTION_TIMER_EVENT]: undefined; + [TAB_CLOSED_EVENT]: string; }; const mittBus = mitt(); diff --git a/frontend/src/views/machine/controlSource/connectionState.ts b/frontend/src/views/machine/controlSource/connectionState.ts new file mode 100644 index 0000000..b7837f7 --- /dev/null +++ b/frontend/src/views/machine/controlSource/connectionState.ts @@ -0,0 +1,111 @@ +export type ControlSourceConnectionStatus = + | "disconnected" + | "connecting" + | "connected" + | "failed"; + +export interface ControlSourceConnectionState { + status: ControlSourceConnectionStatus; + reason: string; +} + +export interface SocketLikeMessage { + requestId?: string; + operateCode?: string; + code?: number; + data?: unknown; + desc?: string; +} + +export function createDisconnectedState(): ControlSourceConnectionState { + return { status: "disconnected", reason: "" }; +} + +export function isSourceSelectable(state: ControlSourceConnectionState): boolean { + return state.status === "disconnected" || state.status === "failed"; +} + +export function isConnectButtonEnabled(state: ControlSourceConnectionState): boolean { + return isSourceSelectable(state); +} + +export function getConnectionStatusText(state: ControlSourceConnectionState): string { + switch (state.status) { + case "connecting": + return "建立连接中"; + case "connected": + return "连接成功"; + case "failed": + return state.reason ? `连接失败:${state.reason}` : "连接失败"; + case "disconnected": + default: + return "未连接"; + } +} + +export function resolveConnectionFailureReason(message: SocketLikeMessage): string { + if (message.requestId === "connect" && message.operateCode === "Source") { + return "源服务端连接失败"; + } + + if (message.requestId === "connect" && message.operateCode === "Dev") { + return "设备服务端连接失败"; + } + + const text = + typeof message.data === "string" && message.data.trim() + ? message.data.trim() + : typeof message.desc === "string" && message.desc.trim() + ? message.desc.trim() + : ""; + + if (text) { + return text; + } + + if (message.requestId === "server_error") { + return "服务端主动关闭连接"; + } + return "源连接失败"; +} + +export function shouldHandleConnectionTerminalMessage(message: SocketLikeMessage): boolean { + if (message.requestId === "yjc_ytxjy" && message.operateCode === "INIT_GATHER") { + return message.code !== 10201; + } + + if (message.requestId === "connect" && message.operateCode === "Source") { + return true; + } + + if (message.requestId === "server_error" && message.operateCode === "server_error") { + return true; + } + + return false; +} + +export function applyConnectionTerminalMessage( + state: ControlSourceConnectionState, + message: SocketLikeMessage +): ControlSourceConnectionState { + if (message.requestId === "yjc_ytxjy" && message.operateCode === "INIT_GATHER") { + if (message.code === 10200) { + return { status: "connected", reason: "" }; + } + + if (message.code !== 10201) { + return { status: "failed", reason: resolveConnectionFailureReason(message) }; + } + } + + if (message.requestId === "connect" && message.operateCode === "Source") { + return { status: "failed", reason: resolveConnectionFailureReason(message) }; + } + + if (message.requestId === "server_error" && message.operateCode === "server_error") { + return { status: "failed", reason: resolveConnectionFailureReason(message) }; + } + + return state; +} diff --git a/frontend/src/views/machine/controlSource/index.vue b/frontend/src/views/machine/controlSource/index.vue index d282129..59b1873 100644 --- a/frontend/src/views/machine/controlSource/index.vue +++ b/frontend/src/views/machine/controlSource/index.vue @@ -1,360 +1,471 @@ - +