This commit is contained in:
2025-10-29 15:32:26 +08:00
parent d90614805b
commit b7462657cd
78921 changed files with 2753938 additions and 71 deletions

View File

@@ -0,0 +1,18 @@
<?php
namespace app\component\controller;
/**
* 文章·组件
*/
class Article extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("article/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 视频·组件
*/
class Audio extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("audio/design.html");
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace app\component\controller;
use app\Controller;
use liliuwei\think\Jump;
class BaseDiyView extends Controller
{
use Jump;
// 当前组件路径
private $path;
// 资源路径
private $resource_path;
// 相对路径
private $relative_path;
public function __construct()
{
parent::__construct();
$class = get_class($this);
$routes = explode('\\', $class);
if ($routes[ 0 ] == 'app') {
//系统·组件app/component/controller/Text
$this->path = './' . $routes[ 0 ] . '/';
$this->resource_path = __ROOT__ . '/' . $routes[ 0 ] . '/' . $routes[ 1 ] . '/view';
$this->relative_path = $routes[ 0 ] . '/' . $routes[ 1 ] . '/view';
} elseif ($routes[ 0 ] == 'addon') {
//插件·组件addon/seckill/component/controller/seckill
$this->path = './' . $routes[ 0 ] . '/' . $routes[ 1 ] . '/';
$this->resource_path = __ROOT__ . '/' . $routes[ 0 ] . '/' . $routes[ 1 ] . '/' . $routes[ 2 ] . '/view';
$this->relative_path = $routes[ 0 ] . '/' . $routes[ 1 ] . '/' . $routes[ 2 ] . '/view';
}
}
/**
* 后台编辑界面
*/
public function design()
{
}
/**
* 加载模板输出
*
* @access protected
* @param string $template 模板文件名
* @param array $vars 模板输出变量
* @param array $replace 模板替换
*/
protected function fetch($template = '', $vars = [], $replace = [])
{
$comp_folder_name = explode('/', $template)[ 0 ];// 获取组件文件夹名称
$template = $this->path . 'component/view/' . $template;
$this->resource_path .= '/' . $comp_folder_name; // 拼接组件文件夹名称
$this->relative_path .= '/' . $comp_folder_name; // 拼接组件文件夹名称
parent::assign('resource_path', $this->resource_path);
parent::assign('relative_path', $this->relative_path);
return parent::fetch($template, $vars, $replace);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 客服信息组件
*/
class Digit extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("digit/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 商品分类·组件
*/
class FloatBtn extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("float_btn/design.html");
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace app\component\controller;
/**
* 关注公众号·组件
*/
class FollowOfficialAccount extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("follow_official_account/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 表单提交组件
*/
class Form extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("form/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 商品品牌·组件
*/
class GoodsBrand extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("goods_brand/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 商品分类·组件
*/
class GoodsCategory extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("goods_category/design.html");
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace app\component\controller;
use app\model\goods\GoodsCategory;
/**
* 商品列表·组件
*/
class GoodsList extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
$site_id = request()->siteid();
$goods_category_model = new GoodsCategory();
$category_condition = [
[ 'site_id', '=', $site_id ]
];
$category_list = $goods_category_model->getCategoryTree($category_condition)[ 'data' ];
$this->assign("category_list", $category_list);
return $this->fetch("goods_list/design.html");
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace app\component\controller;
use app\model\goods\GoodsCategory;
/**
* 商品推荐·组件
*/
class GoodsRecommend extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
$site_id = request()->siteid();
$goods_category_model = new GoodsCategory();
$category_condition = [
[ 'site_id', '=', $site_id ]
];
$category_list = $goods_category_model->getCategoryTree($category_condition)[ 'data' ];
$this->assign("category_list", $category_list);
return $this->fetch("goods_recommend/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 图文导航·组件
*/
class GraphicNav extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("graphic_nav/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 辅助空白·组件
*/
class HorzBlank extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("horz_blank/design.html");
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace app\component\controller;
/**
* 辅助线·组件
*
*/
class HorzLine extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("horz_line/design.html");
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace app\component\controller;
/**
* 热区·组件
*/
class HotArea extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("hot_area/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 图片广告·组件
*/
class ImageAds extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("image_ads/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 图文导航·组件
*/
class ImageNav extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("image_nav/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 客服信息组件
*/
class Kefu extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("kefu/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 客服信息组件
*/
class Listmenu extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("listmenu/design.html");
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace app\component\controller;
use app\model\goods\GoodsCategory;
/**
* 商品列表·组件
*/
class ManyGoodsList extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
$site_id = request()->siteid();
$goods_category_model = new GoodsCategory();
$category_condition = [
[ 'site_id', '=', $site_id ]
];
$category_list = $goods_category_model->getCategoryTree($category_condition)[ 'data' ];
$this->assign("category_list", $category_list);
return $this->fetch("many_goods_list/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 地理位置组件
*/
class Map extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("map/design.html");
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace app\component\controller;
use app\model\web\DiyView as DiyViewModel;
/**
* 会员中心—>会员信息·组件
*/
class MemberInfo extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
$site_id = request()->siteid();
$diy_view = new DiyViewModel();
$system_color = $diy_view->getStyleConfig($site_id)[ 'data' ][ 'value' ];
$this->assign('system_color', $system_color);
return $this->fetch("member_info/design.html");
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace app\component\controller;
/**
* 会员中心—>我的订单·组件
*/
class MemberMyOrder extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("member_my_order/design.html");
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace app\component\controller;
/**
* 文章·组件
*/
class MerchList extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("merchlist/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 公告·组件
*/
class Notice extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("notice/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 单图组
*/
class Picture extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("picture/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 快捷导航·组件
*/
class QuickNav extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("quick_nav/design.html");
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace app\component\controller;
/**
* 富文本·组件
*
*/
class RichText extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
$this->assign("unique_random", unique_random());
return $this->fetch("rich_text/design.html");
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace app\component\controller;
/**
* 魔方·组件
*/
class RubikCube extends BaseDiyView
{
/**
* 前台输出
*/
public function parseHtml($attr)
{
if (!empty($attr['diyHtml'])) {
$attr['diyHtml'] = str_replace("&quot;", '"', $attr['diyHtml']);
}
$this->assign("attr", $attr);
return $this->fetch('rubik_cube/rubik_cube.html');
}
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("rubik_cube/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 商品搜索·组件
*/
class Search extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("search/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 文本·组件
*/
class Text extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("text/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 店铺搜索·组件
*/
class TopCategory extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("top_category/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 视频·组件
*/
class Video extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("video/design.html");
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace app\component\controller;
/**
* 客服信息组件
*/
class VideoList extends BaseDiyView
{
/**
* 后台编辑界面
*/
public function design()
{
return $this->fetch("videolist/design.html");
}
}

View File

@@ -0,0 +1,16 @@
@CHARSET "UTF-8";
/* 文章组件 */
.article-wrap .list-wrap.style-1{}
.article-wrap .list-wrap.style-1 .item{display: flex;padding: 10px;margin-bottom: 10px;}
.article-wrap .list-wrap.style-1 .item:last-child{margin-bottom: 0;}
.article-wrap .list-wrap.style-1 .item .img-wrap{text-align: center;margin-right: 10px;width: 80px;}
.article-wrap .list-wrap.style-1 .item .img-wrap img{max-width: 100%;max-height: 100%;}
.article-wrap .list-wrap.style-1 .item .img-wrap span{display: block;background-color:#F6F6F6;height: 50px;line-height: 50px;padding: 20px;}
.article-wrap .list-wrap.style-1 .item .info-wrap {flex:1;display:flex;flex-direction:column;justify-content:space-between;}
.article-wrap .list-wrap.style-1 .item .info-wrap .title {font-weight:bold;margin-bottom:5px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:15px;line-height:1.5;}
.article-wrap .list-wrap.style-1 .item .info-wrap .abstract {overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;}
.article-wrap .list-wrap.style-1 .item .info-wrap .read-wrap {display:flex;color:#999ca7;justify-content:flex-start;align-items:center;margin-top:5px;line-height:1;}
.article-wrap .list-wrap.style-1 .item .info-wrap .read-wrap text {font-size:12px;}
.article-wrap .list-wrap.style-1 .item .info-wrap .read-wrap .iconfont {font-size:18px;vertical-align:bottom;margin-right:5px;}
.article-wrap .list-wrap.style-1 .item .info-wrap .read-wrap .category-icon {width:4px;height:4px;border-radius:50%;margin-right:5px;}
.article-wrap .list-wrap.style-1 .item .info-wrap .read-wrap .date {margin-left:10px;}

View File

@@ -0,0 +1,105 @@
<nc-component :data="data[index]" class="article-wrap">
<!-- 预览 -->
<template slot="preview">
<div :class="['list-wrap',nc.style]" :style="{ backgroundColor: nc.componentBgColor,
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
}">
<template v-if="nc.previewList && Object.keys(nc.previewList).length">
<div class="item" v-for="(item, previewIndex) in nc.previewList" :key="previewIndex" :style="{
borderTopLeftRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0),
backgroundColor: nc.elementBgColor,
boxShadow: nc.ornament.type == 'shadow' ? ('0 0 5px ' + nc.ornament.color) : '',
border: nc.ornament.type == 'stroke' ? '1px solid ' + nc.ornament.color : ''
}">
<div class="img-wrap">
<img :src="item.cover_img ? changeImgUrl(item.cover_img) : changeImgUrl('public/static/img/default_img/square.png')" />
</div>
<div class="info-wrap">
<div class="title">{{ item.article_title }}</div>
<div class="read-wrap">
<span class="category-icon bg-color" v-if="item.category_name"></span>
<span v-if="item.category_name">{{ item.category_name }}</span>
<span class="date">{{ nc.tempData.methods ? nc.tempData.methods.timeFormat(item.create_time, 'YYYY-MM-DD') : '' }}</span>
</div>
</div>
</div>
</template>
</div>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<article-sources></article-sources>
<div class="template-edit-title">
<h3>文章数据</h3>
<div class="layui-form-item" v-if="nc.tempData.goodsSources">
<label class="layui-form-label sm">数据来源</label>
<div class="layui-input-block">
<div class="source-selected">
<div class="source">{{ nc.tempData.goodsSources[nc.sources].text }}</div>
<div v-for="(item,sourcesKey) in nc.tempData.goodsSources" :key="sourcesKey" class="source-item" :title="item.text" @click="nc.sources=sourcesKey" :class="{ 'text-color border-color' : (nc.sources == sourcesKey) }">
<i class='iconfont' :class='item.icon'></i>
</div>
</div>
</div>
</div>
<div class="layui-form-item" v-if="nc.sources == 'diy'">
<label class="layui-form-label sm">手动选择</label>
<div class="layui-input-block">
<div class="selected-style" @click="nc.tempData.methods.addArticle()">
<span v-if="nc.articleIds.length == 0">请选择</span>
<span v-if="nc.articleIds.length > 0" class="text-color">已选{{ nc.articleIds.length }}个</span>
<i class="iconfont iconyoujiantou"></i>
</div>
</div>
</div>
<slide :data="{ field : 'count', label: '文章数量', min:1, max: 30}" v-if="nc.sources != 'diy'"></slide>
</div>
</template>
</template>
<!-- 样式编辑 -->
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<div class="template-edit-title">
<h3>文章样式</h3>
<div class="layui-form-item tag-wrap">
<label class="layui-form-label sm">边框</label>
<div class="layui-input-block">
<div v-for="(item,ornamentIndex) in nc.tempData.ornamentList" :key="ornamentIndex" @click="nc.ornament.type=item.type" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.ornament.type==item.type) }">
<i class="layui-anim layui-icon">{{ nc.ornament.type == item.type ? "&#xe643;" : "&#xe63f;" }}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<color v-if="nc.ornament.type != 'default'" :data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }"></color>
<color :data="{ field : 'elementBgColor', 'label' : '文章背景' }"></color>
<slide v-show="nc.elementAngle == 'round'" :data="{ field : 'topElementAroundRadius', label : '上圆角', max : 50 }"></slide>
<slide v-show="nc.elementAngle == 'round'" :data="{ field : 'bottomElementAroundRadius', label : '下圆角', max : 50 }"></slide>
</div>
</template>
</template>
<!-- 资源 -->
<template slot="resource">
<css src="{$resource_path}/css/design.css"></css>
<js src="{$resource_path}/js/design.js"></js>
</template>
</nc-component>

View File

@@ -0,0 +1,80 @@
var articleHtml = '<div></div>';
Vue.component("article-sources", {
template: articleHtml,
data: function () {
return {
data: this.$parent.data,
goodsSources: {
initial: {
text: "默认",
icon: "iconmofang"
},
diy: {
text: "手动选择",
icon: "iconshoudongxuanze"
},
},
ornamentList: [
{
type: 'default',
text: '默认',
},
{
type: 'shadow',
text: '投影',
},
{
type: 'stroke',
text: '描边',
},
],
};
},
created: function () {
this.$parent.data.ignore = [];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
if(Object.keys(this.$parent.data.previewList).length == 0) {
for (var i = 1; i < 3; i++) {
this.$parent.data.previewList["brand_id_" + ns.gen_non_duplicate(i)] = {
article_title: "文章标题",
article_abstract: '这里是文章内容',
read_num: (i + 1) * 12,
category_name: '文章分类',
create_time: 1662202804
};
}
}
// 组件所需的临时数据
this.$parent.data.tempData = {
goodsSources: this.goodsSources,
ornamentList: this.ornamentList,
methods: {
addArticle: this.addArticle,
timeFormat: this.timeFormat
},
};
},
methods: {
verify: function (index) {
var res = {code: true, message: ""};
if (vue.data[index].sources === 'diy' && vue.data[index].articleIds.length === 0) {
res.code = false;
res.message = "请选择文章";
}
return res;
},
addArticle: function () {
var self = this;
articleSelect(function (res) {
self.$parent.data.articleIds = res.articleIds;
self.$parent.data.previewList = res.list;
}, {select_id: self.$parent.data.articleIds.toString()});
},
timeFormat(time, format){
return ns.time_to_date(time, format)
}
}
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,121 @@
<nc-component :data="data[index]" class="audio-box">
<!-- 预览 -->
<template slot="preview" >
<div class="audio-wrap" :style="{
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0) }">
<!-- <audio :src="changeImgUrl(nc.audioUrl)" controls :poster="changeImgUrl(nc.imageUrl)"
:style="{
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0) }"></audio> -->
<div class="drag selected">
<div class="fui-audio" style="margin: 0px 0px;" :style="{backgroundColor:nc.background}" v-if="nc.type == 'style-1'">
<div class="horn" style="width:2rem;height:2rem;margin-right:6px;">
<!-- <img src="../app/component/view/audio/audio.png" width="100%" height="100%"> -->
<img :src="changeImgUrl(nc.imageUrl) || changeImgUrl('public/static/img/audio.png')" width="100%" height="100%">
</div>
<div class="center">
<p :style="{color:nc.textcolor}">{{nc.text?nc.text:'未定义音频信息'}}</p>
<p :style="{color:nc.subtitlecolor}">{{nc.desc?nc.desc:'副标题'}}</p>
</div>
<div class="time" :style="{color:nc.timecolor}">11'26''</div>
<div class="speed"></div>
</div>
<div class="fui-audio style1 left" :style="{backgroundColor:nc.background}" v-if="nc.type == 'style-2'">
<div class="content" style="display: flex;flex: 1;">
<p :style="{color:nc.textcolor}">{{nc.text?nc.text:'未定义音频信息'}}</p>
<p :style="{color:nc.subtitlecolor,marginLeft:'10px'}">{{nc.desc?nc.desc:'副标题'}}</p>
</div>
<div class="start icon"><i class="icond icon-playfill"></i></div>
</div>
</div>
</div>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<audio-edit></audio-edit>
<!-- <div class="audio-edit">
<div class="layui-input-inline" id="order_pay_audio_box">
<audio controls height="100" width="100">
<source src="" type="audio/mpeg">
</audio>
</div>
<div class="layui-input-inline">
<span class="text-color" style="cursor: pointer;" id="upload_order_pay_audio">更换</span>
</div>
<input type="hidden" name="order_remind_order_pay_audio" value=""/>
</div> -->
<div class="layui-form-item">
<label class="layui-form-label sm">标题文字</label>
<div class="layui-input-block">
<input type="text" v-model="nc.text" maxlength="15" placeholder="请输入标题" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label sm">副标题</label>
<div class="layui-input-block">
<input type="text" v-model="nc.desc" maxlength="15" placeholder="请输入标题" class="layui-input">
</div>
</div>
<color :data="{ field : 'background', label : '背景颜色',defaultColor : '#303133'}"></color>
<color :data="{ field : 'textcolor', label : '标题颜色',defaultColor : '#303133'}"></color>
<color :data="{ field : 'subtitlecolor', label : '副标题颜色',defaultColor : '#303133'}"></color>
<color :data="{ field : 'timecolor', label : '时间颜色',defaultColor : '#303133'}" v-if="nc.type == 'style-1'"></color>
</template>
</template>
<!-- 样式编辑 -->
<template slot="edit-style"></template>
<!-- 资源 -->
<template slot="resource">
<js></js>
<css src="{$resource_path}/css/design.css?v={$version}"></css>
<js src="{$resource_path}/js/design.js?v={$version}"></js>
</template>
<!-- <script>
layui.use(['form', 'upload'], function () {
var form = layui.form,
upload = layui.upload;
var audio_arr = ['order_pay_audio'];
audio_arr.forEach((field)=>{
console.log(field)
upload.render({
elem: '#upload_'+field,
url: ns.url('shop/upload/audio'),
accept: "audio",
done: function(res){
if(res.code >= 0){
layer.msg('上传成功');
$("input[name='order_remind_"+field+"']").val(res.data.path);
$("#"+field+"_box").html(`<audio controls height="100" width="100">
<source src="${ns.img(res.data.path)}" type="audio/mpeg">
</audio>`);
}else{
layer.msg(res.message);
}
}
});
})
});
</script> -->
</nc-component>

View File

@@ -0,0 +1,63 @@
var audioHtml = '<div class="audio-edit">';
audioHtml += '<div class="template-edit-title">';
audioHtml += '<h3>音频设置</h3>';
audioHtml += '<div class="layui-form-item">';
audioHtml += '<label class="layui-form-label sm">播放样式</label>';
audioHtml += '<div class="layui-input-block">';
audioHtml += '<div @click="data.type=\'style-1\'" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.type==\'style-1\') }">';
audioHtml += '<i class="layui-anim layui-icon">{{ data.type==\'style-1\' ? \'&#xe643;\' : \'&#xe63f;\' }}</i>';
audioHtml += '<div>样式一</div>';
audioHtml += '</div>';
audioHtml += '<div @click="data.type=\'style-2\'" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.type==\'style-2\') }">';
audioHtml += '<i class="layui-anim layui-icon">{{ data.type==\'style-2\' ? \'&#xe643;\' : \'&#xe63f;\' }}</i>';
audioHtml += '<div>样式二</div>';
audioHtml += '</div>';
audioHtml += '</div>';
audioHtml += '</div>';
audioHtml += '<div class="layui-form-item" style="display: flex;">';
audioHtml += '<label class="layui-form-label sm">音频</label>';
audioHtml += '<audio-upload :data="{data : data}"></audio-upload>';
audioHtml += '</div>';
audioHtml += '<div class="layui-form-item" v-show="data.type == \'style-1\'">';
audioHtml += '<label class="layui-form-label sm">封面图</label>';
audioHtml += '<img-upload :data="{data : data}"></img-upload>';
audioHtml += '</div>';
audioHtml += '</div>';
audioHtml += '</div>';
Vue.component("audio-edit",{
data: function () {
return {
data: this.$parent.data,
};
},
created : function(){
if(!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['textColor','componentBgColor','elementBgColor','elementAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
},
methods: {
/*verify : function (index) {
var res = { code : true, message : "" };
if (vue.data[index].audioUrl === '') {
res.code = false;
res.message = "请上传视频";
}
if (vue.data[index].imageUrl === '') {
res.code = false;
res.message = "请上传视频封面";
}
return res;
}*/
},
template: audioHtml
});

View File

@@ -0,0 +1,406 @@
@CHARSET "UTF-8";
/*图文导航组件*/
.digit-navigation .preview-draggable .preview-box {
padding: 8px 0;
margin: 0 15px;
border-radius: 5px;
}
.digit-navigation .preview-draggable ul {
overflow: hidden;
list-style: none;
}
.digit-navigation .preview-draggable ul.horizontal-scroll {
overflow-x: scroll;
white-space: nowrap;
}
.digit-navigation .preview-draggable ul.horizontal-scroll::-webkit-scrollbar {
display: none;
}
.digit-navigation .preview-draggable li {
width: 50%;
text-align: center;
display: inline-block;
vertical-align: top;
}
.digit-navigation .preview-draggable li img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
.digit-navigation .preview-draggable li:last-child {
border: 0;
}
.digit-navigation .preview-draggable li span {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
height: 20px;
display: block;
line-height: 20px;
}
/*.digit-navigation .preview-draggable .digit-nav{visibility: hidden;}*/
.digit-navigation .preview-draggable .digit-nav>.wrap {
/* overflow-x: hidden;white-space: nowrap; background: #ffffff; */
display: flex;
/* justify-content: space-around; */
flex-wrap: wrap;
padding: 0 5px;
}
.digit-navigation .digit-nav-list .template-list .template-item {
float: left;
text-align: center;
border: 1px solid #e5e5e5;
margin-right: 20px;
padding: 5px;
background: #ffffff;
cursor: pointer;
}
.digit-navigation .digit-nav-list .template-list .template-item img {
display: block;
}
.digit-navigation .add-item {
padding: 10px;
border: 1px dashed #e5e5e5;
margin: 16px 0 10px;
cursor: pointer;
text-align: center;
}
.digit-navigation .add-item i {
display: inline-block;
height: 24px;
line-height: 24px;
font-size: 18px;
margin-right: 10px;
font-style: normal;
}
.digit-navigation .add-item span {
display: inline-block;
height: 24px;
line-height: 24px;
}
.digit-navigation .error-msg {
margin: 5px 0 0 53px;
color: #f44;
display: none;
}
/* 新的css */
.digit-navigation .digit-nav{
padding: 10px 5px;
}
/* 预览 */
/* 固定显示 */
.digit-navigation .digit-nav.fixed{
display: flex;
flex-wrap: wrap;
}
/* 单边滑动 */
.digit-navigation .digit-nav.singleSlide{
display: flex;
overflow-x: auto;
}
.digit-navigation .digit-nav.singleSlide::-webkit-scrollbar {
height: 5px;
}
.digit-navigation .digit-nav.singleSlide::-webkit-scrollbar-track {
background-color: #e4e4e4;
}
.digit-navigation .digit-nav.singleSlide::-webkit-scrollbar-thumb {
background-color: #999;
}
.digit-navigation .digit-nav.singleSlide .digit-nav-item{
flex-shrink: 0;
}
/* 分页 */
.digit-navigation .digit-nav.pageSlide{
position: relative;
}
.digit-navigation .digit-nav.pageSlide .digit-nav-wrap{
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
.digit-navigation .digit-nav.pageSlide .carousel-btn{
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.digit-navigation .digit-nav.pageSlide .carousel-btn .arrows{
display: flex;
justify-content: space-between;
padding: 0 15px;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.digit-navigation .digit-nav.pageSlide .carousel-btn .arrows i{
display: none;
width: 36px;
height: 36px;
line-height: 36px;
text-align: center;
color: #fff;
background-color: rgba(0, 0, 0, .35);
border-radius: 50%;
cursor: pointer;
}
.digit-navigation .digit-nav.pageSlide .carousel-btn .dot-wrap{
text-align: center;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.digit-navigation .digit-nav.pageSlide .carousel-btn .dot-wrap.hide{
display: none;
}
.digit-navigation .digit-nav.pageSlide .carousel-btn .dot-wrap.straightLine i{
width: 12px;
height: 4px;
border-radius: 0;
}
.digit-navigation .digit-nav.pageSlide .carousel-btn .dot-wrap i{
display: inline-block;
width: 7px;
height: 7px;
border-radius: 50%;
background-color: rgba(0, 0, 0, .1);
margin-right: 5px;
cursor: pointer;
}
.digit-navigation .digit-nav.pageSlide .carousel-btn .dot-wrap i.active{
background-color: rgba(0, 0, 0, .5);
}
.digit-navigation .digit-nav.pageSlide .carousel-btn:hover .arrows i{
display: block;
}
.digit-navigation .digit-nav .digit-nav-item{
display: flex;
flex-direction: column;
align-items: center;
padding: 7px 0;
box-sizing: border-box;
}
.newright{
margin-right: 10px;
}
.digit-navigation .digit-nav .digit-nav-item .digit-text{
padding-top: 6px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
}
.digit-navigation .digit-nav .digit-nav-item .digit-img{
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
font-size: 40px;
}
.digit-navigation .digit-nav .digit-nav-item .digit-img .tag{
position: absolute;
top: -5px;
right: -12px;
color: #fff;
background-color: red;
border-radius: 12px;
border-bottom-left-radius: 0;
transform: scale(0.8);
padding: 2px 6px;
font-size: 12px;
}
.digit-navigation .digit-nav .digit-nav-item .digit-img img{
max-width: 100%;
max-height: 100%;
}
.digit-navigation .digit-nav .digit-nav-item .digit-img i{
font-size: 25px;
color: #666;
}
/* 图文导航项 */
.digit-navigation p.hint {
padding-left: 15px;
font-size: 12px;
color: #909399;
line-height: 20px;
}
.digit-navigation .digit-nav-list>ul {
padding: 10px 0 10px 15px;
}
.digit-navigation .digit-nav-list>ul>li {
padding: 10px 10px 10px 0px;
background: #ffffff;
border: 1px dashed #e5e5e5;
position: relative;
margin-top: 16px;
}
.digit-navigation .digit-nav-list>ul>li>.iconfont {
position: absolute;
top: calc(50% - 10px);
left: 15px;
cursor: move;
font-size: 20px;
}
.digit-navigation .digit-nav-list>ul>li:first-child {
margin-top: 0;
}
.digit-navigation .digit-nav-list>ul>li:hover .del {
display: block;
}
.digit-navigation .edit-attribute .attr-wrap .restore-wrap .img-block, .digit-navigation .edit-attribute .attr-wrap .restore-wrap .img-block.has-choose-image > div{
width: 50px;
height: 50px;
line-height: 50px;
}
.digit-navigation .edit-attribute .attr-wrap .restore-wrap .img-block.has-choose-image img {
width: 35px;
height: 35px;
}
.digit-navigation .edit-attribute .icon-box {
width: 60px;
height: 60px;
font-size: 60px;
border: 1px dashed #ddd;
display: flex;
align-items: center;
justify-content: center;
padding: 0!important;
cursor: pointer;
position: relative;
}
.digit-navigation .edit-attribute .icon-box .select-icon {
width: inherit;
height: inherit;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
line-height: 1;
}
.digit-navigation .edit-attribute .icon-box .select-icon .add {
font-size: 26px;
color: var(--base-color);
}
.digit-navigation .edit-attribute .icon-box .operation {
position: absolute;
width: 100%;
height: 100%;
background: rgba(0,0,0,.6);
flex-direction: column;
display: none;
}
.digit-navigation .edit-attribute .icon-box:hover .operation {
display: flex;
}
.digit-navigation .edit-attribute .icon-box .operation-warp {
flex: 1;
height: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.digit-navigation .edit-attribute .icon-box .iconfont {
margin: 0 3px;
font-size: 16px!important;
}
.digit-navigation .edit-attribute .icon-box .operation .js-replace{
line-height: 1;
color: #fff;
text-align: center;
padding: 5px 0;
background: rgba(0,0,0,.7);
font-size: 12px;
height: unset;
}
.digit-navigation .edit-attribute .digit-nav-list .icon-box .icon-wrap:hover .operation{
display: block;
}
.digit-navigation .edit-attribute .digit-nav-list .img-upload .upload-img-box:hover .operation{
display: block;
}
.digit-navigation .edit-attribute .navigation-set-list .img-upload {
display: flex;
align-items: center;
}
.digit-navigation .edit-attribute .navigation-set-list .img-upload img {
width: 100%;
height: 100%;
}
.digit-navigation .edit-attribute .navigation-set-list .action-box {
display: flex;
}
.digit-navigation .edit-attribute .navigation-set-list .action {
margin-right: 3px;
width: 42px;
height: 28px;
line-height: 28px;
text-align: center;
border: 1px solid #EEEEEE;
cursor: pointer;
}
.digit-navigation .edit-attribute .navigation-set-list .action:hover {
border-color: var(--base-color);
color: var(--base-color);
}
.digit-navigation .img-icon-box{
display: flex;
align-items: center;
}

View File

@@ -0,0 +1,157 @@
<nc-component :data="data[index]" class="digit-navigation">
<!-- 预览 -->
<template slot="preview">
<template v-if="nc.lazyLoad">
<div :class="['digit-nav',nc.showStyle] " :style="{
backgroundColor: nc.componentBgColor,
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
boxShadow: nc.ornament.type == 'shadow' ? ('0 0 5px ' + nc.ornament.color) : '',
border: nc.ornament.type == 'stroke' ? '1px solid ' + nc.ornament.color : ''
}">
<div class="digit-nav-item" v-for="(item) in nc.list" :key="item.id" :style="{width: (100 / nc.rowCount + '%')}">
<!-- <div class="digit-img" v-show="nc.mode != 'text'" :style="{'font-size' : nc.imageSize + 'px', width: nc.imageSize + 'px', height: nc.imageSize + 'px'}">
<img v-if="item.iconType == 'img' && item.imageUrl" :src="changeImgUrl(item.imageUrl)" alt="" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px', borderRadius: nc.aroundRadius + 'px'}">
<iconfont v-if="item.iconType == 'icon' && item.icon" :icon="item.icon" :value="(item.style ? item.style : null)" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px'}"></iconfont>
<img v-if="!item.icon && !item.imageUrl" :src="changeImgUrl('public/static/img/default_img/square.png')" alt="" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px', borderRadius: nc.aroundRadius + 'px'}">
<span class="tag" v-if="item.label.control" :style="{color: item.label.textColor,backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')'}">{{item.label.text}}</span>
</div> -->
<!-- margin-right: 10px; -->
<div class="digit-text" :style="{fontSize: nc.font.size+'px',fontWeight: nc.font.weight, color: nc.font.color,backgroundColor:nc.mode=='text'?nc.font.bgcolor:'',paddingBottom:nc.mode=='text'?'7px':''}" style="border-radius: 4px;">
<span :style="{fontSize: nc.font.titlesize+'px',color: nc.font.titlecolor}">{{item.title}}</span>
<span :style="{fontSize: nc.font.unitsize+'px',color: nc.font.unitcolor}">{{item.unit}}</span>
</div>
<div :style="{fontSize: nc.font.descsize+'px',color: nc.font.desccolor}">{{item.desc}}</div>
<!-- <div class="fui-cell-group fui-cell-click" style="margin-top: 0px; background-color: #ffffff;font-size:26px">
<div class="fui-cell">
<div class="fui-cell-icon" style="color: #999999;">
<img v-if="item.iconType == 'img' && item.imageUrl" :src="changeImgUrl(item.imageUrl)" alt="" :style="{maxWidth: '30px', maxHeight: '30px', borderRadius: nc.aroundRadius + 'px'}">
<iconfont v-if="item.iconType == 'icon' && item.icon" :icon="item.icon" :value="(item.style ? item.style : null)" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px'}"></iconfont>
</div>
<div class="fui-cell-text" style="color: #000000;padding-left: 6px;">{{item.title}}</div>
<div class="fui-cell-remark" style="color: #888888;">查看</div>
</div>
</div> -->
</div>
</div>
</template>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<digit-nav-list></digit-nav-list>
<div class="template-edit-title">
<h3>数字项设置</h3>
<div class="layui-form-item icon-radio">
<label class="layui-form-label sm">显示样式</label>
<div class="layui-input-block">
<span v-for="item in nc.tempData.rowCountList" :class="[{'layui-hide': item.value != nc.rowCount}]">{{item.name}}</span>
<ul class="icon-wrap">
<li v-for="item in nc.tempData.rowCountList" :class="[item.value == nc.rowCount ? 'text-color border-color' : '']" @click="nc.tempData.methods.setnum(item.value)">
<i :class="['iconfont',item.src]"></i>
</li>
</ul>
</div>
</div>
<div class="digit-nav-list">
<!-- <p class="hint">建议上传尺寸相同的图片(60px * 60px)</p> -->
<ul class="navigation-set-list">
<li v-for="(item,previewIndex) in nc.list" :key="item.id" class="content-block">
<!-- <template>
<div class="layui-form-item">
<label class="layui-form-label sm">图片</label>
<div class="layui-input-block">
<image-upload :data="{ data : item }" :condition="['listmenu','img'].includes(nc.mode)" data-disabled="1"></image-upload>
</div>
</div>
</template> -->
<div class="layui-form-item">
<label class="layui-form-label sm">数字</label>
<div class="layui-input-block">
<input type="number" name='title' placeholder="请输入数字" v-model="item.title" maxlength="20" class="layui-input" autocomplete="off" />
<input type="text" name='unit' placeholder="请输入单位" v-model="item.unit" maxlength="20" class="layui-input" autocomplete="off" />
<input type="text" name='desc' placeholder="请输入描述" v-model="item.desc" maxlength="20" class="layui-input" autocomplete="off" />
</div>
</div>
<!-- <nc-link :data="{ field : item.link, label:'链接' }"></nc-link> -->
<!-- <i class="del" @click="nc.list.splice(previewIndex,1)" data-disabled="1">x</i>
<div class="error-msg"></div>
<div class="iconfont icontuodong"></div> -->
</li>
<!-- <div class="add-item text-color" @click="nc.tempData.methods.addNav()">
<i>+</i>
<span>添加一个数字组</span>
</div> -->
</ul>
</div>
</div>
</template>
</template>
<!-- 样式编辑 -->
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<div class="template-edit-title">
<!--
<h3>图文导航</h3>
<color v-if="nc.ornament.type != 'default'" :data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }"></color>
<div class="template-edit-title" v-show="['listmenu','img'].includes(nc.mode) && nc.type == 'img'">
<h3>图片设置</h3>
<template v-if="nc.type == 'img'">
<slide :data="{ field : 'aroundRadius', label : '图片圆角', max : 50 }"></slide>
<slide :data="{ field : 'imageSize', label : '图片大小', min: 30, max : 60 }"></slide>
</template>
</div> -->
<div class="template-edit-title">
<h3>数字文字设置</h3>
<slide :data="{ field : 'titlesize',parent:'font', label : '文字大小', min: 12, max : 40 }"></slide>
<color :data="{ field : 'titlecolor', label : '文字颜色',parent:'font',defaultColor: '#303133' }"></color>
</div>
<div class="template-edit-title">
<h3>单位文字设置</h3>
<slide :data="{ field : 'unitsize',parent:'font', label : '文字大小', min: 12, max : 40 }"></slide>
<color :data="{ field : 'unitcolor', label : '文字颜色',parent:'font',defaultColor: '#303133' }"></color>
</div>
<div class="template-edit-title">
<h3>描述文字设置</h3>
<slide :data="{ field : 'descsize',parent:'font', label : '文字大小', min: 12, max : 40 }"></slide>
<color :data="{ field : 'desccolor', label : '文字颜色',parent:'font',defaultColor: '#303133' }"></color>
</div>
</template>
</template>
<!-- 资源 -->
<template slot="resource">
<js>
var listmenuNavResourcePath = "{$resource_path}"; // http路径
var listmenuNavRelativePath = "{$relative_path}"; // 相对路径
</js>
<css src="{$resource_path}/css/design.css?v={$version}"></css>
<js src="{$resource_path}/js/design.js?v={$version}"></js>
</template>
</nc-component>

View File

@@ -0,0 +1,498 @@
/**
* [图片导航的图片]·组件
*/
var digitNavListHtml = '<div style="display: none;"></div>';
Vue.component("digit-nav-list", {
template: digitNavListHtml,
data: function () {
return {
data: this.$parent.data,
list: this.$parent.data.list,
rowCountList: [
{
name: "样式1",
value: 2,
src: "iconyihangliangge"
},
{
name: "样式2",
value: 3,
src: "iconyihangsange"
},
],
};
},
created: function () {
if (!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['textColor', 'elementBgColor', 'elementAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
// 组件所需的临时数据
this.$parent.data.tempData = {
...this.$parent.data.tempData,
modeList: this.modeList,
showStyleList: this.showStyleList,
ornamentList: this.ornamentList,
carouselList: this.carouselList,
rowCountList: this.rowCountList,
pageCountList: this.pageCountList,
thicknessList:this.thicknessList,
carouselIndex: 0,
methods: {
addNav: this.addNav,
setnum: this.setnum,
}
};
this.list.forEach(function (e, i) {
if(!e.id ) e.id = ns.gen_non_duplicate(6);
});
this.$parent.data.list = this.list;
var moveBeforeIndex = 0;
var _this = this;
setTimeout(function () {
var componentIndex = _this.data.index;
$('[data-index="' + componentIndex + '"] .navigation-set-list').DDSort({
target: 'li',
floatStyle: {
'border': '1px solid #ccc',
'background-color': '#fff'
},
//设置可拖拽区域
draggableArea: "icontuodong",
down: function (index) {
moveBeforeIndex = index;
},
up: function () {
var index = $(this).index();
var temp = _this.list[moveBeforeIndex];
_this.list.splice(moveBeforeIndex, 1);
_this.list.splice(index, 0, temp);
_this.$parent.data.list = _this.list;
}
});
})
},
watch: {
"data.pageCount"() {
if (this.data.showStyle == 'pageSlide')
this.data.tempData.carouselIndex = 0
},
"data.rowCount"() {
if (this.data.showStyle == 'pageSlide')
this.data.tempData.carouselIndex = 0
}
},
methods: {
setnum(num){
console.log(num)
this.data.rowCount = num
if(num == 3){
this.data.list = [
{
"title": "200",
"unit": "万",
"desc": "这里填写描述",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"icon": "",
"iconType": "img",
"imageUrl": "",
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
}
},
{
"title": "300",
"unit": "万",
"desc": "这里填写描述",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"icon": "",
"iconType": "img",
"imageUrl": "",
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
}
},
{
"title": "400",
"unit": "万",
"desc": "这里填写描述",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"icon": "",
"iconType": "img",
"imageUrl": "",
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
}
}
]
}else{
this.data.list = [
{
"title": "200",
"unit": "万",
"desc": "这里填写描述",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"icon": "",
"iconType": "img",
"imageUrl": "",
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
}
},
{
"title": "300",
"unit": "万",
"desc": "这里填写描述",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"icon": "",
"iconType": "img",
"imageUrl": "",
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
}
},
{
"title": "400",
"unit": "万",
"desc": "这里填写描述",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"icon": "",
"iconType": "img",
"imageUrl": "",
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
}
},
{
"title": "500",
"unit": "万",
"desc": "这里填写描述",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"icon": "",
"iconType": "img",
"imageUrl": "",
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
}
}
]
}
},
addNav() {
this.list.push({
"title": "",
"icon": "",
"imageUrl": "",
"iconType": "img",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
},
id: ns.gen_non_duplicate(6)
});
},
verify: function (index) {
var res = {code: true, message: ""};
/* $(".draggable-element[data-index='" + index + "'] .digit-navigation .digit-nav-list .navigation-set-list>li").each(function (i) {
if (vue.data[index].mode === "img") {
$(this).find("input[name='title']").removeAttr("style");//清空输入框的样式
//检测是否有未上传的图片
if (vue.data[index].list[i].imageUrl === "") {
res.code = false;
res.message = "请选择一张图片";
$(this).find(".error-msg").text("请选择一张图片").show();
return res;
} else {
$(this).find(".error-msg").text("").hide();
}
} else {
if (vue.data[index].list[i].title === "") {
res.code = false;
res.message = "请输入标题";
$(this).find("input[name='title']").attr("style", "border-color:red !important;").focus();
$(this).find(".error-msg").text("请输入标题").show();
return res;
} else {
$(this).find("input[name='title']").removeAttr("style");
$(this).find(".error-msg").text("").hide();
}
}
});*/
return res;
}
}
});
var uploadImgHtml = '<div class="img-icon-box">';
uploadImgHtml += '<img-icon-upload :data="{data:myData.data}"></img-icon-upload>';
uploadImgHtml += '<div class="action-box">';
uploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="风格" @click="iconStyle($event)"><i class="iconfont iconpifu"></i></div>';
uploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="背景" @click="selectColor(\'listmenu-nav-color-\' +id)" :id="\'listmenu-nav-color-\' +id"><i class="iconfont iconyanse"></i></div>';
//uploadImgHtml += '<div class="action" title="标签" @click="selectLabel()"><i class="iconfont iconbiaoqian1"></i></div>';
uploadImgHtml += '</div>';
uploadImgHtml += '</div>';
Vue.component("image-upload", {
template: uploadImgHtml,
props: {
data: {
type: Object,
default: function () {
return {
data: {},
field: "",
callback: null
};
}
}
},
data: function () {
return {
myData: this.data,
list: [],
parent: this.$parent.data,
id: ns.gen_non_duplicate(10),
colorPicker:{}
};
},
created: function () {
if (this.myData.field === undefined) this.myData.field = "imageUrl";
this.id = ns.gen_non_duplicate(10);
},
methods: {
// 选择图标风格
iconStyle(event) {
var self = this;
selectIconStyle({
elem: event.currentTarget,
icon: self.myData.data.icon,
callback: function (data) {
if (data) {
self.myData.data.style = data;
} else {
iconStyleSet({
style: JSON.stringify(self.myData.data.style),
query: {
icon: self.myData.data.icon
}
}, function (style) {
self.myData.data.style = style;
})
}
}
})
},
/**
* 渲染颜色组件
* @param id
* @param color
* @param callback
*/
colorRender(id, color, callback) {
var self = this;
if (this.colorPicker[id]) return;
setTimeout(function () {
self.colorPicker[id] = Colorpicker.create({
el: id,
color: color,
change: function (elem, hex) {
callback(elem, hex)
}
});
$('#' + id).click();
}, 10)
},
selectColor(id) {
let self = this;
this.colorRender(id, '', function (elem, color) {
if (self.myData.data.style['iconBgImg'] || self.myData.data.style['iconBgColor'].length) {
self.myData.data.style['iconBgColor'] = [color];
} else {
self.myData.data.style['iconColor'] = [color];
}
self.$forceUpdate();
})
},
/**
* 标签设置
* @param data
* @param callback
*/
labelStyle(data, callback) {
layer.open({
title: "标签设置",
type: 2,
area: ['800px', '420px'],
fixed: false, //不固定
btn: ['保存', '取消'],
content: ns.url("shop/diy/selectlabel?request_mode=iframe", data ? data : {}),
yes: function (index, layero) {
var iframeWin = window[layero.find('iframe')[0]['name']];//得到iframe页的窗口对象执行iframe页的方法
iframeWin.selectLabelListener(function (obj) {
if (typeof callback == "string") {
try {
eval(callback + '(obj)');
layer.close(index);
} catch (e) {
console.error('回调函数' + callback + '未定义');
}
} else if (typeof callback == "function") {
callback(obj);
layer.close(index);
}
});
}
});
},
selectLabel() {
let self = this;
this.labelStyle(self.myData.data.label, function (data) {
self.myData.data.label = data;
self.$forceUpdate();
})
}
}
});

View File

@@ -0,0 +1,31 @@
.float-btn .comp-title {display: none;}
.float-btn .float-btn-box {display: flex;flex-direction: column;align-items: flex-end;justify-content: center;text-align: center;border: 1px dashed;}
.float-btn .float-btn-item:nth-last-child(1) {margin-bottom: 0;}
.float-btn .float-btn-item {display: flex;justify-content: center;align-items: center;flex-direction: column;margin-bottom: 10px;overflow: hidden;}
.float-btn .float-btn-item .img-box, .float-btn .float-btn-item .icon-box {overflow: hidden;display: flex;justify-content: center;align-items: center;}
.float-btn .float-btn-item .img-box img {max-width: 100%;max-height: 100%;}
.float-btn .float-btn-item span {margin-top: 5px;color: #333;font-size: 12px;}
.float-btn .float-btn-list li, .float-btn .float-btn-list .add-item {display: flex;align-items: end;border: 1px dashed #e5e5e5;padding: 10px;}
.float-btn .float-btn-list li + li {margin: 10px 0;}
.float-btn .float-btn-list .right-wrap {display: flex;flex-direction: column;flex: 1;width: 0;}
.float-btn-list .right-wrap .action-box {display: flex;margin-bottom: 4px;}
.float-btn-list .action {margin-right: 10px;width: 42px;height: 28px;line-height: 28px;text-align: center;border: 1px solid #EEEEEE;cursor: pointer;}
.float-btn-list .action .iconfont {font-size: 20px;}
.float-btn-list .action:hover {border-color: var(--base-color);color: var(--base-color);}
.float-btn .right-wrap .layui-form-item {margin-bottom: 0;}
.float-btn .right-wrap .layui-form-label {text-align: left;}
.float-btn .float-btn-list .add-item {justify-content: center;align-items: center;margin: 10px 0;cursor: pointer;}
.float-btn .float-btn-list .add-item i {font-weight: bold;display: inline-block;height: 24px;line-height: 24px;font-size: 18px;margin-right: 10px;}
.float-btn .float-btn-list .add-item span {display: inline-block;height: 24px;line-height: 24px;}
.float-btn .float-btn-list li {position: relative;}
.float-btn .float-btn-list li:hover .del {display: block;}
.float-btn {position: absolute;}
.float-btn .preview-draggable {padding: 0;}
.float-btn.left {background: rgba(255, 255, 255, 0.45);margin-left: 10px;top: 130px;}
.float-btn.left .edit-attribute {right: -980px;top: -100px;}
.float-btn.right_bottom {margin-left: 10px;bottom: 130px;left: 642px;}
.float-btn-list {margin-left: 20px;}
.float-btn-list .hint {margin: 10px 0 10px 0;color: #909399;font-size: 12px;}
.float-btn .tab-wrap {display: none !important;}
.float-btn .icon-radio .icon-wrap i {color: #303133;}
.float-btn .preview-draggable .del {right: -20px;}

View File

@@ -0,0 +1,45 @@
<nc-component :data="data[index]" class="float-btn" data-disabled="1">
<!-- 预览 -->
<template slot="preview">
<template v-if="nc.lazyLoad">
<div class="float-btn-box border-color" data-disabled="1">
<div v-for="(item,previewIndex) in nc.list" :key="previewIndex" :index="previewIndex" class="float-btn-item" data-disabled="1">
<div class="img-box" data-disabled="1" v-if="!item.iconType || item.iconType == 'img'" :style="{ width : nc.imageSize + 'px',height : nc.imageSize + 'px' }">
<img :src="changeImgUrl(item.imageUrl)" data-disabled="1">
</div>
</div>
</div>
</template>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<div class="template-edit-title">
<h3>按钮位置</h3>
<btn-position></btn-position>
<slide :data="{ field : 'btnBottom', label : '上下偏移' }"></slide>
</div>
<div class="template-edit-title">
<h3>图片设置</h3>
<slide :data="{ field : 'imageSize', label : '图片大小', min: 40, max : 100 }"></slide>
<float-btn-list></float-btn-list>
</div>
</template>
</template>
<!-- 样式编辑 -->
<template slot="edit-style"></template>
<!-- 资源 -->
<template slot="resource">
<js>
var floatBtnResourcePath = "{$resource_path}"; // http路径
var floatBtnRelativePath = "{$relative_path}"; // 相对路径
</js>
<css src="{$resource_path}/css/design.css"></css>
<js src="{$resource_path}/js/design.js"></js>
</template>
</nc-component>

View File

@@ -0,0 +1,309 @@
var floatBtnListHtml = '<div class="float-btn-list">';
floatBtnListHtml += '<p class="hint" style="font-size: 12px; margin: 5px 0 8px;">建议上传正方形图片</p>';
floatBtnListHtml += '<ul>';
floatBtnListHtml += '<li v-for="(item,index) in list" :key="item.id">';
floatBtnListHtml += '<img-icon-upload :data="{data : item}"></img-icon-upload>';
floatBtnListHtml += '<div class="right-wrap">';
floatBtnListHtml += '<div class="action-box" v-show="item.iconType == \'icon\'">';
floatBtnListHtml += '<div class="action" @click="iconStyle($event, index)"><i class="iconfont iconpifu"></i></div>';
floatBtnListHtml += '<div class="action" :id="\'float-btn-color-\' + index"><i class="iconfont iconyanse"></i></div>';
floatBtnListHtml += '</div>';
floatBtnListHtml += '<nc-link :data="{field: $parent.data.list[index].link}"></nc-link>';
floatBtnListHtml += '</div>';
floatBtnListHtml += '<i class="del" @click="del(index)" data-disabled="1">x</i>';
floatBtnListHtml += '<div class="error-msg"></div>';
floatBtnListHtml += '</li>';
floatBtnListHtml += '</ul>';
floatBtnListHtml += '<div class="add-item text-color" v-if="showAddItem" @click="add">';
floatBtnListHtml += '<i>+</i>';
floatBtnListHtml += '<span>添加一个浮动按钮</span>';
floatBtnListHtml += '</div>';
floatBtnListHtml += '</div>';
Vue.component("float-btn-list",{
data: function () {
return {
list: this.$parent.data.list,
maxTip : 3,//最大上传数量提示
showAddItem : true,
screenWidth:0,
colorPicker:{}
};
},
created : function(){
if(!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['textColor','pageBgColor','componentBgColor','elementBgColor','marginTop','marginBottom','marginBoth','componentAngle','elementAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
getElementPosition(this.$parent);
window.onresize = () => {
return (() => {
window.screenWidth = document.body.clientWidth;
this.screenWidth = window.screenWidth
})()
};
this.changeShowAddItem();//获取默认值
this.list.forEach(function (item) {
if (!item.id) item.id = ns.gen_non_duplicate(10)
})
},
watch : {
list : function(){
this.changeShowAddItem();
getElementPosition(this.$parent)
},
screenWidth(val){
// 为了避免频繁触发resize函数导致页面卡顿使用定时器
getElementPosition(this.$parent);
},
"$parent.data.btnBottom": function () {
getElementPosition(this.$parent);
}
},
mounted(){
this.fetchAllMenuIconColor();
},
methods: {
verify :function () {
var res = { code: true, message: "" };
if(this.list.length >0){
for(var i=0;i < this.list.length;i++){
if(this.$parent.data.list[i].imageUrl == "" && this.$parent.data.list[i].icon == ""){
res.code = false;
res.message = "请添加图片";
break;
}
}
}else{
res.code = false;
res.message = "请添加一个浮动按钮";
}
return res;
},
//改变添加浮动按钮
changeShowAddItem(){
if(this.list.length >= this.maxTip) this.showAddItem = false;
else this.showAddItem = true;
},
/**
* 选择图标风格
* @param event
* @param index
*/
iconStyle(event, index){
var self = this;
selectIconStyle({
elem: event.currentTarget,
icon: self.list[index].icon,
callback: function (data) {
if (data) {
self.list[index].style = data;
} else {
iconStyleSet({
style: JSON.stringify(self.list[index].style),
query: {
icon: self.list[index].icon
}
}, function(style){
self.list[index].style = style;
})
}
}
})
},
/**
* 渲染颜色组件
* @param id
* @param color
* @param callback
*/
colorRender(id, color, callback){
var self = this;
if (this.colorPicker[id]) return;
setTimeout(function () {
self.colorPicker[id] = Colorpicker.create({
el: id,
color: color,
change: function (elem, hex) {
callback(elem, hex)
}
});
})
},
/**
* 渲染全部菜单颜色选择器
*/
fetchAllMenuIconColor(){
var self = this;
this.list.forEach(function (item, index) {
self.colorRender('float-btn-color-' + index, '', function (elem, color) {
index = $(elem).parents('li').index();
if (self.list[index].style.iconBgColor.length || self.list[index].style.iconBgImg) {
self.list[index].style.iconBgColor = [color];
} else {
self.list[index].style.iconColor = [color];
}
self.$forceUpdate();
})
})
},
add(){
var self = this;
this.list.push({ imageUrl : '', title : '', link : {name: ''}, iconType: 'img', icon: '', style: {fontSize: 60, iconBgColor: [], iconBgColorDeg: 0,iconBgImg: '',bgRadius: 0,iconColor: ['#000'],iconColorDeg: 0}})
this.colorRender('float-btn-color-' + (this.list.length - 1), '', function (elem, color) {
var index = $(elem).parents('li').index();
if (self.list[index].style.iconBgColor.length || self.list[index].style.iconBgImg) {
self.list[index].style.iconBgColor = [color];
} else {
self.list[index].style.iconColor = [color];
}
self.$forceUpdate();
})
},
del(index){
this.list.splice(index, 1);
delete this.colorPicker['float-btn-color-' + index];
}
},
template: floatBtnListHtml
});
/**
* 按钮位置
*/
var btnPosition = '<div class="layui-form-item icon-radio">';
btnPosition += '<label class="layui-form-label sm">{{data.label}}</label>';
btnPosition += '<div class="layui-input-block">';
btnPosition += '<template v-for="(item,index) in list">';
btnPosition += '<span :class="[parent[data.field] == item.value ? \'\' : \'layui-hide\']">{{item.label}}</span>';
btnPosition += '</template>';
btnPosition += '<ul class="icon-wrap">';
btnPosition += '<template v-for="(item,index) in list">';
btnPosition += '<li @click="changePosition(item.value)" :class="{\'border-color\':parent[data.field] == item.value}">';
btnPosition += '<i class="iconfont" :class="[item.icon_img,parent[data.field] == item.value ? \'text-color\' : \'\']"></i>';
btnPosition += '</li>';
btnPosition += '</template>';
btnPosition += '</ul>';
btnPosition += '</div>';
btnPosition += '</div>';
Vue.component("btn-position", {
props: {
data: {
type: Object,
default: function () {
return {
field: "bottomPosition",
label: "按钮位置"
};
}
}
},
data: function () {
return {
list: [
{
label: "左上",
value: "1",
icon_img: "iconzuoshangjiao",
},
{
label: "右上",
value: "2",
icon_img: "iconyoushangjiao",
},
{
label: "左下",
value: "3",
icon_img: "iconzuoxiajiao",
},
{
label: "右下",
value: "4",
icon_img: "iconyouxiajiao",
},
],
parent: this.$parent.data,
imageSize: this.$parent.data.imageSize,
};
},
created: function () {
$('.float-btn').parent('.draggable-element').css({"border": "none"});// 将边框进行隐藏掉
},
watch: {
"$parent.data.imageSize": function () {
getElementPosition(this.$parent);
}
},
methods: {
changePosition:function(val){
this.parent.bottomPosition = val;
getElementPosition(this.$parent)
}
},
template: btnPosition
});
function getElementPosition(params) {
var type = parseInt(params.data.bottomPosition), //布局类型1为第一种2为第二种依次类推
bottomNumber = parseInt(params.data.btnBottom); //上下偏移的变量
/**
* #diyView .diy-view-wrap .preview-block =》 显示框【定位的参照对象是body】#diyView =》 外边框【定位的参照对象是body】
* 1、弹窗按钮是根据“外边框”进行定位的,但弹窗按钮是需要在“显示框”中展示
* 2、弹窗按钮与显示框的上下间距定义为50px,左右为30px这个是常量
* 3、计算弹窗按钮的四个位置都是根据 topleft进行计算的
* */
var box = document.querySelector("#diyView .diy-view-wrap .preview-block").getBoundingClientRect();
var box1 = document.querySelector("#diyView").getBoundingClientRect();
var topVal = 0; //弹窗按钮的top
var leftVal = 0; //弹窗按钮的left
var leftOffSet = 30; //弹窗按钮左右的偏移量
if (type == 1) {
// topVal = 显示框的top - 外边框的top + 距离显示框下边距的50px + 偏移量
// leftVal = 显示框的left - 外边框的left + 距离显示框右边距的30px
topVal = 100 + bottomNumber + "px";
leftVal = box.left - box1.left + leftOffSet + "px";
} else if (type == 2) {
// topVal = 显示框的top - 外边框的top + 距离显示框下边距的50px + 偏移量
// leftVal = 显示框的left - 外边框的left + 显示框的width82 - 弹窗按钮的width - 距离显示框右边距的30px
topVal = 100 + bottomNumber + "px";
leftVal = box.left - box1.left + box.width - params.data.imageSize - 2 - leftOffSet + "px";
} else if (type == 3) {
// topVal = 显示框的top - 外边框的上边距(20) - 防止贴边(20) - 弹出按钮高度 - 弹出按钮的下外边距 - 偏移量
// leftVal = 显示框的left - 外边框的left + 距离显示框左边距的30px
// topVal = box.top - box1.top + box.height - 82 - topOff - bottomNumber + "px";
topVal = $("#diyView .preview-wrap .div-wrap").height() - 20 - 20 - (params.data.list.length * params.data.imageSize) - ((params.data.list.length - 1) * 10) - bottomNumber + 'px';
leftVal = box.left - box1.left + leftOffSet + "px";
} else if (type == 4) {
// topVal = 显示框的top - 外边框的上边距(20) - 防止贴边(20) - 弹出按钮高度 - 弹出按钮的下外边距 - 偏移量
// leftVal = 显示框的left - 外边框的left + 显示框的width - 弹窗按钮的width - 边框width - 距离显示框右边距的30px
topVal = $("#diyView .preview-wrap .div-wrap").height() - 20 - 20 - (params.data.list.length * params.data.imageSize) - ((params.data.list.length - 1) * 10) - bottomNumber + 'px';
leftVal = box.left - box1.left + box.width - params.data.imageSize - 2 - leftOffSet + "px";
}
$(".draggable-element .float-btn").css({
left: leftVal,
top: topVal,
'z-index': 999
});
$(".draggable-element .float-btn .edit-attribute").css({
position: 'fixed',
right: '15px',
top: Math.abs(box1.top)
})
}

View File

@@ -0,0 +1,71 @@
@CHARSET "UTF-8";
.follow-official-account-wrap{
/*position: absolute;*/
/*width: 370px;*/
/*z-index: 999;*/
}
.follow-official-account-wrap .preview-draggable{
/*padding: 0 !important;*/
}
/* 关注公众号 */
.site-info-box {
padding: 5px 10px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: rgba(0, 0, 0, 0.6);
/*position: absolute;*/
/*width: calc(100% - 20px);*/
/*left:0;*/
}
.site-info-box .site-info {
display: flex;
align-items: center;
}
.site-info-box .site-info .img-box {
width: 35px;
height: 35px;
line-height: initial;
border-radius: 50%;
overflow: hidden;
}
.site-info-box .site-info .img-box img {
width: 100%;
height: 100%;
}
.site-info-box .site-info .info-box {
display: flex;
flex-direction: column;
color: #fff;
justify-content: space-between;
margin-left: 10px;
text-align: left;
width: 200px;
}
.site-info-box .site-info span {
display: -webkit-box;
font-size: 12px;
overflow: hidden;
opacity: 0.8;
white-space: normal;
text-overflow: ellipsis;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.site-info-box .site-info span:nth-child(1) {
width: 150px;
font-weight: bold;
opacity: 1;
font-size: 14px;
}
.site-info-box button {
width: 90px;
height: 28px;
line-height: 28px;
border-radius: 33px;
font-size: 12px;
padding: 0;
}

View File

@@ -0,0 +1,64 @@
<nc-component :data="data[index]" class="follow-official-account-wrap">
<!-- 预览 -->
<template slot="preview">
<div class="site-info-box" :style="{ }" data-disabled="1">
<div class="site-info" data-disabled="1">
<div class="img-box" data-disabled="1">
<img :src="changeImgUrl('public/static/img/default_img/square.png')" />
</div>
<div class="info-box" :style="{ color: '#ffffff' }" data-disabled="1">
<span class="font-size-base">店铺名称</span>
<span>{{ nc.welcomeMsg }}</span>
</div>
</div>
<button class="layui-btn layui-btn-primary text-color">关注公众号</button>
</div>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<div class="template-edit-title">
<h3>内容设置</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">欢迎语</label>
<div class="layui-input-block">
<input type="text" v-model="nc.welcomeMsg" placeholder="请输入欢迎语" class="layui-input" maxlength="20">
</div>
</div>
<div class="layui-form-item checkbox-wrap">
<label class="layui-form-label sm">展示开关</label>
<div class="layui-input-block">
<span v-if="nc.isShow == true">显示</span>
<span v-else>隐藏</span>
<div v-if="nc.isShow == true" @click="nc.isShow = false" class="layui-unselect layui-form-checkbox layui-form-checked" lay-skin="primary">
<i class="layui-icon layui-icon-ok"></i>
</div>
<div v-else @click="nc.isShow = true" class="layui-unselect layui-form-checkbox" lay-skin="primary">
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
<div class="word-aux diy-word-aux">该组件只会在微信内部展示,在普画浏览器或者小程序不展示,需要配置微信公众号,同时用户关注后会自动隐藏</div>
</div>
</div>
</template>
<!-- 样式编辑 -->
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<follow-official-account-sources></follow-official-account-sources>
</template>
</template>
<!-- 资源 -->
<template slot="resource">
<css src="{$resource_path}/css/design.css"></css>
<js src="{$resource_path}/js/design.js"></js>
</template>
</nc-component>

View File

@@ -0,0 +1,38 @@
var followOfficialAccountHtml = '<div></div>';
Vue.component("follow-official-account-sources", {
template: followOfficialAccountHtml,
data: function () {
return {
data: this.$parent.data,
};
},
created: function () {
if (!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['pageBgColor','componentBgColor','textColor','marginBoth','componentAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
// $(".draggable-element .follow-official-account-wrap").css({
// top: 86, // 55+20+11
// });
//
// $(".draggable-element .follow-official-account-wrap .edit-attribute").css({
// position: 'fixed',
// right:15,
// top: 55 // layui-header-right 的高度
// })
},
methods: {
verify: function (index) {
var res = {code: true, message: ""};
if (vue.data[index].welcomeMsg.length === 0) {
res.code = false;
res.message = "请输入欢迎语";
}
return res;
},
}
});

View File

@@ -0,0 +1,5 @@
@CHARSET "UTF-8";
.map-nav-item{
}

View File

@@ -0,0 +1,68 @@
<nc-component :data="data[index]" class="kefu-navigation">
<!-- 预览 -->
<template slot="preview">
<template v-if="nc.lazyLoad">
<div class="kefu-nav" :style="{
backgroundColor: nc.componentBgColor,
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
boxShadow: nc.ornament.type == 'shadow' ? ('0 0 5px ' + nc.ornament.color) : '',
border: nc.ornament.type == 'stroke' ? '1px solid ' + nc.ornament.color : ''
}">
<div class="map-nav-item" v-for="(item) in nc.list" :key="item.id" style="width: 100%">
<img :src="changeImgUrl('public/static/img/default_img/banner-99.jpg')" style="width: 100%">
</div>
</div>
</template>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<kefu-nav-list></kefu-nav-list>
<div class="template-edit-title">
<div class="kefu-nav-list">
<!-- <ul class="navigation-set-list">
<li v-for="(item,previewIndex) in nc.list" :key="item.id">
<div class="layui-form-item">
<label class="layui-form-label sm">经度</label>
<div class="layui-input-block">
<input type="text" name='lng' v-model="item.lng" maxlength="20" class="layui-input" autocomplete="off" />
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label sm">纬度</label>
<div class="layui-input-block">
<input type="text" name='lat' v-model="item.lat" maxlength="20" class="layui-input" autocomplete="off" />
</div>
</div>
<div class="iconfont icontuodong"></div>
</li>
</ul> -->
</div>
</div>
</template>
</template>
<!-- 样式编辑 -->
<template slot="edit-style"></template>
<!-- 资源 -->
<template slot="resource">
<js>
var kefuNavResourcePath = "{$resource_path}"; // http路径
var kefuNavRelativePath = "{$relative_path}"; // 相对路径
</js>
<css src="{$resource_path}/css/design.css?v=1"></css>
<js src="{$resource_path}/js/design.js?v=1"></js>
</template>
</nc-component>

View File

@@ -0,0 +1,264 @@
/**
* [图片导航的图片]·组件
*/
var kefuNavListHtml = '<div style="display: none;"></div>';
Vue.component("kefu-nav-list", {
template: kefuNavListHtml,
data: function () {
return {
data: this.$parent.data,
list: this.$parent.data.list,
ornamentList: [],
};
},
created: function () {
if (!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
// ,'botton_BgColor','botton_Color'
// this.$parent.data.ignore = ['textColor','pageBgColor','componentBgColor','elementBgColor','marginTop','marginBottom','marginBoth','componentAngle','elementAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignore = ['textColor','pageBgColor','componentBgColor','elementBgColor','','','','componentAngle','elementAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
// 组件所需的临时数据
this.$parent.data.tempData = {
...this.$parent.data.tempData,
ornamentList: this.ornamentList,
methods: {
addNav: this.addNav
}
};
this.list.forEach(function (e, i) {
if(!e.id) e.id = ns.gen_non_duplicate(6);
});
this.$parent.data.list = this.list;
var moveBeforeIndex = 0;
var _this = this;
setTimeout(function () {
var componentIndex = _this.data.index;
$('[data-index="' + componentIndex + '"] .navigation-set-list').DDSort({
target: 'li',
floatStyle: {
'border': '1px solid #ccc',
'background-color': '#fff'
},
//设置可拖拽区域
draggableArea: "icontuodong",
down: function (index) {
moveBeforeIndex = index;
},
up: function () {
var index = $(this).index();
var temp = _this.list[moveBeforeIndex];
_this.list.splice(moveBeforeIndex, 1);
_this.list.splice(index, 0, temp);
_this.$parent.data.list = _this.list;
}
});
})
},
methods: {
verify: function (index) {
var res = {code: true, message: ""};
$(".draggable-element[data-index='" + index + "'] .kefu-navigation .kefu-nav-list .navigation-set-list>li").each(function (i) {
if (vue.data[index].list[i].title === "") {
res.code = false;
res.message = "请输入标题";
$(this).find("input[name='title']").attr("style", "border-color:red !important;").focus();
return res;
} else {
$(this).find("input[name='title']").removeAttr("style");
}
});
return res;
}
}
});
var kefuUploadImgHtml = '<div class="img-icon-box">';
kefuUploadImgHtml += '<img-icon-upload :data="{data:myData.data}"></img-icon-upload>';
kefuUploadImgHtml += '<div class="action-box">';
kefuUploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="风格" @click="iconStyle($event)"><i class="iconfont iconpifu"></i></div>';
kefuUploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="背景" @click="selectColor(\'kefu-nav-color-\' +id)" :id="\'kefu-nav-color-\' +id"><i class="iconfont iconyanse"></i></div>';
kefuUploadImgHtml += '</div>';
kefuUploadImgHtml += '</div>';
Vue.component("kefu-image-upload", {
template: kefuUploadImgHtml,
props: {
data: {
type: Object,
default: function () {
return {
data: {},
field: "",
callback: null
};
}
}
},
data: function () {
return {
myData: this.data,
list: [],
parent: this.$parent.data,
id: '',
colorPicker:{}
};
},
created: function () {
this.id = ns.gen_non_duplicate(10);
},
methods: {
// 选择图标风格
iconStyle(event) {
var self = this;
selectIconStyle({
elem: event.currentTarget,
icon: self.myData.data.icon,
callback: function (data) {
if (data) {
self.myData.data.style = data;
} else {
iconStyleSet({
style: JSON.stringify(self.myData.data.style),
query: {
icon: self.myData.data.icon
}
}, function (style) {
self.myData.data.style = style;
})
}
}
})
},
/**
* 渲染颜色组件
* @param id
* @param color
* @param callback
*/
colorRender(id, color, callback) {
var self = this;
if (this.colorPicker[id]) return;
setTimeout(function () {
self.colorPicker[id] = Colorpicker.create({
el: id,
color: color,
change: function (elem, hex) {
callback(elem, hex)
}
});
$('#' + id).click();
}, 10)
},
selectColor(id) {
let self = this;
this.colorRender(id, '', function (elem, color) {
if (self.myData.data.style['iconBgImg'] || self.myData.data.style['iconBgColor'].length) {
self.myData.data.style['iconBgColor'] = [color];
} else {
self.myData.data.style['iconColor'] = [color];
}
self.$forceUpdate();
})
},
}
});
var kefuShowUploadImgHtml = '<div class="img-icon-box">';
kefuShowUploadImgHtml += '<img-icon-upload :data="{data:myData.data}"></img-icon-upload>';
kefuShowUploadImgHtml += '<div class="action-box">';
kefuShowUploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="风格" @click="iconStyle($event)"><i class="iconfont iconpifu"></i></div>';
kefuShowUploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="背景" @click="selectColor(\'kefu-nav-color-\' +id)" :id="\'kefu-nav-color-\' +id"><i class="iconfont iconyanse"></i></div>';
kefuShowUploadImgHtml += '</div>';
kefuShowUploadImgHtml += '</div>';
Vue.component("kefu-image-show-upload", {
template: kefuShowUploadImgHtml,
props: {
data: {
type: Object,
default: function () {
return {
data: {},
field: "imgurl",
callback: null
};
}
}
},
data: function () {
return {
myData: this.data,
list: [],
parent: this.$parent.data,
id: '',
colorPicker:{}
};
},
created: function () {
this.myData.field = "imgurl";
this.id = ns.gen_non_duplicate(10);
},
methods: {
// 选择图标风格
iconStyle(event) {
var self = this;
selectIconStyle({
elem: event.currentTarget,
icon: self.myData.data.icon,
callback: function (data) {
if (data) {
self.myData.data.style = data;
} else {
iconStyleSet({
style: JSON.stringify(self.myData.data.style),
query: {
icon: self.myData.data.icon
}
}, function (style) {
self.myData.data.style = style;
})
}
}
})
},
/**
* 渲染颜色组件
* @param id
* @param color
* @param callback
*/
colorRender(id, color, callback) {
var self = this;
if (this.colorPicker[id]) return;
setTimeout(function () {
self.colorPicker[id] = Colorpicker.create({
el: id,
color: color,
change: function (elem, hex) {
callback(elem, hex)
}
});
$('#' + id).click();
}, 10)
},
selectColor(id) {
let self = this;
this.colorRender(id, '', function (elem, color) {
if (self.myData.data.style['iconBgImg'] || self.myData.data.style['iconBgColor'].length) {
self.myData.data.style['iconBgColor'] = [color];
} else {
self.myData.data.style['iconColor'] = [color];
}
self.$forceUpdate();
})
},
}
});

View File

@@ -0,0 +1,9 @@
@CHARSET "UTF-8";
/* 商品品牌组件 */
.goods-brand .title-wrap{text-align: center;padding: 10px 0 5px;}
.goods-brand ul{display: flex;flex-wrap: wrap;align-items: center;padding: 10px;}
.goods-brand ul li{width: 22.59%;margin-top: 10px;text-align: center;margin-right: 10px;}
.goods-brand ul li:nth-of-type(1),.goods-brand ul li:nth-of-type(2),.goods-brand ul li:nth-of-type(3),.goods-brand ul li:nth-of-type(4){margin-top: 0;}
.goods-brand ul li:nth-of-type(4n){margin-right: 0;}
.goods-brand ul li img{max-width: 100%;}
.goods-brand ul li span{display: block;height: 40px;background: #c7c7c7;line-height: 40px;color: #fff;padding: 5px;}

View File

@@ -0,0 +1,112 @@
<nc-component :data="data[index]" class="goods-brand">
<!-- 预览 -->
<template slot="preview">
<div class="brand-wrap" :style="{ backgroundColor: nc.componentBgColor,
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
boxShadow: nc.ornament.type == 'shadow' ? ('0 0 5px ' + nc.ornament.color) : '',
border: nc.ornament.type == 'stroke' ? '1px solid ' + nc.ornament.color : ''
}">
<h3 class="title-wrap" v-show="nc.title" :style="{ color : nc.textColor, fontWeight : nc.fontWeight ? 'bold' : ''}">{{ nc.title }}</h3>
<ul v-if="nc.previewList && Object.keys(nc.previewList).length">
<li v-for="(item, previewIndex) in nc.previewList" :key="previewIndex">
<img :src="item.image_url ? changeImgUrl(item.image_url) : '{$resource_path}/img/default.png'" :style="{
borderTopLeftRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0)
}" onerror="this.src = '{$resource_path}/img/default.png';" />
</li>
</ul>
</div>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<goods-brand-sources></goods-brand-sources>
<div class="template-edit-title">
<h3>品牌标题</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">标题</label>
<div class="layui-input-block">
<input type="text" v-model="nc.title" maxlength="20" placeholder="请输入标题" class="layui-input">
</div>
</div>
</div>
<div class="template-edit-title">
<h3>品牌数据</h3>
<div class="layui-form-item" v-if="nc.tempData.goodsSources">
<label class="layui-form-label sm">数据来源</label>
<div class="layui-input-block">
<div class="source-selected">
<div class="source">{{ nc.tempData.goodsSources[nc.sources].text }}</div>
<div v-for="(item,sourcesKey) in nc.tempData.goodsSources" :key="sourcesKey" class="source-item" :title="item.text" @click="nc.sources=sourcesKey" :class="{ 'text-color border-color' : (nc.sources == sourcesKey) }">
<i class='iconfont' :class='item.icon'></i>
</div>
</div>
</div>
</div>
<div class="layui-form-item" v-if="nc.sources == 'diy'">
<label class="layui-form-label sm">手动选择</label>
<div class="layui-input-block">
<div class="selected-style" @click="nc.tempData.methods.addBrand()">
<span v-if="nc.brandIds.length == 0">请选择</span>
<span v-if="nc.brandIds.length > 0" class="text-color">已选{{ nc.brandIds.length }}个</span>
<i class="iconfont iconyoujiantou"></i>
</div>
</div>
</div>
<slide :data="{ field : 'count', label: '品牌数量', min:1, max: 30}" v-if="nc.sources != 'diy'"></slide>
</div>
</template>
</template>
<!-- 样式编辑 -->
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<div class="template-edit-title">
<h3>品牌样式</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">标题粗细</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="nc.fontWeight = !nc.fontWeight" :class="{ 'layui-form-checked' : nc.fontWeight }">
<span>{{ nc.fontWeight ? '粗' : '细' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item tag-wrap">
<label class="layui-form-label sm">边框</label>
<div class="layui-input-block">
<div v-for="(item,ornamentIndex) in nc.tempData.ornamentList" :key="ornamentIndex" @click="nc.ornament.type=item.type" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.ornament.type==item.type) }">
<i class="layui-anim layui-icon">{{ nc.ornament.type == item.type ? "&#xe643;" : "&#xe63f;" }}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<color v-if="nc.ornament.type != 'default'" :data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }"></color>
<slide v-show="nc.elementAngle == 'round'" :data="{ field : 'topElementAroundRadius', label : '上圆角', max : 50 }"></slide>
<slide v-show="nc.elementAngle == 'round'" :data="{ field : 'bottomElementAroundRadius', label : '下圆角', max : 50 }"></slide>
</div>
</template>
</template>
<!-- 资源 -->
<template slot="resource">
<css src="{$resource_path}/css/design.css"></css>
<js src="{$resource_path}/js/design.js"></js>
</template>
</nc-component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,72 @@
var brandHtml = '<div></div>';
Vue.component("goods-brand-sources", {
template: brandHtml,
data: function () {
return {
data: this.$parent.data,
goodsSources: {
initial: {
text: "默认",
icon: "iconmofang"
},
diy: {
text: "手动选择",
icon: "iconshoudongxuanze"
},
},
ornamentList: [
{
type: 'default',
text: '默认',
},
{
type: 'shadow',
text: '投影',
},
{
type: 'stroke',
text: '描边',
},
],
};
},
created: function () {
this.$parent.data.ignore = ['elementBgColor'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
if(Object.keys(this.$parent.data.previewList).length == 0) {
for (var i = 1; i < 5; i++) {
this.$parent.data.previewList["brand_id_" + ns.gen_non_duplicate(i)] = {
image_url: "",
};
}
}
// 组件所需的临时数据
this.$parent.data.tempData = {
goodsSources: this.goodsSources,
ornamentList: this.ornamentList,
methods: {
addBrand: this.addBrand,
},
};
},
methods: {
verify: function (index) {
var res = {code: true, message: ""};
if (vue.data[index].sources === 'diy' && vue.data[index].brandIds.length === 0) {
res.code = false;
res.message = "请选择文章";
}
return res;
},
addBrand: function () {
var self = this;
goodsBrandSelect(function (res) {
self.$parent.data.brandIds = res.brandIds;
self.$parent.data.previewList = res.list;
}, {select_id: self.$parent.data.brandIds.toString()});
},
}
});

View File

@@ -0,0 +1,18 @@
/* 公共*/
.goods-category .preview-draggable{padding:0;}
.goods-category{background: #ffffff;}
.goods-category .templet-list{display: flex;justify-content: space-between;flex-wrap: wrap;}
.goods-category .templet-img-box{display: flex;justify-content: center;align-items: center;width: 150px;min-height: 90px;border: 1px solid #eee;margin-bottom: 10px;}
.goods-category .templet-img-box img{max-height: 100%;max-width: 100%;}
.goods-category .real-image-box{/*width: 375px;height: 550px;*/}
.goods-category .real-image-box img{/*max-height: 100%;*/max-width: 100%;}
.goods-category-popup-wrap{display: none;}
/* 弹框中的分类样式*/
.goods-classification-style{padding:0 !important;}
.goods-classification-style .style-title{display: flex;margin-bottom: 20px;}
.goods-classification-style .style-title li{width: 110px;height: 35px;line-height: 35px;text-align: center;border: 1px solid #f1f1f1;color: #666;margin-right: 15px;cursor: pointer;}
.goods-classification-style .style-title li.selected{color: #fff;}
.goods-classification-style .style-content li{display: flex;justify-content: space-between;flex-wrap: wrap;}
.goods-classification-style .style-content li .style-img-box{overflow: hidden;position: relative;width: 280px;height: 480px;border: 1px solid #f4f4f4;display: flex;justify-content: space-between;align-items: center;cursor: pointer;margin-top: 15px;}
.goods-classification-style .style-content li .style-img-box:nth-child(1), .goods-classification-style .style-content li .style-img-box:nth-child(2), .goods-classification-style .style-content li .style-img-box:nth-child(3){margin-top: 0;}
.goods-classification-style .style-content li .style-img-box img{max-height: 100%;max-width: 100%;}

View File

@@ -0,0 +1,54 @@
<nc-component :data="data[index]" class="goods-category">
<!-- 预览 -->
<template slot="preview">
<div class="real-image-box" data-disabled="1">
<img :src="'{$resource_path}/img/category_style_' + nc.template + ((nc.template == 1 && nc.level == 2 || nc.template != 1 && nc.goodsLevel ==1) ? '_1' : '') + ((nc.template == 1 && nc.level == 3 || nc.template != 1 && nc.goodsLevel == 2) ? '_2' : '') + (nc.quickBuy ? '_quickBuy' : '') + (nc.search ? '_search' : '') +'.jpg'">
</div>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<goods-category></goods-category>
</template>
<div class="goods-category-popup-wrap">
<div class="goods-classification-style layui-form">
<ul class="style-content">
<li>
<div :class="{'style-img-box':true,'selected border-color': nc.template == 1}">
<img src="{$resource_path}/img/category_style_1_1_search.jpg" alt="">
</div>
<div :class="{'style-img-box':true,'selected border-color': nc.template == 2}">
<img src="{$resource_path}/img/category_style_2_1_quickBuy_search.jpg" alt="">
</div>
<div :class="{'style-img-box':true,'selected border-color': nc.template == 3}">
<img src="{$resource_path}/img/category_style_3_1_search.jpg" alt="">
</div>
<div :class="{'style-img-box':true,'selected border-color': nc.template == 4}">
<img src="{$resource_path}/img/category_style_4_1_quickBuy_search.jpg" alt="">
</div>
</li>
</ul>
<input type="hidden" class="layui-input" name="level">
<input type="hidden" class="layui-input" name="template">
</div>
</div>
</template>
<!-- 样式编辑 -->
<template slot="edit-style"></template>
<!-- 资源 -->
<template slot="resource">
<js>
var goodsCategoryResourcePath = "{$resource_path}"; // http路径
var goodsCategoryRelativePath = "{$relative_path}"; // 相对路径
</js>
<css src="{$resource_path}/css/design.css"></css>
<js src="{$resource_path}/js/design.js"></js>
</template>
</nc-component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

View File

@@ -0,0 +1,199 @@
/**
* 空的验证组件,后续如果增加业务,则更改组件
*/
var goodsCategoryHtml = '<div class="goods-category-edit layui-form">';
goodsCategoryHtml += '<div class="layui-form-item">';
goodsCategoryHtml += '<label class="layui-form-label sm">风格</label>';
goodsCategoryHtml += '<div class="layui-input-block">';
goodsCategoryHtml += '<p class="selected-style text-color" @click="selectClassificationStyle()">选择</p>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div class="layui-form-item">';
goodsCategoryHtml += '<label class="layui-form-label sm">顶部搜索框</label>';
goodsCategoryHtml += '<div class="layui-input-block">';
goodsCategoryHtml += '<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="data.search = data.search == 1 ? 0 : 1" :class="{ \'layui-form-checked\' : data.search == 1 }">';
goodsCategoryHtml += '<span>{{ data.search == 1 ? \'显示\' : \'隐藏\' }}</span>';
goodsCategoryHtml += '<i class="layui-icon layui-icon-ok"></i>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div class="layui-form-item" v-show="data.template == 1">';
goodsCategoryHtml += '<label class="layui-form-label sm">展示分类</label>';
goodsCategoryHtml += '<div class="layui-input-block">';
goodsCategoryHtml += '<div @click="data.level = 2" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.level == 2) }">';
goodsCategoryHtml += '<i class="layui-anim layui-icon">&#xe63f;</i>';
goodsCategoryHtml += '<div>二级分类</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div @click="data.level = 3" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.level == 3) }">';
goodsCategoryHtml += '<i class="layui-anim layui-icon">&#xe63f;</i>';
goodsCategoryHtml += '<div>三级分类</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div class="layui-form-item" v-show="data.template == 2 || data.template == 3 || data.template == 4">';
goodsCategoryHtml += '<label class="layui-form-label sm">展示分类</label>';
goodsCategoryHtml += '<div class="layui-input-block">';
goodsCategoryHtml += '<div @click="data.goodsLevel = 1" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.goodsLevel == 1) }">';
goodsCategoryHtml += '<i class="layui-anim layui-icon">&#xe63f;</i>';
goodsCategoryHtml += '<div>{{data.template == 4 ? "二级分类" : "一级分类"}}</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div @click="data.goodsLevel = 2" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.goodsLevel == 2) }">';
goodsCategoryHtml += '<i class="layui-anim layui-icon">&#xe63f;</i>';
goodsCategoryHtml += '<div>{{data.template == 4 ? "三级分类" : "二级分类"}}</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div class="layui-form-item" v-show="data.template == 2 || data.template == 3 || data.template == 4">';
goodsCategoryHtml += '<label class="layui-form-label sm">商品排序</label>';
goodsCategoryHtml += '<div class="layui-input-block">';
goodsCategoryHtml += '<div v-for="(item,sortIndex) in sortWayList" :key="sortIndex" @click="data.sortWay=item.value" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.sortWay==item.value) }">';
goodsCategoryHtml += '<i class="layui-anim layui-icon">{{ data.sortWay == item.value ? "&#xe643;" : "&#xe63f;" }}</i>';
goodsCategoryHtml += '<div>{{item.text}}</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div class="layui-form-item" v-show="(data.template == 2 || data.template == 3) && data.goodsLevel == 1">';
goodsCategoryHtml += '<label class="layui-form-label sm">加载模式</label>';
goodsCategoryHtml += '<div class="layui-input-block">';
goodsCategoryHtml += '<div @click="data.loadType = \'all\'" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.loadType == \'all\') }">';
goodsCategoryHtml += '<i class="layui-anim layui-icon">&#xe63f;</i>';
goodsCategoryHtml += '<div>全部加载</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div @click="data.loadType = \'part\'" :class="{ \'layui-unselect layui-form-radio\' : true,\'layui-form-radioed\' : (data.loadType == \'part\') }">';
goodsCategoryHtml += '<i class="layui-anim layui-icon">&#xe63f;</i>';
goodsCategoryHtml += '<div>部分加载</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '<div class="layui-form-item" v-show="data.template == 2 || data.template == 4">';
goodsCategoryHtml += '<label class="layui-form-label sm">快捷购买</label>';
goodsCategoryHtml += '<div class="layui-input-block">';
goodsCategoryHtml += '<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="data.quickBuy = data.quickBuy == 1 ? 0 : 1" :class="{ \'layui-form-checked\' : data.quickBuy == 1 }">';
goodsCategoryHtml += '<span>{{ data.quickBuy == 1 ? \'显示\' : \'隐藏\' }}</span>';
goodsCategoryHtml += '<i class="layui-icon layui-icon-ok"></i>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
goodsCategoryHtml += '</div>';
Vue.component("goods-category", {
template: goodsCategoryHtml,
data: function () {
return {
data: this.$parent.data,
categoryData:[
{
search: 1,
level:2,
goodsLevel: 1,
loadType: 'all',
quickBuy: 0
},
{
search: 1,
level:2,
goodsLevel: 1,
loadType: 'part',
quickBuy: 1
},
{
search: 1,
level:2,
goodsLevel: 1,
loadType: 'part',
quickBuy: 0
},
{
search: 1,
level:2,
goodsLevel: 1,
loadType: 'part',
quickBuy: 1
}
],
sortWayList: [
{
text: "综合",
value: "default"
},
{
text: "新品",
value: "news"
},
{
text: "热销",
value: "sales"
},
{
text: "价格",
value: "price"
}
],
}
},
created:function() {
if(!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['textColor','pageBgColor','componentBgColor','elementBgColor','marginTop','marginBottom','marginBoth','componentAngle','elementAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
if (!this.data.goodsLevel) this.$set(this.data, 'goodsLevel', 1);
if (!this.data.loadType) this.$set(this.data, 'loadType', 'part');
if (!this.data.sortWay) this.$set(this.data, 'sortWay', 'default');
},
methods: {
verify : function (index) {
var res = { code : true, message : "" };
return res;
},
selectClassificationStyle: function () {
var self = this;
layer.open({
type: 0,
title: '选择风格',
area: ['930px', '630px'],
btn: ['确定', '返回'],
content: $(".draggable-element[data-index='" + self.data.index + "'] .edit-attribute .goods-category-popup-wrap").html(),
success: function (layero, index) {
layui.use(['form'], function () {
var form = layui.form;
form.render();
$(".layui-layer-content input[name='level']").val(self.data.level);
$(".layui-layer-content input[name='template']").val(self.data.template);
$("body").off("click", ".layui-layer-content .goods-classification-style .style-title li").on("click", ".layui-layer-content .goods-classification-style .style-title li", function () {
$(this).addClass("selected bg-color").siblings().removeClass("selected bg-color");
$(".layui-layer-content .goods-classification-style .style-content li").eq($(this).index()).removeClass("layui-hide").siblings().addClass('layui-hide');
// 清除所有
$(".layui-layer-content .goods-classification-style .style-content li .style-img-box").removeClass("selected border-color");
// 选中第一个
$(".layui-layer-content .goods-classification-style .style-content li").eq($(this).index()).find(".style-img-box").eq(0).addClass("selected border-color");
$(".layui-layer-content input[name='level']").val($(this).index() + 1);
$(".layui-layer-content input[name='template']").val(1);
});
$("body").off("click", ".layui-layer-content .goods-classification-style .style-content li .style-img-box").on("click", ".layui-layer-content .goods-classification-style .style-content li .style-img-box", function () {
$(".layui-layer-content input[name='template']").val($(this).index() + 1);
$(this).addClass("selected border-color").siblings().removeClass("selected border-color");
});
});
},
yes: function(index, layero){
self.data.level = $(".layui-layer-content input[name='level']").val();
self.data.template = $(".layui-layer-content input[name='template']").val();
self.data = Object.assign(self.data,self.categoryData[self.data.template-1])
layer.closeAll();
},
btn2: function(index, layero){
layer.closeAll();
}
});
}
}
});

View File

@@ -0,0 +1,326 @@
.edit-attribute .tag-wrap .layui-form-radio:last-child{margin-right: 0;}
/* 选择商品分类弹出框 */
.goods-category-layer {display: none;}
.layui-layer-content .category-wrap .category-item, .layui-layer-content .category-head {height: 30px;line-height: 30px;border: 1px solid #ededed;border-radius: 5px;padding: 0 15px;margin: 0 15px 10px 0;box-sizing: border-box;color: #666;font-size: 12px;}
.layui-layer-content .category-head {background: #eee;height: 40px;line-height: 40px;}
.layui-layer-content .category-wrap {overflow-y: scroll;height: calc(100% - 45px);}
.layui-layer-content .category-wrap::-webkit-scrollbar {display: none;}
.layui-layer-content .category-wrap .category-item {cursor: pointer;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}
/* 商品块基础样式 */
/*.goods-list{overflow: hidden;}*/
.goods-list .goods-item {line-height: 1;}
.goods-list .goods-item .sale {align-self: flex-end;font-size: 12px;}
.goods-list .goods-item .info-wrap .goods-name{margin-bottom: 5px;font-size: 14px;line-height: 1.3;}
.goods-list .goods-item .info-wrap .tag-wrap {margin-bottom: 10px;}
.goods-list .goods-item .info-wrap .tag-wrap text{display: inline-block;font-size: 9px;}
.goods-list .goods-item .info-wrap .tag-wrap .hollow-tag{border: 1px solid;border-radius: 2px;margin-right: 5px;box-sizing: border-box;line-height: 1.2;padding: 1px 2px 0;max-width: 100%;}
.goods-list .goods-item .shopping-cart-btn{font-size: 18px;border: 1px solid;border-radius: 50%;padding: 5px;}
.goods-list .goods-item .plus-sign-btn{font-size: 18px;border: 1px solid;border-radius: 50%;padding: 5px;}
.goods-list .goods-item .buy-btn{color: #fff;font-size: 12px;height: 26px;line-height: 28px;padding:0 10px;text-align: center;}
.goods-list .goods-item .price-wrap{font-size: 0;}
.goods-list .goods-item .icon-diy{font-size: 40px;}
/* ---------- 单列(一行一列)---------- */
.goods-list.row1-of1 .goods-item{overflow: hidden;display: flex;margin-bottom: 10px;padding:8px;}
.goods-list.row1-of1 .goods-item:last-of-type{margin-bottom: 0;}
.goods-list.row1-of1 .goods-item .goods-img{width: 130px;height: 130px;}
.goods-list.row1-of1 .goods-item .goods-img img{max-width: 100%;max-height: 100%;}
.goods-list.row1-of1 .goods-item .info-wrap{width: calc(100% - 130px);padding: 3px 0 5px 10px;flex: 1;display: flex;flex-direction: column;box-sizing: border-box;}
.goods-list.row1-of1 .goods-item .info-wrap .pro-info{display: flex;justify-content: space-between;align-items: center;margin-top:auto;}
.goods-list.row1-of1 .goods-item .info-wrap .pro-info .sale{margin-top: 5px;}
.goods-list.row1-of1 .goods-item .info-wrap .pro-info .discount-price{display: flex;justify-content: space-between;flex-direction: column;}
.goods-list.row1-of1 .goods-item .info-wrap .pro-info .discount-price .price-wrap{display: flex;align-items: flex-end;}
.goods-list.row1-of1 .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;}
.goods-list.row1-of1 .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;font-weight: bold;}
.goods-list.row1-of1 .goods-item .info-wrap .pro-info .delete-price{text-decoration: line-through;flex: 1;line-height: 14px;font-size: 12px;}
/* ---------- 两列(一行两列)---------- */
.goods-list.row1-of2{display: flex;flex-wrap: wrap;}
.goods-list.row1-of2 .goods-item{overflow: hidden;margin-right: 10px;margin-top: 10px;width: calc(50% - 5px);display: flex;flex-direction: column;box-sizing: border-box;}
.goods-list.row1-of2 .goods-item:nth-child(2n){margin-right: 0;}
.goods-list.row1-of2 .goods-item:nth-of-type(1), .goods-list.row1-of2 .goods-item:nth-of-type(2){margin-top: 0;}
.goods-list.row1-of2 .goods-item .goods-img{width: calc(100% + 2px);height: 160px;text-align: center;}
.goods-list.row1-of2 .goods-item .goods-img img{width: 100%;height: 100%;}
.goods-list.row1-of2 .goods-item .info-wrap{display: flex;flex-direction: column;flex: 1;padding: 10px;}
.goods-list.row1-of2 .goods-item .info-wrap .pro-info{margin-top: auto;display: flex;justify-content: space-between;}
.goods-list.row1-of2 .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;font-weight: bold;}
.goods-list.row1-of2 .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;font-weight: bold;}
.goods-list.row1-of2 .goods-item .info-wrap .pro-info .delete-price{text-decoration: line-through;flex: 1;line-height: 14px;font-size: 12px;}
.goods-list.row1-of2.style-1 .pro-info .discount-price .price-wrap{display: inline-block;}
.goods-list.row1-of2.style-1 .pro-info .discount-price .delete-price{display: inline-block;margin-left: 5px;}
.goods-list.row1-of2.style-1 .pro-info .sale{margin-top: 5px;}
.goods-list.row1-of2.style-2 .pro-info{align-items: center;}
.goods-list.row1-of2.style-2 .pro-info .discount-price{display: flex;justify-content: space-between;align-items: baseline;flex-direction: column;}
.goods-list.row1-of2.style-2 .pro-info .sale{margin-top: 5px;}
.goods-list.row1-of2.style-3 .pro-info .discount-price{display: flex;justify-content: space-between;flex: 1;align-content: center;}
/* ---------- 三列(一行三个)---------- */
.goods-list.row1-of3{display: flex;flex-wrap: wrap;}
.goods-list.row1-of3 .goods-item{display: flex;flex-direction: column;background: #fff;overflow: hidden;margin-top: 10px;width: calc(33.33% - 6px);box-sizing: border-box;}
.goods-list.row1-of3 .goods-item:nth-child(3n-1){margin-left: 9px;margin-right: 9px;}
.goods-list.row1-of3 .goods-item:nth-of-type(1), .goods-list.row1-of3 .goods-item:nth-of-type(2), .goods-list.row1-of3 .goods-item:nth-of-type(3){margin-top: 0;}
.goods-list.row1-of3 .goods-item .goods-img{width: calc(100% + 2px);height: 110px;}
.goods-list.row1-of3 .goods-item .goods-img img{width: 100%;height: 100%;}
.goods-list.row1-of3 .goods-item .info-wrap{display: flex;flex-direction: column;flex: 1;padding: 5px;}
.goods-list.row1-of3 .goods-item .info-wrap .pro-info{margin-top: auto;display: flex;flex-direction: column;justify-content: space-between;}
.goods-list.row1-of3 .goods-item .info-wrap .pro-info .discount-price{display: flex;justify-content: space-between;align-items: flex-end;}
.goods-list.row1-of3 .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;}
.goods-list.row1-of3 .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;font-weight: bold;}
.goods-list.row1-of3 .goods-item .info-wrap .pro-info .delete-price{text-decoration: line-through;flex: 1;line-height: 14px;font-size: 12px;}
.goods-list.row1-of3.style-1 .pro-info .delete-price{margin-left: 10px;}
.goods-list.row1-of3.style-2 .pro-info{flex-direction: initial !important;align-items: center;}
.goods-list.row1-of3.style-2 .pro-info .discount-price{flex-direction: column;align-items: initial !important;}
/* ---------- 横向滑动 ---------- */
.goods-list.horizontal-slide{white-space: nowrap;overflow: hidden;margin:10px;}
.goods-list.horizontal-slide .goods-item{overflow: hidden;width: 97px;display: inline-block;margin-right: 10px;box-sizing: border-box;}
.goods-list.horizontal-slide .goods-item:last-of-type{margin-right: 0;}
.goods-list.horizontal-slide .goods-item .goods-img{width: calc(100% + 2px);height: 100px;}
.goods-list.horizontal-slide .goods-item .goods-img img{width: 100%;height: 100%;}
.goods-list.horizontal-slide .goods-item .info-wrap{padding: 5px 10px;}
.goods-list.horizontal-slide .goods-item .info-wrap .pro-info{margin-top: 5px;display: flex;flex-direction: column;justify-content: space-between;}
.goods-list.horizontal-slide .goods-item .info-wrap .pro-info .discount-price{display: flex;justify-content: space-between;align-items: center;flex-wrap: wrap;}
.goods-list.horizontal-slide .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;}
.goods-list.horizontal-slide .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;font-weight: bold;}
.goods-list.horizontal-slide .goods-item .info-wrap .pro-info .delete-price{text-decoration: line-through;flex: 1;line-height: 14px;font-size: 12px;align-self: flex-end;flex-basis: 100%;}
/* ---------- 大图 ---------- */
.goods-list.large-mode .goods-item{width: 100%;overflow: hidden;margin-top: 10px;background-color: #fff;}
.goods-list.large-mode .goods-item:first-child{margin-top: 0;}
.goods-list.large-mode .goods-img {width: 101.5%;height: 160px;position: relative;}
.goods-list.large-mode .goods-img img {width: 100%;height: 100%;object-fit: cover;}
.goods-list.large-mode .goods-item .info-wrap{padding: 10px 10px 25px;}
.goods-list.large-mode .goods-item .info-wrap .pro-info{margin-top: 5px;display: flex;justify-content: space-between;align-items: center;position: relative;}
.goods-list.large-mode .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;}
.goods-list.large-mode .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;font-weight: bold;}
.goods-list.large-mode .goods-item .info-wrap .pro-info .delete-price{margin-left: 5px;text-decoration: line-through;flex: 1;line-height: 14px;font-size: 12px;}
.goods-list.large-mode.style-1 .pro-info .discount-price{flex: 1;display: flex;align-items: baseline;}
.goods-list.large-mode.style-1 .pro-info .discount-price .price-wrap{display: flex;align-items: baseline;}
.goods-list.large-mode.style-1 .pro-info .discount-price .delete-price{display: inline-block;}
.goods-list.large-mode.style-1 .pro-info .sale{position: absolute;bottom: -15px;font-size: 12px;}
/* ---------- 购买按钮样式 ---------- */
.goods-list .btn-style .layui-form-label{margin-top: 5px;}
.goods-list .btn-style .layui-input-block{display: flex;align-items: center;}
.goods-list .btn-style .layui-input-block .item{margin-right: 10px;border: 1px solid transparent;padding: 5px;border-radius: 5px;width: 45px;text-align: center;cursor: pointer;height: 30px;line-height: 30px;}
.goods-list .btn-style .layui-input-block .item:last-child{margin-right: 0;width: 60px;}
.goods-list .btn-style .layui-input-block .item:nth-child(2),.goods-list .btn-style .layui-input-block .item:nth-child(3){width: 35px;}
.goods-list .btn-style .layui-input-block .item .border-color{border: 1px solid;}
.goods-list .btn-style .layui-input-block .buy-btn{color: #fff;border-radius: 25px;font-size: 12px;padding: 6px 10px;}
.goods-list .btn-style .layui-input-block .shopping-cart-btn{font-size: 18px;border: 1px solid;border-radius: 50%;padding: 5px;width: 18px;height: 18px;}
.goods-list .btn-style .layui-input-block .plus-sign-btn{font-size: 18px;border: 1px solid;border-radius: 50%;padding: 5px;width: 18px;height: 18px;}
.goods-list .btn-style .layui-input-block .diy-btn{border-radius: 25px;font-size: 12px;padding: 6px 10px;}
.goods-list .diy-icon{margin-top: 10px;margin-bottom: 10px;display: flex;align-items: center;}
.goods-list .diy-icon .action-box {display: flex;margin-bottom: 10px;}
.goods-list .diy-icon .action {margin-right: 10px;width: 42px;height: 28px;line-height: 28px;text-align: center;border: 1px solid #EEEEEE;cursor: pointer;}
.goods-list .diy-icon .action .iconfont {font-size: 20px;}
.goods-list .diy-icon .action:hover {border-color: var(--base-color);color: var(--base-color);}
.goods-list .edit-content-wrap .layui-form-radio{margin-right:5px;}
.goods-list .edit-content-wrap .layui-form-radio:last-child{margin-right: 0;padding-right: 0;}
@CHARSET "UTF-8";
.goods-ads .layui-input-block span.sm span{
max-width: 100px;
}
/*图片广告组件*/
.goods-ads .goods-ads-warp {
overflow: hidden;
position: relative;
}
.goods-ads .goods-ads-warp .goods-ads-item{
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
/* 图片轮播点 */
.goods-ads .carousel-btn{
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.goods-ads .carousel-btn .arrows{
display: flex;
justify-content: space-between;
padding: 0 15px;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.goods-ads .carousel-btn .arrows i{
display: none;
width: 36px;
height: 36px;
line-height: 36px;
text-align: center;
color: #fff;
background-color: rgba(0, 0, 0, .35);
border-radius: 50%;
cursor: pointer;
}
.goods-ads .carousel-btn .dot-wrap{
text-align: center;
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
}
.goods-ads .carousel-btn .dot-wrap.line i{
width: 9px;
height: 3px;
border-radius: 2px;
}
.goods-ads .carousel-btn .dot-wrap.line i:last-of-type{
margin-right: 0;
}
.goods-ads .carousel-btn .dot-wrap.left{
left: 35px;
}
.goods-ads .carousel-btn .dot-wrap.right{
left: auto;
right: 0;
}
.goods-ads .carousel-btn .dot-wrap.hide{
display: none;
}
.goods-ads .carousel-btn .dot-wrap.straightLine i{
width: 12px;
height: 4px;
border-radius: 0;
}
.goods-ads .carousel-btn .dot-wrap i{
display: inline-block;
width: 7px;
height: 7px;
border-radius: 50%;
background-color: #b2b2b2;
margin-right: 5px;
cursor: pointer;
}
.goods-ads .carousel-btn .dot-wrap i.active{
background-color: rgba(0, 0, 0, .6);
}
.goods-ads .carousel-btn .dot-wrap.line i.active{
width: 18px;
}
.goods-ads .carousel-btn:hover .arrows i{
display: block;
}
/* 图片广告 - 属性设置 */
.goods-ads .edit-attribute .attr-wrap .restore-wrap .img-block{
margin-left: 40px;
}
.goods-ads .edit-attribute .attr-wrap .restore-wrap .img-block + .content-block{
width: calc(100% - 125px);
}
.edit-attribute .attr-wrap .restore-wrap .goods-ad-list>ul>li:hover .img-block i.del {
display:block;
}
.goods-ads .goods-ad-list {
margin-left:20px;
}
.goods-ads .goods-ad-list .word-aux {
margin: 10px 0 10px 0;
color: #909399;
font-size: 12px;
}
.goods-ads .goods-ad-list>ul>li {
padding:10px;
background: #ffffff;
border:1px dashed #e5e5e5;
position:relative;
margin-top:16px;
}
.goods-ads .goods-ad-list>ul>li:first-child {
margin-top:0;
}
.goods-ads .goods-ad-list>ul>li .content-block {
display:inline-block;
width:71%;
min-height: 66px;
}
.goods-ads .goods-ad-list>ul>li .content-block.textNavigation {
width:100%;
}
.goods-ads .goods-ad-list>ul>li .content-block .layui-form-item {
margin:0;
}
.goods-ads .goods-ad-list>ul>li .content-block .layui-form-label {
width:60px;
padding:9px 0;
line-height: 1;
}
.goods-ads .goods-ad-list>ul>li .content-block div {
margin-top:10px;
}
.goods-ads .goods-ad-list>ul>li .content-block div:last-child {
margin-top:0;
}
.goods-ads .goods-ad-list>ul>li:hover .del {
display:block;
}
.goods-ads .goods-ad-list>ul>li>.iconfont {
position: absolute;
top: 50%;
left: 15px;
cursor: move;
font-size: 20px;
transform: translateY(-50%);
}
.goods-ads .add-item {
border:1px dashed #e5e5e5;
text-align: center;
cursor:pointer;
background: #ffffff;
padding:10px;
margin:16px 0;
}
.goods-ads .add-item p i {
display: inline-block;
height: 24px;
line-height: 24px;
font-size: 18px;
font-style: normal;
}
.goods-ads .add-item p span {
display: inline-block;
height: 24px;
line-height: 24px;
}
.goods-ads .add-item>span {
vertical-align: middle;
color:#999;
font-size:12px;
}
.goods-ads .navigation-set-list .error-msg{
margin: 5px 0 0 40px;
color: #f44;
display: none;
}

View File

@@ -0,0 +1,610 @@
<nc-component :data="data[index]" class="goods-list goods-ads">
<!-- 预 览 -->
<template slot="preview">
<div :class="['goods-list',nc.template,nc.style]" :style="{ backgroundColor: nc.componentBgColor,
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0)
}">
<template v-if="nc.tempData.previewList && Object.keys(nc.tempData.previewList).length">
<div class="goods-item" v-for="(item, previewIndex,name) in nc.tempData.previewList" :key="previewIndex"
v-if="nc.template=='horizontal-slide'&& name < 3 || nc.template!='horizontal-slide'" :style="{
borderTopLeftRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0),
backgroundColor: nc.elementBgColor,
marginLeft: nc.template == 'horizontal-slide' && (nc.slideMode == 'scroll' && nc.goodsMarginType=='diy' && (nc.goodsMarginNum+'px') || ((60 - nc.margin.both*2) /6 + 'px')) || '',
marginRight: nc.template == 'horizontal-slide' && (nc.slideMode == 'scroll' && nc.goodsMarginType=='diy' && (nc.goodsMarginNum+'px') || ((60 - nc.margin.both*2) /6 + 'px')) || '',
boxShadow: nc.ornament.type == 'shadow' ? ('0 0 5px ' + nc.ornament.color) : '',
border: nc.ornament.type == 'stroke' ? '1px solid ' + nc.ornament.color : ''}">
<div class="goods-img" :style="{ borderRadius: nc.imgAroundRadius + 'px' }">
<img :src="item.goods_image ? changeImgUrl(item.goods_image) : changeImgUrl('public/static/img/default_img/square.png')" onerror="this.src = ns.img('public/static/img/default_img/square.png');"
:style="{ borderRadius: nc.imgAroundRadius + 'px' }"
/>
</div>
<div class="info-wrap"
v-if="nc.goodsNameStyle.control || nc.tag.value != 'hidden' || nc.priceStyle.mainControl || nc.priceStyle.lineControl || nc.btnStyle.control">
<div class="goods-name" v-if="nc.goodsNameStyle.control"
:style="{ color : nc.goodsNameStyle.color,fontWeight : nc.goodsNameStyle.fontWeight ? 'bold' : '' }"
:class="[{'using-hidden' : nc.nameLineMode == 'single'},{'multi-hidden' : nc.nameLineMode == 'multiple'}]">
{{ item.goods_name }}</div>
<div class="tag-wrap" v-if="nc.tag.value != 'hidden'">
<span class="hollow-tag text-color border-color">{{ nc.tag.text }}</span>
</div>
<div class="pro-info">
<div class="discount-price">
<div class="price-wrap" v-if="nc.priceStyle.mainControl">
<span class="unit" :style="{ color : nc.priceStyle.mainColor }">¥</span>
<span class="price"
:style="{ color : nc.priceStyle.mainColor }">{{item.discount_price.split(".")[0]}}</span>
<span class="unit" :style="{ color : nc.priceStyle.mainColor }">.{{
item.discount_price.split(".")[1] != undefined ?
item.discount_price.split(".")[1] : '00'}}</span>
</div>
<div class="delete-price" v-if="nc.priceStyle.lineControl"
:style="{ color : nc.priceStyle.lineColor }">¥{{item.line_price}}</div>
<div class="sale" v-if="nc.saleStyle.control" :style="{ color : nc.saleStyle.color }">
已售{{ item.sale_num }}件</div>
</div>
<template v-if="nc.btnStyle.control">
<!-- 购物车图标 -->
<div v-if="nc.btnStyle.style == 'icon-cart'"
class="cart shopping-cart-btn iconfont icongouwuche"
:style="{ color : nc.btnStyle.textColor }"></div>
<!--加号图标 -->
<div v-else-if="nc.btnStyle.style == 'icon-add'"
class="cart plus-sign-btn iconfont iconjia2"
:style="{ color : nc.btnStyle.textColor }"></div>
<!-- 按钮 -->
<div v-else-if="nc.btnStyle.style == 'button'" class="cart buy-btn"
:style="{fontWeight: (nc.btnStyle.fontWeight ? 'bold' : 'normal'), backgroundColor : nc.btnStyle.bgColor, color : nc.btnStyle.textColor,borderRadius : nc.btnStyle.aroundRadius + 'px',padding : ('0 '+ (nc.btnStyle.padding+10) + 'px') }">
{{ nc.btnStyle.text }}</div>
<!-- 自定义图标 -->
<div v-else-if="nc.btnStyle.style == 'icon-diy'" class="icon-diy">
<iconfont :icon="nc.btnStyle.iconDiy.icon" v-if="nc.btnStyle.iconDiy.icon"
:value="nc.btnStyle.iconDiy.style ? nc.btnStyle.iconDiy.style : ''"></iconfont>
</div>
</template>
</div>
</div>
</div>
</template>
</div>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<goods-list-sources></goods-list-sources>
<div class="template-edit-title">
<h3>商品风格</h3>
<div class="layui-form-item list-style" v-if="nc.tempData.templateList">
<label class="layui-form-label sm">风格</label>
<div class="layui-input-block">
<div class="source">{{ nc.tempData.templateList[nc.template].text }}</div>
<div class="template-selected">
<div v-for="(item,templateKey) in nc.tempData.templateList" :key="templateKey"
class="source-item" :title="item.text"
@click="nc.tempData.methods.selectTemplate(templateKey)"
:class="[(nc.template == templateKey) ? 'text-color border-color' : '' ]">
<i class='iconfont' :class='item.icon'></i>
</div>
</div>
<div class="style-selected">
<div v-for="(item,styleIndex) in nc.tempData.templateList[nc.template].styleList"
:key="styleIndex" @click="nc.tempData.methods.selectTemplate('',item)"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.style==item.value) }">
<i class="layui-anim layui-icon">{{ nc.style == item.value ? "&#xe643;" : "&#xe63f;"
}}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
</div>
</div>
<div class="template-edit-title">
<h3>商品数据</h3>
<div class="layui-form-item" v-if="nc.tempData.goodsSources">
<label class="layui-form-label sm">数据来源</label>
<div class="layui-input-block">
<div class="source-selected">
<div class="source">{{ nc.tempData.goodsSources[nc.sources].text }}</div>
<div v-for="(item,sourcesKey) in nc.tempData.goodsSources" :key="sourcesKey"
class="source-item" :title="item.text" @click="nc.sources=sourcesKey"
:class="{ 'text-color border-color' : (nc.sources == sourcesKey) }">
<i class='iconfont' :class='item.icon'></i>
</div>
</div>
</div>
</div>
<div class="layui-form-item" v-if="nc.sources == 'category'">
<label class="layui-form-label sm">商品分类</label>
<div class="layui-input-block">
<div class="selected-style" @click="nc.tempData.methods.selectCategory()">
<span :class="{ 'text-color' : nc.categoryId > 0 }">{{ nc.categoryName }}</span>
<i class="iconfont iconyoujiantou"></i>
</div>
</div>
</div>
<div class="layui-form-item" v-if="nc.sources == 'diy'">
<label class="layui-form-label sm">手动选择</label>
<div class="layui-input-block">
<div class="selected-style" @click="nc.tempData.methods.addGoods()">
<span v-if="nc.goodsId.length == 0">请选择</span>
<span v-if="nc.goodsId.length > 0" class="text-color">已选{{ nc.goodsId.length }}个</span>
<i class="iconfont iconyoujiantou"></i>
</div>
</div>
</div>
<slide :data="{ field : 'count', label: '商品数量', min:1, max: 30}" v-if="nc.sources != 'diy'"></slide>
<div class="layui-form-item" v-if="nc.sources != 'diy'">
<label class="layui-form-label sm">排序</label>
<div class="layui-input-block">
<div v-for="(item,sortIndex) in nc.tempData.sortWayList" :key="sortIndex"
@click="nc.sortWay=item.value"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.sortWay==item.value) }">
<i class="layui-anim layui-icon">{{ nc.sortWay == item.value ? "&#xe643;" : "&#xe63f;"
}}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<!---手动选择的商品列表--->
<div class="template-edit-title" v-if="nc.sources == 'diy'">
<!-- <goods-list></goods-list> -->
<div class="goods-ad-list">
<ul class="navigation-set-list">
<li v-for="(item,index) in nc.tempData.previewList" :data-sort="index" :data-index="index"
:key="item.id">
<div :id="'goods_'+index" class="img-block layui-form text-color has-choose-image">
<div>
<img :src="item.goods_image ? changeImgUrl(item.goods_image) : changeImgUrl('public/static/img/default_img/square.png')" onerror="this.src = ns.img('public/static/img/default_img/square.png');" />
</div>
</div>
<div class="content-block">
<div class="layui-form-item component-links">{{item.goods_name}}
</div>
</div>
<div class="error-msg"></div>
<!-- <i data-disabled="1" class="del">x</i> -->
<div class="iconfont icontuodong"></div>
</li>
</ul>
</div>
</div>
</div>
<div class="template-edit-title" v-show="nc.btnStyle.support">
<h3>购买按钮</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">是否显示</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary"
@click="nc.btnStyle.control = !nc.btnStyle.control"
:class="{ 'layui-form-checked' : nc.btnStyle.control }">
<span>{{ nc.btnStyle.control ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<!-- <template v-if="nc.btnStyle.control">
<div class="layui-form-item">
<label class="layui-form-label sm">购物车事件</label>
<div class="layui-input-block">
<div @click="nc.btnStyle.cartEvent='detail'" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.btnStyle.cartEvent=='detail') }">
<i class="layui-anim layui-icon">{{ nc.btnStyle.cartEvent=='detail' ? "&#xe643;" : "&#xe63f;" }}</i>
<div>跳转商品详情</div>
</div>
<div @click="nc.btnStyle.cartEvent='cart'" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.btnStyle.cartEvent=='cart') }">
<i class="layui-anim layui-icon">{{ nc.btnStyle.cartEvent=='cart' ? "&#xe643;" : "&#xe63f;" }}</i>
<div>加入购物车</div>
</div>
</div>
<p class="word-aux" style="margin-left: 100px;" v-if="nc.btnStyle.cartEvent=='cart'">只有实物商品才能加入购物车,虚拟商品会跳转到商品详情</p>
</div>
<div class="layui-form-item btn-style">
<label class="layui-form-label sm">样式</label>
<div class="layui-input-block">
<div class="item" :class="{ 'border-color' : nc.btnStyle.style == 'button' }"
@click="nc.btnStyle.style = 'button';nc.btnStyle.textColor= nc.btnStyle.textColor == '#FF6A00' ? '#FFFFFF' : nc.btnStyle.textColor">
<span class="buy-btn bg-color">按钮</span>
</div>
<div class="item" :class="{ 'border-color' : nc.btnStyle.style == 'icon-cart' }"
@click="nc.btnStyle.style = 'icon-cart';nc.btnStyle.textColor= nc.btnStyle.textColor == '#FFFFFF' ? '#FF6A00' : nc.btnStyle.textColor">
<span class="shopping-cart-btn iconfont icongouwuche text-color border-color"></span>
</div>
<div class="item" :class="{ 'border-color' : nc.btnStyle.style == 'icon-add' }"
@click="nc.btnStyle.style = 'icon-add';nc.btnStyle.textColor= nc.btnStyle.textColor == '#FFFFFF' ? '#FF6A00' : nc.btnStyle.textColor">
<span class="plus-sign-btn iconfont iconjia2 text-color border-color"></span>
</div>
<div class="item" :class="{ 'border-color' : nc.btnStyle.style == 'icon-diy' }"
@click="nc.btnStyle.style = 'icon-diy';nc.btnStyle.textColor= nc.btnStyle.textColor == '#FFFFFF' ? '#FF6A00' : nc.btnStyle.textColor">
<span class="diy-btn text-color border-color">自定义</span>
</div>
</div>
<div class="layui-input-block diy-icon" v-show="nc.btnStyle.style == 'icon-diy'">
<img-icon-upload :data="{data : nc.btnStyle.iconDiy, displayType : 'icon'}"></img-icon-upload>
<div class="action-box">
<div class="action" @click="nc.tempData.methods.iconStyle($event)"><i class="iconfont iconpifu"></i></div>
<div class="action" :id="'goods-list-color-' + nc.tempData.goodsDuplicateId"><i class="iconfont iconyanse"></i></div>
</div>
</div>
</div>
<div class="layui-form-item" v-show="nc.btnStyle.style == 'button'">
<label class="layui-form-label sm">文字</label>
<div class="layui-input-block">
<input type="text" v-model="nc.btnStyle.text" maxlength="6" placeholder="请输入按钮文字" class="layui-input">
</div>
</div>
</template> -->
</div>
<div class="template-edit-title">
<h3>显示内容</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">商品名称</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary"
@click="nc.goodsNameStyle.control = !nc.goodsNameStyle.control"
:class="{ 'layui-form-checked' : nc.goodsNameStyle.control }">
<span>{{ nc.goodsNameStyle.control ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label sm">销售价</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary"
@click="nc.priceStyle.mainControl = !nc.priceStyle.mainControl"
:class="{ 'layui-form-checked' : nc.priceStyle.mainControl }">
<span>{{ nc.priceStyle.mainControl ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item" v-show="nc.priceStyle.lineSupport">
<label class="layui-form-label sm">划线价</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary"
@click="nc.priceStyle.lineControl = !nc.priceStyle.lineControl"
:class="{ 'layui-form-checked' : nc.priceStyle.lineControl }">
<span>{{ nc.priceStyle.lineControl ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item" v-show="nc.saleStyle.support">
<label class="layui-form-label sm">商品销量</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary"
@click="nc.saleStyle.control = !nc.saleStyle.control"
:class="{ 'layui-form-checked' : nc.saleStyle.control }">
<span>{{ nc.saleStyle.control ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<!-- <div class="layui-form-item">
<label class="layui-form-label sm">商品标签</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="nc.tempData.methods.selectTag()" :class="{ 'layui-form-checked' : nc.tag.value != 'hidden' }">
<span>{{ nc.tag.value != 'hidden' ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item tag-wrap" v-show="nc.tag.value != 'hidden'">
<label class="layui-form-label sm"></label>
<div class="layui-input-block">
<div v-for="(item,tagIndex) in nc.tempData.tagList" :key="tagIndex" @click="nc.tag=JSON.parse(JSON.stringify(item))" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.tag.value==item.value) }">
<i class="layui-anim layui-icon">{{ nc.tag.value == item.value ? "&#xe643;" : "&#xe63f;" }}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<div class="layui-form-item" v-show="nc.tag.value == 'diy'">
<label class="layui-form-label sm">标签文字</label>
<div class="layui-input-block">
<input type="text" v-model="nc.tag.text" maxlength="10" placeholder="请输入标签文字" class="layui-input">
</div>
</div> -->
</div>
</template>
<!-- 商品分类选择弹框 -->
<script type="text/html" class="goods-category-layer">
<div class="goods-category-list layui-form">
<table class="layui-table pithy-table">
<colgroup>
<col width="5%">
<col width="3%">
<col width="37%">
<col width="25%">
<col width="30%">
</colgroup>
<thead>
<tr>
<th></th>
<th></th>
<th>分类名称</th>
<th>简称</th>
<th>图片</th>
</tr>
</thead>
<tbody>
{if condition="$category_list"}
{foreach name="$category_list" item="vo"}
<tr class='category-line'>
<td><input type="checkbox" name="category_select_id" data-category_select_id = "{$vo['category_id']}"lay-skin="primary" value='{:json_encode($vo)}' lay-filter="category_select_id"{if !empty($link_array.category_id) && $link_array.category_id == $vo['category_id']}checked{/if}></td>
<td>
{notempty name="$vo['child_list']"}
<span class="switch text-color js-switch" data-category-id="{$vo['category_id']}" data-level="{$vo['level']}" data-open="0">+</span>
{/notempty}
</td>
<td class="category-name">{$vo['category_name']}</td>
<td>{$vo['short_name']}</td>
<td>
{notempty name="$vo['image']"}
<div class="img-box">
<img layer-src src="{:img($vo['image'])}"/>
</div>
{/notempty}
</td>
</tr>
{notempty name="$vo['child_list']"}
{foreach name="$vo['child_list']" item="second"}
<tr class='category-line' data-category-id-1="{$second['category_id_1']}" style="display:none;">
<td><input type="checkbox" name="category_select_id" lay-skin="primary"data-category_select_id = "{$second['category_id']}" value='{:json_encode($second)}' lay-filter="category_select_id"{if !empty($link_array.category_id) && $link_array.category_id == $second['category_id']}checked{/if}></td>
<td></td>
<td style="padding-left: 20px;">
<span class="switch text-color js-switch" data-category-id="{$second['category_id']}" data-level="{$second['level']}" data-open="1" style="padding-right: 20px;">-</span>
<span class="category-name">{$second['category_name']}</span>
</td>
<td>{$second['short_name']}</td>
<td>
{notempty name="$second['image']"}
<img layer-src src="{:img($second['image'])}"/>
{/notempty}
</td>
</tr>
{notempty name="$second['child_list']"}
{foreach name="$second['child_list']" item="third"}
<tr class='category-line'data-category-id-1="{$third['category_id_1']}" data-category-id-2="{$third['category_id_2']}" style="display:none;">
<td><input type="checkbox" name="category_select_id" lay-skin="primary" value='{:json_encode($third)}' data-category_select_id = '{$third['category_id']}'lay-filter="category_select_id"{if !empty($link_array.category_id) && $link_array.category_id == $third['category_id']}checked{/if}></td>
<td></td>
<td style="padding-left: 80px;">
<span class="category-name">{$third['category_name']}</span>
</td>
<td>{$third['short_name']}</td>
<td>
{notempty name="$third['image']"}
<img layer-src src="{:img($third['image'])}"/>
{/notempty}
</td>
</tr>
{/foreach}
{/notempty}
{/foreach}
{/notempty}
{/foreach}
{else/}
<tr>
<td colspan="9" style="text-align: center">无数据</td>
</tr>
{/if}
</tbody>
</table>
</div>
</script>
</template>
<!-- 样式编辑 -->
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<div class="template-edit-title">
<h3>商品样式</h3>
<div class="layui-form-item tag-wrap">
<label class="layui-form-label sm">边框</label>
<div class="layui-input-block">
<div v-for="(item,ornamentIndex) in nc.tempData.ornamentList" :key="ornamentIndex"
@click="nc.ornament.type=item.type"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.ornament.type==item.type) }">
<i class="layui-anim layui-icon">{{ nc.ornament.type == item.type ? "&#xe643;" : "&#xe63f;"
}}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<color v-if="nc.ornament.type != 'default'"
:data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }">
</color>
<slide :data="{ field : 'imgAroundRadius', label: '图片圆角', min:0, max: 50 }"></slide>
<div class="layui-form-item" v-if="nc.template == 'horizontal-slide'">
<label class="layui-form-label sm">滚动方式</label>
<div class="layui-input-block">
<div @click="nc.slideMode = 'scroll' "
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.slideMode == 'scroll') }">
<i class="layui-anim layui-icon">{{ nc.slideMode == 'scroll' ? "&#xe643;" : "&#xe63f;"
}}</i>
<div>平移</div>
</div>
<div @click="nc.slideMode = 'slide' "
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.slideMode == 'slide') }">
<i class="layui-anim layui-icon">{{ nc.slideMode == 'slide' ? "&#xe643;" : "&#xe63f;" }}</i>
<div>切屏</div>
</div>
</div>
</div>
<div class="layui-form-item" v-show="nc.goodsNameStyle.control">
<label class="layui-form-label sm">商品名称</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary"
@click="nc.goodsNameStyle.fontWeight = !nc.goodsNameStyle.fontWeight"
:class="{ 'layui-form-checked' : nc.goodsNameStyle.fontWeight }">
<span>加粗</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
<div v-for="(item,nameLineIndex) in nc.tempData.nameLineModeList" :key="nameLineIndex"
@click="nc.nameLineMode=item.value"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.nameLineMode==item.value) }">
<i class="layui-anim layui-icon">{{ nc.nameLineMode == item.value ? "&#xe643;" : "&#xe63f;"
}}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<color :data="{ field : 'elementBgColor', 'label' : '商品背景' }"></color>
<slide v-show="nc.elementAngle == 'round'"
:data="{ field : 'topElementAroundRadius', label : '上圆角', max : 50 }"></slide>
<slide v-show="nc.elementAngle == 'round'"
:data="{ field : 'bottomElementAroundRadius', label : '下圆角', max : 50 }"></slide>
<div class="layui-form-item">
<label class="layui-form-label sm">色调</label>
<div class="layui-input-block">
<div @click="nc.theme='default'"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.theme == 'default') }">
<i class="layui-anim layui-icon">{{ nc.theme == 'default' ? "&#xe643;" : "&#xe63f;" }}</i>
<div>跟随主题风格</div>
</div>
<div @click="nc.theme='diy'"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.theme == 'diy') }">
<i class="layui-anim layui-icon">{{ nc.theme == 'diy' ? "&#xe643;" : "&#xe63f;" }}</i>
<div>自定义</div>
</div>
</div>
</div>
<div v-show="nc.theme == 'diy'">
<color
:data="{ field : 'color', 'label' : '商品名称', parent : 'goodsNameStyle', defaultColor : '#303133' }">
</color>
<color
:data="{ field : 'mainColor', 'label' : '销售价', parent : 'priceStyle', defaultColor : '#FF6A00' }">
</color>
<div v-show="nc.priceStyle.lineSupport">
<color
:data="{ field : 'lineColor', 'label' : '划线价', parent : 'priceStyle', defaultColor : '#999CA7' }">
</color>
</div>
<div v-show="nc.saleStyle.support">
<color
:data="{ field : 'color', 'label' : '商品销量', parent : 'saleStyle', defaultColor : '#999CA7' }">
</color>
</div>
</div>
</div>
<div class="template-edit-title" v-show="nc.btnStyle.support && nc.btnStyle.control">
<h3>购买按钮</h3>
<template v-if="nc.btnStyle.style == 'button'">
<div class="layui-form-item">
<label class="layui-form-label sm">是否加粗</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary"
@click="nc.btnStyle.fontWeight = !nc.btnStyle.fontWeight"
:class="{ 'layui-form-checked' : nc.btnStyle.fontWeight }">
<span>{{ nc.btnStyle.fontWeight ? '加粗' : '常规' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<slide :data="{ field : 'padding', parent : 'btnStyle', label : '按钮边距', min: 0, max : 20 }"></slide>
</template>
<slide v-show="nc.btnStyle.style == 'button'"
:data="{ field : 'aroundRadius', label: '圆角', min:0, max: 50, parent: 'btnStyle' }"></slide>
<div class="layui-form-item">
<label class="layui-form-label sm">色调</label>
<div class="layui-input-block">
<div @click="nc.btnStyle.theme='default'"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.btnStyle.theme == 'default') }">
<i class="layui-anim layui-icon">{{ nc.btnStyle.theme == 'default' ? "&#xe643;" : "&#xe63f;"
}}</i>
<div>跟随主题风格</div>
</div>
<div @click="nc.btnStyle.theme='diy'"
:class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.btnStyle.theme == 'diy') }">
<i class="layui-anim layui-icon">{{ nc.btnStyle.theme == 'diy' ? "&#xe643;" : "&#xe63f;"
}}</i>
<div>自定义</div>
</div>
</div>
</div>
<template v-if="nc.btnStyle.theme == 'diy'">
<color v-if="nc.btnStyle.style == 'button'"
:data="{ field : 'bgColor', 'label' : '背景颜色', parent : 'btnStyle', defaultColor : '#FF6A00' }">
</color>
<color
:data="{ field : 'textColor', 'label' : '文字颜色', parent : 'btnStyle', defaultColor : '#FFFFFF' }">
</color>
</template>
</div>
</template>
</template>
<!-- 资源 -->
<template slot="resource">
<js>
var goodsListResourcePath = "{$resource_path}"; // http路径
var goodsListRelativePath = "{$relative_path}"; // 相对路径
</js>
<css src="{$resource_path}/css/design.css?v={$version}"></css>
<js src="{$resource_path}/js/design.js?v={$version}"></js>
</template>
</nc-component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B

View File

@@ -0,0 +1,428 @@
var goodsListHtml = '<div style="display:none;"></div>';
Vue.component("goods-list-sources", {
template: goodsListHtml,
data: function () {
return {
data: this.$parent.data,
goodsSources: {
initial: {
text: "默认",
icon: "iconmofang"
},
category: {
text: "商品分类",
icon: "iconshangpinfenlei"
},
diy: {
text: "手动选择",
icon: "iconshoudongxuanze"
},
},
sortWayList: [
{
text: "综合",
value: "default"
},
{
text: "新品",
value: "news"
},
{
text: "热销",
value: "sales"
},
{
text: "价格",
value: "price"
}
],
templateList: {
"row1-of1": {
text: "单列",
icon: "iconiPhone86",
styleList: [
{
text: "样式1",
value: "style-1",
cartSupport: true, // 是否支持购物车按钮
saleSupport: true, // 是否支持商品销量
lineSupport: true, // 是否支持划线价
},
],
},
"row1-of2": {
text: "两列",
icon: "iconyihanglianglie",
styleList: [
{
text: "样式1",
value: "style-1",
cartSupport: false, // 是否支持购物车按钮
saleSupport: true, // 是否支持商品销量
lineSupport: true, // 是否支持划线价
},
{
text: "样式2",
value: "style-2",
cartSupport: true, // 是否支持购物车按钮
saleSupport: true, // 是否支持商品销量
lineSupport: true, // 是否支持划线价
},
{
text: "样式3",
value: "style-3",
cartSupport: false, // 是否支持购物车按钮
saleSupport: true, // 是否支持商品销量
lineSupport: false, // 是否支持划线价
},
],
},
"row1-of3": {
text: "三列",
icon: "iconyihangsanlie",
styleList: [
{
text: "样式1",
value: "style-1",
cartSupport: false, // 是否支持购物车按钮
saleSupport: false, // 是否支持商品销量
lineSupport: true, // 是否支持划线价
},
{
text: "样式2",
value: "style-2",
cartSupport: true, // 是否支持购物车按钮
saleSupport: false, // 是否支持商品销量
lineSupport: true, // 是否支持划线价
},
],
},
"horizontal-slide": {
text: "横向滑动",
icon: "iconshangpinliebiaohengxianghuadong",
styleList: [
{
text: "样式1",
value: "style-1",
cartSupport: false, // 是否支持购物车按钮
saleSupport: false, // 是否支持商品销量
lineSupport: true, // 是否支持划线价
},
],
},
"large-mode": {
text: "大图",
icon: "icondanlieshangpin",
styleList: [
{
text: "样式1",
value: "style-1",
cartSupport: true, // 是否支持购物车按钮
saleSupport: true, // 是否支持商品销量
lineSupport: true, // 是否支持划线价
},
],
},
},
ornamentList: [
{
type: 'default',
text: '默认',
},
{
type: 'shadow',
text: '投影',
},
{
type: 'stroke',
text: '描边',
},
],
tagList: [
{
text: "商品标签",
value: "label"
},
{
text: "自定义",
value: "diy"
},
// {
// text: "隐藏",
// value: "hidden"
// },
],
nameLineModeList: [
{
text: "单行",
value: "single"
},
{
text: "多行",
value: "multiple"
}
],
goodsDuplicateId: ''
}
},
created: function () {
//sources diy手动选择category分类其他默认
if (!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['textColor']; //加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
var previewList = {};
for (var i = 1; i < 7; i++) {
previewList["goods_id_" + ns.gen_non_duplicate(i)] = {
goods_name: "商品名称",
discount_price: (Math.random() * 10 * i + 10).toFixed(0), // 随机价格
line_price: (Math.random() * 10 * i + 10 + 10).toFixed(0), // 随机价格
sale_num: Math.floor((Math.random() * 10 * i + 10 + 10))
};
}
//获取商品
if(this.$parent.data.sources == 'diy'){
this.goodslist(this.$parent.data.goodsId.join(","))
}else if(this.$parent.data.sources == 'category'){
this.goodslist(0,this.$parent.data.categoryId)
}else{
//this.goodslist(0,0)
}
this.goodsDuplicateId = ns.gen_non_duplicate(10);
// 组件所需的临时数据
this.$parent.data.tempData = {
goodsSources: this.goodsSources,
sortWayList: this.sortWayList,
templateList: this.templateList,
ornamentList: this.ornamentList,
tagList: this.tagList,
nameLineModeList: this.nameLineModeList,
goodsDuplicateId: this.goodsDuplicateId,
previewList: previewList,
methods: {
addGoods: this.addGoods,
selectCategory: this.selectCategory,
selectTemplate: this.selectTemplate,
selectTag: this.selectTag,
iconStyle: this.iconStyle
},
};
var moveBeforeIndex = 0;
var _this = this;
setTimeout(function () {
console.log(1)
var componentIndex = _this.data.index;
$('[data-index="' + componentIndex + '"] .navigation-set-list').DDSort({
target: 'li',
floatStyle: {
'border': '1px solid #ccc',
'background-color': '#fff'
},
//设置可拖拽区域
draggableArea: "icontuodong",
down: function (index) {
moveBeforeIndex = index;
},
up: function () {
var index = $(this).index();
//拖拽id部分
var goodsids = _this.$parent.data.goodsId
var temp = goodsids[moveBeforeIndex];
goodsids.splice(moveBeforeIndex, 1);
goodsids.splice(index, 0, temp);
_this.$parent.data.goodsId = goodsids
console.log(_this.$parent.data.goodsId)
//拖拽商品部分
// _this.goodslist(goodsids.join(","))
// var list = _this.$parent.data.tempData.previewList
// var temp = list[moveBeforeIndex];
// list.splice(moveBeforeIndex, 1);
// list.splice(index, 0, temp);
// _this.$parent.data.tempData.previewList = list;
}
});
},1000);
this.fetchIconColor();
},
methods: {
verify: function (index) {
var res = {code: true, message: ""};
if (vue.data[index].sources === 'category' && vue.data[index].categoryId === 0) {
res.code = false;
res.message = "请选择商品分类";
}
return res;
},
addGoods: function () {
var self = this;
goodsSelect(function (res) {
self.$parent.data.goodsId = res;
if(res.length>0){
self.goodslist(res.join(","))
}
}, self.$parent.data.goodsId, {mode: "spu", disabled: 0, promotion: "module", post: ns.appModule});
},
goodslist(goods_ids,category_id = 0){
// console.log(goods_ids)
var self = this;
$.ajax({
type: 'post',
url: ns.url('shop/goods/getgoodlist'),
data:{
goods_ids: goods_ids,
sources:self.$parent.data.sources,
category_id:category_id
},
dataType: 'JSON',
success: function (res) {
self.$parent.data.tempData.previewList = res.data;
}
})
},
selectCategory() {
var self = this;
layui.use(['form'], function () {
var form = layui.form;
layer.open({
type: 1,
title: '选择分类',
area: ['630px', '430px'],
btn: ['确定', '返回'],
content: $(".draggable-element[data-index='" + self.data.index + "'] .edit-attribute .goods-category-layer").html(),
success: function (layero, index) {
$(".js-switch").click(function () {
var category_id = $(this).attr("data-category-id");
var level = $(this).attr("data-level");
var open = parseInt($(this).attr("data-open").toString());
if (open) {
$(".goods-category-list .layui-table tr[data-category-id-" + level + "='" + category_id + "']").hide();
$(this).text("+");
} else {
$(".goods-category-list .layui-table tr[data-category-id-" + level + "='" + category_id + "']").show();
$(this).text("-");
}
$(this).attr("data-open", (open ? 0 : 1));
});
// 勾选分类
form.on('checkbox(category_select_id)', function (data) {
if (data.elem.checked) {
$("input[name='category_select_id']:checked").prop("checked", false);
$(data.elem).prop("checked", true);
form.render();
}
});
$("input[name='category_select_id']:checked").prop("checked", false);
if (self.data.categoryId) {
$('.layui-layer-content [data-category_select_id="' + self.data.categoryId + '"]').prop("checked", true);
}
form.render();
},
yes: function (index, layero) {
var selected = $(".layui-layer-content input[name='category_select_id']:checked");
if (selected.length === 0) {
layer.msg('请选择商品分类');
return;
}
self.goodslist(0,selected.attr('data-category_select_id'))
self.data.categoryName = selected.parents('tr').find('.category-name').text();
self.data.categoryId = selected.attr('data-category_select_id');
layer.closeAll()
}
});
});
},
selectTemplate(template, item) {
if (template) {
this.$parent.data.template = template;
item = this.templateList[template].styleList[0];
}
this.$parent.data.style = item.value;
this.$parent.data.btnStyle.support = item.cartSupport;
this.$parent.data.btnStyle.control = item.cartSupport;
this.$parent.data.saleStyle.support = item.saleSupport;
this.$parent.data.saleStyle.control = item.saleSupport;
this.$parent.data.priceStyle.lineSupport = item.lineSupport;
this.$parent.data.priceStyle.lineControl = item.lineSupport;
},
selectTag() {
if (this.$parent.data.tag.value === 'hidden') {
this.$parent.data.tag.text = '商品标签';
this.$parent.data.tag.value = 'label';
} else {
this.$parent.data.tag.text = '隐藏';
this.$parent.data.tag.value = 'hidden';
}
},
/**
* 选择图标风格
* @param event
*/
iconStyle(event) {
var self = this;
selectIconStyle({
elem: event.currentTarget,
icon: self.data.btnStyle.iconDiy.icon,
callback: function (data) {
if (data) {
self.data.btnStyle.iconDiy.style = data;
} else {
iconStyleSet({
style: JSON.stringify(self.data.btnStyle.iconDiy.style),
query: {
icon: self.data.btnStyle.iconDiy.icon
}
}, function (style) {
self.data.btnStyle.iconDiy.style = style;
})
}
}
})
},
/**
* 渲染颜色组件
* @param id
* @param color
* @param callback
*/
colorRender(id, color, callback) {
setTimeout(function () {
Colorpicker.create({
el: id,
color: color,
change: function (elem, hex) {
callback(elem, hex)
}
});
})
},
/**
* 渲染图标颜色选择器
*/
fetchIconColor() {
// var self = this;
// self.colorRender('goods-list-color-' + this.goodsDuplicateId, '', function (elem, color) {
// if (self.data.btnStyle.iconDiy.style.iconBgColor.length || self.data.btnStyle.iconDiy.style.iconBgImg) {
// self.data.btnStyle.iconDiy.style.iconBgColor = [color];
// } else {
// self.data.btnStyle.iconDiy.style.iconColor = [color];
// }
// self.$forceUpdate();
// });
},
}
});

View File

@@ -0,0 +1,73 @@
.edit-attribute .tag-wrap .layui-form-radio:last-child{margin-right: 0;}
/* 选择商品分类弹出框 */
.goods-category-layer {display: none;}
.layui-layer-content .category-wrap .category-item, .layui-layer-content .category-head {height: 30px;line-height: 30px;border: 1px solid #ededed;border-radius: 5px;padding: 0 15px;margin: 0 15px 10px 0;box-sizing: border-box;color: #666;font-size: 12px;}
.layui-layer-content .category-head {background: #eee;height: 40px;line-height: 40px;}
.layui-layer-content .category-wrap {overflow-y: scroll;height: calc(100% - 45px);}
.layui-layer-content .category-wrap::-webkit-scrollbar {display: none;}
.layui-layer-content .category-wrap .category-item {cursor: pointer;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}
/* 选择风格 */
.style-list-box-goods-recommend {display: none;}
.style-list-con-goods-recommend {display: flex;flex-wrap: wrap;}
.style-list-con-goods-recommend .style-li-goods-recommend {overflow: hidden;display: flex;align-items: center;justify-content: center;width: 280px;height: 210px;margin-right: 12px;margin-top: 15px;cursor: pointer;border: 1px solid #ededed;background: #f7f8fa;}
.style-list-con-goods-recommend .style-li-goods-recommend img{width: 100%;}
.style-list-con-goods-recommend .style-li-goods-recommend:nth-child(1), .style-list-con-goods-recommend .style-li-goods-recommend:nth-child(2), .style-list-con-goods-recommend .style-li-goods-recommend:nth-child(3){margin-top: 0;}
.style-list-con-goods-recommend .style-li-goods-recommend:nth-child(3n) {margin-right: 0;}
.goods-recommend .top-wrap{display: flex;align-items: center;padding: 10px 0;}
.goods-recommend .top-wrap i{border-radius: 50%;font-size: 25px;margin-right: 5px;width: 35px;height: 35px;text-align: center;line-height: 35px;margin-left: 10px;}
.goods-recommend .top-wrap .line{height: 14px;margin: 0 5px;border: 1px solid;}
.goods-recommend .top-wrap h3{font-weight: bold;}
.goods-recommend .top-wrap .sub{font-size: 12px;}
/* 商品块基础样式 */
.goods-recommend .goods-list .goods-item {line-height: 1;}
.goods-recommend .goods-list .goods-item .sale {font-size: 12px;}
.goods-recommend .goods-list .goods-item .info-wrap .goods-name{margin-bottom: 5px;font-size: 14px;line-height: 1.3;}
/* ---------- 三列(一行三个)---------- */
.goods-recommend .style-1 .goods-list{display: flex;flex-wrap: wrap;margin: 0 10px;}
.goods-recommend .style-1 .goods-list .goods-item{display: flex;flex-direction: column;background: #fff;overflow: hidden;margin-top: 10px;width: 100px;box-sizing: border-box;}
.goods-recommend .style-1 .goods-list .goods-item:nth-of-type(1), .goods-recommend .style-1 .goods-list .goods-item:nth-of-type(2), .goods-recommend .style-1 .goods-list .goods-item:nth-of-type(3){margin-top: 0;}
.goods-recommend .style-1 .goods-list .goods-item .goods-img{width: calc(100% + 2px);height: 110px;}
.goods-recommend .style-1 .goods-list .goods-item .goods-img img{width: 100%;height: 100%;}
.goods-recommend .style-1 .goods-list .goods-item .info-wrap{display: flex;flex-direction: column;flex: 1;margin: 5px;}
.goods-recommend .style-1 .goods-list .goods-item .info-wrap .pro-info{margin-top: auto;display: flex;justify-content: space-between;}
.goods-recommend .style-1 .goods-list .goods-item .info-wrap .pro-info .discount-price{display: flex;justify-content: space-between;align-items: center;flex: 1;}
.goods-recommend .style-1 .goods-list .goods-item .info-wrap .pro-info .discount-price .price-wrap{font-size: 0;font-weight: bold;}
.goods-recommend .style-1 .goods-list .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;}
.goods-recommend .style-1 .goods-list .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;}
.goods-recommend .style-2{background-repeat: round;padding-bottom: 10px;}
.goods-recommend .style-2 .goods-list{display: flex;margin: 0 5px;background: #fff;border-radius: 10px;padding: 10px;}
.goods-recommend .style-2 .goods-list .goods-item{display: flex;flex-direction: column;background: #fff;overflow: hidden;margin-top: 10px;width: 100px;}
.goods-recommend .style-2 .goods-list .goods-item.stroke{width: 100px;}
.goods-recommend .style-2 .goods-list .goods-item:nth-of-type(1), .goods-recommend .style-2 .goods-list .goods-item:nth-of-type(2), .goods-recommend .style-2 .goods-list .goods-item:nth-of-type(3){margin-top: 0;}
.goods-recommend .style-2 .goods-list .goods-item .goods-img{width: calc(100% + 2px);height: 110px;}
.goods-recommend .style-2 .goods-list .goods-item .goods-img img{width: 100%;height: 100%;}
.goods-recommend .style-2 .goods-list .goods-item .info-wrap{display: flex;flex-direction: column;flex: 1;margin: 5px;}
.goods-recommend .style-2 .goods-list .goods-item .info-wrap .pro-info{margin-top: auto;display: flex;justify-content: space-between;}
.goods-recommend .style-2 .goods-list .goods-item .info-wrap .pro-info .discount-price{display: flex;justify-content: space-between;align-items: center;flex: 1;}
.goods-recommend .style-2 .goods-list .goods-item .info-wrap .pro-info .discount-price .price-wrap{font-size: 0;font-weight: bold;}
.goods-recommend .style-2 .goods-list .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;}
.goods-recommend .style-2 .goods-list .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;}
.goods-recommend .style-3 {background-position: bottom;}
.goods-recommend .style-3 .goods-list{display: flex;flex-wrap: wrap;margin: 0 10px;}
.goods-recommend .style-3 .goods-list .goods-item{display: flex;flex-direction: column;overflow: hidden;margin-top: 10px;width: 100px;box-sizing: border-box;}
.goods-recommend .style-3 .goods-list .goods-item .goods-img{width: calc(100% + 2px);height: 110px;}
.goods-recommend .style-3 .goods-list .goods-item .goods-img img{width: 100%;height: 100%;}
.goods-recommend .style-3 .goods-list .goods-item .info-wrap{display: flex;flex-direction: column;flex: 1;margin: 5px;}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info{text-align: center;}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info .label-wrap{border-radius: 20px;padding: 4px;display: inline-block;margin: 5px 0;position: relative;padding-left: 26px;padding-right:8px;}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info .label-wrap img{position: absolute;top: -1px;left: -1px;width: 23px;height: 23px;}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info .label-wrap span{font-size: 12px;}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info .discount-price{}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info .discount-price .price-wrap{font-size: 0;font-weight: bold;}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info .discount-price .price-wrap .unit{font-size: 12px;}
.goods-recommend .style-3 .goods-item .info-wrap .pro-info .discount-price .price-wrap .price{font-size: 16px;}
.goods-recommend .edit-content-wrap .layui-form-radio{margin-right:5px;}
.goods-recommend .edit-content-wrap .layui-form-radio:last-child{margin-right: 0;padding-right: 0;}

View File

@@ -0,0 +1,410 @@
<nc-component :data="data[index]" class="goods-recommend">
<!-- 预览 -->
<template slot="preview">
<div :class="[nc.style]" :style="{ backgroundColor: nc.componentBgColor,backgroundImage: 'url('+ changeImgUrl(nc.bgUrl)+ ')',borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0) }">
<div class="top-wrap" v-if="nc.topStyle.support">
<i :class="[nc.topStyle.icon.value]" :style="{ backgroundColor : nc.topStyle.icon.bgColor, color : nc.topStyle.icon.color }"></i>
<h3 :style="{ color : nc.topStyle.color }">{{ nc.topStyle.title }}</h3>
<span class="line" :style="{ color : nc.topStyle.subColor }"></span>
<span class="sub" :style="{ color : nc.topStyle.subColor }">{{ nc.topStyle.subTitle }}</span>
</div>
<div class="goods-list">
<template v-if="nc.tempData.previewList && Object.keys(nc.tempData.previewList).length">
<div :class="['goods-item',nc.ornament.type]" v-for="(item, previewIndex) in nc.tempData.previewList" :key="previewIndex"
:style="{
backgroundColor: nc.elementBgColor,
borderTopLeftRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.elementAngle == 'round' ? nc.topElementAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.elementAngle == 'round' ? nc.bottomElementAroundRadius + 'px' : 0),
boxShadow: nc.ornament.type == 'shadow' ? ('0 0 5px ' + nc.ornament.color) : '',
marginLeft: (51 - nc.margin.both * 2) /6 + 'px',
marginRight: (51 - nc.margin.both * 2) /6 + 'px',
border: nc.ornament.type == 'stroke' ? '1px solid ' + nc.ornament.color : ''}">
<div class="goods-img" :style="{ borderRadius: nc.imgAroundRadius + 'px' }">
<img :src="item.goods_image ? changeImgUrl(item.goods_image) : changeImgUrl('public/static/img/default_img/square.png')" :style="{ borderRadius: nc.imgAroundRadius + 'px' }" onerror="this.src = ns.img('public/static/img/default_img/square.png');" />
</div>
<div class="info-wrap" v-if="nc.goodsNameStyle.control || nc.priceStyle.mainControl || nc.priceStyle.lineControl || nc.labelStyle.support">
<div class="goods-name" v-if="nc.goodsNameStyle.control" :style="{ color : nc.goodsNameStyle.color,fontWeight : nc.goodsNameStyle.fontWeight ? 'bold' : '' }" :class="[{'using-hidden' : nc.nameLineMode == 'single'},{'multi-hidden' : nc.nameLineMode == 'multiple'}]">{{ item.goods_name }}</div>
<div class="pro-info">
<div class="label-wrap" v-if="nc.labelStyle.support" :style="{ background : nc.labelStyle.bgColor,color : nc.labelStyle.color}">
<img src="{$resource_path}/img/label.png" />
<span>{{nc.labelStyle.title}}</span>
</div>
<div class="discount-price">
<div class="price-wrap" v-if="nc.priceStyle.mainControl">
<span class="unit" :style="{ color : nc.priceStyle.mainColor }">¥</span>
<span class="price" :style="{ color : nc.priceStyle.mainColor }">{{item.discount_price.split(".")[0]}}</span>
<span class="price" :style="{ color : nc.priceStyle.mainColor }" v-if="item.discount_price.split('.')[1]">{{"."+item.discount_price.split(".")[1]}}</span>
</div>
<div class="delete-price" v-if="nc.priceStyle.lineControl" :style="{ color : nc.priceStyle.lineColor }">¥{{item.line_price}}</div>
<div class="sale" v-if="nc.saleStyle.control" :style="{ color : nc.saleStyle.color }">售{{ item.sale_num }}件</div>
</div>
</div>
</div>
</div>
</template>
</div>
</div>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<goods-recommend-sources></goods-recommend-sources>
<div class="template-edit-title">
<h3>推荐风格</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">风格</label>
<div class="layui-input-block" v-if="nc.tempData.methods">
<div v-if="nc.styleName" class="text-color selected-style" @click="nc.tempData.methods.selectStyle()">
<span>{{nc.styleName}}</span>
<i class="layui-icon layui-icon-right"></i>
</div>
</div>
</div>
</div>
<div class="template-edit-title" v-if="nc.topStyle.support">
<h3>推荐标题</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">标题</label>
<div class="layui-input-block">
<input type="text" v-model="nc.topStyle.title" maxlength="10" placeholder="请输入标题" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label sm">副标题</label>
<div class="layui-input-block">
<input type="text" v-model="nc.topStyle.subTitle" maxlength="10" placeholder="请输入标题" class="layui-input">
</div>
</div>
</div>
<div class="template-edit-title">
<h3>推荐商品</h3>
<div class="layui-form-item" v-if="nc.tempData.goodsSources">
<label class="layui-form-label sm">数据来源</label>
<div class="layui-input-block">
<div class="source-selected">
<div class="source">{{ nc.tempData.goodsSources[nc.sources].text }}</div>
<div v-for="(item,sourcesKey) in nc.tempData.goodsSources" :key="sourcesKey" class="source-item" :title="item.text" @click="nc.sources=sourcesKey" :class="{ 'text-color border-color' : (nc.sources == sourcesKey) }">
<i class='iconfont' :class='item.icon'></i>
</div>
</div>
</div>
</div>
<div class="layui-form-item" v-if="nc.sources == 'category'">
<label class="layui-form-label sm">商品分类</label>
<div class="layui-input-block">
<div class="selected-style" @click="nc.tempData.methods.selectCategory()">
<span :class="{ 'text-color' : nc.categoryId > 0 }">{{ nc.categoryName }}</span>
<i class="iconfont iconyoujiantou"></i>
</div>
</div>
</div>
<div class="layui-form-item" v-if="nc.sources == 'diy'">
<label class="layui-form-label sm">手动选择</label>
<div class="layui-input-block">
<div class="selected-style" @click="nc.tempData.methods.addGoods()">
<span v-if="nc.goodsId.length == 0">请选择</span>
<span v-if="nc.goodsId.length > 0" class="text-color">已选{{ nc.goodsId.length }}个</span>
<i class="iconfont iconyoujiantou"></i>
</div>
</div>
</div>
<slide :data="{ field : 'count', label: '商品数量', min:1, max: 30}" v-if="nc.sources != 'diy'"></slide>
<div class="layui-form-item">
<label class="layui-form-label sm">排序</label>
<div class="layui-input-block">
<div v-for="(item,sortIndex) in nc.tempData.sortWayList" :key="sortIndex" @click="nc.sortWay=item.value" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.sortWay==item.value) }">
<i class="layui-anim layui-icon">{{ nc.sortWay == item.value ? "&#xe643;" : "&#xe63f;" }}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
</div>
<div class="template-edit-title" v-if="nc.labelStyle.support">
<h3>标签内容</h3>
<div class="layui-form-item">
<label class="layui-form-label sm">标签</label>
<div class="layui-input-block">
<input type="text" v-model="nc.labelStyle.title" maxlength="4" placeholder="请输入标签" class="layui-input">
</div>
</div>
</div>
<div class="template-edit-title">
<h3>显示内容</h3>
<div class="layui-form-item" v-show="nc.goodsNameStyle.support">
<label class="layui-form-label sm">商品名称</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="nc.goodsNameStyle.control = !nc.goodsNameStyle.control" :class="{ 'layui-form-checked' : nc.goodsNameStyle.control }">
<span>{{ nc.goodsNameStyle.control ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label sm">销售价</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="nc.priceStyle.mainControl = !nc.priceStyle.mainControl" :class="{ 'layui-form-checked' : nc.priceStyle.mainControl }">
<span>{{ nc.priceStyle.mainControl ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item" v-show="nc.priceStyle.lineSupport">
<label class="layui-form-label sm">划线价</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="nc.priceStyle.lineControl = !nc.priceStyle.lineControl" :class="{ 'layui-form-checked' : nc.priceStyle.lineControl }">
<span>{{ nc.priceStyle.lineControl ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
<div class="layui-form-item" v-show="nc.saleStyle.support">
<label class="layui-form-label sm">商品销量</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="nc.saleStyle.control = !nc.saleStyle.control" :class="{ 'layui-form-checked' : nc.saleStyle.control }">
<span>{{ nc.saleStyle.control ? '显示' : '隐藏' }}</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
</div>
</div>
</div>
</template>
<!-- 弹框 -->
<article class="style-list-box-goods-recommend">
<div class="style-list-goods-recommend layui-form">
<div class="style-list-con-goods-recommend">
<div class="style-li-goods-recommend" v-for="(value,name,index) in nc.tempData.styleList" :key="name" :class="{'selected border-color': nc.style == name}" :data_key="name">
<span class="layui-hide">风格{{index + 1}}</span>
<img :src="'{$resource_path}/img/style' + (index+1) + '.png'" />
</div>
</div>
<input type="hidden" name="style">
<input type="hidden" name="style_name" />
</div>
</article>
<!-- 商品分类选择弹框 -->
<script type="text/html" class="goods-category-layer">
<div class="goods-category-list layui-form">
<table class="layui-table pithy-table">
<colgroup>
<col width="5%">
<col width="3%">
<col width="37%">
<col width="25%">
<col width="30%">
</colgroup>
<thead>
<tr>
<th></th>
<th></th>
<th>分类名称</th>
<th>简称</th>
<th>图片</th>
</tr>
</thead>
<tbody>
{if condition="$category_list"}
{foreach name="$category_list" item="vo"}
<tr class='category-line'>
<td><input type="checkbox" name="category_select_id" data-category_select_id = "{$vo['category_id']}"lay-skin="primary" value='{:json_encode($vo)}' lay-filter="category_select_id"{if !empty($link_array.category_id) && $link_array.category_id == $vo['category_id']}checked{/if}></td>
<td>
{notempty name="$vo['child_list']"}
<span class="switch text-color js-switch" data-category-id="{$vo['category_id']}" data-level="{$vo['level']}" data-open="0">+</span>
{/notempty}
</td>
<td class="category-name">{$vo['category_name']}</td>
<td>{$vo['short_name']}</td>
<td>
{notempty name="$vo['image']"}
<div class="img-box">
<img layer-src src="{:img($vo['image'])}"/>
</div>
{/notempty}
</td>
</tr>
{notempty name="$vo['child_list']"}
{foreach name="$vo['child_list']" item="second"}
<tr class='category-line' data-category-id-1="{$second['category_id_1']}" style="display:none;">
<td><input type="checkbox" name="category_select_id" lay-skin="primary"data-category_select_id = "{$second['category_id']}" value='{:json_encode($second)}' lay-filter="category_select_id"{if !empty($link_array.category_id) && $link_array.category_id == $second['category_id']}checked{/if}></td>
<td></td>
<td style="padding-left: 20px;">
<span class="switch text-color js-switch" data-category-id="{$second['category_id']}" data-level="{$second['level']}" data-open="1" style="padding-right: 20px;">-</span>
<span class="category-name">{$second['category_name']}</span>
</td>
<td>{$second['short_name']}</td>
<td>
{notempty name="$second['image']"}
<img layer-src src="{:img($second['image'])}"/>
{/notempty}
</td>
</tr>
{notempty name="$second['child_list']"}
{foreach name="$second['child_list']" item="third"}
<tr class='category-line' data-category-id-1="{$third['category_id_1']}" data-category-id-2="{$third['category_id_2']}" style="display:none;">
<td><input type="checkbox" name="category_select_id" lay-skin="primary" value='{:json_encode($third)}' data-category_select_id = '{$third['category_id']}'lay-filter="category_select_id"{if !empty($link_array.category_id) && $link_array.category_id == $third['category_id']}checked{/if}></td>
<td></td>
<td style="padding-left: 80px;">
<span class="category-name">{$third['category_name']}</span>
</td>
<td>{$third['short_name']}</td>
<td>
{notempty name="$third['image']"}
<img layer-src src="{:img($third['image'])}"/>
{/notempty}
</td>
</tr>
{/foreach}
{/notempty}
{/foreach}
{/notempty}
{/foreach}
{else/}
<tr>
<td colspan="9" style="text-align: center">无数据</td>
</tr>
{/if}
</tbody>
</table>
</div>
</script>
</template>
<!-- 样式编辑 -->
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<div class="template-edit-title">
<h3>头部样式</h3>
<div v-if="nc.topStyle.support">
<nc-icon :data="{ field : 'value',label:'选择图标', parent : nc.topStyle.icon, color: 'color'}"></nc-icon>
<color :data="{ field : 'color', 'label' : '图标颜色', parent : nc.topStyle.icon, 'defaultColor': '#303133' }"></color>
<color :data="{ field : 'bgColor', 'label' : '图标背景', parent : nc.topStyle.icon }"></color>
<color :data="{ field : 'color', 'label' : '标题颜色', parent : nc.topStyle, defaultColor : '#303133' }"></color>
<color :data="{ field : 'subColor', 'label': '副标题颜色', parent : nc.topStyle, defaultColor : '#999CA7' }"></color>
</div>
<div class="layui-form-item">
<label class="layui-form-label sm">背景图片</label>
<div class="layui-input-block img-upload">
<img-upload :data="{ data : nc, field : 'bgUrl', isShow:true }"></img-upload>
</div>
</div>
</div>
<div class="template-edit-title">
<h3>商品样式</h3>
<div class="layui-form-item tag-wrap">
<label class="layui-form-label sm">边框</label>
<div class="layui-input-block">
<div v-for="(item,ornamentIndex) in nc.tempData.ornamentList" :key="ornamentIndex" @click="nc.ornament.type=item.type" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.ornament.type==item.type) }">
<i class="layui-anim layui-icon">{{ nc.ornament.type == item.type ? "&#xe643;" : "&#xe63f;" }}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<color v-if="nc.ornament.type != 'default'" :data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }"></color>
<slide :data="{ field : 'imgAroundRadius', label: '图片圆角', min:0, max: 50 }"></slide>
<div class="layui-form-item" v-show="nc.goodsNameStyle.control">
<label class="layui-form-label sm">商品名称</label>
<div class="layui-input-block">
<div class="layui-unselect layui-form-checkbox" lay-skin="primary" @click="nc.goodsNameStyle.fontWeight = !nc.goodsNameStyle.fontWeight" :class="{ 'layui-form-checked' : nc.goodsNameStyle.fontWeight }">
<span>加粗</span>
<i class="layui-icon layui-icon-ok"></i>
</div>
<div v-for="(item,nameLineIndex) in nc.tempData.nameLineModeList" :key="nameLineIndex" @click="nc.nameLineMode=item.value" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.nameLineMode==item.value) }">
<i class="layui-anim layui-icon">{{ nc.nameLineMode == item.value ? "&#xe643;" : "&#xe63f;" }}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<color :data="{ field : 'elementBgColor', 'label' : '商品背景' }"></color>
<slide v-show="nc.elementAngle == 'round'" :data="{ field : 'topElementAroundRadius', label : '上圆角', max : 50 }"></slide>
<slide v-show="nc.elementAngle == 'round'" :data="{ field : 'bottomElementAroundRadius', label : '下圆角', max : 50 }"></slide>
<div class="layui-form-item">
<label class="layui-form-label sm">色调</label>
<div class="layui-input-block">
<div @click="nc.theme='default'" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.theme == 'default') }">
<i class="layui-anim layui-icon">{{ nc.theme == 'default' ? "&#xe643;" : "&#xe63f;" }}</i>
<div>跟随主题风格</div>
</div>
<div @click="nc.theme='diy'" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.theme == 'diy') }">
<i class="layui-anim layui-icon">{{ nc.theme == 'diy' ? "&#xe643;" : "&#xe63f;" }}</i>
<div>自定义</div>
</div>
</div>
</div>
<div v-show="nc.theme == 'diy'">
<div v-show="nc.goodsNameStyle.support">
<color :data="{ field : 'color', 'label' : '商品名称', parent : 'goodsNameStyle', defaultColor : '#303133' }"></color>
</div>
<color :data="{ field : 'mainColor', 'label' : '销售价', parent : 'priceStyle', defaultColor : '#FF6A00' }"></color>
<div v-show="nc.priceStyle.lineSupport">
<color :data="{ field : 'lineColor', 'label' : '划线价', parent : 'priceStyle', defaultColor : '#999CA7' }"></color>
</div>
<div v-show="nc.saleStyle.support">
<color :data="{ field : 'color', 'label' : '商品销量', parent : 'saleStyle', defaultColor : '#999CA7' }"></color>
</div>
</div>
</div>
</template>
</template>
<!-- 资源 -->
<template slot="resource">
<js>
var goodsRecommendResourcePath = "{$resource_path}"; // http路径
var goodsRecommendRelativePath = "{$relative_path}"; // 相对路径
</js>
<css src="{$resource_path}/css/design.css"></css>
<js src="{$resource_path}/js/design.js"></js>
</template>
</nc-component>

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,281 @@
var goodsListHtml = '<div style="display:none;"></div>';
Vue.component("goods-recommend-sources", {
template: goodsListHtml,
data: function () {
return {
data: this.$parent.data,
goodsSources: {
initial: {
text: "默认",
icon: "iconmofang"
},
category: {
text: "商品分类",
icon: "iconshangpinfenlei"
},
diy: {
text: "手动选择",
icon: "iconshoudongxuanze"
},
},
sortWayList: [
{
text: "综合",
value: "default"
},
{
text: "新品",
value: "news"
},
{
text: "热销",
value: "sales"
},
{
text: "价格",
value: "price"
}
],
styleList: {
"style-1": {
goodsNameSupport: true, // 是否支持商品名称
saleSupport: true, // 是否支持商品销量
lineSupport: false, // 是否支持划线价
bgUrl: '',
componentBgColor: '',
elementBgColor: '#FFFFFF',
topStyle: {
support: true,
icon: {
value: "icondiy icon-system-tuijian",
color: "#FF3D3D",
bgColor: "",
},
color: "#303133",
subColor: "#999CA7"
},
},
"style-2": {
goodsNameSupport: true, // 是否支持商品名称
saleSupport: true, // 是否支持商品销量
lineSupport: false, // 是否支持划线价
bgUrl: goodsRecommendRelativePath + '/img/bg.png',
componentBgColor: '#1278FE',
elementBgColor: '#FFFFFF',
topStyle: {
support: true,
icon: {
value: "icondiy icon-system-tuijian",
color: "#1278FE",
bgColor: "#FFFFFF",
},
color: "#FFFFFF",
subColor: "#FFFFFF"
},
},
"style-3": {
goodsNameSupport: false, // 是否支持商品名称
saleSupport: false, // 是否支持商品销量
lineSupport: false, // 是否支持划线价
bgUrl: goodsRecommendRelativePath + '/img/style3_bg.png',
componentBgColor: '',
elementBgColor: '',
labelStyle: {
support: true,
bgColor: "#FF504D",
title: "新人专享"
}
},
},
ornamentList: [
{
type: 'default',
text: '默认',
},
{
type: 'shadow',
text: '投影',
},
{
type: 'stroke',
text: '描边',
},
],
nameLineModeList: [
{
text: "单行",
value: "single"
},
{
text: "多行",
value: "multiple"
}
]
}
},
created: function () {
if (!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['textColor']; //加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
var previewList = {};
for (var i = 1; i < 4; i++) {
previewList["goods_id_" + ns.gen_non_duplicate(i)] = {
goods_name: "商品名称",
discount_price: (Math.random() * 10 * i + 10).toFixed(0), // 随机价格
line_price: (Math.random() * 10 * i + 10 + 10).toFixed(0), // 随机价格
sale_num: Math.floor((Math.random() * 10 * i + 10 + 10))
};
}
// 组件所需的临时数据
this.$parent.data.tempData = {
goodsSources: this.goodsSources,
sortWayList: this.sortWayList,
styleList: this.styleList,
ornamentList: this.ornamentList,
nameLineModeList: this.nameLineModeList,
previewList: previewList,
methods: {
addGoods: this.addGoods,
selectCategory: this.selectCategory,
selectTemplate: this.selectTemplate,
selectStyle: this.selectStyle
},
};
},
methods: {
verify: function (index) {
var res = {code: true, message: ""};
if (vue.data[index].sources === 'category' && vue.data[index].categoryId === 0) {
res.code = false;
res.message = "请选择商品分类";
}
return res;
},
addGoods: function () {
var self = this;
goodsSelect(function (res) {
self.$parent.data.goodsId = res;
}, self.$parent.data.goodsId, {mode: "spu", disabled: 0, promotion: "module", post: ns.appModule});
},
selectCategory() {
var self = this;
layui.use(['form'], function () {
var form = layui.form;
layer.open({
type: 1,
title: '选择分类',
area: ['630px', '430px'],
btn: ['确定', '返回'],
content: $(".draggable-element[data-index='" + self.data.index + "'] .edit-attribute .goods-category-layer").html(),
success: function (layero, index) {
$(".js-switch").click(function () {
var category_id = $(this).attr("data-category-id");
var level = $(this).attr("data-level");
var open = parseInt($(this).attr("data-open").toString());
if (open) {
$(".goods-category-list .layui-table tr[data-category-id-" + level + "='" + category_id + "']").hide();
$(this).text("+");
} else {
$(".goods-category-list .layui-table tr[data-category-id-" + level + "='" + category_id + "']").show();
$(this).text("-");
}
$(this).attr("data-open", (open ? 0 : 1));
});
// 勾选分类
form.on('checkbox(category_select_id)', function (data) {
if (data.elem.checked) {
$("input[name='category_select_id']:checked").prop("checked", false);
$(data.elem).prop("checked", true);
form.render();
}
});
$("input[name='category_select_id']:checked").prop("checked", false);
if (self.data.categoryId) {
$('.layui-layer-content [data-category_select_id="' + self.data.categoryId + '"]').prop("checked", true);
}
form.render();
},
yes: function (index, layero) {
var selected = $(".layui-layer-content input[name='category_select_id']:checked");
if (selected.length === 0) {
layer.msg('请选择商品分类');
return;
}
self.data.categoryName = selected.parents('tr').find('.category-name').text();
self.data.categoryId = selected.attr('data-category_select_id');
layer.closeAll()
}
});
});
},
selectTemplate(template, item) {
this.$parent.data.goodsNameStyle.support = this.styleList[this.$parent.data.style].goodsNameSupport;
this.$parent.data.goodsNameStyle.control = this.styleList[this.$parent.data.style].goodsNameSupport;
this.$parent.data.saleStyle.support = this.styleList[this.$parent.data.style].saleSupport;
this.$parent.data.saleStyle.control = this.styleList[this.$parent.data.style].saleSupport;
this.$parent.data.priceStyle.lineSupport = this.styleList[this.$parent.data.style].lineSupport;
this.$parent.data.priceStyle.lineControl = this.styleList[this.$parent.data.style].lineSupport;
this.$parent.data.bgUrl = this.styleList[this.$parent.data.style].bgUrl;
this.$parent.data.componentBgColor = this.styleList[this.$parent.data.style].componentBgColor;
this.$parent.data.elementBgColor = this.styleList[this.$parent.data.style].elementBgColor;
// 顶部标题样式
if(this.styleList[this.$parent.data.style].topStyle) {
this.$parent.data.topStyle.support = this.styleList[this.$parent.data.style].topStyle.support;
this.$parent.data.topStyle.color = this.styleList[this.$parent.data.style].topStyle.color;
this.$parent.data.topStyle.subColor = this.styleList[this.$parent.data.style].topStyle.subColor;
this.$parent.data.topStyle.icon.value = this.styleList[this.$parent.data.style].topStyle.icon.value;
this.$parent.data.topStyle.icon.color = this.styleList[this.$parent.data.style].topStyle.icon.color;
this.$parent.data.topStyle.icon.bgColor = this.styleList[this.$parent.data.style].topStyle.icon.bgColor;
}else{
this.$parent.data.topStyle.support = false;
}
if(this.styleList[this.$parent.data.style].labelStyle){
this.$parent.data.labelStyle.support = this.styleList[this.$parent.data.style].labelStyle.support;
this.$parent.data.labelStyle.bgColor = this.styleList[this.$parent.data.style].labelStyle.bgColor;
this.$parent.data.labelStyle.title = this.styleList[this.$parent.data.style].labelStyle.title;
}else{
this.$parent.data.labelStyle.support = false;
}
},
selectStyle: function () {
var self = this;
layer.open({
type: 1,
title: '风格选择',
area: ['920px', '400px'],
btn: ['确定', '返回'],
content: $(".draggable-element[data-index='" + self.data.index + "'] .edit-attribute .style-list-box-goods-recommend").html(),
success: function (layero, index) {
$(".layui-layer-content input[name='style']").val(self.data.style);
$(".layui-layer-content input[name='style_name']").val(self.data.styleName);
$("body").off("click", ".layui-layer-content .style-list-con-goods-recommend .style-li-goods-recommend").on("click", ".layui-layer-content .style-list-con-goods-recommend .style-li-goods-recommend", function () {
$(this).addClass("selected border-color").siblings().removeClass("selected border-color bg-color-after");
$(".layui-layer-content input[name='style']").val($(this).attr("data_key"));
$(".layui-layer-content input[name='style_name']").val($(this).find("span").text());
});
},
yes: function (index, layero) {
self.data.style = $(".layui-layer-content input[name='style']").val();
self.data.styleName = $(".layui-layer-content input[name='style_name']").val();
self.selectTemplate();
layer.closeAll()
}
});
}
}
});

View File

@@ -0,0 +1,406 @@
@CHARSET "UTF-8";
/*图文导航组件*/
.graphic-navigation .preview-draggable .preview-box {
padding: 8px 0;
margin: 0 15px;
border-radius: 5px;
}
.graphic-navigation .preview-draggable ul {
overflow: hidden;
list-style: none;
}
.graphic-navigation .preview-draggable ul.horizontal-scroll {
overflow-x: scroll;
white-space: nowrap;
}
.graphic-navigation .preview-draggable ul.horizontal-scroll::-webkit-scrollbar {
display: none;
}
.graphic-navigation .preview-draggable li {
width: 50%;
text-align: center;
display: inline-block;
vertical-align: top;
}
.graphic-navigation .preview-draggable li img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
.graphic-navigation .preview-draggable li:last-child {
border: 0;
}
.graphic-navigation .preview-draggable li span {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
height: 20px;
display: block;
line-height: 20px;
}
/*.graphic-navigation .preview-draggable .graphic-nav{visibility: hidden;}*/
.graphic-navigation .preview-draggable .graphic-nav>.wrap {
/* overflow-x: hidden;white-space: nowrap; background: #ffffff; */
display: flex;
/* justify-content: space-around; */
flex-wrap: wrap;
padding: 0 5px;
}
.graphic-navigation .graphic-nav-list .template-list .template-item {
float: left;
text-align: center;
border: 1px solid #e5e5e5;
margin-right: 20px;
padding: 5px;
background: #ffffff;
cursor: pointer;
}
.graphic-navigation .graphic-nav-list .template-list .template-item img {
display: block;
}
.graphic-navigation .add-item {
padding: 10px;
border: 1px dashed #e5e5e5;
margin: 16px 0 10px;
cursor: pointer;
text-align: center;
}
.graphic-navigation .add-item i {
display: inline-block;
height: 24px;
line-height: 24px;
font-size: 18px;
margin-right: 10px;
font-style: normal;
}
.graphic-navigation .add-item span {
display: inline-block;
height: 24px;
line-height: 24px;
}
.graphic-navigation .error-msg {
margin: 5px 0 0 53px;
color: #f44;
display: none;
}
/* 新的css */
.graphic-navigation .graphic-nav{
padding: 10px 5px;
}
/* 预览 */
/* 固定显示 */
.graphic-navigation .graphic-nav.fixed{
display: flex;
flex-wrap: wrap;
}
/* 单边滑动 */
.graphic-navigation .graphic-nav.singleSlide{
display: flex;
overflow-x: auto;
}
.graphic-navigation .graphic-nav.singleSlide::-webkit-scrollbar {
height: 5px;
}
.graphic-navigation .graphic-nav.singleSlide::-webkit-scrollbar-track {
background-color: #e4e4e4;
}
.graphic-navigation .graphic-nav.singleSlide::-webkit-scrollbar-thumb {
background-color: #999;
}
.graphic-navigation .graphic-nav.singleSlide .graphic-nav-item{
flex-shrink: 0;
}
/* 分页 */
.graphic-navigation .graphic-nav.pageSlide{
position: relative;
}
.graphic-navigation .graphic-nav.pageSlide .graphic-nav-wrap{
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn{
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn .arrows{
display: flex;
justify-content: space-between;
padding: 0 15px;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn .arrows i{
display: none;
width: 36px;
height: 36px;
line-height: 36px;
text-align: center;
color: #fff;
background-color: rgba(0, 0, 0, .35);
border-radius: 50%;
cursor: pointer;
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn .dot-wrap{
text-align: center;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn .dot-wrap.hide{
display: none;
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn .dot-wrap.straightLine i{
width: 12px;
height: 4px;
border-radius: 0;
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn .dot-wrap i{
display: inline-block;
width: 7px;
height: 7px;
border-radius: 50%;
background-color: rgba(0, 0, 0, .1);
margin-right: 5px;
cursor: pointer;
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn .dot-wrap i.active{
background-color: rgba(0, 0, 0, .5);
}
.graphic-navigation .graphic-nav.pageSlide .carousel-btn:hover .arrows i{
display: block;
}
.graphic-navigation .graphic-nav .graphic-nav-item{
display: flex;
flex-direction: column;
align-items: center;
padding: 7px 0;
box-sizing: border-box;
}
.newright{
margin-right: 10px;
}
.graphic-navigation .graphic-nav .graphic-nav-item .graphic-text{
padding-top: 6px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
text-align: center;
}
.graphic-navigation .graphic-nav .graphic-nav-item .graphic-img{
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
font-size: 40px;
}
.graphic-navigation .graphic-nav .graphic-nav-item .graphic-img .tag{
position: absolute;
top: -5px;
right: -12px;
color: #fff;
background-color: red;
border-radius: 12px;
border-bottom-left-radius: 0;
transform: scale(0.8);
padding: 2px 6px;
font-size: 12px;
}
.graphic-navigation .graphic-nav .graphic-nav-item .graphic-img img{
max-width: 100%;
max-height: 100%;
}
.graphic-navigation .graphic-nav .graphic-nav-item .graphic-img i{
font-size: 25px;
color: #666;
}
/* 图文导航项 */
.graphic-navigation p.hint {
padding-left: 15px;
font-size: 12px;
color: #909399;
line-height: 20px;
}
.graphic-navigation .graphic-nav-list>ul {
padding: 10px 0 10px 15px;
}
.graphic-navigation .graphic-nav-list>ul>li {
padding: 10px 10px 10px 0px;
background: #ffffff;
border: 1px dashed #e5e5e5;
position: relative;
margin-top: 16px;
}
.graphic-navigation .graphic-nav-list>ul>li>.iconfont {
position: absolute;
top: calc(50% - 10px);
left: 15px;
cursor: move;
font-size: 20px;
}
.graphic-navigation .graphic-nav-list>ul>li:first-child {
margin-top: 0;
}
.graphic-navigation .graphic-nav-list>ul>li:hover .del {
display: block;
}
.graphic-navigation .edit-attribute .attr-wrap .restore-wrap .img-block, .graphic-navigation .edit-attribute .attr-wrap .restore-wrap .img-block.has-choose-image > div{
width: 50px;
height: 50px;
line-height: 50px;
}
.graphic-navigation .edit-attribute .attr-wrap .restore-wrap .img-block.has-choose-image img {
width: 35px;
height: 35px;
}
.graphic-navigation .edit-attribute .icon-box {
width: 60px;
height: 60px;
font-size: 60px;
border: 1px dashed #ddd;
display: flex;
align-items: center;
justify-content: center;
padding: 0!important;
cursor: pointer;
position: relative;
}
.graphic-navigation .edit-attribute .icon-box .select-icon {
width: inherit;
height: inherit;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
line-height: 1;
}
.graphic-navigation .edit-attribute .icon-box .select-icon .add {
font-size: 26px;
color: var(--base-color);
}
.graphic-navigation .edit-attribute .icon-box .operation {
position: absolute;
width: 100%;
height: 100%;
background: rgba(0,0,0,.6);
flex-direction: column;
display: none;
}
.graphic-navigation .edit-attribute .icon-box:hover .operation {
display: flex;
}
.graphic-navigation .edit-attribute .icon-box .operation-warp {
flex: 1;
height: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.graphic-navigation .edit-attribute .icon-box .iconfont {
margin: 0 3px;
font-size: 16px!important;
}
.graphic-navigation .edit-attribute .icon-box .operation .js-replace{
line-height: 1;
color: #fff;
text-align: center;
padding: 5px 0;
background: rgba(0,0,0,.7);
font-size: 12px;
height: unset;
}
.graphic-navigation .edit-attribute .graphic-nav-list .icon-box .icon-wrap:hover .operation{
display: block;
}
.graphic-navigation .edit-attribute .graphic-nav-list .img-upload .upload-img-box:hover .operation{
display: block;
}
.graphic-navigation .edit-attribute .navigation-set-list .img-upload {
display: flex;
align-items: center;
}
.graphic-navigation .edit-attribute .navigation-set-list .img-upload img {
width: 100%;
height: 100%;
}
.graphic-navigation .edit-attribute .navigation-set-list .action-box {
display: flex;
}
.graphic-navigation .edit-attribute .navigation-set-list .action {
margin-right: 3px;
width: 42px;
height: 28px;
line-height: 28px;
text-align: center;
border: 1px solid #EEEEEE;
cursor: pointer;
}
.graphic-navigation .edit-attribute .navigation-set-list .action:hover {
border-color: var(--base-color);
color: var(--base-color);
}
.graphic-navigation .img-icon-box{
display: flex;
align-items: center;
}

View File

@@ -0,0 +1,227 @@
<nc-component :data="data[index]" class="graphic-navigation">
<!-- 预览 -->
<template slot="preview">
<template v-if="nc.lazyLoad">
<div :class="['graphic-nav',nc.showStyle] " :style="{
backgroundColor: nc.componentBgColor,
borderTopLeftRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderTopRightRadius: (nc.componentAngle == 'round' ? nc.topAroundRadius + 'px' : 0),
borderBottomLeftRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
borderBottomRightRadius: (nc.componentAngle == 'round' ? nc.bottomAroundRadius + 'px' : 0),
boxShadow: nc.ornament.type == 'shadow' ? ('0 0 5px ' + nc.ornament.color) : '',
border: nc.ornament.type == 'stroke' ? '1px solid ' + nc.ornament.color : ''
}">
<template v-if="nc.showStyle == 'pageSlide'">
<div class="graphic-nav-wrap" v-for="(numItem,numIndex) in Math.ceil(nc.list.length / (nc.pageCount * nc.rowCount))">
<div :class="['graphic-nav-item',{'layui-hide': nc.tempData.carouselIndex != numIndex}]"
v-for="(item,previewIndex) in nc.list" :key="previewIndex"
v-if="previewIndex >= [(numItem-1) * (nc.pageCount * nc.rowCount)] && previewIndex < [numItem * (nc.pageCount * nc.rowCount)]"
:style="{width: (100 / nc.rowCount + '%')}"
>
<div class="graphic-img" v-show="nc.mode != 'text'" :style="{'font-size' : nc.imageSize + 'px'}">
<img v-if="item.iconType == 'img' && item.imageUrl" :src="changeImgUrl(item.imageUrl)" alt="" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px', borderRadius: nc.aroundRadius + 'px'}">
<iconfont v-if="item.iconType == 'icon' && item.icon" :icon="item.icon" :value="(item.style ? item.style : null)" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px'}"></iconfont>
<img v-if="!item.icon && !item.imageUrl" :src="changeImgUrl('public/static/img/default_img/square.png')" alt="" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px', borderRadius: nc.aroundRadius + 'px'}">
<span class="tag" v-if="item.label.control" :style="{color: item.label.textColor,backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')'}">{{item.label.text}}</span>
</div>
<span v-show="nc.mode != 'img'" class="graphic-text" :style="{fontSize: nc.font.size + 'px',fontWeight: nc.font.weight, color: nc.font.color}">{{item.title}}</span>
</div>
</div>
<div class="carousel-btn" v-if="Math.ceil(nc.list.length / (nc.pageCount * nc.rowCount)) -1">
<div class="arrows">
<i class="iconfont iconback_light" @click="nc.tempData.carouselIndex = (nc.tempData.carouselIndex ? nc.tempData.carouselIndex-1 : nc.tempData.carouselIndex)"></i>
<i class="iconfont iconyoujiantou" @click="nc.tempData.carouselIndex = [nc.tempData.carouselIndex < Math.ceil(nc.list.length / (nc.pageCount * nc.rowCount))-1 ? + nc.tempData.carouselIndex + 1 : Math.ceil(nc.list.length / (nc.pageCount * nc.rowCount))-1]"></i>
</div>
<div :class="['dot-wrap',nc.carousel.type]">
<i v-for="(numItem,numIndex) in Math.ceil(nc.list.length / (nc.pageCount * nc.rowCount))" :class="{'active': nc.tempData.carouselIndex == numIndex}" @click="nc.tempData.carouselIndex = numIndex"></i>
</div>
</div>
</template>
<div v-else class="graphic-nav-item" v-for="(item) in nc.list" :key="item.id" :style="{width: (100 / nc.rowCount + '%')}" :class="nc.mode == 'text'?'newright':''">
<div class="graphic-img" v-show="nc.mode != 'text'" :style="{'font-size' : nc.imageSize + 'px', width: nc.imageSize + 'px', height: nc.imageSize + 'px'}">
<img v-if="item.iconType == 'img' && item.imageUrl" :src="changeImgUrl(item.imageUrl)" alt="" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px', borderRadius: nc.aroundRadius + 'px'}">
<iconfont v-if="item.iconType == 'icon' && item.icon" :icon="item.icon" :value="(item.style ? item.style : null)" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px'}"></iconfont>
<img v-if="!item.icon && !item.imageUrl" :src="changeImgUrl('public/static/img/default_img/square.png')" alt="" :style="{maxWidth: nc.imageSize + 'px', maxHeight: nc.imageSize + 'px', borderRadius: nc.aroundRadius + 'px'}">
<span class="tag" v-if="item.label.control" :style="{color: item.label.textColor,backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')'}">{{item.label.text}}</span>
</div>
<!-- margin-right: 10px; -->
<span v-show="nc.mode != 'img'" class="graphic-text" :style="{fontSize: nc.font.size+'px',fontWeight: nc.font.weight, color: nc.font.color,backgroundColor:nc.mode=='text'?nc.font.bgcolor:'',paddingBottom:nc.mode=='text'?'7px':''}" style="border-radius: 4px;">{{item.title}}</span>
</div>
</div>
</template>
</template>
<!-- 内容编辑 -->
<template slot="edit-content">
<template v-if="nc.lazyLoad">
<graphic-nav-list></graphic-nav-list>
<div class="template-edit-title">
<h3>导航模式</h3>
<div class="layui-form-item icon-radio">
<label class="layui-form-label sm">选择模式</label>
<div class="layui-input-block">
<span v-for="item in nc.tempData.modeList" :class="[item.value == nc.mode ? '' : 'layui-hide']">{{item.name}}</span>
<ul class="icon-wrap">
<li v-for="item in nc.tempData.modeList" :class="[item.value == nc.mode ? 'text-color border-color' : '']" @click="nc.mode = item.value">
<i :class="['iconfont',item.src]"></i>
</li>
</ul>
</div>
</div>
<div class="layui-form-item icon-radio">
<label class="layui-form-label sm">展示风格</label>
<div class="layui-input-block">
<span v-for="item in nc.tempData.showStyleList" :class="[item.value == nc.showStyle ? '' : 'layui-hide']">{{item.name}}</span>
<ul class="icon-wrap">
<li v-for="item in nc.tempData.showStyleList" :class="[item.value == nc.showStyle ? 'text-color border-color' : '']" @click="nc.showStyle = item.value">
<i :class="['iconfont',item.src]"></i>
</li>
</ul>
</div>
</div>
<div class="layui-form-item icon-radio">
<label class="layui-form-label sm">每行数量</label>
<div class="layui-input-block">
<span v-for="item in nc.tempData.rowCountList" :class="[{'layui-hide': item.value != nc.rowCount}]">{{item.name}}</span>
<ul class="icon-wrap">
<li v-for="item in nc.tempData.rowCountList" :class="[item.value == nc.rowCount ? 'text-color border-color' : '']" @click="nc.rowCount = item.value">
<i :class="['iconfont',item.src]"></i>
</li>
</ul>
</div>
</div>
<div class="layui-form-item icon-radio" v-show="nc.showStyle == 'pageSlide'">
<label class="layui-form-label sm">每页行数</label>
<div class="layui-input-block">
<span v-for="item in nc.tempData.pageCountList" :class="[item.value == nc.pageCount ? '' : 'layui-hide']">{{item.name}}</span>
<ul class="icon-wrap">
<li v-for="item in nc.tempData.pageCountList" :class="[item.value == nc.pageCount ? 'text-color border-color' : '']" @click="nc.pageCount = item.value">
<i :class="['iconfont',item.src]"></i>
</li>
</ul>
</div>
</div>
</div>
<div class="template-edit-title">
<h3>图文导航项</h3>
<div class="graphic-nav-list">
<p class="hint">建议上传尺寸相同的图片(60px * 60px)</p>
<ul class="navigation-set-list">
<li v-for="(item,previewIndex) in nc.list" :key="item.id" class="content-block">
<template v-if="['graphic','img'].includes(nc.mode)">
<div class="layui-form-item">
<label class="layui-form-label sm">图片</label>
<div class="layui-input-block">
<image-upload :data="{ data : item }" :condition="['graphic','img'].includes(nc.mode)" data-disabled="1"></image-upload>
</div>
</div>
</template>
<div class="layui-form-item" v-if="['graphic','text'].includes(nc.mode)">
<label class="layui-form-label sm">标题</label>
<div class="layui-input-block">
<input type="text" name='title' v-model="item.title" maxlength="20" class="layui-input" autocomplete="off" />
</div>
</div>
<nc-link :data="{ field : item.link, label:'链接' }"></nc-link>
<i class="del" @click="nc.list.splice(previewIndex,1)" data-disabled="1">x</i>
<div class="error-msg"></div>
<div class="iconfont icontuodong"></div>
</li>
<div class="add-item text-color" @click="nc.tempData.methods.addNav()">
<i>+</i>
<span>添加一个图文导航</span>
</div>
</ul>
</div>
</div>
</template>
</template>
<!-- 样式编辑 -->
<template slot="edit-style">
<template v-if="nc.lazyLoad">
<div class="template-edit-title">
<h3>图文导航</h3>
<div class="layui-form-item tag-wrap">
<label class="layui-form-label sm">样式</label>
<div class="layui-input-block">
<div v-for="(item,ornamentIndex) in nc.tempData.ornamentList" :key="ornamentIndex" @click="nc.ornament.type=item.type" :class="{ 'layui-unselect layui-form-radio' : true,'layui-form-radioed' : (nc.ornament.type==item.type) }">
<i class="layui-anim layui-icon">{{ nc.ornament.type == item.type ? "&#xe643;" : "&#xe63f;" }}</i>
<div>{{item.text}}</div>
</div>
</div>
</div>
<color v-if="nc.ornament.type != 'default'" :data="{ field : 'color', 'label' : '边框颜色', parent : 'ornament', defaultColor : '#EDEDED' }"></color>
<div class="layui-form-item icon-radio" v-show="nc.showStyle == 'pageSlide'">
<label class="layui-form-label sm">轮播点样式</label>
<div class="layui-input-block">
<span v-for="item in nc.tempData.carouselList" :class="[{'layui-hide': item.value != nc.carousel.type}]">{{item.name}}</span>
<ul class="icon-wrap">
<li v-for="item in nc.tempData.carouselList" :class="[item.value == nc.carousel.type ? 'text-color border-color' : '']" @click="nc.carousel.type = item.value">
<i :class="['iconfont',item.src]"></i>
</li>
</ul>
</div>
</div>
</div>
<div class="template-edit-title" v-show="['graphic','img'].includes(nc.mode) && nc.type == 'img'">
<h3>图片设置</h3>
<template v-if="nc.type == 'img'">
<slide :data="{ field : 'aroundRadius', label : '图片圆角', max : 50 }"></slide>
<slide :data="{ field : 'imageSize', label : '图片大小', min: 30, max : 60 }"></slide>
</template>
</div>
<div class="template-edit-title" v-if="['graphic','text'].includes(nc.mode)">
<h3>文字设置</h3>
<slide :data="{ field : 'size',parent:'font', label : '文字大小', min: 12, max : 16 }"></slide>
<div class="layui-form-item icon-radio">
<label class="layui-form-label sm">文字粗细</label>
<div class="layui-input-block">
<span v-for="item in nc.tempData.thicknessList" :class="[item.value == nc.font.weight ? '' : 'layui-hide']">{{item.name}}</span>
<ul class="icon-wrap">
<li v-for="(item, index) in nc.tempData.thicknessList" :class="[item.value == nc.font.weight ? 'text-color border-color' : '']" @click="nc.font.weight = item.value">
<i class="iconfont" :class="[{'text-color': item.value == nc.font.weight}, item.src]"></i>
</li>
</ul>
</div>
</div>
<color :data="{ field : 'color', label : '文字颜色',parent:'font',defaultColor: '#303133' }"></color>
<color :data="{ field : 'bgcolor', label : '文字背景颜色',parent:'font',defaultColor: '#303133' }"></color>
</div>
</template>
</template>
<!-- 资源 -->
<template slot="resource">
<js>
var graphicNavResourcePath = "{$resource_path}"; // http路径
var graphicNavRelativePath = "{$relative_path}"; // 相对路径
</js>
<css src="{$resource_path}/css/design.css?time={$time}"></css>
<js src="{$resource_path}/js/design.js"></js>
</template>
</nc-component>

View File

@@ -0,0 +1,367 @@
/**
* [图片导航的图片]·组件
*/
var graphicNavListHtml = '<div style="display: none;"></div>';
Vue.component("graphic-nav-list", {
template: graphicNavListHtml,
data: function () {
return {
data: this.$parent.data,
list: this.$parent.data.list,
modeList: [
{
name: "图文导航",
value: "graphic",
src: "icontuwendaohang3"
},
{
name: "图片导航",
value: "img",
src: "icontudaohang"
},
{
name: "文字导航",
value: "text",
src: "iconwendaohang"
}
],
showStyleList: [
{
name: "固定显示",
value: "fixed",
src: "icongudingzhanshi"
},
{
name: "单行滑动",
value: "singleSlide",
src: "icondanhanghuadong"
},
{
name: "分页滑动",
value: "pageSlide",
src: "iconfenyehuadong"
}
],
ornamentList: [
{
type: 'default',
text: '默认',
},
{
type: 'shadow',
text: '投影',
},
{
type: 'stroke',
text: '描边',
},
],
carouselList: [
{
name: "圆点",
value: "circle",
src: "iconshenglvehao"
},
{
name: "直线",
value: "straightLine",
src: "iconshixian"
},
{
name: "隐藏",
value: "hide",
src: "iconyincang"
}
],
rowCountList: [
{
name: "3个",
value: 3,
src: "iconyihangsange"
},
{
name: "4个",
value: 4,
src: "iconyihangsige"
},
{
name: "5个",
value: 5,
src: "iconyihang5ge"
}
],
pageCountList: [
{
name: "1行",
value: 1,
src: "iconfuzhushuxian"
},
{
name: "2行",
value: 2,
src: "iconyihangliangge"
}
],
thicknessList: [
{name: "加粗", src: "iconbold", value: "bold"},
{name: "常规", src: "iconbold-copy", value: "normal"}
]
};
},
created: function () {
if (!this.$parent.data.verify) this.$parent.data.verify = [];
this.$parent.data.verify.push(this.verify);//加载验证方法
this.$parent.data.ignore = ['textColor', 'elementBgColor', 'elementAngle'];//加载忽略内容 -- 其他设置中的属性设置
this.$parent.data.ignoreLoad = true; // 等待忽略数组赋值后加载
// 组件所需的临时数据
this.$parent.data.tempData = {
...this.$parent.data.tempData,
modeList: this.modeList,
showStyleList: this.showStyleList,
ornamentList: this.ornamentList,
carouselList: this.carouselList,
rowCountList: this.rowCountList,
pageCountList: this.pageCountList,
thicknessList:this.thicknessList,
carouselIndex: 0,
methods: {
addNav: this.addNav
}
};
this.list.forEach(function (e, i) {
if(!e.id ) e.id = ns.gen_non_duplicate(6);
});
this.$parent.data.list = this.list;
var moveBeforeIndex = 0;
var _this = this;
setTimeout(function () {
var componentIndex = _this.data.index;
$('[data-index="' + componentIndex + '"] .navigation-set-list').DDSort({
target: 'li',
floatStyle: {
'border': '1px solid #ccc',
'background-color': '#fff'
},
//设置可拖拽区域
draggableArea: "icontuodong",
down: function (index) {
moveBeforeIndex = index;
},
up: function () {
var index = $(this).index();
var temp = _this.list[moveBeforeIndex];
_this.list.splice(moveBeforeIndex, 1);
_this.list.splice(index, 0, temp);
_this.$parent.data.list = _this.list;
}
});
})
},
watch: {
"data.pageCount"() {
if (this.data.showStyle == 'pageSlide')
this.data.tempData.carouselIndex = 0
},
"data.rowCount"() {
if (this.data.showStyle == 'pageSlide')
this.data.tempData.carouselIndex = 0
}
},
methods: {
addNav() {
this.list.push({
"title": "",
"icon": "",
"imageUrl": "",
"iconType": "img",
"style": {
"fontSize": "60",
"iconBgColor": [],
"iconBgColorDeg": 0,
"iconBgImg": "",
"bgRadius": 0,
"iconColor": [
"#000000"
],
"iconColorDeg": 0
},
"link": {
"name": ""
},
"label": {
"control": false,
"text": "热门",
"textColor": "#FFFFFF",
"bgColorStart": "#F83287",
"bgColorEnd": "#FE3423"
},
id: ns.gen_non_duplicate(6)
});
},
verify: function (index) {
var res = {code: true, message: ""};
$(".draggable-element[data-index='" + index + "'] .graphic-navigation .graphic-nav-list .navigation-set-list>li").each(function (i) {
if (vue.data[index].mode === "img") {
$(this).find("input[name='title']").removeAttr("style");//清空输入框的样式
//检测是否有未上传的图片
if (vue.data[index].list[i].imageUrl === "") {
res.code = false;
res.message = "请选择一张图片";
$(this).find(".error-msg").text("请选择一张图片").show();
return res;
} else {
$(this).find(".error-msg").text("").hide();
}
} else {
if (vue.data[index].list[i].title === "") {
res.code = false;
res.message = "请输入标题";
$(this).find("input[name='title']").attr("style", "border-color:red !important;").focus();
$(this).find(".error-msg").text("请输入标题").show();
return res;
} else {
$(this).find("input[name='title']").removeAttr("style");
$(this).find(".error-msg").text("").hide();
}
}
});
return res;
}
}
});
var uploadImgHtml = '<div class="img-icon-box">';
uploadImgHtml += '<img-icon-upload :data="{data:myData.data}"></img-icon-upload>';
uploadImgHtml += '<div class="action-box">';
uploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="风格" @click="iconStyle($event)"><i class="iconfont iconpifu"></i></div>';
uploadImgHtml += '<div class="action" v-if="myData.data.iconType == \'icon\'" title="背景" @click="selectColor(\'graphic-nav-color-\' +id)" :id="\'graphic-nav-color-\' +id"><i class="iconfont iconyanse"></i></div>';
//uploadImgHtml += '<div class="action" title="标签" @click="selectLabel()"><i class="iconfont iconbiaoqian1"></i></div>';
uploadImgHtml += '</div>';
uploadImgHtml += '</div>';
Vue.component("image-upload", {
template: uploadImgHtml,
props: {
data: {
type: Object,
default: function () {
return {
data: {},
field: "",
callback: null
};
}
}
},
data: function () {
return {
myData: this.data,
list: [],
parent: this.$parent.data,
id: ns.gen_non_duplicate(10),
colorPicker:{}
};
},
created: function () {
if (this.myData.field === undefined) this.myData.field = "imageUrl";
this.id = ns.gen_non_duplicate(10);
},
methods: {
// 选择图标风格
iconStyle(event) {
var self = this;
selectIconStyle({
elem: event.currentTarget,
icon: self.myData.data.icon,
callback: function (data) {
if (data) {
self.myData.data.style = data;
} else {
iconStyleSet({
style: JSON.stringify(self.myData.data.style),
query: {
icon: self.myData.data.icon
}
}, function (style) {
self.myData.data.style = style;
})
}
}
})
},
/**
* 渲染颜色组件
* @param id
* @param color
* @param callback
*/
colorRender(id, color, callback) {
var self = this;
if (this.colorPicker[id]) return;
setTimeout(function () {
self.colorPicker[id] = Colorpicker.create({
el: id,
color: color,
change: function (elem, hex) {
callback(elem, hex)
}
});
$('#' + id).click();
}, 10)
},
selectColor(id) {
let self = this;
this.colorRender(id, '', function (elem, color) {
if (self.myData.data.style['iconBgImg'] || self.myData.data.style['iconBgColor'].length) {
self.myData.data.style['iconBgColor'] = [color];
} else {
self.myData.data.style['iconColor'] = [color];
}
self.$forceUpdate();
})
},
/**
* 标签设置
* @param data
* @param callback
*/
labelStyle(data, callback) {
layer.open({
title: "标签设置",
type: 2,
area: ['800px', '420px'],
fixed: false, //不固定
btn: ['保存', '取消'],
content: ns.url("shop/diy/selectlabel?request_mode=iframe", data ? data : {}),
yes: function (index, layero) {
var iframeWin = window[layero.find('iframe')[0]['name']];//得到iframe页的窗口对象执行iframe页的方法
iframeWin.selectLabelListener(function (obj) {
if (typeof callback == "string") {
try {
eval(callback + '(obj)');
layer.close(index);
} catch (e) {
console.error('回调函数' + callback + '未定义');
}
} else if (typeof callback == "function") {
callback(obj);
layer.close(index);
}
});
}
});
},
selectLabel() {
let self = this;
this.labelStyle(self.myData.data.label, function (data) {
self.myData.data.label = data;
self.$forceUpdate();
})
}
}
});

View File

@@ -0,0 +1,3 @@
@CHARSET "UTF-8";
/*辅助空白组件*/
.draggable-element>div.auxiliary-blank .preview-box{padding:10px 0;}

Some files were not shown because too many files have changed in this diff Show More