Jelajahi Sumber

新增角色库管理相关接口

lh 4 hari lalu
induk
melakukan
f75ec64fdd

+ 14 - 0
app/Http/Controllers/Anime/AnimeController.php

@@ -1994,6 +1994,20 @@ class AnimeController extends BaseController
         $result = $this->AnimeService->editRole($data);
         return $this->success(['success' => $result ? 1 : 0]);
     }
+    
+    // 获取角色版本历史
+    public function getRoleVersions(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->getRoleVersions($data);
+        return $this->success($result);
+    }
+    
+    // 恢复到指定版本
+    public function restoreRoleVersion(Request $request) {
+        $data = $request->all();
+        $result = $this->AnimeService->restoreRoleVersion($data);
+        return $this->success(['success' => $result ? 1 : 0]);
+    }
 
     // 删除角色
     public function deleteRole(Request $request) {

+ 226 - 23
app/Services/Anime/AnimeService.php

@@ -4320,41 +4320,86 @@ class AnimeService
     }
 
     /**
-     * 获取角色库列表(支持文件夹)
-     * @param array $data 包含 parent_id(父文件夹ID,默认0)、role(搜索关键词)
-     * @return array 返回文件夹和角色列表
+     * 获取角色库列表(支持文件夹递归查询
+     * @param array $data 包含 parent_id(父文件夹ID,默认0表示最外层)、role(搜索关键词)
+     * @return array 返回当前目录下的所有子目录和角色列表(递归)
      */
     public function globalRoles($data) {
         $cpid = Site::getCpid();
         $parent_id = getProp($data, 'parent_id', 0);
         $role = getProp($data, 'role');
         
-        // 构建查询
-        $query = DB::table('mp_roles')
+        // 如果有搜索关键词,只搜索角色图片
+        if ($role) {
+            $result = DB::table('mp_roles')
+                ->where('cpid', $cpid)
+                ->where('is_deleted', 0)
+                ->where('type', 1)
+                ->where('role', 'like', "%{$role}%")
+                ->select('id', 'type', 'parent_id', 'level', 'role', 'url', 'pic_prompt', 'three_view_image_url', 'versions', 'created_at')
+                ->orderByRaw('sort_order DESC, created_at DESC')
+                ->get()
+                ->map(function($value) {
+                    $value = (array)$value;
+                    $value['created_at'] = transDate($value['created_at'], 'Y-m-d');
+                    $value['type'] = (int)$value['type'];
+                    $value['parent_id'] = (int)$value['parent_id'];
+                    $value['level'] = (int)$value['level'];
+                    $value['versions'] = json_decode($value['versions'], true) ?: [];
+                    return $value;
+                })
+                ->toArray();
+            
+            return $result;
+        }
+        
+        // 递归获取所有子目录和角色
+        return $this->getChildrenRecursive($cpid, $parent_id);
+    }
+    
+    /**
+     * 递归获取指定目录下的所有子目录和角色
+     * @param int $cpid 公司ID
+     * @param int $parent_id 父目录ID
+     * @return array
+     */
+    private function getChildrenRecursive($cpid, $parent_id) {
+        // 查询当前层级的所有项(文件夹和角色)
+        $items = DB::table('mp_roles')
             ->where('cpid', $cpid)
             ->where('is_deleted', 0)
             ->where('parent_id', $parent_id)
-            ->select('id', 'type', 'parent_id', 'level', 'role', 'url', 'pic_prompt', 'three_view_image_url', 'sort_order', 'created_at');
+            ->select('id', 'type', 'parent_id', 'level', 'role', 'url', 'pic_prompt', 'three_view_image_url',  'versions', 'created_at')
+            ->orderByRaw('type DESC, sort_order DESC, created_at DESC')
+            ->get();
         
-        // 如果有搜索关键词,只搜索角色图片(type=1)
-        if ($role) {
-            $query->where('type', 1)->where('role', 'like', "%{$role}%");
+        $result = [];
+        
+        foreach ($items as $item) {
+            $itemArray = [
+                'id' => $item->id,
+                'type' => (int)$item->type,
+                'parent_id' => (int)$item->parent_id,
+                'level' => (int)$item->level,
+                'role' => $item->role,
+                'url' => $item->url,
+                'pic_prompt' => $item->pic_prompt,
+                'three_view_image_url' => $item->three_view_image_url,
+                'created_at' => transDate($item->created_at, 'Y-m-d')
+            ];
+            $itemArray['versions'] = json_decode($item->versions, true) ?: [];
+            
+            // 如果是文件夹,递归获取其子项
+            if ($item->type == 2) {
+                $children = $this->getChildrenRecursive($cpid, $item->id);
+                if (!empty($children)) {
+                    $itemArray['children'] = $children;
+                }
+            }
+            
+            $result[] = $itemArray;
         }
         
-        // 排序:文件夹优先,然后按 sort_order 降序,最后按创建时间降序
-        $result = $query->orderByRaw('type DESC, sort_order DESC, created_at DESC')
-            ->get()
-            ->map(function($value) {
-                $value = (array)$value;
-                $value['created_at'] = transDate($value['created_at'], 'Y-m-d');
-                $value['type'] = (int)$value['type'];
-                $value['parent_id'] = (int)$value['parent_id'];
-                $value['level'] = (int)$value['level'];
-                $value['sort_order'] = (int)$value['sort_order'];
-                return $value;
-            })
-            ->toArray();
-
         return $result;
     }
     
@@ -4733,6 +4778,7 @@ class AnimeService
         if (!$role) Utils::throwError('20003:角色不存在');
         
         $updateData = [];
+        $needVersionRecord = false; // 是否需要记录版本
         
         // 角色名
         $roleName = trim(getProp($data, 'role'));
@@ -4751,12 +4797,23 @@ class AnimeService
             if (!in_array($extension, $allowedExtensions)) {
                 Utils::throwError('20003:图片格式不正确,仅支持 jpg、jpeg、png、gif、webp、bmp 格式');
             }
+            
+            // 如果 url 有变更,记录版本
+            if ($url !== $role->url) {
+                $needVersionRecord = true;
+            }
+            
             $updateData['url'] = $url;
         }
         
         // 角色提示词
         $pic_prompt = trim(getProp($data, 'pic_prompt'));
         if ($pic_prompt) {
+            // 如果 pic_prompt 有变更,记录版本
+            if ($pic_prompt !== $role->pic_prompt) {
+                $needVersionRecord = true;
+            }
+            
             $updateData['pic_prompt'] = $pic_prompt;
         }
         
