2eaf07925b6302c8d3b2e04b26de5755bdc65c13..81023be347e109e428788540df2254c6dc008139
2025-11-28 quanwei
Merge branch 'master' of http://git.zlxm286.com/r/companyProjecet
81023b diff | tree
2025-11-28 quanwei
添加商品
3ea53e diff | tree
2025-11-28 liyaozhi
修复连盟端角色无法编辑的问题
f6368a diff | tree
2 files added
26 files modified
4614 ■■■■■ changed files
admin/app/agent/model/supplier/Apply.php 1 ●●●● patch | view | raw | blame | history
admin/app/api/controller/plus/vip/User.php 1 ●●●● patch | view | raw | blame | history
admin/app/api/controller/supplier/Product.php 65 ●●●●● patch | view | raw | blame | history
admin/app/api/model/product/Product.php 186 ●●●●● patch | view | raw | blame | history
admin/app/api/model/supplier/Supplier.php 3 ●●●● patch | view | raw | blame | history
admin/app/common/enum/plus/vip/VipAreaTypeEnum.php 8 ●●●● patch | view | raw | blame | history
admin/app/common/model/plus/shareholder/Apply.php 70 ●●●●● patch | view | raw | blame | history
admin/app/common/model/plus/team/Apply.php 139 ●●●●● patch | view | raw | blame | history
admin/app/common/model/plus/team/User.php 2 ●●● patch | view | raw | blame | history
admin/app/common/model/plus/vip/Grade.php 8 ●●●●● patch | view | raw | blame | history
admin/app/common/model/plus/vip/Order.php 120 ●●●● patch | view | raw | blame | history
admin/app/common/model/supplier/Supplier.php 10 ●●●●● patch | view | raw | blame | history
admin/app/common/model/user/User.php 7 ●●●●● patch | view | raw | blame | history
admin/app/job/event/VipUserGrade.php 29 ●●●● patch | view | raw | blame | history
admin/app/shop/model/plus/vip/Grade.php 47 ●●●●● patch | view | raw | blame | history
admin/app/shop/model/supplier/Apply.php 1 ●●●● patch | view | raw | blame | history
admin/app/supplier/model/product/Product.php 12 ●●●●● patch | view | raw | blame | history
admin/app/supplier/service/ProductService.php 2 ●●● patch | view | raw | blame | history
branch_vue/src/views/auth/role/edit.vue 2 ●●● patch | view | raw | blame | history
mobile/pages.json 28 ●●●● patch | view | raw | blame | history
mobile/pages/user/my_shop/pro_admin.vue 61 ●●●● patch | view | raw | blame | history
mobile/pages/user/my_shop/product_add.vue 1778 ●●●●● patch | view | raw | blame | history
mobile/pages/user/my_shop/product_edit.vue 1878 ●●●●● patch | view | raw | blame | history
shop_vue/src/components/setlink/part/Menu.vue 10 ●●●●● patch | view | raw | blame | history
shop_vue/src/views/plus/team/setting/part/Basic.vue 14 ●●●●● patch | view | raw | blame | history
shop_vue/src/views/plus/vip/grade/part/Add.vue 59 ●●●●● patch | view | raw | blame | history
shop_vue/src/views/plus/vip/grade/part/Edit.vue 52 ●●●●● patch | view | raw | blame | history
shop_vue/src/views/plus/vip/grade/part/List.vue 21 ●●●●● patch | view | raw | blame | history
admin/app/agent/model/supplier/Apply.php
@@ -86,6 +86,7 @@
                    'link_name' => $this['user_name'],
                    'business_id' => $this['business_id'],
                    'category_id' => $this['category_id'],
                    'referee_id' => $this['referee_id'],
                    'agent_id' => self::$agent_id
                ];
                // 供应商状态,如果类目保证金为0,则直接通过,否则需要交纳保证金
admin/app/api/controller/plus/vip/User.php
@@ -41,6 +41,7 @@
        $is_vip = $this->isVipUser();
        if ($is_vip) {
            event('VipUserGrade', $this->user['user_id']);
            $this->vip = VipUserModel::detail($this->user['user_id']);
        }
        return $this->renderSuccess('', [
            // 当前是否为VIP用户
admin/app/api/controller/supplier/Product.php
@@ -4,6 +4,7 @@
use app\api\controller\Controller;
use app\api\model\product\Product as ProductModel;
use app\supplier\service\ProductService;
/**
 * 供应商产品
@@ -49,5 +50,69 @@
        }
        return $this->renderSuccess('操作成功');
    }
    /**
     * 获取添加商品所需的基础数据
     */
    public function getBaseData()
    {
        $data = ProductService::getEditData(null, 'add', $this->supplierUser['shop_supplier_id']);
        return $this->renderSuccess('', $data);
    }
    /**
     * 添加商品
     */
    public function add()
    {
        $data = $this->postData();
        $params = json_decode($data['params'], true);
        $params['shop_supplier_id'] = $this->supplierUser['shop_supplier_id'];
        $model = new ProductModel;
        if ($model->add($params)) {
            return $this->renderSuccess('添加成功');
        }
        return $this->renderError($model->getError() ?: '添加失败');
    }
    /**
     * 获取编辑商品所需的数据
     */
    public function getEditData()
    {
        $data = $this->postData();
        $product_id = $data['product_id'];
        // 获取商品数据
        $model = ProductModel::detail($product_id);
        if($this->supplierUser['shop_supplier_id'] != $model['shop_supplier_id']){
            return $this->renderError('非法请求');
        }
        $result = ProductService::getEditData($model, 'edit', $this->supplierUser['shop_supplier_id']);
        $result['model'] = $model;
        return $this->renderSuccess('', $result);
    }
    /**
     * 编辑商品
     */
    public function edit()
    {
        $data = $this->postData();
        $product_id = $data['product_id'];
        $params = json_decode($data['params'], true);
        // 获取商品数据
        $model = ProductModel::detail($product_id);
        if($this->supplierUser['shop_supplier_id'] != $model['shop_supplier_id']){
            return $this->renderError('非法请求');
        }
        if ($model->edit($params)) {
            return $this->renderSuccess('编辑成功');
        }
        return $this->renderError($model->getError() ?: '编辑失败');
    }
   
}
admin/app/api/model/product/Product.php
@@ -4,6 +4,7 @@
use app\api\model\plus\seckill\Active as ActiveModel;
use app\common\model\product\Product as ProductModel;
use app\common\model\settings\Setting;
use app\common\service\product\BaseProductService;
use app\common\library\helper;
use app\api\model\supplier\Supplier as SupplierModel;
@@ -11,6 +12,7 @@
use app\common\model\supplier\User as SupplierUserModel;
use app\api\model\user\CardRecord as CardRecordModel; // 会员卡 by lyzflash
use app\common\model\plus\advance\Product as AdvanceProductModel;
use app\supplier\model\product\ProductSku;
/**
 * 商品模型
@@ -285,4 +287,188 @@
    {
        return $this->save(['product_status' => $data['product_status']]);
    }
    public function add($data)
    {
        if (!isset($data['image']) || empty($data['image'])) {
            $this->error = '请上传商品图片';
            return false;
        }
        //如果支持核销 by yj
        if ($data['is_virtual'] && $data['is_verify']) {
            if ($data['verify_type'] == 20) {
                if (empty($data['verify_time'])) {
                    $this->error = '请选择核销有效时间';
                    return false;
                }
                $data["verify_start_time"] = strtotime(array_shift($data['verify_time']));
                $data["verify_end_time"] = strtotime(array_pop($data['verify_time']));
            }
            if ($data['verify_store_ids']) {
                $data['verify_store_ids'] = implode(',', array_unique($data['verify_store_ids']));
            }
        }
        $data['content'] = isset($data['content']) ? $data['content'] : '';
        $data['app_id'] = $data['sku']['app_id'] = self::$app_id;
        $this->processContent($data);
        // 开启事务
        $this->startTrans();
        try {
            // 添加商品
            $this->save($data);
            // 商品规格
            $this->addProductSpec($data);
            // 商品图片
            $this->addProductImages($data['image'], $data['shop_supplier_id']);
            // 商品详情图片
            if($data['is_picture'] == 1){
                $this->addProductContentImages($data['contentImage']);
            }
            $this->commit();
            return true;
        } catch (\Exception $e) {
            $this->error = $e->getMessage();
            $this->rollback();
            return false;
        }
    }
    /**
     * 处理内容
     */
    private function processContent(&$data)
    {
        $pattern = "/src=[\"\'](.*?)[\"\']/is";
        preg_match_all($pattern, $data['content'], $match);
    }
    /**
     * 添加商品图片
     */
    private function addProductImages($images, $shop_supplier_id)
    {
        $this->image()->delete();
        $data = array_map(function ($images)  use ($shop_supplier_id)  {
            isset($images['file_id']) && $image_id = $images['file_id'];
            isset($images['image_id']) && $image_id = $images['image_id'];
            if(!isset($images['file_id']) && !isset($images['image_id'])){
                $image_id = $images['file_path'];
            }
            return [
                'image_id' => $image_id,
                'app_id' => self::$app_id
            ];
        }, $images);
        return $this->image()->saveAll($data);
    }
    /**
     * 添加商品详情图片
     */
    private function addProductContentImages($images)
    {
        $this->contentImage()->delete();
        $data = array_map(function ($images) {
            return [
                'image_id' => isset($images['file_id']) ? $images['file_id'] : $images['image_id'],
                'image_type' => 1,
                'app_id' => self::$app_id
            ];
        }, $images);
        return $this->contentImage()->saveAll($data);
    }
    /**
     * 编辑商品
     */
    public function edit($data,$shop_supplier_id)
    {
        if (!isset($data['image']) || empty($data['image'])) {
            $this->error = '请上传商品图片';
            return false;
        }
        //如果支持核销 by yj
        if ($data['is_verify']) {
            if ($data['verify_type'] == 20) {
                if (empty($data['verify_time'])) {
                    $this->error = '请选择核销有效时间';
                    return false;
                }
                $data["verify_start_time"] = strtotime(array_shift($data['verify_time']));
                $data["verify_end_time"] = strtotime(array_pop($data['verify_time']));
            }
            if ($data['verify_store_ids']) {
                $data['verify_store_ids'] = implode(',', array_unique($data['verify_store_ids']));
            }
        }
        $data['spec_type'] = isset($data['spec_type']) ? $data['spec_type'] : $this['spec_type'];
        $data['content'] = isset($data['content']) ? $data['content'] : '';
        $data['app_id'] = $data['sku']['app_id'] = self::$app_id;
        $productSkuIdList = helper::getArrayColumn(($this['sku']), 'product_sku_id');
        return $this->transaction(function () use ($data, $productSkuIdList) {
            // 商品状态,如果已审核过的,看平台配置是否需要再次审核
            $edit_audit = Setting::getItem('store')['edit_audit'];
            if($edit_audit && $data['audit_status'] == 0){
                $data['audit_status'] = 0;
            }
            // 保存商品
            $this->save($data);
            // 商品规格
            $this->addProductSpec($data, true, $productSkuIdList);
            // 商品图片
            $this->addProductImages($data['image'], $this['shop_supplier_id']);
            // 商品详情图片
            if($data['is_picture'] == 1){
                $this->addProductContentImages($data['contentImage']);
            }
            return true;
        });
    }
    /**
     * 添加商品规格
     */
    private function addProductSpec($data, $isUpdate = false, $productSkuIdList = [])
    {
        // 更新模式: 先删除所有规格
        $model = new ProductSku;
        $isUpdate && $model->removeAll($this['product_id']);
        $stock = 0;//总库存
        $product_price = 0;
        $line_price = 0;
        // 商城设置
        $settings = Setting::getItem('store');
        // 添加规格数据
        if ($data['spec_type'] == '10') {
            // 删除多规格遗留数据
            $isUpdate && $model->removeSkuBySpec($this['product_id']);
            // 单规格
            $this->sku()->save($data['sku']);
            $stock = $data['sku']['stock_num'];
            $product_price = $data['sku']['product_price'];
            $line_price = $data['sku']['line_price'];
        } else if ($data['spec_type'] == '20') {
            // 添加商品与规格关系记录
            $model->addProductSpecRel($this['product_id'], $data['spec_many']['spec_attr']);
            // 添加商品sku
            $model->addSkuList($this['product_id'], $data['spec_many']['spec_list'], $productSkuIdList);
            $product_price = $data['spec_many']['spec_list'][0]['spec_form']['product_price'];
            foreach ($data['spec_many']['spec_list'] as &$item) {
                $stock += $item['spec_form']['stock_num'];
                if($item['spec_form']['product_price'] < $product_price){
                    $product_price = $item['spec_form']['product_price'];
                }
                if($item['spec_form']['line_price'] < $line_price){
                    $line_price = $item['spec_form']['line_price'];
                }
            }
        }
        $save_data = [
            'product_stock' => $stock,
            'product_price' => $product_price,
            'line_price' => $line_price
        ];
        // 商品价格
        $save_data['product_price'] = $product_price;
        $this->save($save_data);
    }
}
admin/app/api/model/supplier/Supplier.php
@@ -6,7 +6,7 @@
use app\common\model\supplier\User as SupplierUserModel;
use app\api\model\user\Favorite as FavoriteModel;
use app\api\model\product\Product as ProductModel;
use app\api\model\plus\team\Apply as teamApplyModel;
/**
 * 供应商模型类
 */
@@ -31,6 +31,7 @@
            $data['shop_supplier_id'] = $this['shop_supplier_id'];
            $data['is_super'] = 1;
            $SupplierUserModel->save($data);
            (new teamApplyModel())->becomeTeamByAgent($data['referee_id'],70,$data['app_id']);
            $this->commit();
            return true;
        } catch (\Exception $e) {
admin/app/common/enum/plus/vip/VipAreaTypeEnum.php
@@ -10,6 +10,9 @@
    const REFERRAL = 20; // 推广复购
    const VIP_SUBSIDY = 30; // 下级收益补贴
    const DIRECT_REFEREE = 40; // 平台直推佣金
    const DIRECT_SUPPLIER = 50; // 直推供应商佣金
    /**
     * 获取VIP专区订单类型名称
@@ -18,10 +21,11 @@
    public static function getTypeName()
    {
        return [
            self::NORMAL => '推广',
            self::REFERRAL => '推广复购',
            self::NORMAL => '推广佣金',
            self::REFERRAL => '推广复购佣金',
            self::VIP_SUBSIDY => '下级收益补贴',
            self::DIRECT_REFEREE => '平台直推佣金',
            self::DIRECT_SUPPLIER => '直推商家佣金',
        ];
    }
admin/app/common/model/plus/shareholder/Apply.php
@@ -6,6 +6,8 @@
use app\common\model\plus\agent\User as AgentUserModel;
use app\common\model\plus\team\User as TeamUserModel;
use app\common\model\plus\team\Order as TeamOrderModel;
use app\common\model\plus\vip\User as VipUserModel;
use app\common\model\plus\vip\Order as VipOrderModel;
/**
 * 股东申请模型
@@ -180,4 +182,70 @@
        return ['text' => $method[$value], 'value' => $value];
    }
}
    /**
     * 统计VIP会员直接推荐数量
     * @param $userId
     * @return int
     */
    public function countVipRecommendations($userId)
    {
        return VipUserModel::where('referee_id', '=', $userId)->count();
    }
    /**
     * 统计企业商户入驻数量
     * @param $userId
     * @return int
     */
    public function countMerchantSettlements($userId)
    {
        // 假设商家入驻与推广团队的关联字段是referee_id
        // 需要根据实际数据库结构调整
        return \app\common\model\Shop::where('referee_id', '=', $userId)->count();
    }
    /**
     * 统计VIP专区商品购买次数
     * @param $userId
     * @return int
     */
    public function countSelfVipPurchases($userId)
    {
        return VipOrderModel::where('user_id', '=', $userId)
            ->where('is_vip', '=', 1)
            ->count();
    }
    /**
     * 检查股东候选人是否满足新的三个条件
     * @param $userId
     * @param $appId
     * @return bool
     */
    public function checkNewShareholderConditions($userId, $appId)
    {
        $config = Setting::getItem('basic', $appId);
        // 1. 检查VIP会员直接推荐数量
        $vipRecommendCount = $this->countVipRecommendations($userId);
        if ($vipRecommendCount < $config['vip_recommend_count']) {
            return false;
        }
        // 2. 检查企业商户入驻数量
        $merchantCount = $this->countMerchantSettlements($userId);
        if ($merchantCount < $config['merchant_settle_count']) {
            return false;
        }
        // 3. 检查VIP专区商品购买次数
        $selfVipPurchaseCount = $this->countSelfVipPurchases($userId);
        if ($selfVipPurchaseCount < $config['self_vip_purchase_count']) {
            return false;
        }
        // 所有条件都满足
        return true;
    }
},
admin/app/common/model/plus/team/Apply.php
@@ -1,138 +1 @@
<?php
namespace app\common\model\plus\team;
use app\common\model\BaseModel;
use app\common\model\plus\agent\User as AgentUserModel;
/**
 * 队长申请模型
 */
