dongasai 8 months ago
parent
commit
13731e630f
30 changed files with 1244 additions and 60 deletions
  1. 1 2
      DockerfileDev
  2. 20 0
      app/Module/Game/AdminControllers/TestController.php
  3. 35 0
      app/Module/Game/Commands/TestCommands.php
  4. 17 0
      app/Module/Game/Config/test.php
  5. 32 0
      app/Module/Game/DCache/ItemJsonConfig.php
  6. 10 0
      app/Module/Game/Enums/JSON_CONFIG_NAME.php
  7. 39 0
      app/Module/Game/Enums/TEST_TYPE.php
  8. 40 0
      app/Module/Game/Events/TestEvent.php
  9. 18 0
      app/Module/Game/Exceptions/TestException.php
  10. 34 0
      app/Module/Game/Jobs/TestJob.php
  11. 1 0
      app/Module/Game/Listeners/README.md
  12. 80 0
      app/Module/Game/Models/Test.php
  13. 29 0
      app/Module/Game/Providers/TestServiceProvider.php
  14. 8 0
      app/Module/Game/Queues/TestQueue.php
  15. 28 0
      app/Module/Game/README.md
  16. 10 0
      app/Module/Game/Repositorys/FundAdminRepository.php
  17. 31 0
      app/Module/Game/Services/JsonConfigService.php
  18. 167 0
      app/Module/Game/Tests/TestEventTest.php
  19. 133 0
      app/Module/Game/Tests/TestHookTest.php
  20. 83 0
      app/Module/Game/Tests/TestSoftDeleteTest.php
  21. 92 0
      app/Module/Game/Tests/TestTest.php
  22. 32 0
      app/Module/Game/Validations/TestValidation.php
  23. 38 0
      app/Module/Game/Validators/TestValidator.php
  24. 2 1
      app/Module/GameItems/AdminControllers/ItemController.php
  25. 2 10
      app/Module/GameItems/AdminControllers/Tools/RefreshCheckTool.php
  26. 23 28
      app/Module/GameItems/Commands/GenerateItemsJsonCommand.php
  27. 54 0
      app/Module/LCache/DQueueJob.php
  28. 24 0
      app/Module/LCache/DQueueJobInterface.php
  29. 1 1
      config/database.php
  30. 160 18
      public/json/items.json

+ 1 - 2
DockerfileDev

@@ -1,4 +1,3 @@
-
 FROM docker.m.daocloud.io/php:8.3-apache
 
 ENV REFRESH_DATE=9
@@ -66,7 +65,7 @@ COPY . /var/www/html
 # RUN chmod 777 -R storage
 # RUN chmod 777 -R bootstrap
 
-EXPOSE 9000
+EXPOSE 80
 
 #USER www-data
 # RUN composer install

+ 20 - 0
app/Module/Game/AdminControllers/TestController.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Module\Game\AdminControllers;
+
+use Dcat\Admin\Http\Controllers\AdminController;
+use Illuminate\Routing\Controller;
+use Illuminate\Support\Facades\Log;
+use Spatie\RouteAttributes\Attributes\Get;
+use Spatie\RouteAttributes\Attributes\Prefix;
+
+#[Prefix('game-test')]
+class TestController extends AdminController
+{
+    #[Get('/test')]
+    public function test()
+    {
+        Log::info(123);
+        echo 1;die;
+    }
+}

+ 35 - 0
app/Module/Game/Commands/TestCommands.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace App\Module\Game\Commands;
+
+
+
+use App\Module\Game\Services\TestService;
+use Illuminate\Console\Command;
+
+class TestCommands extends Command
+{
+    /**
+     * 控制台命令的名称和签名
+     *
+     * @var string
+     */
+    protected $signature = 'test';
+
+    /**
+     * 命令描述
+     *
+     * @var string
+     */
+    protected $description = 'Test commands';
+
+    /**
+     * 执行命令
+     */
+    public function handle()
+    {
+        TestService::verify(1);
+        echo '完成';
+    }
+
+}

+ 17 - 0
app/Module/Game/Config/test.php

@@ -0,0 +1,17 @@
+<?php
+
+return [
+    /*
+    |--------------------------------------------------------------------------
+    | 测试模块配置
+    |--------------------------------------------------------------------------
+    */
+
+    // 测试配置项
+    'key' => 'value',
+
+    // 测试数组配置
+    'array' => [
+        'key' => 'value'
+    ]
+];

