Browse Source

Merge branch 'refs/heads/dev' into R1

peterguo 3 weeks ago
parent
commit
670ad2f0ed

+ 0 - 59
app/Admin/Controllers/AuthController.php

@@ -1,59 +0,0 @@
-<?php
-
-namespace App\Admin\Controllers;
-
-use Encore\Admin\Controllers\AuthController as BaseAuthController;
-use GuzzleHttp\Client;
-use Illuminate\Support\Facades\Auth;
-
-class AuthController extends BaseAuthController
-{
-    /**
-     * 获取4s系统的访问令牌
-     *
-     * @return \Illuminate\Http\JsonResponse
-     */
-    public function get4sAccessToken()
-    {
-        try {
-            $user = Auth::user();
-            
-            $client = new Client();
-            $response = $client->post('http://newlinker.net:18001/login/pc', [
-                'query' => [
-                    'username' => $user->username,
-                    'password' => $user->password
-                ],
-                'http_errors' => false
-            ]);
-
-            $result = json_decode($response->getBody()->getContents(), true);
-
-            if ($result['success'] && $result['code'] == 200) {
-                return response()->json([
-                    'success' => true,
-                    'code' => 200,
-                    'message' => '成功',
-                    'data' => [
-                        'token' => $result['data']['token']
-                    ]
-                ]);
-            }
-
-            return response()->json([
-                'success' => false,
-                'code' => $result['code'] ?? 500,
-                'message' => $result['message'] ?? '获取token失败',
-                'data' => null
-            ]);
-
-        } catch (\Exception $e) {
-            return response()->json([
-                'success' => false,
-                'code' => 500,
-                'message' => '获取token失败: ' . $e->getMessage(),
-                'data' => null
-            ]);
-        }
-    }
-}

+ 44 - 14
app/Http/Controllers/API/FileController.php

@@ -27,6 +27,7 @@ use App\Services\File\Upload\CompanyUploadService;
 use App\Services\File\Upload\FilesUploadService;
 use App\Services\File\Upload\KeepDirectoryUploadService;
 use App\Services\File\Upload\ProgressBar;
+use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
 use Illuminate\Support\Facades\Auth;
@@ -67,7 +68,8 @@ class FileController extends Controller
             ->where("object_id", $file->object_id)
             ->update(['title' => $request->get('title')]);
 
-        ActionRepository::createByFile($file->object_id, $file->object_type, ObjectAction::EDITED_FILE);
+
+        ActionRepository::create($id, ActionObjectType::CONTAINER_FILE, ObjectAction::EDITED_FILE);
 
         return $this->noContent();
     }
@@ -94,7 +96,7 @@ class FileController extends Controller
 
         File::query()->whereIn("id", $files->pluck("id")->toArray())->delete();
 
-        ActionRepository::createByFile($file->object_id, $file->object_type, ObjectAction::DELETED_FILE);
+        ActionRepository::create($id, ActionObjectType::CONTAINER_FILE, ObjectAction::DELETED_FILE);
 
         Storage::delete($files->pluck("pathname")->toArray());
 
@@ -132,7 +134,7 @@ class FileController extends Controller
      * 文件上传
      *
      * @param FileUploadRequest $request