class Apply extends BaseModel
{
    protected $name = 'team_apply';
    protected $pk = 'apply_id';
    /**
     * 申请状态
     * @var array
     */
    public $applyStatus = [
        10 => '待审核',
        20 => '审核通过',
        30 => '驳回',
    ];
    /**
     * 申请时间
     * @param $value
     * @return false|string
     */
    public function getApplyTimeAttr($value)
    {
        return date('Y-m-d H:i:s', $value);
    }
    /**
     * 审核时间
     * @param $value
     * @return false|int|string
     */
    public function getAuditTimeAttr($value)
    {
        return $value > 0 ? date('Y-m-d H:i:s', $value) : 0;
    }
    /**
     * 关联推荐人表
     * @return \think\model\relation\BelongsTo
     */
    public function referee()
    {
        return $this->belongsTo('app\common\model\user\User', 'referee_id')
            ->field(['user_id', 'nickName']);
    }
    /**
     * 销商申请记录详情
     * @param $where
     * @return array|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function detail($where)
    {
        $filter = is_array($where) ? $where : ['apply_id' => $where];
        return (new static())->where($filter)->find();
    }
    /**
     * 根据分销判断成为队长
     * @param $userId
     * @param $appId
     * @return bool
     */
    public function becomeTeamByAgent($userId, $become_type, $appId)
    {
        //log_write($become_type);
        // 验证是否设置
        $config = Setting::getItem('basic', $appId);
        if (empty($config['is_open'])) {
            return false;
        }
        if ($config['become'] != $become_type) {
            return false;
        }
        $agent = AgentUserModel::detail($userId);
        if (!$agent) {
            return false;
        }
        $becomeTeam = false;
        //分销商总数
        if ($become_type == '40') {
            $agent_total = $agent['first_num'] + $agent['second_num'] + $agent['third_num'];
            if ($agent_total >= $config['totalfxs_down']) {
                $becomeTeam = true;
            }
        }
        //分销佣金总数
        if ($become_type == '50') {
            $agent_money = $agent['total_money'] + $agent['money'] + $agent['freeze_money'];
            if ($agent_money >= $config['total_money']) {
                $becomeTeam = true;
            }
        }
        // 新增队长用户
        if ($becomeTeam) {
            User::add($userId, [
                'referee_id' => $agent['referee_id'], //推荐人id
                'app_id' => $appId,
            ]);
        }
        return true;
    }
    /**
     * 审核状态
     * @param $value
     * @return array
     */
    public function getApplyStatusAttr($value)
    {
        $method = [10 => '待审核', 20 => '审核通过', '30' => '驳回'];
        return ['text' => $method[$value], 'value' => $value];
    }
    /**
     * 审核方式
     * @param $value
     * @return array
     */
    public function getApplyTypeAttr($value)
    {
        $method = [10 => '后台审核', 20 => '无需审核'];
        return ['text' => $method[$value], 'value' => $value];
    }
}
<?php namespace app\common\model\plus\team; use app\common\model\BaseModel; use app\common\model\plus\agent\User as AgentUserModel; /**  * 队长申请模型  */ class Apply extends BaseModel {     protected $name = 'team_apply';     protected $pk = 'apply_id';     /**      * 申请状态      * @var array      */     public $applyStatus = [         10 => '待审核',         20 => '审核通过',         30 => '驳回',     ];     /**      * 申请时间      * @param $value      * @return false|string      */     public function getApplyTimeAttr($value)     {         return date('Y-m-d H:i:s', $value);     }     /**      * 审核时间      * @param $value      * @return false|int|string      */     public function getAuditTimeAttr($value)     {         return $value > 0 ? date('Y-m-d H:i:s', $value) : 0;     }     /**      * 关联推荐人表      * @return \think\model\relation\BelongsTo      */     public function referee()     {         return $this->belongsTo('app\common\model\user\User', 'referee_id')             ->field(['user_id', 'nickName']);     }     /**      * 销商申请记录详情      * @param $where      * @return array|\think\Model|null      * @throws \think\db\exception\DataNotFoundException      * @throws \think\db\exception\DbException      * @throws \think\db\exception\ModelNotFoundException      */     public static function detail($where)     {         $filter = is_array($where) ? $where : ['apply_id' => $where];         return (new static())->where($filter)->find();     }     /**      * 根据分销判断成为队长      * @param $userId      * @param $appId      * @return bool      */     public function becomeTeamByAgent($userId, $become_type, $appId)     {         //log_write($become_type);         // 验证是否设置         $config = Setting::getItem('basic', $appId);         if (empty($config['is_open'])) {             return false;         }         if ($config['become'] != $become_type) {             return false;         }         $agent = AgentUserModel::detail($userId);         if (!$agent) {             return false;         }         $becomeTeam = false;         //分销商总数         if ($become_type == '40') {             $agent_total = $agent['first_num'] + $agent['second_num'] + $agent['third_num'];             if ($agent_total >= $config['totalfxs_down']) {                 $becomeTeam = true;             }         }         //分销佣金总数         if ($become_type == '50') {             $agent_money = $agent['total_money'] + $agent['money'] + $agent['freeze_money'];             if ($agent_money >= $config['total_money']) {                 $becomeTeam = true;             }         }         if($become_type == '70'){             $vipNum=(new \app\common\model\user\User)->where(['referee_id' =>$userId,'grade_id'=>57,'is_delete'=>0])->count();             $supplierNum=(new \app\common\model\user\User)->where(['referee_id' =>$userId,'is_delete'=>0])->count();             if ($vipNum >= $config['totalvip_down'] && $supplierNum >= $config['totalsh_down']) {                 $BecomeTeam = true;             }         }         // 新增队长用户         if ($BecomeTeam) {             User::add($userId, [                 'referee_id' => $agent['referee_id'], //推荐人id                 'app_id' => $appId,             ]);         }         return true;     }     /**      * 审核状态      * @param $value      * @return array      */     public function getApplyStatusAttr($value)     {         $method = [10 => '待审核', 20 => '审核通过', '30' => '驳回'];         return ['text' => $method[$value], 'value' => $value];     }     /**      * 审核方式      * @param $value      * @return array      */     public function getApplyTypeAttr($value)     {         $method = [10 => '后台审核', 20 => '无需审核'];         return ['text' => $method[$value], 'value' => $value];     } }
admin/app/common/model/plus/team/User.php
@@ -1 +1 @@
<?php namespace app\common\model\plus\team; use app\common\enum\user\grade\ChangeTypeEnum; use app\common\model\BaseModel; /**  * 队长用户模型  */ class User extends BaseModel {     protected $name = 'team_user';     protected $pk = 'user_id';          /**      * 关联会员等级表      */     public function grade()     {         return $this->belongsTo('app\\common\\model\\plus\\team\\Grade', 'grade_id', 'grade_id');     }          /**      * 关联会员记录表      * @return \think\model\relation\BelongsTo      */     public function user()     {         return $this->belongsTo('app\\common\\model\\user\\User');     }     /**      * 关联队长关系表      * @return \think\model\relation\BelongsTo      */     public function referee()     {         return $this->belongsTo('app\\common\\model\\plus\\team\\Referee', 'user_id', 'user_id');     }     /**      * 详情      */     public static function detail($user_id, $with = ['user', 'referee'])     {         return (new static())->with($with)->find($user_id);     }     /**      * 是否为队长      */     public static function isteamUser($user_id)     {         $team = self::detail($user_id);         return !!$team && !$team['is_delete'];     }     /**      * 新增队长用户记录      * @param $user_id      * @param $data      * @return bool      */     public static function add($user_id, $data)     {         $model = static::detail($user_id) ?: new static;         $model->save(array_merge([             'user_id' => $user_id,             'is_delete' => 0,             'app_id' => $model::$app_id         ], $data));         //更新队长成员         Referee::createTeam($user_id);         // 更新改用户队长的成员数量         $heads_id = Referee::getHeadsId($user_id);         if ($heads_id) {             User::setMemberInc($heads_id);         }         return true;     }     /**      * 发放队长佣金      * @param $user_id      * @param $money      * @return bool      */     public static function grantMoney($user_id, $money, $bonus_type)     {         // 队长详情         $model = static::detail($user_id);         if (!$model || $model['is_delete']) {             return false;         }         // 累积队长可提现佣金         $model->where('user_id', '=', $user_id)->inc('money', $money)->update();         // 记录队长资金明细         Capital::add([             'user_id' => $user_id,             'flow_type' => 10,             'money' => $money,             'bonus_type' => $bonus_type['value'],             'describe' => '订单分红结算-' . $bonus_type['text'],             'app_id' => $model['app_id'],         ]);         return true;     }     /**      * 批量设置队长等级      */     public function upgradeGrade($user, $upgradeGrade)     {         // 更新会员等级的数据         $this->where('user_id', '=', $user['user_id'])             ->update([                 'grade_id' => $upgradeGrade['grade_id']             ]);         (new GradeLog)->save([             'old_grade_id' => $user['grade_id'],             'new_grade_id' => $upgradeGrade['grade_id'],             'change_type' => ChangeTypeEnum::AUTO_UPGRADE,             'user_id' => $user['user_id'],             'app_id' => $user['app_id']         ]);         return true;     }     /**      * 累计队长成员数量      */     public static function setMemberInc($user_id)     {         if(empty($user_id)) {             return false;         }         $model = static::detail($user_id);         return $model->save([             'total_num' => Referee::teamCount($user_id)         ]);     } }
<?php namespace app\common\model\plus\team; use app\common\enum\user\grade\ChangeTypeEnum; use app\common\model\BaseModel; /**  * 队长用户模型  */ class User extends BaseModel {     protected $name = 'team_user';     protected $pk = 'user_id';          /**      * 关联会员等级表      */     public function grade()     {         return $this->belongsTo('app\\common\\model\\plus\\team\\Grade', 'grade_id', 'grade_id');     }          /**      * 关联会员记录表      * @return \think\model\relation\BelongsTo      */     public function user()     {         return $this->belongsTo('app\\common\\model\\user\\User');     }     /**      * 关联队长关系表      * @return \think\model\relation\BelongsTo      */     public function referee()     {         return $this->belongsTo('app\\common\\model\\plus\\team\\Referee', 'user_id', 'user_id');     }     /**      * 详情      */     public static function detail($user_id, $with = ['user', 'referee'])     {         return (new static())->with($with)->find($user_id);     }     /**      * 是否为队长      */     public static function isteamUser($user_id)     {         $team = self::detail($user_id);         return !!$team && !$team['is_delete'];     }     /**      * 新增队长用户记录      * @param $user_id      * @param $data      * @return bool      */     public static function add($user_id, $data)     {         $model = static::detail($user_id) ?: new static;         $model->save(array_merge([             'user_id' => $user_id,             'grade_id' => Grade::getDefaultGradeId(),             'is_delete' => 0,             'app_id' => $model::$app_id         ], $data));         //更新队长成员         Referee::createTeam($user_id);         // 更新改用户队长的成员数量         $heads_id = Referee::getHeadsId($user_id);         if ($heads_id) {             User::setMemberInc($heads_id);         }         return true;     }     /**      * 发放队长佣金      * @param $user_id      * @param $money      * @return bool      */     public static function grantMoney($user_id, $money, $bonus_type)     {         // 队长详情         $model = static::detail($user_id);         if (!$model || $model['is_delete']) {             return false;         }         // 累积队长可提现佣金         $model->where('user_id', '=', $user_id)->inc('money', $money)->update();         // 记录队长资金明细         Capital::add([             'user_id' => $user_id,             'flow_type' => 10,             'money' => $money,             'bonus_type' => $bonus_type['value'],             'describe' => '订单分红结算-' . $bonus_type['text'],             'app_id' => $model['app_id'],         ]);         return true;     }     /**      * 批量设置队长等级      */     public function upgradeGrade($user, $upgradeGrade)     {         // 更新会员等级的数据         $this->where('user_id', '=', $user['user_id'])             ->update([                 'grade_id' => $upgradeGrade['grade_id']             ]);         (new GradeLog)->save([             'old_grade_id' => $user['grade_id'],             'new_grade_id' => $upgradeGrade['grade_id'],             'change_type' => ChangeTypeEnum::AUTO_UPGRADE,             'user_id' => $user['user_id'],             'app_id' => $user['app_id']         ]);         return true;     }     /**      * 累计队长成员数量      */     public static function setMemberInc($user_id)     {         if(empty($user_id)) {             return false;         }         $model = static::detail($user_id);         return $model->save([             'total_num' => Referee::teamCount($user_id)         ]);     } }
admin/app/common/model/plus/vip/Grade.php
@@ -12,6 +12,14 @@
    protected $name = 'vip_area_grade';
    protected $pk = 'grade_id';
    public function setRefereeGradeIdsAttr($value)
    {
        return  json_encode( $value);
    }
    public function getRefereeGradeIdsAttr($value)
    {
        return json_decode($value, true);
    }
    /**
     * 获取详情
     */
admin/app/common/model/plus/vip/Order.php
@@ -140,17 +140,9 @@
            if ($deadlineTime > time()) {
                continue;
            }
            // 发放推广佣金(首次购买VIP商品)
            if ($model['vip_area_type'] == 10) {
                $model['vip_area_user_id'] > 0 && User::grantMoney($model['vip_area_user_id'], $model['vip_area_money'], '推广佣金');
            if ($model['vip_area_user_id'] != 0) {
                User::grantMoney($model['vip_area_user_id'], $model['vip_area_money'], VipAreaTypeEnum::getTypeName()[$model['vip_area_type']]);
            }
            // 发放推广复购佣金(非首次购买VIP商品)
            if ($model['vip_area_type'] == 20) {
                $model['vip_area_user_id'] > 0 && User::grantMoney($model['vip_area_user_id'], $model['vip_area_money'], '推广复购佣金');
            }
            // 发放VIP专区补贴给下级用户(当下级获得推广佣金或复购佣金时)
            if ($model['vip_area_type'] == 10 || $model['vip_area_type'] == 20) {
                // 获取下级用户的推荐人(即上级用户)
@@ -160,15 +152,12 @@
                    if ($vipUser['grade']['operating_subsidy']>0){
                        // 获取补贴比例设置
                        $subsidyRate = $vipUser['grade']['operating_subsidy'];
                        // 计算VIP专区补贴
                        $subsidyAmount = bcmul($model['vip_area_money'], bcdiv((string)$subsidyRate, '100', 4), 2);
                        User::grantMoney($superiorUser['referee_id'], $subsidyAmount, 'VIP专区补贴');
                        // 记录分销订单
                        self::createDistributionOrder($order, $superiorUser['referee_id'], $subsidyAmount, 'vip_subsidy',$model['vip_area_money']);
                    }
                }
            }
            
@@ -271,36 +260,13 @@
            if (!$setting['is_open']) {
                return false;
            }
            // 获取当前买家的推荐人信息
            $userModel = UserModel::detail($order['user_id']);
            if (!$userModel || !$userModel['referee_id']) {
                return false;
            }
            // 检查推荐人是否为VIP专区用户
            $vipUser = User::detail($userModel['referee_id']);
            if (!$vipUser) {
                return false;
            }
            // 获取VIP等级设置
            $vipGrade = Grade::detail($vipUser['grade_id']);
            if (!$vipGrade) {
                return false;
            }
            // 验证是否设置
            $config = Setting::getItem('basic', $order['app_id']);
            if (empty($config['become__buy_product_ids'])) {
                return false;
            }
            $data = [
                'user_id' => $order['user_id'],
                'order_id' => $order['order_id'],
                'order_type' => $order_type,
                'order_price' => $order['pay_price'],
                'vip_area_user_id' => $vipUser['user_id'],
                'referee_id' => $userModel['referee_id'],
                'vip_area_user_id' => 0,
                'referee_id' => 0,
                'vip_area_money' => 0,
                'vip_area_type' => 0,
                'is_settled' => 0,
@@ -310,36 +276,64 @@
            $list=[];
            // 计算佣金金额
            $orderPrice = bcsub($order['pay_price'], $order['express_price'], 2);
            $purchase_count=(new self())->getPurchaseCount($order['user_id']);
            foreach ($order['product'] as $product){
                if (in_array($product['product_id'], $config['become__buy_product_ids'])) {
                    // 获取商品数量
                    $quantity = $product['total_num'];
                    // 为每个商品生成分红订单
                    for ($i = 0; $i < $quantity; $i++) {
                        if ($purchase_count==1){
                            $list[]=array_merge($data,['vip_area_type'=>10,'vip_area_money'=>$vipGrade['agent_money'],'is_vip'=>1,'purchase_count'=>$purchase_count]);
                                $purchase_count++;
                        }else{
                            if ($vipGrade['repurchase_money']>0){
                                $list[]=array_merge($data,['vip_area_type'=>20,'vip_area_money'=>$vipGrade['repurchase_money'],'is_vip'=>1,'purchase_count'=>$purchase_count]);
                                $purchase_count++;
            // 获取当前买家的推荐人信息
            $userModel = UserModel::detail($order['user_id']);
            if (!empty($userModel) && !empty($userModel['referee_id'])) {
                // 检查推荐人是否为VIP专区用户
                $vipUser = User::detail($userModel['referee_id']);
                if ($vipUser) {
                    $data['vip_area_user_id'] = $vipUser['user_id'];
                    $data['referee_id'] = $userModel['referee_id'];
                    // 获取VIP等级设置
                    $vipGrade = Grade::detail($vipUser['grade_id']);
                    if ($vipGrade) {
                        $config = Setting::getItem('basic', $order['app_id']);
                        if (!empty($config['become__buy_product_ids'])) {
                            $purchase_count=(new self())->getPurchaseCount($order['user_id']);
                            foreach ($order['product'] as $product){
                                if (in_array($product['product_id'], $config['become__buy_product_ids'])) {
                                    // 获取商品数量
                                    $quantity = $product['total_num'];
                                    // 为每个商品生成分红订单
                                    for ($i = 0; $i < $quantity; $i++) {
                                        if ($purchase_count==1){
                                            $list[]=array_merge($data,['vip_area_type'=>10,'vip_area_money'=>$vipGrade['agent_money'],'is_vip'=>1,'purchase_count'=>$purchase_count]);
                                            $purchase_count++;
                                        }else{
                                            if ($vipGrade['repurchase_money']>0){
                                                $list[]=array_merge($data,['vip_area_type'=>20,'vip_area_money'=>$vipGrade['repurchase_money'],'is_vip'=>1,'purchase_count'=>$purchase_count]);
                                                $purchase_count++;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        $directReferralsCount=0;
                        $user=UserModel::detail($order['user_id']);
                        if (!empty($user['referee_id'])){
                            // 检查推荐人是否满足直推条件(直推用户数量)
                            $directReferralsCount = UserModel::where('referee_id', '=', $user['referee_id'])->count();
                        }
                        $requiredReferralCount = $setting['referee_buy_count'] ?? 0;
                        if ($vipGrade['commission']>0 && $directReferralsCount >= $requiredReferralCount){
                            // 计算平台直推佣金金额
                            $commissionAmount = bcmul($orderPrice, bcdiv($vipGrade['commission'], '100', 4), 2);
                            $list[]=array_merge($data,['vip_area_type'=>40,'vip_area_money'=>$commissionAmount]);
                        }
                    }
                }
            }
            $directReferralsCount=0;
            $user=UserModel::detail($order['user_id']);
            if (!empty($user['referee_id'])){
                // 检查推荐人是否满足直推条件(直推用户数量)
                $directReferralsCount = UserModel::where('referee_id', '=', $user['referee_id'])->count();
            }
            $requiredReferralCount = $setting['referee_buy_count'] ?? 0;
            if ($vipGrade['commission']>0 && $directReferralsCount >= $requiredReferralCount){
                // 计算佣金金额
                $commissionAmount = bcmul($orderPrice, bcdiv($vipGrade['commission'], '100', 4), 2);
                $list[]=array_merge($data,['vip_area_type'=>40,'vip_area_money'=>$commissionAmount]);
            if( $order['supplier']['referee_id']!=0){
                $supplierReferee=VipUserModel::detail($order['supplier']['referee_id']);
                if ($supplierReferee){
                    $vipGradeSupplier=Grade::detail($supplierReferee['grade_id']);
                    if ($vipGradeSupplier['supplier_money']>0){
                        // 计算直推店铺交易额佣金金额
                        $supplier_money = bcmul($orderPrice, bcdiv($vipGrade['supplier_money'], '100', 4), 2);
                        $list[]=array_merge($data,['vip_area_type'=>50,'vip_area_money'=>$supplier_money,'vip_area_user_id'=>$supplierReferee['user_id'],'referee_id'=>$supplierReferee['referee_id']]);
                    }
                }
            }
            if (empty($list)){
                return true;
admin/app/common/model/supplier/Supplier.php
@@ -252,5 +252,15 @@
    {
        $this->save(['money' => $this['money'] - $money,'freeze_money'=>$this['freeze_money']+$money]);
    }
    /**
     * 直推供应商多少人
     */
    public function refereeSupplierCount ($referee_id)
    {
        $count = $this->where('referee_id', '=', $referee_id)
            ->where('is_delete', '=', 0)
            ->count();
        return $count;
    }
}
admin/app/common/model/user/User.php
@@ -332,4 +332,11 @@
        }
        return true;
    }
    /**
     * 获取指定等级推荐人数量
     */
    public function getRefereeGradeCount($user_id,$referee_grade_ids)
    {
        return $this->where('referee_id', '=', $user_id)->where('grade_id', 'in', $referee_grade_ids)->count();
    }
}
admin/app/job/event/VipUserGrade.php
@@ -3,9 +3,10 @@
namespace app\job\event;
use app\common\model\plus\vip\Grade as GradeModel;
use app\common\model\plus\vip\User as UserModel;
use app\common\model\plus\vip\User as vipUserModel;
use app\common\model\plus\vip\Order as OrderModel;
use app\common\model\supplier\Supplier;
use app\job\model\user\User as UserModel;
/**
 * VIP用户等级事件管理
 */
@@ -31,7 +32,7 @@
        }
        log_write('VIP用户升级$user_id='.$userId);
        // 用户模型
        $user = UserModel::detail($userId);
        $user = vipUserModel::detail($userId);
        // 获取所有等级
        $list = GradeModel::getUsableList($user['app_id']);
        if ($list->isEmpty()) {
@@ -56,7 +57,7 @@
            }
        }
        if($upgradeGrade){
            if($user['grade_id'] == $upgradeGrade['grade_id']){
            if($user['grade_id'] == $upgradeGrade['grade_id']||$user['grade']['weight'] >= $upgradeGrade['weight']){
                return true;
            }
            $this->dologs('setVipUserGrade', [
@@ -64,7 +65,7 @@
                'grade_id' => $upgradeGrade['grade_id'],
            ]);
            // 修改会员的等级
            (new UserModel())->upgradeGrade($user, $upgradeGrade);
            (new vipUserModel())->upgradeGrade($user, $upgradeGrade);
        }
    }
@@ -78,11 +79,25 @@
        if($grade['is_purchase_count'] == 1 && $user['user']['purchase_count'] >= $grade['purchase_count']){
            $purchase_count = true;
        }
        $supplier_count = false;
        $referee_supplier_count = (new Supplier())->where('referee_id', $user['user_id'])->count();
        // 直推供应商多少人
        if($grade['is_supplier_count'] == 1 && $referee_supplier_count >= $grade['supplier_count']){
            $supplier_count = true;
        }
        // 推荐人等级
        $user_referee_grade_count = (new UserModel())->getRefereeGradeCount($user['user_id'], $grade['referee_grade_ids']);
        $referee_grade_count=false;
        if($grade['is_referee_grade'] == 1 && $user_referee_grade_count >= $grade['referee_grade_count']){
            $referee_grade_count = true;
        }
        if($grade['condition_type'] == 'and'){
            $grade['is_purchase_count']!=1 && $purchase_count=true;
            return $purchase_count;
            $grade['is_supplier_count']!=1 && $supplier_count=true;
            $grade['is_referee_grade']!=1 && $referee_grade_count=true;
            return $purchase_count && $supplier_count && $referee_grade_count;
        }else{
            return $purchase_count;
            return $purchase_count || $supplier_count || $referee_grade_count;
        }
    }
admin/app/shop/model/plus/vip/Grade.php
@@ -4,6 +4,7 @@
use app\common\model\plus\vip\Grade as GradeModel;
use app\shop\model\plus\vip\User as VipUserModel;
use app\common\model\user\Grade as UserGradeModel;
/**
 * VIP专区等级模型
 */
@@ -61,9 +62,55 @@
        if($data['is_purchase_count'] == 1){
            if(!empty($remark)){
                $remark .= '\r\n';
                if ($data['condition_type']=='and'){
                    $remark .= "并且";
                }else{
                    $remark .= "或";
                }
            }
            $remark .= "购买VIP专区商品次数满{$data['purchase_count']}次";
        }
        if($data['is_supplier_count'] == 1){
            if(!empty($remark)){
                $remark .= '\r\n';
                if ($data['condition_type']=='and'){
                    $remark .= "并且";
                }else{
                    $remark .= "或";
                }
            }
            $remark .= "直推商家满{$data['supplier_count']}家";
        }
        if($data['is_referee_grade'] == 1){
            if(!empty($remark)){
                $remark .= '\r\n';
                if ($data['condition_type']=='and'){
                    $remark .= "并且";
                }else{
                    $remark .= "或";
                }
            }
            // 获取用户等级名称
            $gradeNames = [];
            if (!empty($data['referee_grade_ids']) && is_array($data['referee_grade_ids'])) {
                // 查询用户等级名称
                $grades = UserGradeModel::where('grade_id', 'in', $data['referee_grade_ids'])
                    ->field('name')
                    ->select();
                foreach ($grades as $grade) {
                    $gradeNames[] = $grade['name'];
                }
            }
            $gradeNamesStr = implode('、', $gradeNames);
            $remark .= "直推{$gradeNamesStr}等级会员满{$data['referee_grade_count']}人";
        }
        return $remark;
    }
}
admin/app/shop/model/supplier/Apply.php
@@ -89,6 +89,7 @@
                    'link_name' => $this['user_name'],
                    'business_id' => $this['business_id'],
                    'category_id' => $this['category_id'],
                    'referee_id' => $this['referee_id'],
                    'area_id' => $this['area_id'],
                    'app_id' => self::$app_id
                ];
admin/app/supplier/model/product/Product.php
@@ -45,6 +45,12 @@
        }
        $data['content'] = isset($data['content']) ? $data['content'] : '';
        $data['app_id'] = $data['sku']['app_id'] = self::$app_id;
        // 设置商品重量默认值
        $data['product_weight'] = isset($data['product_weight']) ? $data['product_weight'] : 0;
        // 单规格商品,将规格重量赋值给商品重量
        if (isset($data['spec_type']) && $data['spec_type'] == '10' && isset($data['sku']['weight'])) {
            $data['product_weight'] = $data['sku']['weight'];
        }
        $this->processContent($data);
        // 开启事务
@@ -131,6 +137,12 @@
        $data['spec_type'] = isset($data['spec_type']) ? $data['spec_type'] : $this['spec_type'];
        $data['content'] = isset($data['content']) ? $data['content'] : '';
        $data['app_id'] = $data['sku']['app_id'] = self::$app_id;
        // 设置商品重量默认值
        $data['product_weight'] = isset($data['product_weight']) ? $data['product_weight'] : 0;
        // 单规格商品,将规格重量赋值给商品重量
        if (isset($data['spec_type']) && $data['spec_type'] == '10' && isset($data['sku']['weight'])) {
            $data['product_weight'] = $data['sku']['weight'];
        }
        $productSkuIdList = helper::getArrayColumn(($this['sku']), 'product_sku_id');
        return $this->transaction(function () use ($data, $productSkuIdList) {
            // 商品状态,如果已审核过的,看平台配置是否需要再次审核
admin/app/supplier/service/ProductService.php
@@ -21,7 +21,7 @@
    public static function getEditData($model = null, $scene = 'edit', $shop_supplier_id)
    {
        // 商品分类
        $category = CategoryModel::getCacheTree();
        $category = CategoryModel::getCacheAll();
        // 配送模板
        $delivery = DeliveryModel::getAll($shop_supplier_id);
        // 商品sku数据
branch_vue/src/views/auth/role/edit.vue
@@ -64,7 +64,7 @@
  created() {
    this.role_id = this.$route.query.role_id;
    /*获取列表*/
    this.getData(role_id);
    this.getData(this.role_id);
  },
  methods: {
    /*修改角色*/
mobile/pages.json
@@ -177,7 +177,7 @@
                    //#endif
                }
            }
        }, {
        }, /* {
            "path": "components/upload/upload",
            "style": {
                "app-plus": {
@@ -186,7 +186,7 @@
                    //#endif
                }
            }
        }, {
        }, */ {
            "path": "pages/agent/index/index",
            "style": {
                "navigationStyle": "custom",
@@ -1043,7 +1043,29 @@
                    }
                }
            }, {
            },{"path": "my_shop/product_add",
                    "style": {
                        "navigationBarTitleText": "商品添加",
                        "enablePullDownRefresh": false,
                        "app-plus": {
                            //#ifdef H5
                            "titleNView": false
                            //#endif
                        }
                    }
                },{"path": "my_shop/product_edit",
                    "style": {
                        "navigationBarTitleText": "商品编辑",
                        "enablePullDownRefresh": false,
                        "app-plus": {
                            //#ifdef H5
                            "titleNView": false
                            //#endif
                        }
                    }
                }, {
                "path": "my_shop/my_shop_data",
                "style": {
                    "navigationBarTitleText": "店铺数据",
mobile/pages/user/my_shop/pro_admin.vue
@@ -1,6 +1,6 @@
<template>
    <view class="prodcut-list-wrap">
        <scroll-view scroll-y="true" :style="'height:' + scrollviewHigh + 'px;'" class="scroll-Y" lower-threshold="50"
        <scroll-view scroll-y="true" :style="'height:' + (scrollviewHigh - 120) + 'px;'" class="scroll-Y" lower-threshold="50"
         @scrolltolower="scrolltolowerFunc">
            <view class="shop">
                <view class="shop_head">
@@ -19,14 +19,15 @@
                <view class="shop_body" v-if="!loading">
                    <view class="shop_body_l_item" v-for="(item,index) in product_list" :key="index" >
                        <view class="d-s-c mb20">
                            <view class="shop_body_l_item_img">
                            <view class="shop_body_l_item_img" @click="editProduct(item.product_id)">
                                <image class="item_img" :src="item.product_image" mode="aspectFill"></image>
                            </view>
                            <view class=" flex-1">
                                <view class="shop_body_l_item_info_title h1">{{item.product_name}}</view>
                                <view class="shop_body_l_item_info_title h1" @click="editProduct(item.product_id)">{{item.product_name}}</view>
                                <view class="shop_body_l_item_info_price h2 red">¥<text class="h1">{{item.product_price}}</text></view>
                                <view class="d-b-c">
                                    <view>库存:{{item.product_stock}}</view>
                                    <button class='shop_body_b_btn edit-btn' @click="editProduct(item.product_id)">编辑</button>
                                    <button v-if="type_active=='sell'" type="warn" class='shop_body_b_btn' @click="operation(item.product_id,20)">下架</button>
                                    <text v-if="type_active=='audit'" class="audit_txt">审核中</text>
                                    <button v-if="type_active=='lower'" type="warn" class='shop_body_b_btn' @click="operation(item.product_id,10)">上架</button>
@@ -35,13 +36,18 @@
                        </view>
                    </view>
                </view>
                <view class="d-c-c p30" v-if="product_list.length==0 && !loading">
                    <text class="iconfont icon-wushuju"></text>
                    <text class="cont">亲,暂无相关记录哦</text>
                </view>
                <uni-load-more v-else :loadingType="loadingType"></uni-load-more>
            </view>
            <view class="d-c-c p30" v-if="product_list.length==0 && !loading">
                <text class="iconfont icon-wushuju"></text>
                <text class="cont">亲,暂无相关记录哦</text>
            </view>
            <uni-load-more v-else :loadingType="loadingType"></uni-load-more>
        </scroll-view>
        <!-- 添加商品按钮 -->
        <view class="add-product-btn" @click="addProduct">
            <text class="btn-text">+ 添加商品</text>
        </view>
    </view>
</template>
@@ -202,6 +208,20 @@
                    self.getData(self.type_active);
                    
                })
            },
            // 添加商品
            addProduct() {
                uni.navigateTo({
                    url: '/pages/user/my_shop/product_add?shop_supplier_id=' + this.shop_supplier_id
                });
            },
            // 编辑商品
            editProduct(product_id) {
                uni.navigateTo({
                    url: '/pages/user/my_shop/product_edit?product_id=' + product_id + '&shop_supplier_id=' + this.shop_supplier_id
                });
            }
        }
    }
@@ -674,4 +694,29 @@
        font-size: 23rpx;
        margin-right: 26rpx;
    }
    /* 添加商品按钮样式 */
    .add-product-btn {
        width: 90%;
        height: 70rpx;
        background-color: #e62423;
        color: #fff;
        border-radius: 35rpx;
        display: flex;
        align-items: center;
        justify-content: center;
        margin: 20rpx auto;
        font-size: 28rpx;
        box-shadow: 0 4rpx 10rpx rgba(230, 36, 35, 0.3);
    }
    .btn-text {
        color: #fff;
    }
    /* 编辑按钮样式 */
    .edit-btn {
        background-color: #409eff;
        color: #fff;
    }
</style>
mobile/pages/user/my_shop/product_add.vue
New file
@@ -0,0 +1,1778 @@
<template>
    <view class="product-add">
        <!-- 标签页 -->
        <view class="tab-bar">
            <scroll-view scroll-x="true" class="tab-scroll">
                <view class="tab-item" :class="{ active: activeTab === 'basic' }" @click="switchTab('basic')">基础设置
                </view>
                <view class="tab-item" :class="{ active: activeTab === 'spec' }" @click="switchTab('spec')">规格库存</view>
                <view class="tab-item" :class="{ active: activeTab === 'content' }" @click="switchTab('content')">商品详情
                </view>
                <view class="tab-item" :class="{ active: activeTab === 'buyset' }" @click="switchTab('buyset')">高级设置
                </view>
            </scroll-view>
        </view>
        <!-- 表单内容 -->
        <scroll-view scroll-y="true" class="form-scroll">
            <!-- 基础设置 -->
            <view v-show="activeTab === 'basic'" class="form-section">
                <view class="form-item">
                    <view class="item-label">商品名称</view>
                    <input class="item-input" v-model="form.model.product_name" placeholder="请输入商品名称" />
                </view>
                <view class="form-item">
                    <view class="item-label">商品编码</view>
                    <input class="item-input" v-model="form.model.product_no" placeholder="请输入商品编码" />
                </view>
                <view class="form-item">
                    <view class="item-label">商品分类</view>
                    <picker class="item-picker" @change="categoryChange" :range="form.category" :range-key="'name'">
                        <view class="picker-text">{{ selectedCategory || '请选择商品分类' }}</view>
                    </picker>
                </view>
                <view class="form-item">
                    <view class="item-label">预告商品</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_preview === 1 }"
                            @click="form.model.is_preview = 1">开启</view>
                        <view class="radio-item" :class="{ active: form.model.is_preview === 0 }"
                            @click="form.model.is_preview = 0">关闭</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_preview === 1">
                    <view class="item-label">预告开启购买时间</view>
                    <picker mode="datetime" class="item-picker" @change="previewTimeChange" :value="previewTimeArray">
                        <view class="picker-text">{{ previewTimeText || '请选择预告时间' }}</view>
                    </picker>
                </view>
                <view class="form-item">
                    <view class="item-label">销售状态</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.product_status === 10 }"
                            @click="form.model.product_status = 10">立即上架</view>
                        <view class="radio-item" :class="{ active: form.model.product_status === 20 }"
                            @click="form.model.product_status = 20">放入仓库</view>
                    </view>
                    <view class="form-tips">如果平台开启了商品审核,则商品审核通过后才能销售</view>
                </view>
                <view class="form-item" v-if="form.audit_setting.add_audit == 1 && form.model.scene == 'add'">
                    <view class="item-label">是否审核</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.audit_status === 0 }"
                            @click="form.model.audit_status = 0">提交审核</view>
                        <view class="radio-item" :class="{ active: form.model.audit_status === 40 }"
                            @click="form.model.audit_status = 40">保存草稿</view>
                    </view>
                    <view class="form-tips">当前平台开启了审核,审核通过后才能上架销售</view>
                </view>
                <view class="form-item">
                    <view class="item-label">商品图片</view>
                    <view class="uploader">
                        <view class="uploader-item" v-for="(item, index) in form.model.image" :key="index">
                            <image :src="item.file_path" class="uploader-image"></image>
                            <view class="uploader-delete" @click="deleteImage(index)">×</view>
                        </view>
                        <view class="uploader-add" @click="handleUpload('image')">+</view>
                    </view>
                    <!-- 上传组件 -->
                    <Upload v-if="showUpload && uploadType === 'image'" :isupload="showUpload && uploadType === 'image'" @getImgs="onUploadComplete" type='frontid'>上传图片</Upload>
                </view>
                <view class="form-item">
                    <view class="item-label">商品视频</view>
                    <view class="uploader">
                        <view v-if="form.model.video_id === 0" class="uploader-add" @click="handleUpload('video')">+
                        </view>
                        <view v-else class="uploader-item">
                            <video :src="form.model.video.file_path" class="uploader-video" controls></video>
                            <view class="uploader-delete" @click="deleteVideo">×</view>
                        </view>
                    </view>
                    <!-- 上传组件 -->
                <upload v-if="showUpload && uploadType === 'video'" :num="1" file_type="video"
                    @getImgs="onUploadComplete"></upload>
                </view>
                <view class="form-item">
                    <view class="item-label">视频封面</view>
                    <view class="uploader">
                        <view v-if="form.model.poster_id === 0" class="uploader-add" @click="handleUpload('poster')">+
                        </view>
                        <view v-else class="uploader-item">
                            <image :src="form.model.poster.file_path" class="uploader-image"></image>
                            <view class="uploader-delete" @click="deletePoster">×</view>
                        </view>
                    </view>
                    <!-- 上传组件 -->
                    <uploadOne v-if="showUploadOne && uploadType === 'poster'" @getImgs="onUploadComplete"></uploadOne>
                </view>
                <view class="form-item">
                    <view class="item-label">商品卖点</view>
                    <textarea class="item-textarea" v-model="form.model.selling_point" placeholder="请输入商品卖点"
                        :auto-height="true"></textarea>
                </view>
                <view class="form-item">
                    <view class="item-label">商品属性</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_virtual === 0 }"
                            @click="form.model.is_virtual = 0">实物商品</view>
                        <view class="radio-item" :class="{ active: form.model.is_virtual === 1 }"
                            @click="form.model.is_virtual = 1">虚拟商品</view>
                        <view class="radio-item" :class="{ active: form.model.is_virtual === 2 }"
                            @click="form.model.is_virtual = 2">券商品</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_virtual === 0">
                    <view class="item-label">运费设置</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_delivery_free === 0 }"
                            @click="form.model.is_delivery_free = 0">包邮</view>
                        <view class="radio-item" :class="{ active: form.model.is_delivery_free === 1 }"
                            @click="form.model.is_delivery_free = 1">运费模板</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_delivery_free === 1">
                    <view class="item-label">选择运费模板</view>
                    <picker class="item-picker" @change="deliveryChange" :range="form.delivery" range-key="name">
                        <view class="picker-text">{{ selectedDelivery || '请选择运费模板' }}</view>
                    </picker>
                </view>
                <view class="form-item">
                    <view class="item-label">商品排序</view>
                    <input class="item-input" v-model="form.model.product_sort" placeholder="请输入商品排序" type="number" />
                </view>
                <view class="form-item">
                    <view class="item-label">限购数量</view>
                    <input class="item-input" v-model="form.model.limit_num" placeholder="请输入限购数量,0为不限购"
                        type="number" />
                </view>
                <!-- 虚拟商品设置 -->
                <view class="form-item" v-if="form.model.is_virtual === 1">
                    <view class="item-label">发货类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.virtual_auto === 1 }"
                            @click="form.model.virtual_auto = 1">自动</view>
                        <view class="radio-item" :class="{ active: form.model.virtual_auto === 0 }"
                            @click="form.model.virtual_auto = 0">手动</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_virtual === 1">
                    <view class="item-label">虚拟内容</view>
                    <input class="item-input" v-model="form.model.virtual_content" placeholder="请输入虚拟物品内容" />
                </view>
                <view class="form-item" v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0">
                    <view class="item-label">支持线下核销</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_verify === 1 }"
                            @click="form.model.is_verify = 1">支持</view>
                        <view class="radio-item" :class="{ active: form.model.is_verify === 0 }"
                            @click="form.model.is_verify = 0">不支持</view>
                    </view>
                </view>
                <view class="form-item"
                    v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1">
                    <view class="item-label">核销到期类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.verify_type === 10 }"
                            @click="form.model.verify_type = 10">按天数</view>
                        <view class="radio-item" :class="{ active: form.model.verify_type === 20 }"
                            @click="form.model.verify_type = 20">按固定时间</view>
                    </view>
                </view>
                <view class="form-item"
                    v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 10">
                    <view class="item-label">核销有效天数</view>
                    <input class="item-input" v-model="form.model.verify_day" placeholder="请输入有效天数,0或留空表示永久有效"
                        type="number" />
                </view>
                <view class="form-item"
                    v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 20">
                    <view class="item-label">核销有效时间</view>
                    <picker mode="daterange" class="item-picker" @change="verifyTimeChange" :value="verifyTimeArray">
                        <view class="picker-text">{{ verifyTimeText || '请选择核销有效时间' }}</view>
                    </picker>
                </view>
                <!-- 券商品设置 -->
                <view class="form-item" v-if="form.model.is_virtual === 2">
                    <view class="item-label">抵扣金额</view>
                    <input class="item-input" v-model="form.model.deduction_price" placeholder="请输入抵扣金额" type="digit" />
                    <view class="form-tips">该券线下核销时,实际抵扣的金额</view>
                </view>
            </view>
            <!-- 规格库存 -->
            <view v-show="activeTab === 'spec'" class="form-section">
                <view class="form-item">
                    <view class="item-label">库存计算方式</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.deduct_stock_type === 10 }"
                            @click="form.model.deduct_stock_type = 10">下单减库存</view>
                        <view class="radio-item" :class="{ active: form.model.deduct_stock_type === 20 }"
                            @click="form.model.deduct_stock_type = 20">付款减库存</view>
                    </view>
                </view>
                <view class="form-item">
                    <view class="item-label">规格类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.spec_type === 10 }"
                            @click="form.model.spec_type = 10">单规格</view>
                        <view class="radio-item" :class="{ active: form.model.spec_type === 20 }"
                            @click="form.model.spec_type = 20">多规格</view>
                    </view>
                </view>
                <!-- 单规格 -->
                <view v-if="form.model.spec_type === 10" class="spec-single">
                    <view class="form-item">
                        <view class="item-label">产品编码</view>
                        <input class="item-input" v-model="form.model.sku.product_no" placeholder="请输入产品编码" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">产品价格</view>
                        <input class="item-input" v-model="form.model.sku.product_price" placeholder="请输入产品价格" type="digit" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">产品划线价</view>
                        <input class="item-input" v-model="form.model.sku.line_price" placeholder="请输入产品划线价"
                            type="digit" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">库存数量</view>
                        <input class="item-input" v-model="form.model.sku.stock_num" placeholder="请输入库存数量" type="number" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">商品重量(Kg)</view>
                        <input class="item-input" v-model="form.model.sku.product_weight" placeholder="请输入商品重量(Kg)"
                            type="digit" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">商品条码</view>
                        <input class="item-input" v-model="form.model.sku.bar_code" placeholder="请输入商品条码" />
                    </view>
                </view>
                <!-- 多规格 -->
                <view v-else class="spec-many">
                    <view class="form-item">
                        <view class="item-label">规格属性</view>
                        <view class="spec-attrs">
                            <view class="spec-attr" v-for="(attr, index) in form.model.spec_many.spec_attr"
                                :key="index">
                                <view class="attr-header">
                                    <view class="attr-name">{{ attr.name }}</view>
                                    <view class="attr-delete" @click="deleteSpecAttr(index)">×</view>
                                </view>
                                <view class="attr-values">
                                    <view class="attr-value" v-for="(value, vIndex) in attr.values" :key="vIndex">
                                        <text>{{ value }}</text>
                                        <view class="value-delete" @click="deleteSpecValue(index, vIndex)">×</view>
                                    </view>
                                    <view class="attr-add-value" @click="addSpecValue(index)">+ 添加值</view>
                                </view>
                            </view>
                            <view class="add-spec-attr" @click="addSpecAttr">+ 添加规格属性</view>
                        </view>
                    </view>
                    <view class="form-item" v-if="form.model.spec_many.spec_attr.length > 0">
                        <view class="item-label">SKU列表</view>
                        <view class="sku-list">
                            <view class="sku-item" v-for="(sku, index) in form.model.spec_many.spec_list" :key="index">
                                <view class="sku-info">{{ sku.spec_text }}</view>
                                <view class="form-item">
                                    <view class="item-label">规格图片</view>
                                    <view class="uploader">
                                        <view class="uploader-item" v-if="sku.image && sku.image.length > 0">
                                            <image :src="sku.image[0]" class="uploader-image"></image>
                                            <view class="uploader-delete" @click="deleteSkuImage(index)">×</view>
                                        </view>
                                        <view class="uploader-add" @click="handleUpload('sku', index)">+</view>
                                    </view>
                                    <!-- 上传组件 -->
                                    <uploadOne v-if="showUploadOne && uploadType === 'sku'" @getImgs="onUploadComplete">
                                    </uploadOne>
                                </view>
                                <view class="sku-inputs">
                                    <input class="sku-input" v-model="sku.spec_form.product_no" placeholder="产品编码" />
                                    <input class="sku-input" v-model="sku.spec_form.product_price" placeholder="产品价格" type="digit" />
                                    <input class="sku-input" v-model="sku.spec_form.line_price" placeholder="产品划线价"
                                        type="digit" />
                                    <input class="sku-input" v-model="sku.spec_form.stock_num" placeholder="库存数量" type="number" />
                                    <input class="sku-input" v-model="sku.spec_form.product_weight" placeholder="商品重量(Kg)" type="digit" />
                                </view>
                            </view>
                        </view>
                    </view>
                </view>
            </view>
            <!-- 商品详情 -->
            <view v-show="activeTab === 'content'" class="form-section">
                <view class="form-item">
                    <view class="item-label">详情类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.content_type === 10 }"
                            @click="form.model.content_type = 10">图文</view>
                        <view class="radio-item" :class="{ active: form.model.content_type === 20 }"
                            @click="form.model.content_type = 20">纯图</view>
                    </view>
                </view>
                <!-- 图文类型 -->
                <view v-if="form.model.content_type === 10" class="form-item">
                    <view class="item-label">商品详情</view>
                    <view class="editor">
                        <!-- 富文本编辑器 -->
                        <view class='wrapper'>
                            <view class='toolbar' @tap="format" style="height: 160px;overflow-y: auto;">
                                <view :class="formats.bold ? 'ql-active' : ''" class="iconfont icon-zitijiacu"
                                    data-name="bold">
                                </view>
                                <view :class="formats.italic ? 'ql-active' : ''" class="iconfont icon-zitixieti"
                                    data-name="italic">
                                </view>
                                <view :class="formats.underline ? 'ql-active' : ''" class="iconfont icon-zitixiahuaxian"
                                    data-name="underline"></view>
                                <view :class="formats.strike ? 'ql-active' : ''" class="iconfont icon-zitishanchuxian"
                                    data-name="strike"></view>
                                <!-- #ifndef MP-BAIDU -->
                                <view :class="formats.align === 'left' ? 'ql-active' : ''"
                                    class="iconfont icon-zuoduiqi" data-name="align" data-value="left"></view>
                                <!-- #endif -->
                                <view :class="formats.align === 'center' ? 'ql-active' : ''"
                                    class="iconfont icon-juzhongduiqi" data-name="align" data-value="center"></view>
                                <view :class="formats.align === 'right' ? 'ql-active' : ''"
                                    class="iconfont icon-youduiqi" data-name="align" data-value="right"></view>
                                <view :class="formats.align === 'justify' ? 'ql-active' : ''"
                                    class="iconfont icon-zuoyouduiqi" data-name="align" data-value="justify"></view>
                                <!-- #ifndef MP-BAIDU -->
                                <view :class="formats.lineHeight ? 'ql-active' : ''" class="iconfont icon-line-height"
                                    data-name="lineHeight" data-value="2"></view>
                                <view :class="formats.letterSpacing ? 'ql-active' : ''"
                                    class="iconfont icon-Character-Spacing" data-name="letterSpacing" data-value="2em">
                                </view>
                                <view :class="formats.marginTop ? 'ql-active' : ''"
                                    class="iconfont icon-722bianjiqi_duanqianju" data-name="marginTop"
                                    data-value="20px"></view>
                                <view :class="formats.marginBottom ? 'ql-active' : ''"
                                    class="iconfont icon-723bianjiqi_duanhouju" data-name="marginBottom"
                                    data-value="20px"></view>
                                <!-- #endif -->
                                <view class="iconfont icon-clearedformat" @tap="removeFormat"></view>
                                <!-- #ifndef MP-BAIDU -->
                                <view :class="formats.fontFamily ? 'ql-active' : ''" class="iconfont icon-font"
                                    data-name="fontFamily" data-value="Pacifico"></view>
                                <view :class="formats.fontSize === '24px' ? 'ql-active' : ''"
                                    class="iconfont icon-fontsize" data-name="fontSize" data-value="24px"></view>
                                <!-- #endif -->
                                <view :class="formats.color === '#0000ff' ? 'ql-active' : ''"
                                    class="iconfont icon-text_color" data-name="color" data-value="#0000ff"></view>
                                <view :class="formats.backgroundColor === '#00ff00' ? 'ql-active' : ''"
                                    class="iconfont icon-fontbgcolor" data-name="backgroundColor" data-value="#00ff00">
                                </view>
                                <view class="iconfont icon-date" @tap="insertDate"></view>
                                <view class="iconfont icon--checklist" data-name="list" data-value="check"></view>
                                <view :class="formats.list === 'ordered' ? 'ql-active' : ''"
                                    class="iconfont icon-youxupailie" data-name="list" data-value="ordered"></view>
                                <view :class="formats.list === 'bullet' ? 'ql-active' : ''"
                                    class="iconfont icon-wuxupailie" data-name="list" data-value="bullet"></view>
                                <view class="iconfont icon-undo" @tap="undo"></view>
                                <view class="iconfont icon-redo" @tap="redo"></view>
                                <view class="iconfont icon-outdent" data-name="indent" data-value="-1"></view>
                                <view class="iconfont icon-indent" data-name="indent" data-value="+1"></view>
                                <view class="iconfont icon-fengexian" @tap="insertDivider"></view>
                                <view class="iconfont icon-charutupian" @tap="insertImage"></view>
                                <view :class="formats.header === 1 ? 'ql-active' : ''"
                                    class="iconfont icon-format-header-1" data-name="header" :data-value="1"></view>
                                <view :class="formats.script === 'sub' ? 'ql-active' : ''"
                                    class="iconfont icon-zitixiabiao" data-name="script" data-value="sub"></view>
                                <view :class="formats.script === 'super' ? 'ql-active' : ''"
                                    class="iconfont icon-zitishangbiao" data-name="script" data-value="super"></view>
                                <view class="iconfont icon-shanchu" @tap="clear"></view>
                                <view :class="formats.direction === 'rtl' ? 'ql-active' : ''"
                                    class="iconfont icon-direction-rtl" data-name="direction" data-value="rtl"></view>
                            </view>
                            <view class="editor-wrapper">
                                <editor id="editor" class="ql-container" placeholder="开始输入..." show-img-size
                                    show-img-toolbar show-img-resize @statuschange="onStatusChange"
                                    :read-only="readOnly" @ready="onEditorReady">
                                </editor>
                            </view>
                        </view>
                    </view>
                </view>
                <!-- 纯图类型 -->
                <view v-else-if="form.model.content_type === 20" class="form-item">
                    <view class="item-label">商品详情图片</view>
                    <view class="uploader">
                        <view class="uploader-item" v-for="(item, index) in form.model.contentImage" :key="index">
                            <image :src="item.file_path" class="uploader-image"></image>
                            <view class="uploader-delete" @click="deleteContentImage(index)">×</view>
                        </view>
                        <view class="uploader-add" @click="handleUpload('content')">+</view>
                    </view>
                    <view class="editor-tips">提示:最多上传20张图片</view>
                    <!-- 上传组件 -->
                    <upload v-if="showUpload && uploadType === 'content'" :isupload="showUpload && uploadType === 'content'" :num="20 - form.model.contentImage.length"
                        @getImgs="onUploadComplete"></upload>
                </view>
            </view>
            <!-- 高级设置 -->
            <view v-show="activeTab === 'buyset'" class="form-section">
                <!-- 积分设置 -->
                <view class="form-item">
                    <view class="item-label">积分设置</view>
                    <view class="switch-item">
                        <view class="switch-label">开启积分赠送</view>
                        <switch v-model="form.model.is_points_gift" />
                    </view>
                    <view class="switch-item">
                        <view class="switch-label">允许积分抵扣</view>
                        <switch v-model="form.model.is_points_discount" />
                    </view>
                    <view class="form-item-inner" v-if="form.model.is_points_discount">
                        <view class="inner-label">最大积分抵扣数量</view>
                        <input class="inner-input" v-model="form.model.max_points_discount" placeholder="请输入最大积分抵扣数量"
                            type="number" />
                    </view>
                </view>
                <!-- 分销设置 -->
                <view class="form-item">
                    <view class="item-label">团队分红设置</view>
                    <view class="switch-item">
                        <view class="switch-label">是否参与团队分红</view>
                        <switch checked v-model="form.model.is_enable_team" />
                    </view>
                </view>
            </view>
        </scroll-view>
        <!-- 底部操作栏 -->
        <view class="bottom-bar">
            <view class="bar-item" @click="back">返回</view>
            <view class="bar-item save-btn" @click="save">保存</view>
        </view>
    </view>