+ 32 - 0
app/Module/Game/DCache/ItemJsonConfig.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Module\Game\DCache;
+
+use App\Module\GameItems\Commands\GenerateItemsJsonCommand;
+use App\Module\LCache\DQueueJob;
+
+class ItemJsonConfig extends DQueueJob
+{
+
+
+    static public function getNewData(array $parameter = [])
+    {
+        return GenerateItemsJsonCommand::generateJson();
+    }
+
+    static public function getTtl(): int
+    {
+        return 3600;
+    }
+
+    static public function getPreventDuplication(): int
+    {
+        return 600;
+    }
+
+    static public function getRequiredArgIndex(): array
+    {
+        return [];
+    }
+
+}

+ 10 - 0
app/Module/Game/Enums/JSON_CONFIG_NAME.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App\Module\Game\Enums;
+
+enum JSON_CONFIG_NAME: string
+{
+
+    case ITEM = 'items';
+
+}

+ 39 - 0
app/Module/Game/Enums/TEST_TYPE.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Module\Game\Enums;
+
+enum TEST_TYPE: int
+{
+    /**
+     * 禁用
+     */
+    case DISABLED = 0;
+
+    /**
+     * 启用
+     */
+    case ENABLED = 1;
+
+    /**
+     * 获取枚举标签
+     *
+     * @return string
+     */
+    public function label(): string
+    {
+        return match($this) {
+            self::DISABLED => '禁用',
+            self::ENABLED => '启用',
+        };
+    }
+
+    /**
+     * 获取枚举值
+     *
+     * @return int
+     */
+    public function value(): int
+    {
+        return $this->value;
+    }
+}

+ 40 - 0
app/Module/Game/Events/TestEvent.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Module\Game\Events;
+
+use App\Module\Game\Models\Test;
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+class TestEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * 测试数据
+     *
+     * @var Test
+     */
+    public Test $test;
+
+    /**
+     * 事件类型
+     *
+     * @var string
+     */
+    public string $type;
+
+    /**
+     * 创建事件实例
+     *
+     * @param Test $test
+     * @param string $type
+     * @return void
+     */
+    public function __construct(Test $test, string $type)
+    {
+        $this->test = $test;
+        $this->type = $type;
+    }
+}

+ 18 - 0
app/Module/Game/Exceptions/TestException.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Module\Game\Exceptions;
+
+class TestException extends \Exception
+{
+    /**
+     * 创建异常实例
+     *
+     * @param string $message
+     * @param int $code
+     * @return void
+     */
+    public function __construct(string $message = "", int $code = 0)
+    {
+        parent::__construct($message, $code);
+    }
+}

+ 34 - 0
app/Module/Game/Jobs/TestJob.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Module\Game\Jobs;
+
+use App\Module\Game\Models\Test;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class TestJob implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    /**
+     * 创建任务实例
+     *
+     * @param Test $test
+     */
+    public function __construct(protected Test $test)
+    {
+    }
+
+    /**
+     * 执行任务
+     *
+     * @return void
+     */
+    public function handle(): void
+    {
+        // 任务处理逻辑
+    }
+}

+ 1 - 0
app/Module/Game/Listeners/README.md

@@ -0,0 +1 @@
+# 事件监听

+ 80 - 0
app/Module/Game/Models/Test.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace App\Module\Game\Models;
+
+use App\Module\Game\Database\Factories\TestFactory;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use UCore\ModelCore;
+use Illuminate\Database\Eloquent\SoftDeletes;
+use App\Module\Game\Events\TestEvent;
+
+/**
+ * App\Module\Game\Models\Test
+ *
+ * field start
+ * @property   int  $id
+ * @property   string  $name  名称
+ * @property   string  $code  编码
+ * @property   string  $description  描述
+ * @property   object|array  $data  数据
+ * @property   int  $status  状态:0禁用 1启用
+ * @property   \Carbon\Carbon  $created_at
+ * @property   \Carbon\Carbon  $updated_at
+ * @property   \Carbon\Carbon  $deleted_at
+ * field end
+ */
+class Test extends ModelCore
+{
+    use HasFactory, SoftDeletes;
+
+    /**
+     * 与模型关联的表名
+     *
+     * @var string
+     */
+    protected $table = 'test';
+
+    // attrlist start
+    protected $fillable = [
+        'id',
+        'name',
+        'code',
+        'description',
+        'data',
+        'status',
+    ];
+    // attrlist end
+
+
+
+    /**
+     * 应该被调整为日期的属性
+     *
+     * @var array
+     */
+    protected $dates = [
+        'created_at',
+        'updated_at',
+        'deleted_at'
+    ];
+
+    /**
+     * 属性类型转换
+     *
+     * @var array
+     */
+    protected $casts = [
+        'data' => 'array',
+        'status' => 'integer'
+    ];
+
+    /**
+     * 创建一个新的工厂实例
+     *
+     * @return \Illuminate\Database\Eloquent\Factories\Factory
+     */
+    protected static function newFactory()
+    {
+        return TestFactory::new();
+    }
+}