@@ -4764,12 +4821,158 @@ class AnimeService
             Utils::throwError('20003:没有需要更新的数据');
         }
         
+        // 如果需要记录版本,将数据添加到 versions 数组
+        if ($needVersionRecord) {
+            // 获取现有的 versions 数据
+            $versions = json_decode($role->versions, true) ?: [];
+            $isFirstVersion = empty($versions); // 判断是否是第一次记录版本
+            
+            // 如果是第一次记录版本,先添加旧版本(变更前)
+            if ($isFirstVersion) {
+                $oldVersion = [
+                    'url' => $role->url,
+                    'description' => $role->pic_prompt,
+                ];
+                // 旧版本添加到数组末尾
+                $versions[] = $oldVersion;
+            }
+            
+            // 构建新版本(变更后)
+            $newVersion = [
+                'url' => isset($updateData['url']) ? $updateData['url'] : $role->url,
+                'description' => isset($updateData['pic_prompt']) ? $updateData['pic_prompt'] : $role->pic_prompt,
+            ];
+            
+            // 检查新版本是否已存在于历史版本中
+            $existingIndex = -1;
+            foreach ($versions as $index => $version) {
+                if ($version['url'] === $newVersion['url'] && $version['description'] === $newVersion['description']) {
+                    $existingIndex = $index;
+                    break;
+                }
+            }
+            
+            if ($existingIndex !== -1) {
+                // 如果已存在,移除旧的位置
+                array_splice($versions, $existingIndex, 1);
+            }
+            
+            // 新版本添加到数组开头(最新的在前)
+            array_unshift($versions, $newVersion);
+            
+            // // 限制版本数量(可选,例如只保留最近10个版本)
+            // if (count($versions) > 10) {
+            //     $versions = array_slice($versions, 0, 10);
+            // }
+            
+            $updateData['versions'] = json_encode($versions, 256);
+        }
+        
         $updateData['updated_at'] = date('Y-m-d H:i:s');
         
         return DB::table('mp_roles')
         ->where('cpid', $cpid)
         ->where('id', $id)->update($updateData);
     }
