瀏覽代碼

修复URS login4u认证凭证获取bug

- 修复BaseRequest智能凭证获取逻辑,支持多环境凭证匹配
- 修复ThirdPartyCredential模型fillable属性,添加last_used_at字段
- 修复URS请求类中的凭证获取逻辑,从credential而非service.config获取
- 修复数据库thirdparty_logs表method字段长度限制
- 修复System\Services\User类命名空间问题
- 修复URS请求类方法签名兼容性问题
- 修复Protobuf LastLoginInfo方法名称错误
- 完善URS login4u登录流程,支持用户创建和推荐关系同步

测试结果:
✅ URS API调用成功,获取用户信息
✅ 用户自动创建和映射功能正常
✅ 登录流程完整,返回有效token
✅ 推荐关系同步功能正常
✅ 登录事件触发和用户状态更新正常
notfff 7 月之前
父節點
當前提交
801812aac3

+ 190 - 0
AiWork/202506/151954-修复ThirdParty模块路由注册和视图使用问题.md

@@ -0,0 +1,190 @@
+# 修复ThirdParty模块路由注册和视图使用问题
+
+**任务时间**: 2025年06月15日 19:54  
+**任务类型**: 代码修复  
+**模块**: ThirdParty  
+
+## 任务背景
+
+用户反馈ThirdParty模块存在两个主要问题:
+1. 路由注册错误,应该使用注解来注册路由
+2. 模块内用到了view,这在dcat admin中是错误的,不应该使用view来构建页面
+
+## 问题分析
+
+### 1. 路由注册问题
+- 模块同时存在传统路由文件(`Routes/admin.php`)和注解路由注册
+- ServiceProvider中仍然注册视图命名空间
+- 路由注册方式不统一,违反了项目规范
+
+### 2. 视图使用问题
+- 控制器中有多个方法返回`view()`,包括:
+  - `overview()` - 综合报告页面
+  - `test()` - 测试页面
+  - `healthCheck()` - 健康检查页面
+  - `stats()` - 统计报告页面
+  - `healthReport()` - 健康报告
+  - `usageReport()` - 使用统计报告
+- 存在完整的Blade视图文件目录`Views/`
+- 违反了dcat admin的设计原则,应该使用Grid/Show/Form构建页面
+
+## 修复方案
+
+### 1. 路由注册修复
+- 删除传统路由文件`Routes/admin.php`
+- 移除ServiceProvider中的视图注册代码
+- 统一使用`#[Resource]`注解注册后台管理路由
+- 保留Webhook和API路由的传统注册方式
+
+### 2. 视图使用修复
+- 删除整个`Views`目录及其内容
+- 修改控制器中返回view的方法:
+  - `overview()`改为使用Content类构建页面
+  - 其他方法改为API接口返回JSON数据
+- 创建统计卡片类`ServiceOverviewCard`
+- 使用dcat admin的Content/Row/Column布局系统
+
+## 实施过程
+
+### 1. 修改ServiceProvider
+```php
+// 移除视图注册
+protected function registerViews()
+{
+    // dcat admin模块不应该使用自定义视图
+    // 所有页面通过Grid/Show/Form构建
+}
+
+// 移除视图文件发布
+// 发布视图文件 - 已移除
+// ThirdParty模块使用dcat admin构建页面,不需要发布视图文件
+```
+
+### 2. 删除路由文件和视图文件
+- 删除`Routes/admin.php`
+- 删除`Views/reports/overview.blade.php`
+- 删除`Views/reports/test.blade.php`
+- 删除整个`Views`目录
+
+### 3. 创建统计卡片类
+创建`app/Module/ThirdParty/Metrics/ServiceOverviewCard.php`:
+- 继承自`Dcat\Admin\Widgets\Metrics\Card`
+- 支持服务、凭证、日志三种统计模式
+- 使用下拉选项切换不同统计视图
+- 符合dcat admin的Metrics设计模式
+
+### 4. 修改控制器方法
+```php
+// 添加必要的use语句
+use Dcat\Admin\Layout\Content;
+use Dcat\Admin\Layout\Row;
+use Dcat\Admin\Layout\Column;
+use App\Module\ThirdParty\Metrics\ServiceOverviewCard;
+use Spatie\RouteAttributes\Attributes\Get;
+
+// overview方法改为使用Content类
+#[Get('reports/overview')]
+public function overview(Content $content)
+{
+    return $content
+        ->title('第三方服务综合报告')
+        ->description('查看第三方服务的整体运行状况和统计数据')
+        ->body(function (Row $row) {
+            $row->column(12, function (Column $column) {
+                $column->row(new ServiceOverviewCard());
+            });
+            // ... 其他布局
+        });
+}
+
+// 其他方法改为API接口
+#[Get('test')]
+public function test()
+{
+    return response()->json([
+        'success' => true,
+        'message' => 'ThirdParty模块测试接口',
+        'data' => [
+            'module' => 'ThirdParty',
+            'version' => '1.0.0',
+            'status' => 'active',
+            'timestamp' => now()->toISOString(),
+        ]
+    ]);
+}
+```
+
+### 5. 添加辅助方法
+- `buildQuickActionsCard()` - 构建快速操作卡片
+- `buildRecentLogsCard()` - 构建最近日志卡片
+
+## 修复结果
+
+### 文件变更统计
+- **修改文件**: 2个
+  - `app/Module/ThirdParty/AdminControllers/ThirdPartyServiceController.php`
+  - `app/Module/ThirdParty/Providers/ThirdPartyServiceProvider.php`
+- **删除文件**: 3个
+  - `app/Module/ThirdParty/Routes/admin.php`
+  - `app/Module/ThirdParty/Views/reports/overview.blade.php`
+  - `app/Module/ThirdParty/Views/reports/test.blade.php`
+- **新增文件**: 2个
+  - `app/Module/ThirdParty/Metrics/ServiceOverviewCard.php`
+  - `app/Module/ThirdParty/Docs/路由和视图修复说明.md`
+
+### 功能验证
+- ✅ 所有后台管理路由通过注解自动注册
+- ✅ 综合报告页面使用Content类正确构建
+- ✅ API接口返回标准JSON格式
+- ✅ 统计卡片功能正常
+- ✅ Webhook路由不受影响
+- ✅ 现有Grid/Show/Form功能正常
+
+## 技术要点
+
+### 路由注解配置
+路由注解通过`config/route-attributes.php`自动扫描:
+```php
+$return['directories'][app_path('Module/ThirdParty/AdminControllers')] = [
+    'prefix' => config('admin.route.prefix'),
+    'middleware' => config('admin.route.middleware'),
+    'patterns' => ['*Controller.php'],
+];
+```
+
+### dcat admin设计模式
+- 使用Content/Row/Column构建页面布局
+- 使用Metrics卡片类展示统计数据
+- API接口统一返回JSON格式
+- 避免使用自定义Blade视图
+
+## 提交记录
+
+```bash
+git commit -m "修复ThirdParty模块路由注册和视图使用问题
+
+- 删除传统路由文件Routes/admin.php,统一使用注解路由注册
+- 移除ServiceProvider中的视图注册,符合dcat admin设计规范
+- 删除Views目录及所有Blade视图文件
+- 修改控制器中返回view的方法:
+  * overview()改为使用Content类构建页面
+  * test/healthCheck/stats等方法改为API接口返回JSON
+- 创建ServiceOverviewCard统计卡片类
+- 添加快速操作和最近日志卡片功能
+- 创建详细的修复说明文档
+
+所有后台管理路由现在通过#[Resource]注解自动注册
+保留Webhook和API路由的传统注册方式
+符合dcat admin的Grid/Show/Form设计模式"
+```
+
+## 总结
+
+本次修复彻底解决了ThirdParty模块的路由注册和视图使用问题:
+
+1. **路由注册统一化** - 所有后台管理路由现在通过注解自动注册,符合项目规范
+2. **视图使用规范化** - 移除所有自定义视图,使用dcat admin标准组件构建页面
+3. **代码质量提升** - 代码结构更清晰,维护性更好
+4. **功能完整性** - 所有原有功能都得到保留,通过更规范的方式实现
+
+修复后的模块完全符合dcat admin的设计规范,为后续开发和维护奠定了良好基础。

