ソースを参照

优化后台创建时间/修改时间的展示

- 优化UCore GridHelper中的columnCreatedAt和columnUpdatedAt方法,使用统一的时间格式化
- 新增columnTimes组合时间列方法,将创建时间和更新时间组合显示
- 修复User和Game模块GridHelperTrait中的columnTimes方法签名冲突
- 统一使用'年-月-日 时:分:秒'格式显示所有时间字段
- 添加formatDateTime私有方法实现统一的时间格式化逻辑
- 支持时间戳、Carbon实例、DateTime对象、字符串等多种时间类型
- 空值显示为'-',自动添加sortable功能
- 更新测试用例验证优化后的功能
- 添加详细的使用示例文档
AI Assistant 6 ヶ月 前
コミット
2b59a32e93

+ 143 - 0
AiWork/2025年06月/21日2038-扩展UCore列表助手时间格式化方法.md

@@ -0,0 +1,143 @@
+# 扩展UCore列表助手时间格式化方法
+
+**任务时间**: 2025年06月21日 20:38  
+**任务类型**: 功能扩展  
+**模块**: UCore/DcatAdmin  
+
+## 任务概述
+
+在UCore的GridHelper类中新增`columnDateTime`助手方法,用于统一后台列表中的时间显示格式为"年-月-日 时:分:秒"。
+
+## 实现内容
+
+### 1. 新增方法
+- **位置**: `UCore/DcatAdmin/GridHelper.php`
+- **方法名**: `columnDateTime($field, $label = '')`
+- **功能**: 统一时间格式化为 `Y-m-d H:i:s` 格式
+
+### 2. 功能特性
+- **多类型支持**: 支持时间戳、Carbon实例、DateTime对象、字符串
+- **空值处理**: null或空字符串显示为 `-`
+- **零值处理**: 数字0作为有效时间戳处理
+- **错误容错**: 字符串转换失败时返回原值
+- **自动排序**: 自动添加sortable()功能
+
+### 3. 支持的输入类型
+```php
+// 时间戳
+1640995200 → 2022-01-01 08:00:00
+
+// Carbon实例
+Carbon::parse('2023-06-15 14:30:45') → 2023-06-15 14:30:45
+
+// DateTime对象
+new DateTime('2023-12-25 23:59:59') → 2023-12-25 23:59:59
+
+// 字符串
+'2023-07-20 10:15:30' → 2023-07-20 10:15:30
+
+// 空值
+null 或 '' → -
+
+// 零值
+0 → 1970-01-01 08:00:00
+```
+
+### 4. 使用示例
+```php
+protected function grid()
+{
+    $grid = $this->gridMake();
+    $helper = $this->gridHelper($grid);
+    
+    // 使用新的columnDateTime方法
+    $helper->columnDateTime('created_at', '创建时间');
+    $helper->columnDateTime('updated_at', '更新时间');
+    $helper->columnDateTime('login_time', '登录时间');
+    
+    return $grid;
+}
+```
+
+## 测试验证
+
+### 1. 单元测试
+- **文件**: `tests/Unit/UCore/GridHelperDateTimeTest.php`
+- **测试用例**: 7个断言,覆盖所有输入类型
+- **测试结果**: ✅ 全部通过
+
+### 2. 测试运行
+```bash
+vendor/bin/phpunit tests/Unit/UCore/GridHelperDateTimeTest.php
+# OK (1 test, 7 assertions)
+```
+
+## 文档
+
+### 1. 使用文档
+- **文件**: `docs/GridHelper-columnDateTime使用示例.md`
+- **内容**: 详细的使用示例、功能特性、注意事项
+
+### 2. 文档结构
+- 方法签名和功能特性
+- 支持的输入类型详解
+- 基本用法和组合使用示例
+- 与现有方法的对比
+- 优势和注意事项
+
+## 代码提交
+
+### 1. Git提交
+```bash
+git add .
+git commit -m "新增UCore GridHelper columnDateTime方法
+
+- 在UCore/DcatAdmin/GridHelper.php中新增columnDateTime方法
+- 统一后台列表时间格式为'年-月-日 时:分:秒'格式
+- 支持时间戳、Carbon实例、DateTime对象、字符串等多种时间类型
+- 自动处理空值显示为'-',添加sortable功能
+- 包含完整的单元测试验证各种输入类型
+- 添加详细的使用示例文档"
+
+git push
+```
+
+### 2. 提交内容
+- 修改: `UCore/DcatAdmin/GridHelper.php`
+- 新增: `tests/Unit/UCore/GridHelperDateTimeTest.php`
+- 新增: `docs/GridHelper-columnDateTime使用示例.md`
+
+## 技术要点
+
+### 1. 空值处理逻辑
+```php
+// 检查空值(但不包括0,因为0是有效的时间戳)
+if (is_null($value) || $value === '') {
+    return '-';
+}
+```
+
+### 2. 多类型兼容
+- 数值类型: 直接使用date()函数
+- 对象类型: 调用format()方法
+- 字符串类型: 先转换为DateTime再格式化
+- 异常处理: 转换失败时返回原值
+
+### 3. 自动功能
+- 自动添加sortable()支持列排序
+- 自动处理时区转换
+
+## 影响范围
+
+### 1. 向后兼容
+- 不影响现有代码
+- 新增方法,不修改现有方法
+
+### 2. 使用建议
+- 推荐在新的后台控制器中使用
+- 可逐步替换手动时间格式化代码
+- 统一项目中的时间显示格式
+
+## 总结
+
+成功扩展了UCore的GridHelper类,新增了`columnDateTime`方法,实现了后台列表时间格式的统一化。该方法具有良好的类型兼容性、错误处理能力和易用性,通过了完整的单元测试验证,并提供了详细的使用文档。

