Browse Source

fix:订单冗余规格字段

super-yimizi 2 months ago
parent
commit
a6fb28d132

+ 21 - 10
application/admin/controller/shop/Goods.php

@@ -295,6 +295,7 @@ class Goods extends Backend
         $newSkuData = [
             'goods_id'       => $goods_id,
             'spec_value_ids' => '', // 单规格无规格值ID
+            'sku_attr'       => '', // 单规格无规格属性
             'sku_sn'         => $skuData['sku_sn'] ?? '',
             'image'          => $skuData['image'] ?? '',
             'price'          => $skuData['price'] ?? 0,
@@ -349,10 +350,27 @@ class Goods extends Backend
         $stocks = 0;
         foreach ($skus as $k => $sk) {
             $newSkuId = $this->getSkuId($sk['skus'], $newSpec, $spec);
+            
+            // 生成规格属性JSON,格式:[{"name":"规格名","value":"规格值"}]
+            $skuAttr = '';
+            if (!empty($sk['skus'])) {
+                $attrArray = [];
+                foreach ($sk['skus'] as $index => $value) {
+                    if (isset($spec[$index]['name']) && !empty($value)) {
+                        $attrArray[] = [
+                            'name' => $spec[$index]['name'],
+                            'value' => $value
+                        ];
+                    }
+                }
+                $skuAttr = !empty($attrArray) ? json_encode($attrArray, JSON_UNESCAPED_UNICODE) : '';
+            }
+            
             $newSkuData = [
                 'goods_id'     => $goods_id,
                 'spec_value_ids' => $newSkuId,
-                'sku_sn'       => $sk['goods_sn'] ?? '',
+                'sku_attr'     => $skuAttr, // 冗余存储规格信息
+                'sku_sn'       => $sk['sku_sn'] ?? '',
                 'image'        => $sk['image'] ?? '',
                 'price'        => $sk['price'] ?? 0,
                 'lineation_price' => $sk['lineation_price'] ?? 0,
@@ -666,15 +684,8 @@ class Goods extends Backend
         }
             
         
-        // 查询SKU数据,包含规格属性字符串
-        $list = $this->sku_model->field("sku.*,GROUP_CONCAT(sp.name,':',sv.value ORDER BY sp.id asc) sku_attr")
-        ->alias('sku')
-        ->where('sku.goods_id', $row->id)
-        ->join('shop_goods_sku_spec p', "FIND_IN_SET(p.id,sku.spec_value_ids)", 'LEFT')
-        ->join('shop_spec sp', 'sp.id=p.spec_id', 'LEFT')
-        ->join('shop_spec_value sv', 'sv.id=p.spec_value_id', 'LEFT')
-        ->group('sku.id')
-        ->select();
+        // 简化查询SKU数据,直接使用冗余的 sku_attr 字段
+        $list = $this->sku_model->where('goods_id', $row->id)->select();
         
         // 查询规格值的详细信息(包含图片等扩展字段)
         $spec_values = [];

+ 2 - 0
application/common/Service/OrderService.php

@@ -189,6 +189,8 @@ class OrderService
                 'sku_sn'               => $item->sku->sku_sn ?: '', // SKU编号
                 'goods_type'           => $item->goods->type ?: 0, // 商品类型
                 'goods_id'             => $item->goods->id,
+                'goods_sku_attr'       => $item->sku->sku_attr,
+                'goods_spec_value_ids' => $item->sku->spec_value_ids,
                 'goods_sku_id'         => $item->sku->id,
                 'goods_title'          => $item->goods->title,
                 'goods_market_price'   => $item->sku->market_price ?: 0, // 市场价

+ 179 - 0
application/common/library/SkuHelper.php

@@ -0,0 +1,179 @@
+<?php
+
+namespace app\common\library;
+
+/**
+ * SKU辅助工具类
+ */
+class SkuHelper
+{
+    /**
+     * 格式化SKU规格属性显示
+     * @param string $skuAttr 规格属性JSON字符串,格式:[{"name":"规格名","value":"规格值"}]
+     * @return string 格式化后的显示文本
+     */
+    public static function formatSkuAttr($skuAttr)
+    {
+        if (empty($skuAttr)) {
+            return '';
+        }
+        
+        // 尝试解析JSON格式
+        $attrs = json_decode($skuAttr, true);
+        if (json_last_error() === JSON_ERROR_NONE && is_array($attrs)) {
+            // JSON格式
+            $formatted = [];
+            foreach ($attrs as $attr) {
+                if (isset($attr['name']) && isset($attr['value'])) {
+                    $formatted[] = $attr['name'] . ': ' . $attr['value'];
+                }
+            }
+            return implode(' | ', $formatted);
+        }
+        
+        // 兼容旧的字符串格式:规格名:规格值,规格名:规格值
+        if (strpos($skuAttr, ':') !== false) {
+            $attrs = explode(',', $skuAttr);
+            $formatted = [];
+            foreach ($attrs as $attr) {
+                if (strpos($attr, ':') !== false) {
+                    list($name, $value) = explode(':', $attr, 2);
+                    $formatted[] = trim($name) . ': ' . trim($value);
+                }
+            }
+            return implode(' | ', $formatted);
+        }
+        
+        return $skuAttr;
+    }
+    
+    /**
+     * 解析SKU规格属性为数组
+     * @param string $skuAttr 规格属性字符串
+     * @return array 规格属性数组,格式:[['name' => '颜色', 'value' => '红色'], ...]
+     */
+    public static function parseSkuAttr($skuAttr)
+    {
+        if (empty($skuAttr)) {
+            return [];
+        }
+        
+        // 尝试解析JSON格式
+        $attrs = json_decode($skuAttr, true);
+        if (json_last_error() === JSON_ERROR_NONE && is_array($attrs)) {
+            // 确保每个元素都有name和value字段
+            $parsed = [];
+            foreach ($attrs as $attr) {
+                if (isset($attr['name']) && isset($attr['value'])) {
+                    $parsed[] = [
+                        'name' => $attr['name'],
+                        'value' => $attr['value']
+                    ];
+                }
+            }
+            return $parsed;
+        }
+        
+        // 兼容旧的字符串格式
+        if (strpos($skuAttr, ':') !== false) {
+            $attrs = explode(',', $skuAttr);
+            $parsed = [];
+            foreach ($attrs as $attr) {
+                if (strpos($attr, ':') !== false) {
+                    list($name, $value) = explode(':', $attr, 2);
+                    $parsed[] = [
+                        'name' => trim($name),
+                        'value' => trim($value)
+                    ];
+                }
+            }
+            return $parsed;
+        }
+        
+        return [];
+    }
+    
+    /**
+     * 生成SKU规格属性JSON字符串
+     * @param array $specs 规格数组,格式:[['name' => '颜色', 'value' => '红色'], ...]
+     * @return string 规格属性JSON字符串
+     */
+    public static function buildSkuAttr($specs)
+    {
+        if (empty($specs) || !is_array($specs)) {
+            return '';
+        }
+        
+        $attrs = [];
+        foreach ($specs as $spec) {
+            if (isset($spec['name']) && isset($spec['value']) && !empty($spec['name']) && !empty($spec['value'])) {
+                $attrs[] = [
+                    'name' => trim($spec['name']),
+                    'value' => trim($spec['value'])
+                ];
+            }
+        }
+        
+        return !empty($attrs) ? json_encode($attrs, JSON_UNESCAPED_UNICODE) : '';
+    }
+    
+    /**
+     * 检查SKU规格属性是否匹配
+     * @param string $skuAttr1 第一个SKU的规格属性
+     * @param string $skuAttr2 第二个SKU的规格属性
+     * @return bool 是否匹配
+     */
+    public static function isSkuAttrMatch($skuAttr1, $skuAttr2)
+    {
+        if (empty($skuAttr1) && empty($skuAttr2)) {
+            return true;
+        }
+        
+        if (empty($skuAttr1) || empty($skuAttr2)) {
+            return false;
+        }
+        
+        // 解析为统一的数组格式进行比较
+        $parsed1 = self::parseSkuAttr($skuAttr1);
+        $parsed2 = self::parseSkuAttr($skuAttr2);
+        
+        if (count($parsed1) !== count($parsed2)) {
+            return false;
+        }
+        
+        // 按规格名排序后比较
+        usort($parsed1, function($a, $b) {
+            return strcmp($a['name'], $b['name']);
+        });
+        
+        usort($parsed2, function($a, $b) {
+            return strcmp($a['name'], $b['name']);
+        });
+        
+        for ($i = 0; $i < count($parsed1); $i++) {
+            if ($parsed1[$i]['name'] !== $parsed2[$i]['name'] || 
+                $parsed1[$i]['value'] !== $parsed2[$i]['value']) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * 获取SKU规格的简短显示文本
+     * @param string $skuAttr 规格属性字符串
+     * @param int $maxLength 最大长度
+     * @return string 简短显示文本
+     */
+    public static function getShortSkuAttr($skuAttr, $maxLength = 50)
+    {
+        $formatted = self::formatSkuAttr($skuAttr);
+        
+        if (mb_strlen($formatted) <= $maxLength) {
+            return $formatted;
+        }
+        
+        return mb_substr($formatted, 0, $maxLength - 3) . '...';
+    }
+} 

+ 2 - 1
application/common/model/Order.php

@@ -13,7 +13,8 @@ use traits\model\SoftDelete;
 use app\common\Enum\OrderEnum;
 use app\common\Traits\OrderStatusTrait;
 /**
- * 模型
+ * 订单模型
+ * @property mixed $address 订单地址信息(动态属性)
  */
 class Order extends Model
 {

+ 5 - 0
application/common/model/OrderGoods.php

@@ -141,6 +141,11 @@ class OrderGoods extends Model
         return true;
     }
 
+    public function getGoodsSkuAttrAttr($value, $data)
+    {
+        return json_decode($value, true);
+    }
+
     public function goods()
     {
         return $this->belongsTo('Goods', 'goods_id', 'id', [], 'LEFT')->setEagerlyType(1);

+ 2 - 0
application/common/service/OrderService.php

@@ -189,6 +189,8 @@ class OrderService
                 'sku_sn'               => $item->sku->sku_sn ?: '', // SKU编号
                 'goods_type'           => $item->goods->type ?: 0, // 商品类型
                 'goods_id'             => $item->goods->id,
+                'goods_sku_attr'       => $item->sku->sku_attr,
+                'goods_spec_value_ids' => $item->sku->spec_value_ids,
                 'goods_sku_id'         => $item->sku->id,
                 'goods_title'          => $item->goods->title,
                 'goods_market_price'   => $item->sku->market_price ?: 0, // 市场价

+ 46 - 0
public/assets/js/backend/shop/goods.js

@@ -189,6 +189,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                                     html += '<div style="font-size: 11px; color: #999; line-height: 1.4; word-wrap: break-word; word-break: break-all;" title="' + row.subtitle + '">' + row.subtitle + '</div>';
                                 }
                                 
+                                // 显示规格信息(如果是多规格商品且有默认SKU)
+                                if (row.spec_type == 1 && row.default_sku && row.default_sku.sku_attr) {
+                                    html += '<div style="font-size: 10px; color: #888; margin-top: 4px; padding: 2px 6px; background-color: #f5f5f5; border-radius: 3px;">';
+                                    html += '<i class="fa fa-list-alt" style="margin-right: 3px;"></i>';
+                                    html += '默认规格: ' + Controller.formatSkuAttr(row.default_sku.sku_attr);
+                                    html += '</div>';
+                                }
+                                
                                 html += '</div>';
                                 return html;
                             }
@@ -1695,6 +1703,44 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             }, 1000);
         },
         