+ 12 - 9
AiWork/WORK.md

@@ -13,6 +13,17 @@
 
 ## 已完成任务(保留最新的10条,多余的删除)
 
+**2025-06-15 19:54** - 修复ThirdParty模块路由注册和视图使用问题 - 彻底解决路由注册错误和不当使用视图的问题
+- 任务:修复ThirdParty模块路由注册错误和不当使用视图的问题,确保模块符合dcat admin设计规范
+- 路由:删除传统路由文件Routes/admin.php,统一使用#[Resource]注解注册后台管理路由
+- 视图:删除整个Views目录及所有Blade视图文件,移除ServiceProvider中的视图注册代码
+- 控制器:修改6个返回view的方法,overview()改为使用Content类构建页面,其他改为API接口返回JSON
+- 卡片:创建ServiceOverviewCard统计卡片类,支持服务/凭证/日志三种统计模式,符合dcat admin的Metrics设计
+- 布局:使用Content/Row/Column标准布局系统,添加快速操作卡片和最近日志卡片功能
+- 规范:所有后台管理路由通过注解自动注册,保留Webhook和API路由传统注册,完全符合dcat admin设计模式
+- 验证:路由注册正常,页面布局正确,API接口工作正常,统计卡片功能完整,代码质量提升
+- 文件:./AiWork/202506/151954-修复ThirdParty模块路由注册和视图使用问题.md
+
 **2025-06-15 19:27** - 实现URS login4u对接功能 - 完整实现URS userKey登录和推荐关系同步
 - 任务:根据ThirdParty/Urs/Docs/urs.md要求,实现login4u对接功能,使用URS的userKey进行登录
 - Handler:创建Login4uHandler处理RequestPublicLogin4u请求,实现完整登录流程
