新增商品参数管理、快捷使用

This commit is contained in:
Devil 2020-11-28 20:59:21 +08:00
parent 83b90f1cf4
commit 9020eb960c
23 changed files with 1221 additions and 332 deletions

View File

@ -143,13 +143,13 @@ class Brand extends Common
$brand_category = BrandCategoryService::BrandCategoryList(['field'=>'id,name']);
$this->assign('brand_category', $brand_category['data']);
// 品牌编辑页面钩子
// 编辑页面钩子
$hook_name = 'plugins_view_admin_brand_save';
$this->assign($hook_name.'_data', Hook::listen($hook_name,
[
'hook_name' => $hook_name,
'is_backend' => true,
'brand_id' => isset($params['id']) ? $params['id'] : 0,
'data_id' => isset($params['id']) ? $params['id'] : 0,
'data' => &$data,
'params' => &$params,
]));

View File

@ -14,6 +14,7 @@ use think\facade\Hook;
use app\service\GoodsService;
use app\service\RegionService;
use app\service\BrandService;
use app\service\GoodsParamsTemplateService;
/**
* 商品管理
@ -200,6 +201,19 @@ class Goods extends Common
// 商品参数类型
$this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list'));
// 商品参数模板
$data_params = array(
'm' => 0,
'n' => 0,
'where' => [
['is_enable', '=', 1],
['config_count', '>', 0],
],
'field' => 'id,name',
);
$template = GoodsParamsTemplateService::GoodsParamsTemplateList($data_params);
$this->assign('goods_template_list', $template['data']);
// 是否拷贝
$this->assign('is_copy', (isset($params['is_copy']) && $params['is_copy'] == 1) ? 1 : 0);

View File

@ -0,0 +1,236 @@
<?php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
// | Copyright (c) 2011~2019 http://shopxo.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
namespace app\admin\controller;
use think\facade\Hook;
use app\service\GoodsParamsTemplateService;
/**
* 商品参数管理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
class GoodsParamsTemplate extends Common
{
/**
* 构造方法
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
public function __construct()
{
// 调用父类前置方法
parent::__construct();
// 登录校验
$this->IsLogin();
// 权限校验
$this->IsPower();
}
/**
* 列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
public function Index()
{
// 总数
$total = GoodsParamsTemplateService::GoodsParamsTemplateTotal($this->form_where);
// 分页
$page_params = [
'number' => $this->page_size,
'total' => $total,
'where' => $this->data_request,
'page' => $this->page,
'url' => MyUrl('admin/goodsparamstemplate/index'),
];
$page = new \base\Page($page_params);
// 获取列表
$data_params = [
'where' => $this->form_where,
'm' => $page->GetPageStarNumber(),
'n' => $this->page_size,
'order_by' => $this->form_order_by['data'],
];
$ret = GoodsParamsTemplateService::GoodsParamsTemplateList($data_params);
// 基础参数赋值
$this->assign('params', $this->data_request);
$this->assign('page_html', $page->GetPageHtml());
$this->assign('data_list', $ret['data']);
return $this->fetch();
}
/**
* 详情
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
public function Detail()
{
if(!empty($this->data_request['id']))
{
// 条件
$where = [
['id', '=', intval($this->data_request['id'])],
];
// 获取列表
$data_params = [
'm' => 0,
'n' => 1,
'where' => $where,
];
$ret = GoodsParamsTemplateService::GoodsParamsTemplateList($data_params);
$data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0];
$this->assign('data', $data);
// 商品参数类型
$this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list'));
// 参数配置
$this->assign('parameters', empty($data['config_data']) ? [] : $data['config_data']);
}
return $this->fetch();
}
/**
* 添加/编辑页面
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
public function SaveInfo()
{
// 参数
$params = $this->data_request;
// 数据
$data = [];
if(!empty($params['id']))
{
// 获取列表
$data_params = array(
'm' => 0,
'n' => 1,
'where' => ['id'=>intval($params['id'])],
'field' => '*',
);
$ret = GoodsParamsTemplateService::GoodsParamsTemplateList($data_params);
$data = empty($ret['data'][0]) ? [] : $ret['data'][0];
}
// 商品参数类型
$this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list'));
// 参数配置
$this->assign('parameters', empty($data['config_data']) ? [] : $data['config_data']);
// 编辑页面钩子
$hook_name = 'plugins_view_admin_goods_params_template_save';
$this->assign($hook_name.'_data', Hook::listen($hook_name,
[
'hook_name' => $hook_name,
'is_backend' => true,
'data_id' => isset($params['id']) ? $params['id'] : 0,
'data' => &$data,
'params' => &$params,
]));
// 数据
$this->assign('data', $data);
$this->assign('params', $params);
return $this->fetch();
}
/**
* 保存
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
public function Save()
{
// 是否ajax请求
if(!IS_AJAX)
{
return $this->error('非法访问');
}
// 开始处理
$params = $this->data_request;
return GoodsParamsTemplateService::GoodsParamsTemplateSave($params);
}
/**
* 删除
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
public function Delete()
{
// 是否ajax请求
if(!IS_AJAX)
{
return $this->error('非法访问');
}
// 开始处理
$params = $this->data_request;
$params['user_type'] = 'admin';
return GoodsParamsTemplateService::GoodsParamsTemplateDelete($params);
}
/**
* 状态更新
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
public function StatusUpdate()
{
// 是否ajax请求
if(!IS_AJAX)
{
return $this->error('非法访问');
}
// 开始处理
$params = $this->data_request;
return GoodsParamsTemplateService::GoodsParamsTemplateStatusUpdate($params);
}
}
?>

View File

@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
// | Copyright (c) 2011~2019 http://shopxo.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
namespace app\admin\form;
/**
* 商品参数动态表格
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-06-19
* @desc description
*/
class GoodsParamsTemplate
{
// 基础条件
public $condition_base = [];
/**
* 入口
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-06-18
* @desc description
* @param [array] $params [输入参数]
*/
public function Run($params = [])
{
return [
// 基础配置
'base' => [
'key_field' => 'id',
'status_field' => 'is_enable',
'is_search' => 1,
'search_url' => MyUrl('admin/goodsparamstemplate/index'),
'is_delete' => 1,
'delete_url' => MyUrl('admin/goodsparamstemplate/delete'),
'delete_key' => 'ids',
'detail_title' => '基础信息',
],
// 表单配置
'form' => [
[
'view_type' => 'checkbox',
'is_checked' => 0,
'checked_text' => '反选',
'not_checked_text' => '全选',
'align' => 'center',
'width' => 80,
],
[
'label' => '名称',
'view_type' => 'field',
'view_key' => 'name',
'is_sort' => 1,
'search_config' => [
'form_type' => 'input',
'where_type' => 'like',
],
],
[
'label' => '是否启用',
'view_type' => 'status',
'view_key' => 'is_enable',
'post_url' => MyUrl('admin/goodsparamstemplate/statusupdate'),
'is_form_su' => 1,
'align' => 'center',
'is_sort' => 1,
'search_config' => [
'form_type' => 'select',
'where_type' => 'in',
'data' => lang('common_is_enable_list'),
'data_key' => 'id',
'data_name' => 'name',
'is_multiple' => 1,
],
],
[
'label' => '参数数量',
'view_type' => 'field',
'view_key' => 'config_count',
'is_sort' => 1,
'search_config' => [
'form_type' => 'section',
],
],
[
'label' => '创建时间',
'view_type' => 'field',
'view_key' => 'add_time',
'is_sort' => 1,
'search_config' => [
'form_type' => 'datetime',
],
],
[
'label' => '更新时间',
'view_type' => 'field',
'view_key' => 'upd_time',
'is_sort' => 1,
'search_config' => [
'form_type' => 'datetime',
],
],
[
'label' => '操作',
'view_type' => 'operate',
'view_key' => 'goodsparamstemplate/module/operate',
'align' => 'center',
'fixed' => 'right',
],
],
];
}
}
?>