-     * @return FileUploadSuccessResource|\Illuminate\Http\JsonResponse
+     * @return FileUploadSuccessResource|JsonResponse
      */
     public function upload(FileUploadRequest $request)
     {
@@ -181,7 +183,7 @@ class FileController extends Controller
      * 文件夹上传
      *
      * @param KeepDirectoryUploadRequest $request
-     * @return FileUploadSuccessResource|\Illuminate\Http\JsonResponse
+     * @return FileUploadSuccessResource|JsonResponse
      */
     public function keepDirectoryUpload(KeepDirectoryUploadRequest $request)
     {
@@ -269,14 +271,10 @@ class FileController extends Controller
             return $this->badRequest("BIM is in the process of conversion. Please wait a moment");
         }
 
-        switch ($bimFile->bim_driver) {
-            case BIMDriverEnum::GLENDALE->value:
-                $result = (new BimService)->getGlendaleBimInfo($file->bimFile);
-                break;
-            default:
-                $result = [];
-                break;
-        }
+        $result = match ($bimFile->bim_driver) {
+            BIMDriverEnum::GLENDALE->value => (new BimService)->getGlendaleBimInfo($file->bimFile),
+            default => [],
+        };
 
         return $this->success([
             'data' => [
@@ -286,6 +284,36 @@ class FileController extends Controller
         ]);
     }
 
+    public function batchBimView(Request $request, BimService $service): JsonResponse
+    {
+        $data = [];
+        $ids = $request->get('file_ids');
+        $fileList = File::with('bimFile')->where('is_bim', 1)->whereIn('id', $ids)->get();
+        foreach ($fileList as $file) {
+            $fileObjectType = FileObjectType::from($file->object_type);
+            $object = $fileObjectType->modelBuilderAllowed($file->object_id)->find($file->object_id);
+            if (!$object) {
+                return $this->badRequest(sprintf("File ID: %s, no permission to access", $file->id));
+            }
+            $bimFile = $file->bimFile;
+            if ($bimFile->convert_status !== BimFileConvertStatus::DONE->value) {
+                return $this->badRequest("BIM is in the process of conversion. Please wait a moment");
+            }
+            $result = match ($bimFile->bim_driver) {
+                BIMDriverEnum::GLENDALE->value => $service->getGlendaleBimInfo($file->bimFile),
+                default => [],
+            };
+            $data[] = [
+                'bim_driver' => $bimFile->bim_driver,
+                'bim_view' => $result
+            ];
+        }
+
+        return $this->success([
+            'data' => $data
+        ]);
+    }
+
     /**
      * 获取上传COS临时密钥
      */
@@ -354,7 +382,7 @@ class FileController extends Controller
         $fileId = (int) ($inputArr['file_id'] ?? 0);
         $pageSize = (int) $request->get('page_size', 10);
 
-        $file = File::query()->findOrFail($fileId);
+        $file = File::query()->with(['bimFile', 'createdBy'])->findOrFail($fileId);
 
         if (!empty($file->source_file_id)) {
             $files = File::query()
@@ -371,7 +399,7 @@ class FileController extends Controller
             $files[] = $file;
         }
 
-        return FileSimpleResource::collection($files);
+        return FileByObjectResource::collection($files);
     }
 
     // 文件详情
@@ -391,4 +419,6 @@ class FileController extends Controller
         $fileService->update($id, $request->all());
         return $this->noContent();
     }
+
+
 }

+ 39 - 39
app/Http/Controllers/API/FolderController.php

@@ -8,6 +8,7 @@ use App\Http\Requests\API\Folder\UpdateRequest;
 use App\Http\Resources\API\FileByObjectResource;
 use App\Http\Resources\API\FileVersioTreeByObjectResource;
 use App\Http\Resources\API\FolderDetailResource;
+use App\Http\Resources\API\UserProfileResource;
 use App\Models\Enums\FolderObjectType;
 use App\Models\Enums\ObjectApprovalStatus;
 use App\Models\File;
@@ -21,6 +22,7 @@ use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
+use function Symfony\Component\String\s;
 
 class FolderController extends Controller
 {
@@ -128,6 +130,7 @@ class FolderController extends Controller
 
             if ($isUpdate) {
                 $folder = $updateFolders[$item['id']];
+                $data['updated_by'] = Auth::user()->id;
                 $folder->fill($data);
                 $folder->save();
             } else {
@@ -135,7 +138,8 @@ class FolderController extends Controller
                     'company_id' => Auth::user()->company_id,
                     ...$objectWhere,
                     'parent_id' => $request->parent_id,
-                    ...$data
+                    ...$data,
+                    'created_by' => Auth::user()->id,
                 ]);
 
                 $folder->path = $parentFolder ? $parentFolder?->path . $folder->id . "," : sprintf(",%s,", $folder->id);
@@ -247,8 +251,19 @@ class FolderController extends Controller
         $pageSize = $request->get('page_size') ?? 10;
         $page = $request->get('page') ?? 1;
 