</template>
<script>
    import Upload from '@/components/upload/upload';
    import UploadOne from '@/components/upload/uploadOne.vue';
    export default {
        components: {
            Upload,
            UploadOne
        },
        data() {
            const now = new Date();
            return {
                activeTab: 'basic',
                loading: false,
                // 预告时间相关
                previewTimeArray: [now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes()],
                previewTimeText: '',
                // 核销时间相关
                verifyTimeArray: [],
                verifyTimeText: '',
                // 上传组件控制
                showUpload: false,
                showUploadOne: false,
                // 当前操作的类型和索引
                uploadType: '', // image, video, poster, sku, content
                currentSkuIndex: -1,
                form: {
                    model: {
                        scene: 'add',
                        product_name: '',
                        product_no: '',
                        category_id: null,
                        image: [],
                        is_picture: 0,
                        contentImage: [],
                        video_id: 0,
                        video: {},
                        poster_id: 0,
                        poster: {},
                        selling_point: '',
                        spec_type: 10,
                        deduct_stock_type: 20,
                        content_type: 10,
                        sku: {
                            product_no: '',
                            product_price: '',
                            line_price: '',
                            stock_num: 0,
                            product_weight: 0,
                            bar_code: ''
                        },
                        spec_many: {
                            spec_attr: [],
                            spec_list: []
                        },
                        content: '',
                        notice: '',
                        is_delivery_free: 0,
                        delivery_id: '',
                        product_status: 10,
                        audit_status: 0,
                        product_sort: 100,
                        is_points_gift: 1,
                        is_points_discount: 1,
                        max_points_discount: 0,
                        is_agent: 0,
                        is_enable_team: 1,
                        is_ind_agent: 0,
                        agent_money_type: 10,
                        first_money: 0,
                        second_money: 0,
                        third_money: 0,
                        is_virtual: 0,
                        limit_num: 0,
                        deduction_price: 0,
                        virtual_auto: 0,
                        virtual_content: '',
                        is_preview: 0,
                        preview_time: '',
                        is_verify: 0,
                        verify_type: 10,
                        verify_day: '',
                        verify_time: [],
                        verify_store_ids: [],
                    },
                    category: [],
                    delivery: [],
                    gradeList: [],
                    specData: null,
                    isSpecLocked: false,
                    basicSetting: {},
                    agentSetting: {},
                    audit_setting: {},
                    verifyStoreList: [],
                },
                selectedCategory: '',
                selectedDelivery: ''
            };
        },
        onLoad() {
            this.getBaseData();
        },
        methods: {
            // 返回上一页
            back() {
                uni.navigateBack();
            },
            // 切换标签页
            switchTab(tab) {
                this.activeTab = tab;
            },
            // 获取基础数据
            getBaseData() {
                let self = this;
                self.loading = true;
                self._post('supplier.product/getBaseData', {}, (res) => {
                    if (res.code === 1) {
                        Object.assign(self.form, res.data);
                    }
                    self.loading = false;
                });
            },
            // 选择商品分类
            categoryChange(e) {
                const index = e.detail.value;
                this.form.model.category_id = this.form.category[index].category_id;
                this.selectedCategory = this.form.category[index].name;
            },
            // 处理上传
            handleUpload(type, index = -1) {
                this.uploadType = type;
                if (type === 'image' || type === 'content' || type === 'video') {
                    this.showUpload = true;
                } else {
                    this.showUploadOne = true;
                }
                // 记录当前操作的SKU索引
                this.currentSkuIndex = index;
            },
            // 上传完成回调
            onUploadComplete(res) {
                // 关闭上传组件
                this.showUpload = false;
                this.showUploadOne = false;
                if (!res || res.length === 0) return;
                // 根据上传类型处理结果
                switch (this.uploadType) {
                    case 'image':
                        // 商品图片,多个文件
                        res.forEach(item => {
                            this.form.model.image.push(item);
                        });
                        break;
                    case 'video':
                        // 商品视频,单个文件
                        this.form.model.video = res[0];
                        this.form.model.video_id = res[0].id || 1;
                        break;
                    case 'poster':
                        // 视频封面,单个文件
                        this.form.model.poster = res[0];
                        this.form.model.poster_id = res[0].id || 1;
                        break;
                    case 'sku':
                        // SKU图片,单个文件
                        if (this.currentSkuIndex !== -1) {
                            this.form.model.spec_many.spec_list[this.currentSkuIndex].image = [res[0].file_path];
                        }
                        break;
                    case 'content':
                        // 详情图片,多个文件
                        res.forEach(item => {
                            this.form.model.contentImage.push(item);
                        });
                        break;
                }
            },
            // 删除图片
            deleteImage(index) {
                this.form.model.image.splice(index, 1);
            },
            // 选择运费模板
            deliveryChange(e) {
                const index = e.detail.value;
                this.form.model.delivery_id = this.form.delivery[index].delivery_id;
                this.selectedDelivery = this.form.delivery[index].name;
            },
            // 选择预告时间
            previewTimeChange(e) {
                const date = new Date(e.detail.value);
                this.form.model.preview_time = date.toISOString().slice(0, 19).replace('T', ' ');
                this.previewTimeText =
                    `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
            },
            // 删除视频
            deleteVideo() {
                this.form.model.video = {};
                this.form.model.video_id = 0;
            },
            // 删除视频封面
            deletePoster() {
                this.form.model.poster = {};
                this.form.model.poster_id = 0;
            },
            // 选择核销时间
            verifyTimeChange(e) {
                const startDate = new Date(e.detail.value[0]);
                const endDate = new Date(e.detail.value[1]);
                this.form.model.verify_time = [
                    startDate.toISOString().slice(0, 10),
                    endDate.toISOString().slice(0, 10)
                ];
                this.verifyTimeText =
                    `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')} 至 ${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`;
            },
            // 删除SKU图片
            deleteSkuImage(index) {
                this.form.model.spec_many.spec_list[index].image = [];
            },
            // 删除详情图片
            deleteContentImage(index) {
                this.form.model.contentImage.splice(index, 1);
            },
            // 添加规格属性
            addSpecAttr() {
                uni.showModal({
                    title: '添加规格属性',
                    content: '',
                    editable: true,
                    placeholderText: '例如:颜色',
                    success: (res) => {
                        if (res.confirm && res.content.trim()) {
                            this.form.model.spec_many.spec_attr.push({
                                name: res.content.trim(),
                                values: []
                            });
                            // 生成SKU列表
                            this.generateSkuList();
                        }
                    }
                });
            },
            // 删除规格属性
            deleteSpecAttr(index) {
                this.form.model.spec_many.spec_attr.splice(index, 1);
                // 重新生成SKU列表
                this.generateSkuList();
            },
            // 添加规格值
            addSpecValue(attrIndex) {
                uni.showModal({
                    title: '添加规格值',
                    content: '',
                    editable: true,
                    placeholderText: '例如:红色',
                    success: (res) => {
                        if (res.confirm && res.content.trim()) {
                            const attr = this.form.model.spec_many.spec_attr[attrIndex];
                            attr.values.push(res.content.trim());
                            // 重新生成SKU列表
                            this.generateSkuList();
                        }
                    }
                });
            },
            // 删除规格值
            deleteSpecValue(attrIndex, valueIndex) {
                const attr = this.form.model.spec_many.spec_attr[attrIndex];
                if (attr.values.length > 1) {
                    attr.values.splice(valueIndex, 1);
                    // 重新生成SKU列表
                    this.generateSkuList();
                }
            },
            // 生成SKU列表
            generateSkuList() {
                const attrs = this.form.model.spec_many.spec_attr;
                if (attrs.length === 0) {
                    this.form.model.spec_many.spec_list = [];
                    return;
                }
                // 生成所有可能的组合
                const combinations = this.getCombinations(attrs);
                // 生成SKU列表
                const skuList = combinations.map(comb => {
                    const spec_text = comb.map((val, idx) => `${attrs[idx].name}:${val}`).join('; ');
                    return {
                        spec_text,
                        image: [],
                        product_no: '',
                        price: '',
                        line_price: '',
                        stock: '',
                        weight: '',
                        cost_price: '',
                        bar_code: ''
                    };
                });
                this.form.model.spec_many.spec_list = skuList;
            },
            // 获取规格值组合
            getCombinations(attrs) {
                if (attrs.length === 0) return [
                    []
                ];
                const firstAttr = attrs[0];
                const remainingAttrs = attrs.slice(1);
                const remainingCombinations = this.getCombinations(remainingAttrs);
                const result = [];
                for (const value of firstAttr.values) {
                    for (const combination of remainingCombinations) {
                        result.push([value, ...combination]);
                    }
                }
                return result;
            },
            // 保存商品
            save() {
                let self = this;
                // 先获取富文本编辑器内容
                if (self.form.model.content_type === 10 && self.editorCtx) {
                    // 图文类型,获取编辑器内容
                    self.editorCtx.getContents({
                        success: (res) => {
                            // 将编辑器内容赋值给表单字段
                            self.form.model.content = res.html;
                            // 继续执行保存逻辑
                            self.doSave();
                        },
                        fail: () => {
                            // 获取内容失败,继续执行保存逻辑
                            self.doSave();
                        }
                    });
                    return;
                } else {
                    // 非图文类型或编辑器未初始化,直接执行保存逻辑
                    self.doSave();
                }
            },
            // 实际保存逻辑
            doSave() {
                let self = this;
                // 表单验证
                if (!self.form.model.product_name) {
                    uni.showToast({
                        title: '请输入商品名称',
                        icon: 'none'
                    });
                    return;
                }
                if (!self.form.model.category_id) {
                    uni.showToast({
                        title: '请选择商品分类',
                        icon: 'none'
                    });
                    return;
                }
                if (self.form.model.image.length === 0) {
                    uni.showToast({
                        title: '请上传商品图片',
                        icon: 'none'
                    });
                    return;
                }
                // 规格库存验证
                if (self.form.model.spec_type === 10) {
                    // 单规格验证
                    if (!self.form.model.sku.product_price || parseFloat(self.form.model.sku.product_price) <= 0) {
                        uni.showToast({
                            title: '请输入有效的商品价格',
                            icon: 'none'
                        });
                        return;
                    }
                    if (!self.form.model.sku.stock_num || parseInt(self.form.model.sku.stock_num) < 0) {
                        uni.showToast({
                            title: '请输入有效的库存数量',
                            icon: 'none'
                        });
                        return;
                    }
                } else {
                    // 多规格验证
                    if (self.form.model.spec_many.spec_attr.length === 0) {
                        uni.showToast({
                            title: '请添加规格属性',
                            icon: 'none'
                        });
                        return;
                    }
                    for (let i = 0; i < self.form.model.spec_many.spec_list.length; i++) {
                        const sku = self.form.model.spec_many.spec_list[i];
                        if (!sku.spec_form.product_price || parseFloat(sku.spec_form.product_price) <= 0) {
                            uni.showToast({
                                title: '请输入有效的SKU价格',
                                icon: 'none'
                            });
                            return;
                        }
                        if (!sku.spec_form.stock_num || parseInt(sku.spec_form.stock_num) < 0) {
                            uni.showToast({
                                title: '请输入有效的SKU库存',
                                icon: 'none'
                            });
                            return;
                        }
                    }
                }
                // 根据详情类型验证内容
                if (self.form.model.content_type === 10) {
                    // 图文类型,验证富文本内容
                    if (!self.form.model.content || self.form.model.content.trim() === '') {
                        uni.showToast({
                            title: '请输入商品详情',
                            icon: 'none'
                        });
                        return;
                    }
                } else if (self.form.model.content_type === 20) {
                    // 纯图类型,验证详情图片
                    if (self.form.model.contentImage.length === 0) {
                        uni.showToast({
                            title: '请上传商品详情图片',
                            icon: 'none'
                        });
                        return;
                    }
                }
                self.loading = true;
                self._post('supplier.product/add', {
                    params: JSON.stringify(self.form.model)
                }, (res) => {
                    if (res.code === 0) {
                        uni.showToast({
                            title: '保存成功'
                        });
                        setTimeout(() => {
                            uni.navigateBack();
                        }, 1500);
                    } else {
                        uni.showToast({
                            title: res.msg || '保存失败',
                            icon: 'none'
                        });
                    }
                    self.loading = false;
                });
            },
            readOnlyChange() {
                this.readOnly = !this.readOnly
            },
            onEditorReady() {
                // #ifdef MP-BAIDU
                this.editorCtx = requireDynamicLib('editorLib').createEditorContext('editor');
                // #endif
                // #ifdef APP-PLUS || MP-WEIXIN || H5
                uni.createSelectorQuery().select('#editor').context((res) => {
                    this.editorCtx = res.context
                }).exec()
                // #endif
            },
            undo() {
                this.editorCtx.undo()
            },
            redo() {
                this.editorCtx.redo()
            },
            format(e) {
                let {
                    name,
                    value
                } = e.target.dataset
                if (!name) return
                // console.log('format', name, value)
                this.editorCtx.format(name, value)
            },
            onStatusChange(e) {
                const formats = e.detail
                this.formats = formats
            },
            insertDivider() {
                this.editorCtx.insertDivider({
                    success: function() {
                        console.log('insert divider success')
                    }
                })
            },
            clear() {
                uni.showModal({
                    title: '清空编辑器',
                    content: '确定清空编辑器全部内容?',
                    success: res => {
                        if (res.confirm) {
                            this.editorCtx.clear({
                                success: function(res) {
                                    console.log("clear success")
                                }
                            })
                        }
                    }
                })
            },
            removeFormat() {
                this.editorCtx.removeFormat()
            },
            insertDate() {
                const date = new Date()
                const formatDate = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
                this.editorCtx.insertText({
                    text: formatDate
                })
            },
            insertImage() {
                uni.chooseImage({
                    count: 1,
                    success: (res) => {
                        this.editorCtx.insertImage({
                            src: res.tempFilePaths[0],
                            alt: '图像',
                            success: function() {
                                console.log('insert image success')
                            }
                        })
                    }
                })
            }
        }
    };
