diff --git a/src/addon/personnel/data/upgrade_add_channel_fields.sql b/src/addon/personnel/data/upgrade_add_channel_fields.sql new file mode 100644 index 000000000..4291589a5 --- /dev/null +++ b/src/addon/personnel/data/upgrade_add_channel_fields.sql @@ -0,0 +1,35 @@ +-- 升级脚本:为 personnel_channel 表添加新字段并优化表结构 +-- 执行时间: 2026-01-10 + +-- 1. 为 lucky_personnel_channel 表添加新字段 +ALTER TABLE `lucky_personnel_channel` +ADD COLUMN `feed_token` varchar(255) NOT NULL DEFAULT '' COMMENT '视频号视频的标识' AFTER `feed_id`, +ADD COLUMN `view_count` int unsigned NOT NULL DEFAULT 0 COMMENT '视频观看次数' AFTER `cover_url`, +ADD COLUMN `show_view_count` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否显示视频观看次数:0-不显示,1-显示' AFTER `view_count`, +ADD COLUMN `show_follow` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否显示关注按钮:0-不显示,1-显示' AFTER `show_view_count`; + +-- 2. 优化现有字段长度和类型 +ALTER TABLE `lucky_personnel_channel` +MODIFY COLUMN `channel_type` varchar(30) NOT NULL DEFAULT 'wechat' COMMENT '视频号类型:wechat-微信视频号,douyin-抖音,kuaishou-快手,redbook-小红书,bilibili-B站', +MODIFY COLUMN `channel_name` varchar(200) NOT NULL DEFAULT '' COMMENT '视频号名称', +MODIFY COLUMN `avatar_image_type` varchar(20) NOT NULL DEFAULT 'upload' COMMENT '头像类型:upload-上传图片,url-URL', +MODIFY COLUMN `avatar_url` varchar(500) NOT NULL DEFAULT '' COMMENT '头像URL', +MODIFY COLUMN `video_title` varchar(500) NOT NULL DEFAULT '' COMMENT '视频标题', +MODIFY COLUMN `feed_id` varchar(500) NOT NULL DEFAULT '' COMMENT '视频号内容ID', +MODIFY COLUMN `cover_image_type` varchar(20) NOT NULL DEFAULT 'upload' COMMENT '封面类型:upload-上传图片,url-URL', +MODIFY COLUMN `cover_url` varchar(500) NOT NULL DEFAULT '' COMMENT '封面URL', +MODIFY COLUMN `sort` int NOT NULL DEFAULT 0 COMMENT '排序,数值越小越靠前', +MODIFY COLUMN `is_show` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否显示:0-隐藏,1-显示', +MODIFY COLUMN `channel_id` int unsigned NOT NULL AUTO_INCREMENT, +MODIFY COLUMN `site_id` int unsigned NOT NULL DEFAULT 0 COMMENT '站点ID', +MODIFY COLUMN `create_time` int unsigned NOT NULL DEFAULT 0 COMMENT '创建时间'; + +-- 3. 添加索引优化查询性能 +ALTER TABLE `lucky_personnel_channel` +ADD INDEX `idx_site_id` (`site_id`), +ADD INDEX `idx_channel_type` (`channel_type`), +ADD INDEX `idx_is_show` (`is_show`), +ADD INDEX `idx_sort` (`sort`); + +-- 4. 修改表引擎为 InnoDB 和字符集为 utf8mb4 +ALTER TABLE `lucky_personnel_channel` ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/src/addon/personnel/shop/view/enterprise/channel/edit.html b/src/addon/personnel/shop/view/enterprise/channel/edit.html new file mode 100644 index 000000000..4747d7391 --- /dev/null +++ b/src/addon/personnel/shop/view/enterprise/channel/edit.html @@ -0,0 +1,465 @@ + + + + + + +
+ + +
+ +
+ +
+
+ +
+ +
+ +
+
微信视频号ID获取方式:进入视频号助手,在首页可以查看自己的视频号ID,以sph开头为视频号ID
+
+
+ +
+ +
+
+

不同视频平台的唯一标识获取方式可能不同,请根据具体平台说明获取

+

微信视频号,要填写FeedID的值;

+ +
+
+ +
+ +
+ +
+
+

不同视频平台的唯一标识获取方式可能不同,请根据具体平台说明获取

+

微信视频号,要填写视频的FeedToken值;仅内嵌小程序非同主体视频号视频时使用。

+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + +
+
+ +
+ +
+ +
+
+ +
+ +
+
+
+
+ +

点击上传

+
+
+ + x +
+
+
推荐使用 750x420 像素的图片
+
+ + + +
+ +
+ + +
+
+ +
+ +
+ +
+
+ +
+ +
+
+
+
+ +

点击上传