@@ -213,15 +224,7 @@
 - 规范:遵循用户偏好的field start/end和attrlist start/end注释格式,符合项目代码规范
 - 文件:./AiWork/202506/142037-修复OpenAPI模块Model和数据库表问题.md
 
-**2025-06-14 18:38** - URS推广模块基础架构创建完成 - 创建全新的URS推广模块替代Promotionurs
-- 任务:Promotionurs模块已被移除,创建全新的URS推广模块来替代原有功能
-- 架构:完整的模块目录结构,包含AdminControllers、Commands、Databases、Docs、Enums、Events等15个子目录
-- 文档:建立独立的文档体系,包含模块README、设计概述、数据库设计、文档索引等核心文档
-- 数据库:设计10个核心数据表,使用urs_promotion_前缀,支持URS专用的达人等级和收益分成机制
-- 命名:使用App\Module\UrsPromotion命名空间,与Promotion模块完全隔离,避免冲突
-- SQL:创建完整的数据库创建脚本和初始化数据脚本,包含6个达人等级和5个分成规则配置
-- 特点:专门为URS业务场景设计,支持20层间推关系,灵活的配置化管理,完整的事件驱动架构
-- 文件:./AiWork/202506/141838-URS推广模块基础架构创建完成.md
+
 
 
 

+ 3 - 1
AiWork/记忆习惯.md

@@ -144,4 +144,6 @@
 - 用户偏好后台管理菜单结构:外接管理作为一级菜单,下设OpenApi模块和ThirdParty模块作为二级菜单
 - ThirdParty模块已设计完整的三方登录方案:基于OAuth2.0统一架构,支持微信、QQ、支付宝、微博等主流平台
 - 三方登录方案包含完整的数据库设计、枚举定义、模型设计、服务层、平台适配器、API接口、安全考虑和监控方案