View File

@ -127,30 +127,7 @@
<div class="am-panel am-panel-default">
<div class="am-panel-hd">商品参数</div>
<div class="am-panel-bd">
{{if !empty($parameters) and is_array($parameters)}}
<div class="am-scrollable-vertical am-scrollable-horizontal">
<table class="am-table am-table-bordered am-table-striped am-text-nowrap">
<thead>
<tr>
<th>展示范围</th>
<th>参数名称</th>
<th>参数值</th>
</tr>
</thead>
<tbody>
{{foreach $parameters as $v}}
<tr>
<td class="am-text-middle">{{if isset($common_goods_parameters_type_list[$v['type']])}}{{$common_goods_parameters_type_list[$v['type']]['name']}}{{/if}}</td>
<td class="am-text-middle">{{$v.name}}</td>
<td class="am-text-middle">{{$v.value}}</td>
</tr>
{{/foreach}}
</tbody>
</table>
</div>
{{else /}}
{{include file="public/not_data" /}}
{{/if}}
{{include file="public/goodsparamstemplate/detail" /}}
</div>
</div>

View File

@ -191,7 +191,7 @@
<span class="business-operations-submit quick-spec-title-add">+快捷操作</span>
<span class="business-operations-submit am-margin-left-sm am-icon-gg quick-spec-created">生成规格</span>
<div class="goods-specifications business-form-group" {{if empty($data['spec_base'])}}style="display: none;"{{/if}}>
<table class="am-table am-table-bordered am-table-centered am-table-striped am-table-hover">
<table class="am-table am-table-bordered am-table-centered am-table-striped am-table-hover table-thead-beautify">
<thead>
<tr>
<th class="spec-quick-th-title">规格名</th>
@ -285,7 +285,7 @@
</div>
<!-- 规格列表 -->
<table class="am-table am-table-bordered am-table-centered specifications-table am-margin-bottom-sm am-table-striped am-table-hover">
<table class="am-table am-table-bordered am-table-centered specifications-table am-margin-bottom-sm am-table-striped am-table-hover table-thead-beautify">
<thead class="title-nav">
<tr>
{{if !empty($specifications['type'])}}
@ -432,15 +432,7 @@
<!-- 参数 -->
<div id="goods-nav-parameters" class="division-block">
<label class="block nav-detail-title">商品参数</label>
<div class="am-alert am-alert-warning am-radius" data-am-alert="">
<p>1. 展示范围</p>
<div class="am-padding-left-sm">
<p>1.1 全部(在商品基础信息和详情参数下都展示)</p>
<p>1.2 详情(仅在商品详情参数下都展示)</p>
<p>1.3 基础(仅在商品基础信息下都展示)</p>
</div>
<p>2. 快捷操作将会清除原来的数据、重载页面便可恢复原来的数据(仅保存商品后生效)</p>
</div>
{{include file="public/goodsparamstemplate/tips" /}}
<!-- 通过配置生成商品参数 -->
<div class="am-dropdown" id="parameters-quick-container" data-am-dropdown>
<span class="business-operations-submit am-dropdown-toggle parameters-quick-add">
@ -448,6 +440,16 @@
<i class="am-icon-caret-down"></i>
</span>
<div class="am-dropdown-content parameters-quick-config">
<div class="am-margin-bottom-sm">
<select class="am-radius chosen-select goods-template-params-select" data-placeholder="请选择模板..." data-validation-message="选择商品参数模板">
{{if !empty($goods_template_list) and is_array($goods_template_list)}}
<option value="">请选择模板...</option>
{{foreach $goods_template_list as $v}}
<option value="{{:urlencode(json_encode($v['config_data'], JSON_UNESCAPED_UNICODE))}}">{{$v.name}}</option>
{{/foreach}}
{{/if}}
</select>
</div>
<textarea rows="5" placeholder="粘贴商品参数配置信息"></textarea>
<button type="button" class="am-btn am-btn-secondary am-btn-xs am-radius am-btn-block am-margin-top-sm">确认</button>
</div>
@ -475,47 +477,7 @@
<i class="am-icon-times"></i>
<span>清空参数</span>
</span>
<div class="parameters-content business-form-group am-form-group-refreshing am-padding-top-0 am-margin-top-sm">
<table class="am-table am-table-bordered am-table-centered am-table-striped am-table-hover am-margin-bottom-sm parameters-table">
<thead>
<tr>
<th class="spec-quick-th-title">展示范围</th>
<th class="spec-quick-th-title">参数名称</th>
<th class="spec-quick-th-value">参数值</th>
<th class="spec-quick-th-value">操作</th>
</tr>
</thead>
<tbody>
{{if !empty($parameters)}}
{{foreach $parameters as $pv}}
<tr>
<td class="am-text-middle">
<select name="parameters_type[]" class="am-radius chosen-select" data-validation-message="请选择商品参数展示类型">
{{if !empty($common_goods_parameters_type_list)}}
{{foreach $common_goods_parameters_type_list as $v}}
<option value="{{$v.value}}" {{if $pv['type'] eq $v['value']}}selected{{/if}}>{{$v.name}}</option>
{{/foreach}}
{{/if}}
</select>
</td>
<td class="am-text-middle">
<input type="text" name="parameters_name[]" placeholder="参数名称" value="{{$pv.name}}" data-validation-message="请填写参数名称" maxlength="160" required />
</td>
<td class="am-text-middle">
<input type="text" name="parameters_value[]" placeholder="参数值" value="{{$pv.value}}" maxlength="200" data-validation-message="请填写参数值" />
</td>
<td class="am-text-middle">
<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="top">上移</span>
<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="bottom">下移</span>
<span class="am-text-xs cr-red c-p line-remove">移除</span>
</td>
</tr>
{{/foreach}}
{{/if}}
</tbody>
</table>
<span class="business-operations-submit parameters-line-add">+添加一行</span>
</div>
{{include file="public/goodsparamstemplate/table" /}}
</div>
<!-- 相册 -->