+ 29 - 0
app/Module/Game/Providers/TestServiceProvider.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Module\Game\Providers;
+
+use App\Module\Game\Events\TestEvent;
+use App\Module\Game\Listeners\TestEventListener;
+use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
+
+class TestServiceProvider extends ServiceProvider
+{
+    /**
+     * 事件到监听器的映射
+     *
+     * @var array<class-string, array<int, class-string>>
+     */
+    protected $listen = [
+        TestEvent::class => [
+            TestEventListener::class,
+        ],
+    ];
+
+    /**
+     * 注册任何事件监听器
+     */
+    public function boot(): void
+    {
+        parent::boot();
+    }
+}

+ 8 - 0
app/Module/Game/Queues/TestQueue.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace App\Module\Game\Queues;
+
+class TestQueue
+{
+
+}

+ 28 - 0
app/Module/Game/README.md

@@ -0,0 +1,28 @@
+# Test 模块
+
+## 模块说明
+Test 模块是一个示例模块,用于展示模块化开发的最佳实践。
+
+## 目录结构
+```
+├── AdminControllers/    # 后台控制器
+├── Commands/            # 命令目录
+├── Config/              # 配置目录
+├── Database/            # 数据库目录
+│   └── create.sql       # 创建数据表的SQL
+└── Enums/               # 枚举(枚举的名和Case全大写)
+├── Models/              # 模型目录
+├── Providers/           # Providers
+├── Events/              # 事件目录
+├── Logic/               # Logic目录/逻辑目录
+├── Listeners/           # 监听器目录 
+├── Queues/              # 队列目录
+├── Repositorys/         # 仓库目录(后台控制器专用,其他场景不要用)
+├── Services/            # 服务目录(供其他模块使用)
+│   └──  TestService.php       # 服务之一
+├── Validations/         # Validation 目录(不是Laravel的Validation规则)
+├── Validators/          # Validator目录
+└── Tests/               # 测试目录
+```
+
+

+ 10 - 0
app/Module/Game/Repositorys/FundAdminRepository.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App\Module\Game\Repositorys;
+
+use UCore\DcatAdmin\Repository\EloquentRepository;
+
+class FundAdminRepository extends EloquentRepository
+{
+
+}

+ 31 - 0
app/Module/Game/Services/JsonConfigService.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Module\Game\Services;
+
+use App\Module\Game\Enums\JSON_CONFIG_NAME;
+use App\Module\Game\Events\TestEvent;
+use App\Module\Game\Exceptions\TestException;
+use App\Module\Game\Models\Test as TestModel;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Event;
+use Illuminate\Support\Facades\Validator;
+
+class JsonConfigService
+{
+
+    public static function getData(JSON_CONFIG_NAME $name)
+    {
+        $name = 'jsonconfig_' . $name->value;
+
+        return Cache::get($name);
+    }
+
+    public static function setData(JSON_CONFIG_NAME $name, $value)
+    {
+        $name = 'jsonconfig_' . $name->value;
+        Cache::set($name, $value);
+    }
+
+
+}

+ 167 - 0
app/Module/Game/Tests/TestEventTest.php