+ 76 - 32
UCore/DcatAdmin/GridHelper.php

@@ -51,22 +51,91 @@ class GridHelper
     }
 
     /**
-     * 创建时间
+     * 创建时间 - 使用统一的时间格式
      *
+     * @param string $field 字段名,默认为created_at
+     * @param string $label 标签名,默认为创建时间
      * @return Grid\Column
      */
-    public function columnCreatedAt()
+    public function columnCreatedAt($field = 'created_at', $label = '创建时间')
     {
-        return $this->grid->column('created_at', '创建时间')->sortable();
+        return $this->columnDateTime($field, $label);
     }
 
     /**
-     * 更新时间
+     * 更新时间 - 使用统一的时间格式
+     *
+     * @param string $field 字段名,默认为updated_at
+     * @param string $label 标签名,默认为更新时间
      * @return Grid\Column
      */
-    public function columnUpdatedAt()
+    public function columnUpdatedAt($field = 'updated_at', $label = '更新时间')
     {
-        return $this->grid->column('updated_at', '更新时间')->sortable();
+        return $this->columnDateTime($field, $label);
+    }
+
+    /**
+     * 时间信息组合列 - 将创建时间和更新时间组合显示
+     *
+     * @param string $createdAtField 创建时间字段名,默认为created_at
+     * @param string $updatedAtField 更新时间字段名,默认为updated_at
+     * @param string $label 标签名,默认为时间信息
+     * @return Grid\Column
+     */
+    public function columnTimes($createdAtField = 'created_at', $updatedAtField = 'updated_at', $label = '时间信息')
+    {
+        return $this->grid->column($createdAtField, $label)->display(function ($createdAt) use ($updatedAtField) {
+            $updatedAt = $this->{$updatedAtField} ?? '';
+
+            // 格式化创建时间
+            $createdAtFormatted = $this->formatDateTime($createdAt);
+            $createdAtHtml = "<div><small class='text-muted'>创建:</small> {$createdAtFormatted}</div>";
+
+            // 格式化更新时间
+            $updatedAtHtml = '';
+            if ($updatedAt) {
+                $updatedAtFormatted = $this->formatDateTime($updatedAt);
+                $updatedAtHtml = "<div><small class='text-muted'>更新:</small> {$updatedAtFormatted}</div>";
+            }
+
+            return $createdAtHtml . $updatedAtHtml;
+        })->sortable();
+    }
+
+    /**
+     * 格式化时间的私有方法
+     *
+     * @param mixed $value 时间值
+     * @return string 格式化后的时间字符串
+     */
+    private function formatDateTime($value)
+    {
+        // 检查空值(但不包括0,因为0是有效的时间戳)
+        if (is_null($value) || $value === '') {
+            return '-';
+        }
+
+        // 如果是时间戳,转换为日期时间字符串
+        if (is_numeric($value)) {
+            return date('Y-m-d H:i:s', $value);
+        }
+
+        // 如果是Carbon实例或DateTime对象
+        if ($value instanceof \Carbon\Carbon || $value instanceof \DateTime) {
+            return $value->format('Y-m-d H:i:s');
+        }
+
+        // 如果是字符串,尝试转换为标准格式
+        if (is_string($value)) {
+            try {
+                $date = new \DateTime($value);
+                return $date->format('Y-m-d H:i:s');
+            } catch (\Exception $e) {
+                return $value; // 如果转换失败,返回原值
+            }
+        }
+
+        return $value;
     }
 
 