</script>
<style lang="scss">
    .product-add {
        background-color: #f2f2f2;
        min-height: 100vh;
        padding-bottom: 100rpx;
        /* 为底部操作栏留出空间 */
    }
    /* 底部操作栏 */
    .bottom-bar {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 100rpx;
        background-color: #fff;
        box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
        padding: 0 30rpx;
        box-sizing: border-box;
        z-index: 999;
    }
    .bar-item {
        flex: 1;
        height: 60rpx;
        line-height: 60rpx;
        text-align: center;
        font-size: 28rpx;
        border-radius: 30rpx;
        margin: 0 10rpx;
    }
    .bar-item:first-child {
        border: 1rpx solid #e0e0e0;
        color: #666;
    }
    .save-btn {
        background-color: #e62423;
        color: #fff;
        font-weight: bold;
    }
    .top-nav {
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 88rpx;
        background-color: #fff;
        padding: 0 30rpx;
        box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 999;
    }
    .nav-item {
        font-size: 28rpx;
        color: #666;
    }
    .nav-title {
        font-size: 32rpx;
        font-weight: bold;
        color: #333;
    }
    .tab-bar {
        background-color: #fff;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 998;
    }
    .tab-scroll {
        display: flex;
        white-space: nowrap;
        padding: 0 20rpx;
    }
    .tab-item {
        display: inline-block;
        padding: 20rpx 30rpx;
        font-size: 28rpx;
        color: #666;
        position: relative;
        height: auto;
    }
    .tab-item.active {
        color: #e62423;
    }
    .tab-item.active::after {
        content: '';
        position: absolute;
        bottom: 0;
        left: 50%;
        transform: translateX(-50%);
        width: 40rpx;
        height: 4rpx;
        background-color: #e62423;
        border-radius: 2rpx;
    }
    .form-scroll {
        padding-top: 80rpx;
        padding-bottom: 20rpx;
    }
    .form-section {
        background-color: #fff;
        margin-bottom: 20rpx;
        padding: 0 30rpx;
    }
    .form-item {
        padding: 30rpx 0;
        border-bottom: 1rpx solid #f0f0f0;
    }
    .form-item:last-child {
        border-bottom: none;
    }
    .item-label {
        font-size: 28rpx;
        color: #333;
        margin-bottom: 20rpx;
    }
    .item-input {
        width: 100%;
        height: 80rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 10rpx;
        padding: 0 20rpx;
        font-size: 28rpx;
        box-sizing: border-box;
    }
    .item-textarea {
        width: 100%;
        border: 1rpx solid #e0e0e0;
        border-radius: 10rpx;
        padding: 20rpx;
        font-size: 28rpx;
        box-sizing: border-box;
        min-height: 120rpx;
    }
    .item-picker {
        width: 100%;
        height: 80rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 10rpx;
        padding: 0 20rpx;
        font-size: 28rpx;
        box-sizing: border-box;
        display: flex;
        align-items: center;
        justify-content: space-between;
    }
    .picker-text {
        color: #666;
    }
    .uploader {
        display: flex;
        flex-wrap: wrap;
        gap: 20rpx;
    }
    .uploader-item {
        position: relative;
        width: 160rpx;
        height: 160rpx;
    }
    .uploader-image {
        width: 100%;
        height: 100%;
        border-radius: 10rpx;
    }
    .uploader-delete {
        position: absolute;
        top: -10rpx;
        right: -10rpx;
        width: 40rpx;
        height: 40rpx;
        background-color: rgba(0, 0, 0, 0.5);
        color: #fff;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 32rpx;
    }
    .uploader-add {
        width: 160rpx;
        height: 160rpx;
        border: 2rpx dashed #e0e0e0;
        border-radius: 10rpx;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 64rpx;
        color: #999;
    }
    .radio-group {
        display: flex;
        gap: 40rpx;
    }
    .radio-item {
        padding: 15rpx 30rpx;
        border: 2rpx solid #e0e0e0;
        border-radius: 50rpx;
        font-size: 28rpx;
        color: #666;
    }
    .radio-item.active {
        border-color: #e62423;
        color: #e62423;
        background-color: rgba(230, 36, 35, 0.1);
    }
    .switch-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20rpx;
    }
    .switch-item:last-child {
        margin-bottom: 0;
    }
    .switch-label {
        font-size: 28rpx;
        color: #666;
    }
    /* 规格管理样式 */
    .spec-attrs {
        margin-top: 20rpx;
    }
    .spec-attr {
        margin-bottom: 30rpx;
        padding: 20rpx;
        background-color: #f9f9f9;
        border-radius: 10rpx;
    }
    .attr-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20rpx;
    }
    .attr-name {
        font-size: 28rpx;
        color: #333;
        font-weight: bold;
    }
    .attr-delete {
        width: 40rpx;
        height: 40rpx;
        background-color: #ff4d4f;
        color: #fff;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 32rpx;
    }
    .attr-values {
        display: flex;
        flex-wrap: wrap;
        gap: 15rpx;
    }
    .attr-value {
        display: flex;
        align-items: center;
        padding: 10rpx 20rpx;
        background-color: #fff;
        border: 1rpx solid #e0e0e0;
        border-radius: 20rpx;
        font-size: 26rpx;
    }
    .value-delete {
        margin-left: 10rpx;
        color: #ff4d4f;
        font-size: 24rpx;
    }
    .attr-add-value {
        margin-top: 15rpx;
        padding: 10rpx 20rpx;
        background-color: #e6f7ff;
        color: #1890ff;
        border-radius: 20rpx;
        font-size: 26rpx;
        text-align: center;
        width: 120rpx;
    }
    .add-spec-attr {
        margin-top: 20rpx;
        padding: 15rpx;
        background-color: #f0f9eb;
        color: #52c41a;
        border-radius: 10rpx;
        font-size: 26rpx;
        text-align: center;
    }
    /* SKU列表样式 */
    .sku-list {
        margin-top: 20rpx;
    }
    .sku-item {
        margin-bottom: 20rpx;
        padding: 20rpx;
        background-color: #f9f9f9;
        border-radius: 10rpx;
    }
    .sku-info {
        font-size: 26rpx;
        color: #666;
        margin-bottom: 15rpx;
    }
    .sku-inputs {
        display: flex;
        flex-wrap: wrap;
        gap: 20rpx;
    }
    .sku-input {
        width: calc(50% - 10rpx);
        height: 70rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 8rpx;
        padding: 0 15rpx;
        font-size: 26rpx;
        box-sizing: border-box;
    }
    /* 商品详情样式 */
    .editor {
        position: relative;
    }
    .editor-tips {
        margin-top: 10rpx;
        font-size: 24rpx;
        color: #999;
    }
    /* 表单提示 */
    .form-tips {
        margin-top: 10rpx;
        font-size: 24rpx;
        color: #999;
    }
    /* 视频样式 */
    .uploader-video {
        width: 100%;
        height: 200rpx;
        border-radius: 10rpx;
    }
    /* 高级设置样式 */
    .form-item-inner {
        margin-top: 20rpx;
        padding-left: 40rpx;
    }
    .inner-label {
        font-size: 26rpx;
        color: #666;
        margin-bottom: 15rpx;
        display: block;
    }
    .inner-input {
        width: 100%;
        height: 70rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 8rpx;
        padding: 0 15rpx;
        font-size: 26rpx;
        box-sizing: border-box;
    }
    @font-face {
        font-family: iconfont;
        src: url("data:font/truetype;charset=utf-8;base64,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AAsAJgFuAAoAQwByAGUAYQB0AGUAZAAgAGIAeQAgAGkAYwBvAG4AZgBvAG4AdAAKAAAKQ3JlYXRlZCBieSBpY29uZm9udAoAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAFIAZQBnAHUAbABhAHIAAFJlZ3VsYXIAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAFYAZQByAHMAaQBvAG4AIAAxAC4AMAAAVmVyc2lvbiAxLjAAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AAEdlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC4AAGgAdAB0AHAAOgAvAC8AZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AAGh0dHA6Ly9mb250ZWxsby5jb20AAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOwAAAAEAAgECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4ATkEcmVkbwlzZWxlY3RhbGwHcHJldmlldwR1bmRvBGRhdGUHY2xlYXJ1cBU3MjNiaWFuamlxaV9kdWFuaG91anUWNzIyYmlhbmppcWlfZHVhbnFpYW5qdQotY2hlY2tsaXN0DWRpcmVjdGlvbi1sdHINZGlyZWN0aW9uLXJ0bAtmb250Ymdjb2xvcg1jbGVhcmVkZm9ybWF0BGZvbnQHb3V0ZGVudAhmb250c2l6ZQp0ZXh0X2NvbG9yD2Zvcm1hdC1oZWFkZXItMg9mb3JtYXQtaGVhZGVyLTMLbGluZS1oZWlnaHQPZm9ybWF0LWhlYWRlci0xD2Zvcm1hdC1oZWFkZXItNA9mb3JtYXQtaGVhZGVyLTUPZm9ybWF0LWhlYWRlci02EUNoYXJhY3Rlci1TcGFjaW5nBmluZGVudAZiYW9jdW4IcXVhbnBpbmcFZnV6aGkHc2hhbmNodQxiaWFuamlzZWt1YWkJZmVuZ2V4aWFuB2RpYW56YW4MY2hhcnVsaWFuamllC2NoYXJ1dHVwaWFuCnd1eHVwYWlsaWUManV6aG9uZ2R1aXFpB3lpbnlvbmcLeW91eHVwYWlsaWUIeW91ZHVpcWkJeml0aWRhaW1hCHhpYW9saWFuCXppdGlqaWFjdQ96aXRpc2hhbmNodXhpYW4Neml0aXNoYW5nYmlhbwp6aXRpYmlhb3RpDnppdGl4aWFodWF4aWFuCXppdGl4aWV0aQl6aXRpeWFuc2UIenVvZHVpcWkJeml0aXl1bGFuC3ppdGl4aWFiaWFvC3p1b3lvdWR1aXFpB2R1aWdvdXgGZ3VhbmJpDnNoZW5neWluX3NoaXRpAAAAAAAB//8AAgABAAAADAAAABYAAAACAAEAAwA6AAEABAAAAAIAAAAAAAAAAQAAAADVpCcIAAAAANhk6GIAAAAA2GToYg==") format("truetype");
        font-weight: 400;
        font-style: normal;
        font-display: swap
    }
    .iconfont {
        font-family: iconfont !important;
        font-size: 16px;
        font-style: normal;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale
    }
    .icon-redo:before {
        content: "\e627"
    }
    .icon-undo:before {
        content: "\e633"
    }
    .icon-indent:before {
        content: "\eb28"
    }
    .icon-outdent:before {
        content: "\e6e8"
    }
    .icon-fontsize:before {
        content: "\e6fd"
    }
    .icon-format-header-1:before {
        content: "\e860"
    }
    .icon-format-header-4:before {
        content: "\e863"
    }
    .icon-format-header-5:before {
        content: "\e864"
    }
    .icon-format-header-6:before {
        content: "\e865"
    }
    .icon-clearup:before {
        content: "\e64d"
    }
    .icon-preview:before {
        content: "\e631"
    }
    .icon-date:before {
        content: "\e63e"
    }
    .icon-fontbgcolor:before {
        content: "\e678"
    }
    .icon-clearedformat:before {
        content: "\e67e"
    }
    .icon-font:before {
        content: "\e684"
    }
    .icon-723bianjiqi_duanhouju:before {
        content: "\e65f"
    }
    .icon-722bianjiqi_duanqianju:before {
        content: "\e660"
    }
    .icon-text_color:before {
        content: "\e72c"
    }
    .icon-format-header-2:before {
        content: "\e75c"
    }
    .icon-format-header-3:before {
        content: "\e75d"
    }
    .icon--checklist:before {
        content: "\e664"
    }
    .icon-baocun:before {
        content: "\ec09"
    }
    .icon-line-height:before {
        content: "\e7f8"
    }
    .icon-quanping:before {
        content: "\ec13"
    }
    .icon-direction-rtl:before {
        content: "\e66e"
    }
    .icon-direction-ltr:before {
        content: "\e66d"
    }
    .icon-selectall:before {
        content: "\e62b"
    }
    .icon-fuzhi:before {
        content: "\ec7a"
    }
    .icon-shanchu:before {
        content: "\ec7b"
    }
    .icon-bianjisekuai:before {
        content: "\ec7c"
    }
    .icon-fengexian:before {
        content: "\ec7f"
    }
    .icon-dianzan:before {
        content: "\ec80"
    }
    .icon-charulianjie:before {
        content: "\ec81"
    }
    .icon-charutupian:before {
        content: "\ec82"
    }
    .icon-wuxupailie:before {
        content: "\ec83"
    }
    .icon-juzhongduiqi:before {
        content: "\ec84"
    }
    .icon-yinyong:before {
        content: "\ec85"
    }
    .icon-youxupailie:before {
        content: "\ec86"
    }
    .icon-youduiqi:before {
        content: "\ec87"
    }
    .icon-zitidaima:before {
        content: "\ec88"
    }
    .icon-xiaolian:before {
        content: "\ec89"
    }
    .icon-zitijiacu:before {
        content: "\ec8a"
    }
    .icon-zitishanchuxian:before {
        content: "\ec8b"
    }
    .icon-zitishangbiao:before {
        content: "\ec8c"
    }
    .icon-zitibiaoti:before {
        content: "\ec8d"
    }
    .icon-zitixiahuaxian:before {
        content: "\ec8e"
    }
    .icon-zitixieti:before {
        content: "\ec8f"
    }
    .icon-zitiyanse:before {
        content: "\ec90"
    }
    .icon-zuoduiqi:before {
        content: "\ec91"
    }
    .icon-zitiyulan:before {
        content: "\ec92"
    }
    .icon-zitixiabiao:before {
        content: "\ec93"
    }
    .icon-zuoyouduiqi:before {
        content: "\ec94"
    }
    .icon-duigoux:before {
        content: "\ec9e"
    }
    .icon-guanbi:before {
        content: "\eca0"
    }
    .icon-shengyin_shiti:before {
        content: "\eca5"
    }
    .icon-Character-Spacing:before {
        content: "\e964"
    }
    .page-body {
        height: calc(100vh - var(--window-top) - 0px)
    }
    .wrapper {
        height: 100%
    }
    .editor-wrapper {
        height: calc(100vh - var(--window-top) - 0px - 80px - 46px);
        background: #fff
    }
    .iconfont {
        display: inline-block;
        padding: 8px 8px;
        width: 24px;
        height: 24px;
        cursor: pointer;
        font-size: 20px
    }
    .toolbar {
        box-sizing: border-box;
        border-bottom: 0;
        font-family: Helvetica Neue, Helvetica, Arial, sans-serif
    }
    .ql-container {
        box-sizing: border-box;
        padding: 12px 15px;
        width: 100%;
        min-height: 30vh;
        height: 100%;
        /* margin-top: 20px; */
        font-size: 16px;
        line-height: 1.5
    }
    .ql-active {
        color: #06c
    }
    .iconfont {
        color: #000000;
    }