+    
+    /**
+     * 获取角色版本历史
+     * @param array $data 包含 id(角色ID)
+     * @return array 返回版本历史列表
+     */
+    public function getRoleVersions($data) {
+        $cpid = Site::getCpid();
+        $id = getProp($data, 'id');
+        if (!$id) Utils::throwError('20003:角色ID不能为空');
+        
+        $role = DB::table('mp_roles')
+            ->where('id', $id)
+            ->where('cpid', $cpid)
+            ->where('type', 1)
+            ->first();
+        
+        if (!$role) Utils::throwError('20003:角色不存在');
+        
+        // 获取版本历史
+        $versions = json_decode($role->versions, true) ?: [];
+        
+        // 添加当前版本作为最新版本
+        $currentVersion = [
+            'version' => 0, // 0 表示当前版本
+            'url' => $role->url,
+            'pic_prompt' => $role->pic_prompt,
+            'updated_at' => $role->updated_at,
+            'is_current' => true
+        ];
+        
+        array_unshift($versions, $currentVersion);
+        
+        return $versions;
+    }
+    
+    /**
+     * 恢复到指定版本
+     * @param array $data 包含 id(角色ID)、version(版本号)
+     * @return bool
+     */
+    public function restoreRoleVersion($data) {
+        $uid = Site::getUid();
+        $cpid = Site::getCpid();
+        $id = getProp($data, 'id');
+        $version = getProp($data, 'version');
+        
+        if (!$id) Utils::throwError('20003:角色ID不能为空');
+        if (!$version) Utils::throwError('20003:版本号不能为空');
+        
+        $role = DB::table('mp_roles')
+            ->where('id', $id)
+            ->where('cpid', $cpid)
+            ->where('type', 1)
+            ->first();
+        
+        if (!$role) Utils::throwError('20003:角色不存在');
+        
+        // 获取版本历史
+        $versions = json_decode($role->versions, true) ?: [];
+        
+        // 查找指定版本
+        $targetVersion = null;
+        foreach ($versions as $v) {
+            if ($v['version'] == $version) {
+                $targetVersion = $v;
+                break;
+            }
+        }
+        
+        if (!$targetVersion) Utils::throwError('20003:版本不存在');
+        
+        // 先将当前版本保存到历史
+        $newVersion = [
+            'version' => count($versions) + 1,
+            'url' => $role->url,
+            'pic_prompt' => $role->pic_prompt,
+            'updated_at' => date('Y-m-d H:i:s'),
+            'updated_by' => $uid
+        ];
+        
+        array_unshift($versions, $newVersion);
+        
+        // 限制版本数量
+        if (count($versions) > 10) {
+            $versions = array_slice($versions, 0, 10);
+        }
+        
+        // 恢复到指定版本
+        return DB::table('mp_roles')
+            ->where('id', $id)
+            ->where('cpid', $cpid)
+            ->update([
+                'url' => $targetVersion['url'],
+                'pic_prompt' => $targetVersion['pic_prompt'],
+                'versions' => json_encode($versions, JSON_UNESCAPED_UNICODE),
+                'updated_at' => date('Y-m-d H:i:s')
+            ]);
+    }
 
     public function deleteRole($data) {
         $uid = Site::getUid();

+ 2 - 0
routes/api.php

@@ -200,6 +200,8 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
             Route::get('globalRoles', [AnimeController::class, 'globalRoles']);     // 角色库
             Route::post('createRole', [AnimeController::class, 'createRole']);      // 创建角色
             Route::post('editRole', [AnimeController::class, 'editRole']);          // 编辑角色
+            // Route::get('getRoleVersions', [AnimeController::class, 'getRoleVersions']); // 获取角色版本历史
+            // Route::post('restoreRoleVersion', [AnimeController::class, 'restoreRoleVersion']); // 恢复到指定版本
             Route::get('deleteRole', [AnimeController::class, 'deleteRole']);       // 删除角色
             Route::post('createFolder', [AnimeController::class, 'createFolder']);  // 新建文件夹
             Route::post('renameFolder', [AnimeController::class, 'renameFolder']); // 重命名文件夹