Răsfoiți Sursa

签到配置

laowu 1 zi în urmă
părinte
comite
1cf168a467

+ 145 - 0
app/Http/Controllers/Admin/SignInRewardController.php

@@ -0,0 +1,145 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Http\Controllers\Controller;
+use App\Http\logic\admin\SignInRewardLogic;
+use App\Models\SignInRewardConfig;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Validator;
+
+/**
+ * 签到奖励配置控制器
+ */
+class SignInRewardController extends Controller
+{
+    /**
+     * @var SignInRewardLogic
+     */
+    protected $logic;
+
+    public function __construct()
+    {
+        $this->logic = new SignInRewardLogic();
+    }
+
+    /**
+     * 列表页面
+     *
+     * @param Request $request
+     * @return \Illuminate\View\View
+     */
+    public function listView(Request $request)
+    {
+        $list = $this->logic->getList(10);
+        return view('admin.sign_in_reward.list', [
+            'list' => $list,
+        ]);
+    }
+
+    /**
+     * 添加页面
+     *
+     * @return \Illuminate\View\View
+     */
+    public function addView()
+    {
+        return view('admin.sign_in_reward.add');
+    }
+
+    /**
+     * 处理添加请求
+     *
+     * @param Request $request
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function add(Request $request)
+    {
+        $data = $request->only(['DayNumber', 'RewardScore']);
+
+        // 验证输入
+        $validator = Validator::make($data, [
+            'DayNumber' => ['required', 'integer', 'min:1'],
+            'RewardScore' => ['required', 'integer', 'min:0'],
+        ], [
+            'DayNumber.required' => '签到天数不能为空',
+            'DayNumber.integer' => '签到天数必须是整数',
+            'DayNumber.min' => '签到天数必须大于 0',
+            'RewardScore.required' => '奖励积分不能为空',
+            'RewardScore.integer' => '奖励积分必须是整数',
+            'RewardScore.min' => '奖励积分不能为负数',
+        ]);
+
+        if ($validator->fails()) {
+            return $this->json(400, $validator->errors()->first());
+        }
+
+        // 使用 Logic 处理业务逻辑
+        if (!$this->logic->create($data)) {
+            return $this->json(400, $this->logic->getError());
+        }
+
+        return $this->json(200, '添加成功');
+    }
+
+    /**
+     * 更新页面
+     *
+     * @param int $dayNumber
+     * @return \Illuminate\View\View
+     */
+    public function updateView($dayNumber)
+    {
+        $config = SignInRewardConfig::findOrFail($dayNumber);
+        return view('admin.sign_in_reward.update', [
+            'config' => $config,
+        ]);
+    }
+
+    /**
+     * 处理更新请求
+     *
+     * @param Request $request
+     * @param int $dayNumber
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function update(Request $request, $dayNumber)
+    {
+        $data = $request->only(['RewardScore']);
+
+        // 验证输入
+        $validator = Validator::make($data, [
+            'RewardScore' => ['required', 'integer', 'min:0'],
+        ], [
+            'RewardScore.required' => '奖励积分不能为空',
+            'RewardScore.integer' => '奖励积分必须是整数',
+            'RewardScore.min' => '奖励积分不能为负数',
+        ]);
+
+        if ($validator->fails()) {
+            return $this->json(400, $validator->errors()->first());
+        }
+
+        // 使用 Logic 处理业务逻辑
+        if (!$this->logic->update($dayNumber, $data)) {
+            return $this->json(400, $this->logic->getError());
+        }
+
+        return $this->json(200, '修改成功');
+    }
+
+    /**
+     * 删除操作
+     *
+     * @param int $dayNumber
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function delete($dayNumber)
+    {
+        if (!$this->logic->delete($dayNumber)) {
+            return $this->json(400, $this->logic->getError());
+        }
+
+        return $this->json(200, '删除成功');
+    }
+}

+ 177 - 0
app/Http/logic/admin/SignInRewardLogic.php

@@ -0,0 +1,177 @@
+<?php
+
+namespace App\Http\logic\admin;
+
+use App\Models\SignInRewardConfig;
+
+/**
+ * 签到奖励配置业务逻辑类
+ *
+ * 负责签到奖励配置的增删改查操作
+ */
+class SignInRewardLogic
+{
+    /**
+     * 错误信息存储
+     *
+     * @var string
+     */
+    protected $error = '';
+
+    /**
+     * 获取错误信息
+     *
+     * @return string
+     */
+    public function getError()
+    {
+        return $this->error;
+    }
+
+    /**
+     * 设置错误信息
+     *
+     * @param string $error
+     * @return void
+     */
+    public function setError($error)
+    {
+        $this->error = $error;
+    }
+
+    /**
+     * 获取分页列表
+     *
+     * @param int $perPage
+     * @return \Illuminate\Pagination\Paginator
+     */
+    public function getList($perPage = 10)
+    {
+        return SignInRewardConfig::getPaginatedList($perPage);
+    }
+
+    /**
+     * 获取指定天数的奖励配置
+     *
+     * @param int $dayNumber
+     * @return SignInRewardConfig|null
+     */
+    public function getByDay($dayNumber)
+    {
+        return SignInRewardConfig::findByDay($dayNumber);
+    }
+
+    /**
+     * 创建新的签到奖励配置
+     *
+     * @param array $data 包含 DayNumber 和 RewardScore
+     * @return bool
+     */
+    public function create($data)
+    {
+        try {
+            // 验证数据
+            if (!$this->validateData($data)) {
+                return false;
+            }
+
+            // 检查是否已存在相同的 DayNumber
+            if (SignInRewardConfig::where('DayNumber', $data['DayNumber'])->exists()) {
+                $this->error = "第 {$data['DayNumber']} 天的配置已存在";
+                return false;
+            }
+
+            SignInRewardConfig::create([
+                'DayNumber' => (int) $data['DayNumber'],
+                'RewardScore' => (int) $data['RewardScore'],
+            ]);
+
+            return true;
+        } catch (\Exception $e) {
+            $this->error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * 更新签到奖励配置
+     *
+     * @param int $dayNumber
+     * @param array $data
+     * @return bool
+     */
+    public function update($dayNumber, $data)
+    {
+        try {
+            $config = SignInRewardConfig::findOrFail($dayNumber);
+
+            // 验证数据
+            if (!$this->validateData($data, true)) {
+                return false;
+            }
+
+            $config->update([
+                'RewardScore' => (int) $data['RewardScore'],
+            ]);
+
+            return true;
+        } catch (\Exception $e) {
+            $this->error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * 删除签到奖励配置
+     *
+     * @param int $dayNumber
+     * @return bool
+     */
+    public function delete($dayNumber)
+    {
+        try {
+            $config = SignInRewardConfig::findOrFail($dayNumber);
+            $config->delete();
+            return true;
+        } catch (\Exception $e) {
+            $this->error = $e->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * 验证数据有效性
+     *
+     * @param array $data
+     * @param bool $isUpdate 是否为更新操作(如果为 true,DayNumber 不是必需的)
+     * @return bool
+     */
+    protected function validateData($data, $isUpdate = false)
+    {
+        if (!$isUpdate) {
+            // 创建时,DayNumber 是必需的
+            if (!isset($data['DayNumber']) || $data['DayNumber'] === '') {
+                $this->error = "签到天数不能为空";
+                return false;
+            }
+
+            if (!is_numeric($data['DayNumber']) || (int) $data['DayNumber'] <= 0) {
+                $this->error = "签到天数必须是正整数";
+                return false;
+            }
+        }
+
+        // RewardScore 必需且必须是非负整数
+        if (!isset($data['RewardScore']) || $data['RewardScore'] === '') {
+            $this->error = "奖励积分不能为空";
+            return false;
+        }
+
+        if (!is_numeric($data['RewardScore']) || (int) $data['RewardScore'] < 0) {
+            $this->error = "奖励积分必须是非负整数";
+            return false;
+        }
+
+        return true;
+    }
+}

+ 59 - 0
app/Models/SignInRewardConfig.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 签到奖励配置模型
+ *
+ * @property int $DayNumber 签到第几天
+ * @property int $RewardScore 签到奖励积分
+ */
+class SignInRewardConfig extends Model
+{
+    // 使用 DayNumber 作为主键(代替自增的 id)
+    protected $primaryKey = 'DayNumber';
+    protected $keyType = 'int';
+    public $incrementing = false; // 禁用自增
+
+    // SQL Server 表名:三部分命名
+    protected $table = 'QPAccountsDB.dbo.SignInRewardConfig';
+
+    // 无时间戳字段(该表没有 created_at/updated_at)
+    public $timestamps = false;
+
+    // 可批量赋值的属性
+    protected $fillable = [
+        'DayNumber',
+        'RewardScore',
+    ];
+
+    // 字段转换
+    protected $casts = [
+        'DayNumber' => 'integer',
+        'RewardScore' => 'integer',
+    ];
+
+    /**
+     * 获取分页列表,按 DayNumber 排序
+     *
+     * @param int $perPage
+     * @return \Illuminate\Pagination\Paginator
+     */
+    public static function getPaginatedList($perPage = 10)
+    {
+        return self::orderBy('DayNumber', 'asc')->paginate($perPage);
+    }
+
+    /**
+     * 根据天数查找奖励
+     *
+     * @param int $dayNumber
+     * @return SignInRewardConfig|null
+     */
+    public static function findByDay($dayNumber)
+    {
+        return self::where('DayNumber', $dayNumber)->first();
+    }
+}

+ 55 - 0
resources/views/admin/sign_in_reward/add.blade.php

@@ -0,0 +1,55 @@
+@extends('base.base')
+@section('base')
+    <!-- 内容区域 -->
+    <div class="main-panel">
+        <div class="content-wrapper">
+            <div class="row">
+                <div class="col-12 grid-margin stretch-card">
+                    <div class="card">
+                        <div class="card-body">
+                            <h4 class="card-title">{{ __('auto.请填写签到奖励配置信息') }}</h4>
+                            <form class="forms-sample" id="form">
+                                <div class="form-group">
+                                    <label>* 签到天数</label>
+                                    <input type="number" class="form-control required" name="DayNumber" placeholder="请输入签到天数(例:1,2,3...)" min="1">
+                                    <small class="form-text text-muted">必填,正整数。例如:第 1 天、第 2 天等</small>
+                                </div>
+                                <div class="form-group">
+                                    <label>* 奖励积分</label>
+                                    <input type="number" class="form-control required" name="RewardScore" placeholder="请输入奖励积分" min="0">
+                                    <small class="form-text text-muted">必填,非负整数。例如:100 表示奖励 100 积分</small>
+                                </div>
+                                <button type="button" onclick="commit()" class="btn btn-sm btn-gradient-primary btn-icon-text">
+                                    <i class="mdi mdi-file-check btn-icon-prepend"></i>
+                                    {{ __('auto.提交') }}
+                                </button>
+                                <button type="button" onclick="cancel()" class="btn btn-sm btn-gradient-warning btn-icon-text">
+                                    <i class="mdi mdi-reload btn-icon-prepend"></i>
+                                    {{ __('auto.取消') }}
+                                </button>
+                            </form>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <script>
+        function commit(){
+            if(!checkForm()){
+                return false;
+            }
+            var data = $("#form").serializeObject();
+            myRequest("/admin/sign-in-reward/add", "post", data, function(res){
+                layer.msg(res.msg)
+                setTimeout(function(){
+                    parent.location.reload();
+                }, 1500)
+            });
+        }
+
+        function cancel() {
+            parent.location.reload();
+        }
+    </script>
+@endsection

+ 108 - 0
resources/views/admin/sign_in_reward/list.blade.php

@@ -0,0 +1,108 @@
+@extends('base.base')
+@section('base')
+    <!-- 内容区域 -->
+    <div class="main-panel">
+        <div class="content-wrapper">
+            <div class="page-header">
+                <h3 class="page-title">
+                    <span class="page-title-icon bg-gradient-primary text-white mr-2">
+                        <i class="mdi mdi-gift"></i>
+                    </span>
+                    {{ __('auto.签到奖励配置') }}
+                </h3>
+                <nav aria-label="breadcrumb">
+                    <ol class="breadcrumb">
+                        <li class="breadcrumb-item"><a href="#">{{ __('auto.签到管理') }}</a></li>
+                        <li class="breadcrumb-item active" aria-current="page">{{ __('auto.签到奖励配置') }}</li>
+                    </ol>
+                </nav>
+            </div>
+            <div class="row">
+                <div class="col-lg-12 grid-margin stretch-card">
+                    <div class="card">
+                        <div class="card-body">
+                            <h4 class="card-title">{{ __('auto.签到奖励配置列表') }}</h4>
+                            <div class="col-lg-9" style="float: left;padding: 0;">
+                                <button type="button" class="btn btn-sm btn-gradient-success btn-icon-text" onclick="add()">
+                                    <i class="mdi mdi-plus btn-icon-prepend"></i>
+                                    {{ __('auto.添加配置') }}
+                                </button>
+                            </div>
+                            <table class="table table-bordered">
+                                <thead>
+                                <tr>
+                                    <th width="20%">{{ __('auto.签到天数') }}</th>
+                                    <th width="20%">{{ __('auto.奖励积分') }}</th>
+                                    <th width="30%">{{ __('auto.操作') }}</th>
+                                </tr>
+                                </thead>
+                                <tbody>
+                                @forelse($list as $item)
+                                    <tr>
+                                        <td>第 {{ $item->DayNumber }} 天</td>
+                                        <td>{{ $item->RewardScore }}</td>
+                                        <td>
+                                            <button type="button" class="btn btn-sm btn-gradient-dark btn-icon-text" onclick="update({{ $item->DayNumber }})">
+                                                {{ __('auto.修改') }}
+                                                <i class="mdi mdi-file-check btn-icon-append"></i>
+                                            </button>
+                                            <button type="button" class="btn btn-sm btn-gradient-danger btn-icon-text" onclick="del({{ $item->DayNumber }})">
+                                                <i class="mdi mdi-delete btn-icon-prepend"></i>
+                                                {{ __('auto.删除') }}
+                                            </button>
+                                        </td>
+                                    </tr>
+                                @empty
+                                    <tr>
+                                        <td colspan="3" class="text-center">{{ __('auto.暂无数据') }}</td>
+                                    </tr>
+                                @endforelse
+                                </tbody>
+                            </table>
+                            <div class="box-footer clearfix">
+                                @if($list->total() > 0)
+                                    {{ __('auto.总共') }} <b>{{ $list->total() }}</b> {{ __('auto.条,分为') }}<b>{{ $list->lastPage() }}</b>{{ __('auto.页') }}
+                                    {!! $list->links() !!}
+                                @endif
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <script>
+        function add(){
+            var page = layer.open({
+                type: 2,
+                title: '{{ __('auto.添加签到奖励配置') }}',
+                shadeClose: true,
+                shade: 0.8,
+                area: ['50%', '70%'],
+                content: '/admin/sign-in-reward/add'
+            });
+        }
+
+        function update(dayNumber){
+            var page = layer.open({
+                type: 2,
+                title: '{{ __('auto.修改签到奖励配置') }}',
+                shadeClose: true,
+                shade: 0.8,
+                area: ['50%', '70%'],
+                content: '/admin/sign-in-reward/update/' + dayNumber
+            });
+        }
+
+        function del(dayNumber){
+            myConfirm("{{ __('auto.删除操作不可逆,是否继续') }}?",function(){
+                myRequest("/admin/sign-in-reward/delete/" + dayNumber, "post", {}, function(res){
+                    layer.msg(res.msg)
+                    setTimeout(function(){
+                        window.location.reload();
+                    }, 1500)
+                });
+            });
+        }
+    </script>
+@endsection

+ 55 - 0
resources/views/admin/sign_in_reward/update.blade.php

@@ -0,0 +1,55 @@
+@extends('base.base')
+@section('base')
+    <!-- 内容区域 -->
+    <div class="main-panel">
+        <div class="content-wrapper">
+            <div class="row">
+                <div class="col-12 grid-margin stretch-card">
+                    <div class="card">
+                        <div class="card-body">
+                            <h4 class="card-title">{{ __('auto.请修改签到奖励配置信息') }}</h4>
+                            <form class="forms-sample" id="form">
+                                <div class="form-group">
+                                    <label>签到天数</label>
+                                    <input type="text" class="form-control" value="第 {{ $config->DayNumber }} 天" disabled>
+                                    <small class="form-text text-muted">签到天数不可修改,只能删除后重新添加</small>
+                                </div>
+                                <div class="form-group">
+                                    <label>* 奖励积分</label>
+                                    <input type="number" class="form-control required" name="RewardScore" placeholder="请输入奖励积分" value="{{ $config->RewardScore }}" min="0">
+                                    <small class="form-text text-muted">必填,非负整数</small>
+                                </div>
+                                <button type="button" onclick="commit({{ $config->DayNumber }})" class="btn btn-sm btn-gradient-primary btn-icon-text">
+                                    <i class="mdi mdi-file-check btn-icon-prepend"></i>
+                                    {{ __('auto.提交') }}
+                                </button>
+                                <button type="button" onclick="cancel()" class="btn btn-sm btn-gradient-warning btn-icon-text">
+                                    <i class="mdi mdi-reload btn-icon-prepend"></i>
+                                    {{ __('auto.取消') }}
+                                </button>
+                            </form>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <script>
+        function commit(dayNumber){
+            if(!checkForm()){
+                return false;
+            }
+            var data = $("#form").serializeObject();
+            myRequest("/admin/sign-in-reward/update/" + dayNumber, "post", data, function(res){
+                layer.msg(res.msg)
+                setTimeout(function(){
+                    parent.location.reload();
+                }, 1500)
+            });
+        }
+
+        function cancel() {
+            parent.location.reload();
+        }
+    </script>
+@endsection

+ 9 - 0
routes/web.php

@@ -141,6 +141,15 @@ Route::group([
         $route->get('config/update/{id}', 'Admin\ConfigController@configUpdateView');
         $route->post('config/update/{id}', 'Admin\ConfigController@configUpdate');
         $route->post('config/del/{id}', 'Admin\ConfigController@configDel');
+        
+        // 签到奖励配置
+        $route->get('sign-in-reward/list', 'Admin\SignInRewardController@listView')->defaults('name', '签到奖励配置');
+        $route->get('sign-in-reward/add', 'Admin\SignInRewardController@addView');
+        $route->post('sign-in-reward/add', 'Admin\SignInRewardController@add');
+        $route->get('sign-in-reward/update/{dayNumber}', 'Admin\SignInRewardController@updateView');
+        $route->post('sign-in-reward/update/{dayNumber}', 'Admin\SignInRewardController@update');
+        $route->post('sign-in-reward/delete/{dayNumber}', 'Admin\SignInRewardController@delete');
+        
         //举报与反馈
         $route->get('/complaint/opinion', 'Admin\ComplaintController@opinionList');
         $route->get('/opinion/email/{id}', 'Admin\ComplaintController@emailView');

+ 301 - 0
tests/Feature/SignInRewardControllerTest.php

@@ -0,0 +1,301 @@
+<?php
+
+namespace Tests\Feature;
+
+use App\Models\SignInRewardConfig;
+use Tests\TestCase;
+
+/**
+ * 签到奖励配置控制器功能测试
+ *
+ * 测试 SignInRewardController 的 HTTP 端点
+ */
+class SignInRewardControllerTest extends TestCase
+{
+    /**
+     * 设置测试环境
+     */
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        // 清理测试数据
+        SignInRewardConfig::query()->delete();
+    }
+
+    /**
+     * 测试获取列表页面
+     *
+     * @return void
+     */
+    public function test_list_view_returns_success()
+    {
+        // 创建测试数据
+        SignInRewardConfig::create([
+            'DayNumber' => 1,
+            'RewardScore' => 100,
+        ]);
+
+        $response = $this->get('/admin/sign-in-reward/list');
+
+        $response->assertStatus(200);
+        $response->assertViewHas('list');
+    }
+
+    /**
+     * 测试获取添加页面
+     *
+     * @return void
+     */
+    public function test_add_view_returns_success()
+    {
+        $response = $this->get('/admin/sign-in-reward/add');
+
+        $response->assertStatus(200);
+    }
+
+    /**
+     * 测试成功添加奖励配置
+     *
+     * @return void
+     */
+    public function test_add_valid_config_returns_success()
+    {
+        $data = [
+            'DayNumber' => 1,
+            'RewardScore' => 100,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/add', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 200, 'msg' => '添加成功']);
+        $this->assertDatabaseHas('QPAccountsDB.dbo.SignInRewardConfig', $data);
+    }
+
+    /**
+     * 测试添加时缺少必要字段
+     *
+     * @return void
+     */
+    public function test_add_missing_day_number_returns_error()
+    {
+        $data = [
+            'RewardScore' => 100,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/add', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 400]);
+        $response->assertJsonFragment(['msg' => '签到天数不能为空']);
+    }
+
+    /**
+     * 测试添加时缺少奖励积分
+     *
+     * @return void
+     */
+    public function test_add_missing_reward_score_returns_error()
+    {
+        $data = [
+            'DayNumber' => 1,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/add', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 400]);
+        $response->assertJsonFragment(['msg' => '奖励积分不能为空']);
+    }
+
+    /**
+     * 测试添加时使用无效天数
+     *
+     * @return void
+     */
+    public function test_add_invalid_day_number_returns_error()
+    {
+        $data = [
+            'DayNumber' => -1,
+            'RewardScore' => 100,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/add', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 400]);
+    }
+
+    /**
+     * 测试添加时使用负数奖励积分
+     *
+     * @return void
+     */
+    public function test_add_negative_reward_score_returns_error()
+    {
+        $data = [
+            'DayNumber' => 1,
+            'RewardScore' => -100,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/add', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 400]);
+    }
+
+    /**
+     * 测试添加重复的天数配置
+     *
+     * @return void
+     */
+    public function test_add_duplicate_day_number_returns_error()
+    {
+        // 创建第一条记录
+        SignInRewardConfig::create([
+            'DayNumber' => 1,
+            'RewardScore' => 100,
+        ]);
+
+        // 尝试添加相同的天数
+        $data = [
+            'DayNumber' => 1,
+            'RewardScore' => 200,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/add', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 400]);
+        $response->assertJsonFragment(['msg' => '已存在']);
+    }
+
+    /**
+     * 测试获取更新页面
+     *
+     * @return void
+     */
+    public function test_update_view_returns_success()
+    {
+        // 创建测试数据
+        SignInRewardConfig::create([
+            'DayNumber' => 1,
+            'RewardScore' => 100,
+        ]);
+
+        $response = $this->get('/admin/sign-in-reward/update/1');
+
+        $response->assertStatus(200);
+        $response->assertViewHas('config');
+    }
+
+    /**
+     * 测试更新奖励配置
+     *
+     * @return void
+     */
+    public function test_update_valid_config_returns_success()
+    {
+        // 创建初始记录
+        SignInRewardConfig::create([
+            'DayNumber' => 2,
+            'RewardScore' => 200,
+        ]);
+
+        $data = [
+            'RewardScore' => 300,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/update/2', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 200, 'msg' => '修改成功']);
+        $this->assertDatabaseHas('QPAccountsDB.dbo.SignInRewardConfig', [
+            'DayNumber' => 2,
+            'RewardScore' => 300,
+        ]);
+    }
+
+    /**
+     * 测试更新时使用无效奖励积分
+     *
+     * @return void
+     */
+    public function test_update_invalid_reward_score_returns_error()
+    {
+        // 创建初始记录
+        SignInRewardConfig::create([
+            'DayNumber' => 2,
+            'RewardScore' => 200,
+        ]);
+
+        $data = [
+            'RewardScore' => -100,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/update/2', $data);
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 400]);
+    }
+
+    /**
+     * 测试更新不存在的记录
+     *
+     * @return void
+     */
+    public function test_update_nonexistent_record_returns_error()
+    {
+        $data = [
+            'RewardScore' => 300,
+        ];
+
+        $response = $this->post('/admin/sign-in-reward/update/999', $data);
+
+        $response->assertStatus(404);
+    }
+
+    /**
+     * 测试删除奖励配置
+     *
+     * @return void
+     */
+    public function test_delete_config_returns_success()
+    {
+        // 创建测试数据
+        SignInRewardConfig::create([
+            'DayNumber' => 3,
+            'RewardScore' => 300,
+        ]);
+
+        $response = $this->post('/admin/sign-in-reward/delete/3');
+
+        $response->assertStatus(200);
+        $response->assertJson(['code' => 200, 'msg' => '删除成功']);
+        $this->assertDatabaseMissing('QPAccountsDB.dbo.SignInRewardConfig', [
+            'DayNumber' => 3,
+        ]);
+    }
+
+    /**
+     * 测试删除不存在的记录
+     *
+     * @return void
+     */
+    public function test_delete_nonexistent_record_returns_error()
+    {
+        $response = $this->post('/admin/sign-in-reward/delete/999');
+
+        $response->assertStatus(404);
+    }
+
+    /**
+     * 清理测试数据
+     */
+    public function tearDown(): void
+    {
+        SignInRewardConfig::query()->delete();
+        parent::tearDown();
+    }
+}

+ 302 - 0
tests/Unit/SignInRewardLogicTest.php

@@ -0,0 +1,302 @@
+<?php
+
+namespace Tests\Unit;
+
+use App\Http\logic\admin\SignInRewardLogic;
+use App\Models\SignInRewardConfig;
+use Tests\TestCase;
+
+/**
+ * 签到奖励配置业务逻辑单元测试
+ *
+ * 测试 SignInRewardLogic 的 CRUD 操作
+ */
+class SignInRewardLogicTest extends TestCase
+{
+    /**
+     * @var SignInRewardLogic
+     */
+    protected $logic;
+
+    /**
+     * 设置测试环境
+     */
+    public function setUp(): void
+    {
+        parent::setUp();
+        $this->logic = new SignInRewardLogic();
+
+        // 清理测试数据
+        SignInRewardConfig::query()->delete();
+    }
+
+    /**
+     * 测试创建有效的签到奖励配置
+     *
+     * @return void
+     */
+    public function test_create_valid_reward_config()
+    {
+        $data = [
+            'DayNumber' => 1,
+            'RewardScore' => 100,
+        ];
+
+        $result = $this->logic->create($data);
+
+        $this->assertTrue($result);
+        $this->assertDatabaseHas('QPAccountsDB.dbo.SignInRewardConfig', $data);
+    }
+
+    /**
+     * 测试创建配置时缺少必要字段
+     *
+     * @return void
+     */
+    public function test_create_missing_day_number()
+    {
+        $data = [
+            'RewardScore' => 100,
+        ];
+
+        $result = $this->logic->create($data);
+
+        $this->assertFalse($result);
+        $this->assertStringContainsString('签到天数', $this->logic->getError());
+    }
+
+    /**
+     * 测试创建配置时奖励积分缺失
+     *
+     * @return void
+     */
+    public function test_create_missing_reward_score()
+    {
+        $data = [
+            'DayNumber' => 1,
+        ];
+
+        $result = $this->logic->create($data);
+
+        $this->assertFalse($result);
+        $this->assertStringContainsString('奖励积分', $this->logic->getError());
+    }
+
+    /**
+     * 测试创建配置时使用无效的天数(非正整数)
+     *
+     * @return void
+     */
+    public function test_create_invalid_day_number()
+    {
+        $data = [
+            'DayNumber' => -1,
+            'RewardScore' => 100,
+        ];
+
+        $result = $this->logic->create($data);
+
+        $this->assertFalse($result);
+        $this->assertStringContainsString('正整数', $this->logic->getError());
+    }
+
+    /**
+     * 测试创建配置时使用负数的奖励积分
+     *
+     * @return void
+     */
+    public function test_create_negative_reward_score()
+    {
+        $data = [
+            'DayNumber' => 1,
+            'RewardScore' => -100,
+        ];
+
+        $result = $this->logic->create($data);
+
+        $this->assertFalse($result);
+        $this->assertStringContainsString('非负整数', $this->logic->getError());
+    }
+
+    /**
+     * 测试创建重复的天数配置
+     *
+     * @return void
+     */
+    public function test_create_duplicate_day_number()
+    {
+        // 创建第一条记录
+        $data1 = [
+            'DayNumber' => 1,
+            'RewardScore' => 100,
+        ];
+        $this->logic->create($data1);
+
+        // 尝试创建相同的天数
+        $result = $this->logic->create($data1);
+
+        $this->assertFalse($result);
+        $this->assertStringContainsString('已存在', $this->logic->getError());
+    }
+
+    /**
+     * 测试获取列表
+     *
+     * @return void
+     */
+    public function test_get_list()
+    {
+        // 创建多条记录
+        for ($i = 1; $i <= 3; $i++) {
+            $data = [
+                'DayNumber' => $i,
+                'RewardScore' => $i * 100,
+            ];
+            $this->logic->create($data);
+        }
+
+        $list = $this->logic->getList(10);
+
+        $this->assertCount(3, $list);
+    }
+
+    /**
+     * 测试按天数查找奖励配置
+     *
+     * @return void
+     */
+    public function test_find_by_day()
+    {
+        $data = [
+            'DayNumber' => 5,
+            'RewardScore' => 500,
+        ];
+        $this->logic->create($data);
+
+        $config = $this->logic->getByDay(5);
+
+        $this->assertNotNull($config);
+        $this->assertEquals(5, $config->DayNumber);
+        $this->assertEquals(500, $config->RewardScore);
+    }
+
+    /**
+     * 测试查找不存在的天数
+     *
+     * @return void
+     */
+    public function test_find_by_day_not_found()
+    {
+        $config = $this->logic->getByDay(999);
+
+        $this->assertNull($config);
+    }
+
+    /**
+     * 测试更新奖励配置
+     *
+     * @return void
+     */
+    public function test_update_reward_config()
+    {
+        // 创建初始记录
+        $data = [
+            'DayNumber' => 2,
+            'RewardScore' => 200,
+        ];
+        $this->logic->create($data);
+
+        // 更新记录
+        $updateData = [
+            'RewardScore' => 300,
+        ];
+        $result = $this->logic->update(2, $updateData);
+
+        $this->assertTrue($result);
+        $this->assertDatabaseHas('QPAccountsDB.dbo.SignInRewardConfig', [
+            'DayNumber' => 2,
+            'RewardScore' => 300,
+        ]);
+    }
+
+    /**
+     * 测试更新时使用无效的奖励积分
+     *
+     * @return void
+     */
+    public function test_update_invalid_reward_score()
+    {
+        // 创建初始记录
+        $data = [
+            'DayNumber' => 2,
+            'RewardScore' => 200,
+        ];
+        $this->logic->create($data);
+
+        // 尝试使用无效的奖励积分更新
+        $updateData = [
+            'RewardScore' => 'invalid',
+        ];
+        $result = $this->logic->update(2, $updateData);
+
+        $this->assertFalse($result);
+    }
+
+    /**
+     * 测试更新不存在的记录
+     *
+     * @return void
+     */
+    public function test_update_nonexistent_record()
+    {
+        $updateData = [
+            'RewardScore' => 300,
+        ];
+
+        $this->expectException(\Illuminate\Database\Eloquent\ModelNotFoundException::class);
+        $this->logic->update(999, $updateData);
+    }
+
+    /**
+     * 测试删除奖励配置
+     *
+     * @return void
+     */
+    public function test_delete_reward_config()
+    {
+        // 创建初始记录
+        $data = [
+            'DayNumber' => 3,
+            'RewardScore' => 300,
+        ];
+        $this->logic->create($data);
+
+        // 删除记录
+        $result = $this->logic->delete(3);
+
+        $this->assertTrue($result);
+        $this->assertDatabaseMissing('QPAccountsDB.dbo.SignInRewardConfig', [
+            'DayNumber' => 3,
+        ]);
+    }
+
+    /**
+     * 测试删除不存在的记录
+     *
+     * @return void
+     */
+    public function test_delete_nonexistent_record()
+    {
+        $this->expectException(\Illuminate\Database\Eloquent\ModelNotFoundException::class);
+        $this->logic->delete(999);
+    }
+
+    /**
+     * 清理测试数据
+     */
+    public function tearDown(): void
+    {
+        SignInRewardConfig::query()->delete();
+        parent::tearDown();
+    }
+}