View File

@ -0,0 +1,16 @@
<!-- 继承公共的 form -->
{{extend name="public/module/detail" /}}
<!-- 重写数据模块 -->
{{block name="detail_data"}}
<!-- 父级内容 -->
{__block__}
<!-- 商品参数 -->
<div class="am-panel am-panel-default">
<div class="am-panel-hd">商品参数</div>
<div class="am-panel-bd">
{{include file="public/goodsparamstemplate/detail" /}}
</div>
</div>
{{/block}}

View File

@ -0,0 +1,9 @@
<!-- 继承公共的 form -->
{{extend name="public/module/form" /}}
<!-- 表单顶部操作栏 -->
{{block name="form_operate_top"}}
<a href="{{:MyUrl('admin/goodsparamstemplate/saveinfo')}}" class="am-btn am-btn-secondary am-radius am-btn-xs am-icon-plus"> 新增</a>
<!-- 父级内容 -->
{__block__}
{{/block}}

View File

@ -0,0 +1,13 @@
<!-- 操作栏 -->
<button type="button" class="am-btn am-btn-default am-btn-xs am-radius am-btn-block submit-popup" data-url="{{:MyUrl('admin/goodsparamstemplate/detail', ['id'=>$module_data['id']])}}">
<i class="am-icon-eye"></i>
<span>详情</span>
</button>
<a class="am-btn am-btn-secondary am-btn-xs am-radius am-btn-block" href="{{:MyUrl('admin/goodsparamstemplate/saveinfo', array('id'=>$module_data['id']))}}">
<i class="am-icon-edit"></i>
<span>编辑</span>
</a>
<button type="button" class="am-btn am-btn-danger am-btn-xs am-radius am-btn-block submit-delete" data-url="{{:MyUrl('admin/goodsparamstemplate/delete')}}" data-id="{{$module_data.id}}" data-key="ids">
<i class="am-icon-trash-o"></i>
<span>删除</span>
</button>

View File