@@ -209,32 +278,7 @@ class GridHelper
     public function columnDateTime($field, $label = '')
     {
         return $this->grid->column($field, $label)->display(function ($value) {
-            // 检查空值(但不包括0,因为0是有效的时间戳)
-            if (is_null($value) || $value === '') {
-                return '-';
-            }
-
-            // 如果是时间戳,转换为日期时间字符串
-            if (is_numeric($value)) {
-                return date('Y-m-d H:i:s', $value);
-            }
-
-            // 如果是Carbon实例或DateTime对象
-            if ($value instanceof \Carbon\Carbon || $value instanceof \DateTime) {
-                return $value->format('Y-m-d H:i:s');
-            }
-
-            // 如果是字符串,尝试转换为标准格式
-            if (is_string($value)) {
-                try {
-                    $date = new \DateTime($value);
-                    return $date->format('Y-m-d H:i:s');
-                } catch (\Exception $e) {
-                    return $value; // 如果转换失败,返回原值
-                }
-            }
-
-            return $value;
+            return $this->formatDateTime($value);
         })->sortable();
     }
 

+ 48 - 5
app/Module/Game/AdminControllers/Helper/GridHelperTrait.php

@@ -107,7 +107,7 @@ trait GridHelperTrait
     }
 
     /**
-     * 添加时间信息组合列
+     * 添加时间信息组合列 - 使用统一的时间格式化
      *
      * 复用价值:高 - 将创建时间和更新时间组合显示,提高信息密度
      *
@@ -116,16 +116,59 @@ trait GridHelperTrait
      * @param string $label 标签名
      * @return Column
      */
-    public function columnTimes(string $createdAtField = 'created_at', string $updatedAtField = 'updated_at', string $label = '时间信息'): Column
+    public function columnTimes($createdAtField = 'created_at', $updatedAtField = 'updated_at', $label = '时间信息'): Column
     {
         return $this->grid->column($createdAtField, $label)->display(function ($createdAt) use ($updatedAtField) {
             $updatedAt = $this->{$updatedAtField} ?? '';
 
-            $createdAtHtml = "<div>创建: {$createdAt}</div>";
-            $updatedAtHtml = $updatedAt ? "<div>更新: {$updatedAt}</div>" : '';
+            // 使用静态方法进行时间格式化
+            $createdAtFormatted = self::formatDateTimeStatic($createdAt);
+            $createdAtHtml = "<div><small class='text-muted'>创建:</small> {$createdAtFormatted}</div>";
+
+            $updatedAtHtml = '';
+            if ($updatedAt) {
+                $updatedAtFormatted = self::formatDateTimeStatic($updatedAt);
+                $updatedAtHtml = "<div><small class='text-muted'>更新:</small> {$updatedAtFormatted}</div>";
+            }
 
             return $createdAtHtml . $updatedAtHtml;
-        });
+        })->sortable();
+    }
+
+    /**
+     * 格式化时间的静态方法
+     *
+     * @param mixed $value 时间值
+     * @return string 格式化后的时间字符串
+     */
+    private static function formatDateTimeStatic($value)
+    {
+        // 检查空值(但不包括0,因为0是有效的时间戳)
+        if (is_null($value) || $value === '') {
+            return '-';
+        }
+
+        // 如果是时间戳,转换为日期时间字符串
+        if (is_numeric($value)) {
+            return date('Y-m-d H:i:s', $value);
+        }
+
+        // 如果是Carbon实例或DateTime对象
+        if ($value instanceof \Carbon\Carbon || $value instanceof \DateTime) {
+            return $value->format('Y-m-d H:i:s');
+        }
+
+        // 如果是字符串,尝试转换为标准格式
+        if (is_string($value)) {
+            try {
+                $date = new \DateTime($value);
+                return $date->format('Y-m-d H:i:s');
+            } catch (\Exception $e) {
+                return $value; // 如果转换失败,返回原值
+            }
+        }
+
+        return $value;
     }
 
     /**

+ 48 - 5
app/Module/User/AdminControllers/Helper/GridHelperTrait.php

@@ -116,7 +116,7 @@ trait GridHelperTrait
     }
 
     /**
-     * 添加时间信息组合列
+     * 添加时间信息组合列 - 使用统一的时间格式化
      *
      * 复用价值:高 - 将创建时间和更新时间组合显示,提高信息密度
      *
@@ -125,16 +125,59 @@ trait GridHelperTrait
      * @param string $label 标签名
      * @return Column
      */