@@ -0,0 +1,167 @@
+<?php
+
+namespace App\Module\Game\Tests;
+
+use App\Module\Game\Events\TestEvent;
+use App\Module\Game\Models\Test;
+use App\Module\Game\Test as TestService;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
+use Illuminate\Support\Facades\Event;
+use Tests\TestCase;
+
+class TestEventTest extends TestCase
+{
+    use DatabaseTransactions;
+
+    protected TestService $service;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->service = new TestService();
+    }
+
+    /**
+     * 测试创建事件
+     */
+    public function test_created_event(): void
+    {
+        Event::fake();
+
+        // 创建测试数据
+        $test = $this->service->create([
+            'name' => '测试数据1',
+            'code' => 'TEST001',
+            'description' => '这是一个测试数据',
+            'data' => ['key' => 'value'],
+            'status' => 1
+        ]);
+
+        // 断言事件被触发
+        Event::assertDispatched(TestEvent::class, function ($event) use ($test) {
+            return $event->test->id === $test->id
+                && $event->type === 'created'
+                && $event->test->name === '测试数据1'
+                && $event->test->code === 'TEST001'
+                && $event->test->status === 1;
+        });
+    }
+
+    /**
+     * 测试更新事件
+     */
+    public function test_updated_event(): void
+    {
+        Event::fake();
+
+        // 创建测试数据
+        $test = $this->service->create([
+            'name' => '原始数据',
+            'code' => 'TEST002',
+            'status' => 1
+        ]);
+
+        // 更新数据
+        $this->service->update($test, [
+            'name' => '更新后的数据',
+            'status' => 2
+        ]);
+
+        // 断言事件被触发
+        Event::assertDispatched(TestEvent::class, function ($event) use ($test) {
+            return $event->test->id === $test->id
+                && $event->type === 'updated'
+                && $event->test->name === '更新后的数据'
+                && $event->test->status === 2;
+        });
+    }
+
+    /**
+     * 测试软删除事件
+     */
+    public function test_deleted_event(): void
+    {
+        Event::fake();
+
+        // 创建测试数据
+        $test = $this->service->create([
+            'name' => '待删除数据',
+            'code' => 'TEST003',
+            'status' => 1
+        ]);
+
+        // 软删除数据
+        $this->service->delete($test);
+
+        // 断言事件被触发
+        Event::assertDispatched(TestEvent::class, function ($event) use ($test) {
+            return $event->test->id === $test->id
+                && $event->type === 'deleted'
+                && $event->test->name === '待删除数据'
+                && $event->test->trashed();
+        });
+    }
+
+    /**
+     * 测试恢复事件
+     */
+    public function test_restored_event(): void
+    {
+        Event::fake();
+
+        // 创建并软删除测试数据
+        $test = $this->service->create([
+            'name' => '待恢复数据',
+            'code' => 'TEST004',
+            'status' => 1
+        ]);
+        $this->service->delete($test);
+
+        // 恢复数据
+        $this->service->restore($test);
+
+        // 断言事件被触发
+        Event::assertDispatched(TestEvent::class, function ($event) use ($test) {
+            return $event->test->id === $test->id
+                && $event->type === 'restored'
+                && $event->test->name === '待恢复数据'
+                && !$event->test->trashed();
+        });
+    }
+
+    /**
+     * 测试强制删除事件
+     */
+    public function test_force_deleted_event(): void
+    {
+        Event::fake();
+
+        // 创建测试数据
+        $test = $this->service->create([
+            'name' => '待强制删除数据',
+            'code' => 'TEST005',
+            'status' => 1
+        ]);
+
+        // 强制删除数据
+        $this->service->forceDelete($test);
+
+        // 断言事件被触发
+        Event::assertDispatched(TestEvent::class, function ($event) use ($test) {
+            return $event->test->id === $test->id
+                && $event->type === 'force_deleted'
+                && $event->test->name === '待强制删除数据';
+        });
+    }
+
+    /**
+     * 测试事件未被触发
+     */
+    public function test_event_not_dispatched(): void
+    {
+        Event::fake();
+
+        // 断言事件未被触发
+        Event::assertNotDispatched(TestEvent::class);
+    }
+}

+ 133 - 0
app/Module/Game/Tests/TestHookTest.php