@ -0,0 +1,94 @@
{{include file="public/header" /}}
<!-- right content start -->
<div class="content-right">
<div class="content">
<!-- form start -->
<form class="am-form form-validation view-save" action="{{:MyUrl('admin/goodsparamstemplate/save')}}" method="POST" request-type="ajax-url" request-value="{{:MyUrl('admin/goodsparamstemplate/index', $params)}}" enctype="multipart/form-data">
<legend>
<span class="am-text-default">商品参数{{if empty($data['id'])}}添加{{else /}}编辑{{/if}}</span>
<a href="{{:MyUrl('admin/goodsparamstemplate/index', $params)}}" class="am-fr am-text-sm am-margin-top-xs am-icon-mail-reply"> 返回</a>
</legend>
<div class="am-form-group">
<label>名称</label>
<input type="text" name="name" placeholder="名称" minlength="2" maxlength="30" data-validation-message="名称格式 2~30 个字符" class="am-radius" {{if !empty($data['name'])}} value="{{$data.name}}"{{/if}} required />
</div>
<div class="am-margin-top-lg">
<label class="block">参数配置</label>
{{include file="public/goodsparamstemplate/tips" /}}
<!-- 通过配置生成商品参数 -->
<div class="am-dropdown" id="parameters-quick-container" data-am-dropdown>
<span class="business-operations-submit am-dropdown-toggle parameters-quick-add">
<span>快捷操作</span>
<i class="am-icon-caret-down"></i>
</span>
<div class="am-dropdown-content parameters-quick-config">
<textarea rows="5" placeholder="粘贴商品参数配置信息"></textarea>
<button type="button" class="am-btn am-btn-secondary am-btn-xs am-radius am-btn-block am-margin-top-sm">确认</button>
</div>
</div>
<!-- 复制操作 -->
<span class="business-operations-submit am-margin-left-sm parameters-quick-copy">
<i class="am-icon-copy"></i>
<span>复制配置</span>
</span>
<!-- 复制弹窗、仅复制操作失败的时候显示让用户手动复制 -->
<div class="am-modal am-modal-no-btn" tabindex="-1" id="parameters-quick-copy-modal">
<div class="am-modal-dialog">
<div class="am-modal-hd">
<a href="javascript: void(0)" class="am-close" data-am-modal-close>&times;</a>
</div>
<div class="am-modal-bd">
<div class="am-padding-sm">
<textarea rows="5" placeholder="商品参数配置信息"></textarea>
</div>
</div>
</div>
</div>
<!-- 清空操作 -->
<span class="business-operations-submit am-margin-left-sm parameters-quick-remove">
<i class="am-icon-times"></i>
<span>清空参数</span>
</span>
{{include file="public/goodsparamstemplate/table" /}}
</div>
<div class="am-form-group">
<label class="block">是否启用</label>
<input name="is_enable" value="1" type="checkbox" data-off-text="否" data-on-text="是" data-size="xs" data-on-color="success" data-off-color="default" data-handle-width="50" data-am-switch {{if (isset($data['is_enable']) and $data['is_enable'] eq 1) or !isset($data['is_enable'])}}checked="true"{{/if}} />
</div>
<!-- 插件扩展数据 start -->
{{if isset($shopxo_is_develop) and $shopxo_is_develop eq true}}
<div class="plugins-tag">
<span>plugins_view_admin_goods_params_template_save</span>
</div>
{{/if}}
{{if !empty($plugins_view_admin_goods_params_template_save_data) and is_array($plugins_view_admin_goods_params_template_save_data)}}
<div class="am-alert am-alert-secondary">
<label class="am-text-sm am-text-warning">该区域为插件扩展数据,请按照插件文档填写相应的值</label>
<div>
{{foreach $plugins_view_admin_brand_save_data as $hook}}
{{if is_string($hook) or is_int($hook)}}
{{$hook|raw}}
{{/if}}
{{/foreach}}
</div>
</div>
{{/if}}
<!-- 插件扩展数据 end -->
<div class="am-form-group am-form-group-refreshing am-margin-top-lg am-padding-left-0">
<input type="hidden" name="id" {{if !empty($data['id'])}} value="{{$data.id}}"{{/if}} />
<button type="submit" class="am-btn am-btn-primary am-radius btn-loading-example am-btn-sm am-btn-block" data-am-loading="{loadingText:'处理中...'}">保存</button>
</div>
</form>
<!-- form end -->
</div>
</div>
<!-- right content end -->
<!-- footer start -->
{{include file="public/footer" /}}
<!-- footer end -->

View File

@ -72,6 +72,7 @@
<!-- 项目公共 -->
<script type='text/javascript' src="{{$public_host}}static/common/js/common.js?v={{:MyC('home_static_cache_version')}}"></script>
<script type='text/javascript' src="{{$public_host}}static/admin/{{$default_theme}}/js/common.js?v={{:MyC('home_static_cache_version')}}"></script>
<!-- 应用插件公共js -->
{{if !empty($plugins_js)}}

View File

@ -0,0 +1,24 @@
{{if !empty($parameters) and is_array($parameters)}}
<div class="am-scrollable-vertical am-scrollable-horizontal">
<table class="am-table am-table-bordered am-table-striped am-text-nowrap">
<thead>
<tr>
<th>展示范围</th>
<th>参数名称</th>
<th>参数值</th>
</tr>
</thead>
<tbody>
{{foreach $parameters as $v}}
<tr>
<td class="am-text-middle">{{if isset($common_goods_parameters_type_list[$v['type']])}}{{$common_goods_parameters_type_list[$v['type']]['name']}}{{/if}}</td>
<td class="am-text-middle">{{$v.name}}</td>
<td class="am-text-middle">{{$v.value}}</td>
</tr>
{{/foreach}}
</tbody>
</table>
</div>
{{else /}}
{{include file="public/not_data" /}}
{{/if}}

View File

@ -0,0 +1,41 @@
<div class="parameters-content business-form-group am-form-group-refreshing am-padding-top-0 am-margin-top-sm">
<table class="am-table am-table-bordered am-table-centered am-table-striped am-table-hover am-margin-bottom-sm parameters-table table-thead-beautify">
<thead>
<tr>
<th class="spec-quick-th-title">展示范围</th>
<th class="spec-quick-th-title">参数名称</th>
<th class="spec-quick-th-value">参数值</th>
<th class="spec-quick-th-value">操作</th>
</tr>
</thead>
<tbody>
{{if !empty($parameters) and is_array($parameters)}}
{{foreach $parameters as $pv}}
<tr>
<td class="am-text-middle">
<select name="parameters_type[]" class="am-radius chosen-select" data-validation-message="请选择商品参数展示类型">
{{if !empty($common_goods_parameters_type_list)}}
{{foreach $common_goods_parameters_type_list as $v}}
<option value="{{$v.value}}" {{if $pv['type'] eq $v['value']}}selected{{/if}}>{{$v.name}}</option>
{{/foreach}}
{{/if}}
</select>
</td>
<td class="am-text-middle">
<input type="text" name="parameters_name[]" placeholder="参数名称" value="{{$pv.name}}" data-validation-message="请填写参数名称" maxlength="160" required />
</td>
<td class="am-text-middle">
<input type="text" name="parameters_value[]" placeholder="参数值" value="{{$pv.value}}" maxlength="200" data-validation-message="请填写参数值" />
</td>
<td class="am-text-middle">
<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="top">上移</span>
<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="bottom">下移</span>
<span class="am-text-xs cr-red c-p line-remove">移除</span>
</td>
</tr>
{{/foreach}}
{{/if}}
</tbody>
</table>
<span class="business-operations-submit parameters-line-add">+添加一行</span>
</div>

