Просмотр исходного кода

fix: 修复账号管理相关Bug (#6070,#6075,#6076,#6084)

ethanfly 3 дней назад
Родитель
Сommit
8b06eebc19

+ 6 - 0
client/src/stores/taskQueue.ts

@@ -284,6 +284,12 @@ export const useTaskQueueStore = defineStore('taskQueue', () => {
       accountRefreshTrigger.value++;
     }
     
+    // Bug #6070: 账号数据变更事件(新增/修改头像昵称等),触发前端模块刷新
+    if (data.type === 'account:data_changed') {
+      console.log('[TaskQueue] Account data changed event received:', data.type);
+      accountRefreshTrigger.value++;
+    }
+    
     // 处理验证码事件
     // 1. 通过 type 判断
     // 2. 或者 payload 中包含 captchaTaskId 字段(兼容 type 为 undefined 的情况)

+ 34 - 1
client/src/views/Accounts/index.vue

@@ -114,7 +114,7 @@
           </template>
         </el-table-column>
         
-        <el-table-column label="操作" width="180" fixed="right">
+        <el-table-column label="操作" width="240" fixed="right">
           <template #default="{ row }">
             <el-button type="primary" link size="small" @click="openPlatformAdmin(row)">
               后台
@@ -122,6 +122,24 @@
             <el-button type="primary" link size="small" @click="refreshAccount(row.id)">
               刷新
             </el-button>
+            <el-button
+              v-if="row.status !== 'disabled'"
+              type="danger"
+              link
+              size="small"
+              @click="toggleAccountStatus(row.id, 'disabled')"
+            >
+              禁用
+            </el-button>
+            <el-button
+              v-else
+              type="success"
+              link
+              size="small"
+              @click="toggleAccountStatus(row.id, 'active')"
+            >
+              启用
+            </el-button>
             <el-button type="danger" link size="small" @click="deleteAccount(row.id)">
               删除
             </el-button>
@@ -698,6 +716,21 @@ async function deleteAccount(id: number) {
   }
 }
 
+// 切换账号启用/禁用状态
+async function toggleAccountStatus(id: number, newStatus: 'active' | 'disabled') {
+  const actionText = newStatus === 'disabled' ? '禁用' : '启用';
+  try {
+    await ElMessageBox.confirm(`确定要${actionText}该账号吗?`, '提示', {
+      type: 'warning',
+    });
+    await accountsApi.updateAccount(id, { status: newStatus });
+    ElMessage.success(`账号已${actionText}`);
+    loadAccounts();
+  } catch {
+    // 取消或错误
+  }
+}
+
 // 分组管理方法
 function getGroupAccountCount(groupId: number): number {
   // 使用全量账号列表计算(accounts.value 可能已被筛选条件过滤)

+ 37 - 0
server/src/services/AccountService.ts

@@ -261,6 +261,9 @@ export class AccountService {
       const updated = await this.accountRepository.findOne({ where: { id: existing.id } });
       wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_UPDATED, { account: this.formatAccount(updated!) });
 
+      // Bug #6070: 通知前端账号数据已变更,触发其他模块(如首页数据看板)刷新
+      wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_DATA_CHANGED, { accountId: existing.id });
+
       // 异步刷新账号信息(获取准确的粉丝数、作品数等)
       this.refreshAccountAsync(userId, existing.id, platform).catch(err => {
         logger.warn(`[addAccount] Background refresh failed for existing account ${existing.id}:`, err);
@@ -299,6 +302,9 @@ export class AccountService {
     // 通知其他客户端
     wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_ADDED, { account: this.formatAccount(account) });
 
+    // Bug #6070: 通知前端账号数据已变更,触发其他模块(如首页数据看板)刷新
+    wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_DATA_CHANGED, { accountId: account.id });
+
     // 异步刷新账号信息(获取准确的粉丝数、作品数等)
     // 不阻塞返回,后台执行
     this.refreshAccountAsync(userId, account.id, platform).catch(err => {
@@ -471,6 +477,17 @@ export class AccountService {
     let needReLogin = false;
     let aiRefreshSuccess = false;
 
+    // Bug #6084: cookie 为空的账号直接标记为 expired
+    if (!account.cookieData) {
+      updateData.status = 'expired';
+      needReLogin = true;
+      logger.warn(`[refreshAccount] Account ${accountId} has empty cookieData, marking as expired`);
+      await this.accountRepository.update(accountId, updateData);
+      const updated = await this.accountRepository.findOne({ where: { id: accountId } });
+      wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_UPDATED, { account: this.formatAccount(updated!) });
+      return { ...this.formatAccount(updated!), needReLogin };
+    }
+
     // 尝试通过无头浏览器刷新账号信息
     if (account.cookieData) {
       try {
@@ -603,6 +620,12 @@ export class AccountService {
                 } else {
                   // 获取的信息无效,但 Cookie 有效,保持 active 状态
                   logger.warn(`Could not fetch valid account info for ${accountId}, but cookie is valid`);
+
+                  // Bug #6075: 即使 profile 名称无效,仍然强制更新 avatarUrl(用户可能只改了头像没改昵称)
+                  if (profile.avatarUrl) {
+                    updateData.avatarUrl = profile.avatarUrl;
+                    logger.info(`[refreshAccount] Force updating avatarUrl for ${accountId} (profile name invalid but avatar changed)`);
+                  }
                 }
 
                 // 无论 profile 是否有效,都尝试更新粉丝数和作品数(来自 Python API 的数据是可靠的)
@@ -679,6 +702,20 @@ export class AccountService {
     // 通知其他客户端
     wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_UPDATED, { account: this.formatAccount(updated!) });
 
+    // Bug #6075: 检测 avatarUrl 或 accountName 是否发生变化,通知前端刷新数据
+    if (updated) {
+      const avatarChanged = updateData.avatarUrl !== undefined && updateData.avatarUrl !== account.avatarUrl;
+      const nameChanged = updateData.accountName !== undefined && updateData.accountName !== account.accountName;
+      if (avatarChanged || nameChanged) {
+        logger.info(`[refreshAccount] Account ${accountId} data changed: avatarChanged=${avatarChanged}, nameChanged=${nameChanged}`);
+        wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_DATA_CHANGED, {
+          accountId,
+          accountName: updated.accountName,
+          avatarUrl: updated.avatarUrl,
+        });
+      }
+    }
+
     return { ...this.formatAccount(updated!), needReLogin };
   }
 

+ 1 - 0
shared/src/constants/api.ts

@@ -102,6 +102,7 @@ export const WS_EVENTS = {
   ACCOUNT_ADDED: 'account:added',
   ACCOUNT_UPDATED: 'account:updated',
   ACCOUNT_DELETED: 'account:deleted',
+  ACCOUNT_DATA_CHANGED: 'account:data_changed',
   // 任务
   TASK_CREATED: 'task:created',
   TASK_STATUS_CHANGED: 'task:status_changed',