</style>
mobile/pages/user/my_shop/product_edit.vue
New file
@@ -0,0 +1,1878 @@
<template>
    <view class="product-edit">
        <!-- 标签页 -->
        <view class="tab-bar">
            <scroll-view scroll-x="true" class="tab-scroll">
                <view class="tab-item" :class="{ active: activeTab === 'basic' }" @click="switchTab('basic')">基础设置
                </view>
                <view class="tab-item" :class="{ active: activeTab === 'spec' }" @click="switchTab('spec')">规格库存</view>
                <view class="tab-item" :class="{ active: activeTab === 'content' }" @click="switchTab('content')">商品详情
                </view>
                <view class="tab-item" :class="{ active: activeTab === 'buyset' }" @click="switchTab('buyset')">高级设置
                </view>
            </scroll-view>
        </view>
        <!-- 表单内容 -->
        <scroll-view scroll-y="true" class="form-scroll">
            <!-- 基础设置 -->
            <view v-show="activeTab === 'basic'" class="form-section">
                <view class="form-item">
                    <view class="item-label">商品名称</view>
                    <input class="item-input" v-model="form.model.product_name" placeholder="请输入商品名称" />
                </view>
                <view class="form-item">
                    <view class="item-label">商品编码</view>
                    <input class="item-input" v-model="form.model.product_no" placeholder="请输入商品编码" />
                </view>
                <view class="form-item">
                    <view class="item-label">商品分类</view>
                    <picker class="item-picker" @change="categoryChange" :range="form.category" :range-key="'name'">
                        <view class="picker-text">{{ selectedCategory || '请选择商品分类' }}</view>
                    </picker>
                </view>
                <view class="form-item">
                    <view class="item-label">预告商品</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_preview === 1 }"
                            @click="form.model.is_preview = 1">开启</view>
                        <view class="radio-item" :class="{ active: form.model.is_preview === 0 }"
                            @click="form.model.is_preview = 0">关闭</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_preview === 1">
                    <view class="item-label">预告开启购买时间</view>
                    <picker mode="datetime" class="item-picker" @change="previewTimeChange" :value="previewTimeArray">
                        <view class="picker-text">{{ previewTimeText || '请选择预告时间' }}</view>
                    </picker>
                </view>
                <view class="form-item">
                    <view class="item-label">销售状态</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.product_status === 10 }"
                            @click="form.model.product_status = 10">立即上架</view>
                        <view class="radio-item" :class="{ active: form.model.product_status === 20 }"
                            @click="form.model.product_status = 20">放入仓库</view>
                    </view>
                    <view class="form-tips">如果平台开启了商品审核,则商品审核通过后才能销售</view>
                </view>
                <view class="form-item" v-if="form.audit_setting.add_audit == 1 && form.model.scene == 'add'">
                    <view class="item-label">是否审核</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.audit_status === 0 }"
                            @click="form.model.audit_status = 0">提交审核</view>
                        <view class="radio-item" :class="{ active: form.model.audit_status === 40 }"
                            @click="form.model.audit_status = 40">保存草稿</view>
                    </view>
                    <view class="form-tips">当前平台开启了审核,审核通过后才能上架销售</view>
                </view>
                <view class="form-item">
                    <view class="item-label">商品图片</view>
                    <view class="uploader">
                        <view class="uploader-item" v-for="(item, index) in form.model.image" :key="index">
                            <image :src="item.file_path" class="uploader-image"></image>
                            <view class="uploader-delete" @click="deleteImage(index)">×</view>
                        </view>
                        <view class="uploader-add" @click="handleUpload('image')">+</view>
                    </view>
                    <!-- 上传组件 -->
                    <Upload v-if="showUpload && uploadType === 'image'" :isupload="showUpload && uploadType === 'image'"
                        @getImgs="onUploadComplete" type='frontid'>上传图片</Upload>
                </view>
                <view class="form-item">
                    <view class="item-label">商品视频</view>
                    <view class="uploader">
                        <view v-if="form.model.video_id === 0" class="uploader-add" @click="handleUpload('video')">+
                        </view>
                        <view v-else class="uploader-item">
                            <video :src="form.model.video.file_path" class="uploader-video" controls></video>
                            <view class="uploader-delete" @click="deleteVideo">×</view>
                        </view>
                    </view>
                    <!-- 上传组件 -->
                    <upload v-if="showUpload && uploadType === 'video'" :num="1" file_type="video"
                        @getImgs="onUploadComplete"></upload>
                </view>
                <view class="form-item">
                    <view class="item-label">视频封面</view>
                    <view class="uploader">
                        <view v-if="form.model.poster_id === 0" class="uploader-add" @click="handleUpload('poster')">+
                        </view>
                        <view v-else class="uploader-item">
                            <image :src="form.model.poster.file_path" class="uploader-image"></image>
                            <view class="uploader-delete" @click="deletePoster">×</view>
                        </view>
                    </view>
                    <!-- 上传组件 -->
                    <uploadOne v-if="showUploadOne && uploadType === 'poster'" @getImgs="onUploadComplete"></uploadOne>
                </view>
                <view class="form-item">
                    <view class="item-label">商品卖点</view>
                    <textarea class="item-textarea" v-model="form.model.selling_point" placeholder="请输入商品卖点"
                        :auto-height="true"></textarea>
                </view>
                <view class="form-item">
                    <view class="item-label">商品属性</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_virtual === 0 }"
                            @click="form.model.is_virtual = 0">实物商品</view>
                        <view class="radio-item" :class="{ active: form.model.is_virtual === 1 }"
                            @click="form.model.is_virtual = 1">虚拟商品</view>
                        <view class="radio-item" :class="{ active: form.model.is_virtual === 2 }"
                            @click="form.model.is_virtual = 2">券商品</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_virtual === 0">
                    <view class="item-label">运费设置</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_delivery_free === 0 }"
                            @click="form.model.is_delivery_free = 0">包邮</view>
                        <view class="radio-item" :class="{ active: form.model.is_delivery_free === 1 }"
                            @click="form.model.is_delivery_free = 1">运费模板</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_delivery_free === 1">
                    <view class="item-label">选择运费模板</view>
                    <picker class="item-picker" @change="deliveryChange" :range="form.delivery" range-key="name">
                        <view class="picker-text">{{ selectedDelivery || '请选择运费模板' }}</view>
                    </picker>
                </view>
                <view class="form-item">
                    <view class="item-label">商品排序</view>
                    <input class="item-input" v-model="form.model.product_sort" placeholder="请输入商品排序" type="number" />
                </view>
                <view class="form-item">
                    <view class="item-label">限购数量</view>
                    <input class="item-input" v-model="form.model.limit_num" placeholder="请输入限购数量,0为不限购"
                        type="number" />
                </view>
                <!-- 虚拟商品设置 -->
                <view class="form-item" v-if="form.model.is_virtual === 1">
                    <view class="item-label">发货类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.virtual_auto === 1 }"
                            @click="form.model.virtual_auto = 1">自动</view>
                        <view class="radio-item" :class="{ active: form.model.virtual_auto === 0 }"
                            @click="form.model.virtual_auto = 0">手动</view>
                    </view>
                </view>
                <view class="form-item" v-if="form.model.is_virtual === 1">
                    <view class="item-label">虚拟内容</view>
                    <input class="item-input" v-model="form.model.virtual_content" placeholder="请输入虚拟物品内容" />
                </view>
                <view class="form-item" v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0">
                    <view class="item-label">支持线下核销</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.is_verify === 1 }"
                            @click="form.model.is_verify = 1">支持</view>
                        <view class="radio-item" :class="{ active: form.model.is_verify === 0 }"
                            @click="form.model.is_verify = 0">不支持</view>
                    </view>
                </view>
                <view class="form-item"
                    v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1">
                    <view class="item-label">核销到期类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.verify_type === 10 }"
                            @click="form.model.verify_type = 10">按天数</view>
                        <view class="radio-item" :class="{ active: form.model.verify_type === 20 }"
                            @click="form.model.verify_type = 20">按固定时间</view>
                    </view>
                </view>
                <view class="form-item"
                    v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 10">
                    <view class="item-label">核销有效天数</view>
                    <input class="item-input" v-model="form.model.verify_day" placeholder="请输入有效天数,0或留空表示永久有效"
                        type="number" />
                </view>
                <view class="form-item"
                    v-if="form.model.is_virtual === 1 && form.model.virtual_auto === 0 && form.model.is_verify === 1 && form.model.verify_type === 20">
                    <view class="item-label">核销有效时间</view>
                    <picker mode="daterange" class="item-picker" @change="verifyTimeChange" :value="verifyTimeArray">
                        <view class="picker-text">{{ verifyTimeText || '请选择核销有效时间' }}</view>
                    </picker>
                </view>
                <!-- 券商品设置 -->
                <view class="form-item" v-if="form.model.is_virtual === 2">
                    <view class="item-label">抵扣金额</view>
                    <input class="item-input" v-model="form.model.deduction_price" placeholder="请输入抵扣金额" type="digit" />
                    <view class="form-tips">该券线下核销时,实际抵扣的金额</view>
                </view>
            </view>
            <!-- 规格库存 -->
            <view v-show="activeTab === 'spec'" class="form-section">
                <view class="form-item">
                    <view class="item-label">库存计算方式</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.deduct_stock_type === 10 }"
                            @click="form.model.deduct_stock_type = 10">下单减库存</view>
                        <view class="radio-item" :class="{ active: form.model.deduct_stock_type === 20 }"
                            @click="form.model.deduct_stock_type = 20">付款减库存</view>
                    </view>
                </view>
                <view class="form-item">
                    <view class="item-label">规格类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.spec_type === 10 }"
                            @click="form.model.spec_type = 10">单规格</view>
                        <view class="radio-item" :class="{ active: form.model.spec_type === 20 }"
                            @click="form.model.spec_type = 20">多规格</view>
                    </view>
                </view>
                <!-- 单规格 -->
                <view v-if="form.model.spec_type === 10" class="spec-single">
                    <view class="form-item">
                        <view class="item-label">产品编码</view>
                        <input class="item-input" v-model="form.model.sku.product_no" placeholder="请输入产品编码" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">产品价格</view>
                        <input class="item-input" v-model="form.model.sku.product_price" placeholder="请输入产品价格"
                            type="digit" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">产品划线价</view>
                        <input class="item-input" v-model="form.model.sku.line_price" placeholder="请输入产品划线价"
                            type="digit" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">库存数量</view>
                        <input class="item-input" v-model="form.model.sku.stock_num" placeholder="请输入库存数量"
                            type="number" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">商品重量(Kg)</view>
                        <input class="item-input" v-model="form.model.sku.product_weight" placeholder="请输入商品重量(Kg)"
                            type="digit" />
                    </view>
                    <view class="form-item">
                        <view class="item-label">商品条码</view>
                        <input class="item-input" v-model="form.model.sku.bar_code" placeholder="请输入商品条码" />
                    </view>
                </view>
                <!-- 多规格 -->
                <view v-else class="spec-many">
                    <view class="form-item">
                        <view class="item-label">规格属性</view>
                        <view class="spec-attrs">
                            <view class="spec-attr" v-for="(attr, index) in form.model.spec_many.spec_attr"
                                :key="index">
                                <view class="attr-header">
                                    <view class="attr-name">{{ attr.name }}</view>
                                    <view class="attr-delete" @click="deleteSpecAttr(index)">×</view>
                                </view>
                                <view class="attr-values">
                                    <view class="attr-value" v-for="(value, vIndex) in attr.values" :key="vIndex">
                                        <text>{{ value }}</text>
                                        <view class="value-delete" @click="deleteSpecValue(index, vIndex)">×</view>
                                    </view>
                                    <view class="attr-add-value" @click="addSpecValue(index)">+ 添加值</view>
                                </view>
                            </view>
                            <view class="add-spec-attr" @click="addSpecAttr">+ 添加规格属性</view>
                        </view>
                    </view>
                    <view class="form-item" v-if="form.model.spec_many.spec_attr.length > 0">
                        <view class="item-label">SKU列表</view>
                        <view class="sku-list">
                            <view class="sku-item" v-for="(sku, index) in form.model.spec_many.spec_list" :key="index">
                                <view class="sku-info">{{ sku.spec_text }}</view>
                                <view class="form-item">
                                    <view class="item-label">规格图片</view>
                                    <view class="uploader">
                                        <view class="uploader-item" v-if="sku.image && sku.image.length > 0">
                                            <image :src="sku.image[0]" class="uploader-image"></image>
                                            <view class="uploader-delete" @click="deleteSkuImage(index)">×</view>
                                        </view>
                                        <view class="uploader-add" @click="handleUpload('sku', index)">+</view>
                                    </view>
                                    <!-- 上传组件 -->
                                    <uploadOne v-if="showUploadOne && uploadType === 'sku'" @getImgs="onUploadComplete">
                                    </uploadOne>
                                </view>
                                <view class="sku-inputs">
                                    <input class="sku-input" v-model="sku.spec_form.product_no" placeholder="产品编码" />
                                    <input class="sku-input" v-model="sku.spec_form.product_price" placeholder="产品价格"
                                        type="digit" />
                                    <input class="sku-input" v-model="sku.spec_form.line_price" placeholder="产品划线价"
                                        type="digit" />
                                    <input class="sku-input" v-model="sku.spec_form.stock_num" placeholder="库存数量"
                                        type="number" />
                                    <input class="sku-input" v-model="sku.spec_form.product_weight"
                                        placeholder="商品重量(Kg)" type="digit" />
                                </view>
                            </view>
                        </view>
                    </view>
                </view>
            </view>
            <!-- 商品详情 -->
            <view v-show="activeTab === 'content'" class="form-section">
                <view class="form-item">
                    <view class="item-label">详情类型</view>
                    <view class="radio-group">
                        <view class="radio-item" :class="{ active: form.model.content_type === 10 }"
                            @click="form.model.content_type = 10">图文</view>
                        <view class="radio-item" :class="{ active: form.model.content_type === 20 }"
                            @click="form.model.content_type = 20">纯图</view>
                    </view>
                </view>
                <!-- 图文类型 -->
                <view v-if="form.model.content_type === 10" class="form-item">
                    <view class="item-label">商品详情</view>
                    <view class="editor">
                        <!-- 富文本编辑器 -->
                        <view class='wrapper'>
                            <view class='toolbar' @tap="format" style="height: 160px;overflow-y: auto;">
                                <view :class="formats.bold ? 'ql-active' : ''" class="iconfont icon-zitijiacu"
                                    data-name="bold">
                                </view>
                                <view :class="formats.italic ? 'ql-active' : ''" class="iconfont icon-zitixieti"
                                    data-name="italic">
                                </view>
                                <view :class="formats.underline ? 'ql-active' : ''" class="iconfont icon-zitixiahuaxian"
                                    data-name="underline"></view>
                                <view :class="formats.strike ? 'ql-active' : ''" class="iconfont icon-zitishanchuxian"
                                    data-name="strike"></view>
                                <!-- #ifndef MP-BAIDU -->
                                <view :class="formats.align === 'left' ? 'ql-active' : ''"
                                    class="iconfont icon-zuoduiqi" data-name="align" data-value="left"></view>
                                <!-- #endif -->
                                <view :class="formats.align === 'center' ? 'ql-active' : ''"
                                    class="iconfont icon-juzhongduiqi" data-name="align" data-value="center"></view>
                                <view :class="formats.align === 'right' ? 'ql-active' : ''"
                                    class="iconfont icon-youduiqi" data-name="align" data-value="right"></view>
                                <view :class="formats.align === 'justify' ? 'ql-active' : ''"
                                    class="iconfont icon-zuoyouduiqi" data-name="align" data-value="justify"></view>
                                <!-- #ifndef MP-BAIDU -->
                                <view :class="formats.lineHeight ? 'ql-active' : ''" class="iconfont icon-line-height"
                                    data-name="lineHeight" data-value="2"></view>
                                <view :class="formats.letterSpacing ? 'ql-active' : ''"
                                    class="iconfont icon-Character-Spacing" data-name="letterSpacing" data-value="2em">
                                </view>
                                <view :class="formats.marginTop ? 'ql-active' : ''"
                                    class="iconfont icon-722bianjiqi_duanqianju" data-name="marginTop"
                                    data-value="20px"></view>
                                <view :class="formats.marginBottom ? 'ql-active' : ''"
                                    class="iconfont icon-723bianjiqi_duanhouju" data-name="marginBottom"
                                    data-value="20px"></view>
                                <!-- #endif -->
                                <view class="iconfont icon-clearedformat" @tap="removeFormat"></view>
                                <!-- #ifndef MP-BAIDU -->
                                <view :class="formats.fontFamily ? 'ql-active' : ''" class="iconfont icon-font"
                                    data-name="fontFamily" data-value="Pacifico"></view>
                                <view :class="formats.fontSize === '24px' ? 'ql-active' : ''"
                                    class="iconfont icon-fontsize" data-name="fontSize" data-value="24px"></view>
                                <!-- #endif -->
                                <view :class="formats.color === '#0000ff' ? 'ql-active' : ''"
                                    class="iconfont icon-text_color" data-name="color" data-value="#0000ff"></view>
                                <view :class="formats.backgroundColor === '#00ff00' ? 'ql-active' : ''"
                                    class="iconfont icon-fontbgcolor" data-name="backgroundColor" data-value="#00ff00">
                                </view>
                                <view class="iconfont icon-date" @tap="insertDate"></view>
                                <view class="iconfont icon--checklist" data-name="list" data-value="check"></view>
                                <view :class="formats.list === 'ordered' ? 'ql-active' : ''"
                                    class="iconfont icon-youxupailie" data-name="list" data-value="ordered"></view>
                                <view :class="formats.list === 'bullet' ? 'ql-active' : ''"
                                    class="iconfont icon-wuxupailie" data-name="list" data-value="bullet"></view>
                                <view class="iconfont icon-undo" @tap="undo"></view>
                                <view class="iconfont icon-redo" @tap="redo"></view>
                                <view class="iconfont icon-outdent" data-name="indent" data-value="-1"></view>
                                <view class="iconfont icon-indent" data-name="indent" data-value="+1"></view>
                                <view class="iconfont icon-fengexian" @tap="insertDivider"></view>
                                <view class="iconfont icon-charutupian" @tap="insertImage"></view>
                                <view :class="formats.header === 1 ? 'ql-active' : ''"
                                    class="iconfont icon-format-header-1" data-name="header" :data-value="1"></view>
                                <view :class="formats.script === 'sub' ? 'ql-active' : ''"
                                    class="iconfont icon-zitixiabiao" data-name="script" data-value="sub"></view>
                                <view :class="formats.script === 'super' ? 'ql-active' : ''"
                                    class="iconfont icon-zitishangbiao" data-name="script" data-value="super"></view>
                                <view class="iconfont icon-shanchu" @tap="clear"></view>
                                <view :class="formats.direction === 'rtl' ? 'ql-active' : ''"
                                    class="iconfont icon-direction-rtl" data-name="direction" data-value="rtl"></view>
                            </view>
                            <view class="editor-wrapper">
                                <editor id="editor" class="ql-container" placeholder="开始输入..." show-img-size
                                    show-img-toolbar show-img-resize @statuschange="onStatusChange"
                                    :read-only="readOnly" @ready="onEditorReady">
                                </editor>
                            </view>
                        </view>
                    </view>
                </view>
                <!-- 纯图类型 -->
                <view v-else-if="form.model.content_type === 20" class="form-item">
                    <view class="item-label">商品详情图片</view>
                    <view class="uploader">
                        <view class="uploader-item" v-for="(item, index) in form.model.contentImage" :key="index">
                            <image :src="item.file_path" class="uploader-image"></image>
                            <view class="uploader-delete" @click="deleteContentImage(index)">×</view>
                        </view>
                        <view class="uploader-add" @click="handleUpload('content')">+</view>
                    </view>
                    <view class="editor-tips">提示:最多上传20张图片</view>
                    <!-- 上传组件 -->
                    <upload v-if="showUpload && uploadType === 'content'"
                        :isupload="showUpload && uploadType === 'content'" :num="20 - form.model.contentImage.length"
                        @getImgs="onUploadComplete"></upload>
                </view>
            </view>
            <!-- 高级设置 -->
            <view v-show="activeTab === 'buyset'" class="form-section">
                <!-- 积分设置 -->
                <view class="form-item">
                    <view class="item-label">积分设置</view>
                    <view class="switch-item">
                        <view class="switch-label">开启积分赠送</view>
                        <switch v-model="form.model.is_points_gift" />
                    </view>
                    <view class="switch-item">
                        <view class="switch-label">允许积分抵扣</view>
                        <switch v-model="form.model.is_points_discount" />
                    </view>
                    <view class="form-item-inner" v-if="form.model.is_points_discount">
                        <view class="inner-label">最大积分抵扣数量</view>
                        <input class="inner-input" v-model="form.model.max_points_discount" placeholder="请输入最大积分抵扣数量"
                            type="number" />
                    </view>
                </view>
                <!-- 分销设置 -->
                <view class="form-item">
                    <view class="item-label">团队分红设置</view>
                    <view class="switch-item">
                        <view class="switch-label">是否参与团队分红</view>
                        <switch checked v-model="form.model.is_enable_team" />
                    </view>
                </view>
            </view>
        </scroll-view>
        <!-- 底部操作栏 -->
        <view class="bottom-bar">
            <view class="bar-item" @click="back">返回</view>
            <view class="bar-item save-btn" @click="save">保存</view>
        </view>
    </view>