View File

@ -0,0 +1,10 @@
<div class="am-alert am-alert-warning am-radius" data-am-alert>
<button type="button" class="am-close">&times;</button>
<p>1. 展示范围</p>
<div class="am-padding-left-sm">
<p>1.1 全部(在商品基础信息和详情参数下都展示)</p>
<p>1.2 详情(仅在商品详情参数下都展示)</p>
<p>1.3 基础(仅在商品基础信息下都展示)</p>
</div>
<p>2. 快捷操作将会清除原来的数据、重载页面便可恢复原来的数据(仅保存商品后生效)</p>
</div>

View File

@ -51,16 +51,8 @@ class BrandService
{
$cnames = Db::name('BrandCategory')->where(['id'=>$cids])->column('name', 'id');
}
$common_is_enable_tips = lang('common_is_enable_tips');
foreach($data as &$v)
{
// 是否启用
if(isset($v['is_enable']))
{
$v['is_enable_text'] = $common_is_enable_tips[$v['is_enable']]['name'];
}
// 分类名称
if(isset($v['id']))
{
@ -271,7 +263,7 @@ class BrandService
'is_backend' => true,
'params' => &$params,
'data' => &$data,
'brand_id' => isset($params['id']) ? intval($params['id']) : 0,
'data_id' => isset($params['id']) ? intval($params['id']) : 0,
]));
if(isset($ret['code']) && $ret['code'] != 0)
{

View File

@ -0,0 +1,321 @@
<?php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
// | Copyright (c) 2011~2019 http://shopxo.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
namespace app\service;
use think\Db;
use think\facade\Hook;
/**
* 商品参数服务层
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-11-27
* @desc description
*/
class GoodsParamsTemplateService
{
/**
* 列表
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-18
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsParamsTemplateList($params = [])
{
$where = empty($params['where']) ? [] : $params['where'];
$field = empty($params['field']) ? '*' : $params['field'];
$order_by = empty($params['order_by']) ? 'id desc' : trim($params['order_by']);
$m = isset($params['m']) ? intval($params['m']) : 0;
$n = isset($params['n']) ? intval($params['n']) : 10;
// 获取列表
$data = Db::name('GoodsParamsTemplate')->where($where)->order($order_by)->field($field)->limit($m, $n)->select();
if(!empty($data))
{
// 获取配置数据
$res = Db::name('GoodsParamsTemplateConfig')->where(['template_id'=>array_column($data, 'id')])->field('id,template_id,type,name,value')->order('id asc')->select();
$config = [];
if(!empty($res))
{
foreach($res as $c)
{
$config[$c['template_id']][] = $c;
}
}
foreach($data as &$v)
{
// 参数配置
$v['config_data'] = empty($config[$v['id']]) ? [] : $config[$v['id']];
// 时间
if(isset($v['add_time']))
{
$v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
}
if(isset($v['upd_time']))
{
$v['upd_time'] = empty($v['upd_time']) ? '' : date('Y-m-d H:i:s', $v['upd_time']);
}
}
}
return DataReturn('处理成功', 0, $data);
}
/**
* 总数
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-18
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsParamsTemplateTotal($where)
{
return (int) Db::name('GoodsParamsTemplate')->where($where)->count();
}
/**
* 保存
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-18
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsParamsTemplateSave($params = [])
{
// 请求类型
$p = [
[
'checked_type' => 'length',
'key_name' => 'name',
'checked_data' => '2,30',
'error_msg' => '名称格式 2~30 个字符',
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
// 获取参数解析并添加
$config = self::GoodsParamsTemplateHandle($params);
if($config['code'] != 0)
{
return $config;
}
// 数据
$data = [
'name' => $params['name'],
'config_count' => count($config['data']),
'is_enable' => isset($params['is_enable']) ? intval($params['is_enable']) : 0,
];
// 保存处理钩子
$hook_name = 'plugins_service_goods_params_template_save_handle';
$ret = HookReturnHandle(Hook::listen($hook_name, [
'hook_name' => $hook_name,
'is_backend' => true,
'params' => &$params,
'data' => &$data,
'data_id' => isset($params['id']) ? intval($params['id']) : 0,
]));
if(isset($ret['code']) && $ret['code'] != 0)
{
return $ret;
}
// 启动事务
Db::startTrans();
// 捕获异常
try {
// 添加/编辑
if(empty($params['id']))
{
$data['add_time'] = time();
$template_id = Db::name('GoodsParamsTemplate')->insertGetId($data);
if($template_id <= 0)
{
throw new \Exception('添加失败');
}
} else {
$data['upd_time'] = time();
if(Db::name('GoodsParamsTemplate')->where(['id'=>intval($params['id'])])->update($data) === false)
{
throw new \Exception('更新失败');
} else {
$template_id = $params['id'];
}
}
// 删除商品参数
Db::name('GoodsParamsTemplateConfig')->where(['template_id'=>$template_id])->delete();
// 参数配置
if($config['code'] == 0 && !empty($config['data']))
{
foreach($config['data'] as &$v)
{
$v['template_id'] = $template_id;
$v['add_time'] = time();
}
if(Db::name('GoodsParamsTemplateConfig')->insertAll($config['data']) < count($config['data']))
{
throw new \Exception('规格参数添加失败');
}
}
// 完成
Db::commit();
return DataReturn('操作成功', 0);
} catch(\Exception $e) {
Db::rollback();
return DataReturn($e->getMessage(), -1);
}
}
/**
* 删除
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-18
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsParamsTemplateDelete($params = [])
{
// 参数是否有误
if(empty($params['ids']))
{
return DataReturn('操作id有误', -1);
}
// 是否数组
if(!is_array($params['ids']))
{
$params['ids'] = explode(',', $params['ids']);
}
// 启动事务
Db::startTrans();
// 捕获异常
try {
// 模板删除
if(!Db::name('GoodsParamsTemplate')->where(['id'=>$params['ids']])->delete())
{
throw new \Exception('模板删除失败');
}
// 参数配置删除
if(Db::name('GoodsParamsTemplateConfig')->where(['template_id'=>$params['ids']])->delete() === false)
{
throw new \Exception('规格参数删除失败');
}
// 完成
Db::commit();
return DataReturn('删除成功', 0);
} catch(\Exception $e) {
Db::rollback();
return DataReturn($e->getMessage(), -1);
}
}
/**
* 状态更新
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-12-18
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsParamsTemplateStatusUpdate($params = [])
{
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => '操作id有误',
],
[
'checked_type' => 'empty',
'key_name' => 'field',
'error_msg' => '未指定操作字段',
],
[
'checked_type' => 'in',
'key_name' => 'state',
'checked_data' => [0,1],
'error_msg' => '状态有误',
],
];
$ret = ParamsChecked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
// 数据更新
if(Db::name('GoodsParamsTemplate')->where(['id'=>intval($params['id'])])->update([$params['field']=>intval($params['state']), 'upd_time'=>time()]))
{
return DataReturn('操作成功');
}
return DataReturn('操作失败', -100);
}
/**
* 商品参数处理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-08-31
* @desc description
* @param [array] $params [输入参数]
*/
public static function GoodsParamsTemplateHandle($params = [])
{
// 展示范围、参数名称、参数值
if(!empty($params['parameters_type']) && !empty($params['parameters_name']) && !empty($params['parameters_value']) && is_array($params['parameters_type']) && is_array($params['parameters_name']) && is_array($params['parameters_value']))
{
$data = [];
foreach($params['parameters_type'] as $k=>$v)
{
if(isset($params['parameters_name'][$k]) && isset($params['parameters_value'][$k]))
{
$data[] = [
'type' => $v,
'name' => $params['parameters_name'][$k],
'value' => $params['parameters_value'][$k],
];
}
}
if(!empty($data))
{
return DataReturn('处理成功', 0, $data);
}
}
return DataReturn('请填写参数配置', -1);
}
}
?>

View File

@ -16,6 +16,7 @@ use app\service\ResourcesService;
use app\service\BrandService;
use app\service\RegionService;
use app\service\WarehouseGoodsService;
use app\service\GoodsParamsTemplateService;
/**
* 商品服务层
@ -1152,7 +1153,7 @@ class GoodsService
}
// 商品参数
$ret = self::GoodsParametersInsert($params, $goods_id);
$ret = self::GoodsParamsInsert($params, $goods_id);
if($ret['code'] != 0)
{
throw new \Exception($ret['msg']);
@ -1196,38 +1197,26 @@ class GoodsService
* @param [array] $params [输入参数]
* @param [int] $goods_id [商品id]
*/
public static function GoodsParametersInsert($params, $goods_id)
public static function GoodsParamsInsert($params, $goods_id)
{
// 删除商品参数
Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->delete();
// 展示范围、参数名称、参数值
if(!empty($params['parameters_type']) && !empty($params['parameters_name']) && !empty($params['parameters_value']) && is_array($params['parameters_type']) && is_array($params['parameters_name']) && is_array($params['parameters_value']))
// 获取参数解析并添加
$config = GoodsParamsTemplateService::GoodsParamsTemplateHandle($params);
if($config['code'] == 0 && !empty($config['data']))
{
$data = [];
$time = time();
foreach($params['parameters_type'] as $k=>$v)
foreach($config['data'] as &$v)
{
if(isset($params['parameters_name'][$k]) && isset($params['parameters_value'][$k]))
{
$data[] = [
'type' => $v,
'name' => $params['parameters_name'][$k],
'value' => $params['parameters_value'][$k],
'goods_id' => $goods_id,
'add_time' => $time,
];
}
$v['goods_id'] = $goods_id;
$v['add_time'] = time();
}
if(!empty($data))
if(Db::name('GoodsParams')->insertAll($config['data']) < count($config['data']))
{
if(Db::name('GoodsParams')->insertAll($data) < count($data))
{
return DataReturn('规格参数添加失败', -1);
}
return DataReturn('规格参数添加失败', -1);
}
}
return DataReturn('添加成功', 0);
return DataReturn('操作成功', 0);
}
/**

File diff suppressed because one or more lines are too long

View File

@ -592,3 +592,23 @@ table.am-table .am-btn-danger:hover {
.second-nav li.am-active a {
background-color: #1cc09f !important;
}
/**
* 表格头部美化
*/
.table-thead-beautify thead th {
background-color: #f5f7fa;
position: relative;
border-bottom: 0 !important;
}
/**
* 商品参数
*/
#parameters-quick-copy-modal textarea {
resize: none;
}
#parameters-quick-container .am-dropdown-content {
width: 260px;
}