+
+
+ + x +
+
+
推荐使用 200x200 像素的图片
+
+ + + + +
+ +
+ +
+
数值越小排序越靠前
+
+ +
+ +
+ + +
+
+ +
+ +
+ +
+
+ +
+ +
+ + +
+
+ + + +
+ + +
+ + + +
+ + diff --git a/src/addon/personnel/shop/view/enterprise/channel/lists.html b/src/addon/personnel/shop/view/enterprise/channel/lists.html new file mode 100644 index 000000000..ac9cb85d5 --- /dev/null +++ b/src/addon/personnel/shop/view/enterprise/channel/lists.html @@ -0,0 +1,228 @@ + +
+ + +
+ +
+ +
+
+ +
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/src/addon/personnel/shop/view/public/img/channel.png b/src/addon/personnel/shop/view/public/img/channel.png new file mode 100644 index 000000000..23082294a Binary files /dev/null and b/src/addon/personnel/shop/view/public/img/channel.png differ diff --git a/src/app/api/controller/Member.php b/src/app/api/controller/Member.php index e1fa312c1..f2f5038a6 100644 --- a/src/app/api/controller/Member.php +++ b/src/app/api/controller/Member.php @@ -576,6 +576,8 @@ class Member extends BaseApi $Personnelmodel = new PersonnelModel(); $set = $Personnelmodel->getPersonnelSet($this->site_id, $this->app_module)[ 'data' ][ 'value' ]; + //视频号数据 + $channel_list = model('personnel_channel')->getList(['site_id'=>$this->site_id, 'is_show'=>1],'*','sort asc createtime desc'); //视频文件 $video_list = model('personnel_video')->getList(['site_id'=>$this->site_id],'*','createtime desc'); //企业文件 @@ -583,7 +585,20 @@ class Member extends BaseApi //电子名片diy $config = $Personnelmodel->getPersonnelSet($this->site_id, $this->app_module)[ 'data' ][ 'value' ]; $config['value'] = json_decode($config['value'],true); - return $this->response(['code'=>'0','data'=>$list,'message'=>'操作成功','shop'=>$shop_info_result,'set'=>$set,'video_list'=>$video_list,'file_list'=>$file_list,'diy'=>$config['value']]); + return $this->response(['code'=>'0','data'=>$list,'message'=>'操作成功','shop'=>$shop_info_result,'set'=>$set,'channel_list'=>$channel_list, 'video_list'=>$video_list,'file_list'=>$file_list,'diy'=>$config['value']]); + } + /** + * 视频号观看次数+1 + */ + public function incrementChannelViewCount() + { + $id = $this->params[ 'channel_id' ] ?? 0; + if (empty($id)) { + return $this->response($this->error('', '未传视频号id!')); + } + $cur_view_count = model('personnel_channel')->getValue(['channel_id'=>$id], 'view_count', 0); + $res = model('personnel_channel')->update(['view_count'=>$cur_view_count+1],['channel_id'=>$id]); + return $this->response(['code'=>'0','message'=>'操作成功', 'data'=>$res, 'channel_id'=>$id, 'pre_view_count'=>$cur_view_count]); } //留言 public function message() diff --git a/src/app/component/controller/WechatChannel.php b/src/app/component/controller/WechatChannel.php new file mode 100644 index 000000000..f967745cc --- /dev/null +++ b/src/app/component/controller/WechatChannel.php @@ -0,0 +1,17 @@ +fetch("wechat_channel/design.html"); + } +} \ No newline at end of file diff --git a/src/app/component/view/wechat_channel/css/design.css b/src/app/component/view/wechat_channel/css/design.css new file mode 100644 index 000000000..654f3e318 --- /dev/null +++ b/src/app/component/view/wechat_channel/css/design.css @@ -0,0 +1,315 @@ +.wechat_channel-box .preview-draggable { + padding: 15px; +} + +.wechat_channel-box .video-list-wrap { + position: relative; +} + +.wechat_channel-box .video-list { + display: grid; + grid-template-columns: repeat(var(--row-count, 2), 1fr); + gap: 8px; + padding: 16px 16px 0px; +} + +.wechat_channel-box .video-item { + position: relative; + width: 100%; +} + +.wechat_channel-box .video-wrap { + position: relative; +} + +.wechat_channel-box .video-wrap .channel-preview { + position: relative; + width: 100%; + overflow: hidden; + border-radius: 5px; +} + +.wechat_channel-box .video-item .channel-preview img { + display: block; + width: 100%; + object-fit: cover; + border-radius: 5px; +} + +.wechat_channel-box .video-item .channel-preview { + position: relative; + width: 100%; + overflow: hidden; + border-radius: 5px; +} + +.wechat_channel-box .video-item .play-btn { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 40px; + height: 40px; + background: rgba(0, 0, 0, 0.6); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + z-index: 10; +} + +.wechat_channel-box .video-item .play-btn::before { + content: ''; + width: 0; + height: 0; + border-style: solid; + border-width: 10px 0 10px 16px; + border-color: transparent transparent transparent #fff; + margin-left: 2px; +} + +.wechat_channel-box .video-item .view-count { + position: absolute; + right: 2px; + font-size: 12px; + color: #fff; + padding: 4px 4px; + /* border-radius: 16px; */ + margin-bottom: 0; + z-index: 10; + text-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5); +} + +.wechat_channel-box .video-item .channel-info { + position: relative; + padding: 8px; + background: #fff; + border-radius: 0 0 8px 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + margin-top: -4px; +} + +.wechat_channel-box .video-item .channel-avatar { + display: none; +} + +.wechat_channel-box .video-item .channel-text { + flex: 1; + overflow: hidden; +} + +.wechat_channel-box .video-item .channel-name { + display: none; +} + +.wechat_channel-box .video-item .video-title { + font-size: 13px; + font-weight: 500; + color: #333; + overflow: hidden; + margin-bottom: 3px; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-box-orient: vertical; + word-break: break-all; + word-wrap: break-word; + white-space: normal; +} + +/* 1行标题 */ +.wechat_channel-box .video-item .video-title.title-max-lines-1 { + -webkit-line-clamp: 1; +} + +/* 2行标题 */ +.wechat_channel-box .video-item .video-title.title-max-lines-2 { + -webkit-line-clamp: 2; + margin-bottom: 4px; +} + +/* 3行标题 */ +.wechat_channel-box .video-item .video-title.title-max-lines-3 { + -webkit-line-clamp: 3; + margin-bottom: 4px; +} + +.wechat_channel-box .video-item .bottom-text { + font-size: 14px; + color: #666; + margin-top: 8px; + line-height: 1.4; + font-style: normal; +} + +.wechat_channel-box .video-item .video-placeholder { + height: 200px; + background: #f5f5f5; + display: flex; + align-items: center; + justify-content: center; + border: 1px dashed #ddd; + border-radius: 5px; +} + +.wechat_channel-box .video-item .placeholder-text { + color: #999; + font-size: 14px; +} + +/* 轮播样式 */ +.wechat_channel-box .video-carousel-wrap { + position: relative; + width: 100%; + overflow: hidden; +} + +.wechat_channel-box .video-carousel { + position: relative; + width: 100%; + overflow: hidden; +} + +.wechat_channel-box .carousel-item { + position: absolute; + top: 0; + left: 0; + width: 100%; + opacity: 0; + transition: opacity 0.5s ease-in-out; + z-index: 1; +} + +.wechat_channel-box .carousel-item.active { + position: relative; + opacity: 1; + z-index: 2; +} + +.wechat_channel-box .carousel-indicators { + position: relative; + margin-top: 8px; + margin-bottom: 8px; + margin-left: auto; + margin-right: auto; + width: fit-content; + display: flex; + gap: 8px; + z-index: 10; +} + +.wechat_channel-box .carousel-indicators .indicator { + width: 8px; + height: 8px; + border-radius: 50%; + background-color: rgba(255, 255, 255, 0.5); + cursor: pointer; + transition: background-color 0.3s ease; +} + +.wechat_channel-box .carousel-indicators .indicator.active { + background-color: #000000; + transform: scale(1.2); +} + +/* 轮播模式下的视频项样式 */ +.wechat_channel-box .video-carousel-wrap .video-item { + width: 100%; + max-width: 100%; +} + +/* 轮播模式下的通道预览样式 */ +.wechat_channel-box .video-carousel-wrap .channel-preview { + width: 100%; +} + +/* 16:9比例下的固定高度 */ +/* 一行显示1个 */ +.wechat_channel-box[data-ratio="16:9"] { + --image-height: 212px; +} +/* 一行显示2个 */ +.wechat_channel-box[data-ratio="16:9"][data-row-count="2"] { + --image-height: 104px; +} +/* 一行显示3个 */ +.wechat_channel-box[data-ratio="16:9"][data-row-count="3"] { + --image-height: 65px; +} +/* 一行显示4个 */ +.wechat_channel-box[data-ratio="16:9"][data-row-count="4"] { + --image-height: 47px; +} + +/* 3:4比例下的固定高度 */ +/* 一行显示1个 */ +.wechat_channel-box[data-ratio="3:4"] { + --image-height: 408px; +} +/* 一行显示2个 */ +.wechat_channel-box[data-ratio="3:4"][data-row-count="2"] { + --image-height: 200px; +} +/* 一行显示3个 */ +.wechat_channel-box[data-ratio="3:4"][data-row-count="3"] { + --image-height: 130px; +} +/* 一行显示4个 */ +.wechat_channel-box[data-ratio="3:4"][data-row-count="4"] { + --image-height: 96px; +} + +.wechat_channel-box .video-item .channel-preview img { + height: var(--image-height); +} + +.wechat_channel-box .video-item .view-count { + top: calc(var(--image-height) - 32px); +} + +.wechat_channel-box .edit-attribute .attr-wrap .restore-wrap .video-add-box .img-block { + width: 200px !important; + height: 125px !important; + margin-bottom: 30px; + margin-right: 0; + position: relative; +} + +.wechat_channel-box .edit-attribute .attr-wrap .restore-wrap .video-add-box .img-block>div { + line-height: 125px; + height: 125px !important; + width: 100%; + text-align: center; +} + +.wechat_channel-box .edit-attribute .attr-wrap .restore-wrap .video-add-box .img-block video { + width: 100% !important; + height: 125px !important; +} + +.wechat_channel-box .edit-attribute .attr-wrap .restore-wrap .video-add-box .img-block span { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.wechat_channel-box .video-zhezhao { + position: absolute; + background: #fff; + width: 61%; + height: 125px; + top: 1px; + right: 32px; + text-align: center; + line-height: 105px; + display: none; +} + +.wechat_channel-box .video-zhezhao span { + position: absolute; + top: 35px; + left: 80px; + color: #909399; +} + +/* .wechat_channel-box .layui-form-label + .layui-input-block {margin-left: 0 !important;} */ \ No newline at end of file diff --git a/src/app/component/view/wechat_channel/design.html b/src/app/component/view/wechat_channel/design.html new file mode 100644 index 000000000..68c8e001f --- /dev/null +++ b/src/app/component/view/wechat_channel/design.html @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app/component/view/wechat_channel/js/design.js b/src/app/component/view/wechat_channel/js/design.js new file mode 100644 index 000000000..7d3cc8832 --- /dev/null +++ b/src/app/component/view/wechat_channel/js/design.js @@ -0,0 +1,563 @@ +Vue.component("wechat_channel-edit", { + template: `
+
+