</template>
<script>
    import Upload from '@/components/upload/upload.vue';
    import UploadOne from '@/components/upload/uploadOne.vue';
    export default {
        components: {
            Upload,
            UploadOne
        },
        data() {
            const now = new Date();
            return {
                activeTab: 'basic',
                loading: false,
                productId: '',
                categoryIndex: 0,
                deliveryIndex: 0,
                // 预告时间相关
                previewTimeArray: [now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes()],
                previewTimeText: '',
                // 核销时间相关
                verifyTimeArray: [],
                verifyTimeText: '',
                // 富文本编辑器相关
                editorCtx: null,
                editorStatus: {},
                // 上传组件控制
                showUpload: false,
                showUploadOne: false,
                // 当前操作的类型和索引
                uploadType: '', // image, video, poster, sku, content
                currentSkuIndex: -1,
                form: {
                    model: {
                        scene: 'edit',
                        product_name: '',
                        product_no: '',
                        category_id: null,
                        image: [],
                        is_picture: 0,
                        contentImage: [],
                        video_id: 0,
                        video: {},
                        poster_id: 0,
                        poster: {},
                        selling_point: '',
                        spec_type: 10,
                        deduct_stock_type: 20,
                        content_type: 10,
                        sku: {
                            product_no: '',
                            product_price: '',
                            line_price: '',
                            stock_num: 0,
                            product_weight: 0,
                            bar_code: ''
                        },
                        spec_many: {
                            spec_attr: [],
                            spec_list: []
                        },
                        content: '',
                        notice: '',
                        is_delivery_free: 0,
                        delivery_id: '',
                        product_status: 10,
                        audit_status: 0,
                        product_sort: 100,
                        is_points_gift: 1,
                        is_points_discount: 1,
                        max_points_discount: 0,
                        is_agent: 0,
                        is_enable_team: 1,
                        is_ind_agent: 0,
                        agent_money_type: 10,
                        first_money: 0,
                        second_money: 0,
                        third_money: 0,
                        is_virtual: 0,
                        limit_num: 0,
                        deduction_price: 0,
                        virtual_auto: 0,
                        virtual_content: '',
                        is_preview: 0,
                        preview_time: '',
                        is_verify: 0,
                        verify_type: 10,
                        verify_day: '',
                        verify_time: [],
                        verify_store_ids: [],
                    },
                    category: [],
                    delivery: [],
                    gradeList: [],
                    specData: null,
                    isSpecLocked: false,
                    basicSetting: {},
                    agentSetting: {},
                    audit_setting: {},
                    verifyStoreList: [],
                },
                selectedCategory: '',
                selectedDelivery: ''
            };
        },
        onLoad(option) {
            this.productId = option.product_id;
            this.getBaseData();
            this.getProductData();
        },
        methods: {
            // 返回上一页
            back() {
                uni.navigateBack();
            },
            // 切换标签页
            switchTab(tab) {
                this.activeTab = tab;
            },
            // 获取基础数据
            getBaseData() {
                let self = this;
                self.loading = true;
                self._post('supplier.product/getBaseData', {}, (res) => {
                    if (res.code === 0) {
                        Object.assign(self.form, res.data);
                    }
                    self.loading = false;
                });
            },
            // 获取商品数据
            getProductData() {
                let self = this;
                self.loading = true;
                self._post('supplier.product/getEditData', {
                    product_id: self.productId
                }, (res) => {
                    // 合并默认值和后端返回的数据,确保 spec_many 字段始终存在
                    self.form.model = Object.assign({
                        spec_many: {
                            spec_attr: [],
                            spec_list: []
                        }
                    }, res.data.model);
                    // 设置分类索引
                    self.categoryIndex = self.form.category.findIndex(item => item.category_id === self.form
                        .model.category_id);
                    self.selectedCategory = self.form.category[self.categoryIndex]?.category_name;
                    // 设置运费模板索引
                    self.deliveryIndex = self.form.delivery.findIndex(item => item.delivery_id === self.form
                        .model.delivery_id);
                    self.selectedDelivery = self.form.delivery[self.deliveryIndex]?.delivery_name;
                    self.loading = false;
                });
            },
            // 选择商品分类
            categoryChange(e) {
                const index = e.detail.value;
                this.form.model.category_id = this.form.category[index].category_id;
                this.selectedCategory = this.form.category[index].category_name;
            },
            // 选择图片
            chooseImage() {
                uni.chooseImage({
                    count: 9 - this.form.model.image.length,
                    success: (res) => {
                        this.form.model.image = [...this.form.model.image, ...res.tempFilePaths];
                    }
                });
            },
            // 删除图片
            deleteImage(index) {
                this.form.model.image.splice(index, 1);
            },
            // 选择运费模板
            deliveryChange(e) {
                const index = e.detail.value;
                this.form.model.delivery_id = this.form.delivery[index].delivery_id;
                this.selectedDelivery = this.form.delivery[index].name;
                this.deliveryIndex = index;
            },
            // 选择预告时间
            previewTimeChange(e) {
                const date = new Date(e.detail.value);
                this.form.model.preview_time = date.toISOString().slice(0, 19).replace('T', ' ');
                this.previewTimeText =
                    `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
            },
            // 选择视频
            chooseVideo() {
                uni.chooseVideo({
                    count: 1,
                    success: (res) => {
                        // 这里需要调用上传接口,暂时使用本地路径
                        this.form.model.video = {
                            file_path: res.tempFilePath
                        };
                        this.form.model.video_id = 1; // 模拟上传成功后的id
                    }
                });
            },
            // 删除视频
            deleteVideo() {
                this.form.model.video = {};
                this.form.model.video_id = 0;
            },
            // 选择视频封面
            choosePoster() {
                uni.chooseImage({
                    count: 1,
                    success: (res) => {
                        // 这里需要调用上传接口,暂时使用本地路径
                        this.form.model.poster = {
                            file_path: res.tempFilePaths[0]
                        };
                        this.form.model.poster_id = 1; // 模拟上传成功后的id
                    }
                });
            },
            // 删除视频封面
            deletePoster() {
                this.form.model.poster = {};
                this.form.model.poster_id = 0;
            },
            // 选择核销时间
            verifyTimeChange(e) {
                const startDate = new Date(e.detail.value[0]);
                const endDate = new Date(e.detail.value[1]);
                this.form.model.verify_time = [
                    startDate.toISOString().slice(0, 10),
                    endDate.toISOString().slice(0, 10)
                ];
                this.verifyTimeText =
                    `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')} 至 ${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`;
            },
            // 选择SKU图片
            chooseSkuImage(index) {
                uni.chooseImage({
                    count: 1,
                    success: (res) => {
                        // 这里需要调用上传接口,暂时使用本地路径
                        this.form.model.spec_many.spec_list[index].image = res.tempFilePaths;
                    }
                });
            },
            // 删除SKU图片
            deleteSkuImage(index) {
                this.form.model.spec_many.spec_list[index].image = [];
            },
            // 选择详情图片
            chooseContentImage() {
                uni.chooseImage({
                    count: 20 - this.form.model.contentImage.length,
                    success: (res) => {
                        // 这里需要调用上传接口,暂时使用本地路径
                        this.form.model.contentImage = [...this.form.model.contentImage, ...res.tempFilePaths];
                    }
                });
            },
            // 删除详情图片
            deleteContentImage(index) {
                this.form.model.contentImage.splice(index, 1);
            },
            // 富文本编辑器相关
            onEditorReady() {
                // #ifdef MP-BAIDU
                this.editorCtx = requireDynamicLib('editorLib').createEditorContext('editor');
                // #endif
                // #ifdef APP-PLUS || MP-WEIXIN || H5
                uni.createSelectorQuery().select('#editor').context((res) => {
                    this.editorCtx = res.context
                }).exec()
                // #endif
            },
            undo() {
                this.editorCtx.undo()
            },
            redo() {
                this.editorCtx.redo()
            },
            format(e) {
                let {
                    name,
                    value
                } = e.target.dataset
                if (!name) return
                this.editorCtx.format(name, value)
            },
            onStatusChange(e) {
                const formats = e.detail
                this.editorStatus = formats
            },
            insertDivider() {
                this.editorCtx.insertDivider({
                    success: function() {
                        console.log('insert divider success')
                    }
                })
            },
            clear() {
                uni.showModal({
                    title: '清空编辑器',
                    content: '确定清空编辑器全部内容?',
                    success: res => {
                        if (res.confirm) {
                            this.editorCtx.clear({
                                success: function(res) {
                                    console.log("clear success")
                                }
                            })
                        }
                    }
                })
            },
            removeFormat() {
                this.editorCtx.removeFormat()
            },
            insertDate() {
                const date = new Date()
                const formatDate = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
                this.editorCtx.insertText({
                    text: formatDate
                })
            },
            insertImage() {
                uni.chooseImage({
                    count: 1,
                    success: (res) => {
                        this.editorCtx.insertImage({
                            src: res.tempFilePaths[0],
                            alt: '图像',
                            success: function() {
                                console.log('insert image success')
                            }
                        })
                    }
                })
            },
            // 添加规格属性
            addSpecAttr() {
                uni.showModal({
                    title: '添加规格属性',
                    content: '请输入规格名称',
                    editable: true,
                    placeholderText: '例如:颜色',
                    success: (res) => {
                        if (res.confirm && res.content.trim()) {
                            this.form.model.spec_many.spec_attr.push({
                                name: res.content.trim(),
                                values: []
                            });
                            // 生成SKU列表
                            this.generateSkuList();
                        }
                    }
                });
            },
            // 删除规格属性
            deleteSpecAttr(index) {
                this.form.model.spec_many.spec_attr.splice(index, 1);
                // 重新生成SKU列表
                this.generateSkuList();
            },
            // 添加规格值
            addSpecValue(attrIndex) {
                uni.showModal({
                    title: '添加规格值',
                    content: '请输入规格值',
                    editable: true,
                    placeholderText: '例如:红色',
                    success: (res) => {
                        if (res.confirm && res.content.trim()) {
                            const attr = this.form.model.spec_many.spec_attr[attrIndex];
                            attr.values.push(res.content.trim());
                            // 重新生成SKU列表
                            this.generateSkuList();
                        }
                    }
                });
            },
            // 删除规格值
            deleteSpecValue(attrIndex, valueIndex) {
                const attr = this.form.model.spec_many.spec_attr[attrIndex];
                if (attr.values.length > 1) {
                    attr.values.splice(valueIndex, 1);
                    // 重新生成SKU列表
                    this.generateSkuList();
                }
            },
            // 生成SKU列表
            generateSkuList() {
                const attrs = this.form.model.spec_many.spec_attr;
                if (attrs.length === 0) {
                    this.form.model.spec_many.spec_list = [];
                    return;
                }
                // 生成所有可能的组合
                const combinations = this.getCombinations(attrs);
                // 生成SKU列表
                const skuList = combinations.map(comb => {
                    const spec_text = comb.map((val, idx) => `${attrs[idx].name}:${val}`).join('; ');
                    return {
                        spec_text,
                        image: [],
                        product_no: '',
                        price: '',
                        line_price: '',
                        stock: '',
                        weight: '',
                        cost_price: '',
                        bar_code: ''
                    };
                });
                this.form.model.spec_many.spec_list = skuList;
            },
            // 获取规格值组合
            getCombinations(attrs) {
                if (attrs.length === 0) return [
                    []
                ];
                const firstAttr = attrs[0];
                const remainingAttrs = attrs.slice(1);
                const remainingCombinations = this.getCombinations(remainingAttrs);
                const result = [];
                for (const value of firstAttr.values) {
                    for (const combination of remainingCombinations) {
                        result.push([value, ...combination]);
                    }
                }
                return result;
            },
            // 处理上传
            handleUpload(type, index = -1) {
                this.uploadType = type;
                if (type === 'image' || type === 'content' || type === 'video') {
                    this.showUpload = true;
                } else {
                    this.showUploadOne = true;
                }
                // 记录当前操作的SKU索引
                this.currentSkuIndex = index;
            },
            // 上传完成回调
            onUploadComplete(res) {
                // 关闭上传组件
                this.showUpload = false;
                this.showUploadOne = false;
                if (!res || res.length === 0) return;
                // 根据上传类型处理结果
                switch (this.uploadType) {
                    case 'image':
                        // 商品图片,多个文件
                        res.forEach(item => {
                            this.form.model.image.push(item.file_path);
                        });
                        break;
                    case 'video':
                        // 商品视频,单个文件
                        this.form.model.video = res[0];
                        this.form.model.video_id = res[0].id || 1;
                        break;
                    case 'poster':
                        // 视频封面,单个文件
                        this.form.model.poster = res[0];
                        this.form.model.poster_id = res[0].id || 1;
                        break;
                    case 'sku':
                        // SKU图片,单个文件
                        if (this.currentSkuIndex !== -1) {
                            this.form.model.spec_many.spec_list[this.currentSkuIndex].image = [res[0].file_path];
                        }
                        break;
                    case 'content':
                        // 详情图片,多个文件
                        res.forEach(item => {
                            this.form.model.contentImage.push(item.file_path);
                        });
                        break;
                }
            },
            // 保存商品
            save() {
                let self = this;
                // 先获取富文本编辑器内容
                if (self.form.model.content_type === 10 && self.editorCtx) {
                    // 图文类型,获取编辑器内容
                    self.editorCtx.getContents({
                        success: (res) => {
                            // 将编辑器内容赋值给表单字段
                            self.form.model.content = res.html;
                            // 继续执行保存逻辑
                            self.doSave();
                        },
                        fail: () => {
                            // 获取内容失败,继续执行保存逻辑
                            self.doSave();
                        }
                    });
                    return;
                } else {
                    // 非图文类型或编辑器未初始化,直接执行保存逻辑
                    self.doSave();
                }
            },
            // 实际保存逻辑
            doSave() {
                let self = this;
                // 表单验证
                if (!self.form.model.product_name) {
                    uni.showToast({
                        title: '请输入商品名称',
                        icon: 'none'
                    });
                    return;
                }
                if (!self.form.model.category_id) {
                    uni.showToast({
                        title: '请选择商品分类',
                        icon: 'none'
                    });
                    return;
                }
                if (self.form.model.image.length === 0) {
                    uni.showToast({
                        title: '请上传商品图片',
                        icon: 'none'
                    });
                    return;
                }
                // 规格库存验证
                if (self.form.model.spec_type === 10) {
                    // 单规格验证
                    if (!self.form.model.sku.product_price || parseFloat(self.form.model.sku.product_price) <= 0) {
                        uni.showToast({
                            title: '请输入有效的商品价格',
                            icon: 'none'
                        });
                        return;
                    }
                    if (!self.form.model.sku.stock_num || parseInt(self.form.model.sku.stock_num) < 0) {
                        uni.showToast({
                            title: '请输入有效的库存数量',
                            icon: 'none'
                        });
                        return;
                    }
                } else {
                    // 多规格验证
                    if (self.form.model.spec_many.spec_attr.length === 0) {
                        uni.showToast({
                            title: '请添加规格属性',
                            icon: 'none'
                        });
                        return;
                    }
                    for (let i = 0; i < self.form.model.spec_many.spec_list.length; i++) {
                        const sku = self.form.model.spec_many.spec_list[i];
                        if (!sku.spec_form.product_price || parseFloat(sku.spec_form.product_price) <= 0) {
                            uni.showToast({
                                title: '请输入有效的SKU价格',
                                icon: 'none'
                            });
                            return;
                        }
                        if (!sku.spec_form.stock_num || parseInt(sku.spec_form.stock_num) < 0) {
                            uni.showToast({
                                title: '请输入有效的SKU库存',
                                icon: 'none'
                            });
                            return;
                        }
                    }
                }
                // 根据详情类型验证内容
                if (self.form.model.content_type === 10) {
                    // 图文类型,验证富文本内容
                    if (!self.form.model.content || self.form.model.content.trim() === '') {
                        uni.showToast({
                            title: '请输入商品详情',
                            icon: 'none'
                        });
                        return;
                    }
                } else if (self.form.model.content_type === 20) {
                    // 纯图类型,验证详情图片
                    if (self.form.model.contentImage.length === 0) {
                        uni.showToast({
                            title: '请上传商品详情图片',
                            icon: 'none'
                        });
                        return;
                    }
                }
                self.loading = true;
                self._post('supplier.product/edit', {
                    product_id: self.productId,
                    params: JSON.stringify(self.form.model)
                }, (res) => {
                    if (res.code === 0) {
                        uni.showToast({
                            title: '保存成功'
                        });
                        setTimeout(() => {
                            uni.navigateBack();
                        }, 1500);
                    } else {
                        uni.showToast({
                            title: res.msg || '保存失败',
                            icon: 'none'
                        });
                    }
                    self.loading = false;
                });
            }
        }
    };