View File

@ -65,13 +65,6 @@
/**
* 规格
*/
.specifications-table .title-nav th,
.spec-quick table thead th,
.parameters-table thead th {
background-color: #f5f7fa;
position: relative;
border-bottom: 0 !important;
}
.specifications-table .title-nav th input {
width: calc(100% - 25px);
}
@ -199,13 +192,3 @@ ul li {
width: calc(50% - 12px) !important;
}
}
/**
* 商品参数
*/
#goods-nav-parameters textarea {
resize: none;
}
#parameters-quick-container .am-dropdown-content {
width: 260px;
}

View File

@ -0,0 +1,189 @@
/**
* 商品参数数据创建
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-09-02
* @desc description
* @param {[int]} type [展示类型0,1,2]
* @param {[string]} name [参数名称]
* @param {[string]} value [参数值]
*/
function ParametersItemHtmlCreated(type, name, value)
{
var index = parseInt(Math.random()*1000001);
var html = '<tr class="parameters-line-'+index+'">';
html += '<td class="am-text-middle">';
html += '<select name="parameters_type[]" class="am-radius chosen-select" data-validation-message="请选择商品参数展示类型">';
html += '<option value="0" '+(type == 0 ? 'selected' : '')+'>全部</option>';
html += '<option value="1" '+(type == 1 || type == undefined ? 'selected' : '')+'>详情</option>';
html += '<option value="2" '+(type == 2 ? 'selected' : '')+'>基础</option>';
html += '</select>';
html += '</td>';
html += '<td class="am-text-middle">';
html += '<input type="text" name="parameters_name[]" placeholder="参数名称" value="'+(name || '')+'" data-validation-message="请填写参数名称" maxlength="160" required />';
html += '</td>';
html += '<td class="am-text-middle">';
html += '<input type="text" name="parameters_value[]" placeholder="参数值" value="'+(value || '')+'" maxlength="200" data-validation-message="请填写参数值" />';
html += '</td>';
html += '<td class="am-text-middle">';
html += '<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="top">上移</span>';
html += '<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="bottom">下移</span>';
html += '<span class="am-text-xs cr-red c-p line-remove">移除</span></td>';
html += '</tr>';
// 数据添加
var $parameters_table = $('.parameters-table');
$parameters_table.append(html);
// select组件初始化
$parameters_table.find('.parameters-line-'+index+' .chosen-select').chosen({
inherit_select_classes: true,
enable_split_word_search: true,
search_contains: true,
no_results_text: '没有匹配到结果'
});
}
$(function()
{
// 商品参数添加
var $parameters_table = $('.parameters-table');
$('.parameters-line-add').on('click', function()
{
// 追加内容
ParametersItemHtmlCreated();
});
// 商品参数移动
$parameters_table.on('click', '.line-move', function()
{
// 类型
var type = $(this).data('type') || null;
if(type == null)
{
Prompt('操作类型配置有误');
return false;
}
// 索引
var count = $parameters_table.find('tbody tr').length;
var index = $(this).parents('tr').index() || 0;
var $parent = $(this).parents('tr');
switch(type)
{
// 上移
case 'top' :
if(index == 0)
{
Prompt('已到最顶部');
return false;
}
$parent.prev().insertAfter($parent);
break;
// 下移
case 'bottom' :
if(index >= count-1)
{
Prompt('已到最底部');
return false;
}
$parent.next().insertBefore($parent);
break;
// 默认
default :
Prompt('操作类型配置有误');
}
});
// 商品参数移除
$parameters_table.on('click', '.line-remove', function()
{
$(this).parents('tr').remove();
});
// 商品参数配置信息复制
var $parameters_copy_modal = $('#parameters-quick-copy-modal');
var clipboard = new ClipboardJS('.parameters-quick-copy',
{
text: function()
{
// 获取商品参数配置信息
var data = [];
$parameters_table.find('tbody tr').each(function(k, v)
{
data.push({
"type": $(this).find('td:eq(0) select').val(),
"name": $(this).find('td:eq(1) input').val(),
"value": $(this).find('td:eq(2) input').val(),
});
});
data = JSON.stringify(data);
$parameters_copy_modal.find('textarea').val(data);
return data;
}
});
clipboard.on('success', function(e)
{
Prompt('复制成功', 'success');
});
clipboard.on('error', function(e)
{
// 复制失败则开启复制窗口,让用户自己复制
$parameters_copy_modal.modal({
width: 200,
height: 135
});
});
// 点击选中复制的值
$parameters_copy_modal.find('textarea').on('click', function()
{
$(this).select();
});
// 商品参数快捷操作
var $parameters_quick_config = $('.parameters-quick-config');
$parameters_quick_config.find('button').on('click', function()
{
// 配置数据
var data = $parameters_quick_config.find('textarea').val() || null;
if(data == null)
{
Prompt('请先粘贴配置信息');
return false;
}
// 异常处理、防止json格式错误
try {
data = JSON.parse(data);
} catch(e) {
Prompt('配置格式错误');
return false;
}
if(data.length <= 0)
{
Prompt('配置为空');
return false;
}
// 数据生成
$parameters_table.find('tbody').html('');
for(var i in data)
{
var type = (data[i]['type'] == undefined) ? 1 : data[i]['type'];
var name = data[i]['name'] || '';
var value = data[i]['value'] || '';
ParametersItemHtmlCreated(type, name, value);
}
$('#parameters-quick-container').dropdown('close');
Prompt('生成成功', 'success');
});
// 商品参数清空
$('.parameters-quick-remove').on('click', function()
{
$parameters_table.find('tbody').html('');
});
});