+        $docStages = $request->get('doc_stage', []); // 支持多选
+        $docTypes = $request->get('doc_type', []); // 支持多选
+        $type = $request->get('type', []); // 支持多选
+        $namingRuleId = $request->get('naming_rule_id');
+        $statusCode = $request->get('RevisionCodes');
+        $revisionCodes = $request->get('RevisionCodes');
+        $name = $request->get('name');
+        $approvalStatus = $request->get('approval_status', []); // 支持多选
+
         $folderId = $request->get("id", 0);
-        $orderBy=$request->get('order_by','desc');
+        $orderByFiled = $request->get('order_by_column','updated_at');// 设置默认字段
+        $orderByType = $request->get('order_by_direction','desc'); // 设置默认排序方式
+
         if ($folderId > 0) {
             $folder = Folder::query()->findOrFail($folderId);
             $objectType = $folder->object_type;
@@ -267,61 +282,46 @@ class FolderController extends Controller
         $folders = Folder::with(["namingRule" => function ($query) {
             $query->select(['id', 'name', 'combination_rules']);
         }])
-            ->select(['id', 'name', 'naming_rule_id'])
             ->where($objectWhere)
+            ->when($name, fn($query) => $query->where("name", "like", "%$name%"))
             ->when($folderId, fn($query) => $query->where("parent_id", $folderId))
             ->when(! $folderId, fn($query) => $query->where("parent_id", 0))
-            ->orderBy('updated_at', $orderBy)
+            ->when($namingRuleId, fn($query) => $query->where("naming_rule_id", $namingRuleId))
+            ->when($type, fn($query) => $query->whereRaw("1=?", in_array('folder', $type) ? 1 : 0))
+            ->orderBy(in_array($orderByFiled, Folder::getColumns()) ? $orderByFiled : 'updated_at', $orderByType)
             ->paginate($pageSize);
         $folders_total = $folders->total();
-        $sonFolderCount=Folder::query()
-            ->where($objectWhere)
-            ->whereIn('parent_id',$folders->pluck('id'))
-            ->selectRaw("count(*) as cut, parent_id")
-            ->groupBy("parent_id")
-            ->pluck("cut", "parent_id");
-
-        $sonFileCount=File::query()
-            ->where($objectWhere)
-            ->whereIn('folder_id',$folders->pluck('id'))
-            ->where("is_latest_version", 1)
-            ->selectRaw("count(*) as cut, folder_id")
-            ->groupBy("folder_id")
-            ->pluck("cut", "folder_id");
-
 
         $index=1;
-        $folders = $folders->map(function (Folder $folder) use ($sonFolderCount,$sonFileCount,&$index) {
-            $folder->itemCount =$sonFolderCount->get($folder->id, 0)+$sonFileCount->get($folder->id, 0);
-            $folder->type = 'folder';
-            $folder->uniId = $folder->type . '_' . $folder->id;
+        $folders = $folders->map(function (Folder $folder) use (&$index) {
             $folder->display_id=(string)$index++;
             return $folder;
         });
 
-        $files = File::query()->where($objectWhere)
+       $fileQuery = File::query()->where($objectWhere)
             ->with('bimFile')
             ->where("folder_id", $folderId)
             ->where("is_latest_version", 1)
-            ->orderBy('updated_at', $orderBy)
-            ->get();
+            ->when($name, fn($query) => $query->where("title", "like", "%$name%"))
+            ->when($docStages, fn($query) => $query->whereIn('doc_stage', $docStages))
+            ->when($docTypes, fn($query) => $query->whereIn('doc_type', $docTypes))
+            ->when($namingRuleId, fn($query) => $query->where('naming_rule_id', $namingRuleId))
+            ->when($type, fn($query) => $query->whereIn("extension", $type))
+            ->when($statusCode, fn($query) => $query->whereRaw('naming_rules->>"$.StatusCode"=?', $statusCode))
+            ->when($revisionCodes, fn($query) => $query->whereRaw('naming_rules->>"$.RevisionCodes"=?', $revisionCodes))
+            ->when($approvalStatus, fn($query) => $query->whereIn('approval_status', $approvalStatus))
+            ->orderBy(in_array($orderByFiled, File::getColumns()) ? $orderByFiled : 'updated_at', $orderByType);
+
+        $files = $fileQuery->get();
 
         $files_total = $files->count();
 
-        $total = $files_total + $folders_total;
         //分页
         if ($folders_total < $pageSize * $page){
             $offset = $pageSize * $page - $folders_total <= $pageSize ?  0 : $pageSize  * $page - $pageSize * ($page - 1) - $folders_total ; // 查看当前页面是否有包含文件夹
-            $limit = $pageSize * $page - $folders_total > $pageSize ? $pageSize : $pageSize * $page - $folders_total;
-
-            $files = File::query()->where($objectWhere)
-                ->with('bimFile')
-                ->where("folder_id", $folderId)
-                ->where("is_latest_version", 1)
-                ->orderBy('updated_at', $orderBy)
-                ->offset($offset)
-                ->limit($limit)
-                ->get();
+            $limit = min($pageSize * $page - $folders_total, $pageSize);
+
+            $files = $fileQuery->offset($offset)->limit($limit)->get();
             //因为要接着文件夹进行文件id递增
             $folderCount=$folders->count()+1;
             $files->map(function (File $file) use (&$folderCount) {
@@ -358,7 +358,7 @@ class FolderController extends Controller
         return $this->success([
             'object'=>$container,
             'data' => [
-                'folders' => $folders,
+                'folders' => FolderDetailResource::collection($folders),
                 'total' => $folders_total + $files_total,
                 'files' => FileByObjectResource::collection($files),
                 'folder_parent_id'=>$folderId>0?$folder->parent_id:$folderId,
@@ -430,7 +430,7 @@ class FolderController extends Controller
             ->where($objectWhere)
             ->where('title','like',"%$name%")
             ->where("is_latest_version", 1);
-        
+
         // 添加doc_stage多选过滤
         if (!empty($docStages)) {
             $fileQuery->whereIn('doc_stage', $docStages);

+ 38 - 0
app/Http/Controllers/API/OpenPlatformController.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Http\Controllers\API;
+
+use App\Http\Controllers\Controller;
+use GuzzleHttp\Client;
+use GuzzleHttp\Exception\ClientException;
+use Illuminate\Http\Request;
+
+class OpenPlatformController extends Controller
+{
+    public function proxy(Request $request)
+    {
+        $client = new Client();
+        $path = $request->get('path');
+        $targetUrl = env('OPEN_PLATFORM_URL') . $path;
+        $method = $request->getMethod();
+        $headers = $request->headers->all();
+        $body = $request->getContent();
+
+        try {
+            $response = $client->request($method, $targetUrl, [
+                'headers' => $headers,
+                'body' => $body,
+                'auth' => [
+                    env('OPEN_PLATFORM_USERNAME'),
+                    env('OPEN_PLATFORM_PASSWORD')
+                ]
+            ]);
+            $content = json_decode($response->getBody()->getContents(), true);
+            return $this->success(['data' => $content['data']]);
+        } catch (ClientException $e) {
+            $response = $e->getResponse();
+            $content = json_decode($response->getBody()->getContents(), true);
+            return $this->badRequest($content['message']);
+        }
+    }
+}

+ 6 - 1
app/Http/Resources/API/FileByObjectResource.php

@@ -25,14 +25,19 @@ class FileByObjectResource extends JsonResource
             'download_url' => Storage::url($this->pathname),
             'size' => $this->size,
             'created_by' => $this->createdBy ? new UserProfileResource($this->createdBy) : null,
+            'updated_by' => $this->updatedBy ? new UserProfileResource($this->updatedBy) : null,
             'created_at' => (string) $this->created_at,
+            'updated_at' => (string) $this->updated_at,
             'version' => $this->version,
             'display_id'=>(string)$this->display_id,
             'object_type'=>$this->object_type,
             'object_id'=>$this->object_id,
             'approval_status'=>$this->approval_status,
-            'naming_rule' => new NamingRuleSimpleResource($this->namingRule),
+            'naming_rule' => $this->namingRule ? new NamingRuleSimpleResource($this->namingRule) : null,
             'naming_rules' => $this->naming_rules,
+            'doc_stage' => $this->doc_stage,
+            'doc_type' => $this->doc_type,
+            'bim_file' => $this->bimFile ? new BimFileResource($this->bimFile) : null,
         ];
 
         if ($this->is_bim == 1 && $this->bimFile && $this->bimFile->convert_status == BimFileConvertStatus::DONE->value) {

+ 10 - 0
app/Http/Resources/API/FolderDetailResource.php

@@ -15,11 +15,21 @@ class FolderDetailResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
+            'id' => $this->id,
             'object_type' => $this->object_type,
             'object_id' => $this->object_id,
             'name' => $this->name,
             'parent_id' => $this->parent_id,
             'sequence' => $this->sequence,
+            'created_at' => (string)$this->created_at,
+            'updated_at' => (string)$this->updated_at,
+            'created_by' => $this->createdBy ? new UserProfileResource($this->createdBy) : null,
+            'updated_by' => $this->updatedBy ? new UserProfileResource($this->updatedBy) : null,
+            'type' => 'folder',
+            'itemCount' => $this->children()->count() + $this->files()->where('is_latest_version', 1)->count(),
+            'uniId' => 'folder_' . $this->id,
+            'display_id'=>(string)$this->display_id,
+            'naming_rule' => new NamingRuleSimpleResource($this->namingRule),
         ];
     }
 }

+ 1 - 1
app/Libraries/BIM/Glendale/Client.php

@@ -50,7 +50,7 @@ class Client
     {
         Log::debug('send to glendale engine url: ' . $uri);
         Log::debug('send to glendale engine input: ', $options);
-        
+
         return $this->request("POST", $uri, $options);
     }
 

+ 11 - 0
app/Models/File.php

@@ -11,11 +11,17 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
 use Illuminate\Database\Eloquent\Relations\HasOneThrough;
 use Illuminate\Database\Eloquent\SoftDeletes;
 use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Schema;
 
 class File extends Model
 {
     use HasFactory, SoftDeletes;
 
+    public static function getColumns(): array
+    {
+        return Schema::getColumnListing((new self)->getTable());
+    }
+
     protected $fillable = [
         "company_id",
         "pathname",
@@ -58,6 +64,11 @@ class File extends Model
         return $this->belongsTo(User::class, "created_by");
     }
 
+    public function updatedBy(): BelongsTo
+    {
+        return $this->belongsTo(User::class, "updated_by");
+    }
+
     public function folder(): BelongsTo
     {
         return $this->belongsTo(Folder::class);

+ 15 - 0
app/Models/Folder.php

@@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Database\Eloquent\Relations\HasOneThrough;
 use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Support\Facades\Schema;
 
 class Folder extends Model
 {
@@ -17,6 +18,10 @@ class Folder extends Model
 
     protected $guarded = ['id'];
     private mixed $children;
+    public static function getColumns(): array
+    {
+        return Schema::getColumnListing((new self)->getTable());
+    }
 
     protected static function booted(): void
     {
@@ -52,4 +57,14 @@ class Folder extends Model
     {
         return $this->hasOneThrough(Library::class, Container::class, 'id', 'id', 'object_id', 'library_id');
     }
+
+    public function createdBy(): BelongsTo
+    {
+        return $this->belongsTo(User::class, "created_by");
+    }
+
+    public function updatedBy(): BelongsTo
+    {
+        return $this->belongsTo(User::class, "updated_by");
+    }
 }

+ 1 - 1
app/Repositories/ActionRepository.php

@@ -393,7 +393,7 @@ class ActionRepository
             ->with(['histories', 'createdBy'])
             ->where("object_type", $actionObjectType->value)
             ->whereIn("object_id", $objectIds)
-            ->orderBy("created_at")
+            ->orderBy("created_at", 'desc')
             ->get();
 
         $objectNames = self::objectNamesGroupByType($actions);

+ 5 - 0
app/Services/File/FileService.php

@@ -2,12 +2,16 @@
 
 namespace App\Services\File;
 
+use App\Libraries\BIM\BIMDriverEnum;
 use App\Models\Enums\ActionObjectType;
+use App\Models\Enums\BimFileConvertStatus;
+use App\Models\Enums\FileObjectType;
 use App\Models\Enums\ObjectAction;
 use App\Models\File;
 use App\Repositories\ActionRepository;
 use App\Repositories\CustomFieldRepository;
 use App\Services\History\ModelChangeDetector;
+use Illuminate\Support\Facades\Auth;
 
 class FileService
 {
@@ -20,6 +24,7 @@ class FileService
     public function update(string $id, array $updatedData): void
     {
         $file = File::query()->findOrFail($id);
+        $updatedData['updated_by'] = Auth::user()->id;
         $file->fill($updatedData);
 
         $changes = ModelChangeDetector::detector(ActionObjectType::CONTAINER_FILE, $file);

+ 4 - 2
app/Services/History/Detector/FileDetector.php

@@ -15,7 +15,8 @@ class FileDetector extends DetectorAbstract
             'version',
             'doc_stage',
             'doc_type',
-            'naming_rules'
+            'naming_rules',
+            'is_latest_version',
         ];
     }
 
@@ -28,7 +29,8 @@ class FileDetector extends DetectorAbstract
             'version',
             'doc_stage',
             'doc_type',
-            'naming_rules'
+            'naming_rules',
+            'is_latest_version',
         ];
     }
 

+ 3 - 0
app/Services/History/ModelChangeDetector.php

@@ -56,6 +56,9 @@ class ModelChangeDetector
         $items = [];
         $oldArr = $model->getOriginal($field);
         $newArr = $model->$field;
+        if (!is_array($newArr) || !is_object($newArr)) {
+            return [];
+        }
         foreach ($newArr as $field => $newValue) {
             $oldValue = $oldArr[$field] ?? null;
             $diff = text_diff($oldValue ?? '', $newValue ?? '');

+ 30 - 0
database/migrations/tenant/2025_02_05_160814_add_columns_to_files_table.php

@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('files', function (Blueprint $table) {
+            //
+            $table->integer('updated_by')->nullable();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('files', function (Blueprint $table) {
+            //
+            $table->dropColumn('updated_by');
+        });
+    }
+};

+ 32 - 0
database/migrations/tenant/2025_02_05_160852_add_columns_to_folders_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('folders', function (Blueprint $table) {
+            //
+            $table->integer('created_by')->nullable();
+            $table->integer('updated_by')->nullable();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('folders', function (Blueprint $table) {
+            //
+            $table->dropColumn('created_by');
+            $table->dropColumn('updated_by');
+        });
+    }
+};

+ 4 - 1
routes/api.php

@@ -87,7 +87,7 @@ Route::middleware((function() {
         Route::get("approval-items",[API\ApprovalController::class, "publicSearch"]);
         Route::post("file-cos-token",[API\FileController::class, "getCOSToken"])->name('file.cos.token');
         Route::post("naming-rule/{name_rule}/parse", [API\NameRuleController::class, "parse"]);
-
+        Route::any('open-platform', [API\OpenPlatformController::class, 'proxy']);
 
         // Allow access only to admin role
         Route::middleware(['permission', 'role.super-admin', 'system.operation-log'])->group(function () {
@@ -304,6 +304,8 @@ Route::middleware((function() {
             Route::post("file/keep-directory-upload", [API\FileController::class, "keepDirectoryUpload"])->name("file.keep-directory-upload");
             Route::delete("file/{file}/hide", [API\FileController::class, "hide"])->name("file.hide");
             Route::get("file-bim-view/{file}", [API\FileController::class, "bimView"])->name("file.bim-view");
+            Route::get("file-batch-bim-view", [API\FileController::class, "batchBimView"])->name("file.batch-bim-view");
+
             Route::get("file/models", [API\FileController::class, "models"])->name("file.models");
             Route::get("file/model-history", [API\FileController::class, "modelHistory"])->name("file.model-history");
             Route::get("file/{fileId}", [API\FileController::class, "detail"])->name("file.detail");
@@ -312,6 +314,7 @@ Route::middleware((function() {
             ]);
 
 
+
             Route::get("bim/multiple-views", [API\BimController::class, "multipleViews"])->name("bim.multiple-views");
             Route::post('bim/combine', [API\BimController::class, "combine"])->name("bim.combine");
             Route::put('bim/combine/{combineId}', [API\BimController::class, "combineUpdate"])->name("bim.combine-update");