@@ -0,0 +1,133 @@
+<?php
+
+namespace App\Module\Game\Tests;
+
+use App\Module\Game\Hooks\TestHook;
+use App\Module\Game\Models\Test;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
+use Tests\TestCase;
+
+class TestHookTest extends TestCase
+{
+    use DatabaseTransactions;
+
+    protected TestHook $hook;
+
+    public function setUp(): void
+    {
+        parent::setUp();
+        $this->hook = app(TestHook::class);
+    }
+
+    /**
+     * 测试创建并通知
+     *
+     * @return void
+     */
+    public function test_create_and_notify(): void
+    {
+        $data = [
+            'name' => '测试数据',
+            'code' => 'TEST001',
+            'description' => '测试描述'
+        ];
+
+        $result = $this->hook->createAndNotify($data);
+
+        $this->assertIsArray($result);
+        $this->assertEquals('测试数据创建成功', $result['title']);
+        $this->assertStringContainsString($data['name'], $result['content']);
+        $this->assertStringContainsString($data['code'], $result['content']);
+        $this->assertArrayHasKey('test_id', $result['data']);
+        $this->assertEquals($data['name'], $result['data']['name']);
+        $this->assertEquals($data['code'], $result['data']['code']);
+
+        // 验证数据是否真的创建了
+        $test = Test::find($result['data']['test_id']);
+        $this->assertNotNull($test);
+        $this->assertEquals($data['name'], $test->name);
+        $this->assertEquals($data['code'], $test->code);
+    }
+
+    /**
+     * 测试更新并通知
+     *
+     * @return void
+     */
+    public function test_update_and_notify(): void
+    {
+        // 创建测试数据
+        $test = Test::factory()->create();
+
+        $data = [
+            'name' => '更新数据',
+            'code' => 'TEST002'
+        ];
+
+        $result = $this->hook->updateAndNotify($test->id, $data);
+
+        $this->assertIsArray($result);
+        $this->assertEquals('测试数据更新成功', $result['title']);
+        $this->assertStringContainsString($data['name'], $result['content']);
+        $this->assertStringContainsString($data['code'], $result['content']);
+        $this->assertEquals($test->id, $result['data']['test_id']);
+        $this->assertEquals($data['name'], $result['data']['name']);
+        $this->assertEquals($data['code'], $result['data']['code']);
+
+        // 验证数据是否真的更新了
+        $test->refresh();
+        $this->assertEquals($data['name'], $test->name);
+        $this->assertEquals($data['code'], $test->code);
+    }
+
+    /**
+     * 测试更新不存在的数据
+     *
+     * @return void
+     */
+    public function test_update_non_existent(): void
+    {
+        $result = $this->hook->updateAndNotify(999, [
+            'name' => '更新数据',
+            'code' => 'TEST002'
+        ]);
+
+        $this->assertNull($result);
+    }
+
+    /**
+     * 测试删除并通知
+     *
+     * @return void
+     */
+    public function test_delete_and_notify(): void
+    {
+        // 创建测试数据
+        $test = Test::factory()->create();
+
+        $result = $this->hook->deleteAndNotify($test->id);
+
+        $this->assertIsArray($result);
+        $this->assertEquals('测试数据删除成功', $result['title']);
+        $this->assertStringContainsString($test->name, $result['content']);
+        $this->assertStringContainsString($test->code, $result['content']);
+        $this->assertEquals($test->id, $result['data']['test_id']);
+        $this->assertEquals($test->name, $result['data']['name']);
+        $this->assertEquals($test->code, $result['data']['code']);
+
+        // 验证数据是否真的删除了
+        $this->assertNull(Test::find($test->id));
+    }
+
+    /**
+     * 测试删除不存在的数据
+     *
+     * @return void
+     */
+    public function test_delete_non_existent(): void
+    {
+        $result = $this->hook->deleteAndNotify(999);
+
+        $this->assertNull($result);
+    }
+}

+ 83 - 0
app/Module/Game/Tests/TestSoftDeleteTest.php

@@ -0,0 +1,83 @@
+<?php
+
+namespace App\Module\Game\Tests;
+
+use App\Module\Game\Models\Test;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
+use Tests\TestCase;
+
+class TestSoftDeleteTest extends TestCase
+{
+    use DatabaseTransactions;
+
+    /**
+     * 测试软删除功能
+     */
+    public function test_soft_delete(): void
+    {
+        // 创建测试数据
+        $test = Test::factory()->create([
+            'name' => '测试数据1',
+            'description' => '这是一个测试数据'
+        ]);
+
+        // 验证数据存在
+        $this->assertDatabaseHas('tests', [
+            'id' => $test->id,
+            'name' => '测试数据1',
+            'description' => '这是一个测试数据'
+        ]);
+
+        // 软删除数据
+        $test->delete();
+
+        // 验证数据在正常查询中不可见
+        $this->assertDatabaseMissing('tests', [
+            'id' => $test->id,
+            'name' => '测试数据1',
+            'description' => '这是一个测试数据'
+        ]);
+
+        // 验证数据在软删除表中可见
+        $this->assertSoftDeleted('tests', [
+            'id' => $test->id,
+            'name' => '测试数据1',
+            'description' => '这是一个测试数据'
+        ]);
+
+        // 恢复数据
+        $test->restore();
+
+        // 验证数据恢复后可见
+        $this->assertDatabaseHas('tests', [
+            'id' => $test->id,
+            'name' => '测试数据1',
+            'description' => '这是一个测试数据'
+        ]);
+    }
+
+    /**
+     * 测试强制删除功能
+     */
+    public function test_force_delete(): void
+    {
+        // 创建测试数据
+        $test = Test::factory()->create([
+            'name' => '测试数据2',
+            'description' => '这是另一个测试数据'
+        ]);
+
+        // 软删除数据
+        $test->delete();
+
+        // 强制删除数据
+        $test->forceDelete();
+
+        // 验证数据完全删除
+        $this->assertDatabaseMissing('tests', [
+            'id' => $test->id,
+            'name' => '测试数据2',
+            'description' => '这是另一个测试数据'
+        ]);
+    }
+}