View File

@ -47,53 +47,6 @@ function SpecCartesian(arr1, arr2)
return result;
}
/**
* 商品参数数据创建
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2020-09-02
* @desc description
* @param {[int]} type [展示类型0,1,2]
* @param {[string]} name [参数名称]
* @param {[string]} value [参数值]
*/
function ParametersItemHtmlCreated(type, name, value)
{
var index = parseInt(Math.random()*1000001);
var html = '<tr class="parameters-line-'+index+'">';
html += '<td class="am-text-middle">';
html += '<select name="parameters_type[]" class="am-radius chosen-select" data-validation-message="请选择商品参数展示类型">';
html += '<option value="0" '+(type == 0 ? 'selected' : '')+'>全部</option>';
html += '<option value="1" '+(type == 1 || type == undefined ? 'selected' : '')+'>详情</option>';
html += '<option value="2" '+(type == 2 ? 'selected' : '')+'>基础</option>';
html += '</select>';
html += '</td>';
html += '<td class="am-text-middle">';
html += '<input type="text" name="parameters_name[]" placeholder="参数名称" value="'+(name || '')+'" data-validation-message="请填写参数名称" maxlength="160" required />';
html += '</td>';
html += '<td class="am-text-middle">';
html += '<input type="text" name="parameters_value[]" placeholder="参数值" value="'+(value || '')+'" maxlength="200" data-validation-message="请填写参数值" />';
html += '</td>';
html += '<td class="am-text-middle">';
html += '<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="top">上移</span>';
html += '<span class="am-text-xs cr-blue c-p am-margin-right-sm line-move" data-type="bottom">下移</span>';
html += '<span class="am-text-xs cr-red c-p line-remove">移除</span></td>';
html += '</tr>';
// 数据添加
var $parameters_table = $('.parameters-table');
$parameters_table.append(html);
// select组件初始化
$parameters_table.find('.parameters-line-'+index+' .chosen-select').chosen({
inherit_select_classes: true,
enable_split_word_search: true,
search_contains: true,
no_results_text: '没有匹配到结果'
});
}
$(function()
{
// 表单初始化
@ -734,143 +687,18 @@ $(function()
$(this).addClass('am-primary');
});
// 参数添加
var $parameters_table = $('.parameters-table');
$('.parameters-line-add').on('click', function()
// 商品参数模板选择
$('.goods-template-params-select').on('change', function()
{
// 追加内容
ParametersItemHtmlCreated();
});
// 商品参数移动
$parameters_table.on('click', '.line-move', function()
{
// 类型
var type = $(this).data('type') || null;
if(type == null)
var value = $(this).val() || null;
if(value != null)
{
Prompt('操作类型配置有误');
return false;
}
// 索引
var count = $parameters_table.find('tbody tr').length;
var index = $(this).parents('tr').index() || 0;
var $parent = $(this).parents('tr');
switch(type)
{
// 上移
case 'top' :
if(index == 0)
{
Prompt('已到最顶部');
return false;
}
$parent.prev().insertAfter($parent);
break;
// 下移
case 'bottom' :
if(index >= count-1)
{
Prompt('已到最底部');
return false;
}
$parent.next().insertBefore($parent);
break;
// 默认
default :
Prompt('操作类型配置有误');
}
});
// 商品参数移除
$parameters_table.on('click', '.line-remove', function()
{
$(this).parents('tr').remove();
});
// 商品参数配置信息复制
var $parameters_copy_modal = $('#parameters-quick-copy-modal');
var clipboard = new ClipboardJS('.parameters-quick-copy',
{
text: function()
{
// 获取商品参数配置信息
var data = [];
$parameters_table.find('tbody tr').each(function(k, v)
value = decodeURIComponent(value);
if(typeof(value) == 'object')
{
data.push({
"type": $(this).find('td:eq(0) select').val(),
"name": $(this).find('td:eq(1) input').val(),
"value": $(this).find('td:eq(2) input').val(),
});
});
data = JSON.stringify(data);
$parameters_copy_modal.find('textarea').val(data);
return data;
value = JSON.stringify(value);
}
}
});
clipboard.on('success', function(e)
{
Prompt('复制成功', 'success');
});
clipboard.on('error', function(e)
{
// 复制失败则开启复制窗口,让用户自己复制
$parameters_copy_modal.modal({
width: 200,
height: 135
});
});
// 点击选中复制的值
$parameters_copy_modal.find('textarea').on('click', function()
{
$(this).select();
});
// 商品参数快捷操作
var $parameters_quick_config = $('.parameters-quick-config');
$parameters_quick_config.find('button').on('click', function()
{
// 配置数据
var data = $parameters_quick_config.find('textarea').val() || null;
if(data == null)
{
Prompt('请先粘贴配置信息');
return false;
}
// 异常处理、防止json格式错误
try {
data = JSON.parse(data);
} catch(e) {
Prompt('配置格式错误');
return false;
}
if(data.length <= 0)
{
Prompt('配置为空');
return false;
}
// 数据生成
$parameters_table.find('tbody').html('');
for(var i in data)
{
var type = (data[i]['type'] == undefined) ? 1 : data[i]['type'];
var name = data[i]['name'] || '';
var value = data[i]['value'] || '';
ParametersItemHtmlCreated(type, name, value);
}
$('#parameters-quick-container').dropdown('close');
Prompt('生成成功', 'success');
});
// 商品参数清空
$('.parameters-quick-remove').on('click', function()
{
$parameters_table.find('tbody').html('');
$('#parameters-quick-container textarea').val(value || '');
});
});