+        // 格式化SKU规格属性显示
+        formatSkuAttr: function(skuAttr) {
+            if (!skuAttr) {
+                return '';
+            }
+            
+            try {
+                // 尝试解析JSON格式
+                var attrs = JSON.parse(skuAttr);
+                if (Array.isArray(attrs)) {
+                    var formatted = [];
+                    attrs.forEach(function(attr) {
+                        if (attr.name && attr.value) {
+                            formatted.push(attr.name + ': ' + attr.value);
+                        }
+                    });
+                    return formatted.join(' | ');
+                }
+            } catch (e) {
+                // 兼容旧的字符串格式:规格名:规格值,规格名:规格值
+                if (skuAttr.indexOf(':') !== -1) {
+                    var attrs = skuAttr.split(',');
+                    var formatted = [];
+                    attrs.forEach(function(attr) {
+                        if (attr.indexOf(':') !== -1) {
+                            var parts = attr.split(':');
+                            if (parts.length >= 2) {
+                                formatted.push(parts[0].trim() + ': ' + parts.slice(1).join(':').trim());
+                            }
+                        }
+                    });
+                    return formatted.join(' | ');
+                }
+            }
+            
+            return skuAttr;
+        },
+        
         // 显示表单错误并定位到对应选项卡
         showFormError: function(ret) {
             var message = ret.msg || '操作失败';