</script>
<style lang="scss">
    .product-edit {
        background-color: #f2f2f2;
        min-height: 100vh;
        padding-bottom: 100rpx;
        /* 为底部操作栏留出空间 */
    }
    /* 底部操作栏 */
    .bottom-bar {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 100rpx;
        background-color: #fff;
        box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
        padding: 0 30rpx;
        box-sizing: border-box;
        z-index: 999;
    }
    .bar-item {
        flex: 1;
        height: 60rpx;
        line-height: 60rpx;
        text-align: center;
        font-size: 28rpx;
        border-radius: 30rpx;
        margin: 0 10rpx;
    }
    .bar-item:first-child {
        border: 1rpx solid #e0e0e0;
        color: #666;
    }
    .save-btn {
        background-color: #e62423;
        color: #fff;
        font-weight: bold;
    }
    .top-nav {
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 88rpx;
        background-color: #fff;
        padding: 0 30rpx;
        box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 999;
    }
    .nav-item {
        font-size: 28rpx;
        color: #666;
    }
    .nav-title {
        font-size: 32rpx;
        font-weight: bold;
        color: #333;
    }
    .tab-bar {
        background-color: #fff;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 998;
    }
    .tab-scroll {
        display: flex;
        white-space: nowrap;
        padding: 0 20rpx;
    }
    .tab-item {
        display: inline-block;
        padding: 20rpx 30rpx;
        font-size: 28rpx;
        color: #666;
        position: relative;
        height: auto;
    }
    .tab-item.active {
        color: #e62423;
    }
    .tab-item.active::after {
        content: '';
        position: absolute;
        bottom: 0;
        left: 50%;
        transform: translateX(-50%);
        width: 40rpx;
        height: 4rpx;
        background-color: #e62423;
        border-radius: 2rpx;
    }
    .form-scroll {
        padding-top: 80rpx;
        padding-bottom: 20rpx;
    }
    .form-section {
        background-color: #fff;
        margin-bottom: 20rpx;
        padding: 0 30rpx;
    }
    .form-item {
        padding: 30rpx 0;
        border-bottom: 1rpx solid #f0f0f0;
    }
    .form-item:last-child {
        border-bottom: none;
    }
    .item-label {
        font-size: 28rpx;
        color: #333;
        margin-bottom: 20rpx;
    }
    .item-input {
        width: 100%;
        height: 80rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 10rpx;
        padding: 0 20rpx;
        font-size: 28rpx;
        box-sizing: border-box;
    }
    .item-textarea {
        width: 100%;
        border: 1rpx solid #e0e0e0;
        border-radius: 10rpx;
        padding: 20rpx;
        font-size: 28rpx;
        box-sizing: border-box;
        min-height: 120rpx;
    }
    .item-editor {
        width: 100%;
        height: 500rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 10rpx;
        box-sizing: border-box;
        font-size: 28rpx;
    }
    .item-picker {
        width: 100%;
        height: 80rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 10rpx;
        padding: 0 20rpx;
        font-size: 28rpx;
        box-sizing: border-box;
        display: flex;
        align-items: center;
        justify-content: space-between;
    }
    .picker-text {
        color: #666;
    }
    .uploader {
        display: flex;
        flex-wrap: wrap;
        gap: 20rpx;
    }
    .uploader-item {
        position: relative;
        width: 160rpx;
        height: 160rpx;
    }
    .uploader-image {
        width: 100%;
        height: 100%;
        border-radius: 10rpx;
    }
    .uploader-delete {
        position: absolute;
        top: -10rpx;
        right: -10rpx;
        width: 40rpx;
        height: 40rpx;
        background-color: rgba(0, 0, 0, 0.5);
        color: #fff;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 32rpx;
    }
    .uploader-add {
        width: 160rpx;
        height: 160rpx;
        border: 2rpx dashed #e0e0e0;
        border-radius: 10rpx;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 64rpx;
        color: #999;
    }
    .radio-group {
        display: flex;
        gap: 40rpx;
    }
    .radio-item {
        padding: 15rpx 30rpx;
        border: 2rpx solid #e0e0e0;
        border-radius: 50rpx;
        font-size: 28rpx;
        color: #666;
    }
    .radio-item.active {
        border-color: #e62423;
        color: #e62423;
        background-color: rgba(230, 36, 35, 0.1);
    }
    .switch-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20rpx;
    }
    .switch-item:last-child {
        margin-bottom: 0;
    }
    .switch-label {
        font-size: 28rpx;
        color: #666;
    }
    /* 规格管理样式 */
    .spec-attrs {
        margin-top: 20rpx;
    }
    .spec-attr {
        margin-bottom: 30rpx;
        padding: 20rpx;
        background-color: #f9f9f9;
        border-radius: 10rpx;
    }
    .attr-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20rpx;
    }
    .attr-name {
        font-size: 28rpx;
        color: #333;
        font-weight: bold;
    }
    .attr-delete {
        width: 40rpx;
        height: 40rpx;
        background-color: #ff4d4f;
        color: #fff;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 32rpx;
    }
    .attr-values {
        display: flex;
        flex-wrap: wrap;
        gap: 15rpx;
    }
    .attr-value {
        display: flex;
        align-items: center;
        padding: 10rpx 20rpx;
        background-color: #fff;
        border: 1rpx solid #e0e0e0;
        border-radius: 20rpx;
        font-size: 26rpx;
    }
    .value-delete {
        margin-left: 10rpx;
        color: #ff4d4f;
        font-size: 24rpx;
    }
    .attr-add-value {
        margin-top: 15rpx;
        padding: 10rpx 20rpx;
        background-color: #e6f7ff;
        color: #1890ff;
        border-radius: 20rpx;
        font-size: 26rpx;
        text-align: center;
        width: 120rpx;
    }
    .add-spec-attr {
        margin-top: 20rpx;
        padding: 15rpx;
        background-color: #f0f9eb;
        color: #52c41a;
        border-radius: 10rpx;
        font-size: 26rpx;
        text-align: center;
    }
    /* SKU列表样式 */
    .sku-list {
        margin-top: 20rpx;
    }
    .sku-item {
        margin-bottom: 20rpx;
        padding: 20rpx;
        background-color: #f9f9f9;
        border-radius: 10rpx;
    }
    .sku-info {
        font-size: 26rpx;
        color: #666;
        margin-bottom: 15rpx;
    }
    .sku-inputs {
        display: flex;
        flex-wrap: wrap;
        gap: 20rpx;
    }
    .sku-input {
        width: calc(50% - 10rpx);
        height: 70rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 8rpx;
        padding: 0 15rpx;
        font-size: 26rpx;
        box-sizing: border-box;
    }
    /* 商品详情样式 */
    .editor {
        position: relative;
    }
    .editor-tips {
        margin-top: 10rpx;
        font-size: 24rpx;
        color: #999;
    }
    /* 表单提示 */
    .form-tips {
        margin-top: 10rpx;
        font-size: 24rpx;
        color: #999;
    }
    /* 视频样式 */
    .uploader-video {
        width: 100%;
        height: 200rpx;
        border-radius: 10rpx;
    }
    /* 高级设置样式 */
    .form-item-inner {
        margin-top: 20rpx;
        padding-left: 40rpx;
    }
    .inner-label {
        font-size: 26rpx;
        color: #666;
        margin-bottom: 15rpx;
        display: block;
    }
    .inner-input {
        width: 100%;
        height: 70rpx;
        border: 1rpx solid #e0e0e0;
        border-radius: 8rpx;
        padding: 0 15rpx;
        font-size: 26rpx;
        box-sizing: border-box;
    }
    @font-face {
        font-family: iconfont;
        src: url("data:font/truetype;charset=utf-8;base64,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AAsAJgFuAAoAQwByAGUAYQB0AGUAZAAgAGIAeQAgAGkAYwBvAG4AZgBvAG4AdAAKAAAKQ3JlYXRlZCBieSBpY29uZm9udAoAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAFIAZQBnAHUAbABhAHIAAFJlZ3VsYXIAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAFYAZQByAHMAaQBvAG4AIAAxAC4AMAAAVmVyc2lvbiAxLjAAAGkAYwBvAG4AZgBvAG4AdAAAaWNvbmZvbnQAAEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AAEdlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC4AAGgAdAB0AHAAOgAvAC8AZgBvAG4AdABlAGwAbABvAC4AYwBvAG0AAGh0dHA6Ly9mb250ZWxsby5jb20AAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOwAAAAEAAgECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4ATkEcmVkbwlzZWxlY3RhbGwHcHJldmlldwR1bmRvBGRhdGUHY2xlYXJ1cBU3MjNiaWFuamlxaV9kdWFuaG91anUWNzIyYmlhbmppcWlfZHVhbnFpYW5qdQotY2hlY2tsaXN0DWRpcmVjdGlvbi1sdHINZGlyZWN0aW9uLXJ0bAtmb250Ymdjb2xvcg1jbGVhcmVkZm9ybWF0BGZvbnQHb3V0ZGVudAhmb250c2l6ZQp0ZXh0X2NvbG9yD2Zvcm1hdC1oZWFkZXItMg9mb3JtYXQtaGVhZGVyLTMLbGluZS1oZWlnaHQPZm9ybWF0LWhlYWRlci0xD2Zvcm1hdC1oZWFkZXItNA9mb3JtYXQtaGVhZGVyLTUPZm9ybWF0LWhlYWRlci02EUNoYXJhY3Rlci1TcGFjaW5nBmluZGVudAZiYW9jdW4IcXVhbnBpbmcFZnV6aGkHc2hhbmNodQxiaWFuamlzZWt1YWkJZmVuZ2V4aWFuB2RpYW56YW4MY2hhcnVsaWFuamllC2NoYXJ1dHVwaWFuCnd1eHVwYWlsaWUManV6aG9uZ2R1aXFpB3lpbnlvbmcLeW91eHVwYWlsaWUIeW91ZHVpcWkJeml0aWRhaW1hCHhpYW9saWFuCXppdGlqaWFjdQ96aXRpc2hhbmNodXhpYW4Neml0aXNoYW5nYmlhbwp6aXRpYmlhb3RpDnppdGl4aWFodWF4aWFuCXppdGl4aWV0aQl6aXRpeWFuc2UIenVvZHVpcWkJeml0aXl1bGFuC3ppdGl4aWFiaWFvC3p1b3lvdWR1aXFpB2R1aWdvdXgGZ3VhbmJpDnNoZW5neWluX3NoaXRpAAAAAAAB//8AAgABAAAADAAAABYAAAACAAEAAwA6AAEABAAAAAIAAAAAAAAAAQAAAADVpCcIAAAAANhk6GIAAAAA2GToYg==") format("truetype");
        font-weight: 400;
        font-style: normal;
        font-display: swap
    }
    .iconfont {
        font-family: iconfont !important;
        font-size: 16px;
        font-style: normal;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale
    }
    .icon-redo:before {
        content: "\e627"
    }
    .icon-undo:before {
        content: "\e633"
    }
    .icon-indent:before {
        content: "\eb28"
    }
    .icon-outdent:before {
        content: "\e6e8"
    }
    .icon-fontsize:before {
        content: "\e6fd"
    }
    .icon-format-header-1:before {
        content: "\e860"
    }
    .icon-format-header-4:before {
        content: "\e863"
    }
    .icon-format-header-5:before {
        content: "\e864"
    }
    .icon-format-header-6:before {
        content: "\e865"
    }
    .icon-clearup:before {
        content: "\e64d"
    }
    .icon-preview:before {
        content: "\e631"
    }
    .icon-date:before {
        content: "\e63e"
    }
    .icon-fontbgcolor:before {
        content: "\e678"
    }
    .icon-clearedformat:before {
        content: "\e67e"
    }
    .icon-font:before {
        content: "\e684"
    }
    .icon-723bianjiqi_duanhouju:before {
        content: "\e65f"
    }
    .icon-722bianjiqi_duanqianju:before {
        content: "\e660"
    }
    .icon-text_color:before {
        content: "\e72c"
    }
    .icon-format-header-2:before {
        content: "\e75c"
    }
    .icon-format-header-3:before {
        content: "\e75d"
    }
    .icon--checklist:before {
        content: "\e664"
    }
    .icon-baocun:before {
        content: "\ec09"
    }
    .icon-line-height:before {
        content: "\e7f8"
    }
    .icon-quanping:before {
        content: "\ec13"
    }
    .icon-direction-rtl:before {
        content: "\e66e"
    }
    .icon-direction-ltr:before {
        content: "\e66d"
    }
    .icon-selectall:before {
        content: "\e62b"
    }
    .icon-fuzhi:before {
        content: "\ec7a"
    }
    .icon-shanchu:before {
        content: "\ec7b"
    }
    .icon-bianjisekuai:before {
        content: "\ec7c"
    }
    .icon-fengexian:before {
        content: "\ec7f"
    }
    .icon-dianzan:before {
        content: "\ec80"
    }
    .icon-charulianjie:before {
        content: "\ec81"
    }
    .icon-charutupian:before {
        content: "\ec82"
    }
    .icon-wuxupailie:before {
        content: "\ec83"
    }
    .icon-juzhongduiqi:before {
        content: "\ec84"
    }
    .icon-yinyong:before {
        content: "\ec85"
    }
    .icon-youxupailie:before {
        content: "\ec86"
    }
    .icon-youduiqi:before {
        content: "\ec87"
    }
    .icon-zitidaima:before {
        content: "\ec88"
    }
    .icon-xiaolian:before {
        content: "\ec89"
    }
    .icon-zitijiacu:before {
        content: "\ec8a"
    }
    .icon-zitishanchuxian:before {
        content: "\ec8b"
    }
    .icon-zitishangbiao:before {
        content: "\ec8c"
    }
    .icon-zitibiaoti:before {
        content: "\ec8d"
    }
    .icon-zitixiahuaxian:before {
        content: "\ec8e"
    }
    .icon-zitixieti:before {
        content: "\ec8f"
    }
    .icon-zitiyanse:before {
        content: "\ec90"
    }
    .icon-zuoduiqi:before {
        content: "\ec91"
    }
    .icon-zitiyulan:before {
        content: "\ec92"
    }
    .icon-zitixiabiao:before {
        content: "\ec93"
    }
    .icon-zuoyouduiqi:before {
        content: "\ec94"
    }
    .icon-duigoux:before {
        content: "\ec9e"
    }
    .icon-guanbi:before {
        content: "\eca0"
    }
    .icon-shengyin_shiti:before {
        content: "\eca5"
    }
    .icon-Character-Spacing:before {
        content: "\e964"
    }
    .page-body {
        height: calc(100vh - var(--window-top) - 0px)
    }
    .wrapper {
        height: 100%
    }
    .editor-wrapper {
        height: calc(100vh - var(--window-top) - 0px - 80px - 46px);
        background: #fff
    }
    .iconfont {
        display: inline-block;
        padding: 8px 8px;
        width: 24px;
        height: 24px;
        cursor: pointer;
        font-size: 20px
    }
    .toolbar {
        box-sizing: border-box;
        border-bottom: 0;
        font-family: Helvetica Neue, Helvetica, Arial, sans-serif
    }
    .ql-container {
        box-sizing: border-box;
        padding: 12px 15px;
        width: 100%;
        min-height: 30vh;
        height: 100%;
        /* margin-top: 20px; */
        font-size: 16px;
        line-height: 1.5
    }
    .ql-active {
        color: #06c
    }
    .iconfont {
        color: #000000;
    }