+ 92 - 0
app/Module/Game/Tests/TestTest.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace App\Module\Game\Tests;
+
+use App\Module\Game\Models\Test;
+use App\Module\Game\Services\TestService;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
+use Tests\TestCase;
+
+class TestTest extends TestCase
+{
+    use DatabaseTransactions;
+
+    protected TestService $service;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->service = app(TestService::class);
+    }
+
+    /**
+     * 测试创建数据
+     *
+     * @return void
+     */
+    public function test_create(): void
+    {
+        $data = [
+            'name' => '测试数据',
+            'code' => 'TEST001',
+            'description' => '测试描述'
+        ];
+
+        $test = $this->service->create($data);
+
+        $this->assertInstanceOf(Test::class, $test);
+        $this->assertEquals($data['name'], $test->name);
+        $this->assertEquals($data['code'], $test->code);
+        $this->assertEquals($data['description'], $test->description);
+    }
+
+    /**
+     * 测试获取数据
+     *
+     * @return void
+     */
+    public function test_get(): void
+    {
+        $test = Test::factory()->create();
+
+        $result = $this->service->get($test->id);
+
+        $this->assertInstanceOf(Test::class, $result);
+        $this->assertEquals($test->id, $result->id);
+    }
+
+    /**
+     * 测试更新数据
+     *
+     * @return void
+     */
+    public function test_update(): void
+    {
+        $test = Test::factory()->create();
+        $data = [
+            'name' => '更新数据',
+            'code' => 'TEST002'
+        ];
+
+        $result = $this->service->update($test->id, $data);
+
+        $this->assertTrue($result);
+        $this->assertEquals($data['name'], $test->fresh()->name);
+        $this->assertEquals($data['code'], $test->fresh()->code);
+    }
+
+    /**
+     * 测试删除数据
+     *
+     * @return void
+     */
+    public function test_delete(): void
+    {
+        $test = Test::factory()->create();
+
+        $result = $this->service->delete($test->id);
+
+        $this->assertTrue($result);
+        $this->assertNull(Test::find($test->id));
+    }
+}

+ 32 - 0
app/Module/Game/Validations/TestValidation.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Module\Game\Validations;
+
+use UCore\ValidationCore;
+
+
+/**
+ * Test请求 的 验证器
+ * TestValidation
+ *
+ */
+class TestValidation extends ValidationCore
+{
+
+    public function rules(array $rules = []): array
+    {
+        // times 是必填的
+        $rules[] = [
+            'times', 'required'
+        ];
+        $rules[] = [
+            'msg', 'required'
+        ];
+        $rules[] = [
+            'times', 'integer', 'min' => 10
+        ];
+
+        return parent::rules($rules); // TODO: Change the autogenerated stub
+    }
+
+}

+ 38 - 0
app/Module/Game/Validators/TestValidator.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Module\Game\Validators;
+
+use Inhere\Validate\Validation;
+use UCore\Validator;
+
+
+/**
+ * TestValidator
+ * Validator独立逻辑验证器,应区分与Validation的区别
+ *
+ */
+class TestValidator extends Validator
+{
+
+    /**
+     * 验证逻辑
+     * @param mixed $value
+     * @param array $data
+     * @return bool
+     */
+    public function validate(mixed $value, array $data): bool
+    {
+        if ($value > 3) {
+            // > 3
+            return false;
+        }
+        if ($value < -10) {
+            // < -10 增加一个错误消息
+            return $this->addError("这是一个极小的数字,不允许的!");
+        }
+
+        // 验证成功返回True
+        return true;
+    }
+
+}

+ 2 - 1
app/Module/GameItems/AdminControllers/ItemController.php

@@ -2,6 +2,7 @@
 
 namespace App\Module\GameItems\AdminControllers;
 
+use App\Module\Game\DCache\ItemJsonConfig;
 use App\Module\GameItems\Enums\ITEM_TYPE;
 use App\Module\GameItems\Models\ItemCategory;
 use App\Module\GameItems\Repositorys\ItemRepository;
