diff --git a/frontend/composables/useApi.js b/frontend/composables/useApi.js
index 3858c35..a78b3c9 100644
--- a/frontend/composables/useApi.js
+++ b/frontend/composables/useApi.js
@@ -358,7 +358,13 @@ export const useApi = () => {
method: 'GET',
})
}
-
+
+ const getWxStatus = () => {
+ return useFetch('/api/wechat/status', {
+ method: 'GET',
+ })
+ }
+
return {
detectWechat,
detectCurrentAccount,
@@ -392,5 +398,6 @@ export const useApi = () => {
getWrappedAnnualCard,
getDbKey,
getImageKey,
+ getWxStatus,
}
}
diff --git a/frontend/pages/decrypt.vue b/frontend/pages/decrypt.vue
index 2942d26..bef19e1 100644
--- a/frontend/pages/decrypt.vue
+++ b/frontend/pages/decrypt.vue
@@ -361,6 +361,19 @@
+
+
+
+
+
@@ -403,10 +416,11 @@
import { ref, reactive, computed, onMounted } from 'vue'
import { useApi } from '~/composables/useApi'
-const { decryptDatabase, saveMediaKeys, getSavedKeys, getDbKey, getImageKey } = useApi()
+const { decryptDatabase, saveMediaKeys, getSavedKeys, getDbKey, getImageKey, getWxStatus } = useApi()
const loading = ref(false)
const error = ref('')
+const warning = ref('') // 警告,用于密钥提示
const currentStep = ref(0)
const mediaAccount = ref('')
const isGettingDbKey = ref(false)
@@ -496,10 +510,29 @@ const handleGetDbKey = async () => {
isGettingDbKey.value = true
error.value = ''
-
+ warning.value = ''
formErrors.key = ''
try {
+ const { data: statusData, error: statusError } = await getWxStatus()
+
+ if (statusError.value) {
+ error.value = '无法获取微信状态: ' + statusError.value.message
+ isGettingDbKey.value = false
+ return
+ }
+
+ const wxStatus = statusData.value?.wx_status
+
+ if (wxStatus?.is_running) {
+ warning.value = '检测到微信正在运行,5秒后将终止进程并重启以获取密钥!!'
+ await new Promise(resolve => setTimeout(resolve, 5000))
+ } else {
+ // 没有逻辑
+ }
+
+ warning.value = '正在启动微信以获取密钥,请确保微信未开启“自动登录”,并在启动后 1 分钟内完成登录操作。'
+
const { data, error: fetchError } = await getDbKey()
if (fetchError.value) {
@@ -509,14 +542,14 @@ const handleGetDbKey = async () => {
const res = data.value
- if (res && (res.status === 0)) {
+ if (res && res.status === 0) {
if (res.data?.db_key) {
formData.key = res.data.db_key
+ warning.value = ''
}
- // 有错误信息且不是ok时弹出提示
if (res.errmsg && res.errmsg !== 'ok') {
- error.value = res.errmsg
+ warning.value = res.errmsg
}
} else {
error.value = '获取失败: ' + (res?.errmsg || '未知错误')
@@ -536,6 +569,7 @@ const handleGetImageKey = async () => {
manualKeyErrors.aes_key = ''
error.value = ''
+ warning.value = ''
try {
const { data, fetchError } = await getImageKey()
@@ -573,6 +607,7 @@ const applyManualKeys = () => {
manualKeyErrors.xor_key = ''
manualKeyErrors.aes_key = ''
error.value = ''
+ warning.value = ''
const aes = normalizeAesKey(manualKeys.aes_key)
if (!aes.ok) {
@@ -666,6 +701,7 @@ const handleDecrypt = async () => {
loading.value = true
error.value = ''
+ warning.value = ''
try {
const result = await decryptDatabase({
@@ -712,6 +748,7 @@ const decryptAllImages = async () => {
mediaDecrypting.value = true
mediaDecryptResult.value = null
error.value = ''
+ warning.value = ''
// 重置进度
decryptProgress.current = 0
@@ -787,6 +824,7 @@ const decryptAllImages = async () => {
// 从密钥步骤进入图片解密步骤
const goToMediaDecryptStep = async () => {
error.value = ''
+ warning.value = ''
// 校验并应用(未填写则允许直接进入,后端会使用已保存密钥或报错提示)
const ok = applyManualKeys()
if (!ok || manualKeyErrors.xor_key || manualKeyErrors.aes_key) return
diff --git a/pyproject.toml b/pyproject.toml
index a3651f7..3773d41 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,6 +20,7 @@ dependencies = [
"pilk>=0.2.4",
"pypinyin>=0.53.0",
"wx_key",
+ "packaging",
]
[project.optional-dependencies]
diff --git a/src/wechat_decrypt_tool/routers/keys.py b/src/wechat_decrypt_tool/routers/keys.py
index f4cf35d..5abd00a 100644
--- a/src/wechat_decrypt_tool/routers/keys.py
+++ b/src/wechat_decrypt_tool/routers/keys.py
@@ -3,6 +3,7 @@ from typing import Optional
from fastapi import APIRouter
from ..key_store import get_account_keys_from_store
+from ..key_service import get_db_key_workflow
from ..media_helpers import _load_media_keys, _resolve_account_dir
from ..path_fix import PathFixRoute
diff --git a/src/wechat_decrypt_tool/routers/wechat_detection.py b/src/wechat_decrypt_tool/routers/wechat_detection.py
index ae0077d..b2fe1c5 100644
--- a/src/wechat_decrypt_tool/routers/wechat_detection.py
+++ b/src/wechat_decrypt_tool/routers/wechat_detection.py
@@ -1,5 +1,5 @@
from typing import Optional
-
+import psutil
from fastapi import APIRouter
from ..logging_config import get_logger
@@ -71,3 +71,49 @@ async def detect_current_account(data_root_path: Optional[str] = None):
'error': str(e),
'data': None,
}
+
+
+@router.get("/api/wechat/status", summary="检查微信运行状态")
+async def check_wechat_status():
+ """
+ 检查系统中是否有 Weixin.exe 或 WeChat.exe 进程在运行
+ 返回: status=0 成功, wx_status={is_running: bool, pid: int, ...}
+ """
+ process_name_targets = ["Weixin.exe", "WeChat.exe"]
+
+ wx_status = {
+ "is_running": False,
+ "pid": None,
+ "exe_path": None,
+ "memory_usage_mb": 0.0
+ }
+
+ try:
+ for proc in psutil.process_iter(['pid', 'name', 'exe', 'memory_info']):
+ try:
+ if proc.info['name'] and proc.info['name'] in process_name_targets:
+ wx_status["is_running"] = True
+ wx_status["pid"] = proc.info['pid']
+ wx_status["exe_path"] = proc.info['exe']
+
+ mem = proc.info['memory_info']
+ if mem:
+ wx_status["memory_usage_mb"] = round(mem.rss / (1024 * 1024), 2)
+
+ break
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
+ continue
+
+ return {
+ "status": 0,
+ "errmsg": "ok",
+ "wx_status": wx_status
+ }
+
+ except Exception as e:
+ # 即使出错也返回 JSON,但 status 非 0
+ return {
+ "status": -1,
+ "errmsg": f"检查进程失败: {str(e)}",
+ "wx_status": wx_status
+ }
diff --git a/uv.lock b/uv.lock
index b8d73d9..fc6360c 100644
--- a/uv.lock
+++ b/uv.lock
@@ -845,6 +845,7 @@ dependencies = [
{ name = "cryptography" },
{ name = "fastapi" },
{ name = "loguru" },
+ { name = "packaging" },
{ name = "pilk" },
{ name = "psutil" },
{ name = "pycryptodome" },
@@ -869,6 +870,7 @@ requires-dist = [
{ name = "cryptography", specifier = ">=41.0.0" },
{ name = "fastapi", specifier = ">=0.104.0" },
{ name = "loguru", specifier = ">=0.7.0" },
+ { name = "packaging" },
{ name = "pilk", specifier = ">=0.2.4" },
{ name = "psutil", specifier = ">=7.0.0" },
{ name = "pycryptodome", specifier = ">=3.23.0" },
@@ -901,6 +903,7 @@ wheels = [
{ path = "wx_key-1.0.0-cp311-cp311-win_amd64.whl" },
{ path = "wx_key-1.0.0-cp312-cp312-win_amd64.whl" },
{ path = "wx_key-1.0.0-cp313-cp313-win_amd64.whl" },
+ { path = "wx_key-1.0.0-cp314-cp314-win_amd64.whl" },
]
[[package]]