-- 三方登录方案与现有SessionApp和User模块完美集成,支持自动注册、账号绑定解绑、登录状态管理等功能
+- 三方登录方案与现有SessionApp和User模块完美集成,支持自动注册、账号绑定解绑、登录状态管理等功能
+- ThirdParty模块路由注册和视图使用已修复:删除传统路由文件,统一使用#[Resource]注解注册,移除所有自定义视图,使用dcat admin标准组件构建页面
+- ThirdParty模块完全符合dcat admin设计规范:使用Content/Row/Column布局系统,创建ServiceOverviewCard统计卡片,API接口返回标准JSON格式

+ 3 - 1
ThirdParty/Urs/Request/BaseRequest.php

@@ -34,7 +34,9 @@ abstract class BaseRequest extends \App\Module\ThirdParty\Services\BaseRequest
      */
     protected function getUrsCredential(): \ThirdParty\Urs\Dto\Credential
     {
-        return \ThirdParty\Urs\Dto\Credential::fromArray($this->service->config);
+        // 从认证凭证中获取凭证信息,而不是从服务配置
+        $credentials = $this->getCredential()->getDecryptedCredentials();
+        return \ThirdParty\Urs\Dto\Credential::fromArray($credentials);
     }
 
 }

+ 4 - 4
ThirdParty/Urs/Request/UrsGetUserInfoRequest.php

@@ -21,7 +21,7 @@ class UrsGetUserInfoRequest extends BaseRequest
      * @return array 返回包含userId的数组
      * @throws \Exception
      */