</style>
shop_vue/src/components/setlink/part/Menu.vue
@@ -122,6 +122,16 @@
                        url: 'pages/user/my_activity/index',
                        name: '连盟活动',
                        type: '页面',
                    },
                    {
                        url: 'pages2/bonus/index/index',
                        name: '超级分红',
                        type: '菜单',
                    },
                    {
                        url: 'pages/plus/vip/index',
                        name: 'VIP专区',
                        type: '菜单',
                    }
                    ],
                /*选中的值*/
shop_vue/src/views/plus/team/setting/part/Basic.vue
@@ -39,6 +39,7 @@
          <el-radio v-model="form.become" label="40">下级分销商总数</el-radio>
          <el-radio v-model="form.become" label="50">累计佣金总数</el-radio>
          <!-- <el-radio v-model="form.become" label="60">已提现佣金</el-radio> -->
          <el-radio v-model="form.become" label="70">商户入驻和VIP会员组合条件</el-radio>
        </div>
      </el-form-item>
@@ -66,6 +67,19 @@
          </el-input>
          <div class="tips"></div>
        </el-form-item>
        <el-form-item label="下线商户入驻人数需达到" v-if="form.become==70">
          <el-input v-model="form.totalsh_down" type="number" class="max-w460">
            <template slot="append">人</template>
          </el-input>
          </el-input>
          <div class="tips"></div>
        </el-form-item>
        <el-form-item label="下级VIP会员达到" v-if="form.become==70">
          <el-input v-model="form.totalvip_down" type="number" class="max-w460">
            <template slot="append">人</template>
          </el-input>
          <div class="tips"></div>
        </el-form-item>
      <!--提交-->
      <div class="common-button-wrapper">
shop_vue/src/views/plus/vip/grade/part/Add.vue
@@ -24,8 +24,8 @@
        <template slot="append">元</template>
      </el-input>
    </el-form-item>
    <el-form-item label="VIP专区补贴" :label-width="formLabelWidth" prop="operating_subsidy">
      <el-input v-model="form.operating_subsidy" type="number" placeholder="请输入VIP专区补贴">
    <el-form-item label="下级收益补贴" :label-width="formLabelWidth" prop="operating_subsidy">
      <el-input v-model="form.operating_subsidy" type="number" placeholder="请输入下级收益补贴">
        <template slot="append">%</template>
      </el-input>
    </el-form-item>
@@ -34,6 +34,10 @@
        <template slot="append">%</template>
      </el-input>
    </el-form-item>
    <el-form-item label="直推店铺交易额佣金" :label-width="formLabelWidth" prop="commission">
      <el-input v-model="form.supplier_money" type="number" placeholder="请输入直推店铺交易额佣金">
        <template slot="append">%</template>
      </el-input>
    </el-form-item>
    <el-form-item label="自动升级" :label-width="formLabelWidth" prop="auto_upgrade">
      <el-radio-group v-model="form.auto_upgrade">
@@ -49,9 +53,27 @@
        </el-radio-group>
      </div>
      <div class="d-s-c mt16">
        <el-checkbox v-model="form.is_purchase_count">购买次数</el-checkbox>
        <el-checkbox v-model="form.is_purchase_count">购买次数VIP专区商品</el-checkbox>
        <el-input v-model="form.purchase_count" type="number" :disabled="!form.is_purchase_count" style="width: 160px; margin-left: 10px;" ></el-input>
        <span class="ml10">次</span>
      </div>
      <div class="d-s-c mt16">
        <el-checkbox v-model="form.is_supplier_count">直推商家</el-checkbox>
        <el-input v-model="form.supplier_count" type="number" :disabled="!form.is_supplier_count" style="width: 160px; margin-left: 10px;" ></el-input>
        <span class="ml10">家</span>
      </div>
      <div class="d-s-c mt16">
        <el-checkbox v-model="form.is_referee_grade">直推指定会员等级</el-checkbox>
        <el-select v-model="form.referee_grade_ids" multiple :disabled="!form.is_referee_grade" style="width: 160px; margin-left: 10px;">
          <el-option
            v-for="item in userGradeList"
            :key="item.grade_id"
            :label="item.name"
            :value="item.grade_id">
          </el-option>
        </el-select>
        <el-input v-model="form.referee_grade_count" type="number" :disabled="!form.is_referee_grade" style="width: 160px; margin-left: 10px;" ></el-input>
        <span class="ml10">人</span>
      </div>
    </el-form-item>
  </el-form>
@@ -65,6 +87,7 @@
<script>
  import vipApi from '@/api/plus/vip.js';
  import UserApi from '@/api/user.js';
  export default {
    data() {
      return {
@@ -77,10 +100,12 @@
          agent_money: 0,
          /*推广复购佣金*/
          repurchase_money: 0,
          /*VIP专区补贴*/
          /*下级收益补贴*/
          operating_subsidy: 0,
          /*平台直推佣金*/
          commission: 0,
          /*直推店铺交易额佣金*/
          supplier_money: 0,
          /*自动升级*/
          auto_upgrade: 1,
          /*升级条件*/
@@ -89,9 +114,21 @@
          is_purchase_count: 0,
          /*购买次数*/
          purchase_count: 0,
          /*是否开放直推商家*/
          is_supplier_count: 0,
          /*直推商家*/
          supplier_count: 0,
          /*是否开放直推指定会员等级*/
          is_referee_grade: 0,
          /*直推指定会员等级IDs*/
          referee_grade_ids: [],
          /*直推指定会员等级人数*/
          referee_grade_count: 0,
          /*备注*/
          remark: '',
        },
        /*用户管理模块的等级列表*/
        userGradeList: [],
        /*左边长度*/
        formLabelWidth: '120px',
        /*是否显示*/
@@ -103,8 +140,18 @@
    props: ['open_add'],
    created() {
      this.dialogVisible = this.open_add;
      this.getUserGradeList();
    },
    methods: {
      /*获取用户管理模块的等级列表*/
      getUserGradeList() {
        let self = this;
        UserApi.gradelist({}, true)
          .then(res => {
            self.userGradeList = res.data.list.data || res.data.list;
          })
          .catch(error => {});
      },
      /*添加等级*/
      addGrade() {
        let self = this;
@@ -113,6 +160,8 @@
          if (valid) {
            self.submit_loading = true;
            params.is_purchase_count = params.is_purchase_count == true ? 1 : 0;
            params.is_supplier_count = params.is_supplier_count == true ? 1 : 0;
            params.is_referee_grade = params.is_referee_grade == true ? 1 : 0;
            vipApi.addgrade(params, true).then(data => {
                self.submit_loading = false;
                self.$message({
@@ -145,4 +194,4 @@
  };
</script>
<style></style>
<style></style>
shop_vue/src/views/plus/vip/grade/part/Edit.vue
@@ -24,13 +24,18 @@
        <template slot="append">元</template>
      </el-input>
    </el-form-item>
    <el-form-item label="VIP专区补贴" :label-width="formLabelWidth" prop="operating_subsidy">
      <el-input v-model="form.operating_subsidy" type="number" placeholder="请输入VIP专区补贴">
    <el-form-item label="下级收益补贴" :label-width="formLabelWidth" prop="operating_subsidy">
      <el-input v-model="form.operating_subsidy" type="number" placeholder="请输入下级收益补贴">
        <template slot="append">%</template>
      </el-input>
    </el-form-item>
    <el-form-item label="平台直推佣金" :label-width="formLabelWidth" prop="commission">
      <el-input v-model="form.commission" type="number" placeholder="请输入平台直推佣金">
        <template slot="append">%</template>
      </el-input>
    </el-form-item>
    <el-form-item label="直推店铺交易额佣金" :label-width="formLabelWidth" prop="commission">
      <el-input v-model="form.supplier_money" type="number" placeholder="请输入直推店铺交易额佣金">
        <template slot="append">%</template>
      </el-input>
    </el-form-item>
@@ -48,9 +53,27 @@
        </el-radio-group>
      </div>
      <div class="d-s-c mt16">
        <el-checkbox v-model="form.is_purchase_count">购买次数</el-checkbox>
        <el-checkbox v-model="form.is_purchase_count">购买次数VIP专区商品</el-checkbox>
        <el-input v-model="form.purchase_count" type="number" :disabled="!form.is_purchase_count" style="width: 160px; margin-left: 10px;" ></el-input>
        <span class="ml10">次</span>
      </div>
      <div class="d-s-c mt16">
        <el-checkbox v-model="form.is_supplier_count">直推商家</el-checkbox>
        <el-input v-model="form.supplier_count" type="number" :disabled="!form.is_supplier_count" style="width: 160px; margin-left: 10px;" ></el-input>
        <span class="ml10">家</span>
      </div>
      <div class="d-s-c mt16">
        <el-checkbox v-model="form.is_referee_grade">直推指定会员等级</el-checkbox>
        <el-select v-model="form.referee_grade_ids" multiple :disabled="!form.is_referee_grade" style="width: 160px; margin-left: 10px;">
          <el-option
            v-for="item in userGradeList"
            :key="item.grade_id"
            :label="item.name"
            :value="item.grade_id">
          </el-option>
        </el-select>
        <el-input v-model="form.referee_grade_count" type="number" :disabled="!form.is_referee_grade" style="width: 160px; margin-left: 10px;" ></el-input>
        <span class="ml10">人</span>
      </div>
    </el-form-item>
  </el-form>
@@ -63,9 +86,12 @@
<script>
  import vipApi from '@/api/plus/vip.js';
  import UserApi from '@/api/user.js';
  export default {
    data() {
      return {
        /*用户管理模块的等级列表*/
        userGradeList: [],
        /*左边长度*/
        formLabelWidth: '120px',
        /*是否显示*/
@@ -77,9 +103,25 @@
    props: ['open_edit', 'form'],
    created() {
      this.form.is_purchase_count = this.form.is_purchase_count == 1 ? true : false;
      this.form.is_supplier_count = this.form.is_supplier_count == 1 ? true : false;
      this.form.is_referee_grade = this.form.is_referee_grade == 1 ? true : false;
      // 等级id转换成数组
      for (let i = 0; i < this.form.referee_grade_ids.length; i++) {
        this.form.referee_grade_ids[i] = parseInt(this.form.referee_grade_ids[i]);
      }
      this.dialogVisible = this.open_edit;
      this.getUserGradeList();
    },
    methods: {
      /*获取用户管理模块的等级列表*/
      getUserGradeList() {
        let self = this;
        UserApi.gradelist({}, true)
          .then(res => {
            self.userGradeList = res.data.list.data || res.data.list;
          })
          .catch(error => {});
      },
      /*修改等级*/
      editGrade() {
        let self = this;
@@ -88,6 +130,8 @@
          if (valid) {
            self.submit_loading = true;
            params.is_purchase_count = params.is_purchase_count == true ? 1 : 0;
            params.is_supplier_count = params.is_supplier_count == true ? 1 : 0;
            params.is_referee_grade = params.is_referee_grade == true ? 1 : 0;
            vipApi.editGrade(params, true)
              .then(data => {
                self.submit_loading = false;
@@ -122,4 +166,4 @@
  };
</script>
<style></style>
<style></style>
shop_vue/src/views/plus/vip/grade/part/List.vue
@@ -28,7 +28,21 @@
            <span class="orange">{{ scope.row.commission }}%</span>
          </template>
        </el-table-column>
        <el-table-column prop="remark" label="升级条件" ></el-table-column>
        <el-table-column prop="operating_subsidy" label="平台直推佣金" >
          <template slot-scope="scope">
            <span class="orange">{{ scope.row.commission }}%</span>
          </template>
        </el-table-column>
        <el-table-column prop="supplier_money" label="直推商家交易佣金" >
          <template slot-scope="scope">
            <span class="orange">{{ scope.row.supplier_money }}%</span>
          </template>
        </el-table-column>
        <el-table-column prop="remark" label="升级条件" >
          <template slot-scope="scope">
            <div v-html="keepTextStyle(scope.row.remark)"></div>
          </template>
        </el-table-column>
        <el-table-column prop="create_time" label="创建时间" width="160">
          <template slot-scope="scope">
            <span>{{ scope.row.create_time }}</span>
@@ -80,6 +94,11 @@
    this.getData();
  },
  methods: {
    /*换行*/
    keepTextStyle(val){
      let str=val.replace(/(\\r\\n)/g,'<br/>');
      return str;
    },
    /*获取列表数据*/
    getData() {
      let self = this;