mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-10-07 06:17:07 +08:00
feat: 抽离保留进程功能到设置里
This commit is contained in:
@@ -9,15 +9,7 @@ import type {
|
|||||||
PersonalWechatRuntimeProgressEvent,
|
PersonalWechatRuntimeProgressEvent,
|
||||||
PersonalWechatRuntimeStatus
|
PersonalWechatRuntimeStatus
|
||||||
} from '../../../../shared/personal-wechat-runtime'
|
} from '../../../../shared/personal-wechat-runtime'
|
||||||
import {
|
import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '../ui'
|
||||||
Button,
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
Switch
|
|
||||||
} from '../ui'
|
|
||||||
import { isMac, isWindows } from '../../utils/runtime-environment'
|
import { isMac, isWindows } from '../../utils/runtime-environment'
|
||||||
import { PersonalWechatChatComposer, type ChatMessage } from './PersonalWechatChatComposer'
|
import { PersonalWechatChatComposer, type ChatMessage } from './PersonalWechatChatComposer'
|
||||||
import { PersonalWechatSetupGuide } from './PersonalWechatSetupGuide'
|
import { PersonalWechatSetupGuide } from './PersonalWechatSetupGuide'
|
||||||
@@ -89,7 +81,6 @@ function PersonalWechatMacSendDialog({
|
|||||||
const [sendError, setSendError] = useState<string | null>(null)
|
const [sendError, setSendError] = useState<string | null>(null)
|
||||||
const [voiceDiagnostic, setVoiceDiagnostic] = useState<PersonalWechatVoiceDiagnostic | null>(null)
|
const [voiceDiagnostic, setVoiceDiagnostic] = useState<PersonalWechatVoiceDiagnostic | null>(null)
|
||||||
const [voiceDiagnosticOpen, setVoiceDiagnosticOpen] = useState(false)
|
const [voiceDiagnosticOpen, setVoiceDiagnosticOpen] = useState(false)
|
||||||
const [keepOneBotProcess, setKeepOneBotProcess] = useState(false)
|
|
||||||
const requestIdRef = useRef(0)
|
const requestIdRef = useRef(0)
|
||||||
const restoreFocusRef = useRef<HTMLElement | null>(null)
|
const restoreFocusRef = useRef<HTMLElement | null>(null)
|
||||||
const closingRef = useRef(false)
|
const closingRef = useRef(false)
|
||||||
@@ -155,36 +146,6 @@ function PersonalWechatMacSendDialog({
|
|||||||
return () => window.clearInterval(timer)
|
return () => window.clearInterval(timer)
|
||||||
}, [refreshStatus, senderStatus])
|
}, [refreshStatus, senderStatus])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isMac) return undefined
|
|
||||||
let active = true
|
|
||||||
const readKeepProcess = window.api.getPersonalWechatKeepOneBotProcess
|
|
||||||
if (!readKeepProcess) return undefined
|
|
||||||
void readKeepProcess().then((keep) => {
|
|
||||||
if (active && typeof keep === 'boolean') setKeepOneBotProcess(keep)
|
|
||||||
})
|
|
||||||
return () => {
|
|
||||||
active = false
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleKeepOneBotProcessChange = async (keep: boolean): Promise<void> => {
|
|
||||||
if (!isMac) return
|
|
||||||
const saveKeepProcess = window.api.setPersonalWechatKeepOneBotProcess
|
|
||||||
if (!saveKeepProcess) {
|
|
||||||
setSendError('请重启 TraceMemo 后再使用“保留 OneBot 进程”')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setKeepOneBotProcess(keep)
|
|
||||||
try {
|
|
||||||
const saved = await saveKeepProcess(keep)
|
|
||||||
if (typeof saved === 'boolean') setKeepOneBotProcess(saved)
|
|
||||||
} catch (error) {
|
|
||||||
setKeepOneBotProcess(!keep)
|
|
||||||
setSendError(error instanceof Error ? error.message : String(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDownloadRuntime = async (): Promise<void> => {
|
const handleDownloadRuntime = async (): Promise<void> => {
|
||||||
if (runtimeBusy) return
|
if (runtimeBusy) return
|
||||||
setRuntimeBusy(true)
|
setRuntimeBusy(true)
|
||||||
@@ -399,34 +360,14 @@ function PersonalWechatMacSendDialog({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{setupReady && isMac && (
|
{setupReady && isMac && (
|
||||||
<div className="personal-wechat-chat-footer flex items-center justify-between">
|
<div className="personal-wechat-chat-footer flex items-center justify-end">
|
||||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
||||||
<span>保留 OneBot 进程</span>
|
|
||||||
<Switch
|
|
||||||
checked={keepOneBotProcess}
|
|
||||||
onCheckedChange={(checked) => void handleKeepOneBotProcessChange(checked)}
|
|
||||||
aria-label="保留 OneBot 进程"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Button variant="link" size="sm" onClick={() => void handleOpenVoiceDiagnostic()}>
|
<Button variant="link" size="sm" onClick={() => void handleOpenVoiceDiagnostic()}>
|
||||||
语音发送诊断
|
语音发送诊断
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!setupReady && (
|
{!setupReady && (
|
||||||
<div
|
<div className="personal-wechat-chat-footer flex items-center justify-end">
|
||||||
className={`personal-wechat-chat-footer flex items-center ${isMac ? 'justify-between' : 'justify-end'}`}
|
|
||||||
>
|
|
||||||
{isMac && (
|
|
||||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
||||||
<span>保留 OneBot 进程</span>
|
|
||||||
<Switch
|
|
||||||
checked={keepOneBotProcess}
|
|
||||||
onCheckedChange={(checked) => void handleKeepOneBotProcessChange(checked)}
|
|
||||||
aria-label="保留 OneBot 进程"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<Button variant="outline" onClick={handleClose} disabled={isBusy}>
|
<Button variant="outline" onClick={handleClose} disabled={isBusy}>
|
||||||
关闭
|
关闭
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Input,
|
Input,
|
||||||
Skeleton
|
Skeleton,
|
||||||
|
Switch
|
||||||
} from '../../../components/ui'
|
} from '../../../components/ui'
|
||||||
import { PersonalWechatSetupGuide } from '../../../components/chat/PersonalWechatSetupGuide'
|
import { PersonalWechatSetupGuide } from '../../../components/chat/PersonalWechatSetupGuide'
|
||||||
import { PersonalWechatSupportedVersionsContent } from '../../../components/chat/PersonalWechatSupportedVersionsContent'
|
import { PersonalWechatSupportedVersionsContent } from '../../../components/chat/PersonalWechatSupportedVersionsContent'
|
||||||
@@ -88,6 +89,8 @@ export function PersonalWechatSendPage({
|
|||||||
const [windowsPortInput, setWindowsPortInput] = useState('')
|
const [windowsPortInput, setWindowsPortInput] = useState('')
|
||||||
const [windowsDetectedPort, setWindowsDetectedPort] = useState('')
|
const [windowsDetectedPort, setWindowsDetectedPort] = useState('')
|
||||||
const [windowsEndpointBusy, setWindowsEndpointBusy] = useState(false)
|
const [windowsEndpointBusy, setWindowsEndpointBusy] = useState(false)
|
||||||
|
const [keepOneBotProcess, setKeepOneBotProcess] = useState(false)
|
||||||
|
const [keepProcessBusy, setKeepProcessBusy] = useState(false)
|
||||||
const [showWechatVersions, setShowWechatVersions] = useState(false)
|
const [showWechatVersions, setShowWechatVersions] = useState(false)
|
||||||
const runtimeVersionsTriggerRef = useRef<HTMLButtonElement | null>(null)
|
const runtimeVersionsTriggerRef = useRef<HTMLButtonElement | null>(null)
|
||||||
const personalWechatRuntimeSupported = isMac && Boolean(runtimeStatus?.supported)
|
const personalWechatRuntimeSupported = isMac && Boolean(runtimeStatus?.supported)
|
||||||
@@ -128,6 +131,21 @@ export function PersonalWechatSendPage({
|
|||||||
return () => unsubscribe?.()
|
return () => unsubscribe?.()
|
||||||
}, [refresh])
|
}, [refresh])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isMac) return undefined
|
||||||
|
let active = true
|
||||||
|
const readKeepProcess = window.api.getPersonalWechatKeepOneBotProcess
|
||||||
|
if (typeof readKeepProcess !== 'function') return undefined
|
||||||
|
void readKeepProcess()
|
||||||
|
.then((keep) => {
|
||||||
|
if (active && typeof keep === 'boolean') setKeepOneBotProcess(keep)
|
||||||
|
})
|
||||||
|
.catch(() => undefined)
|
||||||
|
return () => {
|
||||||
|
active = false
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isWindows || !senderStatus || senderStatus.canSend || senderStatus.state === 'error') {
|
if (isWindows || !senderStatus || senderStatus.canSend || senderStatus.state === 'error') {
|
||||||
return undefined
|
return undefined
|
||||||
@@ -219,6 +237,26 @@ export function PersonalWechatSendPage({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleKeepOneBotProcessChange = async (keep: boolean): Promise<void> => {
|
||||||
|
if (!isMac || keepProcessBusy) return
|
||||||
|
const saveKeepProcess = window.api.setPersonalWechatKeepOneBotProcess
|
||||||
|
if (typeof saveKeepProcess !== 'function') {
|
||||||
|
onNotice('请重启 TraceMemo 后再使用“保留 OneBot 进程”')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setKeepProcessBusy(true)
|
||||||
|
setKeepOneBotProcess(keep)
|
||||||
|
try {
|
||||||
|
const saved = await saveKeepProcess(keep)
|
||||||
|
if (typeof saved === 'boolean') setKeepOneBotProcess(saved)
|
||||||
|
} catch (reason) {
|
||||||
|
setKeepOneBotProcess(!keep)
|
||||||
|
onNotice(reason instanceof Error ? reason.message : String(reason))
|
||||||
|
} finally {
|
||||||
|
setKeepProcessBusy(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const bindWechat = async (): Promise<void> => {
|
const bindWechat = async (): Promise<void> => {
|
||||||
if (binding) return
|
if (binding) return
|
||||||
setBinding(true)
|
setBinding(true)
|
||||||
@@ -578,6 +616,20 @@ export function PersonalWechatSendPage({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
<div className="col-span-full flex items-center justify-between gap-4 border-t border-border-subtle pt-4">
|
||||||
|
<div>
|
||||||
|
<strong className="block text-sm">保留 OneBot 进程</strong>
|
||||||
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
|
退出 TraceMemo 后继续保留进程,重新打开时可以复用。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
checked={keepOneBotProcess}
|
||||||
|
disabled={keepProcessBusy}
|
||||||
|
onCheckedChange={(checked) => void handleKeepOneBotProcessChange(checked)}
|
||||||
|
aria-label="保留 OneBot 进程"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<h2 className="settings-section-heading">配置状态</h2>
|
<h2 className="settings-section-heading">配置状态</h2>
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ describe('PersonalWechatSendDialog', () => {
|
|||||||
renderDialog()
|
renderDialog()
|
||||||
await startComposer()
|
await startComposer()
|
||||||
expect(screen.getByRole('dialog')).toHaveTextContent('文字转语音')
|
expect(screen.getByRole('dialog')).toHaveTextContent('文字转语音')
|
||||||
|
expect(screen.queryByRole('switch', { name: '保留 OneBot 进程' })).not.toBeInTheDocument()
|
||||||
expect(screen.queryByText('验证消息能力')).not.toBeInTheDocument()
|
expect(screen.queryByText('验证消息能力')).not.toBeInTheDocument()
|
||||||
expect(screen.getByRole('button', { name: '生成语音' })).toBeDisabled()
|
expect(screen.getByRole('button', { name: '生成语音' })).toBeDisabled()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ const cancelRuntimeDownload = vi.fn()
|
|||||||
const removeRuntime = vi.fn()
|
const removeRuntime = vi.fn()
|
||||||
const openRuntimeDirectory = vi.fn()
|
const openRuntimeDirectory = vi.fn()
|
||||||
const rebindSender = vi.fn()
|
const rebindSender = vi.fn()
|
||||||
|
const getKeepOneBotProcess = vi.fn()
|
||||||
|
const setKeepOneBotProcess = vi.fn()
|
||||||
|
|
||||||
const senderStatus = {
|
const senderStatus = {
|
||||||
state: 'online' as const,
|
state: 'online' as const,
|
||||||
@@ -88,6 +90,8 @@ describe('PersonalWechatSendPage on macOS', () => {
|
|||||||
})
|
})
|
||||||
openRuntimeDirectory.mockReset().mockResolvedValue({ success: true })
|
openRuntimeDirectory.mockReset().mockResolvedValue({ success: true })
|
||||||
rebindSender.mockReset().mockResolvedValue(senderStatus)
|
rebindSender.mockReset().mockResolvedValue(senderStatus)
|
||||||
|
getKeepOneBotProcess.mockReset().mockResolvedValue(false)
|
||||||
|
setKeepOneBotProcess.mockReset().mockImplementation(async (keep: boolean) => keep)
|
||||||
vi.spyOn(window, 'confirm').mockReturnValue(true)
|
vi.spyOn(window, 'confirm').mockReturnValue(true)
|
||||||
Object.defineProperty(window, 'api', {
|
Object.defineProperty(window, 'api', {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
@@ -100,7 +104,9 @@ describe('PersonalWechatSendPage on macOS', () => {
|
|||||||
cancelPersonalWechatRuntimeDownload: cancelRuntimeDownload,
|
cancelPersonalWechatRuntimeDownload: cancelRuntimeDownload,
|
||||||
removePersonalWechatRuntime: removeRuntime,
|
removePersonalWechatRuntime: removeRuntime,
|
||||||
openPersonalWechatRuntimeDirectory: openRuntimeDirectory,
|
openPersonalWechatRuntimeDirectory: openRuntimeDirectory,
|
||||||
rebindPersonalWechatSender: rebindSender
|
rebindPersonalWechatSender: rebindSender,
|
||||||
|
getPersonalWechatKeepOneBotProcess: getKeepOneBotProcess,
|
||||||
|
setPersonalWechatKeepOneBotProcess: setKeepOneBotProcess
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -123,6 +129,18 @@ describe('PersonalWechatSendPage on macOS', () => {
|
|||||||
expect(versionsDialog).toHaveTextContent('4.1.11.53')
|
expect(versionsDialog).toHaveTextContent('4.1.11.53')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('keeps the OneBot process setting on the macOS WeChat send page', async () => {
|
||||||
|
const user = userEvent.setup()
|
||||||
|
render(<PersonalWechatSendPage onNotice={vi.fn()} />)
|
||||||
|
|
||||||
|
const keepProcess = await screen.findByRole('switch', { name: '保留 OneBot 进程' })
|
||||||
|
expect(keepProcess).not.toBeChecked()
|
||||||
|
await user.click(keepProcess)
|
||||||
|
|
||||||
|
await waitFor(() => expect(setKeepOneBotProcess).toHaveBeenCalledWith(true))
|
||||||
|
expect(keepProcess).toBeChecked()
|
||||||
|
})
|
||||||
|
|
||||||
it('downloads a missing macOS runtime from the send page', async () => {
|
it('downloads a missing macOS runtime from the send page', async () => {
|
||||||
getRuntimeStatus.mockResolvedValue({
|
getRuntimeStatus.mockResolvedValue({
|
||||||
...readyRuntime,
|
...readyRuntime,
|
||||||
|
|||||||
@@ -191,4 +191,11 @@ describe('PersonalWechatSendPage on Windows', () => {
|
|||||||
expect(screen.queryByText(/OneBot/i)).not.toBeInTheDocument()
|
expect(screen.queryByText(/OneBot/i)).not.toBeInTheDocument()
|
||||||
expect(screen.queryByText('微信发送组件')).not.toBeInTheDocument()
|
expect(screen.queryByText('微信发送组件')).not.toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('does not show the macOS process setting on the Windows WeChat send page', async () => {
|
||||||
|
render(<PersonalWechatSendPage onNotice={vi.fn()} />)
|
||||||
|
|
||||||
|
expect(await screen.findByRole('spinbutton', { name: '微信发送能力端口' })).toBeVisible()
|
||||||
|
expect(screen.queryByRole('switch', { name: '保留 OneBot 进程' })).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user