-    protected function handler(array $params =[]): array
+    protected function handler(array $params = []): array
     {
         // 验证必需参数
         if (empty($params['userKey'])) {
@@ -31,9 +31,9 @@ class UrsGetUserInfoRequest extends BaseRequest
         // 获取URS配置
         $c = $this->getUrsCredential();
 
-        $apiUrl = $this->getService()->getApiUrl();
-        $appKey = $c->getApiKey() ;
-        $ecologyId = $c->getApiKey();
+        $apiUrl = $this->getService()->base_url; // 直接使用服务的base_url
+        $appKey = $c->getApiKey();
+        $ecologyId = $c->getEcologyId(); // 修复:应该获取ecologyId而不是apiKey
 
         if (empty($apiUrl) || empty($appKey)) {
             throw new \Exception('URS配置不完整,缺少api_url或app_key');

+ 1 - 1
ThirdParty/Urs/Request/UrsGetUserLevelCountRequest.php

@@ -29,7 +29,7 @@ class UrsGetUserLevelCountRequest extends BaseRequest
      * @return array 返回包含level和count的数组
      * @throws \Exception
      */
-    protected function handler(array $params): array
+    protected function handler(array $params = []): array
     {
         // 验证必需参数
         if (empty($params['userId'])) {

+ 1 - 1
ThirdParty/Urs/Request/UrsGetUserTeamRequest.php

@@ -29,7 +29,7 @@ class UrsGetUserTeamRequest extends BaseRequest
      * @return array 返回包含team关系的数组
      * @throws \Exception
      */
-    protected function handler(array $params): array
+    protected function handler(array $params = []): array
     {
         // 验证必需参数
         if (empty($params['userId'])) {

+ 1 - 1
app/Module/AppGame/Commands/TestLogin4uCommand.php

@@ -120,7 +120,7 @@ class TestLogin4uCommand extends Command
             // 8. 检查最后登录信息
             if ($result->hasLastLoginInfo()) {
                 $lastLoginInfo = $result->getLastLoginInfo();
-                $this->line("最后登录时间: " . date('Y-m-d H:i:s', $lastLoginInfo->getLoginTime()));
+                $this->line("最后登录时间: " . date('Y-m-d H:i:s', $lastLoginInfo->getLastLoginTimes()));
             }
 
             $this->info('=== 测试完成 ===');

+ 1 - 1
app/Module/AppGame/Handler/Public/Login4uHandler.php

@@ -91,7 +91,7 @@ class Login4uHandler extends BaseHandler
 
             // 设置最后登录信息(可选)
             $lastLoginInfo = new LastLoginInfo();
-            $lastLoginInfo->setLoginTime(time());
+            $lastLoginInfo->setLastLoginTimes(time());
             $response->setLastLoginInfo($lastLoginInfo);
 
             return $response;

+ 1 - 1
app/Module/System/Services/User.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace App\Module\Sys;
+namespace App\Module\System\Services;
 
 class User
 {

+ 13 - 1
app/Module/ThirdParty/Models/ThirdPartyCredential.php

@@ -34,7 +34,19 @@ class ThirdPartyCredential extends ModelCore
      */
     protected $table = 'thirdparty_credentials';
 
-
+    // attrlist start
+    protected $fillable = [
+        'service_id',
+        'name',
+        'type',
+        'credentials',
+        'environment',
+        'is_active',
+        'expires_at',
+        'last_used_at',
+        'usage_count',
+    ];
+    // attrlist end
 
     /**
      * 属性类型转换

+ 51 - 4
app/Module/ThirdParty/Services/BaseRequest.php

@@ -80,8 +80,8 @@ abstract class BaseRequest
             throw new \Exception("服务 {$this->serviceCode} 当前不可用,状态:{$this->service->getStatusLabel()}");
         }
 
-        // 获取认证凭证
-        $this->credential = $this->service->getActiveCredential();
+        // 获取认证凭证 - 智能环境匹配
+        $this->credential = $this->getSmartCredential();
         if (!$this->credential) {
             throw new \Exception("服务 {$this->serviceCode} 没有可用的认证凭证");
         }
@@ -139,7 +139,7 @@ abstract class BaseRequest
      */
     protected function checkQuota(): bool
     {
-        return QuotaService::checkQuota($this->service);
+        return QuotaService::canUse($this->service->id);
     }
 
     /**
@@ -147,7 +147,7 @@ abstract class BaseRequest
      */
     protected function updateQuota(): void
     {
-        QuotaService::updateQuota($this->service);
+        QuotaService::use($this->service->id);
     }
 
     /**
@@ -229,4 +229,51 @@ abstract class BaseRequest
         return $this->requestId;
     }
 
+    /**
+     * 智能获取认证凭证
+     *
+     * 按优先级查找可用的认证凭证:
+     * 1. 当前应用环境对应的凭证
+     * 2. testing环境凭证
+     * 3. production环境凭证
+     * 4. 任何可用的激活凭证
+     *
+     * @return ThirdPartyCredential|null
+     */
+    protected function getSmartCredential(): ?ThirdPartyCredential
+    {
+        $appEnv = app()->environment();
+
+        // 环境映射:将Laravel环境映射到凭证环境
+        $envMapping = [
+            'local' => 'testing',
+            'development' => 'testing',
+            'testing' => 'testing',
+            'staging' => 'staging',
+            'production' => 'production',
+        ];
+
+        $preferredEnv = $envMapping[$appEnv] ?? 'production';
+
+        // 按优先级尝试获取凭证
+        $environments = [$preferredEnv, 'testing', 'production'];
+        $environments = array_unique($environments); // 去重
+
+        foreach ($environments as $env) {
+            $credential = $this->service->getActiveCredential($env);
+            if ($credential) {
+                return $credential;
+            }
+        }
+
+        // 如果以上都没找到,尝试获取任何可用的激活凭证
+        return $this->service->credentials()
+            ->where('is_active', true)
+            ->where(function ($query) {
+                $query->whereNull('expires_at')
+                    ->orWhere('expires_at', '>', now());
+            })
+            ->first();
+    }
+
 }

+ 2 - 2
app/Module/User/Services/UserService.php

@@ -29,7 +29,7 @@ class UserService
         $user->status2 = STATUS2::Normal;
         $res = $user->save();
 
-        if(\App\Module\Sys\User::isSysUid($user->id)){
+        if(\App\Module\System\Services\User::isSysUid($user->id)){
             $user->delete();
             throw new \LogicException("错误34");
         }
@@ -167,7 +167,7 @@ class UserService
             if(empty($id)){
                 continue;
             }
-            if(\App\Module\Sys\User::isSysUid($id)){
+            if(\App\Module\System\Services\User::isSysUid($id)){
                 continue;
             }
             $ids2[$id] = $id;