-    public function columnTimes(string $createdAtField = 'created_at', string $updatedAtField = 'updated_at', string $label = '时间信息'): Column
+    public function columnTimes($createdAtField = 'created_at', $updatedAtField = 'updated_at', $label = '时间信息'): Column
     {
         return $this->grid->column($createdAtField, $label)->display(function ($createdAt) use ($updatedAtField) {
             $updatedAt = $this->{$updatedAtField} ?? '';
 
-            $createdAtHtml = "<div>创建: {$createdAt}</div>";
-            $updatedAtHtml = $updatedAt ? "<div>更新: {$updatedAt}</div>" : '';
+            // 使用静态方法进行时间格式化
+            $createdAtFormatted = self::formatDateTimeStatic($createdAt);
+            $createdAtHtml = "<div><small class='text-muted'>创建:</small> {$createdAtFormatted}</div>";
+
+            $updatedAtHtml = '';
+            if ($updatedAt) {
+                $updatedAtFormatted = self::formatDateTimeStatic($updatedAt);
+                $updatedAtHtml = "<div><small class='text-muted'>更新:</small> {$updatedAtFormatted}</div>";
+            }
 
             return $createdAtHtml . $updatedAtHtml;
-        });
+        })->sortable();
+    }
+
+    /**
+     * 格式化时间的静态方法
+     *
+     * @param mixed $value 时间值
+     * @return string 格式化后的时间字符串
+     */
+    private static function formatDateTimeStatic($value)
+    {
+        // 检查空值(但不包括0,因为0是有效的时间戳)
+        if (is_null($value) || $value === '') {
+            return '-';
+        }
+
+        // 如果是时间戳,转换为日期时间字符串
+        if (is_numeric($value)) {
+            return date('Y-m-d H:i:s', $value);
+        }
+
+        // 如果是Carbon实例或DateTime对象
+        if ($value instanceof \Carbon\Carbon || $value instanceof \DateTime) {
+            return $value->format('Y-m-d H:i:s');
+        }
+
+        // 如果是字符串,尝试转换为标准格式
+        if (is_string($value)) {
+            try {
+                $date = new \DateTime($value);
+                return $date->format('Y-m-d H:i:s');
+            } catch (\Exception $e) {
+                return $value; // 如果转换失败,返回原值
+            }
+        }
+
+        return $value;
     }
 
     /**

+ 259 - 0
docs/后台时间显示优化示例.md

@@ -0,0 +1,259 @@
+# 后台时间显示优化示例
+
+## 概述
+
+优化了UCore GridHelper中的创建时间/修改时间展示,统一使用"年-月-日 时:分:秒"格式,并新增了组合时间列功能。
+
+## 优化内容
+
+### 1. 优化现有方法
+
+#### columnCreatedAt() 方法优化
+```php
+// 优化前
+public function columnCreatedAt()
+{
+    return $this->grid->column('created_at', '创建时间')->sortable();
+}
+
+// 优化后
+public function columnCreatedAt($field = 'created_at', $label = '创建时间')
+{
+    return $this->columnDateTime($field, $label);
+}
+```
+
+#### columnUpdatedAt() 方法优化
+```php
+// 优化前
+public function columnUpdatedAt()
+{
+    return $this->grid->column('updated_at', '更新时间')->sortable();
+}
+
+// 优化后
+public function columnUpdatedAt($field = 'updated_at', $label = '更新时间')
+{
+    return $this->columnDateTime($field, $label);
+}
+```
+
+### 2. 新增组合时间列
+
+#### columnTimes() 方法
+```php
+public function columnTimes($createdAtField = 'created_at', $updatedAtField = 'updated_at', $label = '时间信息')
+{
+    return $this->grid->column($createdAtField, $label)->display(function ($createdAt) use ($updatedAtField) {
+        $updatedAt = $this->{$updatedAtField} ?? '';
+        
+        // 格式化创建时间
+        $createdAtFormatted = $this->formatDateTime($createdAt);
+        $createdAtHtml = "<div><small class='text-muted'>创建:</small> {$createdAtFormatted}</div>";
+        
+        // 格式化更新时间
+        $updatedAtHtml = '';
+        if ($updatedAt) {
+            $updatedAtFormatted = $this->formatDateTime($updatedAt);
+            $updatedAtHtml = "<div><small class='text-muted'>更新:</small> {$updatedAtFormatted}</div>";
+        }
+        
+        return $createdAtHtml . $updatedAtHtml;
+    })->sortable();
+}
+```
+
+### 3. 统一格式化方法
+
+#### formatDateTime() 私有方法
+```php
+private function formatDateTime($value)
+{
+    // 检查空值(但不包括0,因为0是有效的时间戳)
+    if (is_null($value) || $value === '') {
+        return '-';
+    }
+    
+    // 如果是时间戳,转换为日期时间字符串
+    if (is_numeric($value)) {
+        return date('Y-m-d H:i:s', $value);
+    }
+    
+    // 如果是Carbon实例或DateTime对象
+    if ($value instanceof \Carbon\Carbon || $value instanceof \DateTime) {
+        return $value->format('Y-m-d H:i:s');
+    }
+    
+    // 如果是字符串,尝试转换为标准格式
+    if (is_string($value)) {
+        try {
+            $date = new \DateTime($value);
+            return $date->format('Y-m-d H:i:s');
+        } catch (\Exception $e) {
+            return $value; // 如果转换失败,返回原值
+        }
+    }
+    
+    return $value;
+}
+```
+
+## 使用示例
+
+### 1. 基本用法(向后兼容)
+
+```php
+<?php
+
+namespace App\Module\Example\AdminControllers;
+
+use UCore\DcatAdmin\AdminController;
+
+class ExampleController extends AdminController
+{
+    protected function grid()
+    {
+        $grid = $this->gridMake();
+        $helper = $this->gridHelper($grid);
+        
+        // 现有代码无需修改,自动使用新的格式化
+        $helper->columnCreatedAt();  // 自动格式化为 Y-m-d H:i:s
+        $helper->columnUpdatedAt();  // 自动格式化为 Y-m-d H:i:s
+        
+        return $grid;
+    }
+}
+```
+
+### 2. 自定义字段名
+
+```php
+protected function grid()
+{
+    $grid = $this->gridMake();
+    $helper = $this->gridHelper($grid);
+    
+    // 使用自定义字段名和标签
+    $helper->columnCreatedAt('register_time', '注册时间');
+    $helper->columnUpdatedAt('last_login_time', '最后登录');
+    
+    return $grid;
+}
+```
+
+### 3. 组合时间列
+
+```php
+protected function grid()
+{
+    $grid = $this->gridMake();
+    $helper = $this->gridHelper($grid);
+    
+    // 基本ID列
+    $helper->columnId();
+    
+    // 业务字段
+    $grid->column('username', '用户名');
+    $grid->column('email', '邮箱');
+    
+    // 使用组合时间列,节省空间
+    $helper->columnTimes(); // 默认使用 created_at 和 updated_at
+    
+    // 或者自定义字段
+    $helper->columnTimes('start_time', 'end_time', '活动时间');
+    
+    return $grid;
+}
+```
+
+### 4. 混合使用
+
+```php
+protected function grid()
+{
+    $grid = $this->gridMake();
+    $helper = $this->gridHelper($grid);
+    
+    $helper->columnId();
+    $grid->column('title', '标题');
+    
+    // 重要的时间字段单独显示
+    $helper->columnCreatedAt();
+    
+    // 其他时间字段组合显示
+    $helper->columnTimes('published_at', 'expired_at', '发布时间');
+    
+    return $grid;
+}
+```
+
+## 显示效果
+
+### 1. 单独时间列
+```
+创建时间: 2023-12-25 14:30:45
+更新时间: 2023-12-26 09:15:30
+```
+
+### 2. 组合时间列
+```
+时间信息:
+创建: 2023-12-25 14:30:45
+更新: 2023-12-26 09:15:30
+```
+
+## 优势
+
+### 1. 向后兼容
+- 现有代码无需修改
+- 自动应用新的格式化规则
+
+### 2. 统一格式
+- 所有时间字段使用相同的 `Y-m-d H:i:s` 格式
+- 消除了格式不一致的问题
+
+### 3. 灵活性
+- 支持自定义字段名和标签
+- 提供组合显示选项
+
+### 4. 空间优化
+- 组合时间列可以节省列表空间
+- 适合字段较多的管理页面
+
+### 5. 代码复用
+- 统一的格式化逻辑
+- 减少重复代码
+
+## 注意事项
+
+1. **时区处理**: 时间戳会根据服务器时区进行转换
+2. **空值显示**: null或空字符串显示为 `-`
+3. **排序功能**: 所有时间列都自动支持排序
+4. **错误处理**: 格式转换失败时返回原始值
+5. **性能**: 格式化在前端显示时进行,不影响数据库查询
+
+## 测试验证
+
+项目中包含了完整的单元测试,验证了优化后方法的正确性:
+
+```bash
+vendor/bin/phpunit tests/Unit/UCore/GridHelperDateTimeTest.php
+# OK (2 tests, 13 assertions)
+```
+
+## 迁移建议
+
+### 立即生效
+现有使用 `columnCreatedAt()` 和 `columnUpdatedAt()` 的代码会自动使用新的格式化,无需修改。
+
+### 推荐优化
+对于字段较多的列表页面,建议使用 `columnTimes()` 组合显示来节省空间:
+
+```php
+// 推荐:使用组合时间列
+$helper->columnTimes();
+
+// 而不是:
+$helper->columnCreatedAt();
+$helper->columnUpdatedAt();
+```

+ 32 - 0
tests/Unit/UCore/GridHelperDateTimeTest.php

@@ -36,6 +36,38 @@ class GridHelperDateTimeTest extends TestCase
                 "输入 {$inputStr} 应该输出 {$case['expected']},实际输出 {$result}");
         }
     }
+
+    /**
+     * 测试优化后的columnCreatedAt和columnUpdatedAt方法
+     */
+    public function testOptimizedCreatedAtAndUpdatedAt()
+    {
+        // 测试创建时间格式化
+        $createdAtTestCases = [
+            ['input' => '2023-01-01 12:00:00', 'expected' => '2023-01-01 12:00:00'],
+            ['input' => 1672574400, 'expected' => date('Y-m-d H:i:s', 1672574400)],
+            ['input' => null, 'expected' => '-'],
+        ];
+
+        foreach ($createdAtTestCases as $case) {
+            $result = $this->simulateColumnDateTimeDisplay($case['input']);
+            $this->assertEquals($case['expected'], $result,
+                "columnCreatedAt 输入 {$case['input']} 应该输出 {$case['expected']},实际输出 {$result}");
+        }
+
+        // 测试更新时间格式化
+        $updatedAtTestCases = [
+            ['input' => '2023-12-31 23:59:59', 'expected' => '2023-12-31 23:59:59'],
+            ['input' => 1704067199, 'expected' => date('Y-m-d H:i:s', 1704067199)],
+            ['input' => '', 'expected' => '-'],
+        ];
+
+        foreach ($updatedAtTestCases as $case) {
+            $result = $this->simulateColumnDateTimeDisplay($case['input']);
+            $this->assertEquals($case['expected'], $result,
+                "columnUpdatedAt 输入 {$case['input']} 应该输出 {$case['expected']},实际输出 {$result}");
+        }
+    }
     
     /**
      * 模拟columnDateTime的display回调函数