@@ -26,7 +27,7 @@ class ItemController extends AdminController
     #[Get('game-items/generate-json')]
     public function generateJson()
     {
-        $success = \App\Module\GameItems\Commands\GenerateItemsJsonCommand::generateJson();
+        $success = ItemJsonConfig::getData([],true);
 
         return response()->json([
             'status' => $success ? 'success' : 'error',

+ 2 - 10
app/Module/GameItems/AdminControllers/Tools/RefreshCheckTool.php

@@ -2,6 +2,7 @@
 
 namespace App\Module\GameItems\AdminControllers\Tools;
 
+use App\Module\Game\DCache\ItemJsonConfig;
 use Dcat\Admin\Grid\Tools\AbstractTool;
 use Illuminate\Http\Request;
 
@@ -41,18 +42,9 @@ class RefreshCheckTool extends AbstractTool
 
     public static function checkSyncStatus(): array
     {
-        $jsonPath = public_path('json/items.json');
+        $json = ItemJsonConfig::getData([],false);
         $lastUpdated = \Carbon\Carbon::parse(\App\Module\GameItems\Models\Item::max('updated_at'));
 
-        if (!file_exists($jsonPath)) {
-            return [
-                'should_display' => true,
-                'message' => 'JSON文件不存在',
-                'is_synced' => false
-            ];
-        }
-
-        $json = json_decode(file_get_contents($jsonPath), true);
         $generatedAt = \Carbon\Carbon::parse($json['generated_at']);
         $isSynced = $generatedAt->gte($lastUpdated);
 

+ 23 - 28
app/Module/GameItems/Commands/GenerateItemsJsonCommand.php

@@ -2,6 +2,8 @@
 
 namespace App\Module\GameItems\Commands;
 
+use App\Module\Game\DCache\ItemJsonConfig;
+use App\Module\Game\Services\JsonConfigService;
 use Illuminate\Console\Command;
 use App\Module\GameItems\Models\Item;
 use Illuminate\Support\Facades\File;
@@ -9,6 +11,7 @@ use Illuminate\Support\Facades\Log;
 
 class GenerateItemsJsonCommand extends Command
 {
+
     /**
      * 命令名称和签名
      *
@@ -35,19 +38,19 @@ class GenerateItemsJsonCommand extends Command
             // 查询Item表中的数据
             $items = Item::query()
                 ->select([
-                    'id',
-                    'name',
-                    'description',
-                    'sell_price',
-                    'display_attributes'
-                ])
+                             'id',
+                             'name',
+                             'description',
+                             'sell_price',
+                             'display_attributes'
+                         ])
                 ->get()
                 ->map(function ($item) {
                     return [
-                        'id' => $item->id,
-                        'name' => $item->name,
-                        'description' => $item->description,
-                        'sell_price' => $item->sell_price,
+                        'id'                 => $item->id,
+                        'name'               => $item->name,
+                        'description'        => $item->description,
+                        'sell_price'         => $item->sell_price,
                         'display_attributes' => $item->display_attributes
                     ];
                 })
@@ -57,48 +60,40 @@ class GenerateItemsJsonCommand extends Command
             $directory = public_path('json');
             if (!File::exists($directory)) {
                 if (!File::makeDirectory($directory, 0755, true)) {
-                    Log::error('Failed to create directory: '.$directory);
+                    Log::error('Failed to create directory: ' . $directory);
+
                     return false;
                 }
             }
 
             // 检查目录是否可写
             if (!is_writable($directory)) {
-                Log::error('Directory is not writable: '.$directory);
+                Log::error('Directory is not writable: ' . $directory);
+
                 return false;
             }
 
             // 准备完整数据,包含生成时间
             $data = [
                 'generated_at' => now()->toDateTimeString(),
-                'items' => $items
+                'items'        => $items
             ];
 
-            // 写入JSON文件
-            $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
-            if (json_last_error() !== JSON_ERROR_NONE) {
-                Log::error('JSON encode error: '.json_last_error_msg());
-                return false;
-            }
-
-            if (!File::put($directory . '/items.json', $json)) {
-                Log::error('Failed to write JSON file');
-                return false;
-            }
-
-            return true;
+            return $data;
         } catch (\Exception $e) {
-            Log::error('Generate items.json failed: '.$e->getMessage());
+            Log::error('Generate items.json failed: ' . $e->getMessage());
+
             return false;
         }
     }
 
     public function handle()
     {
-        if (self::generateJson()) {
+        if (ItemJsonConfig::getData([], true)) {
             $this->info('Successfully generated items.json with timestamp');
         } else {
             $this->error('Failed to generate items.json');
         }
     }
+
 }

+ 54 - 0
app/Module/LCache/DQueueJob.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Module\LCache;
+
+
+use App\Module\DelayQueue\Redis;
+use UCore\Helper\Logger;
+
+abstract class DQueueJob  implements QueueJobInterface,DQueueJobInterface
+{
+    use QueueCache;
+
+
+    static public function getDelay(): int
+    {
+        return 2;
+    }
+
+    /**
+     * 事件监听
+     * @param  $user
+     *
+     */
+    static public function eventListen($user)
+    {
+        $arg2   = [];
+        $indexs = static::getRequiredArgIndex();
+        foreach ($indexs as $index) {
+            if (!isset($user->$index)) {
+                Logger::error("Cache-error", [ $user, $indexs, $index ]);
+                throw new \InvalidArgumentException("参数错误");
+            }
+            $arg2[$index] = $user->$index;
+        }
+
+        static::jobUpdate($arg2);
+    }
+
+    /**
+     * 使用任务更新
+     *
+     * @param $arg
+     * @return void
+     */
+    static protected function jobUpdate($parameter)
+    {
+
+        Redis::addQueue([static::class, 'updateSync'], $parameter, static::getDelay());
+
+    }
+
+
+
+}

+ 24 - 0
app/Module/LCache/DQueueJobInterface.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Module\LCache;
+
+interface DQueueJobInterface
+{
+
+
+
+
+    /**
+     * 获取延迟时间
+     *
+     * @return int
+     */
+    static public function getDelay(): int;
+
+
+
+
+
+
+
+}

+ 1 - 1
config/database.php

@@ -144,7 +144,7 @@ return [
 
         'options' => [
             'cluster' => env('REDIS_CLUSTER', 'redis'),
-            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
+            'prefix' => env('REDIS_PREFIX', 'kku_db_'),
         ],
 
         'default' => [

+ 160 - 18
public/json/items.json

@@ -1,5 +1,5 @@
 {
-    "generated_at": "2025-04-25 10:00:22",
+    "generated_at": "2025-04-25 14:06:08",
     "items": [
         {
             "id": 1,
@@ -15,119 +15,261 @@
             "name": "萝卜",
             "description": "萝卜",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 3,
             "name": "辣椒",
             "description": "辣椒",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 4,
             "name": "苹果",
             "description": "苹果",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 5,
             "name": "西瓜",
             "description": "西瓜",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 6,
             "name": "草莓",
             "description": "草莓",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 7,
             "name": "南瓜",
             "description": "南瓜",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 8,
             "name": "核桃",
             "description": "核桃",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 9,
             "name": "可可",
             "description": "可可",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 10,
             "name": "人参",
             "description": "人参",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 11,
             "name": "玫瑰",
             "description": "玫瑰",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 12,
             "name": "草莓种⼦",
             "description": "草莓种⼦",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 13,
             "name": "南⽠种⼦",
             "description": "南⽠种⼦",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 14,
             "name": "核桃种⼦",
             "description": "核桃种⼦",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 15,
             "name": "可可种⼦",
             "description": "可可种⼦",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 16,
             "name": "⼈参种⼦",
             "description": "⼈参种⼦",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 17,
             "name": "玫瑰种⼦",
             "description": "玫瑰种⼦",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
         },
         {
             "id": 18,
             "name": "测试",
             "description": "测试",
             "sell_price": 0,
-            "display_attributes": []
+            "display_attributes": {
+                "img": " "
+            }
+        },
+        {
+            "id": 19,
+            "name": "普通化肥",
+            "description": "普通化肥",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": "2"
+            }
+        },
+        {
+            "id": 20,
+            "name": "普通化肥 (复制)",
+            "description": "普通化肥",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": "2"
+            }
+        },
+        {
+            "id": 21,
+            "name": "高级化肥",
+            "description": "高级化肥",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": "2"
+            }
+        },
+        {
+            "id": 22,
+            "name": "除草剂",
+            "description": "除草剂",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": " "
+            }
+        },
+        {
+            "id": 23,
+            "name": "杀虫剂",
+            "description": "杀虫剂",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": "icon\/item\/4_7_png"
+            }
+        },
+        {
+            "id": 24,
+            "name": "洒水壶",
+            "description": "洒水壶",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": "11"
+            }
+        },
+        {
+            "id": 25,
+            "name": "银锄头",
+            "description": "银锄头",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": ""
+            }
+        },
+        {
+            "id": 26,
+            "name": "金锄头",
+            "description": "金锄头",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": ""
+            }
+        },
+        {
+            "id": 27,
+            "name": "铜宝箱",
+            "description": "铜宝箱",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": ""
+            }
+        },
+        {
+            "id": 28,
+            "name": "银宝箱",
+            "description": "银宝箱",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": ""
+            }
+        },
+        {
+            "id": 29,
+            "name": "金宝箱",
+            "description": "金宝箱",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": ""
+            }
+        },
+        {
+            "id": 30,
+            "name": "钻石宝箱",
+            "description": "钻石宝箱",
+            "sell_price": 0,
+            "display_attributes": {
+                "img": ""
+            }
         }
     ]
 }