容器设置

+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ +
+

视频列表

+ + +
+
+
+ 拖拽排序 +
+
+

视频 {{ index + 1 }}

+ +
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+
+
+
+ +

点击上传

+
+
+ + x +
+
+
+ + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ +
+
+ + +
+ +
+
+
+
+ +

点击上传

+
+
+ + x +
+
+
推荐使用 200x200 像素的图片
+
+
+
+ + + +
+
`, + 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; // 等待忽略数组赋值后加载 + }, + mounted: function () { + console.log("wechat_channel-edit", this.data) + + // 初始化数据结构 + if (!this.data.list) { + this.data.list = []; + } + + if (!this.data.rowCount) { + this.data.rowCount = 2; + } + + if (!this.data.showStyle) { + this.data.showStyle = 'fixed'; + } + + if (!this.data.aspectRatio) { + this.data.aspectRatio = '16:9'; + } + + if (!this.data.titleLineClamp) { + this.data.titleLineClamp = 1; + } + + if (this.data.showPlayBtn === undefined) { + this.data.showPlayBtn = true; + } + + // 初始化轮播幻灯片索引 + if (this.data.currentSlide === undefined) { + this.data.currentSlide = 0; + } + + // 初始化分组列表 + this.updateGroupedList(); + + // 初始化列表项 + this.data.list.forEach((item, index) => { + if (!item.avatarImageType) { + item.avatarImageType = 'url'; + } else if (item.avatarUrl && item.avatarImageType == 'upload') { + var val = '头像'; + $("#avatarImg_" + index).html(val); + } + + if (!item.coverImageType) { + item.coverImageType = 'url'; + } else if (item.coverUrl && item.coverImageType == 'upload') { + var val = '封面'; + $("#coverImg_" + index).html(val); + } + + if (item.showViewCount === undefined) { + item.showViewCount = true; + } + }); + + layui.use(['form'], () => { + var form = layui.form; + form.render(); + + // 头像类型切换 + form.on('radio(avatarType)', (data) => { + const elem = data.elem; + const type = elem.value; + const index = elem.dataset.index; + + if (index !== undefined && this.data.list[index]) { + this.data.list[index].avatarImageType = type; + + this.$nextTick(() => { + if (type == 'upload' && this.data.list[index].avatarUrl) { + var val = '头像'; + $("#avatarImg_" + index).html(val); + } + }); + } + }); + + // 封面类型切换 + form.on('radio(coverImageType)', (data) => { + const elem = data.elem; + const type = elem.value; + const index = elem.dataset.index; + + if (index !== undefined && this.data.list[index]) { + this.data.list[index].coverImageType = type; + + this.$nextTick(() => { + if (type == 'upload' && this.data.list[index].coverUrl) { + var val = '封面'; + $("#coverImg_" + index).html(val); + } + }); + } + }); + + // 封面比例切换 + form.on('radio(aspectRatio)', (data) => { + const elem = data.elem; + const ratio = elem.value; + this.data.aspectRatio = ratio; + }); + + // 标题最多行数切换 + form.on('select(titleLineClamp)', (data) => { + const lines = parseInt(data.value); + this.data.titleLineClamp = lines; + }); + + // 每行显示数量切换 + form.on('select(rowCount)', (data) => { + const count = parseInt(data.value); + this.data.rowCount = count; + // 更新分组列表 + this.updateGroupedList(); + // 重新初始化轮播功能,确保根据新的rowCount重新分组 + this.initCarousel(); + }); + + // 显示风格切换 + form.on('select(showStyle)', (data) => { + const style = data.value; + this.data.showStyle = style; + // 更新分组列表 + this.updateGroupedList(); + // 重新初始化轮播功能 + this.initCarousel(); + }); + + // 显示播放按钮切换 + form.on('switch(showPlayBtn)', (data) => { + const elem = data.elem; + const checked = elem.checked; + this.data.showPlayBtn = checked; + }); + + // 显示观看次数切换 + form.on('switch', (data) => { + const elem = data.elem; + const checked = elem.checked; + // 查找对应的视频号索引 + const videoItem = elem.closest('.video-item-edit'); + if (videoItem) { + const index = videoItem.dataset.index; + if (index !== undefined && this.data.list[index]) { + this.data.list[index].showViewCount = checked; + this.$forceUpdate(); + } + } + }); + }); + + // 初始化拖拽排序 + this.initSortable(); + + // 初始化轮播自动切换 + this.initCarousel(); + }, + methods: { + verify: function () { + var res = { code: true, message: "" }; + // 微信视频号组件暂不需要强制验证 + return res; + }, + + // 上传封面图片 + uploadCover: function (index) { + + // 从媒体库中选择 + openAlbum((data) => { + const imgUrl = data[0].pic_path; + var val = '封面'; + $("#coverImg_" + index).html(val); + + if (this.data.list[index]) { + this.data.list[index].coverUrl = imgUrl; + } + }, 1); + }, + + // 上传头像图片 + uploadAvatar: function (index) { + + // 从媒体库中选择 + openAlbum((data) => { + const imgUrl = data[0].pic_path; + var val = '头像'; + $("#avatarImg_" + index).html(val); + + if (this.data.list[index]) { + this.data.list[index].avatarUrl = imgUrl; + } + }, 1); + }, + + // 添加视频号 + addVideoItem: function () { + this.data.list.push({ + "channelType": "wechat", + "channelName": "", + "finderUserName": "", + "avatarImageType": "url", + "avatarUrl": "", + "videoTitle": "", + "coverImageType": "url", + "coverUrl": "", + "feedId": "", + "feedToken": "", + "viewCount": 0, + "showViewCount": true, + "embedMode": false + }); + this.$forceUpdate(); + this.$parent.$forceUpdate(); + + // 重新渲染表单并绑定事件 + this.$nextTick(() => { + layui.use(['form'], () => { + var form = layui.form; + form.render(); + + // 重新绑定头像类型切换事件 + form.on('radio(avatarType)', (data) => { + const elem = data.elem; + const type = elem.value; + const index = elem.dataset.index; + + if (index !== undefined && this.data.list[index]) { + this.data.list[index].avatarImageType = type; + this.$forceUpdate(); + + this.$nextTick(() => { + if (type == 'upload' && this.data.list[index].avatarUrl) { + var val = '头像'; + $("#avatarImg_" + index).html(val); + } + }); + } + }); + + // 重新绑定封面类型切换事件 + form.on('radio(coverImageType)', (data) => { + const elem = data.elem; + const type = elem.value; + const index = elem.dataset.index; + + if (index !== undefined && this.data.list[index]) { + this.data.list[index].coverImageType = type; + this.$forceUpdate(); + + this.$nextTick(() => { + if (type == 'upload' && this.data.list[index].coverUrl) { + var val = '封面'; + $("#coverImg_" + index).html(val); + } + }); + } + }); + }); + + // 重新初始化拖拽排序 + this.initSortable(); + }); + }, + + // 删除视频号 + removeVideoItem: function (index) { + this.data.list.splice(index, 1); + this.$forceUpdate(); + this.$parent.$forceUpdate(); + + // 重新初始化拖拽排序 + this.$nextTick(() => { + this.initSortable(); + }); + }, + + // 初始化拖拽排序 + initSortable: function () { + // 检查Sortable库是否已加载 + if (typeof Sortable !== 'undefined') { + const videoList = document.getElementById('videoListEdit'); + if (videoList) { + // 销毁现有实例 + if (this.sortableInstance) { + this.sortableInstance.destroy(); + } + + // 创建新的Sortable实例 + this.sortableInstance = new Sortable(videoList, { + handle: '.drag-handle', + animation: 150, + onEnd: (evt) => { + // 获取拖拽前后的索引 + const oldIndex = evt.oldIndex; + const newIndex = evt.newIndex; + + // 重新排序数组 + if (oldIndex !== newIndex) { + const [movedItem] = this.data.list.splice(oldIndex, 1); + this.data.list.splice(newIndex, 0, movedItem); + + // 强制更新视图 + this.$forceUpdate(); + this.$parent.$forceUpdate(); + + // 重新渲染表单 + layui.use(['form'], () => { + var form = layui.form; + form.render(); + }); + } + } + }); + } + } else { + // 如果Sortable库未加载,尝试动态加载 + const script = document.createElement('script'); + script.src = 'https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.0/Sortable.min.js'; + script.onload = () => { + this.initSortable(); + }; + document.head.appendChild(script); + } + }, + + // 更新分组列表 + updateGroupedList: function () { + const list = this.data.list || []; + const rowCount = this.data.rowCount || 2; + const groups = []; + + for (let i = 0; i < list.length; i += rowCount) { + groups.push(list.slice(i, i + rowCount)); + } + + this.data.groupedList = groups; + console.log("groupedList", this.data.groupedList); + }, + + // 初始化轮播自动切换 + initCarousel: function () { + // 清除现有的轮播定时器 + if (this.carouselTimer) { + clearInterval(this.carouselTimer); + } + + // 更新分组列表 + this.updateGroupedList(); + + // 只有当显示风格为carousel且有多个分组时才启动轮播 + if (this.data.showStyle === 'carousel' && this.data.groupedList && this.data.groupedList.length > 1) { + this.carouselTimer = setInterval(() => { + this.data.currentSlide = (this.data.currentSlide + 1) % this.data.groupedList.length; + }, 3000); // 每3秒切换一次 + } + } + }, +}); \ No newline at end of file diff --git a/src/app/shop/view/diy/heat_map.html b/src/app/shop/view/diy/heat_map.html index 70e1bdbac..5499d954b 100644 --- a/src/app/shop/view/diy/heat_map.html +++ b/src/app/shop/view/diy/heat_map.html @@ -105,6 +105,10 @@ text-align: right; } + .heat-map-wrap .manage-wrap .list-wrap .item div { + + } + .heat-map-wrap .manage-wrap .list-wrap .item div span { cursor: pointer; } @@ -115,6 +119,8 @@ } + +
@@ -124,6 +130,7 @@
+ {include file="diy/iconfont_component"/} diff --git a/src/app/shop/view/diy/icon_style.html b/src/app/shop/view/diy/icon_style.html index be43b3a4f..22599245e 100644 --- a/src/app/shop/view/diy/icon_style.html +++ b/src/app/shop/view/diy/icon_style.html @@ -1,3 +1,6 @@ + + + + +
@@ -163,6 +168,8 @@
+ + {include file="diy/iconfont_component"/} diff --git a/src/app/shop/view/diy/iconfont_component.html b/src/app/shop/view/diy/iconfont_component.html index 6dc24d7cd..3c7adc6ce 100644 --- a/src/app/shop/view/diy/iconfont_component.html +++ b/src/app/shop/view/diy/iconfont_component.html @@ -65,7 +65,7 @@ }, iconStyle(){ if (!this.value) return {}; - + // console.log(this.value) var style = { fontSize: this.value.fontSize + '%' } diff --git a/src/public/static/js/Sortable.min.js b/src/public/static/js/Sortable.min.js new file mode 100644 index 000000000..17bb16c73 --- /dev/null +++ b/src/public/static/js/Sortable.min.js @@ -0,0 +1,2 @@ +/*! Sortable 1.15.0 - MIT | git://github.com/SortableJS/Sortable.git */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sortable=e()}(this,function(){"use strict";function e(e,t){var n,o=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),o.push.apply(o,n)),o}function M(o){for(var t=1;tt.length)&&(e=t.length);for(var n=0,o=new Array(e);n"===e[0]&&(e=e.substring(1)),t))try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return}}function N(t,e,n,o){if(t){n=n||document;do{if(null!=e&&(">"!==e[0]||t.parentNode===n)&&p(t,e)||o&&t===n)return t}while(t!==n&&(t=(i=t).host&&i!==document&&i.host.nodeType?i.host:i.parentNode))}var i;return null}var g,m=/\s+/g;function I(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(m," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(m," ")))}function P(t,e,n){var o=t&&t.style;if(o){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];o[e=!(e in o||-1!==e.indexOf("webkit"))?"-webkit-"+e:e]=n+("string"==typeof n?"":"px")}}function v(t,e){var n="";if("string"==typeof t)n=t;else do{var o=P(t,"transform")}while(o&&"none"!==o&&(n=o+" "+n),!e&&(t=t.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function b(t,e,n){if(t){var o=t.getElementsByTagName(e),i=0,r=o.length;if(n)for(;i=n.left-e&&i<=n.right+e,e=r>=n.top-e&&r<=n.bottom+e;return o&&e?a=t:void 0}}),a);if(e){var n,o={};for(n in t)t.hasOwnProperty(n)&&(o[n]=t[n]);o.target=o.rootEl=e,o.preventDefault=void 0,o.stopPropagation=void 0,e[j]._onDragOver(o)}}var i,r,a}function Yt(t){q&&q.parentNode[j]._isOutsideThisEl(t.target)}function Bt(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.el=t,this.options=e=a({},e),t[j]=this;var n,o,i={group:null,sort:!0,disabled:!1,store:null,handle:null,draggable:/^[uo]l$/i.test(t.nodeName)?">li":">*",swapThreshold:1,invertSwap:!1,invertedSwapThreshold:null,removeCloneOnHide:!0,direction:function(){return It(t,this.options)},ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,easing:null,setData:function(t,e){t.setData("Text",e.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,delayOnTouchOnly:!1,touchStartThreshold:(Number.parseInt?Number:window).parseInt(window.devicePixelRatio,10)||1,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:!1!==Bt.supportPointer&&"PointerEvent"in window&&!u,emptyInsertThreshold:5};for(n in K.initializePlugins(this,t,i),i)n in e||(e[n]=i[n]);for(o in Pt(e),this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));this.nativeDraggable=!e.forceFallback&&Mt,this.nativeDraggable&&(this.options.touchStartThreshold=1),e.supportPointer?h(t,"pointerdown",this._onTapStart):(h(t,"mousedown",this._onTapStart),h(t,"touchstart",this._onTapStart)),this.nativeDraggable&&(h(t,"dragover",this),h(t,"dragenter",this)),Et.push(this.el),e.store&&e.store.get&&this.sort(e.store.get(this)||[]),a(this,x())}function Ft(t,e,n,o,i,r,a,l){var s,c,u=t[j],d=u.options.onMove;return!window.CustomEvent||y||w?(s=document.createEvent("Event")).initEvent("move",!0,!0):s=new CustomEvent("move",{bubbles:!0,cancelable:!0}),s.to=e,s.from=t,s.dragged=n,s.draggedRect=o,s.related=i||e,s.relatedRect=r||k(e),s.willInsertAfter=l,s.originalEvent=a,t.dispatchEvent(s),c=d?d.call(u,s,a):c}function jt(t){t.draggable=!1}function Ht(){Ct=!1}function Lt(t){return setTimeout(t,0)}function Kt(t){return clearTimeout(t)}Bt.prototype={constructor:Bt,_isOutsideThisEl:function(t){this.el.contains(t)||t===this.el||(gt=null)},_getDirection:function(t,e){return"function"==typeof this.options.direction?this.options.direction.call(this,t,e,q):this.options.direction},_onTapStart:function(e){if(e.cancelable){var n=this,o=this.el,t=this.options,i=t.preventOnFilter,r=e.type,a=e.touches&&e.touches[0]||e.pointerType&&"touch"===e.pointerType&&e,l=(a||e).target,s=e.target.shadowRoot&&(e.path&&e.path[0]||e.composedPath&&e.composedPath()[0])||l,c=t.filter;if(!function(t){Tt.length=0;var e=t.getElementsByTagName("input"),n=e.length;for(;n--;){var o=e[n];o.checked&&Tt.push(o)}}(o),!q&&!(/mousedown|pointerdown/.test(r)&&0!==e.button||t.disabled)&&!s.isContentEditable&&(this.nativeDraggable||!u||!l||"SELECT"!==l.tagName.toUpperCase())&&!((l=N(l,t.draggable,o,!1))&&l.animated||J===l)){if(nt=B(l),it=B(l,t.draggable),"function"==typeof c){if(c.call(this,e,l,this))return U({sortable:n,rootEl:s,name:"filter",targetEl:l,toEl:o,fromEl:o}),z("filter",n,{evt:e}),void(i&&e.cancelable&&e.preventDefault())}else if(c=c&&c.split(",").some(function(t){if(t=N(s,t.trim(),o,!1))return U({sortable:n,rootEl:t,name:"filter",targetEl:l,fromEl:o,toEl:o}),z("filter",n,{evt:e}),!0}))return void(i&&e.cancelable&&e.preventDefault());t.handle&&!N(s,t.handle,o,!1)||this._prepareDragStart(e,a,l)}}},_prepareDragStart:function(t,e,n){var o,i=this,r=i.el,a=i.options,l=r.ownerDocument;n&&!q&&n.parentNode===r&&(o=k(n),$=r,V=(q=n).parentNode,Q=q.nextSibling,J=n,at=a.group,st={target:Bt.dragged=q,clientX:(e||t).clientX,clientY:(e||t).clientY},ht=st.clientX-o.left,ft=st.clientY-o.top,this._lastX=(e||t).clientX,this._lastY=(e||t).clientY,q.style["will-change"]="all",o=function(){z("delayEnded",i,{evt:t}),Bt.eventCanceled?i._onDrop():(i._disableDelayedDragEvents(),!s&&i.nativeDraggable&&(q.draggable=!0),i._triggerDragStart(t,e),U({sortable:i,name:"choose",originalEvent:t}),I(q,a.chosenClass,!0))},a.ignore.split(",").forEach(function(t){b(q,t.trim(),jt)}),h(l,"dragover",Xt),h(l,"mousemove",Xt),h(l,"touchmove",Xt),h(l,"mouseup",i._onDrop),h(l,"touchend",i._onDrop),h(l,"touchcancel",i._onDrop),s&&this.nativeDraggable&&(this.options.touchStartThreshold=4,q.draggable=!0),z("delayStart",this,{evt:t}),!a.delay||a.delayOnTouchOnly&&!e||this.nativeDraggable&&(w||y)?o():Bt.eventCanceled?this._onDrop():(h(l,"mouseup",i._disableDelayedDrag),h(l,"touchend",i._disableDelayedDrag),h(l,"touchcancel",i._disableDelayedDrag),h(l,"mousemove",i._delayedDragTouchMoveHandler),h(l,"touchmove",i._delayedDragTouchMoveHandler),a.supportPointer&&h(l,"pointermove",i._delayedDragTouchMoveHandler),i._dragStartTimer=setTimeout(o,a.delay)))},_delayedDragTouchMoveHandler:function(t){t=t.touches?t.touches[0]:t;Math.max(Math.abs(t.clientX-this._lastX),Math.abs(t.clientY-this._lastY))>=Math.floor(this.options.touchStartThreshold/(this.nativeDraggable&&window.devicePixelRatio||1))&&this._disableDelayedDrag()},_disableDelayedDrag:function(){q&&jt(q),clearTimeout(this._dragStartTimer),this._disableDelayedDragEvents()},_disableDelayedDragEvents:function(){var t=this.el.ownerDocument;f(t,"mouseup",this._disableDelayedDrag),f(t,"touchend",this._disableDelayedDrag),f(t,"touchcancel",this._disableDelayedDrag),f(t,"mousemove",this._delayedDragTouchMoveHandler),f(t,"touchmove",this._delayedDragTouchMoveHandler),f(t,"pointermove",this._delayedDragTouchMoveHandler)},_triggerDragStart:function(t,e){e=e||"touch"==t.pointerType&&t,!this.nativeDraggable||e?this.options.supportPointer?h(document,"pointermove",this._onTouchMove):h(document,e?"touchmove":"mousemove",this._onTouchMove):(h(q,"dragend",this),h($,"dragstart",this._onDragStart));try{document.selection?Lt(function(){document.selection.empty()}):window.getSelection().removeAllRanges()}catch(t){}},_dragStarted:function(t,e){var n;yt=!1,$&&q?(z("dragStarted",this,{evt:e}),this.nativeDraggable&&h(document,"dragover",Yt),n=this.options,t||I(q,n.dragClass,!1),I(q,n.ghostClass,!0),Bt.active=this,t&&this._appendGhost(),U({sortable:this,name:"start",originalEvent:e})):this._nulling()},_emulateDragOver:function(){if(ct){this._lastX=ct.clientX,this._lastY=ct.clientY,kt();for(var t=document.elementFromPoint(ct.clientX,ct.clientY),e=t;t&&t.shadowRoot&&(t=t.shadowRoot.elementFromPoint(ct.clientX,ct.clientY))!==e;)e=t;if(q.parentNode[j]._isOutsideThisEl(t),e)do{if(e[j])if(e[j]._onDragOver({clientX:ct.clientX,clientY:ct.clientY,target:t,rootEl:e})&&!this.options.dragoverBubble)break}while(e=(t=e).parentNode);Rt()}},_onTouchMove:function(t){if(st){var e=this.options,n=e.fallbackTolerance,o=e.fallbackOffset,i=t.touches?t.touches[0]:t,r=Z&&v(Z,!0),a=Z&&r&&r.a,l=Z&&r&&r.d,e=Ot&&bt&&E(bt),a=(i.clientX-st.clientX+o.x)/(a||1)+(e?e[0]-_t[0]:0)/(a||1),l=(i.clientY-st.clientY+o.y)/(l||1)+(e?e[1]-_t[1]:0)/(l||1);if(!Bt.active&&!yt){if(n&&Math.max(Math.abs(i.clientX-this._lastX),Math.abs(i.clientY-this._lastY))n.right+10||t.clientX<=n.right&&t.clientY>n.bottom&&t.clientX>=n.left:t.clientX>n.right&&t.clientY>n.top||t.clientX<=n.right&&t.clientY>n.bottom+10}(n,r,this)&&!g.animated){if(g===q)return O(!1);if((l=g&&a===n.target?g:l)&&(w=k(l)),!1!==Ft($,a,q,o,l,w,n,!!l))return x(),g&&g.nextSibling?a.insertBefore(q,g.nextSibling):a.appendChild(q),V=a,A(),O(!0)}else if(g&&function(t,e,n){n=k(X(n.el,0,n.options,!0));return e?t.clientX