源文件
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.DS_Store
|
||||
.hbuilderx
|
||||
*.log
|
||||
unpackage
|
||||
sitemap.json
|
||||
.prettierrc.cjs
|
||||
pages/diy/init_data.js
|
||||
2
.vscode/settings.json
vendored
Normal file
2
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 ShopXO免费开源商城 - uniapp手机端
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
68
README.md
Normal file
68
README.md
Normal file
@@ -0,0 +1,68 @@
|
||||
<p align="center">
|
||||
<img src="https://shopxoserver.oss-cn-beijing.aliyuncs.com/demo/system/logo.jpg" width="360" />
|
||||
</p>
|
||||
|
||||
<h3 align="center">ShopXO企业级免费开源电商系统 - uniapp手机端</h3>
|
||||
|
||||
<div align="center">
|
||||
|
||||
```shell
|
||||
如果对您有帮助,您可以点右上角 “Star” 收藏一下 ,获取第一时间更新,谢谢!
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### 项目介绍
|
||||
* 后端支持依托于ShopXO免费开源电商系统开发的uniapp端主题源码
|
||||
* 支持可视化DIY拖拽装修,内置几十种标准组件,热区、魔方、自定义等等...
|
||||
* 默认内置8中搭配主色(可自行扩展更多配色)、自由快捷切换适应各大行业需求
|
||||
* 已支持小程序(微信、QQ、百度、支付宝、头条&抖音、快手)+ H5 + APP
|
||||
|
||||
#### 使用教程
|
||||
`程序打包操作需要有一定的编程技术基础、如需帮助请到git平台提issues寻求帮助`
|
||||
* 打包教程 [https://doc.shopxo.net/article/1/293727233598554112.html](https://doc.shopxo.net/article/1/293727233598554112.html)
|
||||
|
||||
1. 先安装ShopXO免费开源系统 [http://install.shopxo.net/](http://install.shopxo.net/)
|
||||
2. 将该源码导入HBuilderX开发工具、顶部工具栏 `运行->运行到小程序模拟器->(根据支持平台自行选择、如 微信开发者工具)`
|
||||
3. App.vue中修改 request_url 和 static_url 地址为自己的商城地址即可使用
|
||||
4. 主题默认为红色(red),如更改主题 App.vue文件中修改 default_theme 默认主题标识,也可以到商店搜索【默认主题样式】远程控制主题配色
|
||||
5. 发布、HBuilderX开发工具、顶部工具栏 `发行->(根据支持平台自行选择、如 微信开发者工具)`
|
||||
|
||||
#### 官方QQ群、答案`shopxo.net`
|
||||
* 官方uniapp群:679303149
|
||||
|
||||
#### 体验码
|
||||

|
||||
|
||||
|
||||
#### 当前项目源代码平台
|
||||
* Gitee:[https://gitee.com/zongzhige/shopxo-uniapp](https://gitee.com/zongzhige/shopxo-uniapp)
|
||||
* GitHub:[https://github.com/gongfuxiang/shopxo-uniapp](https://github.com/gongfuxiang/shopxo-uniapp)
|
||||
* Coding:[https://zongzhige.coding.net/public/shopxo/uniapp/git](https://zongzhige.coding.net/public/shopxo/uniapp/git)
|
||||
* GitCode:[https://gitcode.net/zongzhige/shopxo-uniapp](https://gitcode.net/zongzhige/shopxo-uniapp)
|
||||
* uni-app:[https://ext.dcloud.net.cn/plugin?id=6380](https://ext.dcloud.net.cn/plugin?id=6380)
|
||||
|
||||
#### ShopXO后端源代码平台
|
||||
* Gitee:[https://gitee.com/zongzhige/shopxo](https://gitee.com/zongzhige/shopxo)
|
||||
* GitHub:[https://github.com/gongfuxiang/shopxo](https://github.com/gongfuxiang/shopxo)
|
||||
* Coding:[https://zongzhige.coding.net/public/shopxo/shopxo/git](https://zongzhige.coding.net/public/shopxo/shopxo/git)
|
||||
* GitCode:[https://gitcode.net/zongzhige/shopxo](https://gitcode.net/zongzhige/shopxo)
|
||||
|
||||
#### DIY装修源代码平台
|
||||
* Gitee:[https://gitee.com/zongzhige/shopxo-diy](https://gitee.com/zongzhige/shopxo-diy)
|
||||
* GitHub:[https://github.com/gongfuxiang/shopxo-diy](https://github.com/gongfuxiang/shopxo-diy)
|
||||
* GitCode:[https://gitcode.net/zongzhige/shopxo-diy](https://gitcode.net/zongzhige/shopxo-diy)
|
||||
|
||||
#### API接口文档
|
||||
* [https://doc.shopxo.net/article/2.html](https://doc.shopxo.net/article/2.html)
|
||||
|
||||
#### 小程序支持多种配色
|
||||

|
||||
|
||||
#### 小程序效果图片
|
||||

|
||||
|
||||
#### 小程序DIY装修
|
||||

|
||||
35
androidPrivacy.json
Normal file
35
androidPrivacy.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"version" : "1",
|
||||
"prompt" : "template",
|
||||
"title" : "服务协议和隐私政策",
|
||||
"message" : " 请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/> 你可阅读<a href=\"https://d1.shopxo.vip/?s=agreement/index/document/userregister/is_content/1.html\">《服务协议》</a>和<a href=\"https://d1.shopxo.vip/?s=agreement/index/document/userprivacy/is_content/1.html\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
|
||||
"buttonAccept" : "同意并接受",
|
||||
"buttonRefuse" : "暂不同意",
|
||||
"hrefLoader" : "system|default",
|
||||
"backToExit" : "false",
|
||||
"second" : {
|
||||
"title" : "确认提示",
|
||||
"message" : " 进入应用前,你需先同意<a href=\"https://d1.shopxo.vip/?s=agreement/index/document/userregister/is_content/1.html\">《服务协议》</a>和<a href=\"https://d1.shopxo.vip/?s=agreement/index/document/userprivacy/is_content/1.html\">《隐私政策》</a>,否则将退出应用。",
|
||||
"buttonAccept" : "同意并继续",
|
||||
"buttonRefuse" : "退出应用"
|
||||
},
|
||||
"disagreeMode" : {
|
||||
"support" : false,
|
||||
"loadNativePlugins" : false,
|
||||
"visitorEntry" : false,
|
||||
"showAlways" : true
|
||||
},
|
||||
"styles" : {
|
||||
"backgroundColor" : "#fff",
|
||||
"borderRadius" : "6px",
|
||||
"title" : {
|
||||
"color" : "#333"
|
||||
},
|
||||
"buttonAccept" : {
|
||||
"color" : "#52C41A"
|
||||
},
|
||||
"buttonRefuse" : {
|
||||
"color" : "#f02720"
|
||||
}
|
||||
}
|
||||
}
|
||||
423
changelog.md
Normal file
423
changelog.md
Normal file
@@ -0,0 +1,423 @@
|
||||
## v6.5.0(2025-03-05)
|
||||
1. DIY新增数据选项卡、自定义增强优化
|
||||
2. DIY浮动导航支持快捷导航
|
||||
3. 订单单号支持复制
|
||||
4. 在线客服企业微信客服适配h5处理
|
||||
5. 多商户首页支持分类筛选
|
||||
6. 商品、文章、活动配置、组合搭配、博客、门店、多商户支持分享图片
|
||||
7. 商品详情购买按钮增加链接和复制事件
|
||||
8. 门店类型选择优化
|
||||
9. 支持同城模式
|
||||
10. 新增问诊开方支持购物车
|
||||
11. 优惠券新增详情
|
||||
|
||||
|
||||
## v6.4.0(2024-12-25)
|
||||
1. 支付宝小程序兼容性优化
|
||||
2. DIY支持新特性和细节优化
|
||||
3. 问答支持富文本
|
||||
4. 博客详情无数据错误修复
|
||||
5. 门店支持最近选择、地图搜索选择、当前门店切换、支持强制选择门店
|
||||
6. 开票支持钱包充值
|
||||
7. 用户中心菜单支持未登录展示
|
||||
8. 基础信息填写支持授权即提示、并支持手机号码一键绑定
|
||||
9. 支付组件优化
|
||||
10. 系统扫码默认走商品搜索,门店详情扫码无效修复
|
||||
11. 积分商城首页优化
|
||||
12. 下单支持填写联系人、联系电话、配送时间
|
||||
13. 新增微信小程序收货组件确认
|
||||
14. 订单支持订单资源插件
|
||||
15. 扫码登录地址解析错误优化
|
||||
16. 底部菜单判断优化
|
||||
17. app评分优化
|
||||
|
||||
|
||||
## v6.3.0(2024-10-22)
|
||||
1. 新增DIY装修,可以自由设计模板
|
||||
2. 底部菜单后台DIY管理、并保留原生
|
||||
3. 商品足迹,增加收藏支持加入购物车
|
||||
4. 商品评论优化
|
||||
5. 初始化配置优化
|
||||
6. 扫码细节优化,适配h5
|
||||
7. 多商户支持二级分类、头部分离优化
|
||||
8. 全站走大圆角风格
|
||||
9. 新增公共commom组件、支持onshow事件
|
||||
10. 微信隐私提示、app管理、用户基础使用提到公共层
|
||||
11. 定位独立为组件
|
||||
12. 新增系统扫码统一接口
|
||||
13. 新增协议
|
||||
14. 新增送礼插件
|
||||
15. 商品详情导航优化
|
||||
16. 支付优化
|
||||
17. 充值支付方式未选中修复
|
||||
18. 文章,门店优化
|
||||
19. 多商户和门店新增核销
|
||||
20. 礼品卡卡密数据展示优化,新增扫码兑换
|
||||
21. 多语言优化
|
||||
22. 优惠券细节优化
|
||||
|
||||
|
||||
|
||||
## v6.2.0.5(2024-07-11)
|
||||
1. 门店基础模式优化支持(基础、商品、基础+商品)
|
||||
2. 文章增加封面支持
|
||||
|
||||
|
||||
|
||||
## v6.2.0.4(2024-07-10)
|
||||
1. 商品详情更多门店追踪商品
|
||||
|
||||
|
||||
|
||||
## v6.2.0.3(2024-07-09)
|
||||
1. 多商户和门店新增核销
|
||||
|
||||
|
||||
|
||||
## v6.2.0.2(2024-07-06)
|
||||
1. 礼品卡卡密数据展示优化
|
||||
2. 礼品卡新增扫码兑换
|
||||
|
||||
|
||||
|
||||
## v6.2.0.1(2024-07-05)
|
||||
1. 修复安卓app下多语言切换无效问题
|
||||
|
||||
|
||||
|
||||
## v6.2.0(2024-07-04)
|
||||
1. 新增礼品卡
|
||||
2. 搜索需要登录优化
|
||||
3. 登录input优化
|
||||
4. 支持多语言
|
||||
5. 增加企业微信客服支持
|
||||
6. 增加app版本更新
|
||||
7. 增加app评分提示
|
||||
8. 增加关于我们页面
|
||||
9. 钱包提现增加手续费
|
||||
10. 首页商品魔方白色模式错误修复
|
||||
11. 基础模式支持商品展示
|
||||
12. 店铺简介改为富文本编辑器
|
||||
13. 商品规格只有一级初始化优化
|
||||
14. 购物车页面底部导航高度优化
|
||||
15. 支持防伪码扫码
|
||||
16. 批量下单商品规格图片支持放大查看
|
||||
17. 新增骨架屏
|
||||
18. 页面加载层优化
|
||||
19. 排序和导航搜索展示加载
|
||||
20. 订单售后页面客服优化
|
||||
21. 订单开票加载错误修复
|
||||
22. 新增获取用户当前位置
|
||||
23. 订单售后详情入口地址错误修复
|
||||
24. 其他细节优化
|
||||
25. 门店和多商户客服展示优化
|
||||
26. 门店新增基础模式
|
||||
27. 首页中间广告展示优化
|
||||
28. 独立购物车页面左上角返回按钮颜色错误修复
|
||||
29. 订单和门店订单快递信息未正常展示修复
|
||||
30. 钱包优化字段错误修复
|
||||
31. 商品详情问答优化展示错误修复,及首页加载优化
|
||||
32. 购物车滑动删除收藏数据类型错误修复
|
||||
33. 设置页面未登录也可以进入
|
||||
34. app新增打开权限控制管理
|
||||
|
||||
|
||||
|
||||
## v6.1.0(2024-04-25)
|
||||
1. 秒杀首页无数据报错修复
|
||||
2. 商品页面批发展示优化
|
||||
3. 积分商城首页优
|
||||
4. 多商户和多门店客服样式优化
|
||||
5. 多商户领券和组合搭配优化
|
||||
6. 门店下单优化
|
||||
7. 商品页面门店模式下底部操作按钮新增加载
|
||||
8. 加载层logo默认读取后台配置
|
||||
9. 优化支付宝小程序自定义页面标题
|
||||
10. 第三方账户绑定去掉小程序入口
|
||||
11. 魔方新增更多样式
|
||||
12. 底部名称直接读取站点名称
|
||||
13. 商品、博文轮播图片模式优化
|
||||
14. 商品页批发属性未定义错误修复
|
||||
15. 虚拟币页面加载细节优化
|
||||
|
||||
|
||||
|
||||
## v6.0.0(2024-04-15)
|
||||
1. 地址导入错误修复
|
||||
2. 商品支持指定规格选中
|
||||
3. 支付app优化,首页标题优化
|
||||
4. 商品规格点击支持展示模式
|
||||
5. 积分商城扫码领取积分
|
||||
6. 购物车顶部导航优化,适配支付宝小程序
|
||||
7. 选择系统地址优化
|
||||
8. 购物车,分类优化
|
||||
9. 物流查询支持多包裹
|
||||
10. 下单运费支持多运费选择
|
||||
11. 商品是否展示和符号及单位适配
|
||||
12. 多语言切换优化
|
||||
13. 首页汇率切换模仿价格不改变原因修复
|
||||
14. paypal支付支持
|
||||
15. 无网络提示优化
|
||||
16. 博客上传图片错误,首页顶部背景色,分享地址优化
|
||||
17. 组件优化公共和局部组件
|
||||
18. 增加虚拟币插件(可转账、转换、充值、提现、支付)
|
||||
19. 登录和手机绑定优化
|
||||
20. 支持密码修改
|
||||
21. 支持绑定邮箱
|
||||
22. 支持绑定第三方登录(微信、qq、支付宝)
|
||||
23. 修复店铺布局错乱问题
|
||||
24. 分包预加载优化
|
||||
25. 打开商品速度优化
|
||||
26. 首页打开速度优化
|
||||
27. 购物车支持优惠明细查看
|
||||
28. 地址一键导入错误修复
|
||||
29. 多语言兼容头条/抖音小程序
|
||||
30. pages支持多语言切换
|
||||
31. 商品支持指定规格选中
|
||||
|
||||
|
||||
|
||||
## v5.0.0(2024-01-19)
|
||||
1. 支持APP(IOS+Android)
|
||||
2. 支持多语言(中文、繁体、英文、西班牙)
|
||||
3. 购物车支持优惠预计算展示
|
||||
4. 购物车支持门店购物车双向切换
|
||||
5. 商品页支持门店购物车展示
|
||||
6. 门店详情支持默认下单类型选择提示
|
||||
7. 支持博文发布
|
||||
8. 新增商品评论
|
||||
9. 支持订单商品表单
|
||||
10. 新增下单备注预选择
|
||||
11. 汇率切换支持图标
|
||||
12. 订单再次购买支持回购和加购物车选择
|
||||
13. APP登录支持(微信、QQ、苹果、谷歌、本机手机)
|
||||
14. 商品分类页面带排序
|
||||
15. 订单仅之前的支付方式可支付
|
||||
16. 下单积分自定义
|
||||
17. 首页支持地理位置选择
|
||||
18. h5下首页搜搜框宽度错位优化
|
||||
19. 地址复制错别字优化
|
||||
20. 问答分享地址优化
|
||||
21. 钱包充值页面空修复,问答评论优化
|
||||
22. 博客评价开关优化
|
||||
23. 用户中心样式优化
|
||||
24. 分类页面H5优化
|
||||
25. 兼容支付宝小程序样式
|
||||
|
||||
|
||||
|
||||
## v4.0.0(2023-11-10)
|
||||
1. 手机端全新UI、极致体验优化
|
||||
2. 首页轮播支持背景色自动切换
|
||||
3. 分配页面支持全部分配查看
|
||||
4. 钱包支持转账
|
||||
5. 新增扫码登录及付款
|
||||
6. 新增商品魔方
|
||||
7. 购物车新增商品展示
|
||||
8. 问答支持评论和点赞
|
||||
9. 客服和快捷导航优化
|
||||
10. 商品详情分享和收藏优化
|
||||
|
||||
|
||||
## v3.0.3(2023-09-18)
|
||||
1. 组合搭配支持展示商品
|
||||
2. 商品列表去除封面错误提示
|
||||
|
||||
|
||||
## v3.0.2(2023-09-11)
|
||||
1. 用户基础信息填写,昵称判断有误修复
|
||||
2. 订单售后退货地址错误修复
|
||||
3. 新增微信小程序隐私弹窗说明
|
||||
|
||||
|
||||
## v3.0.1(2023-09-03)
|
||||
1. 用户基础信息web端错误修复
|
||||
2. 关闭按钮多端兼容性处理
|
||||
3. 下单页面积分使用提示优化
|
||||
|
||||
|
||||
## v3.0.0(2023-08-28)
|
||||
1. 新增微信小程序可以提示完善头像及昵称
|
||||
2. ipad模型下uniapp顶部错位
|
||||
3. 分销支持订单信息插件及数据统计GMV维度、我的团队新增搜索条件
|
||||
4. 秒杀适配v3.0新版本
|
||||
5. 购物车列表默认选中
|
||||
6. 购物车抛物线优化、搜索页面新增页面搜索框,分类页面支持搜索进入独立页面
|
||||
7. 组合搭配支持首页展示和组建封装
|
||||
8. 数据列表读取避免重复请求
|
||||
9. 分类页面支持标签展示
|
||||
10. 多商户支持评分、资质查看
|
||||
11. 开票默认值优化
|
||||
12. form表单支付错误处理
|
||||
13. 购物车无效商品支持选择删除
|
||||
14. 快捷加购错误修复
|
||||
15. 批量下单数量更新价格错误修复
|
||||
16. 单页打开领取优惠券提示
|
||||
17. 分包优化
|
||||
|
||||
|
||||
## v2.3.3(2023-04-10)
|
||||
* 商品列表使用统一组件
|
||||
* 商品参数新增弹窗展示
|
||||
* 初始访问登录页面优化
|
||||
* 公共url打开支持地图、电话、外部小程序协议方式
|
||||
* 适配手机底部横线
|
||||
* 轮播兼容iphone圆角失效问题
|
||||
* 用户中心菜单支持列表展示样式
|
||||
* 搜索页面支持九方格和列表展示样式
|
||||
* 分类支持参数指定跳转
|
||||
* icon导航图标支持纯图片
|
||||
* 分类和门店详情适配规格起购数及限购数
|
||||
* 起购数和限购数提升 到商品规格级别
|
||||
* 地址新增编号快速搜索选择
|
||||
* 订单售后页面新增客服展示
|
||||
* 购买和加购分离统一组件
|
||||
* 提现初始错误修复
|
||||
* 立即购买支持多商品
|
||||
* 积分使用兑换不足提示
|
||||
* 博客新增评论、点赞
|
||||
* 新增组合搭配
|
||||
* 新增列表快捷加入购物车
|
||||
* 商品列表新增错误提示
|
||||
* 商家详情新增搜索全站开关控制
|
||||
* 门店详情新增扫码开关控制
|
||||
* 新增多规格批量下单
|
||||
* 插件分包处理
|
||||
|
||||
|
||||
## v2.3.2(2022-11-30)
|
||||
* 门店详情支持多规格直接加购
|
||||
* 分类页面支持多规格直接加购+购物车操作
|
||||
* 新增会员码
|
||||
* 新增钱包付款码
|
||||
* 新增个人资料修改
|
||||
* 新增手机号码修改
|
||||
* 新增账号注销
|
||||
* 新增条码二维码生成组件
|
||||
* 新增用户ID展示
|
||||
* 购物车分离优化
|
||||
* 适配微信小程序登录新规
|
||||
* 可视化新增图文、图片魔方、自定义html组件,商品支持左图右文样式
|
||||
* 下单时间优化、支持默认提示
|
||||
|
||||
|
||||
## v2.3.1(2022-10-23)
|
||||
* 支付宝获取地图权限优化
|
||||
* 头条小程序分类不铺满问题修复
|
||||
* 优化商品分类滑动方案
|
||||
* 位置选择优化
|
||||
|
||||
|
||||
## v2.3.0(2022-08-16)
|
||||
* 左右滚动最后一个元素显示不全修复
|
||||
* 适配paypal支付
|
||||
* 会员购买支付优化
|
||||
* 去除头条小程序自定义导航
|
||||
* 新增虚拟订单快速提交订单
|
||||
* 头条小程序支持一键获取手机号码登录
|
||||
* 多商户首页支持自动模式
|
||||
* 优惠券支持多商户
|
||||
* 商品错误情况下新增返回按钮
|
||||
* 限时秒杀优化
|
||||
* 博客搜索页面分享优化
|
||||
|
||||
|
||||
## v2.2.9(2022-07-11)
|
||||
* 首页插件数据支持按顺序渲染
|
||||
* 商品分类支持商品列表模式展示
|
||||
* 商品详情支持默认选中第一个有效规格
|
||||
* 商品详情快捷加购自动返回
|
||||
* 下单地址限制优化
|
||||
* 多商户首页支持多种样式展示
|
||||
* 商品url地址使用后端生成、购买导航新增url事件、左侧返回优化
|
||||
* 登录绑定手机返回优化
|
||||
* 搜索页面优化、避免返回事件重复加载
|
||||
|
||||
|
||||
## v2.2.8(2022-05-20)
|
||||
* 活动配置首页推荐支持(图文、九方格、左右滚动)样式展示
|
||||
* 多商户新增店铺认证资质展示
|
||||
* 门店详情支持二级分类
|
||||
* 可视化数据处理错误修复
|
||||
* 退出仅清除用户信息、微信自动登录强制绑定账号循环修复
|
||||
* 主题色样式class错误修复
|
||||
* 适配快手小程序
|
||||
|
||||
|
||||
## v2.2.7(2022-04-22)
|
||||
* 用户地址支持地理位置选择和地址信息智能识别
|
||||
* 登录返回上一页,h5支持微信自动登录
|
||||
* 门店首页新增地理位置选择弹窗、门店详情优化
|
||||
* 商品详情页面导航返回逻辑优化
|
||||
* 首页搜索和导航固定控制优化
|
||||
* 博客详情新增分享入口
|
||||
* 门店详情新增返回按钮关闭开关(适合独立打包)
|
||||
|
||||
|
||||
## v2.2.6(2022-04-07)
|
||||
* 集成新的客服系统、商品页调整为底部导航入口
|
||||
* 下单可直接使用门店次卡消费
|
||||
* 门店详情数据改为分页模式、提高效率
|
||||
* 商品详情新增相关门店列表入口
|
||||
* 商品详情底部导航购物车新增可控开关
|
||||
* 商品详情页提示优化
|
||||
* 新增可关闭原始购买功能、仅可进入门店购买
|
||||
* 标签详情分享地址id为空修复
|
||||
* 支持设置默认下单类型
|
||||
* 新增商品详情购物车展示开关(App.vue中设置)
|
||||
* 新增分享及转发使用页面设置的默认图片及系统默认图片开关(App.vue中设置)
|
||||
|
||||
|
||||
## v2.2.5(2022-03-10)
|
||||
* 基础组件类库更新
|
||||
* 商品详情新增智能工具插件信息提示
|
||||
* 订单取消后隐藏支付按钮,细节优化
|
||||
* 登录加提现优化
|
||||
* 去除微信圈子组件
|
||||
* 分享默认地址优化
|
||||
* 新增门店独立首页和搜索页
|
||||
* 新增分享及转发使用页面设置的图片开关
|
||||
|
||||
|
||||
## v2.2.4(2022-02-16)
|
||||
* 商品海报配置优化
|
||||
* 博客支持首页展示及优化
|
||||
* 新增门店列表和详情
|
||||
* 商品支持自定义返回
|
||||
* 支持自定义购买模式
|
||||
* 适配第三方登录插件
|
||||
* 下单支持0元不用选择支付方式
|
||||
* 下单页面支持指定时间选择
|
||||
* 系统参数读取优化
|
||||
|
||||
|
||||
## v2.2.3(2021-12-13)
|
||||
* 整体适配H5端
|
||||
* 订单、钱包、会员等级支付优化适配
|
||||
* 支持(账号、手机、邮箱)登录注册方式
|
||||
* 分享逻辑优化全局处理
|
||||
* 分销新增上级用户、阶梯返佣提示
|
||||
* 新增独立新增错误页面
|
||||
* 适配第三方登录插件
|
||||
* 支持线下支付自定义信息展示
|
||||
* 规格切换购买数量错误修复
|
||||
* 富文本详情支持视频、超链接、图片预览
|
||||
|
||||
|
||||
## v2.2.2(2021-11-23)
|
||||
* 限时秒杀插件支持独立首页
|
||||
* 活动配置插件支持优惠价格设定
|
||||
* 标签插件
|
||||
* 中间广告插件
|
||||
* 弹屏广告插件
|
||||
* 哀悼插件
|
||||
* 文章支持分类页面
|
||||
* 博客插件
|
||||
* 分销、会员等级增强版、钱包全面支持小程序
|
||||
* 用户授权获取用户信息API
|
||||
* 可视化索引读取错误修复
|
||||
* 支持菜鸟物流查询
|
||||
|
||||
|
||||
## v2.2.1(2021-10-24)
|
||||
* 支持微信小程序(首页、分类、购物车、用户中心、商品搜索、商品详情、订单确认、授权登录、订单管理、订单售后、商品收藏、商品足迹、直播、签到、积分商城、多商户、钱包、批发)
|
||||
712
common/css/animation.css
Normal file
712
common/css/animation.css
Normal file
@@ -0,0 +1,712 @@
|
||||
|
||||
/*
|
||||
* 垂直放大
|
||||
*/
|
||||
.scale-up-ver-bottom {
|
||||
-webkit-animation: scale-up-ver-bottom 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
|
||||
animation: scale-up-ver-bottom 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
|
||||
}
|
||||
|
||||
.scale-up-ver-bottom-infinite {
|
||||
-webkit-animation: scale-up-ver-bottom 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite both;
|
||||
animation: scale-up-ver-bottom 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite both;
|
||||
}
|
||||
@keyframes scale-up-ver-bottom {
|
||||
0% {
|
||||
-webkit-transform: scaleY(0.4);
|
||||
transform: scaleY(0.4);
|
||||
-webkit-transform-origin: 50%;
|
||||
transform-origin: 50%;
|
||||
}
|
||||
80% {
|
||||
-webkit-transform: scaleY(1);
|
||||
transform: scaleY(1);
|
||||
-webkit-transform-origin: 50%;
|
||||
transform-origin: 50%;
|
||||
}
|
||||
85% {
|
||||
-webkit-transform: rotate(-8deg);
|
||||
transform: rotate(-8deg);
|
||||
}
|
||||
95% {
|
||||
-webkit-transform: rotate(8deg);
|
||||
transform: rotate(8deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 交替垂直放大
|
||||
*/
|
||||
.scale-up-ver-bottom-alternate {
|
||||
-webkit-animation: scale-up-ver-bottom-alternate 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) alternate both;
|
||||
animation: scale-up-ver-bottom-alternate 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) alternate both;
|
||||
}
|
||||
.scale-up-ver-bottom-alternate-infinite {
|
||||
-webkit-animation: scale-up-ver-bottom-alternate 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite alternate both;
|
||||
animation: scale-up-ver-bottom-alternate 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite alternate both;
|
||||
}
|
||||
@keyframes scale-up-ver-bottom-alternate {
|
||||
0% {
|
||||
-webkit-transform: scaleY(0.4);
|
||||
transform: scaleY(0.4);
|
||||
-webkit-transform-origin: 0% 100%;
|
||||
transform-origin: 0% 100%;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scaleY(1);
|
||||
transform: scaleY(1);
|
||||
-webkit-transform-origin: 0% 100%;
|
||||
transform-origin: 0% 100%;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 中间区域放大
|
||||
*/
|
||||
.scale-up-ver-center {
|
||||
-webkit-animation: scale-up-ver-center 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
|
||||
animation: scale-up-ver-center 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
|
||||
}
|
||||
.scale-up-ver-center-infinite {
|
||||
-webkit-animation: scale-up-ver-center 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite alternate both;
|
||||
animation: scale-up-ver-center 1s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite alternate both;
|
||||
}
|
||||
|
||||
@keyframes scale-up-ver-center {
|
||||
0% {
|
||||
-webkit-transform: scaleY(0.4);
|
||||
transform: scaleY(0.4);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scaleY(1);
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 淡出
|
||||
.
|
||||
*/fade-out-fwd {
|
||||
-webkit-animation: fade-out-fwd 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
animation: fade-out-fwd 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
.fade-out-fwd-infinite {
|
||||
-webkit-animation: fade-out-fwd 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
animation: fade-out-fwd 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
}
|
||||
@keyframes fade-out-fwd {
|
||||
0% {
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateZ(80px);
|
||||
transform: translateZ(80px);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 淡入
|
||||
*/
|
||||
.fade-in-bck {
|
||||
-webkit-animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
|
||||
animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
|
||||
}
|
||||
.fade-in-bck-infinite {
|
||||
-webkit-animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite both;
|
||||
animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite both;
|
||||
}
|
||||
/*
|
||||
* 淡入淡出
|
||||
*/
|
||||
.fade-in-bck-alternate {
|
||||
-webkit-animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) alternate both;
|
||||
animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) alternate both;
|
||||
}
|
||||
.fade-in-bck-alternate-infinite {
|
||||
-webkit-animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite alternate both;
|
||||
animation: fade-in-bck 2s cubic-bezier(0.390, 0.575, 0.565, 1.000) infinite alternate both;
|
||||
}
|
||||
@keyframes fade-in-bck {
|
||||
0% {
|
||||
-webkit-transform: translateZ(80px);
|
||||
transform: translateZ(80px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 文字铺开
|
||||
*/
|
||||
.tracking-in-expand {
|
||||
-webkit-animation: tracking-in-expand 2s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
|
||||
animation: tracking-in-expand 2s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
|
||||
}
|
||||
|
||||
.tracking-in-expand-infinite {
|
||||
-webkit-animation: tracking-in-expand 2s cubic-bezier(0.215, 0.610, 0.355, 1.000) infinite both;
|
||||
animation: tracking-in-expand 2s cubic-bezier(0.215, 0.610, 0.355, 1.000) infinite both;
|
||||
}
|
||||
|
||||
@keyframes tracking-in-expand {
|
||||
0% {
|
||||
letter-spacing: -0.5em;
|
||||
opacity: 0;
|
||||
}
|
||||
40% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 心跳
|
||||
*/
|
||||
.heartbeat {
|
||||
-webkit-animation: heartbeat 1s ease-in-out both;
|
||||
animation: heartbeat 1s ease-in-out both;
|
||||
}
|
||||
|
||||
.heartbeat-infinite {
|
||||
-webkit-animation: heartbeat 1s ease-in-out infinite both;
|
||||
animation: heartbeat 1s ease-in-out infinite both;
|
||||
}
|
||||
|
||||
@keyframes heartbeat {
|
||||
from {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center;
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
10% {
|
||||
-webkit-transform: scale(0.91);
|
||||
transform: scale(0.91);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
17% {
|
||||
-webkit-transform: scale(0.98);
|
||||
transform: scale(0.98);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
33% {
|
||||
-webkit-transform: scale(0.87);
|
||||
transform: scale(0.87);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
45% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 脉动
|
||||
*/
|
||||
.pulsate-bck {
|
||||
-webkit-animation: pulsate-bck 1s ease-in-out both;
|
||||
animation: pulsate-bck 1s ease-in-out both;
|
||||
}
|
||||
|
||||
.pulsate-bck-infinite {
|
||||
-webkit-animation: pulsate-bck 1s ease-in-out infinite both;
|
||||
animation: pulsate-bck 1s ease-in-out infinite both;
|
||||
}
|
||||
|
||||
@keyframes pulsate-bck {
|
||||
0% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: scale(0.9);
|
||||
transform: scale(0.9);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 向上弹跳
|
||||
*/
|
||||
.bounce-top {
|
||||
-webkit-animation: bounce-top 1.5s both;
|
||||
animation: bounce-top 1.5s both;
|
||||
}
|
||||
.bounce-top-infinite {
|
||||
-webkit-animation: bounce-top 1.5s infinite both;
|
||||
animation: bounce-top 1.5s infinite both;
|
||||
}
|
||||
|
||||
@keyframes bounce-top {
|
||||
0%, 30%, 60%, 100% {
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
15% {
|
||||
-webkit-transform: translateY(-40px);
|
||||
transform: translateY(-40px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
45% {
|
||||
-webkit-transform: translateY(-20px);
|
||||
transform: translateY(-20px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translateY(-8px);
|
||||
transform: translateY(-8px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 向下弹跳
|
||||
*/
|
||||
.bounce-bottom {
|
||||
-webkit-animation: bounce-bottom 1.5s both;
|
||||
animation: bounce-bottom 1.5s both;
|
||||
}
|
||||
.bounce-bottom-infinite {
|
||||
-webkit-animation: bounce-bottom 1.5s infinite both;
|
||||
animation: bounce-bottom 1.5s infinite both;
|
||||
}
|
||||
|
||||
@keyframes bounce-bottom {
|
||||
0%, 30%, 60%, 100% {
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
15% {
|
||||
-webkit-transform: translateY(40px);
|
||||
transform: translateY(40px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
45% {
|
||||
-webkit-transform: translateY(20px);
|
||||
transform: translateY(20px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translateY(8px);
|
||||
transform: translateY(8px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 向左弹跳
|
||||
*/
|
||||
.bounce-left {
|
||||
-webkit-animation: bounce-left 1.5s both;
|
||||
animation: bounce-left 1.5s both;
|
||||
}
|
||||
.bounce-left-infinite {
|
||||
-webkit-animation: bounce-left 1.5s infinite both;
|
||||
animation: bounce-left 1.5s infinite both;
|
||||
}
|
||||
|
||||
@keyframes bounce-left {
|
||||
0%, 30%, 60%, 100% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
15% {
|
||||
-webkit-transform: translateX(-40px);
|
||||
transform: translateX(-40px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
45% {
|
||||
-webkit-transform: translateX(-20px);
|
||||
transform: translateX(-20px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translateX(-8px);
|
||||
transform: translateX(-8px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 向右弹跳
|
||||
*/
|
||||
.bounce-right {
|
||||
-webkit-animation: bounce-right 1.5s both;
|
||||
animation: bounce-right 1.5s both;
|
||||
}
|
||||
.bounce-right-infinite {
|
||||
-webkit-animation: bounce-right 1.5s infinite both;
|
||||
animation: bounce-right 1.5s infinite both;
|
||||
}
|
||||
|
||||
@keyframes bounce-right {
|
||||
0%, 30%, 60%, 100% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
15% {
|
||||
-webkit-transform: translateX(40px);
|
||||
transform: translateX(40px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
45% {
|
||||
-webkit-transform: translateX(20px);
|
||||
transform: translateX(20px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translateX(8px);
|
||||
transform: translateX(8px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 左侧弹跳
|
||||
*/
|
||||
.bounce-in-left {
|
||||
-webkit-animation: bounce-in-left 2s both;
|
||||
animation: bounce-in-left 2s both;
|
||||
}
|
||||
.bounce-in-left-infinite {
|
||||
-webkit-animation: bounce-in-left 2s infinite both;
|
||||
animation: bounce-in-left 2s infinite both;
|
||||
}
|
||||
|
||||
@keyframes bounce-in-left {
|
||||
0% {
|
||||
-webkit-transform: translateX(-500px);
|
||||
transform: translateX(-500px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
opacity: 0;
|
||||
}
|
||||
38% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
opacity: 1;
|
||||
}
|
||||
55% {
|
||||
-webkit-transform: translateX(-68px);
|
||||
transform: translateX(-68px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
72% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
81% {
|
||||
-webkit-transform: translateX(-28px);
|
||||
transform: translateX(-28px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
90% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
95% {
|
||||
-webkit-transform: translateX(-8px);
|
||||
transform: translateX(-8px);
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 翻转
|
||||
*/
|
||||
.flip-in-diag-2-tl {
|
||||
-webkit-animation: flip-in-diag-2-tl 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
animation: flip-in-diag-2-tl 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
.flip-in-diag-2-tl-infinite {
|
||||
-webkit-animation: flip-in-diag-2-tl 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
animation: flip-in-diag-2-tl 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
}
|
||||
|
||||
@keyframes flip-in-diag-2-tl {
|
||||
0% {
|
||||
-webkit-transform: rotate3d(-1, 1, 0, 80deg);
|
||||
transform: rotate3d(-1, 1, 0, 80deg);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate3d(1, 1, 0, 0deg);
|
||||
transform: rotate3d(1, 1, 0, 0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 从左滑动
|
||||
*/
|
||||
.slide-in-left {
|
||||
-webkit-animation: slide-in-left 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
animation: slide-in-left 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
|
||||
.slide-in-left-infinite {
|
||||
-webkit-animation: slide-in-left 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
animation: slide-in-left 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
}
|
||||
|
||||
@keyframes slide-in-left {
|
||||
0% {
|
||||
-webkit-transform: translateX(-500px);
|
||||
transform: translateX(-500px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 在fwd中心滑动
|
||||
*/
|
||||
.slide-in-fwd-center {
|
||||
-webkit-animation: slide-in-fwd-center 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
animation: slide-in-fwd-center 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
|
||||
}
|
||||
|
||||
.slide-in-fwd-center-infinite {
|
||||
-webkit-animation: slide-in-fwd-center 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
animation: slide-in-fwd-center 2s cubic-bezier(0.250, 0.460, 0.450, 0.940) infinite both;
|
||||
}
|
||||
|
||||
@keyframes slide-in-fwd-center {
|
||||
0% {
|
||||
-webkit-transform: translateZ(-1400px);
|
||||
transform: translateZ(-1400px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 左前轮旋转
|
||||
*/
|
||||
.swirl-in-left-fwd {
|
||||
-webkit-animation: swirl-in-left-fwd 2s ease-out both;
|
||||
animation: swirl-in-left-fwd 2s ease-out both;
|
||||
}
|
||||
.swirl-in-left-fwd-infinite {
|
||||
-webkit-animation: swirl-in-left-fwd 2s ease-out infinite both;
|
||||
animation: swirl-in-left-fwd 2s ease-out infinite both;
|
||||
}
|
||||
@keyframes swirl-in-left-fwd {
|
||||
0% {
|
||||
-webkit-transform: rotate(-540deg) scale(0);
|
||||
transform: rotate(-540deg) scale(0);
|
||||
-webkit-transform-origin: 0 50%;
|
||||
transform-origin: 0 50%;
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(0) scale(1);
|
||||
transform: rotate(0) scale(1);
|
||||
-webkit-transform-origin: 0 50%;
|
||||
transform-origin: 0 50%;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 摇动
|
||||
*/
|
||||
.shake-bottom {
|
||||
-webkit-animation: shake-bottom 1s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
|
||||
animation: shake-bottom 1s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
|
||||
}
|
||||
.shake-bottom-infinite {
|
||||
-webkit-animation: shake-bottom 1s cubic-bezier(0.455, 0.030, 0.515, 0.955) infinite both;
|
||||
animation: shake-bottom 1s cubic-bezier(0.455, 0.030, 0.515, 0.955) infinite both;
|
||||
}
|
||||
@keyframes shake-bottom {
|
||||
0% {
|
||||
-webkit-transform: scale(1) rotate(0deg);
|
||||
transform: scale(1) rotate(0deg);
|
||||
-webkit-transform-origin: 50%;
|
||||
transform-origin: 50%;
|
||||
}
|
||||
80% {
|
||||
-webkit-transform: scale(1.2);
|
||||
transform: scale(1.2);
|
||||
-webkit-transform-origin: 50%;
|
||||
transform-origin: 50%;
|
||||
}
|
||||
85% {
|
||||
-webkit-transform: rotate(-16deg);
|
||||
transform: rotate(-16deg);
|
||||
}
|
||||
95% {
|
||||
-webkit-transform: rotate(16deg);
|
||||
transform: rotate(16deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
-webkit-transform-origin: 50%;
|
||||
transform-origin: 50%;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 震动
|
||||
*/
|
||||
.vibrate {
|
||||
-webkit-animation: vibrate 0.3s linear both;
|
||||
animation: vibrate 0.3s linear both;
|
||||
}
|
||||
.vibrate-infinite {
|
||||
-webkit-animation: vibrate 0.3s linear infinite both;
|
||||
animation: vibrate 0.3s linear infinite both;
|
||||
}
|
||||
|
||||
@keyframes vibrate {
|
||||
0% {
|
||||
-webkit-transform: translate(0);
|
||||
transform: translate(0);
|
||||
}
|
||||
20% {
|
||||
-webkit-transform: translate(2px, -2px);
|
||||
transform: translate(2px, -2px);
|
||||
}
|
||||
40% {
|
||||
-webkit-transform: translate(2px, 2px);
|
||||
transform: translate(2px, 2px);
|
||||
}
|
||||
60% {
|
||||
-webkit-transform: translate(-2px, 2px);
|
||||
transform: translate(-2px, 2px);
|
||||
}
|
||||
80% {
|
||||
-webkit-transform: translate(-2px, -2px);
|
||||
transform: translate(-2px, -2px);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: translate(0);
|
||||
transform: translate(0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 模糊显示
|
||||
*/
|
||||
.text-focus-in {
|
||||
-webkit-animation: text-focus-in 2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
|
||||
animation: text-focus-in 2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
|
||||
}
|
||||
.text-focus-in-infinite {
|
||||
-webkit-animation: text-focus-in 2s cubic-bezier(0.550, 0.085, 0.680, 0.530) infinite both;
|
||||
animation: text-focus-in 2s cubic-bezier(0.550, 0.085, 0.680, 0.530) infinite both;
|
||||
}
|
||||
|
||||
@keyframes text-focus-in {
|
||||
0% {
|
||||
-webkit-filter: blur(12px);
|
||||
filter: blur(12px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
-webkit-filter: blur(0px);
|
||||
filter: blur(0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 果冻
|
||||
*/
|
||||
.jello-horizontal {
|
||||
-webkit-animation: jello-horizontal 0.9s both;
|
||||
animation: jello-horizontal 0.9s both;
|
||||
}
|
||||
.jello-horizontal-infinite {
|
||||
-webkit-animation: jello-horizontal 0.9s infinite both;
|
||||
animation: jello-horizontal 0.9s infinite both;
|
||||
}
|
||||
@keyframes jello-horizontal {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
30% {
|
||||
-webkit-transform: scale3d(1.25, 0.75, 1);
|
||||
transform: scale3d(1.25, 0.75, 1);
|
||||
}
|
||||
40% {
|
||||
-webkit-transform: scale3d(0.75, 1.25, 1);
|
||||
transform: scale3d(0.75, 1.25, 1);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: scale3d(1.15, 0.85, 1);
|
||||
transform: scale3d(1.15, 0.85, 1);
|
||||
}
|
||||
65% {
|
||||
-webkit-transform: scale3d(0.95, 1.05, 1);
|
||||
transform: scale3d(0.95, 1.05, 1);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: scale3d(1.05, 0.95, 1);
|
||||
transform: scale3d(1.05, 0.95, 1);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
55
common/css/business.css
Normal file
55
common/css/business.css
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 面板信息 - 文本
|
||||
*/
|
||||
.panel-item .panel-content .item:last-child {
|
||||
border: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
.panel-item .panel-content .item .title {
|
||||
width: 25%;
|
||||
}
|
||||
.panel-item .panel-content .item .content {
|
||||
width: calc(75% - 52rpx);
|
||||
min-height: 46rpx;
|
||||
word-wrap: break-word;
|
||||
word-break: normal;
|
||||
}
|
||||
.panel-item .panel-content .item .title,
|
||||
.panel-item .panel-content .item .content {
|
||||
line-height: 46rpx;
|
||||
}
|
||||
.panel-item-only .panel-content .item .content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
* 面板信息 - 图片
|
||||
*/
|
||||
.panel-item .panel-content-images .item {
|
||||
margin: 20rpx 20rpx 0 0;
|
||||
}
|
||||
.panel-item .panel-content-images .item:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.panel-item .panel-content-images .item image {
|
||||
width: 120rpx;
|
||||
height: 120rpx !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 地址边线
|
||||
*/
|
||||
.address-divider {
|
||||
height: 4px;
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAAAECAYAAADWIIyPAAAAkklEQVR42mP4jwR+7tr1/4OzM1Xwt46O/6SA3Yd//HeLeU0V3DXjE0H7GGCMvw8f/v/o5UUVT39KTPz/78cPoj398Omf/75Jb6ji6ZSyd/9//PxHnMdBjvyUlEQVT4MC7++DB0R7GuTIlPJ3VPE0KPAePvlDlL1gj3/r6qJaEv+5YwdJSbxn5meqJfGdh74TbS8A1dn662xhNdIAAAAASUVORK5CYII=");
|
||||
background-repeat-y: no-repeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付html弹窗
|
||||
*/
|
||||
.popup-pay-html-content {
|
||||
max-height: 80vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
1267
common/css/lib.css
Normal file
1267
common/css/lib.css
Normal file
File diff suppressed because it is too large
Load Diff
1420
common/css/page.css
Normal file
1420
common/css/page.css
Normal file
File diff suppressed because it is too large
Load Diff
265
common/css/plugins.css
Normal file
265
common/css/plugins.css
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 优惠劵
|
||||
*/
|
||||
.plugins-coupon-container .item {
|
||||
overflow: hidden;
|
||||
height: 180rpx;
|
||||
}
|
||||
.plugins-coupon-container .v-left {
|
||||
width: calc(100% - 140rpx);
|
||||
padding: 30rpx 0 30rpx 20rpx;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
.plugins-coupon-container .v-left .base .symbol {
|
||||
font-family: Verdana, Tahoma;
|
||||
}
|
||||
.plugins-coupon-container .v-left .base .price {
|
||||
font-weight: 700;
|
||||
font-family: arial;
|
||||
font-size: 76rpx;
|
||||
}
|
||||
.plugins-coupon-container .v-left .base .unit {
|
||||
margin-left: 5rpx;
|
||||
}
|
||||
.plugins-coupon-container .v-left .base .desc {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
.plugins-coupon-container .v-left .base-tips,
|
||||
.plugins-coupon-container .v-left .base-time {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
.plugins-coupon-container .v-right {
|
||||
width: 140rpx;
|
||||
height: 180rpx;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
.plugins-coupon-container .v-right:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.plugins-coupon-container .v-right .circle {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
top: -3px;
|
||||
width: 3px;
|
||||
height: 180rpx;
|
||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAACpCAYAAADur4c3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3NpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3MjUzYzIwOS04ZWNlLTRlNTctODQ4OC01ZDExOTkwOGNkYmMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTM1QzgxREZGRDI5MTFFNTg3QjhGRUQ1MDY5OURERUQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTM1QzgxREVGRDI5MTFFNTg3QjhGRUQ1MDY5OURERUQiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NTJiNzVkOGUtZDc2Yi00MzEzLWFmNmYtYTJkNTRlYTI4YTY1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjcyNTNjMjA5LThlY2UtNGU1Ny04NDg4LTVkMTE5OTA4Y2RiYyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pvy+vnQAAAEqSURBVHjaYvz//z8DDDAxIAFyOVeBOAHEYfyPMDsLmXMfmfMT2YADDP8h4CEQq4A4aUDMA1LNSKZDXwJxGcg1yJaWIXOeInO+IxuwA+acK0AsA+IEADEbic7hhPOAer4DcQcQMyNb2oLMeYVsADcyZwPMObuBWBTEsQFpI9E54sjO+QvEc0F+YoHKJgHxJ2TnvEM2gBmZswrmnA1AzAXiaJPhHC1k58BNQ3bBTGTOR2QD/iJzFsH8Mw/kHxBHggzn2KA7BxzWyC5Yisz5imwACmc2LLY7QbEN4nCS4ZwAIGZFds5lUEpEdsF6nKn3PTJnAsiAV0BcBsSM5GamFCDmQXYOOJ8iu2Anzrz9HKU8ABlwDYgTKcnbo0XNaFEzWtQgipqOYVLUAAQYAKPWa4c8cIHnAAAAAElFTkSuQmCC) no-repeat;
|
||||
}
|
||||
.plugins-coupon-container .item-disabled .v-right {
|
||||
background: #dfdfdf !important;
|
||||
color: #c0c0c0 !important;
|
||||
cursor: no-drop !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
.plugins-label {
|
||||
z-index: 2;
|
||||
box-sizing: border-box;
|
||||
white-space: initial;
|
||||
max-width: 100%;
|
||||
}
|
||||
.plugins-label-text {
|
||||
padding: 10rpx 10rpx 0 10rpx;
|
||||
}
|
||||
.plugins-label .lv:not(:last-child) {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.plugins-label .lv {
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.plugins-label-img.plugins-label-bottom-left .lv,
|
||||
.plugins-label-img.plugins-label-bottom-center .lv,
|
||||
.plugins-label-img.plugins-label-bottom-right .lv {
|
||||
margin-bottom: 0;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
.plugins-label .lv view {
|
||||
padding: 4rpx 12rpx;
|
||||
-webkit-box-shadow: 0px 1px 2px -1px rgb(0 0 0 / 60%);
|
||||
box-shadow: 0px 1px 2px -1px rgb(0 0 0 / 60%);
|
||||
}
|
||||
.plugins-label-img image {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
}
|
||||
.plugins-label-top-left {
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.plugins-label-top-center {
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.plugins-label-top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
.plugins-label-bottom-left,
|
||||
.plugins-label-bottom-center,
|
||||
.plugins-label-bottom-right {
|
||||
bottom: calc(100% - 380rpx);
|
||||
}
|
||||
.plugins-label-bottom-left {
|
||||
left: 0;
|
||||
}
|
||||
.plugins-label-bottom-center {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.plugins-label-bottom-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品列表标签处理
|
||||
*/
|
||||
.goods-data-rolling-list .plugins-label-bottom-left,
|
||||
.goods-data-rolling-list .plugins-label-bottom-center,
|
||||
.goods-data-rolling-list .plugins-label-bottom-right {
|
||||
bottom: calc(100% - 240rpx) !;
|
||||
}
|
||||
.goods-data-list .plugins-label-bottom-left,
|
||||
.goods-data-list .plugins-label-bottom-center,
|
||||
.goods-data-list .plugins-label-bottom-right {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 灰度样式
|
||||
*/
|
||||
.grayscale {
|
||||
filter: grayscale(100%);
|
||||
-webkit-filter: grayscale(100%);
|
||||
-moz-filter: grayscale(100%);
|
||||
-ms-filter: grayscale(100%);
|
||||
-o-filter: grayscale(100%);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 博客 - 列表
|
||||
*/
|
||||
.plugins-blog-list .blog-img {
|
||||
width: 200rpx !important;
|
||||
height: 170rpx !important;
|
||||
}
|
||||
.plugins-blog-list .base {
|
||||
width: calc(100% - 220rpx);
|
||||
}
|
||||
|
||||
/*
|
||||
* 博客 - 滚动
|
||||
*/
|
||||
.plugins-blog-rolling-list swiper,
|
||||
.plugins-blog-rolling-list .item .blog-img {
|
||||
height: 180rpx !important;
|
||||
}
|
||||
.plugins-blog-rolling-list .item .blog-title {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: calc(100% - 26rpx);
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 博客 - 九方格
|
||||
*/
|
||||
.plugins-blog-grid-list .item {
|
||||
width: calc(50% - 10rpx);
|
||||
float: left;
|
||||
padding-bottom: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.plugins-blog-grid-list .item:nth-of-type(2n + 1) {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.plugins-blog-grid-list .item:nth-of-type(2n) {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.plugins-blog-grid-list .item .blog-img {
|
||||
width: 100%;
|
||||
height: 220rpx !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 门店 - 数据列表
|
||||
*/
|
||||
.plugins-realstore-data-list .item .address-content {
|
||||
width: calc(100% - 150rpx);
|
||||
}
|
||||
|
||||
.plugins-realstore-data-list .item .address-distance {
|
||||
right: 20rpx;
|
||||
bottom: 18rpx;
|
||||
}
|
||||
|
||||
.plugins-realstore-data-list .item .icon-list {
|
||||
right: 24rpx;
|
||||
top: 36rpx;
|
||||
}
|
||||
.plugins-realstore-data-list .item .icon-list .icon-item {
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
}
|
||||
.plugins-realstore-data-list .item .icon-item .badge-icon {
|
||||
top: -10px;
|
||||
right: 2px;
|
||||
}
|
||||
.plugins-realstore-data-list .item .icon-list .icon-item {
|
||||
background: rgba(226, 44, 8, 0.08);
|
||||
border-radius: 8rpx;
|
||||
color: #E46248;
|
||||
}
|
||||
.plugins-realstore-data-list .item .icon-list .icon-item:not(:last-child) {
|
||||
margin-right: 26rpx;
|
||||
}
|
||||
.plugins-realstore-data-list .item .logo {
|
||||
width: 100rpx;
|
||||
height: 100rpx !important;
|
||||
}
|
||||
.plugins-realstore-data-list .item .base-right {
|
||||
padding-left: 14rpx;
|
||||
}
|
||||
.plugins-realstore-data-list .item .base-right .title {
|
||||
width: calc(100% - 110rpx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多商户 - 数据列表
|
||||
*/
|
||||
.plugins-shop-data-list .item .logo {
|
||||
width: 100rpx;
|
||||
height: 100rpx !important;
|
||||
}
|
||||
.plugins-shop-data-list .item .item-right-icon {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.plugins-shop-data-list .item .right-content {
|
||||
padding-left: 14rpx;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
.plugins-shop-data-list .item .auth-icon .icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx !important;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.plugins-shop-data-list .item .desc {
|
||||
min-height: 72rpx;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
838
common/css/theme.css
Normal file
838
common/css/theme.css
Normal file
@@ -0,0 +1,838 @@
|
||||
/******************** 红色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-red .border-color-main-pair {
|
||||
border-color: #F6C133 !important;
|
||||
}
|
||||
.theme-red .border-color-main-light {
|
||||
border-color: #ffdbe2 !important;
|
||||
}
|
||||
.theme-red .border-color-main {
|
||||
border-color: #ff0036 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-red .br-main-pair {
|
||||
border: 1px solid #F6C133 !important;
|
||||
}
|
||||
.theme-red .br-main-light {
|
||||
border: solid 1px #ffdbe2 !important;
|
||||
}
|
||||
.theme-red .br-main {
|
||||
border: 1px solid #ff0036 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-red .br-dashed-main-pair {
|
||||
border: dashed 1px #F6C133 !important;
|
||||
}
|
||||
.theme-red .br-dashed-main-light {
|
||||
border: dashed 1px #ffdbe2 !important;
|
||||
}
|
||||
.theme-red .br-dashed-main {
|
||||
border: dashed 1px #ff0036 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-red .cr-main-pair {
|
||||
color: #F6C133 !important;
|
||||
}
|
||||
.theme-red .cr-main-light {
|
||||
color: #ffdbe2 !important;
|
||||
}
|
||||
.theme-red .cr-main {
|
||||
color: #ff0036 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-red .bg-main-pair {
|
||||
background-color: #F6C133 !important;
|
||||
}
|
||||
.theme-red .bg-main-light {
|
||||
background-color: #ffdbe2 !important;
|
||||
}
|
||||
.theme-red .bg-main {
|
||||
background-color: #ff0036 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-red .nav-active-line::before {
|
||||
background: #ff0036;
|
||||
}
|
||||
.theme-red button[disabled].bg-main-pair {
|
||||
background-color: #d0cbca !important;
|
||||
border-color: #d0cbca !important;
|
||||
color: #eaeaea !important;
|
||||
}
|
||||
.theme-red button[disabled].bg-main-light {
|
||||
background-color: #ffe9ed !important;
|
||||
border-color: #ffe9ed !important;
|
||||
color: #ffa5b7 !important;
|
||||
}
|
||||
.theme-red button[disabled].bg-main {
|
||||
background-color: #ffa7ba !important;
|
||||
border-color: #ffa7ba !important;
|
||||
color: #fff5f7 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-red .title-left-border::before {
|
||||
background: linear-gradient(180deg, #ff0036 0%, #ffdbe2 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-red .nav-left-border::before {
|
||||
background: #ff0036;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************** 黄色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-yellow .border-color-main-pair {
|
||||
border-color: #FF0036 !important;
|
||||
}
|
||||
.theme-yellow .border-color-main-light {
|
||||
border-color: #ffebd2 !important;
|
||||
}
|
||||
.theme-yellow .border-color-main {
|
||||
border-color: #f6c133 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-yellow .br-main-pair {
|
||||
border: 1px solid #FF0036 !important;
|
||||
}
|
||||
.theme-yellow .br-main-light {
|
||||
border: solid 1px #ffebd2 !important;
|
||||
}
|
||||
.theme-yellow .br-main {
|
||||
border: 1px solid #f6c133 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-yellow .br-dashed-main-pair {
|
||||
border: dashed 1px #FF0036 !important;
|
||||
}
|
||||
.theme-yellow .br-dashed-main-light {
|
||||
border: dashed 1px #ffebd2 !important;
|
||||
}
|
||||
.theme-yellow .br-dashed-main {
|
||||
border: dashed 1px #f6c133 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-yellow .cr-main-pair {
|
||||
color: #FF0036 !important;
|
||||
}
|
||||
.theme-yellow .cr-main-light {
|
||||
color: #ffebd2 !important;
|
||||
}
|
||||
.theme-yellow .cr-main {
|
||||
color: #f6c133 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-yellow .nav-active-line::before {
|
||||
background: #f6c133;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-yellow .bg-main-pair {
|
||||
background-color: #FF0036 !important;
|
||||
}
|
||||
.theme-yellow .bg-main-light {
|
||||
background-color: #ffebd2 !important;
|
||||
}
|
||||
.theme-yellow .bg-main {
|
||||
background-color: #f6c133 !important;
|
||||
}
|
||||
.theme-yellow button[disabled].bg-main-pair {
|
||||
background-color: #b5a29c !important;
|
||||
border-color: #b5a29c !important;
|
||||
color: #8c766f !important;
|
||||
}
|
||||
.theme-yellow button[disabled].bg-main-light {
|
||||
background-color: #fbebd6 !important;
|
||||
border-color: #fbebd6 !important;
|
||||
color: #ffcc40 !important;
|
||||
}
|
||||
.theme-yellow button[disabled].bg-main {
|
||||
background-color: #fdd178 !important;
|
||||
border-color: #fdd178 !important;
|
||||
color: #fff7e7 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-yellow .title-left-border::before {
|
||||
background: linear-gradient(180deg, #f6c133 0%, #ffebd2 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-yellow .nav-left-border::before {
|
||||
background: #f6c133;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************** 黑色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-black .border-color-main-pair {
|
||||
border-color: #D3B881 !important;
|
||||
}
|
||||
.theme-black .border-color-main-light {
|
||||
border-color: #dcdcdc !important;
|
||||
}
|
||||
.theme-black .border-color-main {
|
||||
border-color: #333333 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-black .br-main-pair {
|
||||
border: 1px solid #D3B881 !important;
|
||||
}
|
||||
.theme-black .br-main-light {
|
||||
border: solid 1px #dcdcdc !important;
|
||||
}
|
||||
.theme-black .br-main {
|
||||
border: 1px solid #333333 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-black .br-dashed-main-pair {
|
||||
border: dashed 1px #D3B881 !important;
|
||||
}
|
||||
.theme-black .br-dashed-main-light {
|
||||
border: dashed 1px #dcdcdc !important;
|
||||
}
|
||||
.theme-black .br-dashed-main {
|
||||
border: dashed 1px #333333 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-black .cr-main-pair {
|
||||
color: #D3B881 !important;
|
||||
}
|
||||
.theme-black .cr-main-light {
|
||||
color: #dcdcdc !important;
|
||||
}
|
||||
.theme-black .cr-main {
|
||||
color: #333333 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-black .bg-main-pair {
|
||||
background-color: #D3B881 !important;
|
||||
}
|
||||
.theme-black .bg-main-light {
|
||||
background-color: #dcdcdc !important;
|
||||
}
|
||||
.theme-black .bg-main {
|
||||
background-color: #333333 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-black .nav-active-line::before {
|
||||
background: #333333;
|
||||
}
|
||||
.theme-black button[disabled].bg-main-pair {
|
||||
background-color: #bdece8 !important;
|
||||
border-color: #bdece8 !important;
|
||||
color: #edfbf9 !important;
|
||||
}
|
||||
.theme-black button[disabled].bg-main-light {
|
||||
background-color: #efefef !important;
|
||||
border-color: #efefef !important;
|
||||
color: #b7b7b7 !important;
|
||||
}
|
||||
.theme-black button[disabled].bg-main {
|
||||
background-color: #c7c7c7 !important;
|
||||
border-color: #c7c7c7 !important;
|
||||
color: #e2e2e2 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-black .title-left-border::before {
|
||||
background: linear-gradient(180deg, #333333 0%, #dcdcdc 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-black .nav-left-border::before {
|
||||
background: #333333;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************** 绿色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-green .border-color-main-pair {
|
||||
border-color: #20A5A2 !important;
|
||||
}
|
||||
.theme-green .border-color-main-light {
|
||||
border-color: #cce8d2 !important;
|
||||
}
|
||||
.theme-green .border-color-main {
|
||||
border-color: #20a53a !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-green .br-main-pair {
|
||||
border: 1px solid #20A5A2 !important;
|
||||
}
|
||||
.theme-green .br-main-light {
|
||||
border: solid 1px #cce8d2 !important;
|
||||
}
|
||||
.theme-green .br-main {
|
||||
border: 1px solid #20a53a !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-green .br-dashed-main-pair {
|
||||
border: dashed 1px #20A5A2 !important;
|
||||
}
|
||||
.theme-green .br-dashed-main-light {
|
||||
border: dashed 1px #cce8d2 !important;
|
||||
}
|
||||
.theme-green .br-dashed-main {
|
||||
border: dashed 1px #20a53a !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-green .cr-main-pair {
|
||||
color: #20A5A2 !important;
|
||||
}
|
||||
.theme-green .cr-main-light {
|
||||
color: #cce8d2 !important;
|
||||
}
|
||||
.theme-green .cr-main {
|
||||
color: #20a53a !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-green .bg-main-pair {
|
||||
background-color: #20A5A2 !important;
|
||||
}
|
||||
.theme-green .bg-main-light {
|
||||
background-color: #cce8d2 !important;
|
||||
}
|
||||
.theme-green .bg-main {
|
||||
background-color: #20a53a !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-green .nav-active-line::before {
|
||||
background: #20a53a;
|
||||
}
|
||||
.theme-green button[disabled].bg-main-pair {
|
||||
background-color: #cfaae2 !important;
|
||||
border-color: #cfaae2 !important;
|
||||
color: #e6deea !important;
|
||||
}
|
||||
.theme-green button[disabled].bg-main-light {
|
||||
background-color: #daeade !important;
|
||||
border-color: #daeade !important;
|
||||
color: #9dcaa6 !important;
|
||||
}
|
||||
.theme-green button[disabled].bg-main {
|
||||
background-color: #a8c5ae !important;
|
||||
border-color: #a8c5ae !important;
|
||||
color: #d8eadc !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-green .title-left-border::before {
|
||||
background: linear-gradient(180deg, #20a53a 0%, #cce8d2 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-green .nav-left-border::before {
|
||||
background: #20a53a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************** 橙色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-orange .border-color-main-pair {
|
||||
border-color: #F6C133 !important;
|
||||
}
|
||||
.theme-orange .border-color-main-light {
|
||||
border-color: #fde4d1 !important;
|
||||
}
|
||||
.theme-orange .border-color-main {
|
||||
border-color: #fe6f04 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-orange .br-main-pair {
|
||||
border: 1px solid #F6C133 !important;
|
||||
}
|
||||
.theme-orange .br-main-light {
|
||||
border: solid 1px #fde4d1 !important;
|
||||
}
|
||||
.theme-orange .br-main {
|
||||
border: 1px solid #fe6f04 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-orange .br-dashed-main-pair {
|
||||
border: dashed 1px #F6C133 !important;
|
||||
}
|
||||
.theme-orange .br-dashed-main-light {
|
||||
border: dashed 1px #fde4d1 !important;
|
||||
}
|
||||
.theme-orange .br-dashed-main {
|
||||
border: dashed 1px #fe6f04 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-orange .cr-main-pair {
|
||||
color: #F6C133 !important;
|
||||
}
|
||||
.theme-orange .cr-main-light {
|
||||
color: #fde4d1 !important;
|
||||
}
|
||||
.theme-orange .cr-main {
|
||||
color: #fe6f04 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-orange .bg-main-pair {
|
||||
background-color: #F6C133 !important;
|
||||
}
|
||||
.theme-orange .bg-main-light {
|
||||
background-color: #fde4d1 !important;
|
||||
}
|
||||
.theme-orange .bg-main {
|
||||
background-color: #fe6f04 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-orange .nav-active-line::before {
|
||||
background: #fe6f04;
|
||||
}
|
||||
.theme-orange button[disabled].bg-main-pair {
|
||||
background-color: #b5a29c !important;
|
||||
border-color: #b5a29c !important;
|
||||
color: #8c766f !important;
|
||||
}
|
||||
.theme-orange button[disabled].bg-main-light {
|
||||
background-color: #fbe9dc !important;
|
||||
border-color: #fbe9dc !important;
|
||||
color: #f7c49e !important;
|
||||
}
|
||||
.theme-orange button[disabled].bg-main {
|
||||
background-color: #f7cdad !important;
|
||||
border-color: #f7cdad !important;
|
||||
color: #f7efea !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-orange .title-left-border::before {
|
||||
background: linear-gradient(180deg, #fe6f04 0%, #fde4d1 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-orange .nav-left-border::before {
|
||||
background: #fe6f04;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************** 蓝色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-blue .border-color-main-pair {
|
||||
border-color: #16CEFF !important;
|
||||
}
|
||||
.theme-blue .border-color-main-light {
|
||||
border-color: #d1e4ff !important;
|
||||
}
|
||||
.theme-blue .border-color-main {
|
||||
border-color: #1677ff !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-blue .br-main-pair {
|
||||
border: 1px solid #16CEFF !important;
|
||||
}
|
||||
.theme-blue .br-main-light {
|
||||
border: solid 1px #d1e4ff !important;
|
||||
}
|
||||
.theme-blue .br-main {
|
||||
border: 1px solid #1677ff !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-blue .br-dashed-main-pair {
|
||||
border: dashed 1px #16CEFF !important;
|
||||
}
|
||||
.theme-blue .br-dashed-main-light {
|
||||
border: dashed 1px #d1e4ff !important;
|
||||
}
|
||||
.theme-blue .br-dashed-main {
|
||||
border: dashed 1px #1677ff !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-blue .cr-main-pair {
|
||||
color: #16CEFF !important;
|
||||
}
|
||||
.theme-blue .cr-main-light {
|
||||
color: #d1e4ff !important;
|
||||
}
|
||||
.theme-blue .cr-main {
|
||||
color: #1677ff !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-blue .bg-main-pair {
|
||||
background-color: #16CEFF !important;
|
||||
}
|
||||
.theme-blue .bg-main-light {
|
||||
background-color: #d1e4ff !important;
|
||||
}
|
||||
.theme-blue .bg-main {
|
||||
background-color: #1677ff !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-blue .nav-active-line::before {
|
||||
background: #1677ff;
|
||||
}
|
||||
.theme-blue button[disabled].bg-main-pair {
|
||||
background-color: #efcbf5 !important;
|
||||
border-color: #efcbf5 !important;
|
||||
color: #faf1fb !important;
|
||||
}
|
||||
.theme-blue button[disabled].bg-main-light {
|
||||
background-color: #e3eefd !important;
|
||||
border-color: #e3eefd !important;
|
||||
color: #b9d3f7 !important;
|
||||
}
|
||||
.theme-blue button[disabled].bg-main {
|
||||
background-color: #bcd3f5 !important;
|
||||
border-color: #bcd3f5 !important;
|
||||
color: #eef4fd !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-blue .title-left-border::before {
|
||||
background: linear-gradient(180deg, #1677ff 0%, #d1e4ff 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-blue .nav-left-border::before {
|
||||
background: #1677ff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************** 棕色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-brown .border-color-main-pair {
|
||||
border-color: #8B1313 !important;
|
||||
}
|
||||
.theme-brown .border-color-main-light {
|
||||
border-color: #eadcd2 !important;
|
||||
}
|
||||
.theme-brown .border-color-main {
|
||||
border-color: #8B4513 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-brown .br-main-pair {
|
||||
border: 1px solid #8B1313 !important;
|
||||
}
|
||||
.theme-brown .br-main-light {
|
||||
border: solid 1px #eadcd2 !important;
|
||||
}
|
||||
.theme-brown .br-main {
|
||||
border: 1px solid #8B4513 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-brown .br-dashed-main-pair {
|
||||
border: dashed 1px #8B1313 !important;
|
||||
}
|
||||
.theme-brown .br-dashed-main-light {
|
||||
border: dashed 1px #eadcd2 !important;
|
||||
}
|
||||
.theme-brown .br-dashed-main {
|
||||
border: dashed 1px #8B4513 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-brown .cr-main-pair {
|
||||
color: #8B1313 !important;
|
||||
}
|
||||
.theme-brown .cr-main-light {
|
||||
color: #eadcd2 !important;
|
||||
}
|
||||
.theme-brown .cr-main {
|
||||
color: #8B4513 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-brown .bg-main-pair {
|
||||
background-color: #8B1313 !important;
|
||||
}
|
||||
.theme-brown .bg-main-light {
|
||||
background-color: #eadcd2 !important;
|
||||
}
|
||||
.theme-brown .bg-main {
|
||||
background-color: #8B4513 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-brown .nav-active-line::before {
|
||||
background: #8B4513;
|
||||
}
|
||||
.theme-brown button[disabled].bg-main-pair {
|
||||
background-color: #a6ded9 !important;
|
||||
border-color: #a6ded9 !important;
|
||||
color: #dff1ef !important;
|
||||
}
|
||||
.theme-brown button[disabled].bg-main-light {
|
||||
background-color: #f1e6de !important;
|
||||
border-color: #f1e6de !important;
|
||||
color: #d6bdad !important;
|
||||
}
|
||||
.theme-brown button[disabled].bg-main {
|
||||
background-color: #e4cdbc !important;
|
||||
border-color: #e4cdbc !important;
|
||||
color: #f9f4f0 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-brown .title-left-border::before {
|
||||
background: linear-gradient(180deg, #8B4513 0%, #eadcd2 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-brown .nav-left-border::before {
|
||||
background: #8B4513;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************** 紫色 ********************/
|
||||
/**
|
||||
* 边线 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-purple .border-color-main-pair {
|
||||
border-color: #3C8CEC !important;
|
||||
}
|
||||
.theme-purple .border-color-main-light {
|
||||
border-color: #d6cbfb !important;
|
||||
}
|
||||
.theme-purple .border-color-main {
|
||||
border-color: #623cec !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-purple .br-main-pair {
|
||||
border: 1px solid #3C8CEC !important;
|
||||
}
|
||||
.theme-purple .br-main-light {
|
||||
border: solid 1px #d6cbfb !important;
|
||||
}
|
||||
.theme-purple .br-main {
|
||||
border: 1px solid #623cec !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚线边框 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-purple .br-dashed-main-pair {
|
||||
border: dashed 1px #3C8CEC !important;
|
||||
}
|
||||
.theme-purple .br-dashed-main-light {
|
||||
border: dashed 1px #d6cbfb !important;
|
||||
}
|
||||
.theme-purple .br-dashed-main {
|
||||
border: dashed 1px #623cec !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本颜色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-purple .cr-main-pair {
|
||||
color: #3C8CEC !important;
|
||||
}
|
||||
.theme-purple .cr-main-light {
|
||||
color: #d6cbfb !important;
|
||||
}
|
||||
.theme-purple .cr-main {
|
||||
color: #623cec !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景色 搭配色、次主色、主色
|
||||
*/
|
||||
.theme-purple .bg-main-pair {
|
||||
background-color: #3C8CEC !important;
|
||||
}
|
||||
.theme-purple .bg-main-light {
|
||||
background-color: #d6cbfb !important;
|
||||
}
|
||||
.theme-purple .bg-main {
|
||||
background-color: #623cec !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航伪类背景色
|
||||
*/
|
||||
.theme-purple .nav-active-line::before {
|
||||
background: #623cec;
|
||||
}
|
||||
.theme-purple button[disabled].bg-main-pair {
|
||||
background-color: #d8aed8 !important;
|
||||
border-color: #d8aed8 !important;
|
||||
color: #efe4ef !important;
|
||||
}
|
||||
.theme-purple button[disabled].bg-main-light {
|
||||
background-color: #dcd6f1 !important;
|
||||
border-color: #dcd6f1 !important;
|
||||
color: #b2a7dc !important;
|
||||
}
|
||||
.theme-purple button[disabled].bg-main {
|
||||
background-color: #bdb0ef !important;
|
||||
border-color: #bdb0ef !important;
|
||||
color: #e7e4f1 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题左侧边线
|
||||
*/
|
||||
.theme-purple .title-left-border::before {
|
||||
background: linear-gradient(180deg, #623cec 0%, #d6cbfb 100%);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航菜单左侧边线
|
||||
*/
|
||||
.theme-purple .nav-left-border::before {
|
||||
background: #623cec;
|
||||
}
|
||||
82
common/js/common/base.js
Normal file
82
common/js/common/base.js
Normal file
@@ -0,0 +1,82 @@
|
||||
export default {
|
||||
methods: {
|
||||
//转义符换成普通字符
|
||||
escape2Html(str) {
|
||||
if (!str) return str;
|
||||
var arrEntities = {
|
||||
'lt': '<',
|
||||
'gt': '>',
|
||||
'nbsp': ' ',
|
||||
'amp': '&',
|
||||
'quot': '"'
|
||||
};
|
||||
return str.replace(/&(lt|gt|nbsp|amp|quot);/ig, function(all, t) {
|
||||
return arrEntities[t];
|
||||
});
|
||||
},
|
||||
//普通字符转换成转义符
|
||||
html2Escape(sHtml) {
|
||||
if (!sHtml) return sHtml;
|
||||
return sHtml.replace(/[<>&"]/g, function(c) {
|
||||
return {
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'&': '&',
|
||||
'"': '"'
|
||||
} [c];
|
||||
});
|
||||
},
|
||||
//setData polyfill 勿删!!! (用于转换后的uniapp的项目能直接使用this.setData()函数)
|
||||
setData: function(obj, callback) {
|
||||
let that = this;
|
||||
const handleData = (tepData, tepKey, afterKey) => {
|
||||
var tepData2 = tepData;
|
||||
tepKey = tepKey.split('.');
|
||||
tepKey.forEach(item => {
|
||||
if (tepData[item] === null || tepData[item] === undefined) {
|
||||
let reg = /^[0-9]+$/;
|
||||
tepData[item] = reg.test(afterKey) ? [] : {};
|
||||
tepData2 = tepData[item];
|
||||
} else {
|
||||
tepData2 = tepData[item];
|
||||
}
|
||||
});
|
||||
return tepData2;
|
||||
};
|
||||
const isFn = function(value) {
|
||||
return typeof value == 'function' || false;
|
||||
};
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
let val = obj[key];
|
||||
key = key.replace(/\]/g, '').replace(/\[/g, '.');
|
||||
let front, after;
|
||||
let index_after = key.lastIndexOf('.');
|
||||
if (index_after != -1) {
|
||||
after = key.slice(index_after + 1);
|
||||
front = handleData(that, key.slice(0, index_after), after);
|
||||
} else {
|
||||
after = key;
|
||||
front = that;
|
||||
}
|
||||
if (front.$data && front.$data[after] === undefined) {
|
||||
Object.defineProperty(front, after, {
|
||||
get() {
|
||||
return front.$data[after];
|
||||
},
|
||||
set(newValue) {
|
||||
front.$data[after] = newValue;
|
||||
that.hasOwnProperty("$forceUpdate") && that.$forceUpdate();
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
front[after] = val;
|
||||
} else {
|
||||
that.$set(front, after, val);
|
||||
}
|
||||
});
|
||||
this.$forceUpdate();
|
||||
isFn(callback) && this.$nextTick(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
653
common/js/common/common.js
Normal file
653
common/js/common/common.js
Normal file
@@ -0,0 +1,653 @@
|
||||
const app = getApp();
|
||||
// 数据的默认值,避免没有值的时候报错
|
||||
export const old_radius = { radius: 0, radius_top_left: 0, radius_top_right: 0, radius_bottom_left: 0, radius_bottom_right: 0 };
|
||||
export const old_padding = { padding: 0, padding_top: 0, padding_bottom: 0, padding_left: 0, padding_right: 0 };
|
||||
export const old_margin = { margin: 0, margin_top: 0, margin_bottom: 0, margin_left: 0, margin_right: 0 };
|
||||
export const old_border_and_box_shadow = { border_is_show: '0', border_color: '#FF3F3F', border_style: 'solid',border_size: { padding: 1, padding_top: 1, padding_right: 1, padding_bottom: 1, padding_left: 1, }, box_shadow_color: '', box_shadow_x: 0, box_shadow_y: 0, box_shadow_blur: 0, box_shadow_spread: 0 };
|
||||
|
||||
/**
|
||||
* 判断一个对象是否为空。
|
||||
*
|
||||
* 为空的定义是对象的键的数量为0。这适用于任何对象,包括普通对象、数组(视为对象)等。
|
||||
* 该函数不直接使用`Object.keys(obj).length === 0`进行判断,而是通过封装这个逻辑来提供一个独立的、可重用的函数。
|
||||
* 这样做可以增加代码的可读性和可维护性,并且抽象了对象为空的检查,使得调用者不需要关心具体的实现细节。
|
||||
*
|
||||
* @param obj 要检查的对象。可以是任何类型的对象,包括数组。
|
||||
* @returns 如果对象为空,则返回true;否则返回false。
|
||||
*/
|
||||
export function is_obj_empty(obj) {
|
||||
return Object.keys(obj).length === 0;
|
||||
}
|
||||
|
||||
export const border_width = (style) => {
|
||||
if (!style) { return 0; }
|
||||
if (style.border_is_show == '1') {
|
||||
const { padding_left = 0, padding_right = 0 } = style.border_size || {};
|
||||
return padding_left + padding_right;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定的条件类型和值,判断字段值是否满足条件
|
||||
* @param fieldValue 字段值,可以是任何类型
|
||||
* @param type 条件类型,如'contains', 'is-empty', 'greater-than'等
|
||||
* @param value 用于比较的值,可以是数字或字符串
|
||||
* @returns 返回一个布尔值,表示字段值是否满足指定的条件
|
||||
*/
|
||||
export const custom_condition_judg = (fieldValue, type, value) => {
|
||||
// 处理 null 或 undefined 的情况
|
||||
if (fieldValue == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 提前计算并缓存转换结果
|
||||
const stringValue = String(fieldValue);
|
||||
const valueStr = String(value);
|
||||
const numberValue = Number(value);
|
||||
switch (type) {
|
||||
case 'contains':
|
||||
case 'does-not-contain':
|
||||
// 处理包含和不包含的逻辑, 如果值为空,直接返回为空
|
||||
if (!isEmpty(valueStr)) {
|
||||
const result = stringValue.includes(valueStr);
|
||||
return type === 'contains' ? result : !result;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
case 'is-empty':
|
||||
case 'is-not-empty':
|
||||
// 处理为空和不为空的逻辑
|
||||
const is_Empty = ['', '{}', '[]'].includes(stringValue.trim()) || (Array.isArray(fieldValue) && fieldValue.length === 0);
|
||||
return type === 'is-empty' ? is_Empty : !is_Empty;
|
||||
case 'greater-than':
|
||||
case 'less-than':
|
||||
case 'equal':
|
||||
// 根据字段值的类型,进行数字间的比较
|
||||
if (typeof fieldValue === 'number') {
|
||||
return compare_numbers(fieldValue, numberValue, type);
|
||||
} else if (Array.isArray(fieldValue) || typeof fieldValue === 'string') {
|
||||
// 如果字段值是数组或字符串,比较数组长度和指定值
|
||||
const valueLength = fieldValue?.length || 0;
|
||||
return compare_numbers(valueLength, numberValue, type);
|
||||
} else if (typeof fieldValue === 'object') {
|
||||
// 如果字段值是对象,比较对象的属性值
|
||||
const numericFieldValue = Object.keys(fieldValue)?.length || 0;
|
||||
return compare_numbers(numericFieldValue, numberValue, type);
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个数字的大小
|
||||
* @param a 第一个数字
|
||||
* @param b 第二个数字
|
||||
* @param type 比较类型,如'greater-than', 'less-than', 'equal'等
|
||||
* @returns 根据比较类型返回比较结果
|
||||
*/
|
||||
const compare_numbers = (a, b, type) => {
|
||||
switch (type) {
|
||||
case 'greater-than': return a > b;
|
||||
case 'less-than': return a < b;
|
||||
case 'equal': return a === b;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据新的样式对象计算指示器的位置样式
|
||||
*
|
||||
* 此函数根据指示器的新位置和当前位置以及底部距离来生成相应的CSS样式
|
||||
* 它处理的是一个包含指示器位置信息的对象,并返回一个字符串形式的CSS样式
|
||||
*
|
||||
* @param new_style 包含指示器新位置和当前位置及底部距离的样式对象
|
||||
* @returns 返回计算出的指示器位置CSS样式字符串
|
||||
*/
|
||||
export const get_indicator_location = (new_style) => {
|
||||
// 解构指示器的位置信息
|
||||
const { indicator_new_location = '', indicator_location = '', indicator_bottom = 0 } = new_style;
|
||||
let styles = '';
|
||||
// 根据指示器的新位置是水平方向(left或right)还是垂直方向(默认)来决定如何设置样式
|
||||
if (['left', 'right'].includes(indicator_new_location)) {
|
||||
// 如果是水平方向,根据指示器的当前位置设置top、center或bottom样式
|
||||
if (indicator_location == 'flex-start') {
|
||||
styles += `top: 0px;`;
|
||||
} else if (indicator_location == 'center') {
|
||||
styles += `top: 50%; transform: translateY(-50%);`;
|
||||
} else {
|
||||
styles += `bottom: 0px;`;
|
||||
}
|
||||
} else {
|
||||
// 如果是垂直方向,根据指示器的当前位置设置left、center或right样式
|
||||
if (indicator_location == 'flex-start') {
|
||||
styles += `left: 0px;`;
|
||||
} else if (indicator_location == 'center') {
|
||||
styles += `left: 50%; transform: translateX(-50%);`;
|
||||
} else {
|
||||
styles += `right: 0px;`;
|
||||
}
|
||||
}
|
||||
// 如果有位置的处理,就使用指示器的位置处理,否则的话就用下边距处理
|
||||
styles += `${ !isEmpty(indicator_new_location) ? `${indicator_new_location}: ${ indicator_bottom }px;` : `bottom: ${ indicator_bottom }px;` }`;
|
||||
// 返回计算出的指示器位置样式
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定条件是否符合资格,主要用于自定义内部各个组件是否符合显示条件
|
||||
* @param field_list 字段列表,包含各个字段的数据
|
||||
* @param condition 条件数据,包括字段、类型和值
|
||||
* @param props 额外属性,包含自定义组和数据源等信息
|
||||
* @returns 返回一个布尔值,表示是否符合条件
|
||||
*/
|
||||
export const get_is_eligible = (field_list, condition, sourceList, isCustom, isCustomGroup, customGroupFieldId) => {
|
||||
try {
|
||||
// 条件加特殊标识,避免选择的时候出现重复的
|
||||
let new_field = condition.field;
|
||||
// 如果包含{|},则取第一个字段
|
||||
if (condition.field.includes('{|}')) {
|
||||
new_field = condition.field.split('{|}')[0];
|
||||
}
|
||||
// 获取对应条件字段的字段数据
|
||||
let option = {};
|
||||
if (field_list) {
|
||||
// 判断是否是自定义组并且 自定义组选则了对应的数据源
|
||||
if (isCustomGroup && !isEmpty(customGroupFieldId)) {
|
||||
// 取出对应自定义组的内容
|
||||
const group_option_list = field_list.find(item => item.field === customGroupFieldId);
|
||||
// 取出自定义组内部数据源参数的详细数据
|
||||
const new_field_list = group_option_list?.data || [];
|
||||
// 通过对应条件,筛选出对应的数据
|
||||
option = new_field_list.find(item => item.field === new_field);
|
||||
} else {
|
||||
option = field_list.find(item => item.field === new_field);
|
||||
}
|
||||
}
|
||||
// 找不到对应的字段,就直接返回为成功,条件不存在
|
||||
if (!isEmpty(option)) {
|
||||
// 获取到字段的真实数据, option的使用主要是为了获取的他的中间参数和前缀,后缀等拼接在一起
|
||||
const field_value = custom_condition_data(new_field || '', option || {}, sourceList, isCustom);
|
||||
// 判断条件字段是否为空并且是显示面板才会生效,则直接返回true
|
||||
if (!isEmpty(new_field) && !isEmpty(condition.type)) {
|
||||
return custom_condition_judg(field_value, condition.type, condition.value);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
return true; // 或者根据业务需求返回适当的默认值
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据源ID和配置选项来处理和返回特定格式的数据
|
||||
*
|
||||
* @param data_source_id 数据源ID字符串,可以包含多个用分号分隔的ID
|
||||
* @param option 配置选项,包含数据处理的额外参数
|
||||
* @param sourceList 数据源列表,用于查找和处理数据
|
||||
* @param isCustom 是否为自定义模式,用于确定数据处理的方式
|
||||
* @returns 返回处理后的数据字符串
|
||||
*/
|
||||
export const custom_condition_data = (data_source_id, option, sourceList, isCustom) => {
|
||||
let data_value = '';
|
||||
if (data_source_id.includes(';')) {
|
||||
// 当数据源ID包含多个用分号分隔的ID时
|
||||
// 取出所有的字段,使用;分割
|
||||
const ids = data_source_id.split(';');
|
||||
let text = '';
|
||||
// 遍历每个ID,处理数据并合并
|
||||
ids.forEach((item, index) => {
|
||||
text += data_handling(item, sourceList, isCustom) + (index != ids.length - 1 ? (option?.join || '') : '');
|
||||
});
|
||||
data_value = text;
|
||||
} else {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
// 当数据源ID不包含分号时,直接处理数据
|
||||
data_value = data_handling(data_source_id, sourceList, isCustom);
|
||||
}
|
||||
// 如果数据是undefined或者null,则设置为空字符串
|
||||
if (data_value == null) {
|
||||
data_value = '';
|
||||
}
|
||||
// 根据配置选项,添加前缀和后缀到处理后的数据
|
||||
return Array.isArray(data_value) || typeof data_value === "object" ? data_value : ((option?.first || '') + data_value + (option?.last || ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据处理函数
|
||||
* 该函数根据数据源ID和一个数据对象,返回对应的图标路径
|
||||
* 主要用于从复杂的数据结构中提取图标信息,根据是否是自定义图标,
|
||||
* 从不同的数据层级中获取信息
|
||||
*
|
||||
* @param data_source_id 数据源ID,用于定位图标在数据结构中的位置
|
||||
* @param sourceList 包含图标数据的对象,可以是多层嵌套结构
|
||||
* @param isCustom 布尔值,指示是否为自定义图标,影响数据获取的方式
|
||||
* @returns 返回找到的图标路径,如果没有找到或数据为空,则返回空值
|
||||
*/
|
||||
const data_handling = (data_source_id, sourceList, isCustom) => {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
let new_data = get_nested_property(sourceList, data_source_id);
|
||||
// 如果是商品,品牌,文章的图片, 其他的切换为从data中取数据
|
||||
if (!isEmpty(sourceList.data) && isCustom) {
|
||||
new_data = get_nested_property(sourceList.data, data_source_id);
|
||||
}
|
||||
return new_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取嵌套对象的属性值
|
||||
*
|
||||
* 该函数旨在通过指定的属性路径获取嵌套对象中的属性值它接受一个对象和一个属性路径字符串作为参数,
|
||||
* 并返回对应路径的属性值如果输入的路径无效或对象中不存在该路径,则返回空字符串
|
||||
*
|
||||
* @param {Object} obj - 要从中获取属性的嵌套对象
|
||||
* @param {string} path - 属性路径,使用点号分隔的字符串表示
|
||||
* @returns {string} - 返回指定路径的属性值,如果路径无效则返回空字符串
|
||||
*/
|
||||
export function get_nested_property(obj, path) {
|
||||
// 检查路径参数是否为字符串且非空,若不满足条件则返回空字符串
|
||||
if (typeof path !== 'string' || !path) return '';
|
||||
|
||||
// 将属性路径字符串拆分为属性键数组
|
||||
const keys = path.split('.');
|
||||
|
||||
// 使用reduce方法遍历属性键数组,逐层访问对象属性
|
||||
// 如果当前对象存在且拥有下一个属性键,则继续访问;否则返回空字符串
|
||||
return keys.reduce((o, key) => (o != null && o[key] != null ? o[key] : ''), obj) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据源链接ID和属性源列表生成自定义链接
|
||||
*
|
||||
* @param {string} data_source_link_id - 数据源链接ID,可以是单个ID或多个ID以分号分隔
|
||||
* @param {object} propSourceList - 包含数据源的属性列表
|
||||
* @param {object} source_link_option - 链接生成的可选配置,包括首尾添加的字符串和连接符
|
||||
* @returns {string} 生成的自定义链接URL
|
||||
*/
|
||||
export function get_custom_link(data_source_link_id, propSourceList, source_link_option) {
|
||||
let url = '';
|
||||
if (!data_source_link_id) {
|
||||
return '';
|
||||
}
|
||||
// 判断数据源链接ID是否包含分号,包含则表示有多个ID
|
||||
if (data_source_link_id.includes(';')) {
|
||||
// 分割数据源链接ID,处理多个ID
|
||||
const ids = data_source_link_id.split(';');
|
||||
let source_url = '';
|
||||
// 遍历每个ID,获取对应的属性值并拼接成URL
|
||||
ids.forEach((item, index) => {
|
||||
// 判断数据源列表是否为空
|
||||
if (!isEmpty(propSourceList.data)) {
|
||||
// 从数据源列表的data属性中获取嵌套属性值,并使用指定的连接符连接
|
||||
source_url += get_nested_property(propSourceList.data, item) + (index != ids.length -1 ? (source_link_option?.join || '') : '');
|
||||
} else {
|
||||
// 直接从数据源列表中获取嵌套属性值,并使用指定的连接符连接
|
||||
source_url += get_nested_property(propSourceList, item) + (index != ids.length -1 ? (source_link_option?.join || '') : '');
|
||||
}
|
||||
});
|
||||
url = source_url;
|
||||
} else {
|
||||
// 处理单个ID的情况
|
||||
if (!isEmpty(propSourceList.data)) {
|
||||
// 从数据源列表的data属性中获取嵌套属性值作为URL
|
||||
url = get_nested_property(propSourceList.data, data_source_link_id);
|
||||
} else {
|
||||
// 直接从数据源列表中获取嵌套属性值作为URL
|
||||
url = get_nested_property(propSourceList, data_source_link_id);
|
||||
}
|
||||
}
|
||||
// 返回最终的URL,添加首尾的可选字符串
|
||||
return (source_link_option?.first || '') + url + (source_link_option?.last || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 指示器的样式
|
||||
*
|
||||
* @param style_object 样式对象
|
||||
* @returns 返回对应的值
|
||||
*/
|
||||
export function get_indicator_style(style_object) {
|
||||
const { indicator_radius, indicator_style, indicator_size, color, indicator_new_location } = style_object;
|
||||
let styles = '';
|
||||
if (!isEmpty(indicator_radius)) {
|
||||
styles += radius_computer(indicator_radius);
|
||||
}
|
||||
// 数字类型的指示器
|
||||
if (indicator_style == 'num') {
|
||||
styles += `color: ${color || '#DDDDDD'};`;
|
||||
styles += `font-size: ${indicator_size * 2}rpx;`;
|
||||
} else if (indicator_style == 'elliptic') {
|
||||
// 宽的指示器,按照宽高1:3 来计算
|
||||
styles += `background: ${color || '#DDDDDD'};`;
|
||||
if (['left', 'right'].includes(indicator_new_location)) {
|
||||
styles += `width: ${indicator_size * 2 }rpx; height: ${indicator_size * 6}rpx;`;
|
||||
} else {
|
||||
styles += `width: ${indicator_size * 6}rpx; height: ${indicator_size * 2}rpx;`;
|
||||
}
|
||||
} else {
|
||||
// 圆点指示器
|
||||
styles += `background: ${color || '#DDDDDD'};`;
|
||||
styles += `width: ${indicator_size * 2}rpx; height: ${indicator_size * 2}rpx;`;
|
||||
}
|
||||
return styles;
|
||||
}
|
||||
/**
|
||||
* 指示器的位置处理
|
||||
*
|
||||
* @param style_object 样式对象
|
||||
* @returns 返回对应的值
|
||||
*/
|
||||
export function get_indicator_location_style(style_object) {
|
||||
const { indicator_new_location, indicator_location, indicator_bottom } = style_object;
|
||||
let styles = '';
|
||||
if (['left', 'right'].includes(indicator_new_location)) {
|
||||
if (indicator_location == 'flex-start') {
|
||||
styles += `top: 0px;`;
|
||||
} else if (indicator_location == 'center') {
|
||||
styles += `top: 50%; transform: translateY(-50%);`;
|
||||
} else {
|
||||
styles += `bottom: 0px;`;
|
||||
}
|
||||
} else {
|
||||
if (indicator_location == 'flex-start') {
|
||||
styles += `left: 0px;`;
|
||||
} else if (indicator_location == 'center') {
|
||||
styles += `left: 50%; transform: translateX(-50%);`;
|
||||
} else {
|
||||
styles += `right: 0px;`;
|
||||
}
|
||||
}
|
||||
// 如果有位置的处理,就使用指示器的位置处理,否则的话就用下边距处理
|
||||
styles += `${ !isEmpty(indicator_new_location) ? `${indicator_new_location}: ${ indicator_bottom }px;` : `bottom: ${ indicator_bottom }px;` }`;
|
||||
return styles;
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断对象数组等是否为空。
|
||||
*/
|
||||
export function isEmpty(value) {
|
||||
return (
|
||||
value === null ||
|
||||
value === undefined ||
|
||||
value === '' ||
|
||||
value === NaN ||
|
||||
(Array.isArray(value) && value.length === 0) ||
|
||||
(typeof value === 'object' && Object.keys(value).length === 0)
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 检查给定的参数是否为对象
|
||||
*
|
||||
* 此函数用于精确地验证一个变量是否为对象类型它通过以下步骤实现:
|
||||
* 1. 特殊处理 `null` 值,因为 `null` 在 JavaScript 中被当作对象处理,但实质上它不是
|
||||
* 2. 使用 `typeof` 操作符初步判断变量是否为对象
|
||||
* 3. 使用 `Object.prototype.toString.call(obj)` 方法精确判断变量是否为普通的对象
|
||||
*
|
||||
* @param obj 未知类型的参数,待检查是否为对象
|
||||
* @returns 如果参数是对象,则返回 true;否则返回 false
|
||||
*/
|
||||
export function is_obj(obj) {
|
||||
// 特殊处理 null值,因为 typeof null 返回 "object",但 null 并不是我们要检查的对象
|
||||
if (obj === null) return false;
|
||||
// 使用 typeof 排除非对象类型
|
||||
if (typeof obj !== 'object') return false;
|
||||
// 确认是普通对象
|
||||
return Object.prototype.toString.call(obj) === '[object Object]';
|
||||
}
|
||||
/**
|
||||
* 渐变色的方法
|
||||
* color_list: [] 渐变色的存储
|
||||
* direction 渐变色的角度
|
||||
* @param {string[], string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
export function gradient_computer(new_style, is_return_all = true) {
|
||||
let color_list = new_style.color_list;
|
||||
let direction = new_style.direction;
|
||||
return gradient_handle(color_list, direction, is_return_all);
|
||||
}
|
||||
/**
|
||||
* 根据给定的颜色列表和方向生成一个线性渐变的CSS样式字符串。
|
||||
*
|
||||
* @param color_list 颜色列表,包含渐变中的各个颜色值。
|
||||
* @param direction 渐变的方向,可以是角度或其他CSS支持的渐变方向。
|
||||
* @param is_return_all 是否返回所有样式,包括渐变类型、颜色列表和方向。默认为false,只返回渐变样式。
|
||||
* @returns 返回一个字符串,包含生成的线性渐变样式。
|
||||
*/
|
||||
export function gradient_handle(color_list, direction, is_return_all = true) {
|
||||
let container_common_styles = ``;
|
||||
if (color_list && color_list.length > 0) {
|
||||
if (is_return_all) {
|
||||
container_common_styles += `background:`;
|
||||
}
|
||||
container_common_styles += `linear-gradient(${direction || '180deg'},`;
|
||||
const new_color_list = JSON.parse(JSON.stringify(color_list));
|
||||
new_color_list.forEach((item, index) => {
|
||||
container_common_styles += `${item.color ? item.color : 'rgb(255 255 255 / 0%)'}`;
|
||||
if (color_list.length == 1) {
|
||||
container_common_styles += ` ${item.color_percentage || 0}%, ${item.color ? item.color : 'rgb(255 255 255 / 0%)'} 100%`;
|
||||
} else {
|
||||
if (typeof item.color_percentage === 'number') {
|
||||
if (index == color_list.length - 1) {
|
||||
container_common_styles += ` ${item.color_percentage}%`;
|
||||
} else {
|
||||
container_common_styles += ` ${item.color_percentage}%,`;
|
||||
}
|
||||
} else {
|
||||
if (index == color_list.length - 1) {
|
||||
container_common_styles += ` 100%`;
|
||||
} else if (index == 0) {
|
||||
container_common_styles += ` 0%,`;
|
||||
} else {
|
||||
container_common_styles += ` ${(100 / color_list.length) * index}%,`;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
container_common_styles += `)`;
|
||||
if (is_return_all) {
|
||||
container_common_styles += `;`;
|
||||
}
|
||||
}
|
||||
return container_common_styles;
|
||||
}
|
||||
/**
|
||||
* 设置内边距的方法
|
||||
* new_style: 内边距的集合
|
||||
* @param {string[], string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
export function padding_computer(new_style, scale = 1, is_custom = false, index) {
|
||||
if (new_style) {
|
||||
if (!is_custom) {
|
||||
let padding_top = '';
|
||||
if (index == 0) {
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
let sticky_top = 0;
|
||||
// #ifdef MP
|
||||
sticky_top = bar_height + 5 + 10;
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
sticky_top = bar_height + 7 + 10;
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
sticky_top = bar_height + 0 + 10;
|
||||
// #endif
|
||||
padding_top = `padding-top:calc(${new_style.padding_top * 2 || 0}rpx + ${sticky_top}px);`;
|
||||
}
|
||||
return `padding: ${new_style.padding_top * 2 || 0}rpx ${new_style.padding_right * 2 || 0}rpx ${new_style.padding_bottom * 2 || 0}rpx ${new_style.padding_left * 2 || 0}rpx;` + padding_top;
|
||||
} else {
|
||||
return `padding: ${new_style.padding_top * scale || 0}px ${new_style.padding_right * scale || 0}px ${new_style.padding_bottom * scale || 0}px ${new_style.padding_left * scale || 0}px;`;
|
||||
}
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 设置外边距的方法
|
||||
* new_style: 外边距的集合
|
||||
* @param {string[], string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
export function margin_computer(new_style) {
|
||||
return `margin: ${new_style.margin_top * 2 || 0}rpx ${new_style.margin_right * 2 || 0}rpx ${new_style.margin_bottom * 2 || 0}rpx ${new_style.margin_left * 2 || 0}rpx;`;
|
||||
}
|
||||
/**
|
||||
* 设置圆角的方法
|
||||
* new_style: 外边距的集合
|
||||
* @param {string[], string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
export function radius_computer(new_style, scale = 1, is_custom = false) {
|
||||
if (new_style) {
|
||||
if (!is_custom) {
|
||||
return `border-radius: ${new_style.radius_top_left * 2 || 0}rpx ${new_style.radius_top_right * 2 || 0}rpx ${new_style.radius_bottom_right * 2 || 0}rpx ${new_style.radius_bottom_left * 2 || 0}rpx;`;
|
||||
} else {
|
||||
return `border-radius: ${new_style.radius_top_left * scale || 0}px ${new_style.radius_top_right * scale || 0}px ${new_style.radius_bottom_right * scale || 0}px ${new_style.radius_bottom_left * scale || 0}px;`;
|
||||
}
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 设置阴影样式
|
||||
* new_style: 外边距的集合
|
||||
* @param {string[], string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
export function box_shadow_computer(new_style) {
|
||||
return `box-shadow: ${new_style.box_shadow_x * 2 || 0}rpx ${new_style.box_shadow_y * 2 || 0}rpx ${new_style.box_shadow_blur * 2 || 0}rpx ${new_style.box_shadow_spread * 2 || 0}rpx ${new_style.box_shadow_color || 'rgba(0,0,0,0)'};`;
|
||||
}
|
||||
/**
|
||||
* 设置阴影样式
|
||||
* new_style: 外边距的集合
|
||||
* @param {string[], string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
export function background_computer(new_style) {
|
||||
if (new_style.background_img.length > 0) {
|
||||
let url_styke = '';
|
||||
if (new_style.background_img_style == '1') {
|
||||
url_styke = 'background-repeat: repeat;';
|
||||
} else if (new_style.background_img_style == '2') {} else {
|
||||
url_styke = `background-repeat: no-repeat;background-position: center;`;
|
||||
}
|
||||
switch (new_style.background_img_style) {
|
||||
case '1':
|
||||
url_styke = `background-repeat: no-repeat;background-position: bottom;background-size: 100% auto;`;
|
||||
break;
|
||||
case '2':
|
||||
url_styke = `background-repeat: no-repeat;background-position: center;background-size: 100% auto;`;
|
||||
break;
|
||||
case '3':
|
||||
url_styke = 'background-repeat: repeat;';
|
||||
break;
|
||||
case '4':
|
||||
url_styke = 'background-size: cover;background-position: center;';
|
||||
break;
|
||||
default:
|
||||
url_styke = `background-repeat: no-repeat;background-position: top;background-size: 100% auto;`;
|
||||
break;
|
||||
}
|
||||
return `background-image:url(${new_style.background_img[0].url});${url_styke}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算并返回边框的样式字符串
|
||||
*
|
||||
* 此函数根据传入的新样式对象,决定是否显示边框以及边框的样式细节
|
||||
* 如果边框需要显示,函数会构造相应的边框样式字符串,包括边框的宽度、样式和颜色;
|
||||
* 如果边框不需要显示,则返回空字符串
|
||||
*
|
||||
* @param {Object} new_style - 新样式对象,包含边框的相关属性
|
||||
* @returns {String} 边框样式字符串或空字符串
|
||||
*/
|
||||
export const border_computer = (new_style) => {
|
||||
// 从新样式对象中解构边框的相关属性,并设置默认值
|
||||
const { border_is_show = '0', border_color = '', border_style = 'solid', border_size = { padding: 0, padding_bottom: 0, padding_left: 0, padding_right: 0, padding_top: 0 } } = new_style;
|
||||
|
||||
// 根据边框是否需要显示的标志,决定是否构造并返回边框样式字符串
|
||||
if (border_is_show == '1') {
|
||||
return `border-width: ${border_size.padding_top}px ${border_size.padding_right}px ${border_size.padding_bottom}px ${border_size.padding_left}px;border-style: ${ border_style };border-color: ${border_color};`
|
||||
}
|
||||
|
||||
// 如果边框不需要显示,返回空字符串
|
||||
return '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算并组合组件的常用样式。
|
||||
*
|
||||
* 该函数通过调用一系列特定样式的计算函数,来组装一个组件的常用样式字符串。
|
||||
* 这些样式包括渐变色、内边距、外边距、圆角和阴影等,为组件提供了一套完整的外观定义。
|
||||
*
|
||||
* @param new_style 组件的新样式对象,包含了需要计算的样式属性。
|
||||
* @param scale 一个缩放比例,用于控制样式的缩放,默认为1。
|
||||
* @param scale 用于控制样式的缩放比例,默认为1,表示不进行缩放。
|
||||
* @param is_custom 一个布尔值,用于判断是否为自定义样式,默认为false。
|
||||
* @param index 用于标识组件的索引,默认为0。
|
||||
* @returns 返回一个字符串,包含了计算后的样式定义,可以被直接应用于组件的样式属性。
|
||||
*/
|
||||
export function common_styles_computer(new_style) {
|
||||
return gradient_computer(new_style) + margin_computer(new_style) + radius_computer(new_style) + box_shadow_computer(new_style) + border_computer(new_style) + `overflow:hidden;`;
|
||||
}
|
||||
export function common_img_computer(new_style, index, bool) {
|
||||
return padding_computer(new_style, 1, false, index, bool) + background_computer(new_style) + `overflow:hidden;box-sizing: border-box;`;
|
||||
}
|
||||
/**
|
||||
* 生成一个随机数学字符串。
|
||||
* @returns {string} 一个6位的36进制随机字符串。
|
||||
*/
|
||||
export function get_math() {
|
||||
// 通过Math.random()生成随机数,并转换为36进制的字符串
|
||||
let randomString = Math.random().toString(36);
|
||||
// 确保随机字符串至少有6位,因为substring(2)可能会使短于6位的字符串产生错误。
|
||||
// 如果字符串长度不足6位,通过padStart将其前面填充为0,直到长度达到6位。
|
||||
randomString = randomString.length >= 6 ? randomString : randomString.padStart(6, '0');
|
||||
// 截取掉随机字符串开头的'0.'部分,获得最终的6位随机字符串。
|
||||
return randomString.substring(2);
|
||||
}
|
||||
/**
|
||||
* 将大小计算成百分比
|
||||
*
|
||||
* @param num 当前的大小或位置。
|
||||
* @param size 容器的大小。
|
||||
* @returns 计算后的百分比值,含4位小数
|
||||
*/
|
||||
export const percentage_count = (num, container_size) => {
|
||||
const marks = (num / container_size) * 100;
|
||||
return marks.toFixed(4) + '%';
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算当前偏移量
|
||||
*
|
||||
* @param size 当前的组件的大小宽或者高。
|
||||
* @param location 容器的位置的偏移量。
|
||||
* @param container_size 对应位置的容器的大小
|
||||
* @returns 偏移量
|
||||
*/
|
||||
export const location_compute = (size, location, container_size) => {
|
||||
if (size + location >= container_size) {
|
||||
const deviation = container_size - size;
|
||||
if (deviation >= 0) {
|
||||
return deviation;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return location;
|
||||
}
|
||||
};
|
||||
47
common/js/common/share.js
Normal file
47
common/js/common/share.js
Normal file
@@ -0,0 +1,47 @@
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
// 设置默认的分享参数、页面可自定义以下数据
|
||||
// 如果页面不设置share,就触发这个默认的分享
|
||||
// 标题、关键字、描述、地址、参数、封面图片、视频
|
||||
share_info: {
|
||||
title: '',
|
||||
kds: '',
|
||||
desc: '',
|
||||
path: '',
|
||||
query: '',
|
||||
img: '',
|
||||
video: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 分享给好友
|
||||
onShareAppMessage() {
|
||||
var app = getApp();
|
||||
var share = app.globalData.share_content_handle(this.share_info || {});
|
||||
var data = {
|
||||
title: share.title,
|
||||
desc: share.desc,
|
||||
path: share.path + share.query
|
||||
}
|
||||
if(app.globalData.data.is_share_use_image == 1) {
|
||||
data['imageUrl'] = share.img;
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
// 分享朋友圈
|
||||
onShareTimeline() {
|
||||
var app = getApp();
|
||||
var share = app.globalData.share_content_handle(this.share_info || {});
|
||||
var data = {
|
||||
title: share.title,
|
||||
query: ((share.query || null) != null && share.query.substr(0, 1) == '?') ? share.query.slice(1) : share.query
|
||||
};
|
||||
if(app.globalData.data.is_share_use_image == 1) {
|
||||
data['imageUrl'] = share.img;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
8
common/js/lib/base64.js
Normal file
8
common/js/lib/base64.js
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Minified by jsDelivr using Terser v5.7.1.
|
||||
* Original file: /npm/js-base64@3.7.2/base64.js
|
||||
*
|
||||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||
*/
|
||||
!function(t,n){var r,e;"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(r=t.Base64,(e=n()).noConflict=function(){return t.Base64=r,e},t.Meteor&&(Base64=e),t.Base64=e)}("undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this,(function(){"use strict";var t,n="3.7.2",r="function"==typeof atob,e="function"==typeof btoa,o="function"==typeof Buffer,u="function"==typeof TextDecoder?new TextDecoder:void 0,i="function"==typeof TextEncoder?new TextEncoder:void 0,f=Array.prototype.slice.call("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="),c=(t={},f.forEach((function(n,r){return t[n]=r})),t),a=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/,d=String.fromCharCode.bind(String),s="function"==typeof Uint8Array.from?Uint8Array.from.bind(Uint8Array):function(t,n){return void 0===n&&(n=function(t){return t}),new Uint8Array(Array.prototype.slice.call(t,0).map(n))},l=function(t){return t.replace(/=/g,"").replace(/[+\/]/g,(function(t){return"+"==t?"-":"_"}))},h=function(t){return t.replace(/[^A-Za-z0-9\+\/]/g,"")},p=function(t){for(var n,r,e,o,u="",i=t.length%3,c=0;c<t.length;){if((r=t.charCodeAt(c++))>255||(e=t.charCodeAt(c++))>255||(o=t.charCodeAt(c++))>255)throw new TypeError("invalid character found");u+=f[(n=r<<16|e<<8|o)>>18&63]+f[n>>12&63]+f[n>>6&63]+f[63&n]}return i?u.slice(0,i-3)+"===".substring(i):u},y=e?function(t){return btoa(t)}:o?function(t){return Buffer.from(t,"binary").toString("base64")}:p,A=o?function(t){return Buffer.from(t).toString("base64")}:function(t){for(var n=[],r=0,e=t.length;r<e;r+=4096)n.push(d.apply(null,t.subarray(r,r+4096)));return y(n.join(""))},b=function(t,n){return void 0===n&&(n=!1),n?l(A(t)):A(t)},g=function(t){if(t.length<2)return(n=t.charCodeAt(0))<128?t:n<2048?d(192|n>>>6)+d(128|63&n):d(224|n>>>12&15)+d(128|n>>>6&63)+d(128|63&n);var n=65536+1024*(t.charCodeAt(0)-55296)+(t.charCodeAt(1)-56320);return d(240|n>>>18&7)+d(128|n>>>12&63)+d(128|n>>>6&63)+d(128|63&n)},B=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,x=function(t){return t.replace(B,g)},C=o?function(t){return Buffer.from(t,"utf8").toString("base64")}:i?function(t){return A(i.encode(t))}:function(t){return y(x(t))},m=function(t,n){return void 0===n&&(n=!1),n?l(C(t)):C(t)},v=function(t){return m(t,!0)},U=/[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g,F=function(t){switch(t.length){case 4:var n=((7&t.charCodeAt(0))<<18|(63&t.charCodeAt(1))<<12|(63&t.charCodeAt(2))<<6|63&t.charCodeAt(3))-65536;return d(55296+(n>>>10))+d(56320+(1023&n));case 3:return d((15&t.charCodeAt(0))<<12|(63&t.charCodeAt(1))<<6|63&t.charCodeAt(2));default:return d((31&t.charCodeAt(0))<<6|63&t.charCodeAt(1))}},w=function(t){return t.replace(U,F)},S=function(t){if(t=t.replace(/\s+/g,""),!a.test(t))throw new TypeError("malformed base64.");t+="==".slice(2-(3&t.length));for(var n,r,e,o="",u=0;u<t.length;)n=c[t.charAt(u++)]<<18|c[t.charAt(u++)]<<12|(r=c[t.charAt(u++)])<<6|(e=c[t.charAt(u++)]),o+=64===r?d(n>>16&255):64===e?d(n>>16&255,n>>8&255):d(n>>16&255,n>>8&255,255&n);return o},E=r?function(t){return atob(h(t))}:o?function(t){return Buffer.from(t,"base64").toString("binary")}:S,D=o?function(t){return s(Buffer.from(t,"base64"))}:function(t){return s(E(t),(function(t){return t.charCodeAt(0)}))},R=function(t){return D(T(t))},z=o?function(t){return Buffer.from(t,"base64").toString("utf8")}:u?function(t){return u.decode(D(t))}:function(t){return w(E(t))},T=function(t){return h(t.replace(/[-_]/g,(function(t){return"-"==t?"+":"/"})))},Z=function(t){return z(T(t))},j=function(t){return{value:t,enumerable:!1,writable:!0,configurable:!0}},I=function(){var t=function(t,n){return Object.defineProperty(String.prototype,t,j(n))};t("fromBase64",(function(){return Z(this)})),t("toBase64",(function(t){return m(this,t)})),t("toBase64URI",(function(){return m(this,!0)})),t("toBase64URL",(function(){return m(this,!0)})),t("toUint8Array",(function(){return R(this)}))},O=function(){var t=function(t,n){return Object.defineProperty(Uint8Array.prototype,t,j(n))};t("toBase64",(function(t){return b(this,t)})),t("toBase64URI",(function(){return b(this,!0)})),t("toBase64URL",(function(){return b(this,!0)}))},P={version:n,VERSION:"3.7.2",atob:E,atobPolyfill:S,btoa:y,btoaPolyfill:p,fromBase64:Z,toBase64:m,encode:m,encodeURI:v,encodeURL:v,utob:x,btou:w,decode:Z,isValid:function(t){if("string"!=typeof t)return!1;var n=t.replace(/\s+/g,"").replace(/={0,2}$/,"");return!/[^\s0-9a-zA-Z\+/]/.test(n)||!/[^\s0-9a-zA-Z\-_]/.test(n)},fromUint8Array:b,toUint8Array:R,extendString:I,extendUint8Array:O,extendBuiltins:function(){I(),O()},Base64:{}};return Object.keys(P).forEach((function(t){return P.Base64[t]=P[t]})),P}));
|
||||
//# sourceMappingURL=/sm/79de78edcfa94236e4c8354f91262971e185c3633bb865b6fc17942e93a40207.map
|
||||
71
components/activity-list/activity-list.vue
Normal file
71
components/activity-list/activity-list.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(propConfig || null) != null && (propData || null) != null && propData.length > 0">
|
||||
<block v-for="(floor, index) in propData" :key="index">
|
||||
<block v-if="floor.goods_list.length > 0 && floor.home_data_location == propLocation">
|
||||
<component-goods-list
|
||||
:propData="floor"
|
||||
propMoreUrlKey="url"
|
||||
:propLabel="propLabel"
|
||||
:propIsAutoPlay="(propConfig.is_home_auto_play || 0) == 1"
|
||||
:propCurrencySymbol="propCurrencySymbol"
|
||||
:propIsCartParaCurve="propIsCartParaCurve"
|
||||
:propSource="propSource"
|
||||
:propOpenCart="floor.style_type === '2' ? false : true"
|
||||
></component-goods-list>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentGoodsList from '@/components/goods-list/goods-list';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentGoodsList,
|
||||
},
|
||||
props: {
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol(),
|
||||
},
|
||||
propLocation: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
propConfig: {
|
||||
type: [String, Object],
|
||||
default: null,
|
||||
},
|
||||
propData: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
propLabel: {
|
||||
type: [Array, Object, String],
|
||||
default: null,
|
||||
},
|
||||
propIsCartParaCurve: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 来源
|
||||
propSource: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propOpenCart: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
242
components/app-admin/app-admin.vue
Normal file
242
components/app-admin/app-admin.vue
Normal file
@@ -0,0 +1,242 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<!-- 更新 -->
|
||||
<view v-if="is_update_status && (update_data || null) != null" class="update-container pf left-0 top-0 wh-auto ht-auto">
|
||||
<view class="update-content auto bg-white pr">
|
||||
<image :src="update_alert_bg_images" mode="widthFix" class="update-alert-bg-images wh-auto"></image>
|
||||
<view class="padding-top-xs padding-left-xl padding-right-xl padding-bottom-xl">
|
||||
<view class="text-size-xl fw-b tc pa name">{{update_data.name}}</view>
|
||||
<view class="text-size tc pa version">v{{update_data.version_new}}</view>
|
||||
<scroll-view :scroll-y="true" class="content tl">
|
||||
<block v-for="(item, index) in update_data.content" :key="index">
|
||||
<view class="margin-bottom-sm text-size-xs">{{item}}</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
<view class="margin-top-xl flex-row">
|
||||
<button v-if="(update_data.is_force_update || 0) == 0" type="default" class="br-main bg-white cr-main round text-size-md" size="mini" @tap="update_close_event">{{$t('common.cancel')}}</button>
|
||||
<button type="default" class="br-main bg-main cr-white round text-size-md" size="mini" @tap="to_update_event">{{$t('common.now_update_text')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 评分 -->
|
||||
<view v-if="is_star_status && (star_url || null) != null && (star_alert_images || null) != null" class="star-container pf left-0 top-0 wh-auto ht-auto tc">
|
||||
<view class="star-content">
|
||||
<image :src="star_alert_images" mode="widthFix" class="star-alert-images wh-auto" @tap="to_star_event"></image>
|
||||
</view>
|
||||
<view class="padding-sm margin-top-xl">
|
||||
<view class="dis-inline-block" @tap="close_star_event">
|
||||
<iconfont name="icon-close-o" size="30rpx" color="#ccc"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 关于我们中使用 -->
|
||||
<!-- #ifdef APP -->
|
||||
<view v-if="is_about_page && !propIsHideStar" class="margin-top">
|
||||
<text class="cr-grey-9">{{app_version_info}}</text>
|
||||
<block v-if="is_loading">
|
||||
<text v-if="(update_data || null) == null" class="cr-grey-c margin-left-lg text-size-xs">{{$t('common.already_latest_text')}}</text>
|
||||
<text v-else class="cr-blue margin-left-lg text-size-xs cp" @tap="update_event">{{$t('common.to_update_text')}}(v{{update_data.version_new}})</text>
|
||||
<text v-if="(star_url || null) != null && (star_alert_images || null) != null" class="cr-blue margin-left-lg text-size-xs cp" @tap="star_event">{{$t('common.to_star_text')}}</text>
|
||||
</block>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
update_tips_cache_key: app.globalData.data.cache_app_update_tips_interval_time_key,
|
||||
star_tips_cache_key: app.globalData.data.cache_app_star_tips_interval_time_key,
|
||||
app_version_info: app.globalData.data.app_version_info,
|
||||
is_about_page: false,
|
||||
is_loading: false,
|
||||
update_data: null,
|
||||
// 更新提示
|
||||
is_update_status: false,
|
||||
update_tips_interval_time: 0,
|
||||
update_alert_bg_images: null,
|
||||
// 评分提示
|
||||
is_star_status: false,
|
||||
star_tips_await_time: 0,
|
||||
star_tips_interval_time: 0,
|
||||
star_alert_images: null,
|
||||
star_url: null
|
||||
|
||||
};
|
||||
},
|
||||
props: {
|
||||
propIsHideStar: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.init();
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化、获取数据
|
||||
init(is_init = 0) {
|
||||
// #ifdef APP
|
||||
// 是否关于我们页面
|
||||
this.setData({
|
||||
is_about_page: app.globalData.current_page(false) == 'pages/about/about',
|
||||
});
|
||||
|
||||
// 请求接口获取版本数据
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('index', 'version', 'appadmin'),
|
||||
method: 'POST',
|
||||
data: {app_version: app.globalData.data.app_version_info},
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if(res.data.code == 0) {
|
||||
var data = res.data.data;
|
||||
var upd_data = {
|
||||
is_loading: true,
|
||||
update_data: data.update_data || null,
|
||||
// 更新提示
|
||||
update_alert_bg_images: data.update_alert_bg_images || null,
|
||||
is_update_status: parseInt(data.is_update_status || 0) == 1,
|
||||
update_tips_interval_time: parseInt(data.update_tips_interval_time || 600),
|
||||
// 评分提示
|
||||
is_star_status: parseInt(data.is_star_status || 0) == 1,
|
||||
star_tips_await_time: parseInt(data.star_tips_await_time || 600),
|
||||
star_tips_interval_time: parseInt(data.star_tips_interval_time || 1800),
|
||||
star_alert_images: data.star_alert_images || null,
|
||||
star_url: data.star_url || null,
|
||||
};
|
||||
|
||||
// 当前时间
|
||||
var current_time = Date.parse(new Date()) / 1000;
|
||||
|
||||
// 更新提示间隔时间
|
||||
var update_tips_cache_time = parseInt(uni.getStorageSync(this.update_tips_cache_key) || 0);
|
||||
if(update_tips_cache_time > 0 && current_time < update_tips_cache_time + upd_data.update_tips_interval_time) {
|
||||
upd_data.is_update_status = false;
|
||||
}
|
||||
|
||||
// 评分是否可以展示评分
|
||||
var star_tips_cache_time = parseInt(uni.getStorageSync(this.star_tips_cache_key) || 0);
|
||||
if(star_tips_cache_time > 0) {
|
||||
upd_data.is_star_status = current_time > star_tips_cache_time;
|
||||
}
|
||||
// 首次则记录评分缓存
|
||||
if(star_tips_cache_time == 0) {
|
||||
uni.setStorageSync(this.star_tips_cache_key, (Date.parse(new Date()) / 1000)+upd_data.star_tips_await_time);
|
||||
// 如果等待时间为0则不需要等待就提示评分
|
||||
if(upd_data.star_tips_await_time == 0) {
|
||||
upd_data.is_star_status = true;
|
||||
}
|
||||
}
|
||||
// 如果已经展示更新弹窗则不展示评分弹窗
|
||||
if(upd_data.is_update_status) {
|
||||
upd_data.is_star_status = false;
|
||||
}
|
||||
|
||||
// 关于我们页面则不直接展示
|
||||
if(this.is_about_page) {
|
||||
upd_data.is_update_status = false;
|
||||
upd_data.is_star_status = false;
|
||||
}
|
||||
|
||||
this.setData(upd_data);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 失败则再重试一次
|
||||
if(is_init == 0) {
|
||||
this.get_data(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
|
||||
// 更新关闭
|
||||
update_close_event(e) {
|
||||
this.setData({
|
||||
is_update_status: false
|
||||
});
|
||||
uni.setStorageSync(this.update_tips_cache_key, Date.parse(new Date()) / 1000);
|
||||
},
|
||||
|
||||
// 打开更新事件
|
||||
update_event(e) {
|
||||
this.setData({
|
||||
is_update_status: true
|
||||
});
|
||||
},
|
||||
|
||||
// 去更新事件
|
||||
to_update_event(e) {
|
||||
plus.runtime.openURL(this.update_data.update_url);
|
||||
},
|
||||
|
||||
// 打开评分事件
|
||||
star_event(e) {
|
||||
this.setData({
|
||||
is_star_status: true
|
||||
});
|
||||
},
|
||||
|
||||
// 去打分事件
|
||||
to_star_event(e) {
|
||||
// 先关闭评分
|
||||
this.close_star_event();
|
||||
|
||||
// 打开地址
|
||||
plus.runtime.openURL(this.star_url);
|
||||
},
|
||||
|
||||
// 关闭评分事件
|
||||
close_star_event(e) {
|
||||
this.setData({
|
||||
is_star_status: false
|
||||
});
|
||||
// 增加间隔时间,到时间后才会再提示
|
||||
uni.setStorageSync(this.star_tips_cache_key, (Date.parse(new Date()) / 1000)+this.star_tips_interval_time);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.update-container,
|
||||
.star-container {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
z-index: 100;
|
||||
padding-top: 26vh;
|
||||
}
|
||||
.update-container .update-content {
|
||||
width: 75vw;
|
||||
padding-top: 100rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
.update-container .update-content .update-alert-bg-images {
|
||||
margin-top: -180rpx;
|
||||
}
|
||||
.update-container .update-content .name {
|
||||
left: 36rpx;
|
||||
top: 60rpx;
|
||||
}
|
||||
.update-container .update-content .version {
|
||||
left: 36rpx;
|
||||
top: 140rpx;
|
||||
}
|
||||
.update-container .update-content .content {
|
||||
max-height: 26vh;
|
||||
}
|
||||
.star-container .star-content {
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
.star-container .star-content .star-alert-images {
|
||||
max-width: 460rpx;
|
||||
}
|
||||
</style>
|
||||
103
components/ask-comments-goods/ask-comments-goods.vue
Normal file
103
components/ask-comments-goods/ask-comments-goods.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<block v-if="(propData || null) != null && propData.length > 0">
|
||||
<view v-for="(item, index) in propData" :key="index" class="ask-comment-item">
|
||||
<view :data-value="item.url" @tap="url_event" class="flex-row cp">
|
||||
<view class="title cr-white tc">{{$t('goods-list.goods-list.00n7i3')}}</view>
|
||||
<view class="base-nav flex-1 flex-width margin-left-sm">
|
||||
<view class="oh nav padding-bottom-sm">
|
||||
<view class="flex-row jc-sb align-c">
|
||||
<text class="va-m single-text flex-1 flex-width">{{ item.title || item.content }}</text>
|
||||
<text class="cr-grey text-size-xs">{{$t('detail.detail.025362')}}{{ item.comments_count }}{{$t('ask-comments-goods.ask-comments-goods.xl51n6')}}</text>
|
||||
</view>
|
||||
<view v-if="(item.images || null) != null && item.images.length > 0" class="images oh margin-top-lg">
|
||||
<block v-for="(iv, ix) in item.images" :key="ix">
|
||||
<image class="br radius margin-right-sm" @tap="comment_images_show_event" :data-index="index" :data-ix="ix" :src="iv" mode="aspectFit"></image>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="cr-grey-d tc spacing-mb flex-row jc-c align-c">
|
||||
<image :src="ask_static_url + 'no-ask.png'" mode="widthFix" class="no-ask margin-right-main" />{{$t('ask-comments-goods.ask-comments-goods.g6mc44')}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
var ask_static_url = app.globalData.get_static_url('ask', true) + 'app/';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
ask_static_url:ask_static_url,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
propData: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
created: function () {},
|
||||
|
||||
methods: {
|
||||
// 评价图片预览
|
||||
comment_images_show_event(e) {
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var ix = e.currentTarget.dataset.ix;
|
||||
uni.previewImage({
|
||||
current: this.propData[index]["images"][ix],
|
||||
urls: this.propData[index]["images"],
|
||||
});
|
||||
},
|
||||
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
/**
|
||||
* 商品评价
|
||||
*/
|
||||
.title {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
background: #fd9525;
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
.ask-comment-item {
|
||||
padding-bottom: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.ask-comment-item .avatar {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #e2e2e2;
|
||||
}
|
||||
.ask-comment-item .base-nav {
|
||||
border-bottom: 2rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.ask-comment-item:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ask-comment-item:last-of-type .base-nav {
|
||||
border: 0;
|
||||
}
|
||||
.no-ask {
|
||||
width: 174rpx;
|
||||
}
|
||||
</style>
|
||||
55
components/badge/badge.vue
Normal file
55
components/badge/badge.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="propNumber != 0" class="am-badge">
|
||||
<view :class="'am-badge-text ' + ((propNumber > 99) ? 'am-badge-text-max' : '')">
|
||||
<text>{{(propNumber > 99) ? '99+' : propNumber}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propNumber: {
|
||||
type: [Number,String],
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.am-badge {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.am-badge-text {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
transform: translate(50%, -50%);
|
||||
top: 0;
|
||||
min-width: 28rpx;
|
||||
padding: 0;
|
||||
height: 28rpx;
|
||||
line-height: 28rpx;
|
||||
text-align: center;
|
||||
background-color: #FF3B30;
|
||||
border-radius: 40rpx;
|
||||
color: #fff;
|
||||
font-size: 20rpx;
|
||||
padding: 2rpx 2rpx;
|
||||
box-shadow: 0 0 10rpx rgb(0 0 0 / 30%);
|
||||
}
|
||||
.am-badge-text-max {
|
||||
padding: 2rpx 4rpx;
|
||||
}
|
||||
</style>
|
||||
98
components/binding-detail-list/binding-detail-list.vue
Normal file
98
components/binding-detail-list/binding-detail-list.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="((propData || null) != null)" class="plugins-binding-container">
|
||||
<!-- 组合搭配 -->
|
||||
<block v-if="((propData.binding_list || null) != null)">
|
||||
<block v-for="(bv, bi) in propData.binding_list" :key="bi">
|
||||
<view v-if="((bv.goods || null) != null) && bv.goods.length > 0" class="plugins-binding-list padding-horizontal-main padding-top-main border-radius-main oh spacing-mb">
|
||||
<view class="spacing-nav-title oh">
|
||||
<text class="text-wrapper">{{bv.title}}</text>
|
||||
<view v-if="(bv.estimate_discount_price || 0) != 0" class="estimate-discount-price fr">
|
||||
<text class="discount-icon cr-white text-size-xs">{{$t('detail.detail.6026t4')}}</text>
|
||||
<text class="cr-green text-size-lg va-m">{{propCurrencySymbol}}{{bv.estimate_discount_price}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="left-content fl">
|
||||
<component-goods-list :propData="{style_type: 2, goods_list: bv.goods, multiple_items: 2}" :propOpenCart="false" :propLabel="propLabel" :propCurrencySymbol="propCurrencySymbol" :propIsAutoPlay="(propData.config.is_auto_play || 0) == 1"></component-goods-list>
|
||||
</view>
|
||||
<view class="right-content fr bs-bb padding-left-main tc">
|
||||
<button type="default" size="mini" class="bg-main br-main cr-white text-size-xs round" :data-value="'/pages/plugins/binding/detail/detail?id='+bv.id" @tap="url_event">{{bv.buy_button_text}}</button>
|
||||
<view class="sales-price margin-top-sm">{{propCurrencySymbol}}{{bv.estimate_price}}</view>
|
||||
<view v-if="(bv.estimate_original_price || 0) != 0" class="original-price margin-top-sm">{{propCurrencySymbol}}{{bv.estimate_original_price}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</block>
|
||||
|
||||
<!-- 商品关联 -->
|
||||
<view v-if="((propData.relevant_data || null) != null)">
|
||||
<component-goods-list :propData="{title: propData.relevant_data.name, style_type: 2, goods_list: propData.relevant_data.data}" :propLabel="propLabel" :propCurrencySymbol="propCurrencySymbol" :propIsAutoPlay="(propData.config.is_auto_play_relevant || 0) == 1"></component-goods-list>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentGoodsList from "../goods-list/goods-list";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentGoodsList
|
||||
},
|
||||
props: {
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol()
|
||||
},
|
||||
propData: {
|
||||
type: [Array,Object],
|
||||
default: []
|
||||
},
|
||||
propLabel: {
|
||||
type: [Array,Object,String],
|
||||
default: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.plugins-binding-list {
|
||||
background: linear-gradient(to right, rgb(255 235 220), rgb(241 235 255));
|
||||
}
|
||||
.plugins-binding-list .left-content {
|
||||
width: 65%;
|
||||
}
|
||||
.plugins-binding-list .right-content {
|
||||
width: 35%;
|
||||
padding-top: 100rpx;
|
||||
}
|
||||
.plugins-binding-list .estimate-discount-price .discount-icon {
|
||||
border-top-right-radius: 30rpx;
|
||||
border-bottom-left-radius: 30rpx;
|
||||
background-image: linear-gradient(45deg,#a3f9a3,#248828,#8bc34a,#d2374c,#9c27b0);
|
||||
background-size: 400%;
|
||||
animation: gradient 5s ease infinite;
|
||||
padding: 0 16rpx;
|
||||
}
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
173
components/binding-list/binding-list.vue
Normal file
173
components/binding-list/binding-list.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(data_list || null) != null && data_list.length > 0" class="plugins-binding-data-list oh">
|
||||
<block v-for="(item, index) in data_list" :key="index">
|
||||
<view class="item border-radius-main bg-white padding-main oh pr spacing-mb">
|
||||
<view class="oh flex-row" :data-value="item.url" @tap="url_event">
|
||||
<image :src="item.images" mode="aspectFit" class="images dis-block border-radius-main"></image>
|
||||
<view class="flex-1 flex-width flex-col jc-sb">
|
||||
<view class="base-right bs-bb padding-left-main">
|
||||
<view class="fw-b text-size-lg cr-base single-text">{{ item.title }}</view>
|
||||
<view class="sales-price margin-top-main single-text">
|
||||
<text class="text-size-xs">{{ propCurrencySymbol }}</text>
|
||||
<text class="text-size-lg fw-b">{{ item.estimate_price }}</text>
|
||||
</view>
|
||||
<view v-if="(item.estimate_discount_price || 0) != 0" class="margin-top-sm single-text flex-row align-c">
|
||||
<text class="discount-icon cr-white text-size-xs">{{$t('detail.detail.6026t4')}}</text>
|
||||
<view class="cr-green single-text">
|
||||
<text class="text-size-xs">{{ propCurrencySymbol }}</text>
|
||||
<text class="text-size">{{ item.estimate_discount_price }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<button type="default" size="mini" class="br-main bg-main cr-white round buy-submit self-e margin-0 text-size-xs">{{ item.type_name }}{{$t('binding-list.binding-list.kh7951')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="binding-goods-list border-radius-main margin-top-main oh" :style="'height: ' + ((item.is_home_show_goods || 0) == 1 ? Math.ceil(item.goods.length / 2) * 134 + 12 : '0') + 'rpx'">
|
||||
<view class="padding-horizontal-main padding-top-main padding-bottom-main oh">
|
||||
<block v-for="(gv, gi) in item.goods" :key="gi">
|
||||
<view class="goods-item oh margin-bottom-lg" :data-value="gv.goods_url" @tap="url_event">
|
||||
<image :src="gv.images" mode="aspectFit" class="goods-images fl dis-block radius"></image>
|
||||
<view class="goods-right fr bs-bb">
|
||||
<view class="single-text text-size-sm">{{ gv.title }}</view>
|
||||
<view v-if="(gv.show_field_price_status || 0) == 1" class="single-text">
|
||||
<text class="sales-price va-m text-size-xss">{{ gv.show_price_symbol }}{{ gv.price }}</text>
|
||||
<text class="cr-grey va-m text-size-xsss">{{ gv.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="(gv.discount_price || null) != null" class="single-text cr-green text-size-xss">{{$t('detail.detail.6026t4')}}{{ gv.show_price_symbol }}{{ gv.discount_price }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bg-white padding-top-main wh-auto bs-bb bottom-elastic" :class="(item.is_home_show_goods || 0) != 1 ? 'br-t-dashed' : ''" :data-index="index" @tap="item_more_goods_event">
|
||||
<view class="flex-row jc-sb align-c">
|
||||
<view class="cr-grey-9 text-size-xs">{{ (item.is_home_show_goods || 0) == 1 ? $t('binding-list.binding-list.2u4v35') : $t('binding-list.binding-list.91d60h') }}{{ item.type_name }}{{$t('recommend-list.recommend-list.x74z3o')}}</view>
|
||||
<iconfont :name="(item.is_home_show_goods || 0) == 1 ? 'icon-arrow-top' : 'icon-arrow-bottom'" size="24rpx" color="#666"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
config: {},
|
||||
data_list: [],
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
// 价格符号
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol()
|
||||
},
|
||||
propConfig: {
|
||||
type: [String, Object],
|
||||
default: null,
|
||||
},
|
||||
propData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
}
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propData(value, old_value) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function(e) {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化
|
||||
init() {
|
||||
var config = ((this.propConfig || null) == null ? app.globalData.get_config('plugins_base.binding.data') : this.propConfig) || {};
|
||||
var data_list = ((this.propData || null) == null || (this.propData.data || null) == null || this.propData.data.length == 0) ? [] : this.propData.data;
|
||||
this.setData({
|
||||
config: config,
|
||||
data_list: data_list,
|
||||
});
|
||||
},
|
||||
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
|
||||
// 商品展开关闭
|
||||
item_more_goods_event(e) {
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var temp_data = this.data_list;
|
||||
temp_data[index]['is_home_show_goods'] = parseInt(temp_data[index]['is_home_show_goods'] || 0) == 1 ? 0 : 1;
|
||||
this.setData({ data_list: temp_data });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.plugins-binding-data-list .item .images {
|
||||
width: 256rpx;
|
||||
height: 256rpx !important;
|
||||
}
|
||||
.plugins-binding-data-list .item .base-right .discount-icon {
|
||||
border-top-right-radius: 30rpx;
|
||||
border-bottom-left-radius: 30rpx;
|
||||
background-image: linear-gradient(45deg, #a3f9a3, #248828, #8bc34a, #d2374c, #9c27b0);
|
||||
background-size: 400%;
|
||||
animation: gradient 5s ease infinite;
|
||||
padding: 0 16rpx;
|
||||
}
|
||||
.plugins-binding-data-list .item .buy-submit {
|
||||
padding: 0 20rpx;
|
||||
height: 46rpx;
|
||||
line-height: 44rpx;
|
||||
}
|
||||
.plugins-binding-data-list .item .binding-goods-list {
|
||||
background: #f8f8f8;
|
||||
transition: height 0.25s ease-in-out;
|
||||
}
|
||||
.plugins-binding-data-list .item .binding-goods-list .goods-item {
|
||||
width: calc(50% - 15rpx);
|
||||
height: 102rpx;
|
||||
}
|
||||
.plugins-binding-data-list .item .binding-goods-list .goods-item:nth-child(odd) {
|
||||
float: left;
|
||||
}
|
||||
.plugins-binding-data-list .item .binding-goods-list .goods-item:nth-child(even) {
|
||||
float: right;
|
||||
}
|
||||
.plugins-binding-data-list .item .binding-goods-list .goods-item .goods-right {
|
||||
width: calc(100% - 115rpx);
|
||||
}
|
||||
.plugins-binding-data-list .item .binding-goods-list .goods-item .goods-images {
|
||||
width: 100rpx;
|
||||
height: 100rpx !important;
|
||||
}
|
||||
.plugins-binding-data-list .item .bottom-elastic {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
99
components/blog-list/blog-list.vue
Normal file
99
components/blog-list/blog-list.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(propConfig || null) != null && (propData || null) != null && propData.length > 0">
|
||||
<block v-for="(floor, index) in propData" :key="index">
|
||||
<block v-if="floor.blog_list.length > 0 && floor.home_data_location == propLocation">
|
||||
<view class="plugins-blog" :class="floor.style_type == 2 ? 'bg-white border-radius-main padding-main spacing-mb' : ''">
|
||||
<view class="spacing-nav-title flex-row align-c jc-sb text-size-xs">
|
||||
<view class="title-left">
|
||||
<text class="text-wrapper" :class="floor.style_type == 2 ? '' : 'title-left-border'" :style="'color:' + (floor.color || '#333') + ';'">{{ floor.title }}</text>
|
||||
<text v-if="(floor.vice_title || null) != null" class="vice-name margin-left-sm cr-grey-9">{{ floor.vice_title }}</text>
|
||||
</view>
|
||||
<text :data-value="floor.more_url" @tap="url_event" class="arrow-right padding-right cr-grey cp">{{$t('common.more')}}</text>
|
||||
</view>
|
||||
<view class="wh-auto oh pr">
|
||||
<block v-if="floor.blog_list.length > 0">
|
||||
<!-- 默认图文 -->
|
||||
<block v-if="(floor.style_type || 0) == 0">
|
||||
<view class="plugins-blog-list">
|
||||
<view v-for="(item, index) in floor.blog_list" :key="index" class="item oh padding-main border-radius-main bg-white spacing-mb">
|
||||
<view :data-value="item.url" @tap="url_event" class="cp">
|
||||
<image class="blog-img fl radius" :src="item.cover" mode="aspectFill"></image>
|
||||
<view class="base fr">
|
||||
<view class="single-text text-size">{{ item.title }}</view>
|
||||
<view class="cr-grey-9 margin-top-sm text-size-xs">{{ item.add_time_date_cn }}</view>
|
||||
<view v-if="(item.describe || null) != null" class="cr-base multi-text margin-top-sm text-size-xs">{{item.describe}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 九方格 -->
|
||||
<block v-else-if="floor.style_type == 1">
|
||||
<view class="plugins-blog-grid-list">
|
||||
<view v-for="(item, index) in floor.blog_list" :key="index" class="item oh border-radius-main bg-white spacing-mb">
|
||||
<view :data-value="item.url" @tap="url_event" class="cp">
|
||||
<image class="blog-img dis-block" :src="item.cover" mode="widthFix"></image>
|
||||
<view class="base padding-horizontal-sm margin-top-sm">
|
||||
<view class="goods-title multi-text margin-bottom-sm text-size-xs">{{ item.title }}</view>
|
||||
<view class="cr-grey text-size-xs">{{ item.add_time_date_cn }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 滚动 -->
|
||||
<view v-else-if="floor.style_type == 2" class="rolling-horizontal border-radius-main oh spacing-mb">
|
||||
<view class="plugins-blog-rolling-list scroll-view-horizontal">
|
||||
<swiper :vertical="false" :autoplay="(propConfig.is_home_hot_auto_play || 0) == 1" :circular="false" :display-multiple-items="floor.blog_list.length < 3 ? floor.blog_list.length : 3" interval="3000">
|
||||
<block v-for="(item, index) in floor.blog_list" :key="index">
|
||||
<swiper-item>
|
||||
<view :data-value="item.url" @tap="url_event" class="item bg-white border-radius-main margin-right-main oh pr ht-auto pr cp">
|
||||
<image class="blog-img dis-block wh-auto" :src="item.cover" mode="scaleToFill"></image>
|
||||
<view class="blog-title pa single-text cr-white padding-sm text-size-xs">{{ item.title }}</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</block>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propLocation: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
propConfig: {
|
||||
type: [String, Object],
|
||||
default: null,
|
||||
},
|
||||
propData: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
56
components/bottom-line/bottom-line.vue
Normal file
56
components/bottom-line/bottom-line.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(propStatus || false)" class="data-bottom-line">
|
||||
<view class="bottom-exclude">
|
||||
<view class="line-item left"></view>
|
||||
<view class="line-item msg">{{propMsg || $t('bottom-line.bottom-line.44bct2')}}</view>
|
||||
<view class="line-item right"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propStatus: Boolean,
|
||||
propMsg: String
|
||||
},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.data-bottom-line {
|
||||
padding: 40rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
.data-bottom-line .bottom-exclude {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
.data-bottom-line .line-item {
|
||||
width: 33.3%;
|
||||
}
|
||||
.data-bottom-line .line-item.left,
|
||||
.data-bottom-line .line-item.right {
|
||||
margin-top: 8px;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
}
|
||||
.data-bottom-line .line-item.msg {
|
||||
color: #999;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.data-bottom-line .line-item.left,
|
||||
.data-bottom-line .line-item.msg {
|
||||
float: left;
|
||||
}
|
||||
.data-bottom-line .line-item.right {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
187
components/buy-ordergoodsform/buy-ordergoodsform.vue
Normal file
187
components/buy-ordergoodsform/buy-ordergoodsform.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="data.length > 0" class="plugins-ordergoodsform-buy oh margin-top-sm">
|
||||
<view v-for="(item, index) in data" :key="index" class="item pr oh">
|
||||
<view class="title dis-block single-text text-size-sm pa">{{item.title}}</view>
|
||||
<view class="value dis-block pa">
|
||||
<view v-if="propIsRead">{{item.content}}</view>
|
||||
<input v-else :type="((item.element_arr || null) == null || (item.element_arr[1] || null) == null) ? 'text' : item.element_arr[1]"
|
||||
:placeholder="(item.placeholder || null) == null ? item.title : item.placeholder"
|
||||
:data-index="index"
|
||||
:value="item.default_value || ''"
|
||||
@blur="input_value_event"
|
||||
@confirm="input_value_event"
|
||||
placeholder-class="cr-grey"
|
||||
:class="'radius text-size-sm padding-horizontal-sm '+((item.check_status === undefined || item.check_status === true) ? 'br' : 'br-red')"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
data: [],
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propData: {
|
||||
type: [Array],
|
||||
default: []
|
||||
},
|
||||
propGoodsID: {
|
||||
type: [Number,String],
|
||||
default: 0
|
||||
},
|
||||
propIsRead: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.setData({
|
||||
data: this.propData
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 数据值事件
|
||||
input_value_event(e) {
|
||||
// 当前表单数据
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var item = this.data[index];
|
||||
item['default_value'] = e.detail.value.trim();
|
||||
// 数据验证
|
||||
var check = this.input_value_check(item, index);
|
||||
// 保存数据
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('save', 'goods', 'ordergoodsform'),
|
||||
method: 'POST',
|
||||
data: {
|
||||
form_id: item.form_id,
|
||||
goods_id: this.propGoodsID,
|
||||
title: item.title,
|
||||
content: check.value
|
||||
},
|
||||
dataType: 'json',
|
||||
success: (res) => {},
|
||||
fail: (res) => {},
|
||||
});
|
||||
},
|
||||
|
||||
// 数据值验证
|
||||
input_value_check(item, index) {
|
||||
// 是否需要校验
|
||||
var is_required = parseInt(item.is_required || 0);
|
||||
var type = ((item.element_arr || null) == null || (item.element_arr[1] || null) == null) ? 'text' : item.element_arr[1];
|
||||
var value = item.default_value;
|
||||
var msg = item.validation_msg || item.error_message || this.$t('user-address-save.user-address-save.wkfi45');
|
||||
var status = null;
|
||||
|
||||
// 强制填写数据,但是数据没有则错误
|
||||
if(status === null && is_required == 1 && value === '')
|
||||
{
|
||||
status = false;
|
||||
}
|
||||
|
||||
// 有数据则验证正确格式
|
||||
if(status === null && value !== '')
|
||||
{
|
||||
// 根据类型验证数据
|
||||
switch(type)
|
||||
{
|
||||
// 文本
|
||||
case 'text' :
|
||||
var len = value.length;
|
||||
var minlength = parseInt(item.minlength || 0);
|
||||
var maxlength = parseInt(item.maxlength || 0);
|
||||
if((minlength > 0 && len < minlength) || (maxlength > 0 && len > maxlength))
|
||||
{
|
||||
status = false;
|
||||
}
|
||||
break;
|
||||
|
||||
// 整数
|
||||
case 'number' :
|
||||
var val = parseInt(value || 0);
|
||||
var min = parseInt(item.minlength || 0);
|
||||
var max = parseInt(item.maxlength || 0);
|
||||
if((min > 0 && val < min) || (max > 0 && val > max))
|
||||
{
|
||||
value = (min > 0 && val < min) ? min : max;
|
||||
status = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 是否有正则
|
||||
if(status === null) {
|
||||
var pattern = (((item.element_arr || null) == null) || (item.element_arr[2] || null) == null) ? null : item.element_arr[2];
|
||||
if(pattern != null)
|
||||
{
|
||||
var regex = new RegExp(pattern);
|
||||
if(!regex.test(value))
|
||||
{
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 是否提示错误
|
||||
if(status === false) {
|
||||
app.globalData.showToast(msg);
|
||||
}
|
||||
|
||||
// 数据赋值
|
||||
var temp_data = this.data;
|
||||
item['default_value'] = value;
|
||||
temp_data[index] = item;
|
||||
temp_data[index]['check_status'] = (status === null) ? true : status;
|
||||
this.setData({
|
||||
data: temp_data
|
||||
});
|
||||
|
||||
// 验证信息返回
|
||||
return {status: status, value: value};
|
||||
},
|
||||
|
||||
// 数据验证
|
||||
data_check() {
|
||||
var status = true;
|
||||
for(var i in this.data) {
|
||||
var res = this.input_value_check(this.data[i], i);
|
||||
if(res.status === false) {
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.plugins-ordergoodsform-buy .item {
|
||||
height: 72rpx;
|
||||
}
|
||||
.plugins-ordergoodsform-buy .item .title {
|
||||
width: 134rpx;
|
||||
left: 0;
|
||||
bottom: 8rpx;
|
||||
}
|
||||
.plugins-ordergoodsform-buy .item .value {
|
||||
width: calc(100% - 140rpx);
|
||||
left: 140rpx;
|
||||
bottom: 0;
|
||||
}
|
||||
.plugins-ordergoodsform-buy .item .value input {
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
</style>
|
||||
125
components/cart-para-curve/cart-para-curve.vue
Normal file
125
components/cart-para-curve/cart-para-curve.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="cart_icon_data != null && (cart_icon_data.status || 0) == 1" class="cart-para-curve-container pf round" :style="cart_icon_data.style">
|
||||
<image v-if="(cart_icon_data.icon || null) != null" class="cart-para-curve-icon round br" :src="cart_icon_data.icon"></image>
|
||||
<view v-else class="cart-para-curve-icon bg-red padding dis-inline-block round br"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
cart_icon_data: null
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propBtnHeight: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
propBtnWidth: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
propCart: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 初始(购物车对象、当前点击对象、图标、支持tabbar位置)
|
||||
init(cart, pos, icon = '', tabbar_pos = null) {
|
||||
if((pos || null) != null) {
|
||||
var self = this;
|
||||
var btn_size = this.propBtnHeight;
|
||||
var btn_width = this.propBtnWidth;
|
||||
// 未指定购物车对象则读取tabbar数据自动计算购物车位置
|
||||
if((cart || null) == null || (cart[0] || null) == null) {
|
||||
var info = uni.getSystemInfoSync();
|
||||
// 当前页面
|
||||
var page = app.globalData.current_page().split('?');
|
||||
switch(page[0]) {
|
||||
// 商品搜索
|
||||
case 'pages/goods-search/goods-search' :
|
||||
var cart_top = 20;
|
||||
var cart_width = 35;
|
||||
var cart_left = info.screenWidth-20;
|
||||
break;
|
||||
|
||||
// 默认购物车
|
||||
default :
|
||||
// 无购物车菜单则结束执行
|
||||
var tabbar = app.globalData.app_tabbar_pages();
|
||||
if(tabbar_pos === null) {
|
||||
tabbar_pos = tabbar.indexOf('/pages/cart/cart');
|
||||
if(tabbar_pos == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 计算购物车菜单位置
|
||||
var tabbar_count = tabbar.length;
|
||||
var cart_top = info.screenHeight;
|
||||
var cart_width = info.screenWidth/tabbar_count;
|
||||
var cart_left = cart_width*tabbar_pos;
|
||||
}
|
||||
} else {
|
||||
var temp = cart[0];
|
||||
var cart_width = temp.width;
|
||||
var cart_left = temp.left;
|
||||
var cart_top = temp.top;
|
||||
}
|
||||
/* #ifndef MP-ALIPAY */
|
||||
var left = pos.changedTouches[0].clientX + btn_width/2 - btn_size/2;
|
||||
var top = pos.changedTouches[0].clientY - btn_size;
|
||||
/* #endif */
|
||||
/* #ifdef MP-ALIPAY */
|
||||
var left = pos.detail.clientX + btn_width/2 - btn_size/2;
|
||||
var top = pos.detail.clientY - btn_size;
|
||||
/* #endif */
|
||||
var x = cart_left + cart_width/2 - btn_size/2 - left;
|
||||
var y = cart_top - btn_size - top;
|
||||
if(self.cart_icon_data == null || (self.cart_icon_data.status || 0) == 0) {
|
||||
self.setData({cart_icon_data: {
|
||||
status: 1,
|
||||
style: `--left:${left}px;--top:${top}px;--x:${x}px;--y:${y}px;`,
|
||||
icon: icon,
|
||||
}});
|
||||
setTimeout(function(){
|
||||
self.setData({ cart_icon_data: {status: 0}});
|
||||
}, 495);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
@keyframes moveY {
|
||||
to {
|
||||
transform: translateY(var(--y));
|
||||
}
|
||||
}
|
||||
@keyframes moveX {
|
||||
to {
|
||||
transform: translateX(var(--x));
|
||||
}
|
||||
}
|
||||
.cart-para-curve-container {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
z-index: 10;
|
||||
left: var(--left);
|
||||
top: var(--top);
|
||||
--duration: 0.5s;
|
||||
animation: moveY var(--duration) cubic-bezier(0.5, -0.25, 1, 1);
|
||||
}
|
||||
.cart-para-curve-container .cart-para-curve-icon {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
animation: moveX var(--duration) linear;
|
||||
}
|
||||
</style>
|
||||
1690
components/cart/cart.vue
Normal file
1690
components/cart/cart.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="popup_status && (propData || null) != null">
|
||||
<view class="plugins-categorylimit-warm-tips-mask wh-auto ht-auto pf"></view>
|
||||
<view class="plugins-categorylimit-warm-tips-content pf bg-white border-radius-main padding-xxl tc">
|
||||
<image :src="propData.warm_tips_alert_images" class="dis-block wh-auto radius" mode="aspectFit"></image>
|
||||
<view v-if="(propData.warm_tips_alert_msg || null) != null" class="margin-top-lg cr-base">{{propData.warm_tips_alert_msg}}</view>
|
||||
<button type="button" class="bg-main br-main cr-white round text-size-md margin-top-xxxl" @tap="close_event">{{$t('common.confirm')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
popup_status: true,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
propData: {
|
||||
type: [String,Object],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 关闭弹窗
|
||||
close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.plugins-categorylimit-warm-tips-mask {
|
||||
left: 0;
|
||||
top: 0;
|
||||
background: rgb(0, 0, 0, 0.6);
|
||||
z-index: 10;
|
||||
}
|
||||
.plugins-categorylimit-warm-tips-content {
|
||||
z-index: 11;
|
||||
width: calc(100% - 240rpx);
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
height: -webkit-max-content;
|
||||
height: max-content;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
169
components/choice-location/choice-location.vue
Normal file
169
components/choice-location/choice-location.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="propIsShowAddressChoice" class="choice-location pr wh-auto oh" :style="propLocationContainerStyle" @tap.stop="choose_user_location">
|
||||
<view class="flex-row gap-2 align-c oh" :style="propLocationImgContainerStyle">
|
||||
<view v-if="propIsLeftIconArrow" class="dis-inline-block va-m lh">
|
||||
<block v-if="(propLeftImgValue || null) != null && propLeftImgValue.length > 0">
|
||||
<image :src="propLeftImgValue[0].url" class="dis-block" mode="heightFix"></image>
|
||||
</block>
|
||||
<block v-else>
|
||||
<iconfont :name="propLeftIconValue" :size="propIconLocationSize" propClass="lh" :color="propIconLocationColor || propBaseColor" :propContainerDisplay="propContainerDisplay"></iconfont>
|
||||
</block>
|
||||
</view>
|
||||
<view :class="'va-m dis-inline-block margin-left-xs single-text text' + (propType == 'header' ? ' text-size-md' : ' text-size-xs')" :style="'max-width:' + propTextMaxWidth + ';color:' + (propTextColor || propBaseColor) + ';'">{{ location.text || '' }}</view>
|
||||
<view v-if="propIsRightIconArrow" class="va-m lh dis-inline-block margin-left-xs">
|
||||
<block v-if="(propRightImgValue || null) != null && propRightImgValue.length > 0">
|
||||
<image :src="propRightImgValue[0].url" class="dis-block" mode="heightFix"></image>
|
||||
</block>
|
||||
<block v-else>
|
||||
<iconfont :name="propRightIconValue" :size="propIconArrowSize" propClass="lh-xs" :color="propIconArrowColor || propBaseColor" :propContainerDisplay="propContainerDisplay"></iconfont>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
location: {},
|
||||
cloice_location_timer: null,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
propIsShowAddressChoice: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propBaseColor: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
propTextDefaultName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propTextColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propTextMaxWidth: {
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
propIconLocationColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIconLocationSize: {
|
||||
type: String,
|
||||
default: '28rpx',
|
||||
},
|
||||
propIconArrowColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIconArrowSize: {
|
||||
type: String,
|
||||
default: '24rpx',
|
||||
},
|
||||
propIsLeftIconArrow: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propLeftImgValue: {
|
||||
type: [Array,String],
|
||||
default: '',
|
||||
},
|
||||
propLeftIconValue: {
|
||||
type: String,
|
||||
default: 'icon-location',
|
||||
},
|
||||
propIsRightIconArrow: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propRightImgValue: {
|
||||
type: [Array,String],
|
||||
default: '',
|
||||
},
|
||||
propRightIconValue: {
|
||||
type: String,
|
||||
default: 'icon-arrow-bottom',
|
||||
},
|
||||
propType: {
|
||||
type: String,
|
||||
default: 'header',
|
||||
},
|
||||
propLocationContainerStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propLocationImgContainerStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propContainerDisplay: {
|
||||
type: String,
|
||||
default: 'inline-block',
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化
|
||||
init() {
|
||||
let location = app.globalData.choice_user_location_init();
|
||||
if ((this.propTextDefaultName || null) != null) {
|
||||
var default_name = this.$t('shopxo-uniapp.app.4v6q86');
|
||||
if (location.text == default_name) {
|
||||
location.text = this.propTextDefaultName;
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
location: location,
|
||||
});
|
||||
},
|
||||
|
||||
// 选择位置监听
|
||||
choose_user_location(e) {
|
||||
// 定时任务
|
||||
clearInterval(this.cloice_location_timer);
|
||||
var self = this;
|
||||
var timer = setInterval(function () {
|
||||
var result = app.globalData.choice_user_location_init() || null;
|
||||
if (result != null && (result.status == 1 || result.status == 3)) {
|
||||
self.setData({
|
||||
location: result,
|
||||
});
|
||||
clearInterval(self.cloice_location_timer);
|
||||
|
||||
// 回调事件
|
||||
self.$emit('onBack', result);
|
||||
}
|
||||
}, 1000);
|
||||
this.setData({
|
||||
cloice_location_timer: timer,
|
||||
});
|
||||
|
||||
// 进入位置选择
|
||||
app.globalData.choose_user_location_event();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.choice-location {
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
}
|
||||
.dis-block {
|
||||
width: 100%;
|
||||
height: 56rpx;
|
||||
}
|
||||
</style>
|
||||
250
components/common/common.vue
Normal file
250
components/common/common.vue
Normal file
@@ -0,0 +1,250 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<!-- 底部菜单 -->
|
||||
<block v-if="is_tabbar">
|
||||
<component-diy-footer :propKey="key" :propValue="app_tabbar" @onFooterHeight="footer_height_value_event"></component-diy-footer>
|
||||
<view v-if="propIsFooterSeat && footer_height_value > 0" :style="'height:'+footer_height_value+'rpx;'"></view>
|
||||
</block>
|
||||
|
||||
<!-- 微信隐私提示弹窗 -->
|
||||
<view v-if="is_show_privacy" class="agreement-page bs-bb pf wh-auto ht-auto left-0 top-0 z-i-deep-must">
|
||||
<view class="agreement-content border-radius-main bg-white">
|
||||
<view class="tc">
|
||||
<image class="logo circle auto dis-block margin-bottom-lg br" :src="logo" mode="widthFix"></image>
|
||||
<view class="cr-base fw-b text-size-lg">{{ title }}{{$t('common.warm_tips')}}</view>
|
||||
</view>
|
||||
<view class="margin-top-lg text-size-sm cr-base content-desc">
|
||||
<block v-if="(privacy_content || null) == null">{{$t('agreement.agreement.w38e3v')}}{{ title }}{{$t('agreement.agreement.hjn568')}}</block>
|
||||
<block v-else>{{ privacy_content }}</block>
|
||||
</view>
|
||||
<view class="cr-blue margin-top-lg">
|
||||
<view>
|
||||
<text @tap="agreement_event" data-value="userregister">《{{ title }}{{$t('agreement.agreement.iy7863')}}</text>
|
||||
</view>
|
||||
<view class="margin-top-sm">
|
||||
<text @tap="agreement_event" data-value="userprivacy">《{{ title }}{{$t('agreement.agreement.jwi8n1')}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="buttom tc margin-top-xxxl padding-top-lg">
|
||||
<button type="default" size="mini" class="btn br-grey cr-base bg-white text-size-sm round margin-right-xxxl" @tap="exit_event">{{$t('agreement.agreement.062co8')}}</button>
|
||||
<button type="default" size="mini" class="btn br-main cr-white bg-main text-size-sm round margin-left-xxxl" open-type="agreePrivacyAuthorization" @agreeprivacyauthorization="agree_privacy_auth_event">{{$t('agreement.agreement.60t34e')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- app管理 -->
|
||||
<component-app-admin ref="app_admin" :propIsHideStar="true"></component-app-admin>
|
||||
|
||||
<!-- 用户基础 -->
|
||||
<component-user-base ref="user_base" :propIsGrayscale="propIsGrayscale"></component-user-base>
|
||||
|
||||
<!-- 弹屏广告 -->
|
||||
<component-popupscreen ref="popupscreen" :propIsGrayscale="propIsGrayscale"></component-popupscreen>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentDiyFooter from '@/components/diy/footer';
|
||||
import componentAppAdmin from '@/components/app-admin/app-admin';
|
||||
import componentUserBase from '@/components/user-base/user-base';
|
||||
import componentPopupscreen from '@/components/popupscreen/popupscreen';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
logo: app.globalData.get_application_logo_square(),
|
||||
title: app.globalData.get_application_title(),
|
||||
is_show_privacy: false,
|
||||
privacy_content: null,
|
||||
key: '',
|
||||
is_tabbar: false,
|
||||
app_tabbar: null,
|
||||
footer_height_value: 0,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
// 是否灰度
|
||||
propIsGrayscale: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否显示底部菜单占位
|
||||
propIsFooterSeat: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否引入app管理
|
||||
propIsAppAdmin: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否引入用户基础信息提示
|
||||
propIsUserBase: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否引入弹屏广告
|
||||
propIsPopupscreen: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
componentDiyFooter,
|
||||
componentAppAdmin,
|
||||
componentUserBase,
|
||||
componentPopupscreen
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
// 初始化配置
|
||||
this.init_config();
|
||||
},
|
||||
methods: {
|
||||
// 显示响应方法
|
||||
on_show(params = {}) {
|
||||
//隐藏系统tabbar
|
||||
if(app.globalData.data.is_use_native_tabbar != 1) {
|
||||
app.globalData.system_hide_tabbar();
|
||||
}
|
||||
|
||||
// 初始化配置
|
||||
this.init_config(false, params);
|
||||
|
||||
// 系统底部菜单
|
||||
this.footer_init();
|
||||
},
|
||||
|
||||
// 初始化配置
|
||||
init_config(status = false, params = {}) {
|
||||
if ((status || false) == true) {
|
||||
// 初始化数据
|
||||
this.init(params);
|
||||
} else {
|
||||
app.globalData.is_config(this, 'init_config', params);
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化数据
|
||||
init(params = {}) {
|
||||
// 系统底部菜单
|
||||
this.footer_init();
|
||||
|
||||
// app管理
|
||||
if (this.propIsAppAdmin && (this.$refs.app_admin || null) != null) {
|
||||
this.$refs.app_admin.init(params);
|
||||
}
|
||||
|
||||
// 用户头像和昵称设置提示
|
||||
if (this.propIsUserBase && (this.$refs.user_base || null) != null) {
|
||||
this.$refs.user_base.init(params);
|
||||
}
|
||||
|
||||
// 弹屏广告
|
||||
if (this.propIsPopupscreen && (this.$refs.popupscreen || null) != null) {
|
||||
this.$refs.popupscreen.init(params);
|
||||
}
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信协议验证
|
||||
if (app.globalData.data.is_weixin_privacy_setting == 1) {
|
||||
uni.getPrivacySetting({
|
||||
success: (res) => {
|
||||
if (res.needAuthorization) {
|
||||
this.setData({
|
||||
is_show_privacy: true,
|
||||
privacy_content: app.globalData.get_config('config.common_app_mini_weixin_privacy_content', null),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
// 底部菜单初始化
|
||||
footer_init(status = 0) {
|
||||
var is_use_native_tabbar = app.globalData.data.is_use_native_tabbar == 1;
|
||||
var upd_data = {
|
||||
is_tabbar: is_use_native_tabbar ? false : app.globalData.is_tabbar_pages()
|
||||
};
|
||||
if(upd_data['is_tabbar']) {
|
||||
upd_data['key'] = Math.random();
|
||||
upd_data['app_tabbar'] = app.globalData.get_config('app_tabbar') || null;
|
||||
}
|
||||
this.setData(upd_data);
|
||||
|
||||
// 如果没有菜单数据则读取一次
|
||||
if(!is_use_native_tabbar && status == 0 && (upd_data['app_tabbar'] || null) == null) {
|
||||
app.globalData.init_config(0, this, 'footer_init', 1);
|
||||
}
|
||||
},
|
||||
|
||||
// 底部菜单高度回调事件
|
||||
footer_height_value_event(value) {
|
||||
this.setData({
|
||||
footer_height_value: (value*2)+20
|
||||
});
|
||||
this.$emit('onFooterHeight', value);
|
||||
|
||||
// 存储底部菜单高度
|
||||
app.globalData.app_system_tabbar_height_save(value);
|
||||
},
|
||||
|
||||
// 协议事件
|
||||
agreement_event(e) {
|
||||
var value = e.currentTarget.dataset.value || null;
|
||||
if (value == null) {
|
||||
app.globalData.showToast(this.$t('login.login.4wc3hr'));
|
||||
return false;
|
||||
}
|
||||
// 是否存在协议 url 地址
|
||||
var key = 'agreement_' + value + '_url';
|
||||
var url = app.globalData.get_config('config.' + key) || null;
|
||||
if (url == null) {
|
||||
app.globalData.showToast(this.$t('login.login.x0nxxf'));
|
||||
return false;
|
||||
}
|
||||
// 打开 webview
|
||||
app.globalData.open_web_view(url);
|
||||
},
|
||||
|
||||
// 授权回调
|
||||
agree_privacy_auth_event() {
|
||||
this.setData({
|
||||
is_show_privacy: false
|
||||
});
|
||||
},
|
||||
|
||||
// 退出小程序
|
||||
exit_event(e) {
|
||||
uni.exitMiniProgram();
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.agreement-page {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
height: 100vh;
|
||||
padding: 40rpx;
|
||||
}
|
||||
.agreement-content {
|
||||
padding: 40rpx;
|
||||
position: absolute;
|
||||
top: 15%;
|
||||
width: calc(100% - 160rpx);
|
||||
}
|
||||
.agreement-content .logo {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
}
|
||||
.agreement-content .content-desc {
|
||||
line-height: 46rpx;
|
||||
max-height: calc(30vh);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.agreement-content .buttom .btn {
|
||||
min-width: 200rpx;
|
||||
}
|
||||
</style>
|
||||
33
components/copyright/copyright.vue
Normal file
33
components/copyright/copyright.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view class="copyright">
|
||||
<view class="text">{{application_title}} {{version}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
application_title: app.globalData.get_application_title(),
|
||||
version: app.globalData.data.version
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.copyright {
|
||||
color: #cfcfcf;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
.copyright .text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
}
|
||||
</style>
|
||||
211
components/countdown/countdown.vue
Normal file
211
components/countdown/countdown.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view class="countdown" v-if="is_show && !is_end">
|
||||
<block v-if="propMsecShow">
|
||||
<view class="fr time" :style="time_style">{{ msec }}</view>
|
||||
<view class="fr ds" :style="ds_style">{{ propSecondDs }}</view>
|
||||
</block>
|
||||
<view class="fr time" :style="time_style">{{ second }}</view>
|
||||
<view class="fr ds" :style="ds_style">{{ propMinuteDs }}</view>
|
||||
<view class="fr time" :style="time_style">{{ minute }}</view>
|
||||
<view class="fr ds" :style="ds_style">{{ propHourDs }}</view>
|
||||
<view class="fr time" :style="time_style">{{ hour }}</view>
|
||||
</view>
|
||||
<view v-if="is_show && is_end" class="timer-title">{{ propMsg || this.$t('index.index.443683') }}</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
hour: '00',
|
||||
minute: '00',
|
||||
second: '00',
|
||||
msec: 0,
|
||||
is_show: true,
|
||||
is_end: false,
|
||||
timer: null,
|
||||
timers: null,
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propHour: {
|
||||
type: [String, Number],
|
||||
default: '00',
|
||||
},
|
||||
propMinute: {
|
||||
type: [String, Number],
|
||||
default: '00',
|
||||
},
|
||||
propSecond: {
|
||||
type: [String, Number],
|
||||
default: '00',
|
||||
},
|
||||
propEndShow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propMsecShow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propMsg: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propHourDs: {
|
||||
type: String,
|
||||
default: ':',
|
||||
},
|
||||
propMinuteDs: {
|
||||
type: String,
|
||||
default: ':',
|
||||
},
|
||||
propSecondDs: {
|
||||
type: String,
|
||||
default: ':',
|
||||
},
|
||||
propTimePadding: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
propTimeSize: {
|
||||
type: [Number, String],
|
||||
default: 24,
|
||||
},
|
||||
propTimeBackgroundColor: {
|
||||
type: String,
|
||||
default: 'linear-gradient(180deg, #FF601B 0%, #FE1B33 100%);',
|
||||
},
|
||||
propTimeColor: {
|
||||
type: String,
|
||||
default: '#FFF',
|
||||
},
|
||||
propTimeWeight: {
|
||||
type: [Number, String],
|
||||
default: '400',
|
||||
},
|
||||
propDsColor: {
|
||||
type: String,
|
||||
default: '#4B5459',
|
||||
},
|
||||
propDsSize: {
|
||||
type: [Number, String],
|
||||
default: 24,
|
||||
},
|
||||
propDsWeight: {
|
||||
type: [Number, String],
|
||||
default: '400',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
time_style() {
|
||||
return 'padding: 0 ' + this.propTimePadding + 'rpx;background:' + this.propTimeBackgroundColor + ';color:' + this.propTimeColor + ';font-size:' + this.propTimeSize + 'rpx;font-weight:' + this.propTimeWeight;
|
||||
},
|
||||
ds_style() {
|
||||
return 'color:' + this.propDsColor + ';font-size:' + this.propDsSize + 'rpx;font-weight:' + this.propDsWeight;
|
||||
},
|
||||
},
|
||||
created: function (e) {
|
||||
// 参数处理
|
||||
this.hour = this.propHour;
|
||||
this.minute = this.propMinute;
|
||||
this.second = this.propSecond;
|
||||
|
||||
// 定时处理
|
||||
this.countdown();
|
||||
},
|
||||
// #ifndef VUE2
|
||||
destroyed() {
|
||||
clearInterval(this.timer);
|
||||
clearInterval(this.timers);
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
unmounted() {
|
||||
clearInterval(this.timer);
|
||||
clearInterval(this.timers);
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
// 倒计时处理
|
||||
countdown() {
|
||||
// 销毁之前的任务
|
||||
clearInterval(this.timer);
|
||||
clearInterval(this.timers);
|
||||
|
||||
// 秒
|
||||
var self = this;
|
||||
var hour = parseInt(self.hour);
|
||||
var minute = parseInt(self.minute);
|
||||
var second = parseInt(self.second);
|
||||
self.timer = setInterval(function () {
|
||||
if (second <= 0) {
|
||||
if (minute > 0) {
|
||||
minute--;
|
||||
second = 59;
|
||||
} else if (hour > 0) {
|
||||
hour--;
|
||||
minute = 59;
|
||||
second = 59;
|
||||
}
|
||||
} else {
|
||||
second--;
|
||||
}
|
||||
|
||||
self.hour = hour < 10 ? '0' + hour : hour;
|
||||
self.minute = minute < 10 ? '0' + minute : minute;
|
||||
self.second = second < 10 ? '0' + second : second;
|
||||
if (self.propHour <= 0 && self.propMinute <= 0 && self.propSecond <= 0) {
|
||||
// 停止时间
|
||||
clearInterval(self.timer);
|
||||
clearInterval(self.timers);
|
||||
self.is_end = true;
|
||||
|
||||
// 活动已结束、是否结束还展示
|
||||
if (!self.propEndShow) {
|
||||
self.is_show = false;
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// 毫秒
|
||||
var count = 0;
|
||||
self.timers = setInterval(function () {
|
||||
count++;
|
||||
self.msec = count;
|
||||
if (count > 9) {
|
||||
count = 0;
|
||||
}
|
||||
if (!self.is_show) {
|
||||
clearInterval(self.timers);
|
||||
}
|
||||
}, 100);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.countdown {
|
||||
line-height: 38rpx;
|
||||
}
|
||||
.countdown .timer-title {
|
||||
color: #666;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.countdown .time {
|
||||
padding: 0;
|
||||
-moz-border-radius: 8rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #fff;
|
||||
min-width: 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.countdown .ds {
|
||||
color: #4b5459;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
</style>
|
||||
230
components/coupon-card/coupon-card.vue
Normal file
230
components/coupon-card/coupon-card.vue
Normal file
@@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view class="padding-bottom padding-horizontal-main">
|
||||
<view class="coupon-card oh pr flex-row">
|
||||
<view class="card-left flex-col jc-sa align-c" :class="propStatusType > 3 ? 'failure cr-grey-9' : 'cr-white'">
|
||||
<view class="price">
|
||||
<text v-if="propData.type == '0'" class="symbol text-size">{{ currency_symbol }}</text>
|
||||
<text class="num text-size-xxl">{{ propData.discount_value }}</text>
|
||||
<text v-if="propData.type !== '0'" class="unit text-size-md">{{ propData.type_unit }}</text>
|
||||
</view>
|
||||
<text v-if="(propData.desc || null) != null" class="desc text-size-xs single-text">{{ propData.desc }}</text>
|
||||
</view>
|
||||
<view class="card-right flex-1 flex-width flex-row jc-sb align-c" :class="propStatusType > 3 ? 'failure cr-grey-9' : ''">
|
||||
<view class="card-info flex-1 flex-width padding-right-main" :class="propStatusType > 3 ? 'failure cr-grey-9' : 'cr-black'">
|
||||
<view class="title text-size-lg single-text" :class="propData.time_start">{{ propData.use_limit_type_name }}</view>
|
||||
<view v-if="propStartTime && propEndTime" class="date text-size-xs cr-grey-9 single-text padding-top-sm">{{ propStartTime }}-{{ propEndTime }}</view>
|
||||
<view v-if="propIsProgress && propData.process_data" class="progress padding-top-sm flex-row align-c">
|
||||
<block v-if="propData.process_data.type == 0">
|
||||
<text class="text-size-xs cr-grey-9"> {{ propData.process_data.msg }} </text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<progress class="flex-1" :percent="propData.process_data.value" stroke-width="6" activeColor="#FF7004" backgroundColor="#fff" border-radius="3" />
|
||||
<view class="percent text-size-xss cr-grey-9 padding-left-main"> {{ propData.process_data.msg }} </view>
|
||||
</block>
|
||||
</view>
|
||||
<view v-if="propData.expire_tips" class="padding-top-sm text-size-xs cr-red">{{ propData.expire_tips }}</view>
|
||||
</view>
|
||||
<view class="card-type">
|
||||
<!-- 按钮状态 0-领取,1-已领取,2-已抢完,3-去使用,4-已使用,5-已过期 -->
|
||||
<view v-if="propStatusType == 0" class="card-btn dis-inline-block cr-white" @tap="receive">{{ propStatusOperableName || this.$t('coupon-card.coupon-card.m9316y') }}</view>
|
||||
<view v-else-if="propStatusType == 1" class="card-btn dis-inline-block cr-red br-red received">{{ propStatusOperableName || this.$t('coupon-card.coupon-card.m9316y') }}</view>
|
||||
<view v-else-if="propStatusType == 2" class="card-btn dis-inline-block cr-white robbed">{{ propStatusOperableName || this.$t('coupon-card.coupon-card.m9316y') }}</view>
|
||||
<view v-else-if="propStatusType == 3" :data-value="home_page_url" @tap="url_event" class="cp">
|
||||
<view class="card-btn dis-inline-block cr-white">
|
||||
{{ propStatusOperableName || this.$t('coupon-card.coupon-card.m9316y') }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="propStatusType == 4" class="card-image pa top-0 right-0">
|
||||
<image class="image" :src="coupon_static_url + 'coupon-used.png'" mode="scaleToFill"></image>
|
||||
</view>
|
||||
<view v-else-if="propStatusType == 5" class="card-image pa top-0 right-0">
|
||||
<image class="image" :src="coupon_static_url + 'coupon-expire.png'" mode="scaleToFill"></image>
|
||||
</view>
|
||||
<view v-else @tap="receive">{{$t('coupon-card.coupon-card.j318xx')}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-circle-top" :style="{ background: `${propBg}` }"></view>
|
||||
<view class="card-circle-bottom" :style="{ background: `${propBg}` }"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
var coupon_static_url = app.globalData.get_static_url('coupon', true);
|
||||
var tabbar_pages = app.globalData.app_tabbar_pages();
|
||||
export default {
|
||||
name: 'coupon-card',
|
||||
props: {
|
||||
propData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
// id: "0",
|
||||
// // 领取数量
|
||||
// already_send_count: 0,
|
||||
// // 总数
|
||||
// process_data: {
|
||||
// type: 1, // 0 无限制
|
||||
// value: 20,
|
||||
// msg: "已领20%",
|
||||
// },
|
||||
// // 日期有效日期 // 2023.08.30-2023.09.1
|
||||
// date: "",
|
||||
// expire_tips: "",
|
||||
// time_start: "",
|
||||
// time_end: "",
|
||||
};
|
||||
},
|
||||
},
|
||||
// 监听
|
||||
propRandom: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 半圆背景
|
||||
propBg: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
// 进度条
|
||||
propIsProgress: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否可重复领取
|
||||
propRepeatedClaim: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否可点击
|
||||
propDisabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 下标
|
||||
propIndex: {
|
||||
type: [Number,String],
|
||||
default: 0,
|
||||
},
|
||||
// 按钮状态 0-领取,1-已领取,2-已抢完,3-去使用,4-已使用,5-已过期
|
||||
propStatusType: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 按钮名称: 领取 已领取 已抢完 去使用
|
||||
propStatusOperableName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 优惠券有效期
|
||||
propStartTime:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propEndTime:{
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
coupon_static_url: coupon_static_url + 'app/',
|
||||
// 符号
|
||||
currency_symbol: app.globalData.currency_symbol(),
|
||||
// 首页地址
|
||||
home_page_url: tabbar_pages[0],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 领取
|
||||
receive(e) {
|
||||
this.$emit('call-back', this.propIndex, this.propData.id);
|
||||
},
|
||||
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.coupon-card {
|
||||
border-radius: 24rpx;
|
||||
height: 208rpx;
|
||||
}
|
||||
|
||||
.card-left {
|
||||
width: 176rpx;
|
||||
padding: 24rpx 12rpx;
|
||||
background: linear-gradient(95deg, #ff994b 0%, #ff6e00 100%);
|
||||
}
|
||||
|
||||
.card-left.failure {
|
||||
background: linear-gradient(95deg, #eeeeee 0%, #fafafa 100%);
|
||||
}
|
||||
|
||||
.card-right {
|
||||
padding: 32rpx 24rpx 32rpx 46rpx;
|
||||
background-color: #ffe4d1;
|
||||
}
|
||||
|
||||
.card-right.failure {
|
||||
background: linear-gradient(95deg, #f8f8f8 0%, #e0dede 100%);
|
||||
}
|
||||
|
||||
.card-info.failure {
|
||||
padding-right: 116rpx;
|
||||
}
|
||||
|
||||
.card-btn {
|
||||
width: 116rpx;
|
||||
text-align: center;
|
||||
padding: 6rpx 0;
|
||||
background: linear-gradient(93deg, #ff9747 0%, #ff6e01 100%);
|
||||
border-radius: 13px;
|
||||
}
|
||||
|
||||
.robbed {
|
||||
background: #fbd3b7;
|
||||
}
|
||||
|
||||
.received {
|
||||
border-radius: 13px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::v-deep .uni-progress-bar,
|
||||
::v-deep .uni-progress-inner-bar {
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
|
||||
.card-circle-top,
|
||||
.card-circle-bottom {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
left: 180rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.card-circle-top {
|
||||
top: -20rpx;
|
||||
}
|
||||
|
||||
.card-circle-bottom {
|
||||
bottom: -20rpx;
|
||||
}
|
||||
|
||||
.card-image .image {
|
||||
width: 136rpx;
|
||||
height: 108rpx;
|
||||
}
|
||||
</style>
|
||||
430
components/diy/article-list.vue
Normal file
430
components/diy/article-list.vue
Normal file
@@ -0,0 +1,430 @@
|
||||
<template>
|
||||
<!-- 文章列表 -->
|
||||
<view class="oh" :style="style_container">
|
||||
<view class="oh" :style="style_img_container">
|
||||
<view class="pr oh" :style="style">
|
||||
<view v-if="!['4'].includes(article_theme)" class="flex-wrap" :class="article_theme_class" :style="article_theme !== '3' ? article_spacing : ''">
|
||||
<view v-for="(item, index) in data_list" :key="index" class="item oh" :style="article_style" :data-value="item.data.url" @tap="url_event">
|
||||
<view :class="article_theme == '0' ? 'flex-row oh' : 'flex-col oh ht-auto'" :style="article_img_style">
|
||||
<template v-if="article_theme !== '3'">
|
||||
<view class="oh pr flex-row">
|
||||
<template v-if="item.new_cover.length > 0">
|
||||
<image :src="item.new_cover[0].url" class="img" :style="img_radius + img_size" mode="aspectFill" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<image :src="item.data.cover" class="img" :style="img_radius + img_size" mode="aspectFill" />
|
||||
</template>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="field_show.includes('0') || field_show.includes('1') || field_show.includes('2') || field_show.includes('3')" class="jc-sb flex-1" :class="article_theme == '3' ? 'flex-row align-c' : 'flex-col'" :style="article_theme !== '0' ? content_padding : ''">
|
||||
<view class="flex-col" :class="article_theme == '3' ? 'flex-1 flex-width' : ''" :style="'gap:' + name_desc_space + 'px;'">
|
||||
<view v-if="field_show.includes('3')" class="title" :class="article_theme == '3' ? 'text-line-1' : 'text-line-2'" :style="article_name">{{ item.new_title ? item.new_title : item.data.title }}</view>
|
||||
<view v-if="field_show.includes('2')" :class="'desc ' + field_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="article_desc">{{ item.data.describe || '' }}</view>
|
||||
</view>
|
||||
<view class="flex-row jc-sb gap-8" :class="article_theme == '3' ? 'margin-left' : 'align-e margin-top'">
|
||||
<view :style="article_date">{{ field_show.includes('0') ? item.data.add_time : '' }}</view>
|
||||
<view v-show="field_show.includes('1')" class="flex-row align-c gap-3" :style="article_page_view">
|
||||
<iconfont name="icon-eye" propContainerDisplay="flex"></iconfont>
|
||||
<view>
|
||||
{{ item.data.access_count ? item.data.access_count : '' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="oh" :class="article_theme_class">
|
||||
<swiper class="swiper" circular :autoplay="is_roll ? true : false" :interval="interval_time" :next-margin="next_margin" :display-multiple-items="slides_per_group" :style="'height:' + carousel_height_computer">
|
||||
<swiper-item v-for="(item1, index1) in article_carousel_list" :key="index1">
|
||||
<view class="flex-row ht-auto" :style="article_spacing">
|
||||
<view v-for="(item, index) in item1.carousel_list" :key="index" class="item oh ht-auto" :style="article_style" :data-value="item.data.url" @tap="url_event">
|
||||
<view class="oh flex-col ht-auto" :style="article_img_style">
|
||||
<view class="oh pr wh-auto ht-auto flex-row">
|
||||
<template v-if="item.new_cover.length > 0">
|
||||
<image :src="item.new_cover[0].url" class="img" :style="img_radius + 'height:100%;'" mode="aspectFill" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<image :src="item.data.cover" class="img" :style="img_radius + 'height:100%;'" mode="aspectFill" />
|
||||
</template>
|
||||
<template v-if="field_show.includes('3') && name_float == '1'">
|
||||
<view class="text-line-1" :style="article_name + float_name_style">{{ item.new_title ? item.new_title : item.data.title }}</view>
|
||||
</template>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
<view v-if="field_show.includes('0') || field_show.includes('1') || field_show.includes('2') || (field_show.includes('3') && name_float == '0')" class="jc-sb flex-1 flex-col" :style="article_theme !== '0' ? content_padding : ''">
|
||||
<view class="flex-col" :style="'gap:' + name_desc_space + 'px;'">
|
||||
<view v-if="field_show.includes('3') && name_float == '0'" class="title text-line-2" :style="article_name + article_name_height_computer">{{ item.new_title ? item.new_title : item.data.title }}</view>
|
||||
<view v-if="field_show.includes('2')" :class="'desc ' + field_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="article_desc">{{ item.data.describe || '' }}</view>
|
||||
</view>
|
||||
<view :class="'flex-row jc-sb gap-8 align-e' + ((field_show.includes('3') && name_float == '0') || field_show.includes('2') ? ' margin-top' : '')">
|
||||
<view :style="article_date">{{ field_show.includes('0') ? item.data.add_time : '' }}</view>
|
||||
<view v-show="field_show.includes('1')" class="flex-row align-c gap-3" :style="article_page_view">
|
||||
<iconfont name="icon-eye" propContainerDisplay="flex"></iconfont>
|
||||
<view>
|
||||
{{ item.data.access_count ? item.data.access_count : '' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, common_img_computer, padding_computer, radius_computer, get_math, gradient_handle, background_computer, gradient_computer, margin_computer, box_shadow_computer, border_computer, old_margin } from '@/common/js/common/common.js';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
subscriptIndex,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
// 是否使用公共样式
|
||||
propIsCommonStyle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 关键key
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
// 数据
|
||||
data_list: [],
|
||||
// 风格
|
||||
article_theme: '0',
|
||||
|
||||
// 是否显示
|
||||
field_show: ['0', '1'],
|
||||
// 文章
|
||||
article_name: '',
|
||||
// 描述
|
||||
article_desc: '',
|
||||
// 日期
|
||||
article_date: '',
|
||||
// 浏览量
|
||||
article_page_view: '',
|
||||
// 内容圆角
|
||||
content_radius: '',
|
||||
// 图片圆角
|
||||
img_radius: '',
|
||||
// 内间距
|
||||
content_padding: '',
|
||||
// 内容间距
|
||||
content_spacing: '',
|
||||
// 文章间距
|
||||
article_spacing: '',
|
||||
// article_item_height: '',
|
||||
|
||||
article_style: '',
|
||||
article_img_style: '',
|
||||
// 轮播图定时轮播
|
||||
interval_time: 2000,
|
||||
// 轮播图是否滚动
|
||||
is_roll: 1,
|
||||
|
||||
article_theme_class: '',
|
||||
// 轮播高度
|
||||
carousel_height_computer: '',
|
||||
// 文章内容高度
|
||||
article_name_height_computer: '',
|
||||
// 文章名称浮动样式
|
||||
float_name_style: '',
|
||||
name_float: '0',
|
||||
// 图片大小
|
||||
img_size: '',
|
||||
// 文章轮播数据
|
||||
article_carousel_list: [],
|
||||
// 文章描述间距
|
||||
name_desc_space: 0,
|
||||
// 一行显示的数量
|
||||
slides_per_group: 1,
|
||||
next_margin: '0rpx',
|
||||
field_desc_row: '1',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 描述样式
|
||||
const desc_size = new_style.desc_size;
|
||||
let desc_style = 'font-size:' + desc_size + 'px;line-height:' + desc_size + 'px;height:' + desc_size + 'px;color:' + new_style.desc_color + ';';
|
||||
if (new_content.field_desc_row == '2') {
|
||||
desc_style = 'font-size:' + desc_size + 'px;line-height:' + (desc_size > 0 ? desc_size + 3 : 0 ) + 'px;height:'+ (desc_size > 0 ? (desc_size + 3) * 2 : 0) + 'px;color:' + new_style.desc_color + ';';
|
||||
}
|
||||
this.setData({
|
||||
field_desc_row: new_content.field_desc_row,
|
||||
name_float: !isEmpty(new_content.name_float) ? new_content.name_float : '0',
|
||||
// 判断是自动还是手动
|
||||
data_list:
|
||||
new_content.data_type == '0'
|
||||
? new_content.data_list
|
||||
: new_content.data_auto_list && new_content.data_auto_list.length > 0
|
||||
? new_content.data_auto_list.map((item) => ({
|
||||
id: get_math(),
|
||||
new_title: '',
|
||||
new_cover: [],
|
||||
data: item,
|
||||
}))
|
||||
: [],
|
||||
article_theme_class: this.article_theme_class_computer(new_content.theme),
|
||||
article_theme: new_content.theme,
|
||||
field_show: new_content.field_show,
|
||||
// 样式
|
||||
article_name: 'font-size:' + new_style.name_size + 'px;' + 'font-weight:' + new_style.name_weight + ';' + 'color:' + new_style.name_color + ';',
|
||||
article_desc: desc_style,
|
||||
article_date: 'font-size:' + new_style.time_size + 'px;' + 'font-weight:' + new_style.time_weight + ';' + 'color:' + new_style.time_color + ';',
|
||||
article_page_view: 'font-size:' + new_style.page_view_size + 'px;' + 'font-weight:' + new_style.page_view_weight + ';' + 'color:' + new_style.page_view_color + ';',
|
||||
content_radius: radius_computer(new_style.content_radius),
|
||||
img_radius: radius_computer(new_style.img_radius),
|
||||
// 内间距
|
||||
content_padding: padding_computer(new_style.padding),
|
||||
// 内容间距
|
||||
content_spacing: `gap: ${new_style.content_spacing}px;`,
|
||||
// 文章间距
|
||||
article_spacing: `gap: ${new_style.article_spacing}px;`,
|
||||
// 描述间距
|
||||
name_desc_space: parseInt(new_style.name_desc_space),
|
||||
next_margin: new_style.rolling_fashion == 'translation' ? '-' + new_style.article_spacing_margin + 'px' : '0rpx',
|
||||
// 文章内容高度
|
||||
slides_per_group: new_style.rolling_fashion == 'translation' ? Number(new_content.carousel_col) + 1 : 1,
|
||||
|
||||
});
|
||||
// 默认数据
|
||||
const product_style_list = [
|
||||
{ name: '单列展示', value: '0', width:110, height: 83 },
|
||||
{ name: '两列展示(纵向)', value: '1', width:180, height: 180 },
|
||||
{ name: '大图展示', value: '2', width:0, height: 180 },
|
||||
{ name: '无图模式', value: '3', width:0, height: 0 },
|
||||
{ name: '左右滑动展示', value: '4', width:0, height: 0 },
|
||||
];
|
||||
const scale = sys_width / 390;
|
||||
let img_style = ``;
|
||||
if (['0'].includes(new_content.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_width == 'number') {
|
||||
img_style += `width: ${ new_style.content_img_width * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_content.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `width: ${ list[0].width * scale }px;`;
|
||||
} else {
|
||||
img_style += 'width: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!['3', '4'].includes(new_content.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_height == 'number') {
|
||||
img_style += `height: ${ new_style.content_img_height * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_content.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `height: ${ list[0].height * scale }px;`;
|
||||
} else {
|
||||
img_style += 'height: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
// 背景图的处理
|
||||
const article_data = {
|
||||
background_img_style: new_style?.article_background_img_style || '',
|
||||
background_img: new_style?.article_background_img || '',
|
||||
}
|
||||
const article_margin = new_style.value?.margin || old_margin;
|
||||
const margin_width = article_margin.margin_left + article_margin.margin_right;
|
||||
// 渐变效果
|
||||
const all_style = gradient_handle(new_style?.article_color_list || [], new_style?.article_direction || '') + margin_computer(article_margin) + box_shadow_computer(new_style) + border_computer(new_style);
|
||||
// 文章样式
|
||||
if (this.article_theme == '0') {
|
||||
this.setData({
|
||||
img_size: img_style,
|
||||
article_style: this.content_radius + all_style,
|
||||
article_img_style: this.content_spacing + this.content_padding + background_computer(article_data)
|
||||
});
|
||||
} else if (this.article_theme == '1') {
|
||||
this.setData({
|
||||
img_size: img_style,
|
||||
article_style: `width: calc(50% - ${new_style.article_spacing + (margin_width * 2) / 2}px);` + this.content_radius + all_style,
|
||||
article_img_style: background_computer(article_data)
|
||||
});
|
||||
} else if (this.article_theme == '2') {
|
||||
this.setData({
|
||||
img_size: img_style,
|
||||
article_style: this.content_radius + all_style,
|
||||
article_img_style: background_computer(article_data)
|
||||
});
|
||||
} else if (this.article_theme == '3') {
|
||||
this.setData({
|
||||
style: `padding: 0 ${new_style.content_spacing}px;background:#fff;` + this.content_radius,
|
||||
});
|
||||
} else if (this.article_theme == '4') {
|
||||
// 更新轮播图的key,确保更换时能重新更新轮播图
|
||||
const temp_carousel_col = new_content.carousel_col || '1';
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = temp_carousel_col !== '0' ? ((new_style.article_spacing * temp_carousel_col - 1) + (margin_width * temp_carousel_col)) / temp_carousel_col : '0';
|
||||
const multicolumn_columns_width = new_style.rolling_fashion == 'translation' ? `margin-right: ${ new_style.article_spacing + article_margin.margin_right }px;width:100%;` : `width:calc(${100 / (Number(temp_carousel_col) + 1)}% - ${gap * 2}rpx);min-width:calc(${100 / (Number(temp_carousel_col) + 1)}% - ${gap * 2}rpx);`;
|
||||
const { name_bg_color_list = [], name_bg_direction = '180deg', name_bg_radius, name_bg_padding, name_bg_margin } = new_style;
|
||||
const data = {
|
||||
color_list: name_bg_color_list,
|
||||
direction: name_bg_direction,
|
||||
}
|
||||
let location = 'position:absolute;bottom:0;left:0;right:0;'
|
||||
// 轮播宽度
|
||||
this.setData({
|
||||
// 滚动时间
|
||||
interval_time: (new_style.interval_time || 2) * 1000,
|
||||
// 是否滚动修改
|
||||
is_roll: new_style.is_roll,
|
||||
// article_item_height: `height: ${new_style.article_height }px`,
|
||||
article_style: this.content_radius + all_style + multicolumn_columns_width,
|
||||
// 轮播高度
|
||||
carousel_height_computer: new_style.article_height * scale + 'px',
|
||||
// 文章内容高度
|
||||
article_name_height_computer: `height:${new_style.name_size * 2.4 * 2}rpx;line-height:${new_style.name_size * 1.2 * 2}rpx;`,
|
||||
float_name_style: gradient_computer(data) + (!isEmpty(name_bg_radius) ? radius_computer(name_bg_radius) : '') + (!isEmpty(name_bg_padding) ? padding_computer(name_bg_padding) : '' ) + (!isEmpty(name_bg_padding) ? margin_computer(name_bg_margin) : '') + location,
|
||||
article_img_style: background_computer(article_data)
|
||||
});
|
||||
// 文章轮播数据
|
||||
const cloneList = JSON.parse(JSON.stringify(this.data_list));
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = Number(temp_carousel_col) + 1;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({ carousel_list: cloneList.slice(i * num, (i + 1) * num) });
|
||||
}
|
||||
this.setData({
|
||||
article_carousel_list: nav_list,
|
||||
});
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
this.setData({
|
||||
article_carousel_list: [{ carousel_list: cloneList }],
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
carousel_list: [item],
|
||||
});
|
||||
});
|
||||
this.setData({
|
||||
article_carousel_list: nav_list,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.propIsCommonStyle) {
|
||||
this.setData({
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
}
|
||||
},
|
||||
// 文章主题样式
|
||||
article_theme_class_computer(theme) {
|
||||
switch (theme) {
|
||||
case '0':
|
||||
return 'style1 flex-col';
|
||||
case '1':
|
||||
return 'style2 flex-row flex-wrap';
|
||||
case '2':
|
||||
return 'style3 flex-col';
|
||||
case '3':
|
||||
return 'style4 flex-col';
|
||||
default:
|
||||
return 'style5';
|
||||
}
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.style1 {
|
||||
.item {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
.style2 {
|
||||
.item {
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.style3 {
|
||||
.item {
|
||||
width: 100%;
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.style4 {
|
||||
.item {
|
||||
width: 100%;
|
||||
&:not(:last-child) {
|
||||
border-bottom: 2rpx solid #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
.style5 {
|
||||
.item {
|
||||
width: 100%;
|
||||
.img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
264
components/diy/article-tabs.vue
Normal file
264
components/diy/article-tabs.vue
Normal file
@@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<!-- 文章列表 -->
|
||||
<view class="article-tabs ou" :class="'article-tabs-' + propKey" :style="style_container">
|
||||
<view class="ou" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="article_tabs" :propIsTop="top_up == '1'" :propTop="sticky_top" :propStyle="tabs_style" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propCustomNavHeight="propIsTabsUseSafeDistance ? (propCustomNavHeight * 2 + 'rpx') : '0rpx'" :propTabsBackground="tabs_background" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" @onTabsTap="tabs_click_event"></componentDiyModulesTabsView>
|
||||
<view :style="article_margin_top">
|
||||
<view :style="article_container">
|
||||
<view :style="article_img_container">
|
||||
<componentDiyArticleList :propKey="diy_key" :propValue="article_tabs" :propIsCommonStyle="false"></componentDiyArticleList>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, background_computer, gradient_computer, radius_computer, isEmpty, box_shadow_computer, border_computer, old_border_and_box_shadow, old_margin, old_padding } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
import componentDiyArticleList from '@/components/diy/article-list'; // 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
// 距离顶部高度
|
||||
propTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 自定义导航栏高度
|
||||
propCustomNavHeight: {
|
||||
type: Number,
|
||||
default: 33,
|
||||
},
|
||||
// 滚动距离
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 顶部导航是否开启沉浸模式
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
// 选项卡是否使用安全距离
|
||||
propIsTabsUseSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
componentDiyArticleList,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
article_tabs: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
tabs_style: '',
|
||||
tabs_top: 0,
|
||||
tabs_background: 'background:transparent',
|
||||
custom_nav_height: 33,
|
||||
diy_key: '',
|
||||
// 选项卡背景设置
|
||||
article_margin_top: '',
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 商品区域背景设置
|
||||
article_container: '',
|
||||
article_img_container: '',
|
||||
// #ifdef MP
|
||||
nav_safe_space: bar_height + 5,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
nav_safe_space: bar_height + 7,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
nav_safe_space: bar_height + 0,
|
||||
// #endif
|
||||
// 选项卡默认数据
|
||||
tabs_index: 0,
|
||||
sticky_top: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听滚动距离
|
||||
propScrollTop(newVal) {
|
||||
if (newVal + this.sticky_top + this.custom_nav_height > this.tabs_top + this.nav_safe_space && this.top_up == '1') {
|
||||
let new_style = this.propValue.style || {};
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (tabs_bg.length > 0 && (tabs_bg[0].color || null) != null) {
|
||||
new_tabs_background = gradient_computer(new_style.common_style);
|
||||
}
|
||||
let new_tabs_background_img = background_computer(new_style.common_style);
|
||||
if (new_tabs_background_img.length > 0) {
|
||||
new_tabs_background_img += 'background-position: top left;';
|
||||
}
|
||||
this.tabs_background = (new_tabs_background.length > 0 ? new_tabs_background : 'background:#fff;') + new_tabs_background_img;
|
||||
} else {
|
||||
this.tabs_background = 'background:transparent';
|
||||
}
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
this.setData({
|
||||
diy_key: val,
|
||||
});
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
self.getTop();
|
||||
});
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 获取自定义导航栏高度
|
||||
this.setData({
|
||||
custom_nav_height: this.propCustomNavHeight,
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
let new_content = this.propValue.content || {};
|
||||
let new_style = this.propValue.style || {};
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
|
||||
const new_tabs_data = new_data.content.tabs_list[this.tabs_index] || {};
|
||||
new_data.content.theme = new_data.content.article_theme;
|
||||
new_data.content.data_type = new_tabs_data.data_type;
|
||||
new_data.content.category = new_tabs_data.category;
|
||||
new_data.content.carousel_col = new_data.content.article_carousel_col;
|
||||
new_data.content.data_list = new_tabs_data.data_list;
|
||||
new_data.content.data_auto_list = new_tabs_data.data_auto_list;
|
||||
new_data.content.data_ids = new_tabs_data.data_ids;
|
||||
new_data.content.number = new_tabs_data.number;
|
||||
new_data.content.sort = new_tabs_data.sort;
|
||||
new_data.content.sort_rules = new_tabs_data.sort_rules;
|
||||
new_data.content.field_show = new_data.content.field_show;
|
||||
new_data.content.is_cover = new_tabs_data.is_cover;
|
||||
// 公共样式
|
||||
const common_style = new_style.common_style;
|
||||
let tabs_style_obj = {
|
||||
padding_top: common_style.padding_top - this.propCustomNavHeight < 0 ? 0 : common_style.padding_top - this.propCustomNavHeight,
|
||||
padding_left: common_style.padding_left,
|
||||
padding_right: common_style.padding_right,
|
||||
};
|
||||
let new_tabs_style = padding_computer(tabs_style_obj) + margin_computer(tabs_style_obj) + `position:relative;left: -${tabs_style_obj.padding_left * 2}rpx;right: -${tabs_style_obj.padding_right * 2}rpx;width:100%;`;
|
||||
// 如果是历史数据的话,就执行默认添加下边距
|
||||
if (isEmpty(new_style.tabs_padding)) {
|
||||
new_tabs_style += 'padding-bottom: 20rpx;';
|
||||
}
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, article_content_color_list = [], article_content_direction = '', article_content_background_img_style = '', article_content_background_img = [], article_content_margin = old_margin, article_content_padding = old_padding, article_content_radius = old_radius } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
};
|
||||
// 文章区域背景设置
|
||||
const article_content_data = {
|
||||
color_list: article_content_color_list,
|
||||
direction: article_content_direction,
|
||||
background_img_style: article_content_background_img_style,
|
||||
background_img: article_content_background_img,
|
||||
};
|
||||
const article_content = new_style?.article_content || old_border_and_box_shadow;
|
||||
const tabs_content = new_style?.tabs_content || old_border_and_box_shadow;
|
||||
this.setData({
|
||||
top_up: new_content.tabs_top_up,
|
||||
sticky_top: this.propTop + (new_style?.tabs_margin?.margin_top || 0),
|
||||
article_tabs: new_data,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
tabs_style: new_tabs_style,
|
||||
article_margin_top: 'margin-top:' + (new_style?.article_content_spacing || 0) * 2 + 'rpx',
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(new_style?.tabs_margin || old_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + 'overflow: hidden;',
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
article_container: gradient_computer(article_content_data) + margin_computer(article_content_margin) + radius_computer(article_content_radius) + box_shadow_computer(article_content) + border_computer(article_content) + 'overflow: hidden;',
|
||||
article_img_container: background_computer(article_content_data) + padding_computer(article_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
});
|
||||
},
|
||||
// tabs切换事件
|
||||
tabs_click_event(index) {
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
new_data.content.theme = new_data.content.article_theme;
|
||||
new_data.content.data_type = new_data.content.tabs_list[index].data_type;
|
||||
new_data.content.category = new_data.content.tabs_list[index].category;
|
||||
new_data.content.carousel_col = new_data.content.article_carousel_col;
|
||||
new_data.content.data_list = new_data.content.tabs_list[index].data_list;
|
||||
new_data.content.data_auto_list = new_data.content.tabs_list[index].data_auto_list;
|
||||
new_data.content.data_ids = new_data.content.tabs_list[index].data_ids;
|
||||
new_data.content.number = new_data.content.tabs_list[index].number;
|
||||
new_data.content.sort = new_data.content.tabs_list[index].sort;
|
||||
new_data.content.sort_rules = new_data.content.tabs_list[index].sort_rules;
|
||||
new_data.content.field_show = new_data.content.field_show;
|
||||
new_data.content.is_cover = new_data.content.tabs_list[index].is_cover;
|
||||
this.setData({
|
||||
tabs_index: index,
|
||||
article_tabs: new_data,
|
||||
diy_key: Math.random(),
|
||||
});
|
||||
},
|
||||
// 获取商品距离顶部的距离
|
||||
getTop() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.article-tabs-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_style = new_data.style || {};
|
||||
this.setData({
|
||||
tabs_top: res.top - (new_style.common_style?.margin_top || 0) + (new_style?.tabs_margin?.margin_top || 0),
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tabs-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
64
components/diy/auxiliary-blank.vue
Normal file
64
components/diy/auxiliary-blank.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const { height } = this.propValue.content;
|
||||
const { line_color, common_style } = this.propValue.style;
|
||||
this.setData({
|
||||
style: `height: ${height * 2}rpx;background: ${line_color || 'transparent'};`,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.right-0 {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
</style>
|
||||
64
components/diy/auxiliary-line.vue
Normal file
64
components/diy/auxiliary-line.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<!-- 横线 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// key
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 边框设置
|
||||
let border_content = `border-bottom-style: ${new_content?.styles || 'solid'};`;
|
||||
// 边框颜色设置
|
||||
let border_style = `border-bottom-width: ${new_style.line_width * 2 || 2}rpx; border-bottom-color: ${new_style.line_color || 'rgba(204, 204, 204, 1)'};`;
|
||||
this.setData({
|
||||
style: border_content + border_style,
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
371
components/diy/carousel.vue
Normal file
371
components/diy/carousel.vue
Normal file
@@ -0,0 +1,371 @@
|
||||
<template>
|
||||
<view class="pr" :style="style_container + swiper_bg_style">
|
||||
<view class="pa top-0 wh-auto ht-auto" :style="swiper_bg_img_style"></view>
|
||||
<view class="pr" :style="style_img_container + (!isEmpty(swiper_bg_img_style) ? swiper_bg_img_style_null : '')">
|
||||
<swiper circular="true" :autoplay="form.is_roll == '1'" :interval="form.interval_time * 1000" :display-multiple-items="slides_per_group" :duration="500" :style="{ height: swiper_height }" :previous-margin="previousMargin" :next-margin="nextMargin" @change="slideChange">
|
||||
<block v-if="form.carousel_type == 'card'">
|
||||
<swiper-item v-for="(item, index) in new_list" :key="index">
|
||||
<view class="flex-row align-c wt-auto ht-auto" :data-value="item.carousel_link.page" @tap="url_open">
|
||||
<view class="swiper-item" :style="img_style" :class="['scale-defalt', { 'scale-1': animationData === index }]">
|
||||
<view class="wh-auto ht-auto">
|
||||
<imageEmpty :propImageSrc="item.carousel_img[0]" :propStyle="img_style" :propImgFit="img_fit" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="new_style.video_is_show == '1' && item.carousel_video.length > 0" :class="{ 'x-middle': new_style.video_location == 'center', 'right-0': new_style.video_location == 'flex-end' }" class="video-class pa oh" :style="{'bottom': new_style.video_bottom * 2 + 'rpx'}">
|
||||
<view class="flex-row gap-5 align-c" :style="video_style" :data-value="item.carousel_video" @tap.stop="video_play">
|
||||
<block v-if="new_style.video_type == 'img'">
|
||||
<view class="video_img">
|
||||
<imageEmpty :propImageSrc="new_style.video_img[0]" propImgFit="aspectFill" propErrorStyle="width: 28rpx;height: 28rpx;"></imageEmpty>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<iconfont :name="!isEmpty(new_style.video_icon_class) ? 'icon-' + new_style.video_icon_class : 'icon-bofang'" size="'28rpx'" :color="new_style.video_icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</block>
|
||||
<text v-if="!isEmpty(item.video_title)" :style="{ color: new_style.video_title_color, 'font-size': new_style.video_title_size * 2 + 'rpx', 'text-wrap': 'nowrap' }">{{ item.video_title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</block>
|
||||
<block v-else>
|
||||
<swiper-item v-for="(item, index) in new_list" :key="index">
|
||||
<view class="ht-auto" :style="['oneDragOne', 'twoDragOne'].includes(form.carousel_type) ? 'padding-right:' + new_style.image_spacing * 2 + 'rpx;' : ''" :data-value="item.carousel_link.page" @tap="url_open">
|
||||
<view class="wh-auto ht-auto pr" :style="img_style">
|
||||
<imageEmpty :propImageSrc="item.carousel_img[0]" :propStyle="img_style" :propImgFit="img_fit" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-if="new_style.video_is_show == '1' && item.carousel_video.length > 0" :class="{ 'x-middle': new_style.video_location == 'center', 'right-0': new_style.video_location == 'flex-end' }" class="video-class pa oh" :style="{'bottom': new_style.video_bottom * 2 + 'rpx'}">
|
||||
<view class="flex-row gap-5 align-c" :style="video_style" :data-value="item.carousel_video" @tap.stop="video_play">
|
||||
<block v-if="new_style.video_type == 'img'">
|
||||
<view class="video_img">
|
||||
<imageEmpty :propImageSrc="new_style.video_img[0]" propImgFit="aspectFill" propErrorStyle="width: 28rpx;height: 28rpx;"></imageEmpty>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<iconfont :name="!isEmpty(new_style.video_icon_class) ? 'icon-' + new_style.video_icon_class : 'icon-bofang'" size="'28rpx'" :color="new_style.video_icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</block>
|
||||
<text v-if="!isEmpty(item.video_title)" :style="{ color: new_style.video_title_color, 'font-size': new_style.video_title_size * 2 + 'rpx', 'text-wrap': 'nowrap' }">{{ item.video_title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</block>
|
||||
</swiper>
|
||||
<view v-if="new_style.is_show == '1'" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<template v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ form.carousel_list.length }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index2) in form.carousel_list" :key="index2" :style="indicator_style + (actived_index == index2 ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, radius_computer, isEmpty, gradient_computer, padding_computer, get_indicator_location_style, get_indicator_style, background_computer } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propIsCommon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
// 通用样式显示
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
// 图片的设置
|
||||
img_style: '',
|
||||
// 指示器的样式
|
||||
indicator_style: '',
|
||||
seat_list: [],
|
||||
new_list: [],
|
||||
// 指示器选中的位置
|
||||
actived_index: 0,
|
||||
interval_types: '',
|
||||
img_fit: '',
|
||||
dot_style: '',
|
||||
video_style: '',
|
||||
popup_width: '0rpx',
|
||||
popup_height: '0rpx',
|
||||
// 样式二的处理
|
||||
animation: '',
|
||||
animationData: 0,
|
||||
previousMargin: '0rpx',
|
||||
nextMargin: '0rpx',
|
||||
slides_per_group: 1,
|
||||
// hackReset: true,
|
||||
// 轮播图的高度
|
||||
swiper_height: 50,
|
||||
// 轮播时的背景样式
|
||||
swiper_bg_style: '',
|
||||
swiper_bg_img_style: '',
|
||||
swiper_bg_img_style_null: `background-image: url('')`
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
// 获取当前手机的宽度
|
||||
const { windowWidth } = uni.getSystemInfoSync();
|
||||
// 将80%的宽度分成16份
|
||||
const block = (windowWidth * 0.8) / 16;
|
||||
|
||||
const { common_style, actived_color } = new_style;
|
||||
// scaleToFill 对应 fill aspectFit 对应 contain aspectFill 对应 cover
|
||||
let fit = '';
|
||||
if (new_form.img_fit == 'contain') {
|
||||
fit = 'aspectFit';
|
||||
} else if (new_form.img_fit == 'fill') {
|
||||
fit = 'scaleToFill';
|
||||
} else if (new_form.img_fit == 'cover') {
|
||||
fit = 'aspectFill';
|
||||
}
|
||||
const { margin_left, margin_right, padding_left, padding_right } = new_style.common_style;
|
||||
const width = sys_width - margin_left - margin_right - padding_left - padding_right - this.propOuterContainerPadding;
|
||||
const scale = width / 390;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
seat_list: this.get_seat_list(new_form),
|
||||
new_list: new_form.carousel_list.concat(this.get_seat_list(new_form)),
|
||||
popup_width: block * 16 * 2 + 'rpx', // 视频的宽度,依照16:9比例来算
|
||||
popup_height: block * 9 * 2 + 'rpx', // 视频的高度
|
||||
style_container: this.propIsCommon ? common_styles_computer(common_style) : '', // 公共样式显示
|
||||
style_img_container: this.propIsCommon ? common_img_computer(common_style, this.propIndex) : '', // 公共样式显示
|
||||
img_style: radius_computer(new_style), // 图片的设置
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style),
|
||||
dot_style: `bottom: ${ new_style.indicator_bottom * scale }px;`, // 指示器位置
|
||||
img_fit: fit, // 图片风格 默认为aspectFill
|
||||
video_style: this.get_video_style(new_style), // 视频播放按钮显示逻辑
|
||||
swiper_height: new_form.height * scale + 'px', // 轮播图高度
|
||||
swiper_bg_style: this.get_swiper_bg_style(new_form, 0),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(new_form, 0),
|
||||
});
|
||||
// 风格二显示逻辑
|
||||
if (new_form.carousel_type == 'card') {
|
||||
// this.$nextTick(() => {
|
||||
this.setData({
|
||||
previousMargin: '41px',
|
||||
nextMargin: '41px',
|
||||
animationData: 0,
|
||||
});
|
||||
// });
|
||||
} else if (new_form.carousel_type != 'inherit') {
|
||||
// 风格三,四显示逻辑
|
||||
// this.$nextTick(() => {
|
||||
this.setData({
|
||||
nextMargin: '50px',
|
||||
slides_per_group: new_form.carousel_type == 'twoDragOne' ? 2 : 1,
|
||||
});
|
||||
// });
|
||||
}
|
||||
},
|
||||
get_swiper_bg_style(form, actived_index) {
|
||||
if (!this.propIsCommon) {
|
||||
return '';
|
||||
}
|
||||
const style = form?.carousel_list?.[actived_index]?.style;
|
||||
if (style && !isEmpty(style.color_list)) {
|
||||
const color_list = style.color_list;
|
||||
const list = color_list.filter((item) => !isEmpty(item.color));
|
||||
if (list.length > 0) {
|
||||
try {
|
||||
return gradient_computer(style);
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
get_swiper_bg_img_style(form, actived_index) {
|
||||
if (!this.propIsCommon) {
|
||||
return '';
|
||||
}
|
||||
const { carousel_img, style = {} } = form?.carousel_list[actived_index] || {};
|
||||
// 如果是自定义的图片 判断图片是否存在
|
||||
if (!isEmpty(carousel_img) && style?.background_type == 'carousel') {
|
||||
// 如果是使用轮播图,判断轮播图是否存在
|
||||
const data = {
|
||||
background_img: carousel_img,
|
||||
background_img_style: style?.background_img_style || '2',
|
||||
}
|
||||
return background_computer(data) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
} else if (!isEmpty(style?.background_img)) {
|
||||
return background_computer(style) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
get_seat_list(form) {
|
||||
if (form.carousel_list.length > 3) {
|
||||
return [];
|
||||
} else {
|
||||
let seat_list = [];
|
||||
const list = JSON.parse(JSON.stringify(form.carousel_list));
|
||||
switch (list.length) {
|
||||
case 1:
|
||||
seat_list = [...list, ...list, ...list];
|
||||
break;
|
||||
case 2:
|
||||
seat_list.push(...list);
|
||||
break;
|
||||
case 3:
|
||||
seat_list.push(...list);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return seat_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
let actived_index = e.detail.current;
|
||||
if (e.detail.current > this.form.carousel_list.length - 1) {
|
||||
const seat_length = this.seat_list.length;
|
||||
if (this.form.carousel_list.length > 1) {
|
||||
actived_index = actived_index - seat_length;
|
||||
} else {
|
||||
actived_index = 0;
|
||||
}
|
||||
}
|
||||
if (!this.propIsCommon) {
|
||||
this.$emit('slideChange', actived_index);
|
||||
}
|
||||
this.setData({
|
||||
animationData: e.detail.current,
|
||||
actived_index: actived_index,
|
||||
swiper_bg_style: this.get_swiper_bg_style(this.form, actived_index),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(this.form, actived_index),
|
||||
});
|
||||
},
|
||||
get_video_style(new_style) {
|
||||
const { video_radius, video_color_list, video_direction, video_title_color, video_padding } = new_style;
|
||||
let style = ``;
|
||||
if (!isEmpty(video_radius)) {
|
||||
style += radius_computer(video_radius);
|
||||
}
|
||||
const data = {
|
||||
color_list: video_color_list,
|
||||
direction: video_direction,
|
||||
};
|
||||
style += gradient_computer(data) + padding_computer(video_padding) + `color: ${video_title_color};box-sizing: border-box;`;
|
||||
return style;
|
||||
},
|
||||
video_play(e) {
|
||||
const list = e.currentTarget.dataset.value;
|
||||
if (!isEmpty(list)) {
|
||||
this.$emit('onVideoPlay', list[0].url, this.popup_width, this.popup_height);
|
||||
}
|
||||
},
|
||||
url_open(link) {
|
||||
app.globalData.url_event(link);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dot-center {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.dot-right {
|
||||
right: 0;
|
||||
}
|
||||
.dot {
|
||||
z-index: 1;
|
||||
padding-left: 20rpx;
|
||||
padding-right: 20rpx;
|
||||
.dot-item {
|
||||
margin: 0 6rpx;
|
||||
}
|
||||
}
|
||||
.swiper-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.swiper-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 90%;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scale-defalt {
|
||||
position: relative;
|
||||
border-radius: 20rpx;
|
||||
transform: scale(1);
|
||||
transition: -webkit-transform 400ms linear, transform 400ms linear;
|
||||
transform-origin: 50% 50% 0px;
|
||||
&.scale-1 {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
.video_img {
|
||||
max-width: 120rpx;
|
||||
height: 28rpx;
|
||||
}
|
||||
.video-class {
|
||||
max-width: 100%;
|
||||
padding-right: 20rpx;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
.x-middle {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
</style>
|
||||
1013
components/diy/coupon.vue
Normal file
1013
components/diy/coupon.vue
Normal file
File diff suppressed because it is too large
Load Diff
337
components/diy/custom.vue
Normal file
337
components/diy/custom.vue
Normal file
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style_content_container">
|
||||
<view class="w h pr" :style="style_content_img_container">
|
||||
<template v-if="!isEmpty(form.data_source) && form.data_source_is_loop !== '0'">
|
||||
<template v-if="data_source_content_list.length > 0 && form.data_source_direction == 'vertical'">
|
||||
<view class="flex-row flex-wrap" :style="'row-gap:' + new_style.row_gap + 'px;column-gap:' + new_style.column_gap + 'px;'">
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" class="ht-auto" :style="gap_width">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1">
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else-if="data_source_content_list.length > 0 && ['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" class="oh ht-auto">
|
||||
<swiper class="w flex" circular="true" :vertical="form.data_source_direction != 'horizontal'" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_view" :style="{ width: '100%', height: swiper_height + 'px' }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in data_source_content_list" :key="index">
|
||||
<view :class="form.data_source_direction != 'horizontal' ? 'ht-auto ' : 'flex-row'" :style="form.data_source_direction == 'horizontal' ? 'column-gap:' + new_style.column_gap + 'px;' : ''">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" class="wh-auto ht-auto" :style="style_chunk_container + swiper_width + (form.data_source_direction == 'horizontal' ? gap_width : 'margin-bottom:' + content_outer_spacing_magin)">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propFieldList="field_list" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="new_style.is_show == '1' && data_source_content_list.length > 1" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<block v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ data_source_content_list.length }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" :style="indicator_style + (actived_index == index ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<template v-else>
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="!isEmpty(form.data_source) && form.data_source_is_loop == '0'">
|
||||
<view class="h" :style="style_chunk_container">
|
||||
<view class="w h oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propSourceList="{}" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propFieldList="field_list" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer, percentage_count, isEmpty, get_indicator_style, get_indicator_location_style, border_width } from '@/common/js/common/common.js';
|
||||
import dataRendering from '@/components/diy/modules/custom/data-rendering.vue';
|
||||
const app = getApp();
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dataRendering
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propIsCommonStyle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
scale: 1,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
div_width: 0,
|
||||
div_height: 0,
|
||||
custom_list_length: 0,
|
||||
source_list: {
|
||||
// 存放手动输入的id
|
||||
data_ids: [],
|
||||
// 手动输入
|
||||
data_list: [],
|
||||
// 自动
|
||||
data_auto_list: [],
|
||||
},
|
||||
data_source_content_list: [],
|
||||
data_source: '',
|
||||
// 内容样式
|
||||
style_content_container: '',
|
||||
style_content_img_container: '',
|
||||
// 数据样式
|
||||
style_chunk_container: '',
|
||||
style_chunk_img_container: '',
|
||||
// 指示器选中的下标
|
||||
actived_index: 0,
|
||||
// 轮播高度
|
||||
swiper_height: 0,
|
||||
swiper_width: 'width: 100%;',
|
||||
// 指示器样式
|
||||
indicator_location_style: '',
|
||||
indicator_style: '',
|
||||
slides_per_view: 1,
|
||||
show_data: { data_key: 'id', data_name: 'name' },
|
||||
old_data_style: {
|
||||
color_list: [{ color: 'rgb(244, 252, 255)', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
content_outer_spacing_magin: '0rpx',
|
||||
gap_width: '',
|
||||
field_list: [],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
percentage_count,
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
// 不包含新创建的数组时,将历史数据放到手动添加数组中
|
||||
if (!Object.keys(new_form.data_source_content).includes('data_auto_list') && !Object.keys(new_form.data_source_content).includes('data_list')) {
|
||||
//深拷贝一下,保留历史数据
|
||||
const data = JSON.parse(JSON.stringify(new_form.data_source_content));
|
||||
new_form.data_source_content = this.source_list;
|
||||
// 如果老数组中有数据,将数据放到新数组中
|
||||
if (!isEmpty(data)) {
|
||||
new_form.data_source_content.data_list = [ data ];
|
||||
}
|
||||
}
|
||||
// 数据来源的内容
|
||||
let list = [];
|
||||
if (new_form.is_custom_data == '1') {
|
||||
if (Number(new_form.data_source_content.data_type) === 0) {
|
||||
list = new_form.data_source_content?.data_list || [];
|
||||
} else {
|
||||
list = !isEmpty(new_form.data_source_content) ?
|
||||
new_form.data_source_content.data_auto_list.map(item => ({
|
||||
id: Math.random(),
|
||||
new_cover: [],
|
||||
new_title: '',
|
||||
data: item,
|
||||
})) : [];
|
||||
}
|
||||
} else {
|
||||
list = new_form.data_source_content?.data_list || [];
|
||||
}
|
||||
// 数组处理
|
||||
const new_list = list.length > 0 ? this.get_list(list, new_form, new_style) : [];
|
||||
// 初始化数据
|
||||
const { common_style, data_content_style, data_style } = new_style;
|
||||
// 外层左右间距
|
||||
const outer_spacing = (common_style?.margin_left || 0) + (common_style?.margin_right || 0) + (common_style?.padding_left || 0) + (common_style?.padding_right || 0) + border_width(common_style);
|
||||
// 内容左右间距
|
||||
const content_spacing = (data_content_style?.margin_left || 0) + (data_content_style?.margin_right || 0) + (data_content_style?.padding_left || 0) + (data_content_style?.padding_right || 0) + border_width(data_content_style);
|
||||
// 数据左右间距
|
||||
const internal_spacing = (data_style?.margin_left || 0) + (data_style?.margin_right || 0) + (data_style?.padding_left || 0) + (data_style?.padding_right || 0) + border_width(data_style);
|
||||
// 一行显示的数量
|
||||
const carousel_col = Number(new_form.data_source_carousel_col);
|
||||
// 数据间距
|
||||
const data_spacing = ['vertical', 'horizontal'].includes(new_form.data_source_direction) ? new_style.column_gap * (carousel_col - 1) : 0;
|
||||
// 自定义组件宽度
|
||||
const width = sys_width - outer_spacing - content_spacing - internal_spacing - data_spacing - this.propOuterContainerPadding;
|
||||
const new_data_style = !isEmpty(new_style.data_style) ? new_style.data_style : this.old_data_style;
|
||||
const new_data_content_style = !isEmpty(new_style.data_content_style)? new_style.data_content_style : this.old_data_style;
|
||||
// 判断是平移还是整屏滚动
|
||||
const { padding_top = 0, padding_bottom = 0, margin_bottom = 0, margin_top = 0 } = new_data_style;
|
||||
let swiper_height = 0;
|
||||
const scale_number = width / 390;
|
||||
const new_scale = scale_number > 0 ? scale_number : 0;
|
||||
// 间距
|
||||
const space_between = new_form.data_source_direction == 'horizontal' ? new_style.column_gap : new_style.row_gap;
|
||||
let col = Number(new_form.data_source_carousel_col);
|
||||
// 轮播图高度控制
|
||||
if (new_form.data_source_direction == 'horizontal') {
|
||||
swiper_height = new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top;
|
||||
} else {
|
||||
// 商品数量大于列数的时候,高度是列数,否则是当前的数量
|
||||
col = new_list.length > carousel_col ? carousel_col : new_list.length;
|
||||
swiper_height = (new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top) * col + ((Number(new_form.data_source_carousel_col) - 1) * space_between);
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.column_gap * (carousel_col - 1)) / carousel_col;
|
||||
// 横向的时候,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
const swiper_width = (new_form.data_source_direction == 'horizontal' && new_style.rolling_fashion != 'translation') ? `width: ${ 100 / carousel_col }%;`: 'width: 100%;';
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
div_width: width,
|
||||
scale: new_scale,
|
||||
custom_list_length: new_form.custom_list.length - 1,
|
||||
style_container: this.propIsCommonStyle ? common_styles_computer(new_style.common_style) + 'box-sizing: border-box;' : '', // 用于样式显示
|
||||
style_img_container: this.propIsCommonStyle ? common_img_computer(new_style.common_style, this.propIndex) : '',
|
||||
style_content_container: common_styles_computer(new_data_content_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_content_img_container: common_img_computer(new_data_content_style),
|
||||
style_chunk_container: common_styles_computer(new_data_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_chunk_img_container: common_img_computer(new_data_style),
|
||||
style_chunk_width: width,
|
||||
div_height: new_form.height,
|
||||
data_source_content_list: new_list,
|
||||
data_source: !isEmpty(new_form.data_source)? new_form.data_source : '',
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style),
|
||||
swiper_height: swiper_height,
|
||||
swiper_width: swiper_width,
|
||||
content_outer_spacing_magin: space_between + 'px',
|
||||
gap_width: `width: calc(${100 / carousel_col}% - ${gap}px);`,
|
||||
slides_per_view: new_style.rolling_fashion == 'translation' ? (new_form.data_source_direction != 'horizontal' ? col : new_form.data_source_carousel_col ) : 1,
|
||||
show_data: new_form?.show_data || { data_key: 'id', data_name: 'name' },
|
||||
field_list: new_form?.field_list || [],
|
||||
});
|
||||
},
|
||||
get_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation' && form.data_source_direction != 'vertical') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.data_source_carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.setData({
|
||||
actived_index: e.detail.current,
|
||||
});
|
||||
},
|
||||
url_event(e, index, split_index) {
|
||||
if (this.data_source == 'goods' && this.data_source_content_list.length > 0) {
|
||||
const list = this.data_source_content_list[index];
|
||||
if (!isEmpty(list) && !isEmpty(list.split_list[split_index])) {
|
||||
const new_list = list.split_list[split_index];
|
||||
if (!isEmpty(new_list)) {
|
||||
// 缓存商品数据
|
||||
app.globalData.goods_data_cache_handle(new_list.data.id, new_list.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
app.globalData.url_open(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
434
components/diy/data-magic.vue
Normal file
434
components/diy/data-magic.vue
Normal file
@@ -0,0 +1,434 @@
|
||||
<template>
|
||||
<view class="img-magic" :style="'height:' + container_size + ';' + style_container">
|
||||
<view class="magic-container w h pr" :style="style_img_container">
|
||||
<view class="pr" :style="'width:calc(100% + ' + outer_spacing + ');height:calc(100% + ' + outer_spacing + ');margin:-' + spacing + ';'">
|
||||
<!-- 风格9 -->
|
||||
<template v-if="form.style_actived == 7">
|
||||
<view class="flex-row align-c jc-c style-size flex-wrap">
|
||||
<view v-for="(item, index) in data_magic_list" :key="index" :style="'margin:' + spacing + ';' + ([0, 1].includes(index) ? 'width:calc(50% - ' + outer_spacing + ');height:calc(50% - ' + outer_spacing + ')' : 'width:calc((100% / 3) - ' + outer_spacing + ');height:calc(50% - ' + outer_spacing + ')')" class="style9">
|
||||
<view class="w h flex-row" :style="item.data_style.background_style + content_radius">
|
||||
<view class="re flex-1 oh" :style="item.data_style.background_img_style">
|
||||
<template v-if="item.data_content.data_type == 'goods'">
|
||||
<view class="w h flex-col" :style="'gap:'+ item.data_style.title_data_gap * 2 + 'rpx;'">
|
||||
<view v-if="(!isEmpty(item.data_content.heading_title) || !isEmpty(item.data_content.subtitle)) && [0, 1].includes(index)" :class="'tl' + (item.data_style.title_line == '1' ? ' flex-row align-c' : ' flex-col')" :style="'gap:' + item.data_style.title_gap * 2 + 'rpx;'">
|
||||
<template v-if="item.data_content.heading_title_type && item.data_content.heading_title_type == 'image'">
|
||||
<view v-if="item.data_content.heading_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.heading_img_height) ? item.data_style.heading_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.heading_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.heading_style">{{ item.data_content.heading_title || '' }}</view>
|
||||
</template>
|
||||
<template v-if="item.data_content.subtitle_title_type && item.data_content.subtitle_title_type == 'image'">
|
||||
<view v-if="item.data_content.subtitle_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.subtitle_img_height) ? item.data_style.subtitle_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.subtitle_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.subtitle_style">{{ item.data_content.subtitle || '' }}</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="w h flex-1 oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" :propGoodStyle="item.data_style" :propActived="form.style_actived" propType="product" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'images'">
|
||||
<view class="w h flex-1 oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" propType="img" :propActived="form.style_actived" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'custom'">
|
||||
<customIndex :propKey="propKey + index" :propValue="item" :propMagicScale="magic_scale" :propDataSpacing="new_style.image_spacing" :propDataIndex="index" @onCarouselChange="carousel_change"></customIndex>
|
||||
</template>
|
||||
<template v-else>
|
||||
<videoIndex :propKey="propKey + index" :propValue="item.data_content" :propDataStyle="item.data_style"></videoIndex>
|
||||
</template>
|
||||
<view v-if="item.data_style.is_show == '1' && item.data_content.list.length > 1" :class="['left', 'right'].includes(item.data_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="item.data_style.indicator_location_style">
|
||||
<template v-if="item.data_style.indicator_style == 'num'">
|
||||
<view :style="item.data_style.indicator_styles" class="dot-item">
|
||||
<text class="num-active" :style="{ color: item.data_style.actived_color }">{{ item.actived_index + 1 }}</text
|
||||
><text>/{{ item.data_content.list.length }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item3, index3) in item.data_content.list" :key="index3" :style="item.data_style.indicator_styles + style_actived_color(item, index3)" class="dot-item" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in data_magic_list" :key="index" class="cr-main cube-selected" :style="selected_style(item) + ';margin:' + spacing + ';'">
|
||||
<view class="w h flex-row" :style="item.data_style.background_style + content_radius">
|
||||
<view class="re flex-1 oh" :style="item.data_style.background_img_style">
|
||||
<template v-if="item.data_content.data_type == 'goods'">
|
||||
<view class="w h flex-col" :style="'gap:'+ item.data_style.title_data_gap * 2 + 'rpx;'">
|
||||
<view v-if="!isEmpty(item.data_content.heading_title) || !isEmpty(item.data_content.subtitle)" :class="'tl' + (item.data_style.title_line == '1' ? ' flex-row align-c' : ' flex-col')" :style="'gap:' + item.data_style.title_gap * 2 + 'rpx;'">
|
||||
<template v-if="item.data_content.heading_title_type && item.data_content.heading_title_type == 'image'">
|
||||
<view v-if="item.data_content.heading_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.heading_img_height) ? item.data_style.heading_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.heading_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.heading_style">{{ item.data_content.heading_title || '' }}</view>
|
||||
</template>
|
||||
<template v-if="item.data_content.subtitle_title_type && item.data_content.subtitle_title_type == 'image'">
|
||||
<view v-if="item.data_content.subtitle_title_img.length > 0" class="re oh" :style="'width:100%;height:' + (!isEmpty(item.data_style.subtitle_img_height) ? item.data_style.subtitle_img_height * magic_scale : 0) + 'px'">
|
||||
<image :src="item.data_content.subtitle_title_img[0].url" class="ht-auto max-w" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="ma-0 w text-word-break text-line-1 flex-basis-shrink" :style="item.data_style.subtitle_style">{{ item.data_content.subtitle || '' }}</view>
|
||||
</template>
|
||||
</view>
|
||||
<view class="w h oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" :propGoodStyle="item.data_style" propType="product" :propActived="form.style_actived" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'images'">
|
||||
<view class="w h oh flex-row">
|
||||
<magic-carousel class="flex-1" :propKey="propKey + index" :propValue="item" propType="img" :propActived="form.style_actived" :propDataIndex="index" @onCarouselChange="carousel_change"></magic-carousel>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="item.data_content.data_type == 'custom'">
|
||||
<customIndex :propKey="propKey + index" :propValue="item" :propMagicScale="magic_scale" :propDataSpacing="new_style.image_spacing" :propDataIndex="index" @onCarouselChange="carousel_change"></customIndex>
|
||||
</template>
|
||||
<template v-else>
|
||||
<videoIndex :propKey="propKey + index" :propValue="item.data_content" :propDataStyle="item.data_style"></videoIndex>
|
||||
</template>
|
||||
<view v-if="item.data_style.is_show == '1' && item.data_content.list.length > 1" :class="['left', 'right'].includes(item.data_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="item.data_style.indicator_location_style">
|
||||
<template v-if="item.data_style.indicator_style == 'num'">
|
||||
<view :style="item.data_style.indicator_styles" class="dot-item">
|
||||
<text class="num-active" :style="{ color: item.data_style.actived_color }">{{ item.actived_index + 1 }}</text>
|
||||
<text>/{{ item.data_content.list.length }}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item3, index3) in item.data_content.list" :key="index3" :style="item.data_style.indicator_styles + style_actived_color(item, index3)" class="dot-item" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import magicCarousel from '@/components/diy/modules/data-magic/magic-carousel.vue';
|
||||
import customIndex from '@/components/diy/modules/data-magic/custom/index.vue';
|
||||
import videoIndex from '@/components/diy/modules/data-magic/video/index.vue';
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, radius_computer, percentage_count, isEmpty, padding_computer, margin_computer, old_border_and_box_shadow, old_margin, old_padding, box_shadow_computer, border_computer, get_indicator_location_style, get_indicator_style, border_width } from '@/common/js/common/common.js';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
magicCarousel,
|
||||
customIndex,
|
||||
videoIndex
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
outer_spacing: '',
|
||||
// 图片间距设置
|
||||
spacing: '',
|
||||
// 内容圆角设置
|
||||
content_radius: '',
|
||||
// 图片圆角设置
|
||||
// content_img_radius: '',
|
||||
data_magic_list: [],
|
||||
cubeCellWidth: 0,
|
||||
container_size: 0,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
div_width: 0,
|
||||
magic_scale: 1,
|
||||
// is_unlimited_size: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 根据当前页面大小计算成百分比
|
||||
selected_style() {
|
||||
return (item) => {
|
||||
return `overflow: hidden;width: calc(${this.percentage(this.getSelectedWidth(item))} - ${this.outer_spacing} ); height: calc(${this.percentage(this.getSelectedHeight(item))} - ${this.outer_spacing} ); top: ${this.percentage(this.getSelectedTop(item))}; left: ${this.percentage(this.getSelectedLeft(item))};`;
|
||||
};
|
||||
},
|
||||
style_actived_color() {
|
||||
return (item, index) => {
|
||||
return item.actived_index == index ? `background: ${item.data_style.actived_color};` : '';
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
const container_height = !isEmpty(new_form.container_height) ? new_form.container_height : sys_width;
|
||||
const density = !isEmpty(new_form.magic_cube_density) ? new_form.magic_cube_density : 4;
|
||||
const { margin_left, margin_right } = new_style.common_style;
|
||||
const width = sys_width - margin_left - margin_right - border_width(new_style.common_style) - this.propOuterContainerPadding;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
outer_spacing: new_style.image_spacing * 2 + 'rpx',
|
||||
spacing: new_style.image_spacing + 'rpx',
|
||||
content_radius: radius_computer(new_style.data_radius),
|
||||
// content_img_radius: radius_computer(new_style.img_radius),
|
||||
data_magic_list: this.get_data_magic_list(new_form.data_magic_list, new_style),
|
||||
style_container: common_styles_computer(new_style.common_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
magic_scale: width / 390,
|
||||
div_width: sys_width,
|
||||
cubeCellWidth: sys_width / density,
|
||||
container_size: container_height * (width / 390) + 'px',
|
||||
});
|
||||
},
|
||||
get_data_magic_list(data, new_style) {
|
||||
data.forEach((item) => {
|
||||
const data_content = item.data_content;
|
||||
const data_style = item.data_style;
|
||||
item.actived_index = 0;
|
||||
// 指示器样式
|
||||
data_style.indicator_styles = get_indicator_style(data_style);
|
||||
data_style.indicator_location_style = get_indicator_location_style(data_style);
|
||||
// 获取当前的margin
|
||||
const chunk_margin = data_style?.chunk_margin || old_margin;
|
||||
// 计算左右间距
|
||||
const left_right_width_margin = (chunk_margin?.margin_left || 0) + (chunk_margin?.margin_right || 0);
|
||||
// 计算上下间距
|
||||
const top_bottom_height_margin = (chunk_margin?.margin_top || 0) + (chunk_margin?.margin_bottom || 0);
|
||||
data_style.background_style = gradient_computer(data_style) + margin_computer(data_style?.chunk_margin || old_margin) + `width: calc(100% - ${ left_right_width_margin }px);height:calc(100% - ${ top_bottom_height_margin }px);` + box_shadow_computer(data_style?.data_common_style || old_border_and_box_shadow) + border_computer(data_style?.data_common_style || old_border_and_box_shadow);
|
||||
data_style.background_img_style = background_computer(data_style) + padding_computer(data_style?.chunk_padding || old_padding);
|
||||
// 商品价格处理
|
||||
data_style.goods_price_symbol_style = this.goods_trends_config(data_style, 'price_symbol');
|
||||
data_style.goods_price_unit_style = this.goods_trends_config(data_style, 'price_unit');
|
||||
|
||||
let fit = '';
|
||||
if (data_content.img_fit == 'contain') {
|
||||
fit = 'aspectFit';
|
||||
} else if (data_content.img_fit =='fill') {
|
||||
fit = 'scaleToFill';
|
||||
} else if (data_content.img_fit == 'cover') {
|
||||
fit = 'aspectFill';
|
||||
}
|
||||
data_content.fit = fit;
|
||||
// 商品名称和价格样式
|
||||
data_style.goods_title_style = this.goods_trends_config(data_style, 'title') + `line-height: ${ (item.data_style.goods_title_size + 3) * 2 }rpx;height: ${ (item.data_style.goods_title_size + 3) * 2 }rpx;`;
|
||||
data_style.goods_price_style = this.goods_trends_config(data_style, 'price') + `line-height: ${ item.data_style.goods_price_size * 2 }rpx;height: ${ (item.data_style.goods_title_size + 3) * 2 }rpx;`;
|
||||
const radius = !isEmpty(data_style.img_radius) ? data_style.img_radius : { radius: 4, radius_top_left: 4, radius_top_right: 4, radius_bottom_left: 4, radius_bottom_right: 4 };
|
||||
data_style.get_img_radius = radius_computer(radius);
|
||||
|
||||
data_style.chunk_padding_data = padding_computer(data_style.chunk_padding) + 'box-sizing: border-box;';
|
||||
data_style.heading_style = this.trends_config(data_style, 'heading');
|
||||
data_style.subtitle_style = this.trends_config(data_style, 'subtitle');
|
||||
|
||||
if (data_content.data_type == 'goods') {
|
||||
data_content.list = this.commodity_list(data_content.goods_list, data_content.goods_num, data_content, data_style);
|
||||
} else if (data_content.data_type == 'custom' && ['vertical-scroll', 'horizontal'].includes(data_content.data_source_direction)) {
|
||||
// 是自定义并且是轮播状态的时候,添加数据
|
||||
const list = this.data_source_content_list(data_content);
|
||||
const carousel_col = data_content?.data_source_carousel_col || 1;
|
||||
const num = new_style.rolling_fashion == 'translation' ? list.length : Math.ceil(list.length / carousel_col);
|
||||
data_content.list = Array(num);
|
||||
} else {
|
||||
data_content.list = data_content.images_list;
|
||||
}
|
||||
});
|
||||
return data;
|
||||
},
|
||||
// 数据来源的内容
|
||||
data_source_content_list(data_content){
|
||||
if (data_content.is_custom_data == '1') {
|
||||
if (Number(data_content.data_source_content.data_type) === 0) {
|
||||
return data_content.data_source_content.data_list;
|
||||
} else {
|
||||
return data_content.data_source_content.data_auto_list.map((item) => ({
|
||||
id: Math.random(),
|
||||
new_cover: [],
|
||||
new_title: '',
|
||||
data: item,
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
return data_content.data_source_content.data_list;
|
||||
}
|
||||
},
|
||||
/*
|
||||
** 组装产品的数据
|
||||
** @param {Array} list 商品列表
|
||||
** @param {Number} num 显示数量
|
||||
** @return {Array}
|
||||
*/
|
||||
commodity_list(list, num, data_content, data_style) {
|
||||
if (list.length > 0) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const goods_list = JSON.parse(JSON.stringify(list)).map((item) => ({
|
||||
...item.data,
|
||||
title: !isEmpty(item.new_title) ? item.new_title : item.data.title,
|
||||
new_cover: item.new_cover,
|
||||
}));
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 如果是滑动,需要根据每行显示的个数来区分来拆分数据 translation 表示的是平移
|
||||
if (data_style.rolling_fashion != 'translation') {
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(goods_list.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({ split_list: goods_list.slice(i * num, (i + 1) * num) });
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
return this.rotation_calculation(goods_list, num, data_content, data_style);
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
rotation_calculation(list, num, data_content, data_style) {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
const goods_outerflex = data_content.goods_outerflex;
|
||||
const rotation_direction = data_style.rotation_direction;
|
||||
// 如果是商品是横排的,轮播也是横排的,就不对商品进行拆分/如果商品是竖排的,轮播也是竖排的,不对商品进行拆分
|
||||
if ((goods_outerflex == 'row' && rotation_direction == 'horizontal') || (goods_outerflex == 'col' && rotation_direction == 'vertical')) {
|
||||
list.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(list.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({ split_list: list.slice(i * num, (i + 1) * num) });
|
||||
}
|
||||
return nav_list;
|
||||
}
|
||||
return nav_list;
|
||||
},
|
||||
getSelectedWidth(item) {
|
||||
return (item.end.x - item.start.x + 1) * this.cubeCellWidth;
|
||||
},
|
||||
//计算选中层的高度。
|
||||
getSelectedHeight(item) {
|
||||
return (item.end.y - item.start.y + 1) * this.cubeCellWidth;
|
||||
},
|
||||
//计算选中层的右边距离。
|
||||
getSelectedTop(item) {
|
||||
return (item.start.y - 1) * this.cubeCellWidth;
|
||||
},
|
||||
//计算选中层的左边距离。
|
||||
getSelectedLeft(item) {
|
||||
return (item.start.x - 1) * this.cubeCellWidth;
|
||||
},
|
||||
// 计算成百分比
|
||||
percentage(num) {
|
||||
return percentage_count(num, this.div_width);
|
||||
},
|
||||
goods_trends_config(style, key) {
|
||||
return this.text_style(style[`goods_${key}_typeface`], style[`goods_${key}_size`], style[`goods_${key}_color`]);
|
||||
},
|
||||
// 根据传递的参数,从对象中取值
|
||||
trends_config(style, key) {
|
||||
return this.text_style(style[`${key}_typeface`], style[`${key}_size`], style[`${key}_color`]);
|
||||
},
|
||||
text_style(typeface, size, color) {
|
||||
return `font-weight:${typeface}; font-size: ${size * 2}rpx; color: ${color};`;
|
||||
},
|
||||
carousel_change(actived_index, index) {
|
||||
if (this.data_magic_list[index]) {
|
||||
this.data_magic_list[index].actived_index = actived_index;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 图片魔方是一个正方形,根据宽度计算高度
|
||||
.img-magic {
|
||||
overflow: hidden;
|
||||
}
|
||||
.cube-selected {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.text-line-1 {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.style-size {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
.style9 {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.dot-center {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.dot-right {
|
||||
right: 0;
|
||||
}
|
||||
.dot {
|
||||
z-index: 3;
|
||||
.dot-item {
|
||||
margin: 0 6rpx;
|
||||
}
|
||||
}
|
||||
.gap-20 {
|
||||
gap: 40rpx;
|
||||
}
|
||||
.w {
|
||||
width: 100%;
|
||||
}
|
||||
.h {
|
||||
height: 100%;
|
||||
}
|
||||
.flex-basis-shrink {
|
||||
flex-basis: content;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
</style>
|
||||
334
components/diy/data-tabs.vue
Normal file
334
components/diy/data-tabs.vue
Normal file
@@ -0,0 +1,334 @@
|
||||
<template>
|
||||
<view class="data-tabs ou" :class="'data-tabs-' + propKey" :style="style_container">
|
||||
<view class="ou" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="data_tabs" :propIsTop="top_up == '1'" :propTop="sticky_top" :propStyle="tabs_style" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propCustomNavHeight="propIsTabsUseSafeDistance ? (propCustomNavHeight * 2 + 'rpx') : '0rpx'" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" :propTabsBackground="tabs_background" @onTabsTap="tabs_click_event"></componentDiyModulesTabsView>
|
||||
<view :style="data_margin_top">
|
||||
<view :style="data_container">
|
||||
<view :style="data_img_container">
|
||||
<template v-if="tabs_data_type == 'goods'">
|
||||
<view class="oh" :style="data_content_container">
|
||||
<view class="oh" :style="data_content_img_container">
|
||||
<componentGoodsList ref="diy_goods_list" :propKey="diy_key" :propDiyIndex="propDiyIndex" :propValue="tabs_list" :propIsCommonStyle="false" @goods_buy_event="goods_buy_event"></componentGoodsList>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="tabs_data_type == 'article'">
|
||||
<view class="oh" :style="data_content_container">
|
||||
<view class="oh" :style="data_content_img_container">
|
||||
<componentArticleList :propKey="diy_key" :propValue="tabs_list" :propIsCommonStyle="false"></componentArticleList>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="tabs_data_type == 'custom'">
|
||||
<componentCustomList :propKey="diy_key" :propValue="tabs_list" :propOuterContainerPadding="outer_container_width" :propIsCommonStyle="false"></componentCustomList>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, background_computer, gradient_computer, isEmpty, old_border_and_box_shadow, old_margin, old_radius, old_padding, border_computer, box_shadow_computer, radius_computer, get_math } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
import componentGoodsList from '@/components/diy/goods-list';
|
||||
import componentArticleList from '@/components/diy/article-list';
|
||||
import componentCustomList from '@/components/diy/custom';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
componentGoodsList,
|
||||
componentArticleList,
|
||||
componentCustomList,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propCustomNavHeight: {
|
||||
type: Number,
|
||||
default: 33,
|
||||
},
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 顶部导航是否开启沉浸模式
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propDiyIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 选项卡是否使用安全距离
|
||||
propIsTabsUseSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
data_tabs: {},
|
||||
tabs_list: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
tabs_top: 0,
|
||||
tabs_background: 'background:transparent',
|
||||
custom_nav_height: 33,
|
||||
diy_key: '',
|
||||
// 选项卡背景设置
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
// 商品区域背景设置
|
||||
data_margin_top: '',
|
||||
data_container: '',
|
||||
data_img_container: '',
|
||||
// #ifdef MP
|
||||
nav_safe_space: bar_height + 5,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
nav_safe_space: bar_height + 7,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
nav_safe_space: bar_height + 0,
|
||||
// #endif
|
||||
tabs_style: '',
|
||||
// 选项卡默认数据
|
||||
tabs_index: 0,
|
||||
sticky_top: 0,
|
||||
tabs_data_type: 'goods',
|
||||
outer_container_width: 0,
|
||||
// 数据样式
|
||||
data_content_container: '',
|
||||
data_content_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 滑动固定的背景
|
||||
tabs_sliding_fixed_bg: '',
|
||||
data_content_style: {
|
||||
color_list: [{ color: '', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
// 边框样式
|
||||
border_is_show: '0',
|
||||
border_color: '#FF3F3F',
|
||||
border_style: 'solid',
|
||||
border_size: {
|
||||
padding: 1,
|
||||
padding_top: 1,
|
||||
padding_right: 1,
|
||||
padding_bottom: 1,
|
||||
padding_left: 1,
|
||||
},
|
||||
// 阴影
|
||||
box_shadow_color: '',
|
||||
box_shadow_x: 0,
|
||||
box_shadow_y: 0,
|
||||
box_shadow_blur: 0,
|
||||
box_shadow_spread: 0,
|
||||
}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propScrollTop(newVal) {
|
||||
if (newVal + this.sticky_top + this.custom_nav_height > this.tabs_top + this.nav_safe_space && this.top_up == '1') {
|
||||
let new_style = this.propValue.style || {};
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (tabs_bg.length > 0 && (tabs_bg[0].color || null) != null) {
|
||||
new_tabs_background = gradient_computer(new_style.common_style);
|
||||
}
|
||||
let new_tabs_background_img = background_computer(new_style.common_style);
|
||||
if (new_tabs_background_img.length > 0) {
|
||||
new_tabs_background_img += 'background-position: top left;';
|
||||
}
|
||||
this.tabs_background = (new_tabs_background.length > 0 ? new_tabs_background : 'background:#fff;') + new_tabs_background_img;
|
||||
} else {
|
||||
this.tabs_background = 'background:transparent';
|
||||
}
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.setData({
|
||||
diy_key: val,
|
||||
});
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
self.getTop();
|
||||
});
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 获取自定义导航栏高度
|
||||
this.setData({
|
||||
custom_nav_height: this.propCustomNavHeight,
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_content = new_data.content || {};
|
||||
const new_style = new_data.style || {};
|
||||
// 公共样式
|
||||
const common_style = new_style.common_style;
|
||||
let tabs_style_obj = {
|
||||
padding_top: (common_style.padding_top - this.propCustomNavHeight) < 0 ? 0 : common_style.padding_top - this.propCustomNavHeight,
|
||||
padding_left: common_style.padding_left,
|
||||
padding_right: common_style.padding_right,
|
||||
};
|
||||
let new_tabs_style = padding_computer(tabs_style_obj) + `position:relative;left: -${tabs_style_obj.padding_left * 2}rpx;right: -${tabs_style_obj.padding_right * 2}rpx;width:100%;`;
|
||||
// 如果是历史数据的话,就执行默认添加下边距
|
||||
if (isEmpty(new_style.tabs_padding)) {
|
||||
new_tabs_style += 'padding-bottom: 20rpx;';
|
||||
}
|
||||
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, data_content_color_list = [], data_content_direction = '', data_content_background_img_style = '', data_content_background_img = [], data_content_margin = old_margin, data_content_padding = old_padding, data_content_radius = old_radius } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
};
|
||||
// 商品区域背景设置
|
||||
const data_content_data = {
|
||||
color_list: data_content_color_list,
|
||||
direction: data_content_direction,
|
||||
background_img_style: data_content_background_img_style,
|
||||
background_img: data_content_background_img,
|
||||
};
|
||||
const data_content = new_style?.data_content || old_border_and_box_shadow;
|
||||
const tabs_content = new_style?.tabs_content || old_border_and_box_shadow;
|
||||
|
||||
//显示的数据处理
|
||||
this.tabs_click_event(0);
|
||||
this.setData({
|
||||
top_up: new_content.tabs_top_up,
|
||||
sticky_top: this.propTop + (new_style?.tabs_margin?.margin_top || 0),
|
||||
data_tabs: new_data,
|
||||
// 自定义需要做等比缩放,因此宽度需要减去 外层通用的宽度和内容区域的宽度
|
||||
outer_container_width: common_style.margin_left + common_style.margin_right + common_style.padding_left + common_style.padding_right + new_style.data_content_margin.margin_left + new_style.data_content_margin.margin_right + new_style.data_content_padding.padding_left + new_style.data_content_padding.padding_right,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
tabs_style: new_tabs_style,
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(new_style?.tabs_margin || old_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + 'overflow: hidden;',
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
data_margin_top: 'margin-top:' + (new_style?.data_content_spacing || 0) * 2 + 'rpx;',
|
||||
data_container: gradient_computer(data_content_data) + margin_computer(data_content_margin) + radius_computer(data_content_radius) + box_shadow_computer(data_content) + border_computer(data_content) + 'overflow: hidden;',
|
||||
data_img_container: background_computer(data_content_data) + padding_computer(data_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
});
|
||||
},
|
||||
tabs_click_event(index) {
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
// 显示的数据处理
|
||||
const tabs_data_list = new_data.content.tabs_list[index] || {};
|
||||
const tabs_data_type = tabs_data_list?.tabs_data_type || '';
|
||||
let tabs_list = {};
|
||||
// 内容样式
|
||||
let data_content_container = '';
|
||||
let data_content_img_container = '';
|
||||
if (tabs_data_type === 'goods') {
|
||||
tabs_list = tabs_data_list.goods_config;
|
||||
const new_style = tabs_data_list.goods_config.style;
|
||||
// 内容样式
|
||||
data_content_container = common_styles_computer(new_style?.data_content_style || this.data_content_style);
|
||||
data_content_img_container = common_img_computer(new_style?.data_content_style || this.data_content_style);
|
||||
} else if (tabs_data_type === 'article') {
|
||||
tabs_list = tabs_data_list.article_config;
|
||||
const new_style = tabs_data_list.article_config.style;
|
||||
// 内容样式
|
||||
data_content_container = common_styles_computer(new_style?.data_content_style || this.data_content_style);
|
||||
data_content_img_container = common_img_computer(new_style?.data_content_style || this.data_content_style);
|
||||
} else if (tabs_data_type === 'custom') {
|
||||
tabs_list = tabs_data_list.custom_config;
|
||||
}
|
||||
this.setData({
|
||||
tabs_data_type: tabs_data_type,
|
||||
tabs_index: index,
|
||||
tabs_list: tabs_list,
|
||||
data_content_container: data_content_container,
|
||||
data_content_img_container: data_content_img_container,
|
||||
diy_key: get_math(),
|
||||
});
|
||||
},
|
||||
// 获取商品距离顶部的距离
|
||||
getTop() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.data-tabs-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_style = new_data.style || {};
|
||||
this.setData({
|
||||
tabs_top: res.top - (new_style.common_style?.margin_top || 0),
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
goods_buy_event(index, goods = {}, params = {}, back_data = null) {
|
||||
this.$emit('goods_buy_event', index, goods, params, back_data);
|
||||
},
|
||||
goods_cart_back_event(e) {
|
||||
if ((this.$refs.diy_goods_list || null) != null) {
|
||||
this.$refs.diy_goods_list.goods_cart_back_event(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
784
components/diy/diy.vue
Normal file
784
components/diy/diy.vue
Normal file
@@ -0,0 +1,784 @@
|
||||
<template>
|
||||
<view :style="page_style">
|
||||
<view :style="page_img_style">
|
||||
<scroll-view :scroll-y="true" class="ht" @scroll="on_scroll_event" @scrolltolower="on_scroll_lower_event" @scrolltoupper="on_scroll_upper_event" lower-threshold="60" scroll-with-animation="true">
|
||||
<!-- 头部小程序兼容 -->
|
||||
<view class="pr header">
|
||||
<componentDiyHeader :propKey="header_data.id" :propValue="header_data.com_data" :propScrollTop="head_scroll_top" @onImmersionModelCallBack="immersion_model_call_back" @onLocationBack="choice_location_back"></componentDiyHeader>
|
||||
</view>
|
||||
<view :style="content_padding">
|
||||
<view class="content flex-col" :style="'padding-top:calc(' + (temp_is_header_top ? temp_header_top + temp_sticky_top + 'px)' : '0px)')">
|
||||
<view v-for="item in tabs_data" :key="item.key">
|
||||
<template v-if="item.is_enable == '1'">
|
||||
<componentDiyTabs v-if="item.key == 'tabs'" :propIndex="is_immersive_style_and_general_safe_distance_value ? item.index : -1" :propContentPadding="content_padding" :propValue="item.com_data" :propTop="get_tabs_data_prop_top" :propStickyTop="get_tabs_data_prop_sticky_top" :propIsImmersionModel="is_immersion_model && is_the_safe_distance_enabled && item.com_data.content.tabs_top_up == '1'" :propNavIsTop="is_header_top" :propTabsIsTop="true" @onComputerHeight="tabs_height_event" @onTabsTap="tabs_click_event"></componentDiyTabs>
|
||||
<componentDiyTabsCarousel v-else-if="item.key == 'tabs-carousel'" :propIndex="is_immersive_style_and_general_safe_distance_value ? item.index : -1" :propContentPadding="content_padding" :propValue="item.com_data" :propTop="get_tabs_data_prop_top" :propStickyTop="get_tabs_data_prop_sticky_top" :propIsImmersionModel="is_immersion_model && is_the_safe_distance_enabled" :propScrollTop="scroll_top" :propTabsIsTop="true" @onComputerHeight="tabs_height_event" @onTabsTap="tabs_click_event" @onVideoPlay="video_play"></componentDiyTabsCarousel>
|
||||
</template>
|
||||
</view>
|
||||
<template v-if="is_tabs_type">
|
||||
<template v-if="diy_data.length > 0">
|
||||
<view v-for="(item, index) in diy_data" :key="index" :style="'margin-top:' + (['float-window'].includes(item.key) ? '0rpx;z-index:1' : -(item.com_data.style.common_style.floating_up * 2 || 0) + 'rpx;z-index:' + (!isEmpty(item.com_data.style.common_style.module_z_index) ? item.com_data.style.common_style.module_z_index : 0))">
|
||||
<!-- 基础组件 -->
|
||||
<template v-if="item.is_enable == '1'">
|
||||
<componentDiySearch v-if="item.key == 'search'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiySearch>
|
||||
<componentDiyCarousel v-else-if="item.key == 'carousel'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data" @onVideoPlay="video_play"></componentDiyCarousel>
|
||||
<componentDiyNavGroup v-else-if="item.key == 'nav-group'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyNavGroup>
|
||||
<componentDiyUserInfo v-else-if="item.key == 'user-info'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyUserInfo>
|
||||
<componentDiyNotice v-else-if="item.key == 'notice'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyNotice>
|
||||
<componentDiyVideo v-else-if="item.key == 'video'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyVideo>
|
||||
<componentDiyArticleList v-else-if="item.key == 'article-list'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyArticleList>
|
||||
<componentDiyArticleTabs v-else-if="item.key == 'article-tabs'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data" :propTop="get_diy_prop_top(item.com_data)" :propScrollTop="scroll_top" :propCustomNavHeight="get_diy_custom_nav_height(item.com_data)" :propIsTabsUseSafeDistance="getPropIsTabsUseSafeDistance"></componentDiyArticleTabs>
|
||||
<componentDataTabs v-else-if="item.key == 'data-tabs'" :ref="'diy_goods_buy' + index" :propIndex="get_prop_index(item)" :propDiyIndex="index" :propKey="item.id + index" :propValue="item.com_data" :propTop="get_diy_prop_top(item.com_data)" :propScrollTop="scroll_top" :propCustomNavHeight="get_diy_custom_nav_height(item.com_data)" :propIsTabsUseSafeDistance="getPropIsTabsUseSafeDistance" @goods_buy_event="goods_buy_event"></componentDataTabs>
|
||||
<componentDiyGoodsTabs v-else-if="item.key == 'goods-tabs'" :ref="'diy_goods_buy' + index" :propIndex="get_prop_index(item)" :propDiyIndex="index" :propKey="item.id + index" :propValue="item.com_data" :propTop="get_diy_prop_top(item.com_data)" :propScrollTop="scroll_top" :propCustomNavHeight="get_diy_custom_nav_height(item.com_data)" :propIsTabsUseSafeDistance="getPropIsTabsUseSafeDistance" @goods_buy_event="goods_buy_event"></componentDiyGoodsTabs>
|
||||
<componentDiyGoodsList v-else-if="item.key == 'goods-list'" :ref="'diy_goods_buy' + index" :propIndex="get_prop_index(item)" :propDiyIndex="index" :propKey="item.id + index" :propValue="item.com_data" @goods_buy_event="goods_buy_event"></componentDiyGoodsList>
|
||||
<componentDiyDataMagic v-else-if="item.key == 'data-magic'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyDataMagic>
|
||||
<componentDiyCustom v-else-if="item.key == 'custom'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyCustom>
|
||||
<componentDiyImgMagic v-else-if="item.key == 'img-magic'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyImgMagic>
|
||||
<componentDiyHotZone v-else-if="item.key == 'hot-zone'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyHotZone>
|
||||
<componentDiySeckill v-else-if="item.key == 'seckill'" :propOuterContainerPadding="outer_container_padding" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiySeckill>
|
||||
<!-- 插件 -->
|
||||
<componentDiyCoupon v-else-if="item.key == 'coupon'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyCoupon>
|
||||
<!-- 工具组件 -->
|
||||
<componentDiyFloatWindow v-else-if="item.key == 'float-window'" :propKey="item.id + index" :propValue="item.com_data"></componentDiyFloatWindow>
|
||||
<componentDiyTitle v-else-if="item.key == 'title'" :propKey="item.id + index" :propIndex="get_prop_index(item)" :propValue="item.com_data"></componentDiyTitle>
|
||||
<componentDiyAuxiliaryLine v-else-if="item.key == 'row-line'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyAuxiliaryLine>
|
||||
<componentDiyRichText v-else-if="item.key == 'rich-text'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyRichText>
|
||||
<componentDiyAuxiliaryBlank v-else-if="item.key == 'auxiliary-blank'" :propIndex="get_prop_index(item)" :propKey="item.id + index" :propValue="item.com_data"></componentDiyAuxiliaryBlank>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- diy底部卡槽 -->
|
||||
<slot name="diy-bottom-content"></slot>
|
||||
<slot name="diy-bottom-common"></slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 商品九宫格列表 -->
|
||||
<view v-if="goods_list.length > 0" class="padding-horizontal-main padding-top-main oh">
|
||||
<component-goods-list :propData="{ style_type: goods_show_type_value, goods_list: goods_list, random: random_value }" :propLabel="plugins_label_data" :propCurrencySymbol="currency_symbol"></component-goods-list>
|
||||
</view>
|
||||
<view v-else class="pr">
|
||||
<!-- 提示信息 -->
|
||||
<component-no-data :propStatus="goods_list_loding_status" :propMsg="goods_list_loding_msg" propLoadingLogoTop="30%"></component-no-data>
|
||||
</view>
|
||||
|
||||
<!-- diy底部卡槽 -->
|
||||
<template v-if="goods_bottom_line_status">
|
||||
<slot name="diy-bottom-content"></slot>
|
||||
</template>
|
||||
<slot name="diy-bottom-common"></slot>
|
||||
</template>
|
||||
|
||||
<view class="z-i-deep">
|
||||
<!-- 商品购买 -->
|
||||
<component-goods-buy ref="goods_buy" v-on:CartSuccessEvent="goods_cart_back_event"></component-goods-buy>
|
||||
<!-- 视频播放 -->
|
||||
<uni-popup ref="popup" type="center" border-radius="20rpx" :mask-click="false">
|
||||
<view class="flex-col align-c jc-c gap-10">
|
||||
<video :src="video_src" id="carousel_video" :autoplay="true" :controls="true" show-fullscreen-btn class="radius-md" :style="{ width: popup_width, height: popup_height }"></video>
|
||||
<iconfont name="icon-qiandao-tancguanbi" size="56rpx" color="#ccc" propContainerDisplay="flex" @tap="video_close"></iconfont>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 当前diy页面底部菜单(非公共底部菜单) -->
|
||||
<block v-if="is_show_footer">
|
||||
<componentDiyFooter :propKey="footer_data.id" :propValue="footer_data.com_data" @onFooterHeight="footer_height_value_event"></componentDiyFooter>
|
||||
<view v-if="footer_height_value > 0" :style="'height:' + footer_height_value + 'rpx;'"></view>
|
||||
</block>
|
||||
|
||||
<!-- 底部卡槽 -->
|
||||
<slot name="bottom"></slot>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, background_computer, padding_computer } from '@/common/js/common/common.js';
|
||||
import componentDiyHeader from '@/components/diy/header';
|
||||
import componentDiyFooter from '@/components/diy/footer';
|
||||
import componentDiyTabs from '@/components/diy/tabs';
|
||||
import componentDiySearch from '@/components/diy/search';
|
||||
import componentDiyCarousel from '@/components/diy/carousel';
|
||||
import componentDiyUserInfo from '@/components/diy/user-info';
|
||||
import componentDiyNotice from '@/components/diy/notice';
|
||||
import componentDiyVideo from '@/components/diy/video';
|
||||
import componentDiyArticleList from '@/components/diy/article-list';
|
||||
import componentDiyArticleTabs from '@/components/diy/article-tabs';
|
||||
import componentDiyHotZone from '@/components/diy/hot-zone';
|
||||
import componentDiyCoupon from '@/components/diy/coupon';
|
||||
import componentDiyFloatWindow from '@/components/diy/float-window';
|
||||
import componentDiyTitle from '@/components/diy/title';
|
||||
import componentDiyAuxiliaryLine from '@/components/diy/auxiliary-line';
|
||||
import componentDiyRichText from '@/components/diy/rich-text';
|
||||
import componentDiyAuxiliaryBlank from '@/components/diy/auxiliary-blank';
|
||||
import componentDiyNavGroup from '@/components/diy/nav-group';
|
||||
import componentDiyGoodsList from '@/components/diy/goods-list';
|
||||
import componentDiyGoodsTabs from '@/components/diy/goods-tabs';
|
||||
import componentDiyDataMagic from '@/components/diy/data-magic';
|
||||
import componentDiyCustom from '@/components/diy/custom';
|
||||
import componentDiyImgMagic from '@/components/diy/img-magic';
|
||||
import componentDiySeckill from '@/components/diy/seckill';
|
||||
import componentDiyTabsCarousel from '@/components/diy/tabs-carousel';
|
||||
import componentDataTabs from '@/components/diy/data-tabs';
|
||||
import componentGoodsList from '@/components/goods-list/goods-list';
|
||||
import componentNoData from '@/components/no-data/no-data';
|
||||
import componentBottomLine from '@/components/bottom-line/bottom-line';
|
||||
import componentGoodsBuy from '@/components/goods-buy/goods-buy';
|
||||
import componentSearch from '@/components/search/search';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
name: 'diy',
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propDataId: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
componentDiyHeader,
|
||||
componentDiyFooter,
|
||||
componentDiyTabs,
|
||||
componentDiySearch,
|
||||
componentDiyCarousel,
|
||||
componentDiyUserInfo,
|
||||
componentDiyNotice,
|
||||
componentDiyVideo,
|
||||
componentDiyArticleList,
|
||||
componentDiyArticleTabs,
|
||||
componentDiyHotZone,
|
||||
componentDiyCoupon,
|
||||
componentDiyAuxiliaryLine,
|
||||
componentDiyRichText,
|
||||
componentDiyFloatWindow,
|
||||
componentDiyTitle,
|
||||
componentDiyAuxiliaryBlank,
|
||||
componentDiyNavGroup,
|
||||
componentDiyGoodsList,
|
||||
componentDiyGoodsTabs,
|
||||
componentDiyDataMagic,
|
||||
componentDiyCustom,
|
||||
componentDiyImgMagic,
|
||||
componentDiySeckill,
|
||||
componentDiyTabsCarousel,
|
||||
componentDataTabs,
|
||||
componentGoodsList,
|
||||
componentNoData,
|
||||
componentBottomLine,
|
||||
componentGoodsBuy,
|
||||
componentSearch,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 基础配置
|
||||
currency_symbol: app.globalData.currency_symbol(),
|
||||
// 是否有选项卡
|
||||
is_tabs: false,
|
||||
// 是否是模块数据或者是九宫格商品分类样式数据, 默认模块数据
|
||||
is_tabs_type: true,
|
||||
// 是否开启沉浸模式
|
||||
is_immersion_model: false,
|
||||
|
||||
// 5,7,0 是误差,, 10 是下边距,66是高度,bar_height是不同小程序下的导航栏距离顶部的高度
|
||||
// #ifdef MP
|
||||
sticky_top: bar_height + 5 + 10,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
sticky_top: bar_height + 7 + 10,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
sticky_top: bar_height + 0 + 10,
|
||||
// #endif
|
||||
header_top: '',
|
||||
temp_sticky_top: 0,
|
||||
temp_header_top: '0px',
|
||||
is_header_top: false,
|
||||
temp_is_header_top: false,
|
||||
scroll_top: 0,
|
||||
// 选项卡高度
|
||||
tabs_height: 0,
|
||||
|
||||
header_data: {},
|
||||
footer_data: {},
|
||||
// 选项卡数据
|
||||
tabs_data: {},
|
||||
diy_data: [],
|
||||
page_style: '',
|
||||
page_img_style: '',
|
||||
is_show_footer: false,
|
||||
tabs_home_id: this.propDataId,
|
||||
// 商品列表
|
||||
goods_list: [],
|
||||
goods_total: 0,
|
||||
goods_page_total: 0,
|
||||
goods_page: 1,
|
||||
// 数据展示样式(0图文、1九方格)
|
||||
goods_show_type_value: 1,
|
||||
// 增加随机数,避免无法监听数据列表内部数据更新
|
||||
random_value: 0,
|
||||
// 标签插件
|
||||
plugins_label_data: null,
|
||||
goods_list_loding_status: 1,
|
||||
goods_list_loding_msg: '',
|
||||
goods_bottom_line_status: false,
|
||||
// 判断数据是否在加载中
|
||||
data_is_loading: 0,
|
||||
// 缓存key
|
||||
cache_key: app.globalData.data.cache_diy_data_key,
|
||||
// 底部导航高度
|
||||
footer_height_value: 0,
|
||||
// 商品ref索引
|
||||
goods_index: 0,
|
||||
// 视频播放逻辑
|
||||
video_src: '',
|
||||
popup_width: '0rpx',
|
||||
popup_height: '0rpx',
|
||||
// 顶部导航是否换行
|
||||
is_search_alone_row: false,
|
||||
data_alone_row_space: 0,
|
||||
content_padding: '',
|
||||
outer_container_padding: 0,
|
||||
|
||||
// 滚动延迟器
|
||||
head_scroll_top: 0,
|
||||
scroll_throttle_timeout: null,
|
||||
// 是否开启安全距离
|
||||
is_the_safe_distance_enabled: false,
|
||||
// 是否开启置顶
|
||||
is_tabs_data_topped: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
get_tabs_data_prop_top() {
|
||||
// 开启了沉浸式时的处理
|
||||
if (this.is_immersion_model) {
|
||||
// 并且开启了安全距离
|
||||
return this.is_the_safe_distance_enabled ? this.temp_header_top : 0;
|
||||
} else {
|
||||
return this.temp_header_top;
|
||||
}
|
||||
},
|
||||
get_tabs_data_prop_sticky_top() {
|
||||
// 开启了沉浸式时的处理
|
||||
if (this.is_immersion_model) {
|
||||
// 并且开启了安全距离
|
||||
return this.is_the_safe_distance_enabled ? this.temp_sticky_top : 0;
|
||||
} else {
|
||||
return this.temp_sticky_top;
|
||||
}
|
||||
},
|
||||
get_prop_index() {
|
||||
return (item) => {
|
||||
return this.is_the_safe_distance_enabled && this.tabs_data.length == 0 ? item.index : -1;
|
||||
}
|
||||
},
|
||||
get_diy_prop_top() {
|
||||
return (item) => {
|
||||
// 不开启沉浸模式时的处理
|
||||
if (!this.is_immersion_model) {
|
||||
return this.temp_sticky_top + this.tabs_height;
|
||||
} else {
|
||||
// 开启沉浸模式且开启选项卡置顶时
|
||||
if (this.is_tabs_data_topped) {
|
||||
return this.tabs_height;
|
||||
} else {
|
||||
// 开启安全距离
|
||||
let is_general_safe_distance_num = this.temp_sticky_top;
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
is_general_safe_distance_num = this.is_header_top ? this.temp_sticky_top : 0
|
||||
// #endif
|
||||
if (this.is_the_safe_distance_enabled) {
|
||||
return is_general_safe_distance_num;
|
||||
} else {
|
||||
if (item?.content?.is_general_safe_distance == '1') {
|
||||
return is_general_safe_distance_num;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
get_diy_custom_nav_height() {
|
||||
return (item) => {
|
||||
let header_height = (this.is_search_alone_row ? 66 + this.data_alone_row_space : 33);
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
header_height = this.is_header_top ? header_height : 0;
|
||||
// #endif
|
||||
// 不开启沉浸模式时的处理
|
||||
if (!this.is_immersion_model) {
|
||||
return header_height;
|
||||
} else {
|
||||
// 开启沉浸模式且开启选项卡置顶时
|
||||
if (this.is_tabs_data_topped) {
|
||||
return 0;
|
||||
} else {
|
||||
// 开启沉浸模式时并且开启安全距离
|
||||
if (this.is_the_safe_distance_enabled) {
|
||||
return this.is_search_alone_row ? 66 + this.data_alone_row_space : 33;
|
||||
} else {
|
||||
if (item?.content?.is_general_safe_distance == '1') {
|
||||
return header_height;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getPropIsTabsUseSafeDistance() {
|
||||
let is_tabs_use_safe_distance = this.is_immersion_model;
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
is_tabs_use_safe_distance = this.is_immersion_model && this.is_header_top;
|
||||
// #endif
|
||||
return is_tabs_use_safe_distance || !this.is_immersion_model;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 如果当前存在别的diy或者商品分类tabs则不更新数据
|
||||
if ((this.tabs_id || null) == null) {
|
||||
// 初始化
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 初始化配置
|
||||
this.init_config();
|
||||
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
// 初始化配置
|
||||
init_config(status) {
|
||||
if ((status || false) == true) {
|
||||
// 是否显示底部菜单,如果当前地址已经存在系统底部菜单中则不显示当前diy页面自定义的底部菜单
|
||||
var is_show_footer = parseInt(this.propValue.header.com_data.content.bottom_navigation_show || 0) == 1;
|
||||
var is_tabbar = app.globalData.is_tabbar_pages();
|
||||
this.setData({
|
||||
is_show_footer: is_show_footer && !is_tabbar,
|
||||
});
|
||||
// diy页面不显示底部菜单则设置底部菜单高度为0
|
||||
if(!this.is_show_footer) {
|
||||
// 存储diy页面底部菜单高度
|
||||
if(app.globalData.current_page(false) == 'pages/diy/diy') {
|
||||
app.globalData.app_diy_tabbar_height_save(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app.globalData.is_config(this, 'init_config');
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化
|
||||
init() {
|
||||
const { header = {}, diy_data = [], tabs_data = [] } = this.propValue;
|
||||
// 头部的样式
|
||||
let header_style = header.com_data.style;
|
||||
let new_diy_index = 0;
|
||||
let new_tabs_data = [];
|
||||
let new_diy_data = [];
|
||||
if (tabs_data.length > 0) {
|
||||
tabs_data.forEach((item) => {
|
||||
// 修改item的内容
|
||||
item = this.get_index_content(new_diy_index, header, header_style, item);
|
||||
new_tabs_data.push(item);
|
||||
new_diy_index++;
|
||||
});
|
||||
new_diy_data = diy_data;
|
||||
} else {
|
||||
new_tabs_data = tabs_data;
|
||||
// 过滤数据
|
||||
diy_data.forEach((item) => {
|
||||
// 判断是否是商品列表
|
||||
if (item.com_name == 'float-window') {
|
||||
item.index = -1;
|
||||
} else {
|
||||
// 修改item的内容
|
||||
item = this.get_index_content(new_diy_index, header, header_style, item);
|
||||
new_diy_data.push(item);
|
||||
new_diy_index++;
|
||||
}
|
||||
});
|
||||
}
|
||||
const { padding_right = 0, padding_left = 0 } = header_style.common_style;
|
||||
const new_is_search_alone_row = header.com_data.content.data_alone_row_value.length > 0 ? true : false;
|
||||
const new_data_alone_row_space = parseInt(header_style.data_alone_row_space || 0);
|
||||
// tabs选项卡数据过滤
|
||||
this.setData({
|
||||
header_data: header,
|
||||
footer_data: this.propValue.footer,
|
||||
diy_data: new_diy_data,
|
||||
tabs_data: new_tabs_data,
|
||||
page_style: common_styles_computer(header_style.common_style),
|
||||
page_img_style: background_computer(header_style.common_style),
|
||||
// 内间距
|
||||
content_padding: `padding: 0px ${padding_right}px 0px ${padding_left}px;` + 'box-sizing:border-box;',
|
||||
outer_container_padding: padding_right + padding_left,
|
||||
// 判断顶部导航是否置顶
|
||||
is_header_top: parseInt(header_style.up_slide_display) == 1 ? true : false,
|
||||
is_tabs_data_topped: new_tabs_data[0]?.com_data?.content?.tabs_top_up == '1' || false,
|
||||
temp_sticky_top: this.sticky_top,
|
||||
temp_header_top: (new_is_search_alone_row ? 66 + new_data_alone_row_space : 33),
|
||||
header_top: (new_is_search_alone_row ? 66 + new_data_alone_row_space : 33),
|
||||
is_immersion_model: header_style.header_background_type !== 'color_image' && header_style.immersive_style == '1',
|
||||
// 顶部导航高度是否变化--------------------------------------------------
|
||||
is_search_alone_row: new_is_search_alone_row,
|
||||
data_alone_row_space: new_data_alone_row_space,
|
||||
is_immersive_style_and_general_safe_distance_value: header_style.immersive_style == '1' && header_style.general_safe_distance_value == '1',
|
||||
is_the_safe_distance_enabled: header_style.immersive_style == '1' && header_style.general_safe_distance_value == '1',// diy_data是否开启安全距离
|
||||
});
|
||||
// 缓存数据
|
||||
uni.setStorageSync(this.cache_key + this.tabs_home_id, diy_data);
|
||||
},
|
||||
// 顶部导航沉浸模式回调
|
||||
// immersion_model_call_back(bool) {
|
||||
// this.setData({
|
||||
// is_immersion_model: bool,
|
||||
// });
|
||||
// },
|
||||
get_index_content(new_diy_index, header, header_style, item) {
|
||||
item.index = new_diy_index;
|
||||
if (new_diy_index == 0) {
|
||||
// 判断是否开启沉浸模式和是否开启安全距离 如果为true则除了选项卡和选项卡轮播外, 第一个组件则加上安全距离样式的padding_top加上顶部导航的高度和安全距离的高度
|
||||
if (header_style.immersive_style == '1' && header_style.general_safe_distance_value == '1') {
|
||||
let new_data = JSON.parse(JSON.stringify(item));
|
||||
// 顶部导航的高度
|
||||
let header_top_height = (header.com_data.content.data_alone_row_value.length > 0 ? parseInt(header.com_data.style.data_alone_row_space || 5) : 0) + 33 + (header.com_data.content.data_alone_row_value.length > 0 ? 33 : 0);
|
||||
new_data.com_data.style.common_style.padding_top = parseInt(new_data.com_data.style.common_style.padding_top) + header_top_height;
|
||||
return new_data;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
return item;
|
||||
},
|
||||
// 选项卡回调更新数据
|
||||
tabs_click_event(tabs_id, bool, params = {}) {
|
||||
let new_data = [];
|
||||
this.setData({
|
||||
is_tabs_type: bool,
|
||||
tabs_id: tabs_id,
|
||||
});
|
||||
let new_params = {
|
||||
...params,
|
||||
id: tabs_id,
|
||||
};
|
||||
if (tabs_id) {
|
||||
new_data = uni.getStorageSync(this.cache_key + tabs_id) || [];
|
||||
if (new_data.length > 0) {
|
||||
// 先使用缓存数据展示
|
||||
this.setData({
|
||||
diy_data: new_data,
|
||||
});
|
||||
// 已有本地缓存则直接取远程有效数据(默认首次取的是远程缓存数据)
|
||||
new_params['is_cache'] = 0;
|
||||
}
|
||||
// diy数据
|
||||
if (bool) {
|
||||
uni.showLoading({
|
||||
title: this.$t('common.loading_in_text'),
|
||||
mask: true,
|
||||
});
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('index', 'diy'),
|
||||
method: 'POST',
|
||||
data: new_params,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
uni.hideLoading();
|
||||
// 数据处理
|
||||
let data = res.data.data.data;
|
||||
if (res.data.code == 0) {
|
||||
new_data = data?.config.diy_data || [];
|
||||
uni.setStorageSync(this.cache_key + tabs_id, new_data);
|
||||
this.setData({
|
||||
diy_data: new_data,
|
||||
});
|
||||
// 是否需要重新加载数据
|
||||
if (parseInt(data.is_result_data_cache || 0) == 1) {
|
||||
this.tabs_click_event(tabs_id, bool, { is_cache: 0 });
|
||||
}
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
goods_page: 1,
|
||||
goods_list: [],
|
||||
goods_list_loding_status: 1,
|
||||
goods_bottom_line_status: false,
|
||||
});
|
||||
this.get_goods_list(1);
|
||||
}
|
||||
} else {
|
||||
if (tabs_id == '') {
|
||||
new_data = uni.getStorageSync(this.cache_key + this.tabs_home_id) || [];
|
||||
}
|
||||
// 先使用缓存数据展示
|
||||
this.setData({
|
||||
diy_data: new_data,
|
||||
});
|
||||
}
|
||||
},
|
||||
// 选项卡高度
|
||||
tabs_height_event(height) {
|
||||
let new_tabs_height = 0;
|
||||
// 判断是否有选项卡切选项卡数组数据内的字段is_enable值是否为1
|
||||
if (this.tabs_data.length > 0) {
|
||||
this.tabs_data.forEach((item, index) => {
|
||||
if (item.is_enable == '1') {
|
||||
new_tabs_height = height;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.setData({
|
||||
tabs_height: new_tabs_height,
|
||||
});
|
||||
},
|
||||
|
||||
// 滚动加载
|
||||
on_scroll_lower_event(e) {
|
||||
if (!this.is_tabs_type) {
|
||||
this.get_goods_list();
|
||||
}
|
||||
},
|
||||
// 滚动到顶部
|
||||
on_scroll_upper_event() {
|
||||
setTimeout(() => {
|
||||
this.head_scroll_top = 0;
|
||||
});
|
||||
},
|
||||
|
||||
// 查询商品
|
||||
get_goods_list(is_mandatory) {
|
||||
// 分页是否还有数据
|
||||
if ((is_mandatory || 0) == 0) {
|
||||
if (this.goods_bottom_line_status == true) {
|
||||
uni.stopPullDownRefresh();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 是否加载中
|
||||
if (this.data_is_loading == 1) {
|
||||
return false;
|
||||
}
|
||||
this.setData({
|
||||
data_is_loading: 1,
|
||||
});
|
||||
|
||||
// 获取数据
|
||||
if (this.goods_page > 1) {
|
||||
uni.showLoading({
|
||||
title: this.$t('common.loading_in_text'),
|
||||
});
|
||||
}
|
||||
let new_data = {
|
||||
category_id: this.tabs_id,
|
||||
page: this.goods_page,
|
||||
};
|
||||
// 九宫格数据
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('datalist', 'search'),
|
||||
method: 'POST',
|
||||
data: new_data,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (this.goods_page > 1) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
uni.stopPullDownRefresh();
|
||||
if (res.data.code == 0) {
|
||||
var data = res.data.data;
|
||||
if (data.data.length > 0) {
|
||||
if (this.goods_page <= 1) {
|
||||
var temp_goods_list = data.data;
|
||||
} else {
|
||||
var temp_goods_list = this.goods_list || [];
|
||||
var temp_data = data.data;
|
||||
for (var i in temp_data) {
|
||||
temp_goods_list.push(temp_data[i]);
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
goods_list: temp_goods_list,
|
||||
random_value: Math.random(),
|
||||
goods_total: data.total,
|
||||
goods_page_total: data.page_total,
|
||||
goods_list_loding_status: 3,
|
||||
goods_list_loding_msg: '',
|
||||
goods_page: this.goods_page + 1,
|
||||
data_is_loading: 0,
|
||||
});
|
||||
|
||||
// 是否还有数据
|
||||
this.setData({
|
||||
goods_bottom_line_status: this.goods_page > 1 && this.goods_page > this.goods_page_total,
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
goods_list_loding_status: 0,
|
||||
goods_list_loding_msg: res.data.msg,
|
||||
goods_total: 0,
|
||||
data_is_loading: 0,
|
||||
});
|
||||
if (this.goods_page <= 1) {
|
||||
this.setData({
|
||||
goods_list: [],
|
||||
goods_bottom_line_status: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.setData({
|
||||
goods_list_loding_status: 0,
|
||||
goods_list_loding_msg: res.data.msg,
|
||||
data_is_loading: 0,
|
||||
});
|
||||
app.globalData.is_login_check(res.data, this, 'get_goods_list', is_mandatory);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
if (this.goods_page > 1) {
|
||||
uni.hideLoading();
|
||||
}
|
||||
uni.stopPullDownRefresh();
|
||||
this.setData({
|
||||
goods_list_loding_status: 2,
|
||||
goods_list_loding_msg: this.$t('common.internet_error_tips'),
|
||||
data_is_loading: 0,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 页面滚动事件
|
||||
on_scroll_event(e) {
|
||||
const scroll_num = parseInt(e.detail.scrollTop);
|
||||
if (scroll_num <= 20) {
|
||||
this.head_scroll_top = 0;
|
||||
} else {
|
||||
if (scroll_num / (this.sticky_top + 33) <= 1) {
|
||||
// 更新数据的逻辑
|
||||
this.head_scroll_top = scroll_num;
|
||||
} else {
|
||||
this.head_scroll_top = this.sticky_top + 100;
|
||||
}
|
||||
}
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 判断顶部导航是否置顶
|
||||
if (!this.is_header_top && !this.is_immersion_model) {
|
||||
if (scroll_num >= this.sticky_top + 33 + (this.is_search_alone_row ? 0 : 33 + this.data_alone_row_space)) {
|
||||
this.temp_sticky_top = 0;
|
||||
this.temp_header_top = 0;
|
||||
this.temp_sticky_no_h5_top = 0;
|
||||
this.temp_is_header_top = true;
|
||||
} else {
|
||||
this.temp_header_top = this.header_top;
|
||||
this.temp_sticky_top = this.sticky_top;
|
||||
this.temp_sticky_no_h5_top = this.sticky_top;
|
||||
this.temp_is_header_top = false;
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
this.scroll_timer_compute(scroll_num);
|
||||
},
|
||||
|
||||
scroll_timer_compute(scroll_num) {
|
||||
// 使用节流技术减少事件触发的处理次数
|
||||
if (!this.scroll_throttle_timeout) {
|
||||
const self = this;
|
||||
this.scroll_throttle_timeout = setTimeout(() => {
|
||||
this.scroll_top = scroll_num;
|
||||
// 清除定时器
|
||||
this.scroll_throttle_timeout = null;
|
||||
}, 20); // 可以根据实际情况调整延时时间
|
||||
}
|
||||
},
|
||||
|
||||
// 底部菜单高度
|
||||
footer_height_value_event(value) {
|
||||
this.setData({
|
||||
footer_height_value: (value*2)+20,
|
||||
});
|
||||
|
||||
// 存储diy页面底部菜单高度
|
||||
if(app.globalData.current_page(false) == 'pages/diy/diy') {
|
||||
app.globalData.app_diy_tabbar_height_save(value);
|
||||
}
|
||||
},
|
||||
// 商品数量更新回调
|
||||
goods_buy_event(index, goods = {}, params = {}, back_data = null) {
|
||||
if ((this.$refs.goods_buy || null) != null) {
|
||||
this.goods_index = index;
|
||||
this.$refs.goods_buy.init(goods, params, back_data);
|
||||
}
|
||||
},
|
||||
// 商品加购回调
|
||||
goods_cart_back_event(e) {
|
||||
if ((this.$refs[`diy_goods_buy${this.goods_index}`][0] || null) != null) {
|
||||
this.$refs[`diy_goods_buy${this.goods_index}`][0].goods_cart_back_event(e);
|
||||
}
|
||||
},
|
||||
// 视频播放
|
||||
video_play(url, width, height) {
|
||||
this.setData({
|
||||
video_src: url,
|
||||
popup_width: width,
|
||||
popup_height: height,
|
||||
});
|
||||
this.$refs.popup.open();
|
||||
const videoContext = uni.createVideoContext('carousel_video');
|
||||
if (!isEmpty(videoContext)) {
|
||||
videoContext.play();
|
||||
}
|
||||
},
|
||||
// 视频关闭
|
||||
video_close() {
|
||||
const videoContext = uni.createVideoContext('carousel_video');
|
||||
if (!isEmpty(videoContext)) {
|
||||
videoContext.pause();
|
||||
}
|
||||
this.$refs.popup.close();
|
||||
},
|
||||
// 位置回调
|
||||
choice_location_back(e) {
|
||||
// 如果存在tabs_id则表示当前有选择tab数据则仅当前模块更新,无需给上级回调位置
|
||||
if ((this.tabs_id || null) == null) {
|
||||
this.$emit('onLocationBack', e);
|
||||
} else {
|
||||
this.tabs_click_event(this.tabs_id, this.is_tabs_type);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
164
components/diy/float-window.vue
Normal file
164
components/diy/float-window.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<movable-area class="float-window-movable-container">
|
||||
<movable-view :x="x" :y="y" direction="all" class="float-window-spread flex-row align-c jc-c" @tap="btn_event">
|
||||
<block v-if="style.float_style == 'diffuse'">
|
||||
<view class="ring" :style="content_style"></view>
|
||||
<view class="ring" :style="content_style"></view>
|
||||
</block>
|
||||
<view class="img oh" :style="content_style">
|
||||
<block v-if="(form || null) != null && form.button_jump == 'customer_service'">
|
||||
<component-online-service :propChatImage="img_url" :propIsSpread="false" :propIsMovable="false"></component-online-service>
|
||||
</block>
|
||||
<block v-else>
|
||||
<imageEmpty :propImageSrc="img_url" propImgFit="aspectFill" propErrorStyle="width: 60rpx;height: 60rpx;"></imageEmpty>
|
||||
</block>
|
||||
</view>
|
||||
</movable-view>
|
||||
<component-quick-nav ref="quick_nav" :propIsBtn="false"></component-quick-nav>
|
||||
</movable-area>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import componentOnlineService from '@/components/online-service/online-service';
|
||||
import componentQuickNav from '@/components/quick-nav/quick-nav';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
componentOnlineService,
|
||||
componentQuickNav
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
style: {},
|
||||
img_url: '',
|
||||
x: 0,
|
||||
y: 0,
|
||||
content_style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
// 获取内容
|
||||
let form = this.propValue.content || {};
|
||||
// 获取图片
|
||||
let img_url = (form.button_img || null) != null ? (form.button_img[0] || null) : null;
|
||||
if (img_url != null) {
|
||||
img_url = img_url.url || null;
|
||||
}
|
||||
const { float_style, float_style_color, display_location, offset_number_percentage } = this.propValue.style;
|
||||
// 获取当前手机的宽度和高度
|
||||
const { windowWidth, windowHeight } = uni.getSystemInfoSync();
|
||||
// 计算出距离左边的距离
|
||||
let x = display_location == 'left' ? 10 : windowWidth - 60;
|
||||
// 计算出距离顶部的距离
|
||||
const y = Math.ceil(windowHeight * (1 - Number(offset_number_percentage)) - 20);
|
||||
this.setData({
|
||||
form: form,
|
||||
style: this.propValue.style,
|
||||
img_url: img_url,
|
||||
content_style: float_style == 'shadow' ? `box-shadow: 0 0 40rpx ${float_style_color};border-radius: 50%;` : `background-color: ${float_style_color};border-radius: 50%;`,
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
},
|
||||
// 按钮事件
|
||||
btn_event() {
|
||||
const { button_jump, button_link } = this.form;
|
||||
switch(button_jump) {
|
||||
// 链接
|
||||
case 'link' :
|
||||
if (!isEmpty(button_link)) {
|
||||
app.globalData.url_open(button_link.page);
|
||||
}
|
||||
break;
|
||||
// 快捷导航
|
||||
case 'quick_nav' :
|
||||
if ((this.$refs.quick_nav || null) != null) {
|
||||
this.$refs.quick_nav.quick_open_event();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.img {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
border-radius: 50%;
|
||||
z-index: 2;
|
||||
}
|
||||
.float-window-movable-container {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
z-index: 103;
|
||||
}
|
||||
/**
|
||||
* 呼吸灯
|
||||
*/
|
||||
.float-window-spread {
|
||||
position: relative;
|
||||
pointer-events: auto;
|
||||
z-index: 1;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.float-window-spread .ring {
|
||||
/* 速度为1.5 * 层数 = 实际运行速度,速度修改则 animation-delay 属性也修改相同速度 */
|
||||
animation: pulsing 1.5s ease-out infinite;
|
||||
border-radius: 100%;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
position: absolute;
|
||||
}
|
||||
/* 速度为1*层数 */
|
||||
.float-window-spread .ring:nth-of-type(1) {
|
||||
-webkit-animation-delay: -1.5s;
|
||||
animation-delay: -1.5s;
|
||||
}
|
||||
|
||||
/* 速度为1*层数 */
|
||||
.float-window-spread .ring:nth-of-type(2) {
|
||||
-webkit-animation-delay: -2s;
|
||||
animation-delay: -2s;
|
||||
}
|
||||
@keyframes pulsing {
|
||||
100% {
|
||||
transform: scale(1.35);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
201
components/diy/footer.vue
Normal file
201
components/diy/footer.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<!-- 底部导航 -->
|
||||
<view v-if="(propValue || null) !== null" class="footer-nav flex-row jc-c align-c" :class="nav_type == 1 ? 'bottom-line-exclude' : ''">
|
||||
<view class="flex-1 wh-auto" :style="style_container">
|
||||
<view class="footer-nav-content flex-row jc-c align-c wh-auto" :style="style_img_container">
|
||||
<view class="flex-row jc-c align-c wh-auto" :class="nav_type == 0 ? 'bottom-line-exclude' : ''">
|
||||
<view class="flex-row jc-sa align-c wh padding-0">
|
||||
<block v-for="(item, index) in nav_content" :key="index">
|
||||
<view class="flex-1 flex-col jc-c align-c gap-5 pr" :data-value="item.link.page || ''" @tap="url_event">
|
||||
<view v-if="nav_style != 2" class="img-content pr">
|
||||
<view class="img-item pa border-radius-xs animate-linear" :class="active_index != index ? 'active' : ''">
|
||||
<template v-if="item.img.length > 0">
|
||||
<image :src="item.img[0].url" class="img dis-block" model="widthFix"></image>
|
||||
</template>
|
||||
</view>
|
||||
<view class="img-item pa border-radius-xs animate-linear" :class="active_index == index ? 'active' : ''">
|
||||
<template v-if="item.img_checked.length > 0">
|
||||
<image :src="item.img_checked[0].url" class="img dis-block" model="widthFix"></image>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<text v-if="nav_style != 1" class="animate-linear text-size-xs pr z-i" :style="active_index == index ? text_color_checked : default_text_color">{{ item.name }}</text>
|
||||
<view v-if="(item.badge || null) != null" class="pa badge-icon">
|
||||
<component-badge :propNumber="item.badge"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
let app = getApp();
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
import componentBadge from '@/components/badge/badge';
|
||||
export default {
|
||||
props: {
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
// 底部选中索引
|
||||
propFooterActiveIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
nav_content: [],
|
||||
nav_type: 0,
|
||||
nav_style: 0,
|
||||
default_text_color: '',
|
||||
text_color_checked: '',
|
||||
active_index: 0,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentBadge,
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 唯一key
|
||||
propKey(value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
// 选中索引
|
||||
propFooterActiveIndex(value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化
|
||||
init() {
|
||||
if ((this.propValue || null) !== null) {
|
||||
let new_content = this.propValue.content || {};
|
||||
let new_style = this.propValue.style || {};
|
||||
let nav_content = new_content.nav_content || [];
|
||||
let page = app.globalData.current_page() || null;
|
||||
let active_index = this.propFooterActiveIndex;
|
||||
if (page != null) {
|
||||
// 角标链接定义
|
||||
let badge_arr = {
|
||||
'/pages/cart/cart': 'cart',
|
||||
'/pages/cart-page/cart-page': 'cart',
|
||||
};
|
||||
for (var i in nav_content) {
|
||||
if ((nav_content[i]['link'] || null) != null && (nav_content[i]['link']['page'] || null) != null) {
|
||||
// 选中索引
|
||||
if (nav_content[i]['link']['page'] == '/' + page) {
|
||||
active_index = i;
|
||||
}
|
||||
|
||||
// 获取角标数据
|
||||
var badge_key = badge_arr[nav_content[i]['link']['page']];
|
||||
if (badge_key !== undefined) {
|
||||
nav_content[i]['badge'] = app.globalData.get_tab_bar_badge(badge_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
nav_content: nav_content,
|
||||
nav_type: new_content.nav_type || 0,
|
||||
nav_style: new_content.nav_style || 0,
|
||||
active_index: active_index,
|
||||
default_text_color: 'color:' + new_style.default_text_color || 'rgba(0, 0, 0, 1)',
|
||||
text_color_checked: 'color:' + new_style.text_color_checked || 'rgba(204, 204, 204, 1)',
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style),
|
||||
});
|
||||
|
||||
// 高度计算
|
||||
let nav_min_height = 70;
|
||||
var nav_height = parseInt(new_style.common_style.padding_top) + parseInt(new_style.common_style.padding_bottom) + 44;
|
||||
if (nav_height < nav_min_height) {
|
||||
nav_height = nav_min_height;
|
||||
}
|
||||
let footer_height = nav_height + parseInt(new_style.common_style.margin_top) + parseInt(new_style.common_style.margin_bottom);
|
||||
|
||||
// #ifndef H5
|
||||
// 底部菜单距离底部的安全距离,减去20、默认的安全距离太高了
|
||||
var safe_areaInsets = uni.getSystemInfoSync().safeAreaInsets || {};
|
||||
var bottom = parseInt(safe_areaInsets.bottom || 0);
|
||||
if (bottom > 0) {
|
||||
bottom -= 24;
|
||||
}
|
||||
footer_height += bottom;
|
||||
// #endif
|
||||
|
||||
// 回调高度
|
||||
this.$emit('onFooterHeight', footer_height);
|
||||
}
|
||||
},
|
||||
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
let index = e.currentTarget.dataset.index;
|
||||
let item = this.nav_content[index];
|
||||
app.globalData.url_event(e);
|
||||
this.$emit('onFooterTap', index, item);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.footer-nav {
|
||||
z-index: 102;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
background-color: transparent;
|
||||
.footer-nav-content {
|
||||
min-height: 140rpx;
|
||||
box-sizing: border-box;
|
||||
.img-content {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
.img-item {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
opacity: 0;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
.img {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.badge-icon {
|
||||
margin-top: -70rpx;
|
||||
margin-right: -70rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* #ifdef H5 */
|
||||
@media only screen and (min-width: 1600rpx) {
|
||||
.footer-nav {
|
||||
max-width: 1600rpx;
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
607
components/diy/goods-list.vue
Normal file
607
components/diy/goods-list.vue
Normal file
@@ -0,0 +1,607 @@
|
||||
<template>
|
||||
<view v-if="!isEmpty(list)" class="oh" :style="style_container" @tap.stop="onTap">
|
||||
<view class="oh" :style="style_img_container">
|
||||
<view :class="outer_class" :style="onter_style">
|
||||
<block v-if="!['5'].includes(theme)">
|
||||
<view v-for="(item, index) in list" :key="index" class="pr oh" :style="layout_style" :data-index="index" :data-value="item.goods_url" @tap.stop="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<block v-if="theme == '6'">
|
||||
<view :class="['flex-row align-c jc-sb ptb-15 mlr-10 gap-20', { 'br-b-e': index != list.length - 1 }]">
|
||||
<view v-if="is_show('title')" :class="text_line" :style="title_style">{{ item.title }}</view>
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num nowrap" :style="'color:' + new_style.shop_price_color">
|
||||
<text class="identifying">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" class="identifying">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<block v-if="!isEmpty(item)">
|
||||
<view class="oh pr" :class="img_size">
|
||||
<view v-if="!isEmpty(item.new_cover)" :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('original_price') || is_show('sales_count') || is_show('plugins_view_icon') || form.is_shop_show == '1'" class="flex-col flex-1 jc-sb content gap-10" :style="content_style">
|
||||
<view class="flex-col gap-10 top-title">
|
||||
<view v-if="is_show('title') || (['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc'))" class="flex-col" :style="{ gap: new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :class="text_line" :style="title_style">{{ item.title }}</view>
|
||||
<view v-if="['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc')" :class="form.simple_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('plugins_view_icon') && !isEmpty(item.plugins_view_icon_data)" class="flex-row gap-5 align-c">
|
||||
<view v-for="(icon_data, icon_index) in item.plugins_view_icon_data" :key="icon_index" class="radius text-size-xsss padding-horizontal-xs" :style="{ background: icon_data.bg_color, color: icon_data.color, border: '1rpx solid' + (!isEmpty(icon_data.br_color) ? icon_data.br_color : icon_data.bg_color) }">{{ icon_data.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!['3', '4', '5'].includes(form.theme)" class="flex-col gap-5">
|
||||
<view :class="[form.is_price_solo == '1' ? 'flex-row align-c nowrap' : 'flex-col gap-5']">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="'color:' + new_style.shop_price_color">
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('original_price') && !isEmpty(item.min_original_price)" class="text-size-xss flex-row">
|
||||
<!-- <image v-if="form.static_img.length > 0" class="original-price-left" :src="form.static_img[0].url" model="widthFix"></image> -->
|
||||
<text :class="['original-price text-line-1', { 'flex-1': form.is_price_solo == '1' }]" :style="original_price">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<block v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</block>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row jc-sb align-e">
|
||||
<view>
|
||||
<view v-if="show_content" class="flex-row align-c text-size-xss">
|
||||
<view v-if="is_show('sales_count') && !isEmpty(item.sales_count)" class="pr-5" :style="sold_number_style">已售{{ item.sales_count || 0 }}件</view>
|
||||
<!-- <view v-if="is_show('sales_count')" :class="['pr-5', {'br-r-e': is_show('sales_count') && is_show('4')}]" :style="sold_number_style>已售{{ item.sales_count }}件</view> -->
|
||||
<!-- <view v-if="is_show('4')" class="pl-5" :style="score_style">评分0</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(form.is_shop_show == '1' && form.shop_button_effect == '1' && item.is_error == 0) || (form.is_shop_show == '1' && form.shop_button_effect == '0')" class="pr" :data-index="index" @tap.stop="goods_button_event">
|
||||
<block v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + ('color:' + new_style.shop_button_text_color)">{{ form.shop_button_text }}</view>
|
||||
</block>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :style="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-if="form.shop_button_effect == '1'" class="cart-badge-icon pa badge-style">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="flex-row align-c jc-sb">
|
||||
<view class="flex-row align-c nowrap">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="'color:' + new_style.shop_price_color">
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('original_price') && !isEmpty(item.min_original_price)" class="text-size-xss flex-row">
|
||||
<!-- <image v-if="form.static_img.length > 0" class="original-price-left" :src="form.static_img[0].url" model="widthFix"></image> -->
|
||||
<text :class="['original-price text-line-1', { 'flex-1': form.is_price_solo == '1' }]" :style="original_price">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<block v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</block>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(form.is_shop_show == '1' && form.shop_button_effect == '1' && item.is_error == 0) || (form.is_shop_show == '1' && form.shop_button_effect == '0')" class="pr" :data-index="index" @tap.stop="goods_button_event">
|
||||
<block v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + ('color:' + new_style.shop_button_text_color)">{{ form.shop_button_text }}</view>
|
||||
</block>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :style="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-if="form.shop_button_effect == '1'" class="cart-badge-icon pa badge-style">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<swiper circular="true" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :next-margin="new_style.rolling_fashion == 'translation' ? '-' + content_outer_spacing_magin : '0rpx'" :display-multiple-items="slides_per_group" :style="{ width: '100%', height: new_style.content_outer_height * new_scale + 'px' }">
|
||||
<swiper-item v-for="(item1, index1) in shop_content_list" :key="index1">
|
||||
<view class="flex-row wh-auto ht-auto" :style="onter_style">
|
||||
<view v-for="(item, index) in item1.split_list" :key="index" class="pr oh" :style="layout_style" :data-index="index1" :data-split-index="index" :data-value="item.goods_url" @tap.stop="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<block v-if="!isEmpty(item)">
|
||||
<view class="oh pr" :class="'flex-img' + theme">
|
||||
<view v-if="!isEmpty(item.new_cover)" :class="'flex-img' + theme">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else :class="'flex-img' + theme">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width: 100rpx;height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('plugins_view_icon') || is_show('original_price') || form.is_shop_show == '1'" class="flex-col flex-1 jc-sb content gap-10" :style="content_style">
|
||||
<view class="flex-col gap-10 top-title">
|
||||
<view v-if="is_show('title') || (['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc'))" class="flex-col" :style="{ gap: new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :class="text_line" :style="title_style">{{ item.title }}</view>
|
||||
<view v-if="['0', '1', '2', '3', '5'].includes(theme) && is_show('simple_desc')" :class="form.simple_desc_row == '2' ? 'text-line-2' : 'text-line-1'" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('plugins_view_icon') && !isEmpty(item.plugins_view_icon_data)" class="flex-row gap-5 align-c">
|
||||
<view v-for="(icon_data, icon_index) in item.plugins_view_icon_data" :key="icon_index" class="radius text-size-xsss padding-horizontal-xs" :style="{ background: icon_data.bg_color, color: icon_data.color, border: '1rpx solid' + (!isEmpty(icon_data.br_color) ? icon_data.br_color : icon_data.bg_color) }">{{ icon_data.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row align-c jc-sb">
|
||||
<view class="flex-row align-c nowrap">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="'color:' + new_style.shop_price_color">
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="show_content && is_show('original_price') && !isEmpty(item.min_original_price)" class="text-size-xss flex">
|
||||
<!-- <image v-if="form.static_img.length > 0" class="original-price-left" :src="form.static_img[0].url" model="widthFix"></image> -->
|
||||
<text :class="['original-price text-line-1', { 'flex-1': form.is_price_solo == '1' }]" :style="original_price">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<block v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</block>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(form.is_shop_show == '1' && form.shop_button_effect == '1' && item.is_error == 0) || (form.is_shop_show == '1' && form.shop_button_effect == '0')" class="pr" :data-index="index1" :data-split-index="index" @tap.stop="goods_button_event">
|
||||
<block v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + ('color:' + new_style.shop_button_text_color)">{{ form.shop_button_text }}</view>
|
||||
</block>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :style="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-if="form.shop_button_effect == '1'" class="cart-badge-icon pa badge-style">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, common_img_computer, gradient_handle, padding_computer, radius_computer, background_computer, border_computer, box_shadow_computer, old_margin, margin_computer } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
import componentBadge from '@/components/badge/badge';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
componentBadge,
|
||||
subscriptIndex
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propIsCommonStyle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propDiyIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
propIsCartParaCurve: false,
|
||||
list: [],
|
||||
content_radius: '', // 圆角设置
|
||||
content_img_radius: '', // 图片圆角设置
|
||||
content_padding: '', // 内边距设置
|
||||
theme: '', // 选择的风格
|
||||
content_outer_spacing: '', // 商品间距
|
||||
content_outer_spacing_magin: '', // 商品间距
|
||||
// 最外层不同风格下的显示
|
||||
outer_class: '',
|
||||
onter_style: '',
|
||||
// 不同风格下的样式
|
||||
layout_type: '',
|
||||
layout_style: '',
|
||||
layout_img_style: '',
|
||||
content_style: '', // 内容区域的样式
|
||||
show_content: false, // 显示除标题外的其他区域
|
||||
text_line: '', // 超过多少行隐藏
|
||||
style_container: '', // 公共样式
|
||||
style_img_container: '',
|
||||
shop_content_list: [],
|
||||
slides_per_group: 1,
|
||||
// 内容样式
|
||||
title_style: '',
|
||||
price_style: '',
|
||||
sold_number_style: '',
|
||||
score_style: '',
|
||||
button_style: '',
|
||||
simple_desc: '',
|
||||
price_symbol: '',
|
||||
price_unit: '',
|
||||
original_price: '',
|
||||
// 按钮背景色
|
||||
button_gradient: '',
|
||||
// 图片大小
|
||||
img_size: '',
|
||||
new_scale: 1,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
},
|
||||
propValue(new_value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content || null;
|
||||
const new_style = this.propValue.style || null;
|
||||
if (new_form != null && new_style != null) {
|
||||
let new_list = [];
|
||||
// 指定商品并且指定商品数组不为空
|
||||
if (!isEmpty(new_form.data_list) && new_form.data_type == '0') {
|
||||
new_list = new_form.data_list.map((item) => ({
|
||||
...item.data,
|
||||
title: !isEmpty(item.new_title) ? item.new_title : item.data.title,
|
||||
new_cover: item.new_cover,
|
||||
}));
|
||||
} else if (!isEmpty(new_form.data_auto_list) && new_form.data_type == '1') {
|
||||
// 筛选商品并且筛选商品数组不为空
|
||||
new_list = new_form.data_auto_list;
|
||||
}
|
||||
// 最外层不同风格下的显示
|
||||
const flex = ['0', '2', '6'].includes(new_form.theme) ? 'flex-col ' : 'flex-row ';
|
||||
const wrap = new_form.theme == '5' ? '' : 'flex-wrap ';
|
||||
const background = ['6'].includes(new_form.theme) ? 'bg-white ' : '';
|
||||
const button_gradient = gradient_handle(new_style.shop_button_color, '180deg');
|
||||
// 默认数据
|
||||
const product_style_list = [
|
||||
{ name: '单列展示', value: '0', width: 110, height: 120 },
|
||||
{ name: '大图展示', value: '2', width: 166, height: 166 },
|
||||
{ name: '无图模式', value: '6', width: 0, height: 0 },
|
||||
{ name: '两列展示(纵向)', value: '1', width: 180, height: 180 },
|
||||
{ name: '两列展示(横向)', value: '4', width: 70, height: 70 },
|
||||
{ name: '三列展示', value: '3', width: 116, height: 114 },
|
||||
{ name: '左右滑动展示', value: '5', width: 0, height: 0 },
|
||||
];
|
||||
const scale = sys_width / 390;
|
||||
let img_style = ``;
|
||||
if (['0', '4'].includes(new_form.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_width == 'number') {
|
||||
img_style += `width: ${ new_style.content_img_width * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `width: ${ list[0].width * scale }px;`;
|
||||
} else {
|
||||
img_style += 'width: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!['5', '6'].includes(new_form.theme)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_height == 'number') {
|
||||
img_style += `height: ${ new_style.content_img_height * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.theme);
|
||||
if (list.length > 0) {
|
||||
img_style += `height: ${ list[0].height * scale }px;`;
|
||||
} else {
|
||||
img_style += 'height: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
outer_class: flex + wrap + background + 'oh',
|
||||
list: new_list,
|
||||
new_scale: scale,
|
||||
content_radius: radius_computer(new_style.shop_radius), // 圆角设置
|
||||
content_img_radius: radius_computer(new_style.shop_img_radius), // 图片圆角设置
|
||||
content_padding: padding_computer(new_style.shop_padding) + 'box-sizing: border-box;', // 内边距设置
|
||||
theme: new_form.theme, // 选择的风格
|
||||
content_outer_spacing: new_style.content_outer_spacing, // 商品间距
|
||||
content_outer_spacing_magin: new_style.content_outer_spacing * 2 + 'rpx',
|
||||
onter_style: new_form.theme == '6' ? radius_computer(new_style.shop_radius) : `gap: ${new_style.content_outer_spacing * 2 + 'rpx'};`,
|
||||
// 不同风格下的样式
|
||||
layout_type: ['0', '4'].includes(new_form.theme) ? 'flex-row wh-auto ht-auto oh' : 'flex-col wh-auto ht-auto oh',
|
||||
layout_style: this.get_layout_style(new_style, new_form),
|
||||
layout_img_style: this.get_layout_img_style(new_style, new_form),
|
||||
content_style: this.get_content_style(new_style, new_form), // 内容区域的样式
|
||||
show_content: ['0', '1', '2'].includes(new_form.theme), // 显示除标题外的其他区域
|
||||
text_line: this.get_text_line(new_form), // 超过多少行隐藏
|
||||
style_container: this.propIsCommonStyle ? common_styles_computer(new_style.common_style) : '', // 公共样式
|
||||
style_img_container: this.propIsCommonStyle ? common_img_computer(new_style.common_style, this.propIndex) : '', // 图片样式
|
||||
// 内容样式设置
|
||||
button_gradient: button_gradient,
|
||||
title_style: this.trends_config(new_style, 'title', 'title', new_form),
|
||||
price_style: this.trends_config(new_style, 'price'),
|
||||
sold_number_style: this.trends_config(new_style, 'sold_number'),
|
||||
score_style: this.trends_config(new_style, 'score'),
|
||||
button_style: this.trends_config(new_style, 'button', 'buy_button') + button_gradient,
|
||||
simple_desc: this.trends_config(new_style, 'simple_desc', 'desc', new_form),
|
||||
price_symbol: !isEmpty(new_style.shop_price_symbol_color) ? this.trends_config(new_style, 'price_symbol') : 'font-size: 18rpx;color: #EA3323;' ,
|
||||
price_unit: !isEmpty(new_style.shop_price_unit_color) ? this.trends_config(new_style, 'price_unit') : 'font-size: 18rpx;color: #EA3323;',
|
||||
original_price: this.trends_config(new_style, 'original_price'),
|
||||
shop_content_list: this.get_shop_content_list(new_list, new_form, new_style),
|
||||
slides_per_group: new_style.rolling_fashion == 'translation' ? new_form.carousel_col : 1,
|
||||
img_size: img_style,
|
||||
});
|
||||
}
|
||||
},
|
||||
get_shop_content_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
get_text_line(form) {
|
||||
let line = '';
|
||||
if (['1', '6'].includes(form.theme)) {
|
||||
line = 'text-line-1';
|
||||
} else if (['0', '2', '3', '4', '5'].includes(form.theme)) {
|
||||
line = 'text-line-2';
|
||||
}
|
||||
return line;
|
||||
},
|
||||
// 不同风格下的样式
|
||||
get_layout_style(new_style, form) {
|
||||
const { shop_margin = old_margin } = new_style;
|
||||
const radius = form.theme == '6' ? '' : radius_computer(new_style.shop_radius);
|
||||
const style = form.theme != '6' ? gradient_handle(new_style?.shop_color_list || [], new_style?.shop_direction || '') + margin_computer(shop_margin) + border_computer(new_style) + box_shadow_computer(new_style) : '';
|
||||
let size_style = ``;
|
||||
const shop_left_right_width = shop_margin.margin_left + shop_margin.margin_right;
|
||||
if (['1', '4'].includes(form.theme)) {
|
||||
size_style = `width: calc((100% - ${new_style.content_outer_spacing * 2 + (shop_left_right_width * 4) + 'rpx'}) / 2);`;
|
||||
} else if (form.theme == '3') {
|
||||
size_style = `width: calc((100% - ${new_style.content_outer_spacing * 4 + (shop_left_right_width * 6) + 'rpx'}) / 3);`;
|
||||
} else if (form.theme == '5') {
|
||||
// 如果不是平移的时候执行
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
size_style = `width: ${this.get_multicolumn_columns_width(new_style, form)};min-width: ${this.get_multicolumn_columns_width(new_style, form)};height: ${new_style.content_outer_height * (sys_width / 390) + 'px'};`;
|
||||
} else {
|
||||
size_style = `margin-right: ${ (new_style.content_outer_spacing * 2) + (shop_margin.margin_right * 2) }rpx;width: 100%;height: 100%;`;
|
||||
}
|
||||
} else if (form.theme == '0') {
|
||||
size_style = `width: calc(100% - ${ shop_left_right_width }px);`;
|
||||
}
|
||||
return `${radius} ${ style } ${size_style}`;
|
||||
},
|
||||
get_layout_img_style(new_style, form) {
|
||||
const padding = ['0', '4'].includes(form.theme) ? padding_computer(new_style.shop_padding) + 'box-sizing: border-box;' : '';
|
||||
const data = {
|
||||
background_img_style: new_style?.shop_background_img_style || '',
|
||||
background_img: new_style?.shop_background_img || '',
|
||||
}
|
||||
const background = form.theme != '6' ? background_computer(data) : '';
|
||||
return `${padding} ${background}`;
|
||||
},
|
||||
get_multicolumn_columns_width(new_style, form) {
|
||||
const { carousel_col } = form;
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.content_outer_spacing * (carousel_col - 1)) / carousel_col;
|
||||
return `calc(${100 / carousel_col}% - ${gap * 2}rpx)`;
|
||||
},
|
||||
get_content_style(new_style, form) {
|
||||
const spacing_value = new_style.content_spacing;
|
||||
let spacing = '';
|
||||
if (['0', '4'].includes(form.theme)) {
|
||||
spacing = `margin-left: ${spacing_value * 2}rpx;`;
|
||||
} else {
|
||||
spacing = padding_computer(new_style.shop_padding) + 'box-sizing: border-box;';
|
||||
}
|
||||
return `${spacing}`;
|
||||
},
|
||||
// 判断是否显示对应的内容
|
||||
is_show(index) {
|
||||
return this.form.is_show.includes(index);
|
||||
},
|
||||
// 根据传递的参数,从对象中取值
|
||||
trends_config(new_style, key, type, new_form) {
|
||||
return this.style_config(new_style[`shop_${key}_typeface`], new_style[`shop_${key}_size`], new_style[`shop_${key}_color`], type, new_form);
|
||||
},
|
||||
// 根据传递的值,显示不同的内容
|
||||
style_config(typeface, size, color, type, new_form) {
|
||||
let style = `font-weight:${typeface}; font-size: ${size * 2}rpx;`;
|
||||
if (type == 'title') {
|
||||
if (['1', '6'].includes(new_form.theme)) {
|
||||
style += `line-height: ${size * 2}rpx;height: ${size * 2}rpx;color: ${color};`;
|
||||
} else if (['0', '2', '3', '4', '5'].includes(new_form.theme)) {
|
||||
style += `line-height: ${size > 0 ? (size + 3) * 2 : 0}rpx;height: ${size > 0 ? (size + 3) * 4 : 0}rpx;color: ${color};`;
|
||||
}
|
||||
} else if (type == 'desc') {
|
||||
if (new_form.simple_desc_row == '2') {
|
||||
style += `line-height: ${size > 0 ? (size + 3) * 2 : 0}rpx;height: ${size > 0 ? (size + 3) * 4 : 0}rpx;color: ${color};`;
|
||||
} else {
|
||||
style += `line-height: ${size * 2}rpx;height: ${size * 2}rpx;color: ${color};`;
|
||||
}
|
||||
} else {
|
||||
if (type != 'buy_button') {
|
||||
style += `color: ${color};`;
|
||||
}
|
||||
}
|
||||
return style;
|
||||
},
|
||||
// icon标志显示样式
|
||||
icon_style(item) {
|
||||
let style = `background: ${item.bg_color};color: ${item.color};`;
|
||||
if (!isEmpty(item.br_color)) {
|
||||
style += `border: 2rpx solid ${item.br_color};`;
|
||||
} else {
|
||||
style += `border: 2rpx solid ${item.bg_color};`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
let index = e.currentTarget.dataset.index || 0;
|
||||
let goods = this.list[index];
|
||||
let split_index = 0;
|
||||
if (this.theme == '5') {
|
||||
split_index = e.currentTarget.dataset.splitIndex || 0;
|
||||
goods = this.shop_content_list[index].split_list[split_index];
|
||||
}
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
goods_button_event(e) {
|
||||
this.goods_cart_event(e);
|
||||
},
|
||||
// 加入购物车
|
||||
goods_cart_event(e) {
|
||||
let index = e.currentTarget.dataset.index || 0;
|
||||
let split_index = 0;
|
||||
let goods = this.list[index];
|
||||
if (this.theme == '5') {
|
||||
split_index = e.currentTarget.dataset.splitIndex || 0;
|
||||
goods = this.shop_content_list[index].split_list[split_index];
|
||||
}
|
||||
if (this.form.shop_button_effect == '0') {
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
|
||||
app.globalData.url_open(goods.goods_url);
|
||||
} else {
|
||||
// 开启购物车抛物线效果则展示提示操作
|
||||
let is_success_tips = this.propIsCartParaCurve ? 0 : 1;
|
||||
this.$emit(
|
||||
'goods_buy_event',
|
||||
this.propDiyIndex,
|
||||
goods,
|
||||
{
|
||||
buy_event_type: 'cart',
|
||||
is_direct_cart: 1,
|
||||
is_success_tips: is_success_tips,
|
||||
},
|
||||
{
|
||||
index: index,
|
||||
split_index: split_index,
|
||||
pos: e,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
// 加入购物车成功回调
|
||||
goods_cart_back_event(e) {
|
||||
app.globalData.showToast('加入成功', 'success');
|
||||
// 增加数量
|
||||
var { index, split_index } = e.back_data;
|
||||
let new_data = this.list;
|
||||
let goods = new_data[index];
|
||||
if (this.theme == '5') {
|
||||
new_data = this.shop_content_list;
|
||||
goods = new_data[index][split_index];
|
||||
}
|
||||
goods['user_cart_count'] = parseInt(goods['user_cart_count'] || 0) + parseInt(e.stock);
|
||||
if (goods['user_cart_count'] > 99) {
|
||||
goods['user_cart_count'] = '99+';
|
||||
}
|
||||
if (this.theme != '5') {
|
||||
new_data[index] = goods;
|
||||
this.setData({
|
||||
list: new_data,
|
||||
});
|
||||
} else {
|
||||
new_data[index][split_index] = goods;
|
||||
this.setData({
|
||||
shop_content_list: new_data,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.identifying {
|
||||
font-size: 18rpx;
|
||||
}
|
||||
.original-price {
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
.flex-img5 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
// .original-price-left {
|
||||
// width: 20rpx;
|
||||
// height: 28rpx;
|
||||
// }
|
||||
.br-b-e {
|
||||
border-bottom: 2rpx solid #eee;
|
||||
}
|
||||
.badge-style {
|
||||
top: -20rpx;
|
||||
right: 10rpx;
|
||||
}
|
||||
</style>
|
||||
253
components/diy/goods-tabs.vue
Normal file
253
components/diy/goods-tabs.vue
Normal file
@@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<view class="goods-tabs ou" :class="'goods-tabs-' + propKey" :style="style_container">
|
||||
<view class="ou" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="goods_tabs" :propIsTop="top_up == '1'" :propTop="sticky_top" :propStyle="tabs_style" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propCustomNavHeight="propIsTabsUseSafeDistance ? (propCustomNavHeight * 2 + 'rpx') : '0rpx'" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" :propTabsBackground="tabs_background" @onTabsTap="tabs_click_event"></componentDiyModulesTabsView>
|
||||
<view :style="shop_margin_top">
|
||||
<view :style="shop_container">
|
||||
<view :style="shop_img_container">
|
||||
<componentGoodsList ref="diy_goods_list" :propKey="diy_key" :propDiyIndex="propDiyIndex" :propValue="goods_tabs" :propIsCommonStyle="false" @goods_buy_event="goods_buy_event"></componentGoodsList>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, background_computer, gradient_computer, isEmpty, old_border_and_box_shadow, old_margin, old_radius, old_padding, border_computer, box_shadow_computer, radius_computer } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
import componentGoodsList from '@/components/diy/goods-list';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
componentGoodsList,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propCustomNavHeight: {
|
||||
type: Number,
|
||||
default: 33,
|
||||
},
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 顶部导航是否开启沉浸模式
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propDiyIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propIsTabsUseSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
goods_tabs: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
tabs_top: 0,
|
||||
tabs_background: 'background:transparent',
|
||||
custom_nav_height: 33,
|
||||
diy_key: '',
|
||||
// 选项卡背景设置
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 商品区域背景设置
|
||||
shop_margin_top: '',
|
||||
shop_container: '',
|
||||
shop_img_container: '',
|
||||
// #ifdef MP
|
||||
nav_safe_space: bar_height + 5,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
nav_safe_space: bar_height + 7,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
nav_safe_space: bar_height + 0,
|
||||
// #endif
|
||||
// 选项卡默认数据
|
||||
tabs_index: 0,
|
||||
sticky_top: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propScrollTop(newVal) {
|
||||
if (newVal + this.sticky_top + this.custom_nav_height > this.tabs_top + this.nav_safe_space && this.top_up == '1') {
|
||||
let new_style = this.propValue.style || {};
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (tabs_bg.length > 0 && (tabs_bg[0].color || null) != null) {
|
||||
new_tabs_background = gradient_computer(new_style.common_style);
|
||||
}
|
||||
let new_tabs_background_img = background_computer(new_style.common_style);
|
||||
if (new_tabs_background_img.length > 0) {
|
||||
new_tabs_background_img += 'background-position: top left;';
|
||||
}
|
||||
this.tabs_background = (new_tabs_background.length > 0 ? new_tabs_background : 'background:#fff;') + new_tabs_background_img;
|
||||
} else {
|
||||
this.tabs_background = 'background:transparent';
|
||||
}
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.setData({
|
||||
diy_key: val,
|
||||
});
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
self.getTop();
|
||||
});
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// 获取自定义导航栏高度
|
||||
this.setData({
|
||||
custom_nav_height: this.propCustomNavHeight,
|
||||
});
|
||||
// #endif
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_content = new_data.content || {};
|
||||
const new_style = new_data.style || {};
|
||||
const new_tabs_data = new_data.content.tabs_list[this.tabs_index] || {};
|
||||
// 产品的值
|
||||
new_data.content.data_type = new_tabs_data.data_type;
|
||||
new_data.content.category = new_tabs_data.category;
|
||||
new_data.content.brand = new_tabs_data.brand;
|
||||
new_data.content.number = new_tabs_data.number;
|
||||
new_data.content.sort = new_tabs_data.sort;
|
||||
new_data.content.sort_rules = new_tabs_data.sort_rules;
|
||||
new_data.content.data_list = new_tabs_data.data_list;
|
||||
new_data.content.data_auto_list = new_tabs_data.data_auto_list;
|
||||
// 公共样式
|
||||
const common_style = new_style.common_style;
|
||||
let tabs_style_obj = {
|
||||
padding_top: common_style.padding_top - this.propCustomNavHeight < 0 ? 0 : common_style.padding_top - this.propCustomNavHeight,
|
||||
padding_left: common_style.padding_left,
|
||||
padding_right: common_style.padding_right,
|
||||
};
|
||||
let new_tabs_style = padding_computer(tabs_style_obj) + `position:relative;left: -${tabs_style_obj.padding_left * 2}rpx;right: -${tabs_style_obj.padding_right * 2}rpx;width:100%;`;
|
||||
// 如果是历史数据的话,就执行默认添加下边距
|
||||
if (isEmpty(new_style.tabs_padding)) {
|
||||
new_tabs_style += 'padding-bottom: 20rpx;';
|
||||
}
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, shop_content_color_list = [], shop_content_direction = '', shop_content_background_img_style = '', shop_content_background_img = [], shop_content_margin = old_margin, shop_content_padding = old_padding, shop_content_radius = old_radius } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
};
|
||||
// 商品区域背景设置
|
||||
const shop_content_data = {
|
||||
color_list: shop_content_color_list,
|
||||
direction: shop_content_direction,
|
||||
background_img_style: shop_content_background_img_style,
|
||||
background_img: shop_content_background_img,
|
||||
};
|
||||
const shop_content = new_style?.shop_content || old_border_and_box_shadow;
|
||||
const tabs_content = new_style?.tabs_content || old_border_and_box_shadow;
|
||||
this.setData({
|
||||
top_up: new_content.tabs_top_up,
|
||||
sticky_top: this.propTop + (new_style?.tabs_margin?.margin_top || 0),
|
||||
goods_tabs: new_data,
|
||||
style_container: common_styles_computer(common_style),
|
||||
style_img_container: common_img_computer(common_style, this.propIndex),
|
||||
tabs_style: new_tabs_style,
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(new_style?.tabs_margin || old_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + 'overflow: hidden;',
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
shop_margin_top: 'margin-top:' + (new_style?.shop_content_spacing || 0) * 2 + 'rpx;',
|
||||
shop_container: gradient_computer(shop_content_data) + margin_computer(shop_content_margin) + radius_computer(shop_content_radius) + box_shadow_computer(shop_content) + border_computer(shop_content) + 'overflow: hidden;',
|
||||
shop_img_container: background_computer(shop_content_data) + padding_computer(shop_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
});
|
||||
},
|
||||
tabs_click_event(index) {
|
||||
let new_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
new_data.content.data_type = new_data.content.tabs_list[index].data_type;
|
||||
new_data.content.category = new_data.content.tabs_list[index].category;
|
||||
new_data.content.brand = new_data.content.tabs_list[index].brand;
|
||||
new_data.content.number = new_data.content.tabs_list[index].number;
|
||||
new_data.content.sort = new_data.content.tabs_list[index].sort;
|
||||
new_data.content.sort_rules = new_data.content.tabs_list[index].sort_rules;
|
||||
new_data.content.data_list = new_data.content.tabs_list[index].data_list;
|
||||
new_data.content.data_auto_list = new_data.content.tabs_list[index].data_auto_list;
|
||||
this.setData({
|
||||
tabs_index: index,
|
||||
goods_tabs: new_data,
|
||||
diy_key: Math.random(),
|
||||
});
|
||||
},
|
||||
// 获取商品距离顶部的距离
|
||||
getTop() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.goods-tabs-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
let new_data = typeof this.propValue == 'string' ? JSON.parse(JSON.stringify(this.propValue)) : this.propValue;
|
||||
const new_style = new_data.style || {};
|
||||
this.setData({
|
||||
tabs_top: res.top - (new_style.common_style?.margin_top || 0),
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
goods_buy_event(index, goods = {}, params = {}, back_data = null) {
|
||||
this.$emit('goods_buy_event', index, goods, params, back_data);
|
||||
},
|
||||
goods_cart_back_event(e) {
|
||||
if ((this.$refs.diy_goods_list || null) != null) {
|
||||
this.$refs.diy_goods_list.goods_cart_back_event(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
420
components/diy/header.vue
Normal file
420
components/diy/header.vue
Normal file
@@ -0,0 +1,420 @@
|
||||
<template>
|
||||
<view v-if="(propValue || null) !== null" class="header-container">
|
||||
<view class="header-around wh-auto" :style="roll_style + position">
|
||||
<view class="wh-auto" :style="roll_img_style">
|
||||
<view class="wh-auto ht-auto pa up_slide_bg" :style="up_slide_style">
|
||||
<view class="wh-auto ht-auto" :style="up_slide_img_style"></view>
|
||||
</view>
|
||||
<view :style="top_content_style">
|
||||
<view class="header-content flex-row align-s">
|
||||
<view class="model-top flex-1 mt-1">
|
||||
<view class="roll pr z-i">
|
||||
<view class="model-head pr padding-left-main padding-right-main" style="box-sizing: border-box">
|
||||
<view class="flex-col" :style="'gap:' + data_alone_row_space">
|
||||
<view class="model-head-content flex-row align-c jc-sb gap-16 wh-auto pr" :style="header_style">
|
||||
<!-- 支付宝小程序自带返回按钮,这里就不给返回按钮了,这里给留出一点空间就行 -->
|
||||
<!-- #ifndef MP-ALIPAY -->
|
||||
<view v-if="!is_tabbar_pages" class="z-i dis-inline-block margin-top-xs" @tap="top_nav_left_back_event">
|
||||
<iconfont name="icon-arrow-left" size="40rpx" propContainerDisplay="flex" :color="form.style.left_back_btn_color || '#333'"></iconfont>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<view class="dis-inline-block padding-left-sm"></view>
|
||||
<!-- #endif -->
|
||||
<view v-if="['1', '2', '3'].includes(form.content.theme)" class="flex-1">
|
||||
<view class="flex-row align-c jc-c ht-auto gap-16" :class="position_class" :style="text_style + 'justify-content:' + form.content.indicator_location || 'center'">
|
||||
<template v-if="['2', '3'].includes(form.content.theme)">
|
||||
<view v-if="form.content.logo.length > 0" class="logo-outer-style re flex-row align-c">
|
||||
<template v-if="form.style.up_slide_logo && form.style.up_slide_logo.length > 0">
|
||||
<!-- 有上滑logo的处理逻辑 -->
|
||||
<view v-if="(propScrollTop - 5) / (header_top + 33) < 1" class="logo-style" :style="up_slide_old_logo_style">
|
||||
<image class="logo-style" :src="form.content.logo[0].url" mode="heightFix" />
|
||||
</view>
|
||||
<view :class="['logo-style left-0', { pa: (propScrollTop - 5) / (header_top + 33) < 1 }]" :style="'opacity:0;' + up_slide_opacity">
|
||||
<image class="logo-style" :src="form.style.up_slide_logo[0].url" mode="heightFix" />
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 没有上滑logo的处理逻辑 -->
|
||||
<image class="logo-style" :src="form.content.logo[0].url" mode="heightFix" />
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="['1', '2', '3'].includes(form.content.theme) && !isEmpty(form.content.title)">{{ form.content.title }}</view>
|
||||
<template v-if="['3'].includes(form.content.theme) && !is_search_alone_row">
|
||||
<view class="flex-1 fw-n">
|
||||
<componentDiySearch :propValue="form" :propIsPageSettings="true"></componentDiySearch>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="['4', '5'].includes(form.content.theme)" class="flex-1 flex-row align-c">
|
||||
<view v-if="form.content.positioning_name_float !== '1'" class="flex-row align-c gap-2">
|
||||
<view :style="location_margin">
|
||||
<component-choice-location :propLocationContainerStyle="style_location_container" :propLocationImgContainerStyle="style_location_img_container" :propBaseColor="location_color" :propTextDefaultName="form.content.positioning_name" :propIsLeftIconArrow="form.content.is_location_left_icon_show == '1'" :propLeftImgValue="form.content.location_left_img" :propLeftIconValue="'icon-' + form.content.location_left_icon" :propIconLocationSize="location_left_size" :propIconArrowSize="location_right_size" :propIsRightIconArrow="form.content.is_location_right_icon_show == '1'" :propRightImgValue="form.content.location_right_img" :propRightIconValue="'icon-' + form.content.location_right_icon" :propTextMaxWidth="location_name_style" propContainerDisplay="flex" @onBack="choice_location_back"></component-choice-location>
|
||||
</view>
|
||||
</view>
|
||||
<template v-if="['5'].includes(form.content.theme) && !is_search_alone_row">
|
||||
<view class="flex-1">
|
||||
<componentDiySearch :propValue="form" :propIsPageSettings="true" :propLocationMargin="location_margin" propSearchType="header" :propLocationContainerStyle="style_location_container" :propLocationImgContainerStyle="style_location_img_container" :propBaseColor="location_color" :propIconLocationSize="location_left_size" :propIconArrowSize="location_right_size" @onBack="choice_location_back"></componentDiySearch>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<view v-if="!isEmpty(form.content.icon_setting) && !is_icon_alone_row" class="flex-row align-c z-i" :class="['1'].includes(form.content.theme) ? 'right-0' : ''" :style="{ gap: form.style.img_space * 2 + 'rpx' }">
|
||||
<view v-for="(item, index) in form.content.icon_setting" :key="index" class="pr" :style="{ width: form.style.img_size * 2 + 'rpx', height: form.style.img_size * 2 + 'rpx' }" :data-value="item.link.page" @tap="url_event">
|
||||
<imageEmpty v-if="item.img.length > 0" :propImageSrc="item.img[0].url" :propErrorStyle="'width: ' + Number(form.style.img_size) * 2 + 'rpx;height:' + Number(form.style.img_size) * 2 + 'rpx;'"></imageEmpty>
|
||||
<iconfont v-else :name="'icon-' + item.icon" :size="form.style.img_size * 2 + 'rpx'" :color="form.style.img_color" propContainerDisplay="flex"></iconfont>
|
||||
<view v-if="!isEmpty(item.badge) && item.badge !== 0" class="pa badge-style">
|
||||
<component-badge :propNumber="item.badge || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="is_search_alone_row || is_icon_alone_row" class="model-head-content flex-row align-c gap-16">
|
||||
<template v-if="['3', '5'].includes(form.content.theme) && is_search_alone_row">
|
||||
<view class="flex-1">
|
||||
<componentDiySearch :propValue="form" :propIsPageSettings="true" :propLocationMargin="location_margin" propSearchType="header" :propLocationContainerStyle="style_location_container" :propLocationImgContainerStyle="style_location_img_container" :propBaseColor="location_color" :propIconLocationSize="location_left_size" :propIconArrowSize="location_right_size" @onBack="choice_location_back"></componentDiySearch>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="!isEmpty(form.content.icon_setting) && is_icon_alone_row" class="flex-row align-c z-i" :class="['1'].includes(form.content.theme) ? 'right-0' : ''" :style="{ gap: form.style.img_space * 2 + 'rpx' }">
|
||||
<view v-for="(item, index) in form.content.icon_setting" :key="index" class="pr" :style="{ width: form.style.img_size * 2 + 'rpx', height: form.style.img_size * 2 + 'rpx' }" :data-value="item.link.page" @tap="url_event">
|
||||
<imageEmpty v-if="item.img.length > 0" :propImageSrc="item.img[0].url" :propErrorStyle="'width: ' + Number(form.style.img_size) * 2 + 'rpx;height:' + Number(form.style.img_size) * 2 + 'rpx;'"></imageEmpty>
|
||||
<iconfont v-else :name="'icon-' + item.icon" :size="form.style.img_size * 2 + 'rpx'" :color="form.style.img_color" propContainerDisplay="flex"></iconfont>
|
||||
<view v-if="!isEmpty(item.badge) && item.badge !== 0" class="pa badge-style">
|
||||
<component-badge :propNumber="item.badge || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block v-if="!is_immersion_model">
|
||||
<view v-if="!is_positon_realative" class="nav-seat" :style="top_content_style">
|
||||
<view :style="'height:' + (is_search_alone_row || is_icon_alone_row ? 'calc(132rpx + ' + data_alone_row_space + ');' : '66rpx;')"></view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- #ifndef H5 || MP-TOUTIAO -->
|
||||
<!-- <view v-if="is_positon_realative" class="wh-auto pf top-0 left-0 right-0" :style="roll_style">
|
||||
<view :style="top_content_style">
|
||||
<view :style="'height:' + (is_search_alone_row || is_icon_alone_row ? 'calc(132rpx + ' + data_alone_row_space + ');' : '66rpx;')"></view>
|
||||
</view>
|
||||
</view> -->
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentDiySearch from '@/components/diy/search';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty';
|
||||
import componentChoiceLocation from '@/components/choice-location/choice-location';
|
||||
import componentBadge from '@/components/badge/badge';
|
||||
import { isEmpty, background_computer, gradient_computer, margin_computer, padding_computer, radius_computer } from '@/common/js/common/common.js';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: [String, Number, Object],
|
||||
default: '',
|
||||
},
|
||||
// 滚动距离
|
||||
propScrollTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
componentDiySearch,
|
||||
imageEmpty,
|
||||
componentChoiceLocation,
|
||||
componentBadge,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
position: '',
|
||||
roll_style: '',
|
||||
text_style: '',
|
||||
header_style: 'max-width:100%',
|
||||
common_app_is_header_nav_fixed: 0,
|
||||
// 5,7,0 是误差,, 10 是下边距,66是高度,bar_height是不同小程序下的导航栏距离顶部的高度
|
||||
// #ifdef MP
|
||||
top_content_style: 'padding-top:' + (bar_height + 5) + 'px;padding-bottom:10px;',
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
top_content_style: 'padding-top:' + (bar_height + 7) + 'px;padding-bottom:10px;',
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
top_content_style: 'padding-top:' + bar_height + 'px;padding-bottom:10px;',
|
||||
// #endif
|
||||
is_positon_realative: false,
|
||||
// 顶部背景样式类别
|
||||
header_background_type: 'color_image',
|
||||
// #ifdef MP
|
||||
header_top: bar_height + 5 + 10 + 33,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
header_top: bar_height + 7 + 10 + 33,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
header_top: bar_height + 0 + 10 + 33,
|
||||
// #endif
|
||||
// 判断是否是沉浸模式
|
||||
is_immersion_model: false,
|
||||
up_slide_opacity: '',
|
||||
up_slide_old_logo_style: '',
|
||||
up_slide_style: '',
|
||||
up_slide_img_style: '',
|
||||
// 当前页面是否在底部菜单中
|
||||
is_tabbar_pages: app.globalData.is_tabbar_pages(),
|
||||
// 判断header的查询是否独行
|
||||
is_search_alone_row: false,
|
||||
is_icon_alone_row: false,
|
||||
data_alone_row_space: '0rpx',
|
||||
// 定位设置
|
||||
style_location_container: '',
|
||||
style_location_img_container: '',
|
||||
location_left_size: '24rpx',
|
||||
location_right_size: '24rpx',
|
||||
location_margin: '', // 悬浮之后有间距,所以要将margin设置成外padding
|
||||
location_color: '', // 定位颜色
|
||||
location_name_style: '', // 定位样式
|
||||
// 默认数据
|
||||
old_radius: { radius: 0, radius_top_left: 0, radius_top_right: 0, radius_bottom_left: 0, radius_bottom_right: 0 },
|
||||
old_padding: { padding: 0, padding_top: 0, padding_bottom: 0, padding_left: 0, padding_right: 0 },
|
||||
old_margin: { margin: 0, margin_top: 0, margin_bottom: 0, margin_left: 0, margin_right: 0 },
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听滚动距离
|
||||
propScrollTop(newVal) {
|
||||
const { up_slide_background_color_list, up_slide_background_direction, up_slide_background_img, up_slide_background_img_style, up_slide_display } = this.propValue.style || {};
|
||||
if (up_slide_display == '1') {
|
||||
// 渐变
|
||||
const gradient = { color_list: up_slide_background_color_list, direction: up_slide_background_direction };
|
||||
// 背景图
|
||||
const back = { background_img: up_slide_background_img, background_img_style: up_slide_background_img_style };
|
||||
const up_slide_opacity = 'opacity:' + ((newVal - 20) / this.header_top > 1 ? 1 : ((newVal - 20) / this.header_top).toFixed(2)) + ';';
|
||||
this.up_slide_opacity = up_slide_opacity;
|
||||
// 来的logo要比新的隐藏的快,所以要比原来的logo快一点
|
||||
this.up_slide_old_logo_style = 'opacity:' + ((newVal - 5) / this.header_top > 1 ? 0 : (1 - (newVal - 5) / this.header_top).toFixed(2)) + ';';
|
||||
// =0是大小误差
|
||||
this.up_slide_style = gradient_computer(gradient) + up_slide_opacity;
|
||||
this.up_slide_img_style = background_computer(back);
|
||||
}
|
||||
},
|
||||
propKey(val) {
|
||||
if ((this.propValue || null) !== null) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 判断是否有值初始化
|
||||
if ((this.propValue || null) !== null) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 判断是否为空
|
||||
isEmpty,
|
||||
// 初始化
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
let new_roll_style = '';
|
||||
let new_roll_img_style = '';
|
||||
const { header_background_img, header_background_img_style, header_background_color_list, header_background_direction, header_background_type, immersive_style } = new_style;
|
||||
if (header_background_type === 'color_image') {
|
||||
// 渐变
|
||||
const gradient = { color_list: header_background_color_list, direction: header_background_direction };
|
||||
// 背景图
|
||||
const back = { background_img: header_background_img, background_img_style: header_background_img_style };
|
||||
new_roll_style += gradient_computer(gradient);
|
||||
new_roll_img_style += background_computer(back);
|
||||
} else {
|
||||
new_roll_style += `background: transparent;`;
|
||||
}
|
||||
// 小程序下,获取小程序胶囊的宽度
|
||||
let menu_button_info = 'max-width:100%';
|
||||
let new_text_style = `font-weight:${new_style.header_background_title_typeface}; font-size: ${new_style.header_background_title_size * 2}rpx; color: ${new_style.header_background_title_color};`;
|
||||
// #ifndef MP-TOUTIAO
|
||||
// #ifdef MP
|
||||
// 判断是否有胶囊
|
||||
const is_current_single_page = app.globalData.is_current_single_page();
|
||||
// 如果有胶囊的时候,做处理
|
||||
if (is_current_single_page == 0) {
|
||||
const custom = uni.getMenuButtonBoundingClientRect();
|
||||
menu_button_info = `max-width:calc(100% - ${custom.width + 10}px);`;
|
||||
new_text_style += `right:-${custom.width + 10}px;`;
|
||||
}
|
||||
// #endif
|
||||
// #endif
|
||||
const { location_margin = this.old_margin } = new_style;
|
||||
this.setData({
|
||||
form: this.propValue,
|
||||
position: new_style.up_slide_display == '1' ? 'position:fixed;' : new_style.immersive_style === '1' ? 'position:absolute;' : 'position:relative;',
|
||||
is_positon_realative: new_style.up_slide_display == '1' ? false : true,
|
||||
roll_style: new_roll_style,
|
||||
roll_img_style: new_roll_img_style,
|
||||
text_style: new_text_style,
|
||||
position_class: new_content.indicator_location == 'center' ? `indicator-center` : '',
|
||||
header_style: menu_button_info,
|
||||
header_background_type: header_background_type,
|
||||
is_immersion_model: header_background_type !== 'color_image' && immersive_style == '1',
|
||||
data_alone_row_space: new_style.data_alone_row_space * 2 + 'rpx',
|
||||
is_search_alone_row: new_content.data_alone_row_value && new_content.data_alone_row_value.includes('search'),
|
||||
is_icon_alone_row: new_content.data_alone_row_value && new_content.data_alone_row_value.includes('icon'),
|
||||
style_location_container: this.get_style_location_container(new_style),
|
||||
style_location_img_container: this.get_style_location_img_container(new_style),
|
||||
location_left_size: !isEmpty(new_style.location_left_icon_size) ? new_style.location_left_icon_size * 2 + 'rpx' : '24rpx',
|
||||
location_right_size: !isEmpty(new_style.location_right_icon_size) ? new_style.location_right_icon_size * 2 + 'rpx' : '24rpx',
|
||||
location_color: !isEmpty(new_style.location_color) ? new_style.location_color : new_style?.position_color || '',
|
||||
location_name_style: this.get_location_name_style(new_content),
|
||||
location_margin: `padding: ${location_margin.margin_top * 2}rpx ${location_margin.margin_right * 2}rpx ${location_margin.margin_bottom * 2}rpx ${location_margin.margin_left * 2}rpx;`, // 悬浮之后有间距,所以要将margin设置成外padding
|
||||
});
|
||||
// this.$emit('onImmersionModelCallBack', this.is_immersion_model);
|
||||
},
|
||||
get_location_name_style(new_content) {
|
||||
const is_search_alone_row = new_content.data_alone_row_value && new_content.data_alone_row_value.includes('search');
|
||||
const is_icon_alone_row = new_content.data_alone_row_value && new_content.data_alone_row_value.includes('icon');
|
||||
let width = 0;
|
||||
if (is_search_alone_row && is_icon_alone_row) {
|
||||
width = 200;
|
||||
} else if (is_search_alone_row || is_icon_alone_row) {
|
||||
width = 100;
|
||||
}
|
||||
if (new_content.theme == '4') {
|
||||
return `${(150 + width) * 2}rpx;`;
|
||||
} else {
|
||||
return `${(100 + width) * 2}rpx;`;
|
||||
}
|
||||
},
|
||||
// 定位设置
|
||||
get_style_location_container(new_style) {
|
||||
const { location_margin = this.old_margin, location_radius = this.old_radius } = new_style;
|
||||
const style = {
|
||||
color_list: new_style?.location_color_list || [],
|
||||
direction: new_style?.location_direction || '',
|
||||
};
|
||||
const height = 32 - location_margin.margin_top - location_margin.margin_bottom;
|
||||
return gradient_computer(style) + radius_computer(location_radius) + `height: ${height * 2}rpx;line-height: ${height * 2}rpx;`;
|
||||
},
|
||||
// 背景图片
|
||||
get_style_location_img_container(new_style) {
|
||||
const { location_background_img = [], location_background_img_style = '2', location_border_show = '0', location_padding = this.old_padding, location_margin = this.old_margin, location_border_size = this.old_padding, location_border_color = '', location_border_style = 'solid' } = new_style;
|
||||
const style = {
|
||||
background_img: location_background_img,
|
||||
background_img_style: location_background_img_style,
|
||||
};
|
||||
let border = ``;
|
||||
if (location_border_show == '1') {
|
||||
border += `border-width: ${location_border_size.padding_top}px ${location_border_size.padding_right}px ${location_border_size.padding_bottom}px ${location_border_size.padding_left}px;border-style: ${location_border_style};border-color: ${location_border_color};`;
|
||||
}
|
||||
const height = 32 - (location_margin.margin_top || 0) - (location_margin.margin_bottom || 0);
|
||||
return background_computer(style) + padding_computer(location_padding) + border + `height: ${(height > 0 ? height : 0) * 2}rpx;line-height: ${(height > 0 ? height : 0) * 2}rpx;box-sizing: border-box;`;
|
||||
},
|
||||
// 获取顶部导航高度
|
||||
get_nav_height() {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.article-tabs')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
this.setData({
|
||||
tabs_top: res.top,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
// 位置回调
|
||||
choice_location_back(e) {
|
||||
this.$emit('onLocationBack', e);
|
||||
},
|
||||
// 打开地址
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
// 返回事件
|
||||
top_nav_left_back_event() {
|
||||
app.globalData.page_back_prev_event();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-container {
|
||||
width: 100%;
|
||||
.header-around {
|
||||
z-index: 12;
|
||||
}
|
||||
.model-top {
|
||||
.roll {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.img {
|
||||
width: 680rpx;
|
||||
}
|
||||
}
|
||||
.model-head {
|
||||
.model-head-content {
|
||||
height: 66rpx;
|
||||
// overflow: hidden;
|
||||
top: -1rpx;
|
||||
/* #ifdef H5 || MP-TOUTIAO */
|
||||
top: 4rpx;
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
.model-head-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 66rpx;
|
||||
.function-icon {
|
||||
height: 66rpx;
|
||||
}
|
||||
}
|
||||
.logo-outer-style {
|
||||
height: 56rpx;
|
||||
.logo-style {
|
||||
height: 56rpx;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.indicator-center {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.up_slide_bg {
|
||||
z-index: -1;
|
||||
}
|
||||
.badge-style {
|
||||
top: -20rpx;
|
||||
right: 5rpx;
|
||||
}
|
||||
</style>
|
||||
122
components/diy/hot-zone.vue
Normal file
122
components/diy/hot-zone.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<!-- 热区 -->
|
||||
<view ref="containerRef" class="oh container" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view ref="hotRef" class="hot pr" :style="style">
|
||||
<image :src="img" class="wh-auto dis-block" mode="widthFix" @load="on_load_img" />
|
||||
<view v-for="(item, index) in hot_data" :key="index" class="hot_box" :style="'left: ' + item.drag_start.x * w_scale1 * w_scale2 + 'px;top:' + item.drag_start.y * h_scale1 * h_scale2 + 'px;width: ' + Math.max(item.drag_end.width * w_scale1 * w_scale2, 1) + 'px;height: ' + Math.max(item.drag_end.height * h_scale1 * h_scale2, 1) + 'px;display: flex;'" :data-value="item.link.page" @tap="url_event"> </view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
img: '',
|
||||
hot_data: [],
|
||||
img_width: 1,
|
||||
img_height: 1,
|
||||
container_ref_h: 0,
|
||||
hot_ref_h: 0,
|
||||
hot_ref_w: 0,
|
||||
w_scale1: 1,
|
||||
h_scale1: 1,
|
||||
w_scale2: 1,
|
||||
h_scale2: 1,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
this.setData({
|
||||
img: new_content.img[0].url,
|
||||
img_width: new_content.hot.img_width || 1,
|
||||
img_height: new_content.hot.img_height || 1,
|
||||
hot_data: new_content.hot.data || [],
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 图片加载完成 获取宽高
|
||||
on_load_img(e) {
|
||||
const query = uni.createSelectorQuery();
|
||||
// 选择我们想要的元素
|
||||
query
|
||||
.in(this)
|
||||
.select('.container')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
container_ref_h: res.height,
|
||||
w_scale1: res.height / this.img_width,
|
||||
h_scale1: res.height / this.img_height,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec(); // 执行查询
|
||||
query
|
||||
.in(this)
|
||||
.select('.hot')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
w_scale2: res.width / this.container_ref_h,
|
||||
h_scale2: res.height / this.container_ref_h,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec(); // 执行查询
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.hot {
|
||||
min-height: 20rpx;
|
||||
.hot_box {
|
||||
// background: rgba(42, 148, 255, 0.15);
|
||||
// border: 2rpx dashed rgba(142, 198, 255, 0.5);
|
||||
position: absolute;
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
228
components/diy/img-magic.vue
Normal file
228
components/diy/img-magic.vue
Normal file
@@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<!-- 图片魔方 -->
|
||||
<view class="img-magic" :style="style_container + 'height:' + (form.style_actived == 10 ? '100%' : container_size)">
|
||||
<view class="magic-container wh-auto ht-auto" :style="style_img_container">
|
||||
<view class="pr" :style="outer_style">
|
||||
<!-- 风格3 -->
|
||||
<template v-if="form.style_actived == 2">
|
||||
<view class="flex-row align-c jc-c style-size">
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="three flex-row" :style="img_spacing" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 风格9 -->
|
||||
<template v-else-if="form.style_actived == 8">
|
||||
<view class="flex-row align-c jc-c style-size flex-wrap">
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" :class="['flex-row', { 'style9-top': [0, 1].includes(index), 'style9-bottom': ![0, 1].includes(index) }]" :style="img_spacing" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="form.style_actived == 10">
|
||||
<template v-if="form.limit_size == '0'">
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="cr-main flex-row" :style="img_spacing + selected_style(item)" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto" mode="widthFix" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="cr-main flex-row" :style="img_spacing + selected_style(item) + ';height:' + image_height" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in form.img_magic_list" :key="index" class="cube-selected cr-main flex-row" :style="img_spacing + selected_style(item)" :data-value="item.img_link ? item.img_link.page : ''" @tap="url_event">
|
||||
<view class="wh-auto flex-row" :style="content_img_container">
|
||||
<view class="flex-1" :style="content_img_style_container">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="dis-block wh-auto ht-auto" :mode="img_fit" :style="content_img_radius"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, radius_computer, percentage_count, isEmpty, margin_computer, padding_computer, old_padding, old_margin, border_width } from '@/common/js/common/common.js';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propOuterContainerPadding: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
// 外部样式
|
||||
outer_style: '',
|
||||
// 图片间距设置
|
||||
img_spacing: '',
|
||||
// 图片圆角
|
||||
content_img_radius: '',
|
||||
cube_cell: '',
|
||||
container_size: '',
|
||||
div_width: 0,
|
||||
image_height: '',
|
||||
img_fit: '',
|
||||
content_img_container: '',
|
||||
content_img_style_container: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
// 根据当前页面大小计算成百分比
|
||||
selected_style() {
|
||||
return (item) => {
|
||||
return `overflow: hidden;width: ${this.percentage(this.getSelectedWidth(item))}; height: ${this.percentage(this.getSelectedHeight(item))}; top: ${this.percentage(this.getSelectedTop(item))}; left: ${this.percentage(this.getSelectedLeft(item))};`;
|
||||
};
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const new_style_spacing = new_content.style_actived === 10 ? 0 : new_style.image_spacing;
|
||||
// 外部样式
|
||||
const outer_spacing = `calc(100% + ${new_style_spacing * 2}rpx)`;
|
||||
const outer_sx = `-${new_style_spacing}rpx`;
|
||||
// 图片间距设置
|
||||
const spacing = `${new_style_spacing}rpx`;
|
||||
// scaleToFill 对应 cover aspectFit 对应 contain center 对应 none
|
||||
let fit = '';
|
||||
if (new_content.img_fit == 'contain') {
|
||||
fit = 'aspectFit';
|
||||
} else if (new_content.img_fit == 'fill') {
|
||||
fit = 'scaleToFill';
|
||||
} else if (new_content.img_fit == 'cover') {
|
||||
fit = 'aspectFill';
|
||||
}
|
||||
const container_height = !isEmpty(new_content.container_height) ? new_content.container_height : sys_width;
|
||||
const density = !isEmpty(new_content.magic_cube_density) ? new_content.magic_cube_density : 4;
|
||||
|
||||
const { margin_left, margin_right } = new_style.common_style;
|
||||
const width = sys_width - margin_left - margin_right - border_width(new_style.common_style) - this.propOuterContainerPadding;
|
||||
const scale = width / 390;
|
||||
this.setData({
|
||||
form: this.propValue.content,
|
||||
new_style: this.propValue.style,
|
||||
outer_style: `width:${outer_spacing};height:${outer_spacing};margin:${outer_sx};`,
|
||||
img_spacing: `padding:${spacing};`,
|
||||
content_img_radius: radius_computer(new_style),
|
||||
style_container: common_styles_computer(new_style.common_style) + 'box-sizing: border-box;',
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex) + 'box-sizing: border-box;',
|
||||
img_fit: fit,
|
||||
div_width: sys_width,
|
||||
container_size: container_height * scale + 'px',
|
||||
cube_cell: sys_width / density,
|
||||
image_height: this.propValue.content.image_height * scale + 'px',
|
||||
content_img_container: common_styles_computer(new_style) + margin_computer(new_style?.margin || old_margin) + 'box-sizing: border-box;',
|
||||
content_img_style_container: common_img_computer(new_style) + padding_computer(new_style?.padding || old_padding) + 'box-sizing: border-box;',
|
||||
});
|
||||
},
|
||||
getSelectedWidth(item) {
|
||||
return (item.end.x - item.start.x + 1) * this.cube_cell;
|
||||
},
|
||||
//计算选中层的高度。
|
||||
getSelectedHeight(item) {
|
||||
return (item.end.y - item.start.y + 1) * this.cube_cell;
|
||||
},
|
||||
//计算选中层的右边距离。
|
||||
getSelectedTop(item) {
|
||||
return (item.start.y - 1) * this.cube_cell;
|
||||
},
|
||||
//计算选中层的左边距离。
|
||||
getSelectedLeft(item) {
|
||||
return (item.start.x - 1) * this.cube_cell;
|
||||
},
|
||||
// 计算成百分比
|
||||
percentage(num) {
|
||||
return percentage_count(num, this.div_width);
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 图片魔方是一个正方形,根据宽度计算高度
|
||||
.img-magic {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.cube-selected {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.style-size {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
.three {
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.style9-top {
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.style9-bottom {
|
||||
width: calc(100% / 3);
|
||||
height: 50%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
279
components/diy/modules/custom/data-group-rendering.vue
Normal file
279
components/diy/modules/custom/data-group-rendering.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<view :class="'wh-auto pr allSignList-' + propIndex + propKey" :style="'height:' + propDataHeight * propScale + 'px;'">
|
||||
<view v-for="(item, index) in new_list" :key="index" :data-id="item.id" :data-location-x="item.location.x" :data-location-y="item.location.y" :class="'sign-' + propIndex + propKey + ' main-content ' + get_animation_class(item.com_data)" :style="'left:' + get_percentage_count(item.location.x, item.com_data.data_follow, 'left') + ';top:' + get_percentage_count(item.location.y, item.com_data.data_follow, 'top') + ';width:' + get_percentage_count(item.com_data.com_width, item.com_data.data_follow, 'width', item.com_data.is_width_auto, item.com_data.max_width, item.key) + ';height:' + get_percentage_count(item.com_data.com_height, item.com_data.data_follow, 'height', item.com_data.is_height_auto, item.com_data.max_height, item.key) + ';z-index:' + (new_list.length - 1 > 0 ? (new_list.length - 1) - index : 0)">
|
||||
<template v-if="item.key == 'text'">
|
||||
<model-text :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propTitleParams="propShowData.data_name" @url_event="url_event"></model-text>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'img'">
|
||||
<model-image :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propImgParams="propShowData.data_logo" @url_event="url_event"></model-image>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'auxiliary-line'">
|
||||
<model-lines :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId"></model-lines>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'icon'">
|
||||
<model-icon :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-icon>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'panel'">
|
||||
<model-panel :propKey="propKey" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-panel>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modelText from '@/components/diy/modules/custom/model-text.vue';
|
||||
import modelLines from '@/components/diy/modules/custom/model-lines.vue';
|
||||
import modelImage from '@/components/diy/modules/custom/model-image.vue';
|
||||
import modelIcon from '@/components/diy/modules/custom/model-icon.vue';
|
||||
import modelPanel from '@/components/diy/modules/custom/model-panel.vue';
|
||||
import { location_compute, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
components: {
|
||||
modelText,
|
||||
modelLines,
|
||||
modelImage,
|
||||
modelIcon,
|
||||
modelPanel,
|
||||
},
|
||||
props: {
|
||||
propCustomList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propSourceList: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
propDataHeight: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataSplitIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propShowData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
data_key: 'id',
|
||||
data_name: 'name'
|
||||
}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
new_list: [],
|
||||
custom_width: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
propCustomList(val) {
|
||||
this.init(val);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
get_percentage_count() {
|
||||
return (num, data_follow, type, is_auto = '0', max_size = 0, key = '') => {
|
||||
// 检查类型是否为'left'或'top',如果是,则根据跟随数据计算样式
|
||||
if (['left', 'top'].includes(type)) {
|
||||
const { id = '', type: follow_type = 'left' } = data_follow || { id: '', type: 'left' };
|
||||
// 如果id不为空且follow_type与type匹配,则返回原始值的字符串表示
|
||||
if (id !== '' && follow_type === type) {
|
||||
return `${num}px`;
|
||||
}
|
||||
// 如果条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
} else {
|
||||
// 如果is_auto设置为'1',则根据type和max_size计算自动样式
|
||||
if (is_auto === '1') {
|
||||
if (type === 'width' || type === 'height') {
|
||||
if (typeof max_size === 'number' && max_size >= 0) {
|
||||
const scaledMaxSize = max_size * this.propScale;
|
||||
const autoStyle = 'auto;';
|
||||
const maxSizeStyle = scaledMaxSize > 0 ? ` max-${type}: ${scaledMaxSize}px;` : '';
|
||||
const whiteSpaceStyle = type === 'width' && scaledMaxSize <= 0 ? ' white-space:nowrap;' : '';
|
||||
return `${ autoStyle }${ maxSizeStyle }${ whiteSpaceStyle }`;
|
||||
} else {
|
||||
return 'auto;';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 微信小程序图片等比缩放对小数点后的内容支持的不是特别的好,需要取向上取整数
|
||||
if (key == 'img' && ['width', 'height'].includes(type)) {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${ Math.round(num * this.propScale) }px`;
|
||||
} else {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
get_animation_class() {
|
||||
return (data) => {
|
||||
const { type = 'none', number = 'infinite' } = data?.animation_style || {};
|
||||
if (type != 'none') {
|
||||
return type + (number == 'infinite' ? `-${number}` : '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
methods: {
|
||||
async init(val) {
|
||||
// 如果为空就不进行渲染
|
||||
if (isEmpty(val)) {
|
||||
return;
|
||||
}
|
||||
await this.get_custom_width();
|
||||
this.set_new_list(val);
|
||||
},
|
||||
get_custom_width() {
|
||||
// 获取当前容器的宽度
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('.allSignList-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if (res) {
|
||||
this.setData({
|
||||
custom_width: res.width,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
async set_new_list(val) {
|
||||
// 第一次渲染先渲染全部数据
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
// 判断是否有跟随的数据
|
||||
const follow_list = val.filter(item => item.com_data.data_follow && item.com_data?.data_follow?.id !== '');
|
||||
if (follow_list.length > 0) {
|
||||
// 等待页面渲染完成之后再获取内容
|
||||
await this.$nextTick();
|
||||
// 第二次如果有跟随数据,更新对应数据的内容, 如果有超出容器范围的数据,限制其超出容器范围
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.selectAll('.sign-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((rect) => {
|
||||
if (rect) {
|
||||
// 将返回的内容转成map对象,方便快速查找,节省性能
|
||||
const idMap = new Map(rect.map(item => [item.dataset.id, item]));
|
||||
// 历史数据拷贝,方便后续操作避免每次都更新数据,统一重新渲染
|
||||
const val = JSON.parse(JSON.stringify(this.new_list));
|
||||
val.forEach((item1) => {
|
||||
const { data_follow } = item1.com_data;
|
||||
const targetItem = idMap.get(data_follow?.id);
|
||||
if (targetItem) {
|
||||
const text_item = item1.key == 'text' ? idMap.get((item1?.id || '')+ '') : undefined;
|
||||
if (data_follow?.type === 'left') {
|
||||
// 更新位置信息
|
||||
const location_x = this.updateLocation(targetItem, data_follow, this.propScale, true);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_width = item1.com_data.com_width;
|
||||
// 如果是宽度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data?.is_width_auto === '1' && text_item) {
|
||||
item_width = text_item.width;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.x = location_compute(item_width, location_x, this.custom_width);
|
||||
} else if (data_follow?.type === 'top') {
|
||||
// 更新位置信息
|
||||
const location_y = this.updateLocation(targetItem, data_follow, this.propScale, false);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_height = item1.com_data.com_height;
|
||||
// 如果是高度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data?.is_height_auto === '1' && text_item) {
|
||||
item_height = text_item.height;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.y = location_compute(item_height, location_y, this.propDataHeight * this.propScale);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}
|
||||
},
|
||||
updateLocation(targetItem, data_follow, scale, isX) {
|
||||
try {
|
||||
const locationValueStr = targetItem.dataset[`location${isX ? 'X' : 'Y'}`];
|
||||
if (locationValueStr == null) {
|
||||
return;
|
||||
}
|
||||
const locationValue = parseFloat(locationValueStr);
|
||||
if (isNaN(locationValue) || scale <= 0 || (isX ? targetItem.width < 0 : targetItem.height < 0)) return;
|
||||
|
||||
return ((locationValue + (data_follow?.spacing || 0)) * scale) + (isX ? targetItem.width : targetItem.height);
|
||||
} catch (error) {
|
||||
console.error(`Error updating location ${isX ? 'X' : 'Y'}:`, error);
|
||||
}
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', e, this.propDataIndex, this.propDataSplitIndex);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main-content {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
290
components/diy/modules/custom/data-rendering.vue
Normal file
290
components/diy/modules/custom/data-rendering.vue
Normal file
@@ -0,0 +1,290 @@
|
||||
<template>
|
||||
<view :class="'wh-auto pr allSignList-' + propIndex + propKey" :style="'height:' + propDataHeight * propScale + 'px;'">
|
||||
<view v-for="(item, index) in new_list" :key="index" :data-id="item.id" :data-location-x="item.location.x" :data-location-y="item.location.y" :class="'sign-' + propIndex + propKey + ' main-content ' + get_animation_class(item.com_data)" :style="'left:' + get_percentage_count(item.location.x, item.com_data.data_follow, 'left') + ';top:' + get_percentage_count(item.location.y, item.com_data.data_follow, 'top') + ';width:' + get_percentage_count(item.com_data.com_width, item.com_data.data_follow, 'width', item.com_data.is_width_auto, item.com_data.max_width, item.key) + ';height:' + get_percentage_count(item.com_data.com_height, item.com_data.data_follow, 'height', item.com_data.is_height_auto, item.com_data.max_height, item.key) + ';z-index:' + (new_list.length - 1 > 0 ? (new_list.length - 1) - index : 0)">
|
||||
<template v-if="item.key == 'text'">
|
||||
<model-text :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propTitleParams="propShowData.data_name" @url_event="url_event"></model-text>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'img'">
|
||||
<model-image :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" :propImgParams="propShowData.data_logo" @url_event="url_event"></model-image>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'auxiliary-line'">
|
||||
<model-lines :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId"></model-lines>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'icon'">
|
||||
<model-icon :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-icon>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'panel'">
|
||||
<model-panel :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propSourceList="propSourceList" :propConfigLoop="propConfigLoop" :propIsCustom="propIsCustom" :propIsCustomGroup="propIsCustomGroup" :propCustomGroupFieldId="propCustomGroupFieldId" @url_event="url_event"></model-panel>
|
||||
</template>
|
||||
<template v-else-if="item.key == 'custom-group'">
|
||||
<model-custom-group :propKey="propKey + item.id" :propValue="item.com_data" :propScale="propScale" :propFieldList="propFieldList" :propConfigLoop="propConfigLoop" :propDataWidth="item.com_data.com_width" :propDataHeight="item.com_data.custom_height" :propSourceList="propSourceList" :propGroupSourceList="propGroupSourceList" :propIsCustom="propIsCustom" :propShowData="propShowData"></model-custom-group>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modelText from '@/components/diy/modules/custom/model-text.vue';
|
||||
import modelLines from '@/components/diy/modules/custom/model-lines.vue';
|
||||
import modelImage from '@/components/diy/modules/custom/model-image.vue';
|
||||
import modelIcon from '@/components/diy/modules/custom/model-icon.vue';
|
||||
import modelPanel from '@/components/diy/modules/custom/model-panel.vue';
|
||||
import modelCustomGroup from '@/components/diy/modules/custom/model-custom-group.vue';
|
||||
import { location_compute, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
components: {
|
||||
modelText,
|
||||
modelLines,
|
||||
modelImage,
|
||||
modelIcon,
|
||||
modelPanel,
|
||||
modelCustomGroup
|
||||
},
|
||||
props: {
|
||||
propCustomList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propSourceList: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
propGroupSourceList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propDataHeight: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataSplitIndex: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propShowData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
data_key: 'id',
|
||||
data_name: 'name'
|
||||
}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
new_list: [],
|
||||
custom_width: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
propCustomList(val) {
|
||||
this.init(val);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
get_percentage_count() {
|
||||
return (num, data_follow, type, is_auto = '0', max_size = 0, key = '') => {
|
||||
// 检查类型是否为'left'或'top',如果是,则根据跟随数据计算样式
|
||||
if (['left', 'top'].includes(type)) {
|
||||
const { id = '', type: follow_type = 'left' } = data_follow || { id: '', type: 'left' };
|
||||
// 如果id不为空且follow_type与type匹配,则返回原始值的字符串表示
|
||||
if (id !== '' && follow_type === type) {
|
||||
return `${num}px`;
|
||||
}
|
||||
// 如果条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
} else {
|
||||
// 如果is_auto设置为'1',则根据type和max_size计算自动样式
|
||||
if (is_auto === '1') {
|
||||
if (type === 'width' || type === 'height') {
|
||||
if (typeof max_size === 'number' && max_size >= 0) {
|
||||
const scaledMaxSize = max_size * this.propScale;
|
||||
const autoStyle = 'auto;';
|
||||
const maxSizeStyle = scaledMaxSize > 0 ? ` max-${type}: ${scaledMaxSize}px;` : '';
|
||||
const whiteSpaceStyle = type === 'width' && scaledMaxSize <= 0 ? ' white-space:nowrap;' : '';
|
||||
return `${ autoStyle }${ maxSizeStyle }${ whiteSpaceStyle }`;
|
||||
} else {
|
||||
return 'auto;';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 微信小程序图片等比缩放对小数点后的内容支持的不是特别的好,需要取向上取整数
|
||||
if (key == 'img' && ['width', 'height'].includes(type)) {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${ Math.round(num * this.propScale) }px`;
|
||||
} else {
|
||||
// 如果is_auto未设置或条件不满足,则根据比例缩放num并返回
|
||||
return `${num * this.propScale}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
get_animation_class() {
|
||||
return (data) => {
|
||||
const { type = 'none', number = 'infinite' } = data?.animation_style || {};
|
||||
if (type != 'none') {
|
||||
return type + (number == 'infinite' ? `-${number}` : '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init(this.propCustomList);
|
||||
},
|
||||
methods: {
|
||||
async init(val) {
|
||||
// 如果为空就不进行渲染
|
||||
if (isEmpty(val)) {
|
||||
return;
|
||||
}
|
||||
await this.get_custom_width();
|
||||
this.set_new_list(val);
|
||||
},
|
||||
get_custom_width() {
|
||||
// 获取当前容器的宽度
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('.allSignList-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if (res) {
|
||||
this.setData({
|
||||
custom_width: res.width,
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
async set_new_list(val) {
|
||||
// 第一次渲染先渲染全部数据
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
// 判断是否有跟随的数据
|
||||
const follow_list = val.filter(item => item.com_data.data_follow && item.com_data?.data_follow?.id !== '');
|
||||
if (follow_list.length > 0) {
|
||||
await this.$nextTick();
|
||||
// 第二次如果有跟随数据,更新对应数据的内容, 如果有超出容器范围的数据,限制其超出容器范围
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.selectAll('.sign-' + this.propIndex + this.propKey)
|
||||
.boundingClientRect((rect) => {
|
||||
if (rect) {
|
||||
// 将返回的内容转成map对象,方便快速查找,节省性能
|
||||
const idMap = new Map(rect.map(item => [item.dataset.id, item]));
|
||||
// 历史数据拷贝,方便后续操作避免每次都更新数据,统一重新渲染
|
||||
const val = JSON.parse(JSON.stringify(this.new_list));
|
||||
val.forEach((item1) => {
|
||||
const { data_follow } = item1.com_data;
|
||||
const targetItem = idMap.get(data_follow?.id);
|
||||
if (targetItem) {
|
||||
const text_item = item1.key == 'text' ? idMap.get((item1?.id || '')+ '') : undefined;
|
||||
if (data_follow?.type === 'left') {
|
||||
// 更新位置信息
|
||||
const location_x = this.updateLocation(targetItem, data_follow, this.propScale, true);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_width = item1.com_data.com_width;
|
||||
// 如果是宽度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data.is_width_auto === '1' && text_item) {
|
||||
item_width = text_item.width;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.x = location_compute(item_width, location_x, this.custom_width);
|
||||
} else if (data_follow?.type === 'top') {
|
||||
// 更新位置信息
|
||||
const location_y = this.updateLocation(targetItem, data_follow, this.propScale, false);
|
||||
// 获取组件的宽度,如果是宽度自适应,则需要重新计算位置
|
||||
let item_height = item1.com_data.com_height;
|
||||
// 如果是高度自适应,需要重新判断一下处理逻辑
|
||||
if (item1.com_data?.is_height_auto === '1' && text_item) {
|
||||
item_height = text_item.height;
|
||||
}
|
||||
// 根据容器信息更新位置信息
|
||||
item1.location.y = location_compute(item_height, location_y, this.propDataHeight * this.propScale);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
new_list: val
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}
|
||||
},
|
||||
updateLocation(targetItem, data_follow, scale, isX) {
|
||||
try {
|
||||
const locationValueStr = targetItem.dataset[`location${isX ? 'X' : 'Y'}`];
|
||||
if (locationValueStr == null) {
|
||||
return;
|
||||
}
|
||||
const locationValue = parseFloat(locationValueStr);
|
||||
if (isNaN(locationValue) || scale <= 0 || (isX ? targetItem.width < 0 : targetItem.height < 0)) return;
|
||||
|
||||
const computedValue = ((locationValue + (data_follow?.spacing || 0)) * scale) + (isX ? targetItem.width : targetItem.height);
|
||||
return computedValue;
|
||||
} catch (error) {
|
||||
console.error(`Error updating location ${isX ? 'X' : 'Y'}:`, error);
|
||||
}
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', e, this.propDataIndex, this.propDataSplitIndex);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main-content {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
378
components/diy/modules/custom/model-custom-group.vue
Normal file
378
components/diy/modules/custom/model-custom-group.vue
Normal file
@@ -0,0 +1,378 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="ht-auto" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view :style="style_content_container">
|
||||
<view class="w h pr" :style="style_content_img_container">
|
||||
<template v-if="data_source_content_list.length > 0 && form.data_source_direction == 'vertical'">
|
||||
<view class="flex-row flex-wrap" :style="'row-gap:' + new_style.row_gap + 'px;column-gap:' + new_style.column_gap + 'px;'">
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" class="ht-auto" :style="gap_width">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1">
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataGroupRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propFieldList="propFieldList" :propDataHeight="propDataHeight" :propScale="custom_scale" :propIsCustom="propIsCustom" :propIsCustomGroup="true" :propShowData="propShowData" :propConfigLoop="propConfigLoop !== '1' ? form.is_use_parent_data : '1'" :propDataIndex="index" :propDataSplitIndex="index1" @url_event="url_event"></dataGroupRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else-if="data_source_content_list.length > 0 && ['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" class="oh ht-auto">
|
||||
<swiper class="w flex" circular="true" :vertical="form.data_source_direction != 'horizontal'" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_view" :style="{ width: '100%', height: swiper_height + 'px' }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in data_source_content_list" :key="index">
|
||||
<view :class="form.data_source_direction != 'horizontal' ? 'wh-auto ht-auto' : 'flex-row'" :style="form.data_source_direction == 'horizontal' ? 'column-gap:' + new_style.column_gap + 'px;' : ''">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" class="wh-auto ht-auto" :style="style_chunk_container + swiper_width + (form.data_source_direction == 'horizontal' ? gap_width : 'margin-bottom:' + content_outer_spacing_magin)">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataGroupRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propFieldList="propFieldList" :propDataHeight="propDataHeight" :propScale="custom_scale" :propIsCustom="propIsCustom" :propIsCustomGroup="true" :propShowData="propShowData" :propConfigLoop="propConfigLoop !== '1' ? form.is_use_parent_data : '1'" :propDataIndex="index" :propDataSplitIndex="index1" @url_event="url_event"></dataGroupRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="new_style.is_show == '1' && data_source_content_list.length > 1" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<block v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ data_source_content_list.length }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" :style="indicator_style + (actived_index == index ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<template v-else>
|
||||
<view :style="style_chunk_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_chunk_img_container">
|
||||
<dataGroupRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propFieldList="propFieldList" :propDataHeight="propDataHeight" :propScale="custom_scale" :propConfigLoop="propConfigLoop !== '1' ? form.is_use_parent_data : '1'" @url_event="url_event"></dataGroupRendering>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer, percentage_count, isEmpty, get_indicator_style, get_indicator_location_style, border_width, get_is_eligible } from '@/common/js/common/common.js';
|
||||
// a组件调用b组件 b组件调用a组件,为了避免循环引用在uniapp中出问题,复制一个相同的data-group-rendering组件
|
||||
import dataGroupRendering from '@/components/diy/modules/custom/data-group-rendering.vue';
|
||||
const app = getApp();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dataGroupRendering
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propDataWidth: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propDataHeight: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propGroupSourceList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
propShowData: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
data_key: 'id',
|
||||
data_name: 'name',
|
||||
})
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
custom_scale: 1,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
custom_list_length: 0,
|
||||
custom_group_field_id: '',
|
||||
source_list: {
|
||||
// 存放手动输入的id
|
||||
data_ids: [],
|
||||
// 手动输入
|
||||
data_list: [],
|
||||
// 自动
|
||||
data_auto_list: [],
|
||||
},
|
||||
data_source_content_list: [],
|
||||
data_source: '',
|
||||
// 内容样式
|
||||
style_content_container: '',
|
||||
style_content_img_container: '',
|
||||
// 数据样式
|
||||
style_chunk_container: '',
|
||||
style_chunk_img_container: '',
|
||||
// 指示器选中的下标
|
||||
actived_index: 0,
|
||||
// 轮播高度
|
||||
swiper_height: 0,
|
||||
swiper_width: 'width: 100%;',
|
||||
// 指示器样式
|
||||
indicator_location_style: '',
|
||||
indicator_style: '',
|
||||
slides_per_view: 1,
|
||||
show_data: { data_key: 'id', data_name: 'name' },
|
||||
old_data_style: {
|
||||
color_list: [{ color: 'rgb(244, 252, 255)', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
content_outer_spacing_magin: '0rpx',
|
||||
gap_width: '',
|
||||
is_show: true
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
percentage_count,
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
const new_style = this.propValue.data_style;
|
||||
const data_source_id = new_form?.data_source_field?.id || '';
|
||||
// 自定义组的数据源内容切换, 判断是取自定义组数据源内容还是取自定义数据源内容
|
||||
const is_data_source_id = this.propFieldList.filter((item) => item.field == data_source_id);
|
||||
let new_list = [];
|
||||
// 判断是否是循环内容
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 如果自定义组选择了数据源,就按照自定义组的数据源的方式走,否则的话就按照自定义的数据走
|
||||
if (is_data_source_id.length > 0) {
|
||||
const list = this.get_data_source_content_list(this.propSourceList, new_form);
|
||||
// 数据来源的内容
|
||||
new_list = list.length > 0 ? this.get_list(list, new_form, new_style) : [];
|
||||
} else {
|
||||
if (!isEmpty(this.propSourceList)) {
|
||||
const new_source_list = [ this.propSourceList ];
|
||||
new_list = [{ split_list: new_source_list }];
|
||||
} else {
|
||||
new_list = [];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果使用父级数据,就直接使用父级的全部数据,否则的话就没有任何数据
|
||||
if (new_form.is_use_parent_data == '1') {
|
||||
new_list = this.propGroupSourceList;
|
||||
} else {
|
||||
new_list = [];
|
||||
}
|
||||
}
|
||||
// 初始化数据
|
||||
const { common_style, data_content_style, data_style } = new_style;
|
||||
const old_width = this.propDataWidth * this.propScale;
|
||||
// 外层左右间距
|
||||
const outer_spacing = (common_style?.margin_left || 0) + (common_style?.margin_right || 0) + (common_style?.padding_left || 0) + (common_style?.padding_right || 0) + border_width(common_style);
|
||||
// 内容左右间距
|
||||
const content_spacing = (data_content_style?.margin_left || 0) + (data_content_style?.margin_right || 0) + (data_content_style?.padding_left || 0) + (data_content_style?.padding_right || 0) + border_width(data_content_style);
|
||||
// 数据左右间距
|
||||
const internal_spacing = (data_style?.margin_left || 0) + (data_style?.margin_right || 0) + (data_style?.padding_left || 0) + (data_style?.padding_right || 0) + border_width(data_style);
|
||||
// 一行显示的数量
|
||||
const carousel_col = Number(new_form.data_source_carousel_col);
|
||||
// 数据间距
|
||||
const data_spacing = ['vertical', 'horizontal'].includes(new_form.data_source_direction) ? new_style.column_gap * (carousel_col - 1) : 0;
|
||||
// 自定义组件宽度
|
||||
const width = old_width - outer_spacing - content_spacing - internal_spacing - data_spacing;
|
||||
// 自定义组的比例
|
||||
const scale_number = width / this.propDataWidth;
|
||||
const custom_scale = scale_number > 0 ? scale_number : 0;
|
||||
const new_data_style = !isEmpty(new_style.data_style) ? new_style.data_style : this.old_data_style;
|
||||
const new_data_content_style = !isEmpty(new_style.data_content_style)? new_style.data_content_style : this.old_data_style;
|
||||
// 判断是平移还是整屏滚动
|
||||
const { padding_top = 0, padding_bottom = 0, margin_bottom = 0, margin_top = 0 } = new_data_style;
|
||||
let swiper_height = 0;
|
||||
let col = Number(new_form.data_source_carousel_col);
|
||||
// 间距
|
||||
const space_between = new_form.data_source_direction == 'horizontal' ? new_style.column_gap : new_style.row_gap;
|
||||
// 轮播图高度控制
|
||||
if (new_form.data_source_direction == 'horizontal') {
|
||||
swiper_height = this.propDataHeight * custom_scale + padding_top + padding_bottom + margin_bottom + margin_top;
|
||||
} else {
|
||||
// 商品数量大于列数的时候,高度是列数,否则是当前的数量
|
||||
col = new_list.length > carousel_col ? carousel_col : new_list.length;
|
||||
swiper_height = (this.propDataHeight * custom_scale + padding_top + padding_bottom + margin_bottom + margin_top) * col + ((Number(new_form.data_source_carousel_col) - 1) * space_between);
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.column_gap * (carousel_col - 1)) / carousel_col;
|
||||
// 横向的时候,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
const swiper_width = (new_form.data_source_direction == 'horizontal' && new_style.rolling_fashion != 'translation') ? `width: ${ 100 / carousel_col }%;`: 'width: 100%;';
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
custom_scale: custom_scale,
|
||||
custom_list_length: new_form.custom_list.length - 1,
|
||||
style_container: common_styles_computer(new_style.common_style) + (new_form.is_scroll_bar == '1' ? 'overflow: auto;' : '') + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
style_content_container: common_styles_computer(new_data_content_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_content_img_container: common_img_computer(new_data_content_style),
|
||||
style_chunk_container: common_styles_computer(new_data_style) + 'box-sizing: border-box;', // 用于样式显示
|
||||
style_chunk_img_container: common_img_computer(new_data_style),
|
||||
style_chunk_width: width,
|
||||
data_source_content_list: new_list,
|
||||
data_source: !isEmpty(new_form.data_source)? new_form.data_source : '',
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style),
|
||||
swiper_height: swiper_height,
|
||||
swiper_width: swiper_width,
|
||||
content_outer_spacing_magin: space_between + 'px',
|
||||
gap_width: `width: calc(${100 / carousel_col}% - ${gap}px);`,
|
||||
slides_per_view: new_style.rolling_fashion == 'translation' ? (new_form.data_source_direction != 'horizontal' ? col : new_form.data_source_carousel_col ) : 1,
|
||||
is_show: this.get_is_show(new_form),
|
||||
custom_group_field_id: new_form.data_source_field.id,
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, false, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_data_source_content_list(sourceList, form) {
|
||||
if (!isEmpty(sourceList)) {
|
||||
const data_source_id = form?.data_source_field.id || '';
|
||||
let list = this.get_nested_property(sourceList, data_source_id);
|
||||
// 如果是自定义标题,进一步处理嵌套对象中的数据
|
||||
if (sourceList.data) {
|
||||
list = this.get_nested_property(sourceList.data, data_source_id);
|
||||
}
|
||||
return list == '' ? [] : list;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
get_nested_property(obj, path) {
|
||||
// 检查路径参数是否为字符串且非空,若不满足条件则返回空字符串
|
||||
if (typeof path !== 'string' || !path) return [];
|
||||
// 将属性路径字符串拆分为属性键数组
|
||||
const keys = path.split('.');
|
||||
// 使用reduce方法遍历属性键数组,逐层访问对象属性
|
||||
// 如果当前对象存在且拥有下一个属性键,则继续访问;否则返回空字符串
|
||||
return keys.reduce((o, key) => (o != null && o[key] != null ? o[key] : []), obj) ?? [];
|
||||
},
|
||||
get_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation' && form.data_source_direction != 'vertical') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.data_source_carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.setData({
|
||||
actived_index: e.detail.current,
|
||||
});
|
||||
},
|
||||
url_event(e, index, split_index) {
|
||||
if (this.data_source == 'goods' && this.data_source_content_list.length > 0) {
|
||||
const list = this.data_source_content_list[index];
|
||||
if (!isEmpty(list) && !isEmpty(list.split_list[split_index])) {
|
||||
const new_list = list.split_list[split_index];
|
||||
if (!isEmpty(new_list)) {
|
||||
// 缓存商品数据
|
||||
app.globalData.goods_data_cache_handle(new_list.data.id, new_list.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
app.globalData.url_open(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
161
components/diy/modules/custom/model-icon.vue
Normal file
161
components/diy/modules/custom/model-icon.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="img-outer pr oh flex-row align-c wh-auto ht-auto" :style="com_style" @tap="url_event">
|
||||
<iconfont :name="'icon-' + icon_class" :color="form.icon_color" :size="form.icon_size * scale + 'px'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { radius_computer, padding_computer, gradient_handle, isEmpty, get_nested_property, get_custom_link, get_is_eligible } from '@/common/js/common/common.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
com_style: '',
|
||||
scale: 1,
|
||||
icon_class: '',
|
||||
icon_url: '',
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
let icon_class_value = '';
|
||||
if (!isEmpty(new_form.icon_class)) {
|
||||
icon_class_value = new_form.icon_class;
|
||||
} else {
|
||||
if (!isEmpty(this.propSourceList)) {
|
||||
let icon = '';
|
||||
// 获取数据源ID
|
||||
const data_source_id = !isEmpty(new_form?.data_source_field?.id || '') && this.propConfigLoop == '1' ? new_form.data_source_field.id : '';
|
||||
// 数据源内容
|
||||
const option = new_form?.data_source_field?.option || {};
|
||||
if (data_source_id.includes(';')) {
|
||||
const ids = data_source_id.split(';');
|
||||
let url = '';
|
||||
ids.forEach((item, index) => {
|
||||
url += this.data_handling(item) + (index != ids.length - 1 ? (option?.join || '') : '');
|
||||
});
|
||||
icon = url;
|
||||
} else {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
icon = this.data_handling(data_source_id);
|
||||
}
|
||||
icon_class_value = (option?.first || '') + icon + (option?.last || '');
|
||||
} else {
|
||||
icon_class_value = '';
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
scale: this.propScale,
|
||||
com_style: this.get_com_style(new_form, this.propScale),
|
||||
icon_class: icon_class_value,
|
||||
icon_url: this.get_icon_link(new_form),
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_icon_link(new_form) {
|
||||
let url = '';
|
||||
if (!isEmpty(new_form.icon_link)) {
|
||||
url = new_form.icon_link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(new_form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? new_form?.data_source_link_field?.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = new_form?.data_source_link_field?.option || {};
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option)
|
||||
}
|
||||
return url;
|
||||
},
|
||||
data_handling(data_source_id) {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
let icon = get_nested_property(this.propSourceList, data_source_id);
|
||||
// 如果是商品,品牌,文章的图片, 其他的切换为从data中取数据
|
||||
if (this.propIsCustom && !isEmpty(this.propSourceList.data)) {
|
||||
icon = get_nested_property(this.propSourceList.data, data_source_id);
|
||||
}
|
||||
return icon;
|
||||
},
|
||||
get_com_style(form, scale) {
|
||||
let style = `${ gradient_handle(form.color_list, form.direction) } ${ radius_computer(form.bg_radius, scale, true) };transform: rotate(${form.icon_rotate}deg);${ padding_computer(form.icon_padding, scale, true) };`;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color};box-sizing: border-box;`;
|
||||
}
|
||||
if (form.icon_location == 'center') {
|
||||
style += `justify-content: center;`;
|
||||
} else if (form.icon_location == 'left') {
|
||||
style += `justify-content: flex-start;`;
|
||||
} else if (form.icon_location == 'right') {
|
||||
style += `justify-content: flex-end;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.icon_url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
178
components/diy/modules/custom/model-image.vue
Normal file
178
components/diy/modules/custom/model-image.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="img-outer pr wh-auto ht-auto" :style="border_style" @tap="url_event">
|
||||
<imageEmpty :propImageSrc="img" :propStyle="image_style" propErrorStyle="width: 60rpx;height: 60rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { percentage_count, radius_computer, isEmpty, get_nested_property, get_custom_link, get_is_eligible } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propImgParams: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
img: '',
|
||||
img_url: '',
|
||||
image_style: '',
|
||||
border_style: '',
|
||||
keyMap: {
|
||||
goods: 'images',
|
||||
article: 'cover',
|
||||
brand: 'logo'
|
||||
},
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
img: this.get_img_url(new_form),
|
||||
image_style: this.get_image_style(new_form, this.propScale),
|
||||
border_style: this.get_border_style(new_form, this.propScale),
|
||||
img_url: this.get_img_link(new_form),
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_img_link(form) {
|
||||
let url = '';
|
||||
if (!isEmpty(form.link)) {
|
||||
url = form.link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? form.data_source_link_field.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = form?.data_source_link_field?.option || {};
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option)
|
||||
}
|
||||
return url;
|
||||
},
|
||||
get_img_url(form) {
|
||||
if (!isEmpty(form.img[0])) {
|
||||
return form.img[0];
|
||||
} else {
|
||||
if (!isEmpty(this.propSourceList)) {
|
||||
let image_url = '';
|
||||
// 获取数据源ID
|
||||
const data_source_id = !isEmpty(form?.data_source_field?.id || '') && this.propConfigLoop == '1' ? form.data_source_field.id : '';
|
||||
// 数据源内容
|
||||
const option = form?.data_source_field?.option || {};
|
||||
if (data_source_id.includes(';')) {
|
||||
const ids = data_source_id.split(';');
|
||||
let url = '';
|
||||
ids.forEach((item, index) => {
|
||||
url += this.data_handling(item) + (index != ids.length - 1 ? (option?.join || '') : '');
|
||||
});
|
||||
image_url = url;
|
||||
} else {
|
||||
image_url = this.data_handling(data_source_id);
|
||||
}
|
||||
return (option?.first || '') + image_url + (option?.last || '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
data_handling(data_source_id) {
|
||||
// 不输入商品, 文章和品牌时,从外层处理数据
|
||||
let image_url = get_nested_property(this.propSourceList, data_source_id);
|
||||
// 如果是商品,品牌,文章的图片, 其他的切换为从data中取数据
|
||||
if (this.propIsCustom && !isEmpty(this.propSourceList.data)) {
|
||||
// 判断是否是同一标志
|
||||
if (data_source_id == this.propImgParams) {
|
||||
// 如果是符合条件的标志,先判断新的图片是否存在,存在就取新的图片,否则的话取原来的图片
|
||||
image_url = !isEmpty(this.propSourceList.new_cover)? this.propSourceList.new_cover[0]?.url || '' : get_nested_property(this.propSourceList.data, data_source_id);
|
||||
} else {
|
||||
image_url = get_nested_property(this.propSourceList.data, data_source_id);
|
||||
}
|
||||
}
|
||||
return image_url;
|
||||
},
|
||||
get_image_style(form, scale) {
|
||||
return `width: ${percentage_count(form.img_width, form.com_width)}; height: ${percentage_count(form.img_height, form.com_height)};transform: rotate(${form.img_rotate}deg); ${radius_computer(form.img_radius, scale, true)};`;
|
||||
},
|
||||
get_border_style(form, scale) {
|
||||
let style = ``;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color}; ${radius_computer(form.border_radius, scale, true)};box-sizing: border-box;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.img_url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.img-outer {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
94
components/diy/modules/custom/model-lines.vue
Normal file
94
components/diy/modules/custom/model-lines.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<view v-if="is_show" :style="border_style"></view>
|
||||
</template>
|
||||
<script>
|
||||
import { get_is_eligible } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
border_style: '',
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
border_style: this.get_border_style(new_form, this.propScale),
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_border_style(form, scale) {
|
||||
if (form.line_settings === 'horizontal') {
|
||||
return `margin: 10rpx 0;border-bottom: ${form.line_size * scale }px ${form.line_style} ${form.line_color};`;
|
||||
} else {
|
||||
return `margin: 0 10rpx;height:100%;border-right: ${form.line_size * scale }px ${form.line_style} ${form.line_color};`;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
133
components/diy/modules/custom/model-panel.vue
Normal file
133
components/diy/modules/custom/model-panel.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="wh-auto ht-auto re oh" :style="com_style" @tap="url_event">
|
||||
<view class="wh-auto ht-auto" :style="com_img_style"></view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { radius_computer, background_computer, gradient_handle, isEmpty, get_custom_link, get_is_eligible } from '@/common/js/common/common.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
text_title: '',
|
||||
text_style: '',
|
||||
com_style: '',
|
||||
panel_url: '',
|
||||
is_show: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
let url = '';
|
||||
if (!isEmpty(new_form.link)) {
|
||||
url = new_form.link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(new_form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? new_form.data_source_link_field.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = new_form?.data_source_link_field?.option || {};
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option);
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
com_style: this.get_com_style(new_form, this.propScale),
|
||||
com_img_style: this.get_com_img_style(new_form),
|
||||
panel_url: url,
|
||||
is_show: this.get_is_show(new_form),
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_com_style(form, scale) {
|
||||
let style = `${ gradient_handle(form.color_list, form.direction) } ${radius_computer(form.bg_radius, scale, true)}; transform: rotate(${form.panel_rotate}deg);`;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color};box-sizing: border-box;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
get_com_img_style(form) {
|
||||
const data = {
|
||||
background_img: form?.background_img || [],
|
||||
background_img_style: form?.background_img_style || '2'
|
||||
}
|
||||
return background_computer(data);
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.panel_url);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.break {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
.rich-text-content {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
* {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
236
components/diy/modules/custom/model-text.vue
Normal file
236
components/diy/modules/custom/model-text.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<view v-if="is_show" class="img-outer wh-auto ht-auto re oh" :style="com_style" @tap="url_event">
|
||||
<view :style="text_style" :class="'break ' + text_line_class">
|
||||
<template v-if="form.is_rich_text == '1'">
|
||||
<mp-html :content="text_title" />
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ text_title }}
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import { radius_computer, padding_computer, isEmpty, gradient_handle, get_nested_property, get_custom_link, get_is_eligible, custom_condition_data } from '@/common/js/common/common.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
propSourceList: {
|
||||
type: [ Object, Array ],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
propScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
propIsCustom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsCustomGroup: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCustomGroupFieldId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propTitleParams: {
|
||||
type: String,
|
||||
default: 'name'
|
||||
},
|
||||
propFieldList: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
propConfigLoop: {
|
||||
type: String,
|
||||
default: "1"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
text_title: '',
|
||||
text_style: '',
|
||||
com_style: '',
|
||||
text_url: '',
|
||||
keyMap: {
|
||||
goods: 'title',
|
||||
article: 'title',
|
||||
brand: 'name'
|
||||
},
|
||||
is_show: true,
|
||||
text_line_class: ''
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_form = this.propValue;
|
||||
let url = '';
|
||||
if (!isEmpty(new_form.text_link)) {
|
||||
url = new_form.text_link?.page || '';
|
||||
} else {
|
||||
// 获取数据源ID
|
||||
const data_source_link_id = !isEmpty(new_form?.data_source_link_field?.id || '') && this.propConfigLoop == '1' ? new_form.data_source_link_field.id : '';
|
||||
// 数据源内容
|
||||
const source_link_option = new_form?.data_source_link_field?.option || {};
|
||||
// 调用方法处理数据显示
|
||||
url = get_custom_link(data_source_link_id, this.propSourceList, source_link_option);
|
||||
}
|
||||
this.setData({
|
||||
form: new_form,
|
||||
text_title: (new_form?.text_captions || '') + this.get_text_title(new_form),
|
||||
text_style: this.get_text_style(new_form, this.propScale),
|
||||
com_style: this.get_com_style(new_form, this.propScale),
|
||||
text_url: url,
|
||||
is_show: this.get_is_show(new_form),
|
||||
text_line_class: new_form.width_omit_num == '0' || new_form.is_rich_text == '1' ? '' : `text-line-${ new_form?.width_omit_num || '' }`
|
||||
});
|
||||
},
|
||||
get_is_show(form) {
|
||||
if (this.propConfigLoop == '1') {
|
||||
// 取出条件判断的内容
|
||||
const condition = form?.condition || { field: '', type: '', value: '' };
|
||||
return get_is_eligible(this.propFieldList, condition, this.propSourceList, this.propIsCustom, this.propIsCustomGroup, this.propCustomGroupFieldId);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
get_text_title(form) {
|
||||
let text = '';
|
||||
if (!isEmpty(form.text_title)) {
|
||||
// 存储待处理的文本标题
|
||||
let new_title = JSON.parse(JSON.stringify((form.text_title)));
|
||||
let new_field_list = this.propFieldList;
|
||||
// 判断是否是自定义组
|
||||
if (this.propIsCustomGroup && !isEmpty(this.propCustomGroupFieldId)) {
|
||||
// 取出对应自定义组的内容
|
||||
const group_option_list = new_field_list.find((item) => item.field === this.propCustomGroupFieldId);
|
||||
// 取出自定义组内部数据源参数的详细数据
|
||||
new_field_list = group_option_list?.data || [];
|
||||
}
|
||||
// 遍历字段列表,替换文本标题中的占位符
|
||||
if (!isEmpty(new_field_list)) {
|
||||
new_field_list.forEach((item) => {
|
||||
const new_field = '${' + item.field + '}';
|
||||
if (form.text_title.includes(new_field)) {
|
||||
// 获取到字段的真实数据
|
||||
const field_value = custom_condition_data(item.field, item, this.propSourceList, this.propIsCustom);
|
||||
// 使用正则表达式替换文本标题
|
||||
const regular = new RegExp(`\\$\\{\\s*${item.field}\\s*\\}`, 'g');
|
||||
// 替换后的内容赋值给原内容, 确保后续可以继续替换
|
||||
new_title = new_title.replace(regular, field_value);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 将内容替换为处理后的标题
|
||||
text = new_title;
|
||||
} else {
|
||||
let text_title = '';
|
||||
// 获取数据源ID
|
||||
const data_source_id = !isEmpty(form?.data_source_field?.id || []) && this.propConfigLoop == '1' ? form?.data_source_field?.id : [];
|
||||
// 数据源内容
|
||||
const option = form?.data_source_field?.option || [];
|
||||
// 多选判断
|
||||
if (data_source_id.length > 0) {
|
||||
text_title += form?.data_split?.left || '';
|
||||
// 遍历取出所有的值
|
||||
data_source_id.forEach((source_id, index) => {
|
||||
const sourceList = option.find((item) => item.field == source_id);
|
||||
// 根据数据源ID是否包含点号来区分处理方式
|
||||
if (source_id.includes(';')) {
|
||||
const ids = source_id.split(';');
|
||||
let source_text = '';
|
||||
ids.forEach((item, index) => {
|
||||
source_text += this.data_handling(item) + (index != ids.length - 1 ? (sourceList?.join || '') : '');
|
||||
});
|
||||
text_title += (sourceList?.first || '') + source_text + (sourceList?.last || '');
|
||||
} else {
|
||||
text_title += (sourceList?.first || '') + this.data_handling(source_id) + (sourceList?.last || '');
|
||||
}
|
||||
if (index < data_source_id.length - 1) {
|
||||
text_title += form?.data_split?.middle || '';
|
||||
}
|
||||
});
|
||||
text_title += form?.data_split?.right || '';
|
||||
}
|
||||
// 如果是商品的标题或者是品牌的名称,需要判断是否有新的标题,没有的话就取原来的标题
|
||||
text = text_title;
|
||||
}
|
||||
return text;
|
||||
},
|
||||
data_handling(data_source_id) {
|
||||
let text = get_nested_property(this.propSourceList, data_source_id);
|
||||
// 如果是商品的标题或者是品牌的名称,需要判断是否有新的标题,没有的话就取原来的标题
|
||||
if (this.propIsCustom && !isEmpty(this.propSourceList.data)) {
|
||||
// 其他的切换为从data中取数据
|
||||
if (data_source_id == this.propTitleParams) {
|
||||
// 如果是符合条件的标志,先判断新的标题是否存在,存在就取新的标题,否则的话取原来的标题
|
||||
text = !isEmpty(this.propSourceList.new_title) ? this.propSourceList.new_title : get_nested_property(this.propSourceList.data, data_source_id);
|
||||
} else {
|
||||
text = get_nested_property(this.propSourceList.data, data_source_id);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
},
|
||||
get_text_style(form, scale) {
|
||||
let style = `font-size: ${form.text_size * scale }px;line-height: ${ (typeof form.line_text_size === "number" ? form.line_text_size : form.text_size) * scale }px;color: ${form.text_color}; text-align: ${form.text_location}; transform: rotate(${form.text_rotate}deg);text-decoration: ${form.text_option};${padding_computer(form.text_padding, scale, true)};box-sizing: border-box;`;
|
||||
if (form.text_weight == 'italic') {
|
||||
style += `font-style: italic`;
|
||||
} else if (['bold', '500'].includes(form.text_weight)) {
|
||||
style += `font-weight: bold;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
get_com_style(form, scale) {
|
||||
let style = `${ gradient_handle(form.color_list, form.direction) } ${radius_computer(form.bg_radius, scale, true)}`;
|
||||
if (form.border_show == '1') {
|
||||
style += `border: ${form.border_size * scale }px ${form.border_style} ${form.border_color};box-sizing: border-box;`;
|
||||
}
|
||||
// 是富文本并且开启了上下滚动的开关
|
||||
if (form.is_rich_text == '1' && form.is_up_down == '1') {
|
||||
style += `overflow-y: auto;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
url_event(e) {
|
||||
this.$emit('url_event', this.text_url)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.break {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
.rich-text-content {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
* {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
304
components/diy/modules/data-magic/custom/index.vue
Normal file
304
components/diy/modules/data-magic/custom/index.vue
Normal file
@@ -0,0 +1,304 @@
|
||||
<template>
|
||||
<view :style="style_content_container">
|
||||
<view :style="style_content_img_container">
|
||||
<template v-if="!isEmpty(form.data_source) && form.data_source_is_loop !== '0'">
|
||||
<view v-if="data_source_content_list.length > 0 && form.data_source_direction == 'vertical'">
|
||||
<view class="flex-row flex-wrap" :style="'row-gap:' + new_style.row_gap + 'px;column-gap:' + new_style.column_gap + 'px;'">
|
||||
<view v-for="(item, index) in data_source_content_list" :key="index" class="ht-auto" :style="gap_width">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1">
|
||||
<view :style="style_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propSourceType="form.data_source" :propDataHeight="form.height" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="data_source_content_list.length > 0 && ['vertical-scroll', 'horizontal'].includes(form.data_source_direction)" class="oh pr">
|
||||
<swiper class="w flex" circular="true" :vertical="form.data_source_direction != 'horizontal'" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_view" :style="{ width: '100%', height: swiper_height + 'px' }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in data_source_content_list" :key="index">
|
||||
<view :class="form.data_source_direction != 'horizontal' ? '' : 'flex-row'" :style="form.data_source_direction == 'horizontal' ? 'column-gap:' + new_style.column_gap + 'px;' : ''">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" :style="style_container + swiper_width + (form.data_source_direction == 'horizontal' ? gap_width : 'margin-bottom:' + content_outer_spacing_magin)">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="index1" :propSourceList="item1" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propSourceType="form.data_source" :propDataHeight="form.height" :propScale="scale" :propDataIndex="index" :propDataSplitIndex="index1" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view :style="style_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else-if="!isEmpty(form.data_source) && form.data_source_is_loop == '0'">
|
||||
<view :style="style_container">
|
||||
<view class="w h oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propSourceList="{}" :propConfigLoop="form.data_source_is_loop || '1'" :propGroupSourceList="data_source_content_list" :propSourceType="form.data_source" :propDataHeight="form.height" :propScale="scale" :propIsCustom="form.is_custom_data == '1'" :propShowData="show_data" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<view :style="style_container">
|
||||
<view class="wh-auto ht-auto oh" :style="style_img_container">
|
||||
<dataRendering :propKey="propKey" :propCustomList="form.custom_list" :propIndex="0" :propConfigLoop="form.data_source_is_loop || '1'" :propDataHeight="form.height" :propScale="scale" @url_event="url_event"></dataRendering>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { padding_computer, isEmpty, margin_computer, gradient_computer, radius_computer, background_computer, common_styles_computer, common_img_computer, border_width, box_shadow_computer, border_computer, old_border_and_box_shadow, old_margin, old_padding, old_radius } from '@/common/js/common/common.js';
|
||||
import dataRendering from '@/components/diy/modules/custom/data-rendering.vue';
|
||||
const app = getApp();
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dataRendering
|
||||
},
|
||||
props: {
|
||||
propKey: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propMagicScale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
propDataSpacing: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
scale: 1,
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
div_width: 0,
|
||||
div_height: 0,
|
||||
custom_list_length: 0,
|
||||
data_source_content_list: [],
|
||||
data_source: '',
|
||||
// 一屏显示的数量
|
||||
slides_per_view: 1,
|
||||
// 轮播高度
|
||||
swiper_height: 0,
|
||||
swiper_width: 'width: 100%;',
|
||||
show_data: { data_key: 'id', data_name: 'name' },
|
||||
gap_width: '',
|
||||
content_outer_spacing_magin: '0rpx',
|
||||
defalt_style: {
|
||||
color_list: [{ color: '', color_percentage: undefined }],
|
||||
direction: '180deg',
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
radius: 0,
|
||||
radius_top_left: 0,
|
||||
radius_top_right: 0,
|
||||
radius_bottom_left: 0,
|
||||
radius_bottom_right: 0,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
style_content_container: '',
|
||||
style_content_img_container: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
get_percentage_count() {
|
||||
return (num) => {
|
||||
return num * this.scale + 'px';
|
||||
};
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
if (!isEmpty(this.propValue)) {
|
||||
const new_form = this.propValue.data_content;
|
||||
const new_style = this.propValue.data_style;
|
||||
const { data_common_style = {}, data_color_list = [], data_direction = '180deg', data_radius = old_radius, data_background_img = [], data_background_img_style = '2', data_chunk_padding = old_padding, data_chunk_margin = old_margin, data_content_style = {}, data_pattern = old_border_and_box_shadow } = new_style;
|
||||
const style_data = {
|
||||
color_list: data_color_list,
|
||||
direction: data_direction,
|
||||
}
|
||||
const style_img_data = {
|
||||
background_img: data_background_img,
|
||||
background_img_style: data_background_img_style,
|
||||
}
|
||||
// 数据来源的内容
|
||||
let list = [];
|
||||
if (new_form.is_custom_data == '1') {
|
||||
if (Number(new_form.data_source_content.data_type) === 0) {
|
||||
list = new_form.data_source_content.data_list;
|
||||
} else {
|
||||
list = new_form.data_source_content.data_auto_list.map(item => ({
|
||||
id: Math.random(),
|
||||
new_cover: [],
|
||||
new_title: '',
|
||||
data: item,
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
list = new_form.data_source_content.data_list;
|
||||
}
|
||||
const new_list = list.length > 0 ? this.get_list(list, new_form, new_style) : [];
|
||||
// 计算宽度
|
||||
const { padding_left, padding_right, padding_top, padding_bottom } = data_chunk_padding;
|
||||
const { margin_left, margin_right, margin_bottom, margin_top } = data_chunk_margin;
|
||||
const old_width = new_form.width * this.propMagicScale;
|
||||
// 数据宽度
|
||||
const data_style = padding_left + padding_right + margin_left + margin_right + border_width(data_pattern);
|
||||
// 通用样式
|
||||
const chunk_padding = new_style?.chunk_padding || old_padding;
|
||||
const chunk_margin = new_style?.chunk_margin || old_margin;
|
||||
const common_styles = (chunk_margin?.margin_left || 0) + (chunk_margin?.margin_right || 0) + (chunk_padding?.padding_left || 0) + (chunk_padding?.padding_right || 0) + border_width(data_common_style);
|
||||
// 内容左右间距
|
||||
const content_spacing = (data_content_style?.margin_left || 0) + (data_content_style?.margin_right || 0) + (data_content_style?.padding_left || 0) + (data_content_style?.padding_right || 0) + border_width(data_content_style);
|
||||
const carousel_col = Number(new_form.data_source_carousel_col);
|
||||
// 数据间距
|
||||
const data_spacing = ['vertical', 'horizontal'].includes(new_form.data_source_direction) ? new_style.column_gap * (carousel_col - 1) : 0;
|
||||
// 当前容器的宽度 减去 左右两边的padding值 再减去 数据间距的一半 再除以 容器的宽度 得到比例 再乘以数据魔方的比例
|
||||
const width = old_width - data_style - content_spacing - common_styles - data_spacing - (this.propDataSpacing / 2);
|
||||
// 计算缩放比例
|
||||
// 比例增加最小值判断
|
||||
const scale_number = width / new_form.width;
|
||||
const new_scale = scale_number > 0 ? scale_number : 0;
|
||||
// 间距
|
||||
const space_between = new_form.data_source_direction == 'horizontal' ? new_style.column_gap : new_style.row_gap;
|
||||
// 判断是平移还是整屏滚动
|
||||
let swiper_height = 0;
|
||||
// 商品数量大于列数的时候,高度是列数,否则是当前的数量
|
||||
const col = new_list.length > carousel_col ? carousel_col : new_list.length;
|
||||
// 轮播图高度控制
|
||||
if (new_form.data_source_direction == 'horizontal') {
|
||||
swiper_height = new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top;
|
||||
} else {
|
||||
swiper_height = (new_form.height * new_scale + padding_top + padding_bottom + margin_bottom + margin_top) * col + ((carousel_col - 1) * space_between);
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.column_gap * (carousel_col - 1)) / carousel_col;
|
||||
// 横向的时候,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
const swiper_width = (new_form.data_source_direction == 'horizontal' && new_style.rolling_fashion != 'translation') ? `width: ${ 100 / carousel_col }%;`: 'width: 100%;';
|
||||
const content_style = !isEmpty(new_style.data_content_style)? new_style.data_content_style : this.defalt_style;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
div_width: width,
|
||||
scale: new_scale,
|
||||
custom_list_length: new_form.custom_list.length - 1,
|
||||
style_content_container: common_styles_computer(content_style),
|
||||
style_content_img_container: common_img_computer(content_style),
|
||||
style_container: gradient_computer(style_data) + radius_computer(data_radius) + margin_computer(data_chunk_margin) + box_shadow_computer(data_pattern) + border_computer(data_pattern), // 用于样式显示
|
||||
style_img_container: padding_computer(data_chunk_padding) + background_computer(style_img_data) + 'box-sizing: border-box;',
|
||||
data_source_content_list: new_list,
|
||||
data_source: !isEmpty(new_form.data_source)? new_form.data_source : '',
|
||||
slides_per_view: new_style.rolling_fashion == 'translation' ? (new_form.data_source_direction != 'horizontal' ? col : carousel_col) : 1,
|
||||
swiper_height: swiper_height,
|
||||
swiper_width: swiper_width,
|
||||
show_data: new_form?.show_data || { data_key: 'id', data_name: 'name' },
|
||||
content_outer_spacing_magin: space_between + 'px',
|
||||
gap_width: `width: calc(${100 / carousel_col}% - ${gap}px);`,
|
||||
});
|
||||
}
|
||||
},
|
||||
get_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation' && form.data_source_direction != 'vertical') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.data_source_carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.$emit('onCarouselChange', e.detail.current, this.propDataIndex);
|
||||
},
|
||||
url_event(e, index, split_index) {
|
||||
if (this.form.data_source == 'goods' && this.data_source_content_list.length > 0) {
|
||||
const list = this.data_source_content_list[index];
|
||||
if (!isEmpty(list) && !isEmpty(list.split_list[split_index])) {
|
||||
const new_list = list.split_list[split_index];
|
||||
if (!isEmpty(new_list)) {
|
||||
// 缓存商品数据
|
||||
app.globalData.goods_data_cache_handle(new_list.data.id, new_list.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
app.globalData.url_open(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.main-content {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
142
components/diy/modules/data-magic/magic-carousel.vue
Normal file
142
components/diy/modules/data-magic/magic-carousel.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<view class="wh-auto ht-auto oh" :style="style_container">
|
||||
<view class="pr oh wh-auto ht-auto" :style="style_img_container">
|
||||
<swiper circular="true" :autoplay="propValue.data_style.is_roll == '1'" :interval="propValue.data_style.interval_time * 1000" :duration="500" :vertical="propValue.data_style.rotation_direction == 'vertical'" :next-margin="next_margin" :display-multiple-items="slides_per_view" class="swiper" style="height: 100%" @change="carousel_change">
|
||||
<swiper-item v-for="(item1, index1) in propValue.data_content.list" :key="index1">
|
||||
<template v-if="propType === 'img'">
|
||||
<view class="wh-auto ht-auto" :data-value="item1.carousel_link.page" @tap="url_event">
|
||||
<imageEmpty :propImageSrc="item1.carousel_img[0]" :propStyle="propValue.data_style.get_img_radius" :propImgFit="propValue.data_content.fit" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="wh-auto ht-auto" :style="shop_spacing">
|
||||
<product-list-show :propKey="propKey" :propOuterflex="propValue.data_content.goods_outerflex" :propFlex="propValue.data_content.goods_flex" :propNum="show_num" :propActived="propActived" :propIsShow="propValue.data_content.is_show" :propChunkPadding="propValue.data_style.chunk_padding" :propValue="item1.split_list" :propGoodStyle="propGoodStyle" :propContentImgRadius="propValue.data_style.get_img_radius" @url_event="url_event"></product-list-show>
|
||||
</view>
|
||||
</template>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { gradient_computer, radius_computer, padding_computer, background_computer, isEmpty, border_computer, box_shadow_computer, old_border_and_box_shadow, old_margin, old_radius, old_padding, margin_computer } from "@/common/js/common/common.js";
|
||||
const app = getApp();
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import productListShow from '@/components/diy/modules/data-magic/product-list-show.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
productListShow,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propContentImgRadius: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propType: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propActived: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propGoodStyle: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
propDataIndex: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
slides_per_view: 1,
|
||||
show_num: 1,
|
||||
shop_spacing: '',
|
||||
next_margin: '0rpx',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (!isEmpty(this.propValue)) {
|
||||
const { data_color_list = [], data_direction = '180deg', data_chunk_margin = old_margin, data_radius = old_radius, data_pattern = old_border_and_box_shadow, data_background_img = [], data_background_img_style = '2', data_chunk_padding = old_padding } = this.propValue.data_style;
|
||||
const style_data = {
|
||||
color_list: data_color_list,
|
||||
direction: data_direction,
|
||||
}
|
||||
const style_img_data = {
|
||||
background_img: data_background_img,
|
||||
background_img_style: data_background_img_style,
|
||||
}
|
||||
let slides_per_view = 1;
|
||||
let show_num = 1;
|
||||
// 商品时的处理逻辑
|
||||
const { goods_outerflex, goods_num } = this.propValue.data_content;
|
||||
const { rotation_direction, rolling_fashion, data_goods_gap } = this.propValue.data_style;
|
||||
// 图片时的处理
|
||||
if (this.propType === 'img') {
|
||||
slides_per_view = 1; // 能够同时显示的slides数量
|
||||
} else {
|
||||
// 判断是平移还是整屏滚动, 平移的时候是一个为1组,如果是整屏滚动,就为一屏为一组
|
||||
if (rolling_fashion == 'translation') {
|
||||
// 如果是商品是横排的,轮播也是横排的,就不对商品进行拆分/如果商品是竖排的,轮播也是竖排的,不对商品进行拆分
|
||||
if ((goods_outerflex == 'row' && rotation_direction == 'horizontal') || (goods_outerflex == 'col' && rotation_direction == 'vertical')) {
|
||||
slides_per_view = goods_num; // 能够同时显示的slides数量
|
||||
show_num = 1; // 一屏显示的数量 用于商品内部处理显示
|
||||
} else {
|
||||
slides_per_view = 1; // 能够同时显示的slides数量
|
||||
show_num = goods_num; // 一屏显示的数量 用于商品内部处理显示
|
||||
}
|
||||
} else {
|
||||
// 切屏的时候为多个为一组
|
||||
show_num = goods_num; // 一屏显示的数量 用于商品内部处理显示
|
||||
slides_per_view = 1; // 能够同时显示的slides数量
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
style_container: gradient_computer(style_data) + radius_computer(data_radius) + margin_computer(data_chunk_margin) + box_shadow_computer(data_pattern) + border_computer(data_pattern), // 用于样式显示
|
||||
style_img_container: padding_computer(data_chunk_padding) + background_computer(style_img_data) + 'box-sizing: border-box;',
|
||||
next_margin: rolling_fashion == 'translation' && rotation_direction == 'horizontal' ? `-${ data_goods_gap * 2 }rpx` : '0rpx',
|
||||
shop_spacing: this.propType === 'img' ? 'margin-right: 0px;' : `margin-right: ${ data_goods_gap * 2 }rpx;`,
|
||||
slides_per_view: slides_per_view,
|
||||
show_num: show_num,
|
||||
});
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
carousel_change(e) {
|
||||
this.$emit('onCarouselChange', e.detail.current, this.propDataIndex);
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
233
components/diy/modules/data-magic/product-list-show.vue
Normal file
233
components/diy/modules/data-magic/product-list-show.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<view :class="['align-c flex-1 w h', (propOuterflex == 'row' ? 'flex-row' : 'flex-col')]" :style="'gap:' + propGoodStyle.data_goods_gap + 'px;'">
|
||||
<template v-if="propFlex === 'row'">
|
||||
<view v-for="(item, index) in propValue" :key="index" :style="block_size" class="w h">
|
||||
<view class="w h oh" :style="style_container">
|
||||
<view class="w h flex-row gap-10" :style="style_img_container" :data-index="index" :data-value="item.goods_url" @tap="url_event">
|
||||
<template v-if="!isEmpty(item.new_cover)">
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="!isEmpty(propIsShow)" class="flex-col w h tl jc-sb">
|
||||
<view v-if="propIsShow.includes('title')" class="text-line-2" :style="propGoodStyle.goods_title_style + 'height:'+ ((propGoodStyle.goods_title_size + 3) * 4) + 'rpx;'">{{ item.title || '' }}</view>
|
||||
<view v-if="propIsShow.includes('price')" :style="propGoodStyle.goods_price_style">
|
||||
<text :style="propGoodStyle.goods_price_symbol_style">{{ item.show_price_symbol || '' }}</text>
|
||||
{{ item.min_price || '' }}
|
||||
<template v-if="propIsShow.includes('price_unit')">
|
||||
<text :style="propGoodStyle.goods_price_unit_style">{{ item.show_price_unit || '' }}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="propFlex === 'col_price_float'">
|
||||
<view v-for="(item, index) in propValue" :key="index" :style="block_size" class="w h">
|
||||
<view class="w h oh" :style="style_container">
|
||||
<view class="w h flex-col gap-10" :style="style_img_container" :data-index="index" :data-value="item.goods_url" @tap="url_event">
|
||||
<view class="w h flex-1 pr oh">
|
||||
<template v-if="!isEmpty(item.new_cover)">
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="propIsShow.includes('price')" class="pa" :style="propGoodStyle.goods_price_style + float_pirce_style">
|
||||
<text :style="propGoodStyle.goods_price_symbol_style">{{ item.show_price_symbol || ''}}</text>{{ item.min_price || ''}}
|
||||
<template v-if="propIsShow.includes('price_unit')">
|
||||
<text :style="propGoodStyle.goods_price_unit_style">{{ item.show_price_unit || ''}}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="propIsShow.includes('title')" class="text-line-1 tl w" :style="propGoodStyle.goods_title_style + 'height:'+ ((propGoodStyle.goods_title_size + 3) * 2) + 'rpx;'">{{ item.title || '' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-for="(item, index) in propValue" :key="index" :style="block_size" class="w h">
|
||||
<view class="w h oh" :style="style_container">
|
||||
<view class="w h flex-col" :style="style_img_container" :data-index="index" :data-value="item.goods_url" @tap="url_event">
|
||||
<template v-if="!isEmpty(item.new_cover)">
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="w h">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="propContentImgRadius" propErrorStyle="width: 80rpx;height: 80rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="!isEmpty(propIsShow)" class="flex-col w h tl jc-sb">
|
||||
<view v-if="propIsShow.includes('title')" class="text-line-2" :style="propGoodStyle.goods_title_style + 'height:'+ ((propGoodStyle.goods_title_size + 3) * 4) + 'rpx;'">{{ item.title || '' }}</view>
|
||||
<view v-if="propIsShow.includes('price')" :style="propGoodStyle.goods_price_style">
|
||||
<text :style="propGoodStyle.goods_price_symbol_style">{{ item.show_price_symbol || ''}}</text>{{ item.min_price || '' }}
|
||||
<template v-if="propIsShow.includes('price_unit')">
|
||||
<text :style="propGoodStyle.goods_price_unit_style">{{ item.show_price_unit || ''}}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { gradient_computer, radius_computer, padding_computer, background_computer, isEmpty, margin_computer, box_shadow_computer, border_computer, old_margin, old_border_and_box_shadow, old_padding } from "@/common/js/common/common.js";
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
propOuterflex: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propFlex: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propContentImgRadius: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propNum: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propActived: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
propIsShow: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
propChunkPadding: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
propGoodStyle: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
block_size: '',
|
||||
float_pirce_style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
computed: {
|
||||
img_padding_computer() {
|
||||
if (!isEmpty(this.propChunkPadding)) {
|
||||
return padding_computer(this.propChunkPadding) + ';box-sizing: border-box;';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
if (!isEmpty(this.propGoodStyle)) {
|
||||
const { goods_color_list = [], goods_direction = '180deg', goods_radius = old_radius, goods_background_img = [], goods_background_img_style = '2', goods_chunk_padding = old_padding, goods_price_color_list = [], goods_price_direction = '180deg', goods_price_radius = old_radius, goods_price_padding = old_padding, goods_price_margin = old_margin, goods_price_location = 'center', goods_chunk_margin = old_margin} = this.propGoodStyle;
|
||||
const style_data = {
|
||||
color_list: goods_color_list,
|
||||
direction: goods_direction,
|
||||
}
|
||||
const style_img_data = {
|
||||
background_img: goods_background_img,
|
||||
background_img_style: goods_background_img_style,
|
||||
}
|
||||
|
||||
const data = {
|
||||
color_list: goods_price_color_list,
|
||||
direction: goods_price_direction,
|
||||
}
|
||||
let location = 'left:50%;transform:translateX(-50%);bottom:0;'
|
||||
if (goods_price_location == 'left') {
|
||||
location = 'left:0;bottom:0;';
|
||||
} else if (goods_price_location == 'right') {
|
||||
location = 'right:0;bottom:0;';
|
||||
}
|
||||
// 左右间距
|
||||
const shop_left_right_width_margin = goods_chunk_margin?.margin_left || 0 + goods_chunk_margin?.margin_right || 0;
|
||||
// 上下间距
|
||||
const shop_top_bottom_width_margin = goods_chunk_margin?.margin_top || 0 + goods_chunk_margin?.margin_bottom || 0;
|
||||
// 内容间距
|
||||
const total_gap = this.propGoodStyle.data_goods_gap * (this.propValue.length - 1);
|
||||
// 总的宽度
|
||||
const all_width = total_gap + (shop_left_right_width_margin.value * this.propNum);
|
||||
// 总的高度
|
||||
const all_height = total_gap + (shop_top_bottom_width_margin.value * this.propNum);
|
||||
this.setData({
|
||||
float_pirce_style: gradient_computer(data) + radius_computer(goods_price_radius) + padding_computer(goods_price_padding) + margin_computer(goods_price_margin) + location,
|
||||
style_container: gradient_computer(style_data) + radius_computer(goods_radius) + margin_computer(goods_chunk_margin) + border_computer(this.propGoodStyle) + box_shadow_computer(this.propGoodStyle), // 用于样式显示
|
||||
style_img_container: this.propFlex == 'col' ? background_computer(style_img_data) : padding_computer(goods_chunk_padding) + background_computer(style_img_data) + 'box-sizing: border-box;',
|
||||
block_size: this.propOuterflex == 'row' ? 'height:calc(100% - ' + shop_top_bottom_width_margin.value + 'px);width:calc((100% - ' + all_width + 'px) / ' + this.propNum + ');' : 'width:calc(100% - ' + shop_left_right_width_margin.value + 'px);height:calc((100% - ' + all_height + 'px) / ' + this.propNum + ');',
|
||||
});
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
url_event(e) {
|
||||
// 存储数据显示缓存
|
||||
let index = e.currentTarget.dataset.index || 0;
|
||||
let goods = this.propValue[index];
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
|
||||
this.$emit('url_event', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.w {
|
||||
width: 100%;
|
||||
}
|
||||
.h {
|
||||
height: 100%;
|
||||
}
|
||||
.half-width {
|
||||
width: 50%;
|
||||
}
|
||||
.gap-20 {
|
||||
gap: 40rpx;
|
||||
}
|
||||
</style>
|
||||
57
components/diy/modules/data-magic/video/index.vue
Normal file
57
components/diy/modules/data-magic/video/index.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<!-- 视频 -->
|
||||
<view class="video pr wh-auto ht-auto">
|
||||
<video :src="video" class="wh-auto ht-auto" :poster="video_img" objectFit="cover" :style="'object-fit: cover;' + video_style"></video>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { padding_computer, radius_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propDataStyle: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
video_img: '',
|
||||
video: '',
|
||||
video_style: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue || {};
|
||||
// 视频比例
|
||||
this.setData({
|
||||
video_img: new_content.video_img.length > 0 ? new_content.video_img[0].url : '',
|
||||
video: new_content.video.length > 0 ? new_content.video[0].url : '',
|
||||
video_style: radius_computer(this.propDataStyle.img_radius),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
79
components/diy/modules/image-empty.vue
Normal file
79
components/diy/modules/image-empty.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<view :class="['oh img_wh', propClass]" :style="empty_outer_style + propStyle">
|
||||
<image :src="img_url" :mode="propImgFit" :style="empty_style + 'display: block;'" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { is_obj, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propImageSrc: {
|
||||
type: [Object, String],
|
||||
default: () => {},
|
||||
},
|
||||
propErrorStyle: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propImgFit: {
|
||||
type: String,
|
||||
default: () => 'aspectFill',
|
||||
},
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
propClass: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
empty_outer_style: '',
|
||||
empty_style: 'width: 100%; height: 100%;', // 有图片的时候显示为100%
|
||||
img_url: '',
|
||||
default_image: '/static/images/common/image-empty.png',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propImageSrc(val) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let img_url = this.propImageSrc;
|
||||
if (is_obj(this.propImageSrc)) {
|
||||
img_url = !isEmpty(this.propImageSrc) ? this.propImageSrc.url : '';
|
||||
}
|
||||
// 没有图片的时候根据默认值来算
|
||||
if (img_url == undefined || img_url == null || img_url == '') {
|
||||
this.setData({
|
||||
empty_outer_style: 'background: #f4fcff;display:flex;align-items: center;justify-content: center;',
|
||||
empty_style: `${this.propErrorStyle}`,
|
||||
});
|
||||
img_url = this.default_image;
|
||||
} else {
|
||||
this.setData({
|
||||
empty_outer_style: '',
|
||||
empty_style: 'width: 100%; height: 100%;', // 有图片的时候显示为100%
|
||||
});
|
||||
}
|
||||
this.setData({
|
||||
img_url: img_url,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.img_wh {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
98
components/diy/modules/subscript/index.vue
Normal file
98
components/diy/modules/subscript/index.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<view v-if="form.seckill_subscript_show == '1'" class="corner-marker" :style="corner_marker">
|
||||
<view class="flex-row nowrap" :style="corner_img_marker">
|
||||
<template v-if="form.subscript_type == 'img-icon'">
|
||||
<template v-if="!isEmpty(form.subscript_img_src)">
|
||||
<image :src="form.subscript_img_src[0].url" mode="aspectFill" :style="img_style" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<iconfont :name="'icon-' + form.subscript_icon_class" propContainerDisplay="flex" :size="new_style.subscript_style.text_or_icon_size * 2 + 'rpx'" :color="new_style.subscript_style.text_or_icon_color"></iconfont>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-line-1" :style="text_size">{{ form.subscript_text }}</span>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_img_computer, common_styles_computer, isEmpty } from '@/common/js/common/common.js';
|
||||
import iconfont from '@/components/iconfont/iconfont';
|
||||
export default {
|
||||
components: {
|
||||
iconfont,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propType: {
|
||||
type: String,
|
||||
default: 'outer',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
corner_img_marker: '',
|
||||
img_style: '',
|
||||
text_size: '',
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
// 初始化数据
|
||||
init() {
|
||||
if (!isEmpty(this.propValue)) {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propType == 'outer' ? this.propValue.style || {} : { subscript_style: this.propValue.style || {} };
|
||||
if (!isEmpty(new_style.subscript_style)) {
|
||||
// 视频比例
|
||||
this.setData({
|
||||
form: new_content,
|
||||
new_style: new_style,
|
||||
corner_marker: this.get_corner_marker(new_style),
|
||||
text_size: `font-size: ${ new_style.subscript_style.text_or_icon_size * 2 }rpx;color: ${ new_style.subscript_style.text_or_icon_color };`,
|
||||
corner_img_marker: common_img_computer(new_style.subscript_style),
|
||||
img_style: `height: ${new_style.subscript_style.img_height * 2}rpx; width: ${new_style.subscript_style.img_width * 2}rpx`,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
get_corner_marker(new_style) {
|
||||
const { subscript_style } = new_style;
|
||||
let location = common_styles_computer(subscript_style);
|
||||
// 获取内部的显示数据
|
||||
const { seckill_subscript_location, top_or_bottom_spacing, left_or_right_spacing } = subscript_style;
|
||||
// 圆角根据图片的圆角来计算 对角线是同样的圆角
|
||||
if (seckill_subscript_location == 'top-left') {
|
||||
location += `top: ${ top_or_bottom_spacing * 2 }rpx;left: ${ left_or_right_spacing * 2 }rpx;`;
|
||||
} else if (seckill_subscript_location == 'top-center') {
|
||||
location += 'top: 0;left: 50%;transform: translateX(-50%);';
|
||||
} else if (seckill_subscript_location == 'top-right') {
|
||||
location += `top: ${ top_or_bottom_spacing * 2 }rpx;right:${ left_or_right_spacing * 2 }rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-left') {
|
||||
location += `bottom: ${ top_or_bottom_spacing * 2 }rpx;left: ${ left_or_right_spacing * 2 }rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-center') {
|
||||
location += 'bottom: 0;left: 50%;transform: translateX(-50%);';
|
||||
} else if (seckill_subscript_location == 'bottom-right') {
|
||||
location += `bottom: ${ top_or_bottom_spacing * 2 }rpx;right: ${ left_or_right_spacing * 2 }rpx;`;
|
||||
}
|
||||
return location;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.corner-marker {
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
592
components/diy/modules/tabs-view.vue
Normal file
592
components/diy/modules/tabs-view.vue
Normal file
@@ -0,0 +1,592 @@
|
||||
<template>
|
||||
<!-- 66rpx是自定义顶部导航栏的高度-->
|
||||
<view class="tabs-view" :style="tabs_sticky">
|
||||
<view class="tabs-view" :style="propStyle + propTabsBackground">
|
||||
<view class="pr" :style="propsTabsContainer">
|
||||
<view v-if="propIsRotatingBackground" class="pa top-0 wh-auto ht-auto" :style="propBgImgStyle"></view>
|
||||
<view class="flex-row gap-10 jc-sb align-c" :style="propsTabsImgContainer">
|
||||
<view class="tabs flex-1 flex-width">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" :scroll-with-animation="tabs_list_is_sliding_fixed" :scroll-left="scroll_left" :class="'wh-auto interior-area-' + propKey">
|
||||
<view :class="'flex-row ' + flex_class" :style="'height:' + tabs_height + ';width:' + tabs_scroll_width + 'px;'">
|
||||
<view v-for="(item, index) in tabs_list" :key="index" :class="'item nowrap flex-col jc-c align-c gap-4 scroll-item-' + propKey + ' ' + tabs_theme + (index == active_index ? ' active' : '') + ((tabs_theme_index == '0' && tabs_theme_1_style) || tabs_theme_index == '1' || tabs_theme_index == '2' ? ' pb-0' : '')" :style="'flex:0 0 auto;padding-left:' + (index == 0 ? '0' : tabs_spacing) + 'rpx;padding-right:' + (index + 1 == tabs_list.length ? '0' : tabs_spacing) + 'rpx;' + get_item_style(item.is_sliding_fixed)" :data-index="index" @tap="handle_event">
|
||||
<view class="nowrap ma-auto">
|
||||
<view v-if="tabs_theme_index == '4'" :class="'img oh pr z-i-deep ' + (!isEmpty(item.img) ? 'img-no-empty' : '')" :style="tabs_theme_style.tabs_top_img">
|
||||
<imageEmpty :propImageSrc="item.img[0]" propImgFit="aspectFit" propErrorStyle="width: 20rpx;height: 20rpx;"></imageEmpty>
|
||||
<!-- <image :src="item.img[0].url" class="img" mode="aspectFit" /> -->
|
||||
</view>
|
||||
<template v-if="item.tabs_type == '1'">
|
||||
<template v-if="!isEmpty(item.tabs_icon)">
|
||||
<view :class="tabs_theme_index == '4' ? 'title pr z-i' : 'title pr z-i-deep'" :style="(tabs_theme_index == '4' ? tabs_sign_spacing : '') + (index == active_index ? (['2', '4'].includes(tabs_theme_index) ? tabs_check : '') : '' + tabs_padding_bottom)">
|
||||
<iconfont :name="'icon-' + item.tabs_icon" :color="index == active_index ? tabs_icon_checked_color : tabs_icon_color" propContainerDisplay="flex" :size="index == active_index ? tabs_icon_checked_size : tabs_icon_size"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :class="tabs_theme_index == '4' ? 'title pr z-i' : 'title pr z-i-deep'" :style="(tabs_theme_index == '4' ? tabs_sign_spacing : '') + index == active_index ? new_style.is_tabs_img_background == '1' && ['2', '4'].includes(tabs_theme_index) ? tabs_check : '' : tabs_padding_bottom">
|
||||
<imageEmpty :propImageSrc="item.tabs_img[0]" :propStyle="index == active_index ? tabs_theme_style.tabs_img_checked : tabs_theme_style.tabs_img" propImgFit="heightFix" propErrorStyle="width: 40rpx;height: 40rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :class="tabs_theme_index == '4' ? 'title pr z-i' : 'title pr z-i-deep'" :style="(tabs_theme_index == '4' ? tabs_sign_spacing : '') + (index == active_index ? ['2', '4'].includes(tabs_theme_index) ? tabs_theme_style.tabs_title_checked + tabs_check : tabs_theme_style.tabs_title_checked : tabs_theme_style.tabs_title + tabs_padding_bottom)">{{ item.title }}</view>
|
||||
</template>
|
||||
<view class="desc pr z-i wh-auto" :style="tabs_sign_spacing + (tabs_theme_index == '1' && index == active_index ? tabs_check : '')">{{ item.desc }}</view>
|
||||
<template v-if="tabs_theme_index == '3' && index == active_index">
|
||||
<template v-if="!isEmpty(form.tabs_adorn_icon)">
|
||||
<view class="icon pr z-i wh-auto flex-row jc-c align-c" :style="tabs_sign_spacing">
|
||||
<iconfont :name="'icon-' + form.tabs_adorn_icon" :style="icon_tabs_check" propContainerDisplay="flex" :size="tabs_adorn_icon_size"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="pr z-i wh-auto flex-row jc-c align-c ma-auto" :style="tabs_sign_spacing">
|
||||
<imageEmpty :propImageSrc="form.tabs_adorn_img[0]" :propStyle="tabs_adorn_img_style" propImgFit="aspectFit" propErrorStyle="width: 20rpx;height: 20rpx;"></imageEmpty>
|
||||
</view>
|
||||
</template>
|
||||
</template>
|
||||
<view class="bottom_line z-i" :class="tabs_bottom_line_theme" :style="tabs_check + tabs_sign_spacing"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view v-if="propIsTabsIcon && form.show_more !== '0'" :style="tabs_padding_bottom">
|
||||
<iconfont :name="'icon-' + icon.more_icon_class || 'category-more'" :size="icon.more_icon_size + '' || '14'" :color="icon.more_icon_color || '#000'" propContainerDisplay="flex" @click="category_check_event"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 选项卡更多弹窗 -->
|
||||
<componentPopup :propShow="popup_status" :propIsBar="propIsBar" propPosition="top" :propMask="true" :propTop="newPropTop" :propStyle="newPropStyle" @onclose="quick_close_event">
|
||||
<view :class="'padding-bottom-lg ' + (['toutiao', 'app', 'h5'].includes(platform) ? 'padding-top-lg' : 'padding-top')">
|
||||
<view class="padding-left-main padding-bottom-main">全部选项卡</view>
|
||||
<view class="divider-b">
|
||||
<view class="nav-list-more">
|
||||
<view class="flex-row flex-wrap align-c">
|
||||
<view v-for="(item, index) in tabs_list" :key="index" class="item tc cr-base cp text-size-xs" :data-index="index" @tap="handle_event">
|
||||
<view class="dis-inline-block padding-vertical-xs padding-horizontal round" :class="active_index == index ? 'bg-main border-color-main cr-white' : ''">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tc padding-top-lg flex-row jc-c align-c" @tap="quick_close_event">
|
||||
<text class="padding-right-sm">{{ $t('nav-more.nav-more.h9g4b1') }}</text>
|
||||
<iconfont name="icon-arrow-top" color="#ccc" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</componentPopup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { gradient_computer, isEmpty, radius_computer } from '@/common/js/common/common.js';
|
||||
import componentPopup from '@/components/popup/popup';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
components: {
|
||||
componentPopup,
|
||||
imageEmpty,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
// 是否需要icon
|
||||
propIsTabsIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否需要粘性定位置顶
|
||||
propIsTop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 指定样式
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 层级
|
||||
propZIndex: {
|
||||
type: Number,
|
||||
default: 11,
|
||||
},
|
||||
// 自定义导航栏高度
|
||||
propCustomNavHeight: {
|
||||
type: String,
|
||||
default: '66rpx',
|
||||
},
|
||||
// tabs背景色
|
||||
propTabsBackground: {
|
||||
type: String,
|
||||
default: 'transparent',
|
||||
},
|
||||
// 置顶距离顶部高度
|
||||
propTop: {
|
||||
type: [String, Number],
|
||||
default: '0',
|
||||
},
|
||||
propsTabsContainer: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propsTabsImgContainer: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIsRotatingBackground: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propBgImgStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propTabsSlidingFixedBg: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
tabs_theme_index: '',
|
||||
tabs_theme: '',
|
||||
tabs_check: '',
|
||||
icon_tabs_check: '',
|
||||
tabs_spacing: '',
|
||||
tabs_sign_spacing: '',
|
||||
tabs_padding_bottom: '',
|
||||
tabs_list: [],
|
||||
active_index: 0,
|
||||
tabs_theme_style: {
|
||||
tabs_title_checked: '',
|
||||
tabs_title: '',
|
||||
tabs_img_checked: '',
|
||||
tabs_img: '',
|
||||
tabs_top_img: ''
|
||||
},
|
||||
tabs_icon_checked_size: '',
|
||||
tabs_icon_size: '',
|
||||
tabs_icon_checked_color: '',
|
||||
tabs_icon_color: '',
|
||||
icon: {
|
||||
more_icon_class: '',
|
||||
more_icon_size: '',
|
||||
more_icon_color: '',
|
||||
},
|
||||
// 过滤弹窗
|
||||
popup_status: false,
|
||||
propIsBar: false,
|
||||
tabs_bottom_line_theme: '',
|
||||
tabs_sticky: '',
|
||||
tabs_height: '100%',
|
||||
tabs_adorn_img_style: '',
|
||||
tabs_width: 0,
|
||||
tabs_scroll_width: 0,
|
||||
// #ifdef MP
|
||||
sticky_top: bar_height,
|
||||
// #endif
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
sticky_top: bar_height,
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
sticky_top: bar_height,
|
||||
// #endif
|
||||
newPropTop: '',
|
||||
newPropStyle: '',
|
||||
platform: app.globalData.application_client_type(),
|
||||
is_out_of_range: false,
|
||||
tabs_list_is_sliding_fixed: true,
|
||||
scroll_left: 0,
|
||||
tabs_adorn_icon_size: '0rpx',
|
||||
// 默认数据
|
||||
old_radius: { radius: 0, radius_top_left: 0, radius_top_right: 0, radius_bottom_left: 0, radius_bottom_right: 0 },
|
||||
old_padding: { padding: 0, padding_top: 0, padding_bottom: 0, padding_left: 0, padding_right: 0 },
|
||||
old_margin: { margin: 0, margin_top: 10, margin_bottom: 0, margin_left: 0, margin_right: 0 },
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
flex_class() {
|
||||
if (this.is_out_of_range) {
|
||||
return this.form.justification == 'center' ? 'jc-c' : this.form.justification == 'right' ? 'jc-e': '';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
get_item_style() {
|
||||
return (val) => {
|
||||
return val == '1' ? `${ this.propTabsSlidingFixedBg };position: sticky;left: 0;z-index: 11;` : ''
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
propValue() {
|
||||
this.init();
|
||||
},
|
||||
propIsTop: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler(new_val) {
|
||||
if (new_val) {
|
||||
this.tabs_sticky = 'position: sticky;top: calc(' + parseInt(this.propTop) + 'px + ' + this.propCustomNavHeight + ');z-index: ' + this.propZIndex + ';';
|
||||
} else {
|
||||
this.tabs_sticky = '';
|
||||
}
|
||||
},
|
||||
},
|
||||
propTop(new_val, old_val) {
|
||||
if (this.propIsTop) {
|
||||
this.tabs_sticky = 'position: sticky;top: calc(' + parseInt(this.propTop) + 'px + ' + this.propCustomNavHeight + ');z-index: ' + this.propZIndex + ';';
|
||||
} else {
|
||||
this.tabs_sticky = '';
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 判断是否为空
|
||||
isEmpty,
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const new_tabs_check = this.tabs_check_computer(new_style);
|
||||
const new_icon = {
|
||||
more_icon_class: new_style.more_icon_class,
|
||||
more_icon_size: new_style.more_icon_size,
|
||||
more_icon_color: new_style.more_icon_color,
|
||||
};
|
||||
const tabs_top_img_height = new_style?.tabs_top_img_height || 39;
|
||||
const tabs_top_img_radius = new_style?.tabs_top_img_radius || { radius: 100, radius_top_left: 100, radius_top_right: 100, radius_bottom_left: 100, radius_bottom_right: 100}
|
||||
// 标题样式
|
||||
const new_tabs_theme_style = {
|
||||
tabs_title_checked: `font-weight: ${new_style.tabs_weight_checked};font-size: ${new_style.tabs_size_checked * 2}rpx;line-height: ${new_style.tabs_size_checked * 2}rpx;color:${new_style.tabs_color_checked};`,
|
||||
tabs_title: `font-weight: ${new_style.tabs_weight};font-size: ${new_style.tabs_size * 2}rpx;line-height: ${new_style.tabs_size * 2}rpx;color:${new_style.tabs_color};`,
|
||||
tabs_img_checked: `height: ${(new_style?.tabs_img_height || 0) * 2}rpx;` + radius_computer(new_style?.tabs_img_radius || this.old_radius),
|
||||
tabs_img: `height: ${(new_style?.tabs_img_height || 0) * 2}rpx;` + radius_computer(new_style?.tabs_img_radius || this.old_radius),
|
||||
tabs_top_img: `height: ${tabs_top_img_height * 2 }rpx;width: ${tabs_top_img_height * 2 }rpx;box-sizing: border-box;` + radius_computer(tabs_top_img_radius),
|
||||
};
|
||||
const { tabs_size_checked, tabs_size, tabs_icon_size_checked = 0, tabs_icon_size = 0, tabs_img_height = 0, tabs_sign_spacing = 0 } = new_style || {};
|
||||
let default_height = 0;
|
||||
if (new_content.tabs_theme == '2') {
|
||||
default_height = 12; // 选中的时候,风格二的内间距
|
||||
} else if (new_content.tabs_theme == '4') {
|
||||
// const top_index = new_content?.tabs_list?.findIndex((item) => !isEmpty(item.img)) ?? -1;
|
||||
// default_height = 4 + (top_index > -1 ? tabs_top_img_height + tabs_sign_spacing : 0); // 选中的时候,风格二的内间距 加上上边图片的大小和上边图片之间的间距
|
||||
default_height = 4 + tabs_top_img_height + tabs_sign_spacing;
|
||||
}
|
||||
// 筛选出所有的icon
|
||||
const is_icon = new_content?.tabs_list?.findIndex((item) => item.tabs_type === '1' && !isEmpty(item.tabs_icon)) ?? -1;
|
||||
// 如果有icon,则取选中的icon大小和未选中的icon大小取最大值,作为图标的高度
|
||||
let icon_height = 0;
|
||||
if (is_icon > -1) {
|
||||
icon_height = Math.max(tabs_icon_size_checked + default_height, tabs_icon_size);
|
||||
}
|
||||
// 筛选出所有的图片, 没有选择图标的时候默认是图片
|
||||
const is_img = new_content?.tabs_list?.findIndex((item) => item.tabs_type === '1' && isEmpty(item.tabs_icon)) ?? -1;
|
||||
// 选项卡高度 五个值,作为判断依据,因为图片没有未选中的大小设置,所以高度判断的时候只取选中的高度, 其余的icon和标题都分别取选中和未选中的大小对比,取出最大的值,作为选项卡的高度,避免选项卡切换时会出现抖动问题
|
||||
const height = Math.max(tabs_size_checked + default_height, tabs_size, icon_height, is_img > -1 ? (tabs_img_height + default_height) : '');
|
||||
const findIndex = new_content.tabs_list.findIndex(item => item.is_sliding_fixed == '1');
|
||||
// 参数设置
|
||||
this.setData({
|
||||
form: new_content,
|
||||
tabs_list_is_sliding_fixed: findIndex == -1,
|
||||
newPropTop: `calc(${ this.sticky_top * 2}rpx);`,
|
||||
newPropStyle: `padding-top: ${ this.sticky_top * 2 }rpx;margin-top: -${ this.sticky_top * 2 }rpx;`,
|
||||
new_style: new_style,
|
||||
tabs_spacing: Number(new_style.tabs_spacing),
|
||||
tabs_sign_spacing: !isEmpty(new_style.tabs_sign_spacing) ? `margin-top: ${new_style.tabs_sign_spacing * 2}rpx;` : 'margin-top: 8rpx;',
|
||||
tabs_list: new_content.tabs_list,
|
||||
tabs_padding_bottom: this.get_padding_bottom(new_content, new_style) + 'z-index: 11;',
|
||||
// 选项卡主题
|
||||
tabs_theme: this.get_tabs_theme(new_content),
|
||||
tabs_theme_index: new_content.tabs_theme,
|
||||
// 选项卡样式
|
||||
tabs_check: new_tabs_check,
|
||||
icon_tabs_check: `${new_tabs_check};line-height: 1;background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;`,
|
||||
icon: new_icon,
|
||||
tabs_icon_checked_size: (new_style?.tabs_icon_size_checked || 0) * 2 + 'rpx',
|
||||
tabs_icon_size: (new_style?.tabs_icon_size || 0) * 2 + 'rpx',
|
||||
tabs_icon_checked_color: new_style?.tabs_icon_color_checked || '',
|
||||
tabs_icon_color: new_style?.tabs_icon_color || '',
|
||||
tabs_theme_style: new_tabs_theme_style,
|
||||
tabs_bottom_line_theme: new_style.tabs_one_theme == '1' ? 'tabs-bottom-line-theme' : '',
|
||||
tabs_theme_1_style: new_style.tabs_one_theme == '1',
|
||||
tabs_height: ['2', '4'].includes(new_content.tabs_theme) ? height * 2 + 'rpx' : '100%;',
|
||||
tabs_adorn_img_style: this.get_tabs_adorn_img_style(new_style),
|
||||
tabs_adorn_icon_size: (new_style?.tabs_adorn_icon_size || 0) * 2 + 'rpx',
|
||||
});
|
||||
// 只有居中居右的才重新获取dom判断
|
||||
// if (['center', 'right'].includes(this.form.justification)) {
|
||||
setTimeout(() => {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('.interior-area-' + this.propKey)
|
||||
.fields({ size: true, scrollOffset: true},(res) => {
|
||||
if ((res || null) != null) {
|
||||
const { scrollWidth, width } = res;
|
||||
this.setData({
|
||||
is_out_of_range: scrollWidth <= width,
|
||||
tabs_scroll_width: scrollWidth,
|
||||
tabs_width: width
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
}, 0)
|
||||
// }
|
||||
},
|
||||
get_tabs_adorn_img_style(new_style) {
|
||||
return radius_computer(new_style?.tabs_adorn_img_radius || this.old_radius) + `height: ${(new_style?.tabs_adorn_img_height || 10) * 2}rpx;${ new_style.is_tabs_adorn_img_background == '1' ? tabs_check.value : ''}`;
|
||||
},
|
||||
// 获取选项卡主题
|
||||
get_tabs_theme(data) {
|
||||
let arr = {
|
||||
1: 'tabs-style-2',
|
||||
2: 'tabs-style-3',
|
||||
3: 'tabs-style-4',
|
||||
4: 'tabs-style-5',
|
||||
};
|
||||
let value = arr[data.tabs_theme];
|
||||
return value === undefined ? 'tabs-style-1' : value;
|
||||
},
|
||||
get_padding_bottom(form, new_style) {
|
||||
let bottom = 0;
|
||||
if (form.tabs_theme == '0') {
|
||||
if (new_style.tabs_one_theme == '1') {
|
||||
bottom = 6;
|
||||
} else {
|
||||
bottom = 3;
|
||||
}
|
||||
} else if (form.tabs_theme == '3') {
|
||||
bottom = !isEmpty(form.tabs_adorn_icon) ? new_style.tabs_adorn_icon_size : new_style.tabs_adorn_img_height;
|
||||
}
|
||||
const tabs_sign_spacing = !isEmpty(new_style.tabs_sign_spacing) ? new_style.tabs_sign_spacing : 4;
|
||||
return ['1', '2', '4'].includes(form.tabs_theme) ? '' : `padding-bottom: ${(tabs_sign_spacing + bottom) * 2 }rpx;`;
|
||||
},
|
||||
// 选中的背景渐变色样式
|
||||
tabs_check_computer(data) {
|
||||
const new_gradient_params = {
|
||||
color_list: data.tabs_checked,
|
||||
direction: data.tabs_direction,
|
||||
};
|
||||
return gradient_computer(new_gradient_params);
|
||||
},
|
||||
|
||||
// 事件
|
||||
// tabs切换事件
|
||||
handle_event(e) {
|
||||
const index = e.currentTarget.dataset.index;
|
||||
const tabs_list_item = this.tabs_list[index];
|
||||
this.setData({
|
||||
active_index: index,
|
||||
popup_status: false,
|
||||
});
|
||||
this.set_scoll_left(index);
|
||||
this.$emit('onTabsTap', index, tabs_list_item);
|
||||
setTimeout(() => {
|
||||
this.$emit('tabsZindex', 11)
|
||||
}, 200)
|
||||
},
|
||||
// 将选中的内容定位到中间
|
||||
set_scoll_left(index) {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.selectAll(`.scroll-item-` + this.propKey)
|
||||
.boundingClientRect((rect) => {
|
||||
const tabs_index = this.form.tabs_list.findIndex(item => item.is_sliding_fixed == '1');
|
||||
// 如果第一个悬浮了,就取第二个的left加上 第一个的宽度和left
|
||||
let new_width = tabs_index == 0 && index != 0 ? rect[1].left - rect[0].width - rect[0].left : rect[0].left;
|
||||
// 如果悬浮的不是第一个并且选中的是悬浮的内容
|
||||
if (index > 0 && tabs_index == index) {
|
||||
new_width = rect[0].left - rect[index + 1].left + rect[index].width;
|
||||
}
|
||||
const scrollLeft =
|
||||
rect[index].left +
|
||||
rect[index].width / 2 -
|
||||
this.tabs_width / 2 -
|
||||
new_width
|
||||
this.setData({
|
||||
scroll_left: scrollLeft,
|
||||
});
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
// 分类选择事件
|
||||
category_check_event() {
|
||||
this.setData({
|
||||
popup_status: true,
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.$emit('tabsZindex', 13)
|
||||
}, 0)
|
||||
},
|
||||
// 关闭分类选择事件
|
||||
quick_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.$emit('tabsZindex', 11)
|
||||
}, 200)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tabs {
|
||||
.item {
|
||||
// padding: 0 0 10rpx 0;
|
||||
position: relative;
|
||||
&:first-of-type {
|
||||
margin-left: 0;
|
||||
}
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.desc {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
.bottom_line {
|
||||
width: 100%;
|
||||
height: 6rpx;
|
||||
border-radius: 20rpx;
|
||||
background-color: red;
|
||||
// position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: none;
|
||||
}
|
||||
.icon {
|
||||
// position: absolute;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
font-size: 40rpx;
|
||||
line-height: 20rpx !important;
|
||||
display: none;
|
||||
}
|
||||
.img {
|
||||
// width: 78rpx;
|
||||
// height: 78rpx;
|
||||
border-radius: 100%;
|
||||
border: 2rpx solid transparent;
|
||||
display: none;
|
||||
margin: 0 auto;
|
||||
}
|
||||
&.tabs-style-1 {
|
||||
&.active {
|
||||
.bottom_line {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.tabs-bottom-line-theme {
|
||||
opacity: 0.6;
|
||||
bottom: 0;
|
||||
z-index: 0;
|
||||
height: 14rpx;
|
||||
border-radius: 0;
|
||||
// left: 12%;
|
||||
}
|
||||
}
|
||||
&.tabs-style-2 {
|
||||
&.active {
|
||||
.desc {
|
||||
background: #ff5e5e;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.desc {
|
||||
border-radius: 40rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&.tabs-style-3 {
|
||||
&.active {
|
||||
.title {
|
||||
// background: #ff2222;
|
||||
border-radius: 40rpx;
|
||||
padding: 6px 12px;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.tabs-style-4 {
|
||||
// padding-bottom: 28rpx;
|
||||
&.active {
|
||||
.title {
|
||||
color: #ff2222;
|
||||
}
|
||||
.icon {
|
||||
color: #ff2222;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.tabs-style-5 {
|
||||
align-items: center;
|
||||
&.active {
|
||||
.title {
|
||||
// font-size: 22rpx;
|
||||
// background: #ff5e5e;
|
||||
border-radius: 40rpx;
|
||||
padding: 2px 7px;
|
||||
box-sizing: border-box;
|
||||
// color: #fff;
|
||||
}
|
||||
.img {
|
||||
border-color: #ff5e5e;
|
||||
}
|
||||
}
|
||||
.img-no-empty {
|
||||
width: 100% !important;
|
||||
}
|
||||
.img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.nav-list-more {
|
||||
width: 100%;
|
||||
max-height: 550rpx;
|
||||
padding-bottom: 20rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.nav-list-more .item {
|
||||
width: 20%;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
.pb-14 {
|
||||
padding-bottom: 28rpx;
|
||||
}
|
||||
.pb-0 {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
.ma-auto {
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
248
components/diy/nav-group.vue
Normal file
248
components/diy/nav-group.vue
Normal file
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view class="pr" :style="style_img_container">
|
||||
<swiper class="swiper" circular="true" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_group" :style="{ height: new_height }" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in nav_content_list" :key="index" class="swiper-item">
|
||||
<view class="banner-img flex-row flex-wrap wh-auto" :class="'banner-img-' + propKey" :style="space">
|
||||
<view v-for="(item1, index1) in item.split_list" :key="index1" class="flex-col gap-10 align-c" :style="group_width + nav_title_space" :data-value="item1.link.page" @tap="url_open_event">
|
||||
<view v-if="['image_with_text', 'image'].includes(nav_style)" class="flex-row align-c jc-c pr">
|
||||
<view class="top-img" :style="img_size">
|
||||
<imageEmpty :propImageSrc="item1.img[0]" :propStyle="img_style" propErrorStyle="width: 60rpx;height: 60rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="item1.subscript" propType="nav-group"></subscriptIndex>
|
||||
</view>
|
||||
<view v-if="['image_with_text', 'text'].includes(nav_style)" class="wh-auto size-12 ma-0 nowrap oh tc" :style="text_style">{{ item1.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="form.display_style == 'slide' && new_style.is_show == '1'" :class="['left', 'right'].includes(new_style.indicator_new_location) ? 'indicator_up_down_location' : 'indicator_about_location'" :style="indicator_location_style">
|
||||
<block v-if="new_style.indicator_style == 'num'">
|
||||
<view :style="indicator_style" class="dot-item">
|
||||
<text :style="{ color: new_style.actived_color }">{{ actived_index + 1 }}</text>
|
||||
<text>/{{ nav_content_list.length }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-for="(item, index) in nav_content_list" :key="index" :style="indicator_style + (actived_index == index ? 'background:' + new_style.actived_color : '')" class="dot-item" />
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { isEmpty, common_styles_computer, common_img_computer, radius_computer, padding_computer, get_indicator_style, get_indicator_location_style } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
subscriptIndex,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
img_style: '',
|
||||
text_style: '',
|
||||
indicator_style: '',
|
||||
new_height: '300rpx',
|
||||
actived_index: 0,
|
||||
group_width: '',
|
||||
nav_content_list: [],
|
||||
nav_title_space: 'row-gap:20rpx', // 导航标题间距
|
||||
space: 'row-gap:20rpx', // 导航间距
|
||||
img_size: '72rpx',
|
||||
slides_per_group: 1,
|
||||
indicator_location_style: '',
|
||||
subscriptStyle: {
|
||||
seckill_subscript_location: 'top-left',
|
||||
text_or_icon_color: '#fff',
|
||||
text_or_icon_size: 12,
|
||||
img_width: 20,
|
||||
img_height: 20,
|
||||
direction: '90deg',
|
||||
top_or_bottom_spacing: 0,
|
||||
left_or_right_spacing: 0,
|
||||
color_list: [{ color: '#FF7607', color_percentage: undefined }],
|
||||
background_img_style: '2',
|
||||
background_img: [],
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
radius: 4,
|
||||
radius_top_left: 4,
|
||||
radius_top_right: 4,
|
||||
radius_bottom_left: 4,
|
||||
radius_bottom_right: 4,
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
box_shadow_color: '',
|
||||
box_shadow_x: 0,
|
||||
box_shadow_y: 0,
|
||||
box_shadow_blur: 0,
|
||||
box_shadow_spread: 0,
|
||||
}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
const new_content = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
|
||||
let group = 1;
|
||||
let group_width = `width: ${100 / (new_content.single_line || 4)}%;`;
|
||||
// 判断是否是轮播图
|
||||
if (new_content?.display_style == 'slide') {
|
||||
if (new_content.row == 1 && new_style.rolling_fashion == 'translation') {
|
||||
group = new_content.single_line || 4;
|
||||
group_width = 'width: 100%;';
|
||||
} else {
|
||||
group = 1;
|
||||
group_width = `width: ${100 / (new_content.single_line || 4)}%;`;
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
form: new_content,
|
||||
new_style: new_style,
|
||||
style_container: common_styles_computer(new_style.common_style), // 用于样式显示
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
img_style: radius_computer(new_style), // 图片的设置
|
||||
text_style: `font-size: ${new_style.title_size * 2 || 24}rpx; color: ${new_style.title_color || '#000'};`, // 标题的样式
|
||||
indicator_style: get_indicator_style(new_style), // 指示器的样式
|
||||
indicator_location_style: get_indicator_location_style(new_style), // 指示器位置处理
|
||||
actived_color: new_style.actived_color || '#2A94FF', // 轮播图显示样式
|
||||
slides_per_group: group, // 每个轮播图显示的个数
|
||||
group_width: group_width, // 每个导航所占位置
|
||||
nav_title_space: 'row-gap:' + (new_style.title_space || 0) * 2 + 'rpx', // 导航标题间距
|
||||
space: 'row-gap:' + (new_style.space || 0) * 2 + 'rpx;' + padding_computer(new_style.data_padding), // 导航间距
|
||||
img_size: 'width:' + (new_style.img_size || 0) * 2 + 'rpx;height:' + (new_style.img_size || 0) * 2 + 'rpx;', // 图片大小
|
||||
nav_style: new_content.nav_style || 'image_with_text', // 是否显示文字和图片
|
||||
nav_content_list: this.get_nav_content_list(new_content, new_style),
|
||||
});
|
||||
setTimeout(() => {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
// 选择我们想要的元素
|
||||
query
|
||||
.select('.banner-img-' + this.propKey)
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
new_height: res.height + 'px',
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec(); // 执行查询
|
||||
}, 50);
|
||||
},
|
||||
get_nav_content_list(data, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const list = JSON.parse(JSON.stringify(data.nav_content_list || Array(4))).map(item => ({
|
||||
...item,
|
||||
// 角标配置
|
||||
subscript: isEmpty(item.subscript) ?
|
||||
{
|
||||
content: {
|
||||
seckill_subscript_show: '0',
|
||||
subscript_type: 'text',
|
||||
subscript_img_src: [],
|
||||
subscript_icon_class: '',
|
||||
subscript_text: '',
|
||||
},
|
||||
style: this.subscriptStyle,
|
||||
} : item.subscript,
|
||||
}));
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (list.length > 0 && data.display_style == 'slide') {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
if (data.row == 1 && new_style.rolling_fashion == 'translation') {
|
||||
// 拆分的数量
|
||||
list.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
} else {
|
||||
// 每页显示的数量
|
||||
const num = (data.single_line || 4) * (data.row || 1);
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(list.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: list.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
}
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: list,
|
||||
},
|
||||
];
|
||||
}
|
||||
},
|
||||
slideChange(e) {
|
||||
this.setData({
|
||||
actived_index: e.detail.current,
|
||||
});
|
||||
},
|
||||
url_open_event(link) {
|
||||
app.globalData.url_event(link);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.top-img {
|
||||
height: 72rpx;
|
||||
width: 72rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.gap-x-10 {
|
||||
row-gap: 20rpx;
|
||||
}
|
||||
</style>
|
||||
211
components/diy/notice.vue
Normal file
211
components/diy/notice.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<!-- 公告 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<template v-if="form_content.notice_style == 'inherit'">
|
||||
<view class="news-box" :style="container_background_style + container_height">
|
||||
<view class="flex-row align-c gap-8" :style="container_background_img_style">
|
||||
<template v-if="form_content.title_type == 'img-icon'">
|
||||
<view v-if="form_content.icon_class">
|
||||
<iconfont :name="'icon-' + form_content.icon_class" :size="form_style.icon_size * 2 + 'rpx'" :color="form_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
<view v-else>
|
||||
<image v-if="form_content.img_src.length > 0" :src="form_content.img_src[0].url" class="border-radius-sm dis-block" mode="aspectFill" :style="img_style"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :style="title_style" class="padding-horizontal-sm border-radius-sm">{{ form_content.title || '公告' }}</view>
|
||||
</template>
|
||||
<swiper class="swiper flex-1" circular :indicator-dots="false" :autoplay="true" :interval="interval_time" :vertical="direction_type == 'vertical'" :style="container_height">
|
||||
<swiper-item v-for="(item, index) in notice_list" :key="index">
|
||||
<view class="swiper-item flex-row align-c ht-auto" :style="content_title_style + 'color:' + form_style.news_color" :data-value="item.notice_link.page" @tap="url_event">
|
||||
<view class="text-line-1">{{ item.notice_title }}</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-if="form_content.is_right_button == '1'" class="flex-row align-c" :style="'color: ' + form_style.right_button_color + ';font-size:' + form_style.right_button_size * 2 + 'rpx;'" :data-value="form_content.more_link.page" @tap="url_event">
|
||||
{{ form_content.right_title }}
|
||||
<view class="pr">
|
||||
<iconfont name="icon-arrow-right" :color="form_style.right_button_color || '#999'" :size="form_style.right_button_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="news-card" :style="container_background_style">
|
||||
<view class="flex-col gap-10" :style="container_background_img_style">
|
||||
<view class="flex-row wh-auto jc-sb align-c">
|
||||
<template v-if="form_content.title_type == 'img-icon'">
|
||||
<template v-if="form_content.icon_class">
|
||||
<iconfont :name="'icon-' + form_content.icon_class" :size="form_style.icon_size * 2 + 'rpx'" :color="form_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</template>
|
||||
<template v-else>
|
||||
<image v-if="form_content.img_src.length > 0" :src="form_content.img_src[0].url" class="border-radius-sm dis-block" mode="aspectFill" :style="img_style"></image>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view :style="title_style" class="padding-horizontal-sm border-radius-sm">{{ form_content.title }}</view>
|
||||
</template>
|
||||
<view v-if="form_content.is_right_button == '1'" class="flex-row align-c" :style="'color: ' + form_style.right_button_color + ';font-size:' + form_style.right_button_size * 2 + 'rpx;'" :data-value="form_content.more_link.page" @tap="url_event">
|
||||
{{ form_content.right_title }}
|
||||
<view class="pr">
|
||||
<iconfont name="icon-arrow-right" :color="form_style.right_button_color || '#999'" :size="form_style.right_button_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(item, index) in notice_list" :key="index" class="flex-row" :style="content_title_style" :data-value="item.notice_link.page" @tap="url_event">
|
||||
<view class="num" :class="'one' + (index + 1)">{{ index + 1 }}</view>
|
||||
<view class="break" :style="'color:' + form_style.news_color">{{ item.notice_title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, gradient_handle, radius_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form_content: {},
|
||||
form_style: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
// 容器高度
|
||||
container_height: '',
|
||||
// 容器背景
|
||||
container_background_style: '',
|
||||
// 图片设置
|
||||
img_style: '',
|
||||
// 标题的设置
|
||||
title_style: '',
|
||||
// 内容标题设置
|
||||
content_title_style: '',
|
||||
// 指示器的样式
|
||||
// 轮播图定时显示
|
||||
interval_time: 2000,
|
||||
// 轮播图滚动方向 // vertical' | 'horizontal
|
||||
direction_type: 'vertical',
|
||||
// 记录当前显示的轮播图的数据
|
||||
interval_list: {
|
||||
time: 2000,
|
||||
direction: 'vertical',
|
||||
notice_length: 1,
|
||||
},
|
||||
// 公告数据
|
||||
notice_list: [],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 容器背景
|
||||
const { container_color_list, container_direction, container_background_img_style, container_background_img } = new_style;
|
||||
const temp_obj = {
|
||||
color_list: container_color_list,
|
||||
direction: container_direction,
|
||||
background_img: container_background_img,
|
||||
background_img_style: container_background_img_style,
|
||||
};
|
||||
const temp_container_background_style = gradient_computer(temp_obj) + radius_computer(new_style.container_radius) + `overflow:hidden;`;
|
||||
const temp_container_background_img_style = background_computer(temp_obj);
|
||||
// 标题渐变色处理
|
||||
const gradient = gradient_handle(new_style.title_color_list, '90deg');
|
||||
const time = (new_style.interval_time || 2) * 1000;
|
||||
const direction = new_content.direction;
|
||||
const new_notice_list = new_content.notice_list.filter((item) => item.is_show == '1');
|
||||
// 判断长度是否相等
|
||||
const notice_length = new_notice_list.length;
|
||||
const new_interval_list = {
|
||||
time: time,
|
||||
direction: direction,
|
||||
notice_length: notice_length,
|
||||
};
|
||||
this.setData({
|
||||
form_content: new_content,
|
||||
form_style: new_style,
|
||||
container_height: 'height:' + new_style.container_height * 2 + 'rpx',
|
||||
container_background_style: temp_container_background_style,
|
||||
container_background_img_style: temp_container_background_img_style,
|
||||
img_style: `height: ${new_style.title_height * 2}rpx; width: ${new_style.title_width * 2}rpx`,
|
||||
title_style: `color:${new_style.title_color}; font-size: ${new_style.title_size * 2}rpx; font-weight: ${new_style.title_typeface}; ${gradient}`,
|
||||
content_title_style: `font-size: ${new_style.news_size * 2}rpx; font-weight: ${new_style.news_typeface};`,
|
||||
notice_list: new_notice_list,
|
||||
interval_time: time,
|
||||
direction_type: direction,
|
||||
interval_list: new_interval_list,
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.news-box {
|
||||
overflow: hidden;
|
||||
padding: 0 20rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.news-card {
|
||||
padding: 30rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.num {
|
||||
padding-right: 14rpx;
|
||||
color: #999;
|
||||
}
|
||||
.one1 {
|
||||
color: #ea3323;
|
||||
}
|
||||
.one2 {
|
||||
color: #ff7303;
|
||||
}
|
||||
.one3 {
|
||||
color: #ffc300;
|
||||
}
|
||||
.two-style {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
}
|
||||
.break {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
73
components/diy/rich-text.vue
Normal file
73
components/diy/rich-text.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<!-- 富文本 -->
|
||||
<view class="diy-rich-text" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<mp-html :content="content" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
content: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
this.setData({
|
||||
content: new_content.html,
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.diy-rich-text {
|
||||
* {
|
||||
max-width: 100%;
|
||||
}
|
||||
/* #ifdef H5 */
|
||||
[id^=v] {
|
||||
width: 100%;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
.diy-rich-text video {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
327
components/diy/search.vue
Normal file
327
components/diy/search.vue
Normal file
@@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="search wh-auto pr">
|
||||
<view class="box oh flex-row align-c" :style="box_style">
|
||||
<view v-if="form.positioning_name_float == '1' && propSearchType == 'header'" :style="propLocationMargin">
|
||||
<component-choice-location propType="search" :propLocationContainerStyle="propLocationContainerStyle" :propLocationImgContainerStyle="propLocationImgContainerStyle" :propBaseColor="propBaseColor" :propTextDefaultName="form.positioning_name" :propIsLeftIconArrow="form.is_location_left_icon_show == '1'" :propLeftImgValue="form.location_left_img" :propLeftIconValue="'icon-' + form.location_left_icon" :propIconLocationSize="propIconLocationSize" :propIconArrowSize="propIconArrowSize" :propIsRightIconArrow="form.is_location_right_icon_show == '1'" :propRightImgValue="form.location_right_img" :propRightIconValue="'icon-' + form.location_right_icon" :propTextMaxWidth="['4'].includes(form.theme) ? '300rpx' : '200rpx'" propContainerDisplay="flex" @onBack.stop="choice_location_back"></component-choice-location>
|
||||
</view>
|
||||
<view :class="'oh flex-1 ht-auto flex-row align-c gap-10' + (form.is_center == '1' ? ' tips-float' : '')" @tap.stop="search_tap">
|
||||
<view v-if="form.is_icon_show == '1'" class="pr">
|
||||
<view class="search-icon-before" :style="(form.positioning_name_float == '1' && propSearchType == 'header') || form.is_center == '1' ? '' : 'left: -' + (new_style.search_padding_left ? new_style.search_padding_left * 2 : 30) + 'rpx;'" @tap.stop="search_icon_tap"></view>
|
||||
<view class="wh-auto ht-auto">
|
||||
<template v-if="form.icon_img.length > 0">
|
||||
<view class="img-box">
|
||||
<image :src="form.icon_img[0].url" class="img" mode="heightFix"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view>
|
||||
<iconfont :name="!isEmpty(form.icon_class) ? 'icon-' + form.icon_class : 'icon-search-max'" size="28rpx" :color="new_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!isEmpty(form.hot_word_list) && form.is_hot_word_show == '1'" :style="form.is_center == '1' ? `min-width:100px;` : 'width:100%;'">
|
||||
<swiper circular="true" :autoplay="new_style.is_roll == '1'" :interval="new_style.interval_time * 1000" :vertical="true" :duration="500" class="swiper_style" @change="slideChange">
|
||||
<swiper-item v-for="(item, index) in form.hot_word_list" :key="index">
|
||||
<view class="flex-row align-c wh-auto ht-auto" :style="{ color: !isEmpty(item.color) ? item.color : !isEmpty(new_style.hot_words_color) ? new_style.hot_words_color : '#999' }" :data-value="item.value" @tap.stop="serch_event">
|
||||
{{ item.value }}
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
<template v-else>
|
||||
<text v-if="form.is_tips_show == '1'" :class="[propIsPageSettings ? 'text-size-xs text-line-1' : 'text-size-md text-line-1']" :style="'color:' + new_style.tips_color">{{ form.tips }}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row align-c pa search-outer-botton oh" :style="right_icon_style">
|
||||
<view v-if="form.is_right_icon_show == '1' && (form.right_icon_img.length > 0 || !isEmpty(form.right_icon_class))" class="pr margin-right-main">
|
||||
<view class="search-icon-before" @tap.stop="search_right_icon_tap"></view>
|
||||
<view class="wh-auto ht-auto">
|
||||
<template v-if="form.right_icon_img.length > 0">
|
||||
<view class="img-box right_icon_height flex-row align-c">
|
||||
<image :src="form.right_icon_img[0].url" class="img" mode="heightFix"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="right_icon_height flex-row align-c">
|
||||
<iconfont :name="!isEmpty(form.right_icon_class) ? 'icon-' + form.right_icon_class : 'icon-search-max'" size="28rpx" :color="new_style.right_icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.is_search_show == '1'" class="flex-row align-c jc-c">
|
||||
<view class="search-botton flex-row align-c jc-c z-i" :style="search_button_style" @tap.stop="serch_button_event">
|
||||
<view class="oh" :style="search_button_img_style">
|
||||
<template v-if="form.search_type === 'text'">
|
||||
<view class="text-size-xs">{{ form.search_tips }}</view>
|
||||
</template>
|
||||
<template v-else-if="!isEmpty(form.search_botton_img) && form.search_botton_img.length > 0">
|
||||
<image :src="form.search_botton_img[0].url" class="img" :style="search_button_height" mode="heightFix"></image>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="text-size-xs">
|
||||
<iconfont :name="!isEmpty(form.search_botton_icon) ? 'icon-' + form.search_botton_icon : ''" size="28rpx" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import componentChoiceLocation from '@/components/choice-location/choice-location';
|
||||
const app = getApp();
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, radius_computer, isEmpty, padding_computer, old_padding, old_radius, margin_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
components: {
|
||||
componentChoiceLocation,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propIsPageSettings: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propSearchType: {
|
||||
type: String,
|
||||
default: 'search',
|
||||
},
|
||||
propBaseColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propLocationMargin: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propLocationContainerStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propLocationImgContainerStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIconLocationSize: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIconArrowSize: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search_content: '',
|
||||
form: {},
|
||||
new_style: {},
|
||||
style: '',
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
search_button_radius: '',
|
||||
box_style: '',
|
||||
keywords: '',
|
||||
right_icon_style: '',
|
||||
search_button_style: '',
|
||||
search_button_img_style: '',
|
||||
search_button_height: '',
|
||||
button_padding: { padding: 0, padding_bottom: 3, padding_left: 12, padding_right: 12, padding_top: 3 },
|
||||
button_margin: { margin: 0, margin_bottom: 2, margin_left: 0, margin_right: 2, margin_top: 2 },
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
const { search_button_radius, common_style } = new_style;
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
search_button_img_style: this.get_search_button_img_style(new_style),
|
||||
search_button_height: this.get_search_button_height(new_style),
|
||||
// style: this.get_style(new_style), // 内部样式
|
||||
style_container: this.propIsPageSettings ? '' : common_styles_computer(common_style), // 全局样式
|
||||
style_img_container: this.propIsPageSettings ? '' : common_img_computer(common_style, this.propIndex),
|
||||
search_button_radius: radius_computer(search_button_radius), // 按钮圆角
|
||||
box_style: this.get_box_style(new_style, new_form), // 搜索框设置
|
||||
search_box_style: `border: 2rpx solid ${new_style.search_border == '#fff' ? '#eee' : new_style.search_border};`,
|
||||
search_button_style: this.get_search_button_style(new_form, new_style), // 搜索按钮显示
|
||||
right_icon_style: `border-radius: 0px ${ new_style.search_border_radius?.radius_top_right * 2 || 0 }rpx ${ new_style.search_border_radius?.radius_bottom_right * 2 || 0 }rpx 0px;`,
|
||||
});
|
||||
},
|
||||
get_search_button_style(form, new_style) {
|
||||
const { search_botton_color_list = [], search_botton_direction, search_botton_background_img_style, search_button_radius = old_radius, search_botton_background_img, search_botton_margin = this.button_margin, search_botton_border_show = '0', search_botton_border_size = old_padding, search_botton_border_style = 'solid', search_botton_border_color = '' } = new_style;
|
||||
let style = radius_computer(search_button_radius);
|
||||
if (form.search_type != 'img') {
|
||||
const data = {
|
||||
color_list: search_botton_color_list,
|
||||
direction: search_botton_direction,
|
||||
background_img: search_botton_background_img,
|
||||
background_img_style: search_botton_background_img_style,
|
||||
}
|
||||
style += gradient_computer(data) + margin_computer(search_botton_margin) + `color: ${ new_style.button_inner_color };`;
|
||||
}
|
||||
let border = ``;
|
||||
if (search_botton_border_show == '1') {
|
||||
border += `border-width: ${search_botton_border_size.padding_top * 2}rpx ${search_botton_border_size.padding_right * 2}rpx ${search_botton_border_size.padding_bottom * 2}rpx ${search_botton_border_size.padding_left * 2}rpx;border-style: ${ search_botton_border_style };border-color: ${search_botton_border_color};`
|
||||
}
|
||||
const height = 32 - search_botton_margin.margin_top - search_botton_margin.margin_bottom - search_botton_border_size.padding_top - search_botton_border_size.padding_bottom;
|
||||
return style + border + `height: ${height > 0 ? height * 2 : 0}rpx;line-height: ${height > 0 ? height * 2 : 0}rpx;`;
|
||||
},
|
||||
get_search_button_height(new_style) {
|
||||
const { search_botton_border_size = old_padding, search_botton_padding = this.button_padding } = new_style;
|
||||
const height = 32 - search_botton_border_size.padding_top - search_botton_border_size.padding_bottom - search_botton_padding.padding_top - search_botton_padding.padding_bottom;
|
||||
return `height: ${height > 0 ? height * 2 : 0}rpx !important;line-height: ${height > 0 ? height * 2 : 0}rpx;`;
|
||||
},
|
||||
// 搜索按钮圆角
|
||||
get_search_button_img_style(new_style) {
|
||||
const { search_botton_background_img_style, search_botton_background_img } = new_style;
|
||||
const data = {
|
||||
background_img: search_botton_background_img,
|
||||
background_img_style: search_botton_background_img_style,
|
||||
}
|
||||
return background_computer(data) + padding_computer(new_style?.search_botton_padding || this.button_padding) + 'box-sizing: border-box;';
|
||||
},
|
||||
// get_style(new_style) {
|
||||
// let common_styles = '';
|
||||
// if (new_style.text_style == 'italic') {
|
||||
// common_styles += `font-style: italic`;
|
||||
// } else if (new_style.text_style == '500') {
|
||||
// common_styles += `font-weight: 500`;
|
||||
// }
|
||||
// return common_styles;
|
||||
// },
|
||||
get_box_style(new_style, form) {
|
||||
let style = `background: ${ new_style?.search_bg_color || '' };border: 2rpx solid ${new_style.search_border}; ${radius_computer(new_style.search_border_radius)};box-sizing: border-box;`;
|
||||
if (form.positioning_name_float == '1' && this.propSearchType == 'header') {
|
||||
style += `padding-left: ${ (new_style.search_padding_left? new_style.search_padding_left : 15) * 2 }rpx;`;
|
||||
} else if (form.is_center != '1') {
|
||||
style += `padding-left: ${ (new_style.search_padding_left ? new_style.search_padding_left : 15) * 2 }rpx;`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
search_tap() {
|
||||
app.globalData.url_open('/pages/goods-search-start/goods-search-start?keywords=' + this.keywords);
|
||||
},
|
||||
serch_event() {
|
||||
app.globalData.url_open('/pages/goods-search-start/goods-search-start?keywords=' + this.keywords);
|
||||
},
|
||||
serch_button_event() {
|
||||
if (!isEmpty(this.keywords)) {
|
||||
app.globalData.url_open('pages/goods-search/goods-search?keywords=' + this.keywords);
|
||||
}
|
||||
app.globalData.url_open('/pages/goods-search-start/goods-search-start?keywords=' + this.keywords);
|
||||
},
|
||||
search_icon_tap() {
|
||||
if (isEmpty(this.form.icon_link)) {
|
||||
this.search_tap();
|
||||
return;
|
||||
}
|
||||
app.globalData.url_open(this.form.icon_link.page);
|
||||
},
|
||||
search_right_icon_tap() {
|
||||
if (isEmpty(this.form.right_icon_link)) {
|
||||
this.search_tap();
|
||||
return;
|
||||
}
|
||||
app.globalData.url_open(this.form.right_icon_link.page);
|
||||
},
|
||||
slideChange(e) {
|
||||
let actived_index = e.detail.current;
|
||||
this.setData({
|
||||
keywords: this.form.hot_word_list[actived_index].value,
|
||||
})
|
||||
},
|
||||
// 位置回调
|
||||
onBack(e) {
|
||||
this.$emit('onBack', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
.box {
|
||||
height: 64rpx;
|
||||
// padding: 12rpx 30rpx;
|
||||
}
|
||||
.swiper_style {
|
||||
height: 64rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.img-box {
|
||||
height: 100%;
|
||||
.img {
|
||||
height: 36rpx;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.search-outer-botton {
|
||||
height: 64rpx;
|
||||
top: 0;
|
||||
right: 0;
|
||||
.search-botton {
|
||||
height: 64rpx;
|
||||
.img {
|
||||
height: 64rpx;
|
||||
min-width: 6rpx;
|
||||
max-width: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right_icon_height {
|
||||
position: relative;
|
||||
height: 56rpx !important;
|
||||
}
|
||||
.search-icon {
|
||||
position: relative;
|
||||
}
|
||||
.search-icon-before {
|
||||
position: absolute;
|
||||
z-index: 10; // 确保悬浮在内容上层
|
||||
top: -20rpx;
|
||||
right: -20rpx;
|
||||
bottom: -20rpx;
|
||||
left: -20rpx
|
||||
}
|
||||
.tips-float {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
643
components/diy/seckill.vue
Normal file
643
components/diy/seckill.vue
Normal file
@@ -0,0 +1,643 @@
|
||||
<template>
|
||||
<view v-if="!isEmpty(list) || !isEmpty(sckill_list)" :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="flex-col gap-10">
|
||||
<view v-if="form.head_state == '1'" class="oh" :style="seckill_head_style">
|
||||
<view class="seckill-head flex-row align-c jc-sb" :style="seckill_head_img_style">
|
||||
<view :class="['flex-row align-c', { 'gap-10': form.theme != '1', 'jc-sb wh-auto': form.theme == '2' }]">
|
||||
<view class="seckill-title">
|
||||
<imageEmpty v-if="form.title_type == 'image'" :propImageSrc="form.title_src[0]" propImgFit="heightFix" propErrorStyle="width:42rpx; height: 20rpx;"></imageEmpty>
|
||||
<text v-else :style="{ color: new_style.title_color, 'font-size': new_style.title_size * 2 + 'rpx', 'line-height': '42rpx', 'font-weight': 600 }">{{ form.title_text }}</text>
|
||||
</view>
|
||||
<view v-if="form.theme == '1'" class="padding-horizontal-sm cr-white">|</view>
|
||||
<view v-if="intervalId != undefined" class="flex-row align-c gap-4">
|
||||
<text class="text-size-xss" :style="{ color: new_style.end_text_color }">{{ seckill_time.time_first_text }}</text>
|
||||
<view class="flex-row gap-3 jc-c align-c" :style="form.theme == '4' ? time_bg + 'padding: 6rpx 8rpx;border-radius: 22rpx;' : ''">
|
||||
<image v-if="form.theme == '4' && form.theme_4_static_img.length > 0" class="seckill-head-icon radius-xs" :src="form.theme_4_static_img[0].url" />
|
||||
<view v-for="(item, index) in time_config" :key="item.key" class="flex-row gap-3 jc-c align-c">
|
||||
<template v-if="form.theme == '4'">
|
||||
<view class="text-size-xs flex-row jc-c align-c" :style="'min-width:50rpx;color:' + new_style.countdown_color">{{ item.value }}</view>
|
||||
<text v-if="[0, 1].includes(index)" class="colon" :style="{ color: new_style.countdown_color }">:</text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="time-config text-size-xs flex-row jc-c align-c" :style="time_bg + 'min-width:50rpx;color:' + new_style.countdown_color">{{ item.value }}</view>
|
||||
<text v-if="[0, 1].includes(index)" class="colon" :style="icon_time_check">:</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="flex-row align-c gap-4">
|
||||
<text class="text-size-xss" :style="{ color: new_style.end_text_color }">已结束</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.button_status == '1'" class="flex-row align-c" :style="{ color: new_style.head_button_color }" :data-value="'/pages/plugins/seckill/index/index'" @tap="url_event">
|
||||
<text :style="{ 'font-size': new_style.head_button_size * 2 + 'rpx' }">{{ form.button_text }}</text>
|
||||
<iconfont name="icon-arrow-right" :color="new_style.head_button_color" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="oh" :style="shop_container">
|
||||
<view class="oh" :style="shop_img_container">
|
||||
<template v-if="form.shop_style_type != '3'">
|
||||
<view class="flex-row flex-wrap wh-auto ht-auto" :style="{ gap: content_outer_spacing }">
|
||||
<view v-for="(item, index) in sckill_list" :key="index" :style="layout_style + layout_type_style + content_radius" :data-value="item.goods_url" @tap="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<template v-if="!isEmpty(item)">
|
||||
<view class="oh pr">
|
||||
<view v-if="!isEmpty(item.new_cover)" :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else :style="img_size">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('original_price') || form.is_shop_show == '1'" class="flex-col gap-10 wh-auto flex-1 jc-sb oh" :style="content_style">
|
||||
<view class="flex-col gap-10 wh-auto">
|
||||
<!-- 标题 -->
|
||||
<view v-if="is_show('title') || is_show('simple_desc')" class="flex-col" :style="{'gap': new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :style="title_style" class="text-line-2">{{ item.title }}</view>
|
||||
<view v-if="is_show('simple_desc')" class="text-line-1" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<!-- 进度条 -->
|
||||
<!-- <view v-if="form.shop_style_type == '1'" class="flex-row align-c gap-6">
|
||||
<view class="re flex-1">
|
||||
<view class="slide-bottom" :style="`background: ${new_style.progress_bg_color}`"></view>
|
||||
<view class="slide-top" :style="` width: 51%; ${slide_active_color}`">
|
||||
<view class="slide-top-icon round" :style="`background: ${new_style.progress_button_color}`"><icon name="a-miaosha" :color="new_style.progress_button_icon_color" size="9"></icon></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="text-size-xss" :style="`color: ${new_style.progress_text_color}`">已抢51%</text>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="flex-row align-e gap-10 jc-sb">
|
||||
<view class="flex-col gap-5">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="{ color: new_style.shop_price_color }">
|
||||
<text v-if="form.shop_style_type == '1'" class="text-size-xss pr-4">{{ form.seckill_pirce_title ? form.seckill_pirce_title : ''}}</text>
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="is_show('original_price') && !isEmpty(item.min_original_price)" class="size-11 flex" :style="original_price">
|
||||
<text class="original-price text-line-1 flex-1">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<template v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</template>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.is_shop_show == '1'">
|
||||
<template v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + 'color:' + new_style.shop_button_text_color">{{ form.shop_button_text }}</view>
|
||||
</template>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :styles="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<swiper circular="false" :autoplay="new_style.is_roll == '1'" :next-margin="new_style.rolling_fashion == 'translation' ? '-' + content_outer_spacing_magin : '0rpx'" :interval="new_style.interval_time * 1000" :duration="500" :display-multiple-items="slides_per_group" :style="{ height: new_style.content_outer_height * 2 + 'rpx' }">
|
||||
<swiper-item v-for="(item1, index1) in list" :key="index1">
|
||||
<view class="wh-auto ht-auto" :class="{ 'flex-row': new_style.rolling_fashion != 'translation' }" :style="new_style.rolling_fashion != 'translation' ? 'gap:' + content_outer_spacing_magin : ''">
|
||||
<view v-for="(item, index) in item1.split_list" :key="index" :style="layout_style + content_radius + (new_style.rolling_fashion != 'translation' ? layout_type_style : 'margin-right:' + content_outer_spacing_magin + ';height: 100%;whith: 100%')" :data-value="item.goods_url" @tap="url_event">
|
||||
<view :class="layout_type" :style="layout_img_style">
|
||||
<template v-if="!isEmpty(item)">
|
||||
<view class="oh pr wh-auto ht-auto">
|
||||
<view v-if="!isEmpty(item.new_cover)" class="wh-auto ht-auto">
|
||||
<imageEmpty :propImageSrc="item.new_cover[0]" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<view v-else class="wh-auto ht-auto">
|
||||
<imageEmpty :propImageSrc="item.images" :propStyle="content_img_radius" propErrorStyle="width:100rpx; height: 100rpx;"></imageEmpty>
|
||||
</view>
|
||||
<!-- 角标 -->
|
||||
<subscriptIndex :propValue="propValue"></subscriptIndex>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="is_show('title') || is_show('simple_desc') || is_show('price') || is_show('original_price') || form.is_shop_show == '1'" class="flex-col gap-10 wh-auto flex-1 jc-sb" :style="content_style">
|
||||
<view class="flex-col gap-10 wh-auto">
|
||||
<!-- 标题 -->
|
||||
<view v-if="is_show('title') || is_show('simple_desc')" class="flex-col" :style="{'gap': new_style.title_simple_desc_spacing * 2 + 'rpx' }">
|
||||
<view v-if="is_show('title')" :style="title_style" class="text-line-2">{{ item.title }}</view>
|
||||
<view v-if="is_show('simple_desc')" class="text-line-1" :style="simple_desc">{{ item.simple_desc }}</view>
|
||||
</view>
|
||||
<!-- 进度条 -->
|
||||
<!-- <view v-if="form.shop_style_type == '1'" class="flex-row align-c gap-6">
|
||||
<view class="re flex-1">
|
||||
<view class="slide-bottom" :style="{ 'background': new_style.progress_bg_color }"></view>
|
||||
<view class="slide-top" :style="'width: 51%;' + slide_active_color ">
|
||||
<view class="slide-top-icon round" :style="{ 'background': new_style.progress_button_color}"><icon name="a-miaosha" :color="new_style.progress_button_icon_color" size="9"></icon></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="text-size-xss" :style="{ 'color': new_style.progress_text_color }">已抢51%</text>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="flex-row align-e gap-10 jc-sb">
|
||||
<view class="flex-col gap-5">
|
||||
<view v-if="is_show('price') && !isEmpty(item.min_price)" class="num" :style="{ color: new_style.shop_price_color }">
|
||||
<text v-if="form.shop_style_type == '1'" class="text-size-xss pr-4">{{ form.seckill_pirce_title ? form.seckill_pirce_title : ''}}</text>
|
||||
<text :style="price_symbol">{{ item.show_price_symbol }}</text>
|
||||
<text :style="price_style">{{ item.min_price }}</text>
|
||||
<text v-if="is_show('price_unit')" :style="price_unit">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="is_show('original_price') && !isEmpty(item.min_original_price)" class="size-11 flex" :style="original_price">
|
||||
<text class="original-price text-line-1 flex-1">
|
||||
{{ item.show_original_price_symbol }}{{ item.min_original_price }}
|
||||
<template v-if="is_show('original_price_unit')">
|
||||
{{ item.show_original_price_unit }}
|
||||
</template>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="form.is_shop_show == '1'">
|
||||
<template v-if="form.shop_type == 'text'">
|
||||
<view class="plr-11 padding-vertical-xs round" :style="button_style + 'color:' + new_style.shop_button_text_color">{{ form.shop_button_text }}</view>
|
||||
</template>
|
||||
<view v-else class="round padding-horizontal-sm ptb-5" :styles="button_gradient">
|
||||
<iconfont :name="'icon-' + (!isEmpty(form.shop_button_icon_class) ? form.shop_button_icon_class : 'cart')" :color="new_style.shop_icon_color" :size="new_style.shop_icon_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, gradient_handle, padding_computer, radius_computer, isEmpty, margin_computer, box_shadow_computer, border_computer, old_margin, old_border_and_box_shadow } from '@/common/js/common/common.js';
|
||||
import imageEmpty from '@/components/diy/modules/image-empty.vue';
|
||||
import subscriptIndex from '@/components/diy/modules/subscript/index.vue';
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var sys_width = app.globalData.window_width_handle(system.windowWidth);
|
||||
export default {
|
||||
components: {
|
||||
imageEmpty,
|
||||
subscriptIndex
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
time_bg: '',
|
||||
slide_active_color: '',
|
||||
seckill_head_style: '',
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
time_config: [
|
||||
{ key: 'hour', value: '00' },
|
||||
{ key: 'minute', value: '00' },
|
||||
{ key: 'second', value: '00' },
|
||||
],
|
||||
seckill_time: {},
|
||||
// 商品间距
|
||||
content_outer_spacing: '',
|
||||
content_outer_spacing_magin: '',
|
||||
// 圆角设置
|
||||
content_radius: '',
|
||||
// 内边距设置
|
||||
content_padding: '',
|
||||
// 内容区域的样式
|
||||
content_style: '',
|
||||
// 不同风格下的样式
|
||||
img_size: '',
|
||||
layout_type: '',
|
||||
layout_type_style: '',
|
||||
layout_img_style: '',
|
||||
layout_style: '',
|
||||
//图片圆角设置
|
||||
content_img_radius: '',
|
||||
//角标设置
|
||||
corner_marker: '',
|
||||
// 定时器
|
||||
intervalId: null,
|
||||
// 数据存储
|
||||
list: [],
|
||||
// 一屏显示的数量
|
||||
slides_per_group: '',
|
||||
// 内容样式
|
||||
title_style: '',
|
||||
price_style: '',
|
||||
button_style: '',
|
||||
simple_desc: '',
|
||||
price_symbol: '',
|
||||
price_unit: '',
|
||||
original_price: '',
|
||||
shop_container: '',
|
||||
shop_img_container: '',
|
||||
// 商品列表
|
||||
sckill_list: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
icon_time_check() {
|
||||
return `${this.time_bg};line-height: 1;background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;`;
|
||||
},
|
||||
// 按钮渐变色处理
|
||||
button_gradient() {
|
||||
return gradient_handle(this.new_style.shop_button_color, '180deg');
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 如果有定时任务执行,在离开的时候清空掉定时任务
|
||||
if (!isEmpty(this.intervalId)) {
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
const data = new_form.data;
|
||||
let new_list = [];
|
||||
if (data && !isEmpty(data.current)) {
|
||||
if (!isEmpty(data.current.goods)) {
|
||||
new_list = data.current.goods;
|
||||
}
|
||||
const { status, time_first_text } = data.current.time;
|
||||
this.setData({
|
||||
seckill_time: {
|
||||
time_end_number: Number(data.current.time_end_number + '000'),
|
||||
time_start_number: Number(data.current.time_start_number + '000'),
|
||||
status: status,
|
||||
time_first_text: time_first_text,
|
||||
},
|
||||
});
|
||||
// 先执行一次倒计时,后续的等待倒计时执行
|
||||
setTimeout(() => {
|
||||
this.updateCountdown();
|
||||
}, 0);
|
||||
this.setData({
|
||||
intervalId: setInterval(this.updateCountdown, 1000),
|
||||
});
|
||||
}
|
||||
// 默认数据
|
||||
const product_style_list = [
|
||||
{ name: '单列', value: '1', width: 110, height: 120 },
|
||||
{ name: '双列', value: '2', width: 180, height: 180 },
|
||||
{ name: '横向滑动', value: '3', width: 0, height: 0 },
|
||||
];
|
||||
const scale = sys_width / 390;
|
||||
let img_style = ``;
|
||||
if (['1'].includes(new_form.shop_style_type)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_width == 'number') {
|
||||
img_style += `width: ${ new_style.content_img_width * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.shop_style_type);
|
||||
if (list.length > 0) {
|
||||
img_style += `width: ${ list[0].width * scale }px;`;
|
||||
} else {
|
||||
img_style += 'width: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!['3'].includes(new_form.shop_style_type)) {
|
||||
// 图片宽度
|
||||
if (typeof new_style.content_img_height == 'number') {
|
||||
img_style += `height: ${ new_style.content_img_height * scale }px;`;
|
||||
} else {
|
||||
const list = product_style_list.filter(item => item.value == new_form.shop_style_type);
|
||||
if (list.length > 0) {
|
||||
img_style += `height: ${ list[0].height * scale }px;`;
|
||||
} else {
|
||||
img_style += 'height: auto;';
|
||||
}
|
||||
}
|
||||
}
|
||||
const shop_style = new_style?.shop_style || old_border_and_box_shadow;
|
||||
this.setData({
|
||||
form: this.propValue.content,
|
||||
new_style: this.propValue.style,
|
||||
time_bg: this.get_time_bg(new_style),
|
||||
slide_active_color: this.get_slide_active_color(new_style),
|
||||
seckill_head_style: this.get_seckill_head_style(new_style, '1'),
|
||||
seckill_head_img_style: this.get_seckill_head_style(new_style, '2'),
|
||||
style_container: common_styles_computer(new_style.common_style) + 'box-sizing: border-box;',
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
content_outer_spacing: new_style.content_outer_spacing + 'px',
|
||||
content_outer_spacing_magin: new_style.content_outer_spacing * 2 + 'rpx',
|
||||
content_radius: radius_computer(new_style.shop_radius),
|
||||
content_padding: padding_computer(new_style.shop_padding) + 'box-sizing: border-box;',
|
||||
content_style: this.get_content_style(new_style, new_form),
|
||||
layout_type: new_form.shop_style_type == '1' ? 'flex-row wh-auto ht-auto oh' : 'flex-col wh-auto ht-auto oh',
|
||||
layout_img_style: this.get_layout_img_style(new_style, new_form),
|
||||
layout_type_style: this.get_layout_type_style(new_style, new_form),
|
||||
layout_style: gradient_handle(new_style.shop_color_list, new_style.shop_direction) + margin_computer(new_style?.shop_margin || old_margin) + border_computer(shop_style) + box_shadow_computer(shop_style),
|
||||
content_img_radius: radius_computer(new_style.shop_img_radius),
|
||||
corner_marker: this.get_corner_marker(new_style),
|
||||
slides_per_group: new_style.rolling_fashion == 'translation' ? new_form.carousel_col : 1,
|
||||
// 内容样式设置
|
||||
title_style: this.trends_config(new_style, 'title', 'title'),
|
||||
price_style: this.trends_config(new_style, 'price'),
|
||||
button_style: this.trends_config(new_style, 'button', 'gradient'),
|
||||
simple_desc: this.trends_config(new_style, 'simple_desc', 'desc'),
|
||||
price_symbol: !isEmpty(new_style.shop_price_symbol_color) ? this.trends_config(new_style, 'price_symbol') : 'font-size: 18rpx;color: #EA3323;' ,
|
||||
price_unit: !isEmpty(new_style.shop_price_unit_color) ? this.trends_config(new_style, 'price_unit') : 'font-size: 18rpx;color: #EA3323;',
|
||||
original_price: this.trends_config(new_style, 'original_price'),
|
||||
list: this.get_shop_content_list(new_list, new_form, new_style),
|
||||
shop_container: this.get_shop_container(new_style),
|
||||
shop_img_container: this.get_shop_img_container(new_style),
|
||||
sckill_list: new_list,
|
||||
img_size: img_style,
|
||||
});
|
||||
},
|
||||
// 商品内容区域显示
|
||||
get_shop_container(new_style){
|
||||
const { shop_content_color_list = [], shop_content_direction = '', shop_content_radius = old_radius, shop_content_margin = old_margin, shop_content = old_border_and_box_shadow } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: shop_content_color_list, direction: shop_content_direction };
|
||||
return gradient_computer(gradient) + radius_computer(shop_content_radius) + margin_computer(shop_content_margin) + border_computer(shop_content) + box_shadow_computer(shop_content);
|
||||
},
|
||||
get_shop_img_container (new_style) {
|
||||
const { shop_content_background_img_style = '2', shop_content_background_img = [], shop_content_padding = old_padding } = new_style;
|
||||
// 背景图
|
||||
const back = { background_img: shop_content_background_img, background_img_style: shop_content_background_img_style };
|
||||
return padding_computer(shop_content_padding) + background_computer(back);
|
||||
},
|
||||
get_shop_content_list(list, form, new_style) {
|
||||
// 深拷贝一下,确保不会出现问题
|
||||
const cloneList = JSON.parse(JSON.stringify(list));
|
||||
if (new_style.rolling_fashion != 'translation') {
|
||||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||||
if (cloneList.length > 0) {
|
||||
// 每页显示的数量
|
||||
const num = form.carousel_col;
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
// 拆分的数量
|
||||
const split_num = Math.ceil(cloneList.length / num);
|
||||
for (let i = 0; i < split_num; i++) {
|
||||
nav_list.push({
|
||||
split_list: cloneList.slice(i * num, (i + 1) * num),
|
||||
});
|
||||
}
|
||||
return nav_list;
|
||||
} else {
|
||||
// 否则的话,就返回全部的信息
|
||||
return [
|
||||
{
|
||||
split_list: cloneList,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 存储数据显示
|
||||
let nav_list = [];
|
||||
cloneList.forEach((item) => {
|
||||
nav_list.push({
|
||||
split_list: [item],
|
||||
});
|
||||
});
|
||||
return nav_list;
|
||||
}
|
||||
},
|
||||
get_time_bg(new_style) {
|
||||
const { countdown_bg_color_list, countdown_direction } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: countdown_bg_color_list, direction: countdown_direction };
|
||||
return gradient_computer(gradient);
|
||||
},
|
||||
get_slide_active_color(new_style) {
|
||||
const { progress_actived_color_list, progress_actived_direction } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: progress_actived_color_list, direction: progress_actived_direction };
|
||||
return gradient_computer(gradient);
|
||||
},
|
||||
get_seckill_head_style(new_style, num) {
|
||||
const { header_background_img, header_background_img_style, header_background_color_list, header_background_direction, seckill_head_padding, seckill_head_radius, seckill_head_margin = old_margin, seckill_head_style = old_border_and_box_shadow } = new_style;
|
||||
// 渐变
|
||||
const gradient = { color_list: header_background_color_list, direction: header_background_direction };
|
||||
// 背景图
|
||||
const back = { background_img: header_background_img, background_img_style: header_background_img_style };
|
||||
if (num == '1') {
|
||||
return gradient_computer(gradient) + radius_computer(seckill_head_radius) + margin_computer(seckill_head_margin) + border_computer(seckill_head_style) + box_shadow_computer(seckill_head_style);
|
||||
} else {
|
||||
// 秒杀头部内间距设置, 没有的时候默认15px
|
||||
const padding = !isEmpty(seckill_head_padding) ? seckill_head_padding : { padding: 0, padding_top: 15, padding_bottom: 15, padding_left: 13, padding_right: 13};
|
||||
return background_computer(back) + padding_computer(padding) + 'box-sizing: border-box;';
|
||||
}
|
||||
},
|
||||
updateCountdown() {
|
||||
let time_end_number = this.seckill_time.time_end_number;
|
||||
if (this.seckill_time.status === 0) {
|
||||
time_end_number = this.seckill_time.time_start_number;
|
||||
}
|
||||
// 先获取秒杀结束时间和当前时间的差值
|
||||
const distance = time_end_number - new Date().getTime();
|
||||
// 如果倒计时结束,显示结束信息
|
||||
if (distance <= 1000) {
|
||||
clearInterval(this.intervalId);
|
||||
// 如果是待开始状态,则显示开始倒计时,并且在结束的时候根据结束时候再执行一个定时器
|
||||
if (this.seckill_time.status === 0) {
|
||||
this.setData({
|
||||
seckill_time: {
|
||||
time_end_number: this.seckill_time.time_end_number,
|
||||
time_start_number: this.seckill_time.time_start_number,
|
||||
status: 1,
|
||||
time_first_text: '距结束',
|
||||
},
|
||||
});
|
||||
// 先执行一次倒计时,后续的等待倒计时执行
|
||||
setTimeout(() => {
|
||||
this.updateCountdown();
|
||||
}, 0);
|
||||
this.setData({
|
||||
intervalId: setInterval(this.updateCountdown, 1000),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 计算时间
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
this.time_config.forEach((item) => {
|
||||
if (item.key == 'hour') {
|
||||
item.value = hours < 10 ? '0' + hours : hours.toString();
|
||||
} else if (item.key == 'minute') {
|
||||
item.value = minutes < 10 ? '0' + minutes : minutes.toString();
|
||||
} else if (item.key == 'second') {
|
||||
item.value = seconds < 10 ? '0' + seconds : seconds.toString();
|
||||
}
|
||||
});
|
||||
},
|
||||
get_content_style(new_style, form) {
|
||||
const spacing_value = new_style.content_spacing;
|
||||
let spacing = '';
|
||||
if (form.shop_style_type == '1') {
|
||||
spacing = `margin-left: ${spacing_value * 2}rpx;`;
|
||||
} else {
|
||||
spacing = padding_computer(new_style.shop_padding) + 'box-sizing: border-box;';
|
||||
}
|
||||
return `${spacing}`;
|
||||
},
|
||||
get_layout_type_style(new_style, form) {
|
||||
return ['1', '2'].includes(form.shop_style_type) ? `height: 100%;width: ${this.get_multicolumn_columns_width(new_style, form)};min-width: ${this.get_multicolumn_columns_width(new_style, form)};` : `height: ${new_style.content_outer_height * 2}rpx;width: ${this.get_multicolumn_columns_width(new_style, form)};min-width: ${this.get_multicolumn_columns_width(new_style, form)};`;
|
||||
},
|
||||
get_layout_img_style(new_style, form) {
|
||||
const padding = ['1'].includes(form.shop_style_type) ? padding_computer(new_style.shop_padding) + 'box-sizing: border-box;' : '';
|
||||
const data = {
|
||||
background_img_style: new_style.shop_background_img_style,
|
||||
background_img: new_style.shop_background_img,
|
||||
}
|
||||
return `${padding} ${ background_computer(data) }`;
|
||||
},
|
||||
// 根据传递的参数,从对象中取值
|
||||
trends_config(new_style, key, type) {
|
||||
return this.style_config(new_style[`shop_${key}_typeface`], new_style[`shop_${key}_size`], new_style[`shop_${key}_color`], type, new_style);
|
||||
},
|
||||
// 根据传递的值,显示不同的内容
|
||||
style_config(typeface, size, color, type, new_style) {
|
||||
let style = `font-weight:${typeface}; font-size: ${size * 2}rpx;`;
|
||||
if (type == 'gradient') {
|
||||
style += gradient_handle(new_style.shop_button_color, '180deg');
|
||||
} else if (type == 'title') {
|
||||
style += `line-height: ${size > 0 ? (size + 3) * 2 : 0}rpx;height: ${size > 0 ? (size + 3) * 4 : 0}rpx;color: ${color};`;
|
||||
} else if (type == 'desc') {
|
||||
style += `line-height: ${size * 2}rpx;height: ${size * 2}rpx;color: ${color};`;
|
||||
} else {
|
||||
style += `color: ${color};`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
get_multicolumn_columns_width(new_style, form) {
|
||||
let model_number = form.carousel_col;
|
||||
if (form.shop_style_type == '1') {
|
||||
model_number = 1;
|
||||
} else if (form.shop_style_type == '2') {
|
||||
model_number = 2;
|
||||
}
|
||||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||||
let gap = (new_style.content_outer_spacing * (model_number - 1)) / model_number;
|
||||
return `calc(${100 / model_number}% - ${gap}px)`;
|
||||
},
|
||||
is_show(index) {
|
||||
return this.form.is_show.includes(index);
|
||||
},
|
||||
get_corner_marker(new_style) {
|
||||
const { seckill_subscript_location, shop_img_radius, seckill_subscript_bg_color, seckill_subscript_text_color } = new_style;
|
||||
let location = `background: ${seckill_subscript_bg_color};color: ${seckill_subscript_text_color};`;
|
||||
// 圆角根据图片的圆角来计算 对角线是同样的圆角
|
||||
if (seckill_subscript_location == 'top-left') {
|
||||
location += `top: 0;left: 0;border-radius: ${shop_img_radius.radius_top_left * 2}rpx 0 ${shop_img_radius.radius_top_left * 2}rpx 0;`;
|
||||
} else if (seckill_subscript_location == 'top-right') {
|
||||
location += `top: 0;right: 0;border-radius: 0 ${shop_img_radius.radius_top_right * 2}rpx 0 ${shop_img_radius.radius_top_right * 2}rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-left') {
|
||||
location += `bottom: 0;left: 0;border-radius: 0 ${shop_img_radius.radius_bottom_left * 2}rpx 0 ${shop_img_radius.radius_bottom_left * 2}rpx;`;
|
||||
} else if (seckill_subscript_location == 'bottom-right') {
|
||||
location += `bottom: 0;right: 0;border-radius: ${shop_img_radius.radius_bottom_right * 2}rpx 0 ${shop_img_radius.radius_bottom_right * 2}rpx 0;`;
|
||||
}
|
||||
return location;
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(link) {
|
||||
app.globalData.url_event(link);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.seckill-head {
|
||||
padding: 30rpx 26rpx;
|
||||
width: 100%;
|
||||
height: 102rpx;
|
||||
border-radius: 16rpx 16rpx 0 0;
|
||||
box-sizing: border-box;
|
||||
.seckill-title {
|
||||
width: auto;
|
||||
height: 42rpx;
|
||||
}
|
||||
.time-config {
|
||||
padding: 2rpx 10rpx;
|
||||
box-sizing: border-box;
|
||||
line-height: 34rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
.seckill-head-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
.colon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 33rpx;
|
||||
top: -2rpx;
|
||||
}
|
||||
.slide-bottom {
|
||||
height: 20rpx;
|
||||
border-radius: 10rpx;
|
||||
background: red;
|
||||
}
|
||||
.slide-top {
|
||||
position: absolute;
|
||||
height: 20rpx;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-radius: 10rpx;
|
||||
.slide-top-icon {
|
||||
position: absolute;
|
||||
top: -6rpx;
|
||||
right: 0;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
.original-price {
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
.size-11 {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
</style>
|
||||
231
components/diy/tabs-carousel.vue
Normal file
231
components/diy/tabs-carousel.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<template>
|
||||
<view class="ou pr" :style="style_container + swiper_bg_style">
|
||||
<view class="pa top-0 wh-auto ht-auto" :style="swiper_bg_img_style"></view>
|
||||
<view class="ou wh-auto" :style="style_img_container + (!isEmpty(swiper_bg_img_style) ? swiper_bg_img_style_null : '')">
|
||||
<componentDiyTabs :propKey="propKey" :propContentPadding="propContentPadding" :propValue="propValue" :propTop="propTop" :propIsRotatingBackground="is_rotating_background" :propBgStyle="swiper_bg_style" :propBgImgStyle="swiper_bg_img_style" :propStickyTop="propStickyTop" :propIsImmersionModel="propIsImmersionModel" :propNewIsTabsSafeDistance="new_is_tabs_safe_distance" :propNavIsTop="propNavIsTop" :propTabsIsTop="propTabsIsTop" :propIsCommon="false" :propsTabsContainer="tabs_container" :propsTabsImgContainer="tabs_img_container" :propSpacingCommonStyle="spacing_common_style" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" @onComputerHeight="tabs_height_event" @onTabsTap="tabs_click_event"></componentDiyTabs>
|
||||
<view :style="carousel_margin_top">
|
||||
<view :style="carousel_container">
|
||||
<view :style="carousel_img_container">
|
||||
<componentDiycarousel :propValue="propValue" :propIsCommon="false" @onVideoPlay="video_play" @slideChange="slideChange"></componentDiycarousel>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, isEmpty, gradient_computer, margin_computer, background_computer, radius_computer, old_margin, old_padding, old_radius, old_border_and_box_shadow, border_computer, box_shadow_computer, } from '@/common/js/common/common.js';
|
||||
import componentDiyTabs from '@/components/diy/tabs';
|
||||
import componentDiycarousel from '@/components/diy/carousel';
|
||||
export default {
|
||||
components: {
|
||||
componentDiyTabs,
|
||||
componentDiycarousel,
|
||||
},
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propTop: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
propStickyTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 是否导航栏置顶
|
||||
propNavIsTop: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否选项卡置顶
|
||||
propTabsIsTop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propContentPadding: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
// 选项卡是否使用安全距离
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style_margin_container: '',
|
||||
spacing_common_style: {
|
||||
padding: 0,
|
||||
padding_top: 0,
|
||||
padding_bottom: 0,
|
||||
padding_left: 0,
|
||||
padding_right: 0,
|
||||
margin: 0,
|
||||
margin_top: 0,
|
||||
margin_bottom: 0,
|
||||
margin_left: 0,
|
||||
margin_right: 0,
|
||||
},
|
||||
tabs_padding_style: '',
|
||||
// 选项卡内容
|
||||
tabs_container: '',
|
||||
tabs_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
// 轮播图内容
|
||||
carousel_margin_top: '',
|
||||
carousel_container: '',
|
||||
carousel_img_container: '',
|
||||
// top_up: '0',
|
||||
actived_index: 0,
|
||||
// 轮播图背景
|
||||
swiper_bg_style: '',
|
||||
swiper_bg_img_style: '',
|
||||
swiper_bg_img_style_null: `background-image: url('')`,
|
||||
is_rotating_background: false,
|
||||
new_is_tabs_safe_distance: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propTabsIsTop(value, old_value) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isEmpty,
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const { tabs_bg_color_list = [], tabs_bg_direction = '', tabs_bg_background_img_style = '', tabs_bg_background_img = [], tabs_radius = old_radius, tabs_padding = old_padding, tabs_margin = old_margin, tabs_content = old_border_and_box_shadow, carousel_content_color_list = [], carousel_content_direction = '', carousel_content_background_img_style = '', carousel_content_background_img = [], carousel_content_margin = old_margin, carousel_content_padding = old_padding, carousel_content_radius = old_radius, carousel_content = old_border_and_box_shadow } = new_style;
|
||||
// 选项卡背景设置
|
||||
const tabs_data = {
|
||||
color_list: tabs_bg_color_list,
|
||||
direction: tabs_bg_direction,
|
||||
background_img_style: tabs_bg_background_img_style,
|
||||
background_img: tabs_bg_background_img,
|
||||
}
|
||||
// 商品区域背景设置
|
||||
const carousel_content_data = {
|
||||
color_list: carousel_content_color_list,
|
||||
direction: carousel_content_direction,
|
||||
background_img_style: carousel_content_background_img_style,
|
||||
background_img: carousel_content_background_img,
|
||||
}
|
||||
// 头部的高度
|
||||
const newPropTop = app.globalData.rpx_to_px(this.propTop);
|
||||
// 选项卡的外边距
|
||||
const new_tabs_top = app.globalData.rpx_to_px(tabs_margin?.margin_top || 0);
|
||||
// 选项卡的实际外边距
|
||||
const tabs_margin_top = new_content.is_tabs_safe_distance == '1' ? newPropTop + this.propStickyTop : 0;
|
||||
// 选项卡的内边距处理
|
||||
const new_padding_top = new_style.common_style.padding_top - newPropTop;
|
||||
this.setData({
|
||||
// style_container: `${common_styles_computer(common_style)};gap:${new_style.data_spacing * 2}rpx`,
|
||||
style_container: `${common_styles_computer(new_style.common_style)};`,
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
carousel_margin_top: 'margin-top:' + new_style.data_spacing * 2 + 'rpx',
|
||||
new_is_tabs_safe_distance: new_content.is_tabs_safe_distance == '1',
|
||||
// 是否开启轮播图背景设置
|
||||
is_rotating_background: new_content.rotating_background == '1',
|
||||
tabs_sliding_fixed_bg: gradient_computer(tabs_data),
|
||||
tabs_container: gradient_computer(tabs_data) + radius_computer(tabs_radius) + margin_computer(tabs_margin) + border_computer(tabs_content) + box_shadow_computer(tabs_content) + `overflow: hidden;margin-top: ${ new_tabs_top - tabs_margin_top }px;`,
|
||||
tabs_img_container: background_computer(tabs_data) + padding_computer(tabs_padding) + `box-sizing: border-box;overflow: hidden;padding-top: ${ (tabs_padding?.padding_top || 0) + tabs_margin_top }px;`,
|
||||
carousel_container: gradient_computer(carousel_content_data) + margin_computer(carousel_content_margin) + radius_computer(carousel_content_radius) + border_computer(carousel_content) + box_shadow_computer(carousel_content) + 'overflow: hidden;',
|
||||
carousel_img_container: background_computer(carousel_content_data) + padding_computer(carousel_content_padding) + 'box-sizing: border-box;overflow: hidden;',
|
||||
spacing_common_style: {
|
||||
padding: 0,
|
||||
padding_top: (this.propIsImmersionModel && new_content.is_tabs_safe_distance == '1' ? new_style.common_style.padding_top + this.propStickyTop : new_padding_top > 0 ? new_padding_top : 0),
|
||||
padding_bottom: 0,
|
||||
padding_left: new_style.common_style.padding_left,
|
||||
padding_right: new_style.common_style.padding_right,
|
||||
margin: 0,
|
||||
margin_top: new_style.common_style.margin_top,
|
||||
margin_left: new_style.common_style.margin_left,
|
||||
margin_right: new_style.common_style.margin_right,
|
||||
},
|
||||
swiper_bg_style: this.get_swiper_bg_style(new_content, 0),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(new_content, 0),
|
||||
});
|
||||
},
|
||||
// tab点击
|
||||
tabs_click_event(tabs_id, is_micro_page) {
|
||||
this.$emit('onTabsTap', tabs_id, is_micro_page);
|
||||
},
|
||||
// tab高度
|
||||
tabs_height_event(height) {
|
||||
this.$emit('onComputerHeight', height);
|
||||
},
|
||||
// 视频播放
|
||||
video_play(url, popup_width, popup_height) {
|
||||
this.$emit('onVideoPlay', url, popup_width, popup_height);
|
||||
},
|
||||
get_swiper_bg_style(form, actived_index) {
|
||||
const style = form?.carousel_list?.[actived_index]?.style;
|
||||
if (style && !isEmpty(style.color_list)) {
|
||||
const color_list = style.color_list;
|
||||
const list = color_list.filter((item) => !isEmpty(item.color));
|
||||
if (list.length > 0) {
|
||||
try {
|
||||
return gradient_computer(style);
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
get_swiper_bg_img_style(form, actived_index) {
|
||||
const { carousel_img, style = {} } = form?.carousel_list[actived_index] || {};
|
||||
// 如果是自定义的图片 判断图片是否存在
|
||||
if (!isEmpty(carousel_img) && style?.background_type == 'carousel') {
|
||||
// 如果是使用轮播图,判断轮播图是否存在
|
||||
const data = {
|
||||
background_img: carousel_img,
|
||||
background_img_style: style?.background_img_style || '2',
|
||||
}
|
||||
return background_computer(data) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
} else if (!isEmpty(style?.background_img)) {
|
||||
return background_computer(style) + (style.is_background_img_blur == '1' ? `filter: blur(14px);opacity: 0.6;` : '');
|
||||
}
|
||||
return '';
|
||||
},
|
||||
slideChange(index) {
|
||||
this.setData({
|
||||
actived_index: index,
|
||||
swiper_bg_style: this.get_swiper_bg_style(this.propValue.content || {}, index),
|
||||
swiper_bg_img_style: this.get_swiper_bg_img_style(this.propValue.content || {}, index),
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
270
components/diy/tabs.vue
Normal file
270
components/diy/tabs.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<!-- 选项卡 -->
|
||||
<view class="tabs-container pr" :style="tabs_z_index">
|
||||
<view :class="top_up == '1' ? 'tabs-top' : ''" :style="tabs_top_style + (top_up == '1' ? propContentPadding : '')">
|
||||
<view :style="style_margin_container">
|
||||
<view class="tabs-contents bs-bb pr" :style="style_container">
|
||||
<view :class="top_up == '1' ? 'bs-bb' : 'wh-auto bs-bb'" :style="style_img_container">
|
||||
<componentDiyModulesTabsView :propKey="propKey" :propValue="tabs_data" :propIsTabsIcon="true" :propTop="propTop" :propsTabsContainer="propsTabsContainer + (propIsRotatingBackground ? propBgStyle : '')" :propIsRotatingBackground="propIsRotatingBackground" :propBgImgStyle="propBgImgStyle" :propsTabsImgContainer="propsTabsImgContainer" :propStyle="propStyle" :propTabsSlidingFixedBg="tabs_sliding_fixed_bg" @onTabsTap="tabs_click_event" @tabsZindex="tabsZindex"></componentDiyModulesTabsView>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="top_up == '1'" class="tabs-seat" :style="'height:' + (propIsCommon ? tabs_seat_height : tabs_carousel_seat_height) + 'px;'"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, padding_computer, margin_computer, gradient_computer, background_computer } from '@/common/js/common/common.js';
|
||||
import componentDiyModulesTabsView from '@/components/diy/modules/tabs-view';
|
||||
// 状态栏高度
|
||||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||||
// #ifdef MP-TOUTIAO
|
||||
bar_height = 0;
|
||||
// #endif
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// 置顶距离顶部高度
|
||||
propTop: {
|
||||
type: [String, Number],
|
||||
default: '0',
|
||||
},
|
||||
propStickyTop: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 是否导航栏置顶
|
||||
propNavIsTop: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否选项卡置顶
|
||||
propTabsIsTop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsCommon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propSpacingCommonStyle: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
// 样式
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propsTabsContainer: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propsTabsImgContainer: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propContentPadding: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
propIsImmersionModel: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propNewIsTabsSafeDistance: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
propTabsSlidingFixedBg: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propIsRotatingBackground: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propBgStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propBgImgStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
componentDiyModulesTabsView,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
tabs_sliding_fixed_bg: '',
|
||||
content: '',
|
||||
tabs_data: {},
|
||||
// 是否滑动置顶
|
||||
top_up: '0',
|
||||
// 置顶时,选项卡高度
|
||||
tabs_seat_height: 0,
|
||||
// 置顶时,轮播选项卡高度
|
||||
tabs_carousel_seat_height: 0,
|
||||
// 置顶时,选项卡样式
|
||||
tabs_top_style: '',
|
||||
style_margin_container: '',
|
||||
tabs_z_index: ''
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.get_tabs_height();
|
||||
}, 100);
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propTabsIsTop(value, old_value) {
|
||||
this.init();
|
||||
setTimeout(() => {
|
||||
this.get_tabs_height();
|
||||
}, 100);
|
||||
},
|
||||
propTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propStickyTop(val) {
|
||||
this.init();
|
||||
},
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
propSpacingCommonStyle(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
let new_tabs_data = JSON.parse(JSON.stringify(this.propValue));
|
||||
new_tabs_data.content.tabs_list.unshift(new_tabs_data.content.home_data);
|
||||
// 判断选项卡是否置顶
|
||||
let other_style = this.propTop;
|
||||
let new_tabs_top_style = this.propNavIsTop || this.propTabsIsTop || new_content.tabs_top_up == '1' ? (new_content.tabs_top_up == '1' ? 'top:calc(' + (this.propStickyTop > 0 ? this.propStickyTop + 'px + ' : '') + other_style * 2 + 'rpx);z-index:11;' : '') : '';
|
||||
let new_top_up = new_content.tabs_top_up;
|
||||
// #ifdef H5 || MP-TOUTIAO
|
||||
// if (this.propTabsIsTop) {
|
||||
// other_style = '0';
|
||||
// }
|
||||
new_tabs_top_style = 'top:calc(' + (this.propStickyTop > 0 ? this.propStickyTop + 'px + ' : '') + other_style * 2 + 'rpx);z-index:11;';
|
||||
new_top_up = this.propNavIsTop || this.propTabsIsTop ? new_content.tabs_top_up : '0';
|
||||
// #endif
|
||||
let tabs_bg = new_style.common_style.color_list;
|
||||
let new_tabs_background = '';
|
||||
if (!Array.isArray(tabs_bg) || tabs_bg.length === 0 || !tabs_bg[0] || !tabs_bg[0].color) {
|
||||
new_tabs_background = 'background:#fff;';
|
||||
}
|
||||
const newPropTop = this.propIsCommon ? (app.globalData.rpx_to_px(this.propTop) + this.propStickyTop) : (app.globalData.rpx_to_px(this.propTop + this.propStickyTop));
|
||||
this.setData({
|
||||
tabs_data: new_tabs_data,
|
||||
tabs_sliding_fixed_bg: this.propIsCommon ? gradient_computer(new_style.common_style) : this.propTabsSlidingFixedBg,
|
||||
style_container: this.propIsCommon ? new_tabs_background + common_styles_computer(new_style.common_style) : new_content.tabs_top_up == '1' ? new_tabs_background + gradient_computer(new_style.common_style) + margin_computer(this.propSpacingCommonStyle) : '', // 如果是选项卡轮播,不需要走默认样式
|
||||
// 如果开了滑动置顶,并且开了沉浸式,不需要走传递过来的index,否则的话就用传递过来的index
|
||||
style_img_container: this.propIsCommon ? common_img_computer(new_style.common_style, this.propIndex) : new_content.tabs_top_up == '1' ? background_computer(new_style.common_style) + padding_computer(this.propSpacingCommonStyle, 1, false) + 'box-sizing: border-box;' : '', // 如果是选项卡轮播,不需要走默认样式
|
||||
tabs_top_style: new_tabs_top_style,
|
||||
// 沉浸模式下并且开通了安全距离 会显示-的margin
|
||||
style_margin_container: this.propIsImmersionModel && this.propNewIsTabsSafeDistance ? `margin-top: -${ newPropTop }px;` : '',
|
||||
// 判断是否置顶
|
||||
top_up: new_top_up,
|
||||
tabs_z_index: 'z-index: 11;'
|
||||
});
|
||||
},
|
||||
// 获取选项卡高度
|
||||
get_tabs_height() {
|
||||
if (this.top_up == '1') {
|
||||
// 选择我们想要的元素
|
||||
const query = uni.createSelectorQuery();
|
||||
query
|
||||
.in(this)
|
||||
.select('.tabs-top')
|
||||
.boundingClientRect((res) => {
|
||||
if ((res || null) != null) {
|
||||
const newPropTop = app.globalData.rpx_to_px(this.propTop);
|
||||
// data包含元素的宽度、高度等信息
|
||||
this.setData({
|
||||
tabs_seat_height: res.height + (this.propIsImmersionModel ? newPropTop + this.propStickyTop : 0),
|
||||
tabs_carousel_seat_height: (res.height + (this.propIsImmersionModel ? newPropTop + this.propStickyTop : 0)) - this.propSpacingCommonStyle.padding_top - this.propSpacingCommonStyle.margin_top, // 轮播选项卡置顶时去掉顶部间距
|
||||
});
|
||||
this.$emit('onComputerHeight', this.tabs_seat_height);
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
} else {
|
||||
this.$emit('onComputerHeight', 0);
|
||||
}
|
||||
},
|
||||
tabsZindex(val) {
|
||||
this.setData({
|
||||
tabs_z_index: `z-index: ${ val };`
|
||||
});
|
||||
},
|
||||
// 选项卡回调
|
||||
tabs_click_event(index, item) {
|
||||
let tabs_id = '';
|
||||
// 抽象出获取 tabs_id 的逻辑
|
||||
tabs_id = this.get_tabs_id(item, index);
|
||||
// 是否是商品分类页面
|
||||
const is_micro_page = item.data_type == '0';
|
||||
this.$emit('onTabsTap', tabs_id, is_micro_page);
|
||||
},
|
||||
// 获取 tabs_id
|
||||
get_tabs_id(item, index) {
|
||||
if (item.data_type === '0') {
|
||||
return index !== 0 ? item.micro_page_list?.id : '';
|
||||
} else {
|
||||
return index !== 0 ? item.classify?.id : '';
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tabs-container {
|
||||
z-index: 11;
|
||||
.tabs-top {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
.tabs-contents {
|
||||
max-width: 1600rpx !important;
|
||||
}
|
||||
@media only screen and (min-width: 1600rpx) {
|
||||
.tabs-container .tabs-top {
|
||||
left: calc(50% - 400px) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
143
components/diy/title.vue
Normal file
143
components/diy/title.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="flex-col gap-10">
|
||||
<view class="pr flex-row" :class="title_center">
|
||||
<view class="z-i flex-row align-c gap-10">
|
||||
<template v-if="!isEmpty(form.img_src) && !isEmpty(form.img_src[0].url)">
|
||||
<view class="wh-auto" :style="{'height': new_style.img_height * 2 + 'rpx' }">
|
||||
<image :src="form.img_src[0].url" class="ht-auto" mode="heightFix"></image>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="!isEmpty(form.icon_class)">
|
||||
<iconfont :name="'icon-' + form.icon_class" :size="new_style.icon_size * 2 + 'rpx'" :color="new_style.icon_color" propContainerDisplay="flex"></iconfont>
|
||||
</template>
|
||||
<view v-if="!isEmpty(form.title)" class="nowrap" :style="title_style" :data-value="!isEmpty(form.title_link) ? form.title_link.page : ''" @tap="url_event">{{ form.title }}</view>
|
||||
<view v-if="!isEmpty(form.subtitle) && new_style.title_line == '1'" class="text-word-break nowrap" :style="subtitle_style">{{ form.subtitle }}</view>
|
||||
</view>
|
||||
<view class="flex-row gap-10 align-c right-0 pa">
|
||||
<template v-if="form.keyword_show == '1'">
|
||||
<view class="flex-row align-c" :style="keyword_gap">
|
||||
<view v-for="item in keyword_list" :key="item.id" :style="keyword_style" :data-value="!isEmpty(item.link) ? item.link.page : ''" @tap="url_event">
|
||||
{{ item.title }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<view v-if="form.right_show == '1'" class="nowrap flex-row align-c" :style="right_style" :data-value="!isEmpty(form.right_link) ? form.right_link.page : ''" @tap="url_event"
|
||||
>{{ form.right_title }}
|
||||
<iconfont name="icon-arrow-right" :color="new_style.right_color" :size="new_style.right_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!isEmpty(form.subtitle) && new_style.title_line != '1'" class="text-word-break" :style="subtitle_style">{{ form.subtitle }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
new_style: {},
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
title_center: '',
|
||||
subtitle_style: '',
|
||||
keyword_list: [],
|
||||
keyword_style: '',
|
||||
keyword_gap: '',
|
||||
right_style: '',
|
||||
right_size: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 判断是否为空
|
||||
isEmpty,
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_form = this.propValue.content;
|
||||
const new_style = this.propValue.style;
|
||||
|
||||
const { keyword_color, keyword_size, right_color, right_size, common_style, title_weight, title_color, title_size, keyword_spacing = 10 } = new_style;
|
||||
// 标题样式设置
|
||||
let common_styles = '';
|
||||
if (title_weight == 'italic') {
|
||||
common_styles += `font-style: italic`;
|
||||
} else if (['bold', '500'].includes(title_weight)) {
|
||||
common_styles += `font-weight: bold`;
|
||||
}
|
||||
// 是否居中
|
||||
this.setData({
|
||||
form: new_form,
|
||||
new_style: new_style,
|
||||
title_center: new_form.is_title_center == '1' ? 'jc-c' : '',
|
||||
keyword_list: new_form.keyword_list.filter((item) => item.is_show == '1'), // 关键字
|
||||
keyword_style: `color:${keyword_color}; font-size: ${keyword_size * 2}rpx;`, // 关键字设置
|
||||
keyword_gap: !isEmpty(keyword_spacing) ? `gap: ${ keyword_spacing * 2}rpx` : 'gap: 20rpx;', // 关键字间距设置
|
||||
right_size: right_size * 2 + 'rpx', // 右边按钮设置
|
||||
right_style: `color:${right_color}; font-size: ${right_size * 2}rpx;`, //右侧按钮样式
|
||||
title_style: `color:${title_color}; font-size: ${title_size * 2}rpx; ${common_styles}`, // 标题样式设置
|
||||
subtitle_style: this.get_subtitle_style(new_style), // 副标题样式设置
|
||||
style_container: common_styles_computer(common_style), // 通用样式区
|
||||
style_img_container: common_img_computer(common_style, this.propIndex), // 通用图片样式区
|
||||
});
|
||||
},
|
||||
// 副标题样式设置
|
||||
get_subtitle_style(new_style) {
|
||||
let common_styles = '';
|
||||
if (new_style.subtitle_weight == 'italic') {
|
||||
common_styles += `font-style: italic`;
|
||||
} else if (['bold', '500'].includes(new_style.subtitle_weight)) {
|
||||
common_styles += `font-weight: bold;`;
|
||||
}
|
||||
return `color:${new_style.subtitle_color}; font-size: ${new_style.subtitle_size * 2}rpx; ${common_styles}`;
|
||||
},
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.right-0 {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.break {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
164
components/diy/user-info.vue
Normal file
164
components/diy/user-info.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<!-- 用户信息 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="pr padding-xxl" :style="style">
|
||||
<view class="flex-row jc-sb align-c margin-bottom-xxl">
|
||||
<view class="flex-1 flex-row align-c gap-12">
|
||||
<image :src="(user_info.user || null) !== null ? user_info.user.avatar : user.avatar" class="circle" mode="widthFix" :style="'width:' + base_data.user_avatar_size * 2 + 'rpx;height:' + base_data.user_avatar_size * 2 + 'rpx;'" data-value="/pages/personal/personal" @tap="url_event" />
|
||||
<view class="flex-col gap-8" data-value="/pages/personal/personal" @tap="url_event">
|
||||
<view class="text-size fw-b" :style="user_name_style">{{ (user_info.user || null) !== null ? user_info.user.user_name_view : user.user_name_view }}</view>
|
||||
<view v-if="id_bool && (user_info.user || null) !== null" class="padding-horizontal-sm padding-vertical-xsss border-radius-sm" :style="number_code_style">ID:{{ user_info.user.number_code }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row align-c" :style="'gap:' + base_data.img_space * 2 + 'rpx;'">
|
||||
<view v-for="(item, index) in icon_setting" :key="index" :style="{ width: base_data.img_size + 'px', height: base_data.img_size + 'px' }" :data-value="item.link.page || ''" @tap="url_event">
|
||||
<image v-if="item.img.length > 0" :src="item.img[0].url" class="border-radius-sm" mode="scaleToFill" :style="{ width: base_data.img_size + 'px', height: base_data.img_size + 'px' }" />
|
||||
<iconfont v-else :name="'icon-' + item.icon" :size="base_data.img_size * 2 + 'rpx'" color="#666" propContainerDisplay="flex"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row jc-sa align-c">
|
||||
<template v-for="(item, index) in stats_list">
|
||||
<view v-if="config.includes(item.id)" :key="index" class="tc" :data-value="'/pages/' + item.url + '/' + item.url" @tap="url_event">
|
||||
<view class="text-size fw-b margin-bottom-sm" :style="stats_number_style">{{ item.value }}</view>
|
||||
<view class="text-size-xs" :style="stats_name_style">{{ item.name }}</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import { common_styles_computer, common_img_computer, gradient_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String,Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
id_bool: true,
|
||||
stats_list: [
|
||||
{ id: 'order_count', name: '订单总数', value: '100', url: 'user-order' },
|
||||
{ id: 'goods_favor_count', name: '商品收藏', value: '10', url: 'user-favor' },
|
||||
{ id: 'goods_browse_count', name: '我的足迹', value: '1000', url: 'user-goods-browse' },
|
||||
{ id: 'integral_number', name: '我的积分', value: '10000', url: 'user-integral' },
|
||||
],
|
||||
config: ['order_count', 'goods_favor_count', 'goods_browse_count', 'integral_number'],
|
||||
icon_setting: [
|
||||
{ id: '1', img: [], icon: '', link: {} },
|
||||
{ id: '2', img: [], icon: '', link: {} },
|
||||
],
|
||||
base_data: {},
|
||||
// 样式
|
||||
user_name_style: '',
|
||||
number_code_style: '',
|
||||
stats_name_style: '',
|
||||
stats_number_style: '',
|
||||
// 用户信息
|
||||
user_info: {
|
||||
user: null,
|
||||
order_count: '0',
|
||||
goods_favor_count: '0',
|
||||
goods_browse_count: '0',
|
||||
message_unread_count: '0',
|
||||
integral_number: '0',
|
||||
},
|
||||
user: {
|
||||
avatar: app.globalData.data.default_user_head_src,
|
||||
user_name_view: '用户名',
|
||||
number_code: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
const temp_base_data = {
|
||||
// 头像
|
||||
user_avatar_size: new_style.user_avatar_size,
|
||||
// 人物
|
||||
user_name_color: new_style.user_name_color,
|
||||
user_name_weight: new_style.user_name_weight,
|
||||
user_name_size: new_style.user_name_size,
|
||||
// id
|
||||
number_code_color_list: new_style.number_code_color_list,
|
||||
number_code_color: new_style.number_code_color,
|
||||
number_code_direction: new_style.number_code_direction,
|
||||
number_code_weight: new_style.number_code_weight,
|
||||
number_code_size: new_style.number_code_size,
|
||||
// 图标设置
|
||||
img_size: new_style.img_size,
|
||||
img_space: new_style.img_space,
|
||||
stats_name_color: new_style.stats_name_color,
|
||||
stats_name_weight: new_style.stats_name_weight,
|
||||
stats_name_size: new_style.stats_name_size,
|
||||
stats_number_color: new_style.stats_number_color,
|
||||
stats_number_weight: new_style.stats_number_weight,
|
||||
stats_number_size: new_style.stats_number_size,
|
||||
};
|
||||
// id样式
|
||||
const new_gradient_obj = {
|
||||
color_list: temp_base_data.number_code_color_list,
|
||||
direction: temp_base_data.number_code_direction,
|
||||
};
|
||||
let temp_stats_list = this.stats_list;
|
||||
temp_stats_list.map((item) => {
|
||||
if (new_content.config.includes(item.id)) {
|
||||
item.value = new_content.data[item.id];
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
user_info: new_content.data,
|
||||
config: new_content.config,
|
||||
icon_setting: new_content.icon_setting,
|
||||
base_data: temp_base_data,
|
||||
id_bool: new_content.config ? new_content.config.includes('number_code') : true,
|
||||
stats_list: temp_stats_list,
|
||||
// 人物名称样式
|
||||
user_name_style: 'color:' + temp_base_data.user_name_color + ';' + 'font-size:' + temp_base_data.user_name_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.user_name_weight + ';',
|
||||
number_code_style: gradient_computer(new_gradient_obj) + 'color:' + temp_base_data.number_code_color + ';' + 'font-size:' + temp_base_data.number_code_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.number_code_weight + ';',
|
||||
// 统计名称样式
|
||||
stats_name_style: 'color:' + temp_base_data.stats_name_color + ';' + 'font-size:' + temp_base_data.stats_name_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.stats_name_weight + ';',
|
||||
stats_number_style: 'color:' + temp_base_data.stats_number_color + ';' + 'font-size:' + temp_base_data.stats_number_size * 2 + 'rpx;' + 'font-weight:' + temp_base_data.stats_number_weight + ';',
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 跳转链接
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
86
components/diy/video.vue
Normal file
86
components/diy/video.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<!-- 视频 -->
|
||||
<view :style="style_container">
|
||||
<view :style="style_img_container">
|
||||
<view class="video pr" :style="style">
|
||||
<video :src="video" class="wh-auto ht-auto" :poster="video_img" objectFit="cover" style="object-fit: cover"></video>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { common_styles_computer, common_img_computer } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
props: {
|
||||
propValue: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
propKey: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 组件渲染的下标
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 1000000,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
style_container: '',
|
||||
style_img_container: '',
|
||||
style: '',
|
||||
video_img: '',
|
||||
video: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
propKey(val) {
|
||||
// 初始化
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化数据
|
||||
init() {
|
||||
const new_content = this.propValue.content || {};
|
||||
const new_style = this.propValue.style || {};
|
||||
// 视频比例
|
||||
this.get_video_height(new_content.video_ratio);
|
||||
this.setData({
|
||||
video_img: new_content.video_img.length > 0 ? new_content.video_img[0].url : '',
|
||||
video: new_content.video.length > 0 ? new_content.video[0].url : '',
|
||||
style_container: common_styles_computer(new_style.common_style),
|
||||
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
|
||||
});
|
||||
},
|
||||
// 获取视频高度
|
||||
get_video_height(data) {
|
||||
uni.getSystemInfo({
|
||||
success: (res) => {
|
||||
let video_ratio = ``;
|
||||
const width = res.windowWidth;
|
||||
if (data == '4:3') {
|
||||
video_ratio = `height: ${(((width * 3) / 4) * 2).toFixed(2)}rpx;`;
|
||||
} else if (data == '1:1') {
|
||||
video_ratio = `height: ${width * 2}rpx;`;
|
||||
} else {
|
||||
// 16:9 保留两位小数
|
||||
video_ratio = `height: ${(((width * 9) / 16) * 2).toFixed(2)}rpx;`;
|
||||
}
|
||||
this.setData({
|
||||
style: video_ratio,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
95
components/emoji-popup/emoji-popup.vue
Normal file
95
components/emoji-popup/emoji-popup.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
|
||||
<view class="emoji-popup bg-white">
|
||||
<view class="close fr oh">
|
||||
<view class="fr" @tap.stop="popup_close_event">
|
||||
<iconfont name="icon-close-o" size="28rpx" color="#999"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
<view class="emoji-popup-content oh tc">
|
||||
<block v-if="emoji_list.length > 0">
|
||||
<block v-for="(item, index) in emoji_list" :key="index">
|
||||
<view class="emoji-item fl bs-bb text-size-xxxl" @tap="choice_confirm_event" :data-value="item.emoji">{{item.emoji}}</view>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</component-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
var common_static_url = app.globalData.get_static_url('common');
|
||||
import componentPopup from "@/components/popup/popup";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
common_static_url: common_static_url,
|
||||
popup_status: false,
|
||||
emoji_list: []
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
componentPopup
|
||||
},
|
||||
|
||||
created: function() {},
|
||||
|
||||
methods: {
|
||||
// 初始配置
|
||||
init(config = {}) {
|
||||
if(!app.globalData.is_single_page_check()) {
|
||||
return false;
|
||||
}
|
||||
this.setData({
|
||||
popup_status: config.status == undefined ? true : config.status,
|
||||
emoji_list: config.emoji_list || [],
|
||||
});
|
||||
},
|
||||
|
||||
// 弹层关闭
|
||||
popup_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false
|
||||
});
|
||||
},
|
||||
|
||||
// 选择确认事件
|
||||
choice_confirm_event(e) {
|
||||
// 关闭弹窗
|
||||
this.setData({
|
||||
popup_status: false
|
||||
});
|
||||
|
||||
// 调用父级
|
||||
this.$emit('choiceConfirmEvent', e.currentTarget.dataset.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.emoji-popup {
|
||||
padding: 20rpx 10rpx 0 10rpx;
|
||||
position: relative;
|
||||
}
|
||||
.emoji-popup .close {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
.emoji-popup-content {
|
||||
max-height: 50vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.emoji-popup-content .emoji-item {
|
||||
height: 130rpx;
|
||||
line-height: 130rpx;
|
||||
width: 25%;
|
||||
}
|
||||
</style>
|
||||
576
components/goods-batch-buy/goods-batch-buy.vue
Normal file
576
components/goods-batch-buy/goods-batch-buy.vue
Normal file
@@ -0,0 +1,576 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
|
||||
<view class="bg-white">
|
||||
<view class="close oh padding-horizontal-main padding-top-main">
|
||||
<view class="fr" @tap.stop="popup_close_event">
|
||||
<iconfont name="icon-close-o" size="28rpx" color="#999"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
<view class="plugins-batchbuy-container">
|
||||
<!-- 批发规则 -->
|
||||
<view v-if="(plugins_wholesale_data || null) != null" class="padding-main br-b-f5">
|
||||
<component-wholesale-rules :propCurrencySymbol="propCurrencySymbol" :propData="plugins_wholesale_data"></component-wholesale-rules>
|
||||
</view>
|
||||
<!-- 下单规格选择 -->
|
||||
<view v-if="(goods || null) != null && (batchbuy_data || null) != null && (batchbuy_data.goods_spec_data || null) != null && batchbuy_data.goods_spec_data.length > 0" :class="'spec-data-content oh '+((plugins_wholesale_data || null) != null ? 'wholesale' : '')">
|
||||
<block v-if="batchbuy_data.is_only_level_one == 0">
|
||||
<view class="left-nav ht-auto bg-base fl">
|
||||
<scroll-view :scroll-y="true" class="ht-auto">
|
||||
<block v-for="(item, index) in batchbuy_data.goods_spec_data" :key="index">
|
||||
<view :class="'padding-vertical-main tc cp oh pr ' + (nav_active_index == index ? 'bg-white cr-main' : '')" :data-index="index" @tap="nav_event">
|
||||
<block v-if="(item.images || null) != null">
|
||||
<image class="dis-inline-block br-f5 radius dis-block spec-images" :src="item.images" mode="widthFix"></image>
|
||||
<view class="icon-enlarge-submit pa padding-xs lh-sm radius" :data-value="item.images" @tap="spec_images_view_event">
|
||||
<iconfont name="icon-enlarge" size="26rpx" color="#fff" propClass="lh-sm"></iconfont>
|
||||
</view>
|
||||
</block>
|
||||
<view class="cr-base">{{ item.name }}</view>
|
||||
<view v-if="(item.badge_total || 0) > 0" class="badge-icon pa">
|
||||
<component-badge :propNumber="item.badge_total"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="right-conent ht-auto bs-bb fr">
|
||||
<scroll-view :scroll-y="true" class="ht-auto">
|
||||
<block v-for="(item, index) in batchbuy_data.goods_spec_data[nav_active_index]['data']" :key="index">
|
||||
<view class="padding-main oh">
|
||||
<view class="fl item-left">
|
||||
<view class="text-size-xs">{{ item.name }}</view>
|
||||
<view class="sales-price text-size-xs">{{ propCurrencySymbol }}{{ item.base.price }}</view>
|
||||
</view>
|
||||
<text v-if="(item.base.inventory || 0) == 0" class="fr text-size-xs cr-grey">{{$t('goods-batch-buy.goods-batch-buy.dsfd98')}}</text>
|
||||
<view v-else class="tc oh round fr item-right text-size-xs">
|
||||
<view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-grey fl va-m" data-type="0" :data-index="index">-</view>
|
||||
<input @blur="batchbuy_goods_buy_number_blur" class="number-input tc cr-grey bg-white fl va-m radius-0" type="number" :value="item.buy_number || 0" :data-index="index" />
|
||||
<view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-grey fl va-m" data-type="1" :data-index="index">+</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="right-conent ht-auto padding-main bs-bb right-conent-only-level-one">
|
||||
<scroll-view :scroll-y="true" class="ht-auto">
|
||||
<block v-for="(item, index) in batchbuy_data.goods_spec_data" :key="index">
|
||||
<view class="oh padding-vertical-main">
|
||||
<view class="fl item-left">
|
||||
<view class="pr">
|
||||
<block v-if="(item.images || null) != null">
|
||||
<image class="dis-inline-block va-m br-f5 radius margin-right-sm spec-images" :src="item.images" mode="widthFix"></image>
|
||||
<view class="icon-enlarge-submit pa padding-xs lh-sm radius" :data-value="item.images" @tap="spec_images_view_event">
|
||||
<iconfont name="icon-enlarge" size="26rpx" color="#fff" propClass="lh-sm"></iconfont>
|
||||
</view>
|
||||
</block>
|
||||
<text class="text-size-xs va-m">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="sales-price text-size-xs margin-top-xs">{{ propCurrencySymbol }}{{ item.base.price }}</view>
|
||||
</view>
|
||||
<text v-if="(item.base.inventory || 0) == 0" class="fr text-size-xs cr-grey">{{$t('goods-batch-buy.goods-batch-buy.dsfd98')}}</text>
|
||||
<view v-else :class="'tc oh round fr item-right text-size-xs margin-top'+((item.images || null) == null ? 'xs' : '')">
|
||||
<view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-grey fl va-m" data-type="0" :data-index="index">-</view>
|
||||
<input @blur="batchbuy_goods_buy_number_blur" class="tc cr-grey bg-white fl va-m radius-0" type="number" :value="item.buy_number || 0" :data-index="index" />
|
||||
<view @tap="batchbuy_goods_buy_number_event" class="number-submit tc cr-grey fl va-m" data-type="1" :data-index="index">+</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="confirm-submit pa wh-auto bottom-line-exclude bg-white padding-top-main br-t-f5">
|
||||
<view class="oh padding-horizontal-main padding-bottom-main cr-grey">
|
||||
<text class="text-size-xs">
|
||||
<text>{{$t('buy.buy.g2vt78')}}</text>
|
||||
<text class="cr-red padding-left-xs padding-right-xs">{{ base_data.kind }}</text>
|
||||
<text>{{$t('goods-batch-buy.goods-batch-buy.9ectyf')}}</text>
|
||||
<text class="cr-red padding-left-xs padding-right-xs">{{ base_data.quantity }}</text>
|
||||
<text>{{ goods.inventory_unit }}</text>
|
||||
</text>
|
||||
<text class="text-size-xs fr">{{$t('goods-batch-buy.goods-batch-buy.geq82x')}}<text class="fw-b sales-price">{{ propCurrencySymbol }}{{ base_data.amount_money }}</text></text>
|
||||
</view>
|
||||
<view v-if="(opt_button || null) != null && opt_button.length > 0" class="padding-bottom-main">
|
||||
<view :class="'oh buy-nav-btn-number-' + (opt_button.length || 0)">
|
||||
<block v-for="(item, index) in opt_button" :key="index">
|
||||
<view v-if="(item.name || null) != null && (item.type || null) != null" class="item fl bs-bb padding-horizontal-main">
|
||||
<button :class="'cr-white round text-size-sm bg-' + ((item.color || 'main') == 'main' ? 'main' : 'main-pair')" type="default" @tap="confirm_event" :data-type="item.type" hover-class="none">{{ item.name }}</button>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block v-else>
|
||||
<view class="cr-grey tc padding-top-xl padding-bottom-xxxl">{{$t('goods-batch-buy.goods-batch-buy.ypby1k')}}</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</component-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import base64 from "@/common/js/lib/base64.js";
|
||||
import componentPopup from "@/components/popup/popup";
|
||||
import componentBadge from "@/components/badge/badge";
|
||||
import componentWholesaleRules from '@/components/wholesale-rules/wholesale-rules';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
popup_status: false,
|
||||
nav_active_index: 0,
|
||||
goods: null,
|
||||
batchbuy_data: null,
|
||||
back_data: null,
|
||||
opt_button: [],
|
||||
base_data: {
|
||||
kind: 0,
|
||||
quantity: 0,
|
||||
amount_money: "0.00",
|
||||
},
|
||||
// 批发数据
|
||||
plugins_wholesale_data: null,
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
componentPopup,
|
||||
componentBadge,
|
||||
componentWholesaleRules
|
||||
},
|
||||
|
||||
props: {
|
||||
// 价格符号
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol(),
|
||||
},
|
||||
// 批发数据
|
||||
propPluginsWholesaleData: {
|
||||
type: [Array, Object],
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.setData({
|
||||
plugins_wholesale_data: this.propPluginsWholesaleData,
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化
|
||||
init(params = {}) {
|
||||
if (!app.globalData.is_single_page_check()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 购买按钮处理,仅展示购买和购物车
|
||||
var opt_button = [];
|
||||
var buy_button = params.buy_button || null;
|
||||
if(buy_button != null && (buy_button.data || null) != null && buy_button.data.length > 0) {
|
||||
var arr = ['plugins-batchbuy-button-cart', 'plugins-batchbuy-button-buy'];
|
||||
for(var i in buy_button.data) {
|
||||
if(arr.indexOf(buy_button.data[i]['type']) != -1) {
|
||||
opt_button.push(buy_button.data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置数据
|
||||
this.setData({
|
||||
popup_status: true,
|
||||
opt_button: opt_button,
|
||||
goods: params.goods || null,
|
||||
batchbuy_data: params.batchbuy_data || null,
|
||||
back_data: params.back_data || null,
|
||||
plugins_wholesale_data: params.plugins_wholesale_data || null
|
||||
});
|
||||
},
|
||||
|
||||
// 弹层关闭
|
||||
popup_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
},
|
||||
|
||||
// 弹层导航切换
|
||||
nav_event(e) {
|
||||
this.setData({
|
||||
nav_active_index: e.currentTarget.dataset.index,
|
||||
});
|
||||
},
|
||||
|
||||
// 商品批量下单数量操作事件
|
||||
batchbuy_goods_buy_number_event(e) {
|
||||
var type = e.currentTarget.dataset.type;
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var temp_data = this.batchbuy_data;
|
||||
var temp_spec_data = parseInt(temp_data.is_only_level_one || 0) == 1 ? temp_data.goods_spec_data[index] : temp_data.goods_spec_data[this.nav_active_index]["data"][index];
|
||||
var number = parseInt(temp_spec_data.buy_number || 0);
|
||||
var min = parseInt(temp_spec_data.base.buy_min_number || 0);
|
||||
// 首次增加使用起购数量
|
||||
number = type == 0 ? number - 1 : number == 0 && min > 0 ? min : number + 1;
|
||||
this.batch_goods_buy_number_handle(temp_data, temp_spec_data, index, number);
|
||||
},
|
||||
|
||||
// 商品批量下单数量输入事件
|
||||
batchbuy_goods_buy_number_blur(e) {
|
||||
var number = parseInt(e.detail.value) || 0;
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var temp_data = this.batchbuy_data;
|
||||
var temp_spec_data = parseInt(temp_data.is_only_level_one || 0) == 1 ? temp_data.goods_spec_data[index] : temp_data.goods_spec_data[this.nav_active_index]["data"][index];
|
||||
if (isNaN(number)) {
|
||||
number = 0;
|
||||
}
|
||||
this.batch_goods_buy_number_handle(temp_data, temp_spec_data, index, number);
|
||||
},
|
||||
|
||||
// 商品批量下单数量处理
|
||||
batch_goods_buy_number_handle(temp_data, temp_spec_data, index, number) {
|
||||
var min = parseInt(temp_spec_data.base.buy_min_number || 0);
|
||||
var max = parseInt(temp_spec_data.base.buy_max_number || 0);
|
||||
var inventory = parseInt(temp_spec_data.base.inventory || 0);
|
||||
var inventory_unit = this.goods.inventory_unit;
|
||||
|
||||
// 是否负数
|
||||
if (number < 0) {
|
||||
number = 0;
|
||||
}
|
||||
// 不能小于起购数则0
|
||||
if (number > 0 && min > 0 && number < min) {
|
||||
number = 0;
|
||||
app.globalData.showToast(this.$t('recommend-detail.recommend-detail.265vyu') + min + inventory_unit);
|
||||
}
|
||||
// 不能超过最大限购
|
||||
if (max > 0 && number > max) {
|
||||
number = max;
|
||||
app.globalData.showToast(this.$t('goods-category.goods-category.z1eh3v') + max + inventory_unit);
|
||||
}
|
||||
// 不能超过库存
|
||||
if (number > inventory) {
|
||||
number = inventory;
|
||||
app.globalData.showToast(this.$t('recommend-detail.recommend-detail.2sis3v') + inventory + inventory_unit);
|
||||
}
|
||||
temp_spec_data["buy_number"] = number;
|
||||
if (parseInt(temp_data.is_only_level_one || 0) == 1) {
|
||||
temp_data.goods_spec_data[index] = temp_spec_data;
|
||||
} else {
|
||||
temp_data.goods_spec_data[this.nav_active_index]["data"][index] = temp_spec_data;
|
||||
}
|
||||
|
||||
// 非仅一级则处理一级总数
|
||||
if (parseInt(temp_data.is_only_level_one || 0) != 1) {
|
||||
var badge_total = 0;
|
||||
temp_data.goods_spec_data[this.nav_active_index]["data"].forEach((item) => {
|
||||
var temp_badge = parseInt(item.buy_number || 0);
|
||||
if (temp_badge > 0) {
|
||||
badge_total += temp_badge;
|
||||
}
|
||||
});
|
||||
temp_data.goods_spec_data[this.nav_active_index]["badge_total"] = badge_total;
|
||||
}
|
||||
|
||||
// 总数、汇总
|
||||
var stock_total = 0;
|
||||
var kind_total = 0;
|
||||
var amount_money_total = 0;
|
||||
temp_data.goods_spec_data.forEach((item) => {
|
||||
if (parseInt(temp_data.is_only_level_one || 0) == 1) {
|
||||
var temp_stock = parseInt(item.buy_number || 0);
|
||||
if (temp_stock > 0) {
|
||||
stock_total += temp_stock;
|
||||
kind_total += 1;
|
||||
amount_money_total += temp_stock * parseFloat(item.base.price);
|
||||
}
|
||||
} else {
|
||||
item.data.forEach((item2) => {
|
||||
var temp_stock = parseInt(item2.buy_number || 0);
|
||||
if (temp_stock > 0) {
|
||||
stock_total += temp_stock;
|
||||
kind_total += 1;
|
||||
amount_money_total += temp_stock * parseFloat(item2.base.price);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 设置数据
|
||||
this.setData({
|
||||
batchbuy_data: temp_data,
|
||||
base_data: {
|
||||
kind: kind_total,
|
||||
quantity: stock_total,
|
||||
amount_money: app.globalData.price_two_decimal(amount_money_total),
|
||||
},
|
||||
});
|
||||
|
||||
// 下单数据
|
||||
var goods_data = [];
|
||||
var goods_id = this.goods.id;
|
||||
temp_data.goods_spec_data.forEach((item) => {
|
||||
if (parseInt(temp_data.is_only_level_one || 0) == 1) {
|
||||
goods_data.push({
|
||||
id: goods_id,
|
||||
stock: stock_total,
|
||||
spec: item.spec || "",
|
||||
});
|
||||
} else {
|
||||
item.data.forEach((item2) => {
|
||||
goods_data.push({
|
||||
id: goods_id,
|
||||
stock: stock_total,
|
||||
spec: item2.spec || "",
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 数量更新获取最新数据
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url("stock", "goods"),
|
||||
method: "POST",
|
||||
data: { goods_data: goods_data },
|
||||
dataType: "json",
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
var plugins_wholesale_data = null;
|
||||
res.data.data.forEach((item) => {
|
||||
if (item.code == 0) {
|
||||
// 批发数据
|
||||
if((item.data.plugins_wholesale_data || null) != null && temp_spec_data.base_id == item.data.spec_base.id) {
|
||||
plugins_wholesale_data = item.data.plugins_wholesale_data;
|
||||
}
|
||||
// 规格数据处理
|
||||
for (var i1 in temp_data.goods_spec_data) {
|
||||
if (parseInt(temp_data.is_only_level_one || 0) == 1) {
|
||||
if (temp_data.goods_spec_data[i1].base.id == item.data.spec_base.id) {
|
||||
temp_data.goods_spec_data[i1].base.price = item.data.spec_base.price;
|
||||
temp_data.goods_spec_data[i1].base.original_price = item.data.spec_base.original_price;
|
||||
temp_data.goods_spec_data[i1].base.inventory = item.data.spec_base.inventory;
|
||||
}
|
||||
} else {
|
||||
for (var i2 in temp_data.goods_spec_data[i1].data) {
|
||||
if (temp_data.goods_spec_data[i1].data[i2].base.id == item.data.spec_base.id) {
|
||||
temp_data.goods_spec_data[i1].data[i2].base.price = item.data.spec_base.price;
|
||||
temp_data.goods_spec_data[i1].data[i2].base.original_price = item.data.spec_base.original_price;
|
||||
temp_data.goods_spec_data[i1].data[i2].base.inventory = item.data.spec_base.inventory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
batchbuy_data: temp_data,
|
||||
plugins_wholesale_data: plugins_wholesale_data,
|
||||
});
|
||||
|
||||
// 调用父级
|
||||
this.$emit("BatchStockSuccessEvent", {
|
||||
current_spec: temp_spec_data,
|
||||
goods_data: goods_data,
|
||||
back_data: res.data.data,
|
||||
plugins_wholesale_data: plugins_wholesale_data,
|
||||
});
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 确认事件
|
||||
confirm_event(e) {
|
||||
var user = app.globalData.get_user_info(this, "confirm_event", e);
|
||||
if (user != false) {
|
||||
// 获取数据
|
||||
var goods_data = [];
|
||||
var goods_id = this.goods.id;
|
||||
this.batchbuy_data.goods_spec_data.forEach((item) => {
|
||||
if (parseInt(this.batchbuy_data.is_only_level_one || 0) == 1) {
|
||||
var buy_number = parseInt(item.buy_number || 0);
|
||||
if (buy_number > 0) {
|
||||
goods_data.push({
|
||||
goods_id: goods_id,
|
||||
stock: buy_number,
|
||||
spec: item.spec || "",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
item.data.forEach((item2) => {
|
||||
var buy_number = parseInt(item2.buy_number || 0);
|
||||
if (buy_number > 0) {
|
||||
goods_data.push({
|
||||
goods_id: goods_id,
|
||||
stock: buy_number,
|
||||
spec: item2.spec || "",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (goods_data.length <= 0) {
|
||||
app.globalData.showToast(this.$t('goods-detail.goods-detail.6brk57'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 操作类型
|
||||
switch (e.currentTarget.dataset.type) {
|
||||
case "plugins-batchbuy-button-buy":
|
||||
// 进入订单确认页面
|
||||
var data = {
|
||||
buy_type: "goods",
|
||||
goods_data: encodeURIComponent(base64.encode(JSON.stringify(goods_data))),
|
||||
};
|
||||
app.globalData.url_open("/pages/buy/buy?data=" + encodeURIComponent(base64.encode(JSON.stringify(data))));
|
||||
this.popup_close_event();
|
||||
break;
|
||||
|
||||
// 加入购物车
|
||||
case "plugins-batchbuy-button-cart":
|
||||
this.goods_cart_event(goods_data);
|
||||
break;
|
||||
|
||||
default:
|
||||
app.globalData.showToast(this.$t('goods-batch-buy.goods-batch-buy.7tp1tc'));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 加入购物车事件
|
||||
goods_cart_event(goods_data) {
|
||||
uni.showLoading({
|
||||
title: this.$t('common.processing_in_text'),
|
||||
});
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url("save", "cart"),
|
||||
method: "POST",
|
||||
data: { goods_data: goods_data },
|
||||
dataType: "json",
|
||||
success: (res) => {
|
||||
uni.hideLoading();
|
||||
if (res.data.code == 0) {
|
||||
app.globalData.showToast(res.data.msg, "success");
|
||||
|
||||
// 调用父级
|
||||
this.$emit("BatchCartSuccessEvent", {
|
||||
cart_number: res.data.data.buy_number,
|
||||
back_data: this.back_data,
|
||||
});
|
||||
|
||||
// 关闭购买弹窗窗口
|
||||
this.popup_close_event();
|
||||
} else {
|
||||
if (app.globalData.is_login_check(res.data, this, "confirm_event")) {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 规格图片预览事件
|
||||
spec_images_view_event(e) {
|
||||
var value = e.currentTarget.dataset.value || null;
|
||||
if (value != null) {
|
||||
uni.previewImage({
|
||||
current: value,
|
||||
urls: [value],
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.plugins-batchbuy-container {
|
||||
height: 70vh;
|
||||
padding-bottom: 160rpx;
|
||||
}
|
||||
.plugins-batchbuy-container .spec-data-content {
|
||||
height: calc(100% - 15rpx);
|
||||
}
|
||||
.plugins-batchbuy-container .spec-data-content.wholesale {
|
||||
height: calc(100% - 160rpx);
|
||||
}
|
||||
.plugins-batchbuy-container .left-nav {
|
||||
width: 200rpx;
|
||||
}
|
||||
.plugins-batchbuy-container .left-nav .badge-icon {
|
||||
top: 8rpx;
|
||||
right: 36rpx;
|
||||
}
|
||||
.plugins-batchbuy-container .left-nav .spec-images {
|
||||
width: 100rpx;
|
||||
height: 100rpx !important;
|
||||
}
|
||||
.plugins-batchbuy-container .icon-enlarge-submit {
|
||||
left: 55rpx;
|
||||
top: 30rpx;
|
||||
background: rgb(0, 0, 0, 30%);
|
||||
}
|
||||
.plugins-batchbuy-container .right-conent {
|
||||
width: calc(100% - 210rpx);
|
||||
}
|
||||
.plugins-batchbuy-container .right-conent .item-left {
|
||||
width: calc(100% - 290rpx);
|
||||
}
|
||||
.plugins-batchbuy-container .item-right {
|
||||
background: #fbfbfb;
|
||||
border: 1px solid #f0f0f0;
|
||||
}
|
||||
.plugins-batchbuy-container .item-right .number-submit {
|
||||
width: 80rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.plugins-batchbuy-container .item-right .number-input {
|
||||
width: 50px;
|
||||
}
|
||||
.plugins-batchbuy-container .item-right .number-submit,
|
||||
.plugins-batchbuy-container .item-right .number-input {
|
||||
padding: 0;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
}
|
||||
.plugins-batchbuy-container .right-conent-only-level-one {
|
||||
width: 100%;
|
||||
}
|
||||
.plugins-batchbuy-container .right-conent-only-level-one .spec-images {
|
||||
width: 100rpx;
|
||||
height: 100rpx !important;
|
||||
}
|
||||
.plugins-batchbuy-container .right-conent-only-level-one .icon-enlarge-submit {
|
||||
left: 5rpx;
|
||||
top: 5rpx;
|
||||
}
|
||||
.plugins-batchbuy-container .confirm-submit {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.plugins-batchbuy-container .buy-nav-btn-number-0 .item,
|
||||
.plugins-batchbuy-container .buy-nav-btn-number-1 .item {
|
||||
width: 100% !important;
|
||||
}
|
||||
.plugins-batchbuy-container .buy-nav-btn-number-2 .item {
|
||||
width: 50% !important;
|
||||
}
|
||||
.plugins-batchbuy-container .buy-nav-btn-number-3 .item {
|
||||
width: 33.33% !important;
|
||||
}
|
||||
.plugins-batchbuy-container .buy-nav-btn-number-4 .item {
|
||||
width: 25% !important;
|
||||
}
|
||||
</style>
|
||||
945
components/goods-buy/goods-buy.vue
Normal file
945
components/goods-buy/goods-buy.vue
Normal file
@@ -0,0 +1,945 @@
|
||||
<template>
|
||||
<view :class="theme_view" class="z-i-deep">
|
||||
<component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event" :propIndex="propIndex">
|
||||
<view class="goods-spec-choice-container padding-main bg-white pr">
|
||||
<view class="close fr oh">
|
||||
<view class="fr" @tap.stop="popup_close_event">
|
||||
<iconfont name="icon-close-o" size="28rpx" color="#999"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 规格基础信息 -->
|
||||
<view class="goods-spec-base oh br-b pr">
|
||||
<image :src="goods_spec_base_images" mode="scaleToFill" class="spec-images radius br" @tap="goods_detail_images_view_event" :data-value="goods_spec_base_images"></image>
|
||||
<view class="goods-spec-base-content">
|
||||
<view class="goods-price">
|
||||
<view v-if="(goods.show_field_price_status || 0) == 1">
|
||||
<text class="sales-price va-m">{{ goods.show_price_symbol }}{{ goods_spec_base_price }}</text>
|
||||
<text class="cr-grey text-size-xs va-m">{{ goods.show_price_unit }}</text>
|
||||
</view>
|
||||
<view v-if="(goods.show_field_original_price_status || 0) == 1 && (goods_spec_base_original_price || null) != null && goods_spec_base_original_price != 0" class="original-price margin-top-sm">{{ goods.show_original_price_symbol }}{{ goods_spec_base_original_price }}{{ goods.show_original_price_unit }}</view>
|
||||
</view>
|
||||
<view v-if="(goods.show_inventory_status || 0) == 1" class="inventory text-size-xs margin-top">
|
||||
<text class="cr-grey">{{ $t('goods-detail.goods-detail.1s79t4') }}</text>
|
||||
<text class="cr-base">{{ goods_spec_base_inventory }}</text>
|
||||
<text class="cr-grey">{{ goods.inventory_unit }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block v-if="(goods.is_exist_many_spec || 0) == 1 && goods_spec_choose.length == 0">
|
||||
<view class="padding-top-xxxl padding-bottom-xxxl tc cr-red">{{ $t('goods-buy.goods-buy.ufdm25') }}</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="goods-spec-choice-content">
|
||||
<!-- 商品规格 -->
|
||||
<view v-if="goods_spec_choose.length > 0" class="goods-spec-choose">
|
||||
<view v-for="(item, key) in goods_spec_choose" :key="key" class="item padding-top-xxl padding-bottom-xxl">
|
||||
<view class="text-size-sm">{{ item.name }}</view>
|
||||
<view v-if="item.value.length > 0" class="spec margin-top-sm">
|
||||
<block v-for="(items, keys) in item.value" :key="keys">
|
||||
<button @tap.stop="goods_spec_choice_event" :data-key="key" :data-keys="keys" type="default" size="mini" hover-class="none" :class="'spec-btn round ' + items.is_active + ' ' + items.is_dont + ' ' + items.is_disabled">
|
||||
<image v-if="(items.images || null) != null" :src="items.images" mode="scaleToFill" class="spec-images va-m dis-inline-block round margin-right-sm"></image>
|
||||
<text class="va-m">{{ items.name }}</text>
|
||||
</button>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 购买数量 -->
|
||||
<view class="goods-buy-number oh pr margin-top-xl margin-bottom-xxl">
|
||||
<view class="fl margin-top">{{ $t('goods-buy.goods-buy.737wzz') }}</view>
|
||||
<view class="number-content tc oh round">
|
||||
<view @tap="goods_buy_number_event" class="number-submit tc cr-grey fl va-m" data-type="0">-</view>
|
||||
<input @blur="goods_buy_number_blur" class="number-input tc cr-grey bg-white fl va-m radius-0" type="number" :value="buy_number" />
|
||||
<view @tap="goods_buy_number_event" class="number-submit tc cr-grey fl va-m" data-type="1">+</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(opt_button || null) != null && opt_button.length > 0" class="padding-bottom-main">
|
||||
<view :class="'oh buy-nav-btn-number-' + (opt_button.length || 0)">
|
||||
<block v-for="(item, index) in opt_button" :key="index">
|
||||
<view v-if="(item.name || null) != null && (item.type || null) != null" class="item fl bs-bb padding-horizontal-main">
|
||||
<button :class="'cr-white round text-size-sm bg-' + ((item.color || 'main') == 'main' ? 'main' : 'main-pair')" type="default" @tap="spec_confirm_event" :data-value="item.value" :data-type="item.type" :data-business="item.business || ''" hover-class="none">{{ item.name }}</button>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<button v-else class="bg-main br-main cr-white text-size-sm round" type="default" @tap.stop="spec_confirm_event" hover-class="none">{{ $t('index.index.7w75zb') }}</button>
|
||||
</block>
|
||||
</view>
|
||||
</component-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import base64 from '@/common/js/lib/base64.js';
|
||||
import componentPopup from '@/components/popup/popup';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
params: {},
|
||||
back_data: {},
|
||||
popup_status: false,
|
||||
goods_spec_base_price: 0,
|
||||
goods_spec_base_original_price: 0,
|
||||
goods_spec_base_inventory: 0,
|
||||
goods_spec_base_buy_min_number: 0,
|
||||
goods_spec_base_buy_max_number: 0,
|
||||
goods_spec_base_images: '',
|
||||
goods: {},
|
||||
goods_spec_choose: [],
|
||||
buy_number: 1,
|
||||
buy_event_type: 'cart',
|
||||
opt_button: [],
|
||||
is_direct_cart: 0,
|
||||
is_success_tips: 1,
|
||||
// 选中规格临时定时变量
|
||||
spec_selected_timer: null,
|
||||
spec_selected_timerout: null,
|
||||
// 智能工具插件
|
||||
plugins_intellectstools_config: app.globalData.get_config('plugins_base.intellectstools.data'),
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
componentPopup,
|
||||
},
|
||||
props: {
|
||||
propParams: {
|
||||
type: [String, Object],
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol(),
|
||||
},
|
||||
// 弹窗层级
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
},
|
||||
|
||||
created: function () {},
|
||||
|
||||
methods: {
|
||||
// 初始化
|
||||
init(goods = {}, params = {}, back_data = null) {
|
||||
if (!app.globalData.is_single_page_check()) {
|
||||
return false;
|
||||
}
|
||||
params = params || {};
|
||||
|
||||
// 状态默认开启弹窗
|
||||
var status = true;
|
||||
// 商品可选规格
|
||||
var goods_spec_choose = (goods.specifications || null) != null ? goods.specifications.choose || [] : [];
|
||||
// 无规格是否直接操作
|
||||
var is_direct_cart = 0;
|
||||
if ((params.is_direct_cart || 0) == 1 && parseInt(goods.is_exist_many_spec || 0) == 0 && goods_spec_choose.length == 0) {
|
||||
status = false;
|
||||
is_direct_cart = 1;
|
||||
}
|
||||
// 是否成功提示、默认提示
|
||||
var is_success_tips = params.is_success_tips == undefined ? 1 : params.is_success_tips || 0;
|
||||
// 直接加购、并且用户已经存在购物车则依次+1
|
||||
if (is_direct_cart == 1 && parseInt(goods.user_cart_count || 0) > 0) {
|
||||
var buy_number = 1;
|
||||
} else {
|
||||
var buy_number = goods.buy_min_number || 1;
|
||||
}
|
||||
|
||||
// 购买按钮处理,仅展示购买和购物车
|
||||
var opt_button = [];
|
||||
var buy_button = params.buy_button || null;
|
||||
if (buy_button != null && (buy_button.data || null) != null && buy_button.data.length > 0) {
|
||||
var arr = ['buy', 'cart', 'show'];
|
||||
for (var i in buy_button.data) {
|
||||
if (arr.indexOf(buy_button.data[i]['type']) != -1) {
|
||||
opt_button.push(buy_button.data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置数据
|
||||
this.setData({
|
||||
popup_status: status,
|
||||
params: params || {},
|
||||
back_data: back_data,
|
||||
goods: goods || {},
|
||||
goods_spec_choose: goods_spec_choose,
|
||||
goods_spec_base_price: goods.price,
|
||||
goods_spec_base_original_price: goods.original_price || 0,
|
||||
goods_spec_base_inventory: goods.inventory,
|
||||
goods_spec_base_images: goods.images,
|
||||
buy_number: buy_number,
|
||||
buy_event_type: params.buy_event_type || 'cart',
|
||||
opt_button: opt_button,
|
||||
is_direct_cart: is_direct_cart,
|
||||
is_success_tips: is_success_tips,
|
||||
});
|
||||
|
||||
// 初始化不能选择规格处理
|
||||
this.spec_handle_dont(0, 1);
|
||||
|
||||
// 获取规格详情
|
||||
this.get_spec_detail();
|
||||
|
||||
// 规格选中处理
|
||||
this.selected_spec_handle();
|
||||
|
||||
// 是否直接操作加入购物车
|
||||
if (is_direct_cart) {
|
||||
this.spec_confirm_event();
|
||||
}
|
||||
},
|
||||
|
||||
// 规格选中处理
|
||||
selected_spec_handle() {
|
||||
var temp_spec_choose = this.goods_spec_choose;
|
||||
if (temp_spec_choose.length > 0) {
|
||||
// 是否已选择
|
||||
var active_count = 0;
|
||||
for (var i in temp_spec_choose) {
|
||||
for (var k in temp_spec_choose[i]['value']) {
|
||||
if ((temp_spec_choose[i]['value'][k]['is_active'] || null) != null) {
|
||||
active_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (active_count > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 是否指定规格初始化
|
||||
var spec = (this.propParams || null) != null && (this.propParams.spec || null) != null ? this.propParams.spec : null;
|
||||
if (spec != null) {
|
||||
this.appoint_selected_spec_handle(temp_spec_choose, spec);
|
||||
} else {
|
||||
// 是否默认选中第一个规格、、已存在指定规格初始化则不走默认选择第一个规格
|
||||
this.plugins_intellectstools_selected_spec_handle(temp_spec_choose);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 指定规格初始化
|
||||
appoint_selected_spec_handle(spec_choose, spec) {
|
||||
spec = decodeURIComponent(spec).split('|');
|
||||
if (spec.length == spec_choose.length) {
|
||||
// 选择处理
|
||||
var self = this;
|
||||
// 销毁之前的任务
|
||||
clearInterval(self.spec_selected_timer);
|
||||
clearInterval(self.spec_selected_timerout);
|
||||
// 必须存在购买和加入购物车任意一个、规格必须多个
|
||||
var sku_count = app.globalData.get_length(spec_choose);
|
||||
// 先清除价格展示信息
|
||||
self.setData({
|
||||
goods_spec_base_price: '...',
|
||||
goods_spec_base_original_price: '...',
|
||||
});
|
||||
var num = 0;
|
||||
var timer = setInterval(function () {
|
||||
for (var i in spec_choose) {
|
||||
// 清除价格展示信息、避免获取价格类型赋值
|
||||
self.setData({
|
||||
goods_spec_base_price: '...',
|
||||
goods_spec_base_original_price: '...',
|
||||
});
|
||||
// 必须不存在已选择项
|
||||
var active =
|
||||
spec_choose[i]['value']
|
||||
.map(function (v) {
|
||||
return v.is_active;
|
||||
})
|
||||
.join('') || null;
|
||||
if (active == null) {
|
||||
// 不能选择规格处理
|
||||
self.spec_handle_dont(i);
|
||||
|
||||
// 规格选择处理
|
||||
var temp_spec = spec[i];
|
||||
var status = false;
|
||||
for (var k in spec_choose[i]['value']) {
|
||||
// 必须是可选和未选
|
||||
if (!status && (spec_choose[i]['value'][k]['is_disabled'] || null) == null && (spec_choose[i]['value'][k]['is_dont'] || null) == null && temp_spec == spec_choose[i]['value'][k]['name']) {
|
||||
self.goods_spec_choice_handle(i, k);
|
||||
status = true;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num >= sku_count) {
|
||||
clearInterval(self.spec_selected_timer);
|
||||
}
|
||||
}, 100);
|
||||
var timerout = setTimeout(function () {
|
||||
clearInterval(self.spec_selected_timerout);
|
||||
}, 20000);
|
||||
self.setData({
|
||||
spec_selected_timer: timer,
|
||||
spec_selected_timerout: timerout,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 默认选中第一个规格 - 智能工具箱插件
|
||||
plugins_intellectstools_selected_spec_handle(spec_choose) {
|
||||
// 选择处理
|
||||
var self = this;
|
||||
// 销毁之前的任务
|
||||
clearInterval(self.spec_selected_timer);
|
||||
clearInterval(self.spec_selected_timerout);
|
||||
// 读取智能工具插件配置、是否开启
|
||||
var config = self.plugins_intellectstools_config || null;
|
||||
if (config != null && (config.is_goods_detail_selected_first_spec || 0) == 1) {
|
||||
// 必须存在购买和加入购物车任意一个、规格必须多个
|
||||
var sku_count = app.globalData.get_length(spec_choose);
|
||||
// 先清除价格展示信息
|
||||
self.setData({
|
||||
goods_spec_base_price: '...',
|
||||
goods_spec_base_original_price: '...',
|
||||
});
|
||||
var num = 0;
|
||||
var timer = setInterval(function () {
|
||||
for (var i in spec_choose) {
|
||||
// 清除价格展示信息、避免获取价格类型赋值
|
||||
self.setData({
|
||||
goods_spec_base_price: '...',
|
||||
goods_spec_base_original_price: '...',
|
||||
});
|
||||
// 必须不存在已选择项
|
||||
var active =
|
||||
spec_choose[i]['value']
|
||||
.map(function (v) {
|
||||
return v.is_active;
|
||||
})
|
||||
.join('') || null;
|
||||
if (active == null) {
|
||||
// 不能选择规格处理
|
||||
self.spec_handle_dont(i);
|
||||
|
||||
// 规格选择处理
|
||||
var status = false;
|
||||
for (var k in spec_choose[i]['value']) {
|
||||
// 必须是可选和未选
|
||||
if (!status && (spec_choose[i]['value'][k]['is_disabled'] || null) == null && (spec_choose[i]['value'][k]['is_dont'] || null) == null) {
|
||||
self.goods_spec_choice_handle(i, k);
|
||||
status = true;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num >= sku_count) {
|
||||
clearInterval(self.spec_selected_timer);
|
||||
}
|
||||
}, 100);
|
||||
var timerout = setTimeout(function () {
|
||||
clearInterval(self.spec_selected_timerout);
|
||||
}, 20000);
|
||||
self.setData({
|
||||
spec_selected_timer: timer,
|
||||
spec_selected_timerout: timerout,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 弹层关闭
|
||||
popup_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
},
|
||||
|
||||
// 规格事件
|
||||
goods_spec_choice_event(e) {
|
||||
var key = e.currentTarget.dataset.key || 0;
|
||||
var keys = e.currentTarget.dataset.keys || 0;
|
||||
this.goods_spec_choice_handle(key, keys);
|
||||
},
|
||||
|
||||
// 规格选择处理
|
||||
goods_spec_choice_handle(key, keys) {
|
||||
var temp_spec = this.goods_spec_choose;
|
||||
var temp_images = this.goods_spec_base_images;
|
||||
// 不能选择和禁止选择跳过
|
||||
if ((temp_spec[key]['value'][keys]['is_dont'] || null) == null && (temp_spec[key]['value'][keys]['is_disabled'] || null) == null) {
|
||||
// 规格选择
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if ((temp_spec[i]['value'][k]['is_dont'] || null) == null && (temp_spec[i]['value'][k]['is_disabled'] || null) == null) {
|
||||
if (key == i) {
|
||||
if (keys == k && (temp_spec[i]['value'][k]['is_active'] || null) == null) {
|
||||
temp_spec[i]['value'][k]['is_active'] = 'cr-white bg-main br-main';
|
||||
if ((temp_spec[i]['value'][k]['images'] || null) != null) {
|
||||
temp_images = temp_spec[i]['value'][k]['images'];
|
||||
}
|
||||
} else {
|
||||
temp_spec[i]['value'][k]['is_active'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
goods_spec_choose: temp_spec,
|
||||
goods_spec_base_images: temp_images,
|
||||
});
|
||||
|
||||
// 不能选择规格处理
|
||||
this.spec_handle_dont(key);
|
||||
|
||||
// 获取下一个规格类型
|
||||
this.get_spec_type(key);
|
||||
|
||||
// 获取规格详情
|
||||
this.get_spec_detail();
|
||||
|
||||
// 规格选择回调
|
||||
this.$emit('SpecChoiceEvent', {
|
||||
goods_id: this.goods.id,
|
||||
spec: this.choice_spec_data(),
|
||||
goods_spec_choose: this.goods_spec_choose,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 获取下一个规格类型
|
||||
get_spec_type(key) {
|
||||
var temp_spec = this.goods_spec_choose;
|
||||
var active_index = parseInt(key) + 1;
|
||||
var sku_count = app.globalData.get_length(temp_spec);
|
||||
if (active_index <= 0 || active_index >= sku_count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取规格值
|
||||
var spec = this.choice_spec_data();
|
||||
if (spec.length <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
var data = this.params;
|
||||
data['id'] = this.goods.id;
|
||||
data['spec'] = JSON.stringify(spec);
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('spectype', 'goods'),
|
||||
method: 'POST',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
var spec_type = res.data.data.spec_type;
|
||||
var spec_count = spec.length;
|
||||
var index = spec_count > 0 ? spec_count : 0;
|
||||
if (index < sku_count) {
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if (index == i) {
|
||||
temp_spec[i]['value'][k]['is_dont'] = '';
|
||||
var temp_value = temp_spec[i]['value'][k]['name'];
|
||||
var temp_status = false;
|
||||
for (var t in spec_type) {
|
||||
if (spec_type[t] == temp_value) {
|
||||
temp_status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (temp_status == true) {
|
||||
temp_spec[i]['value'][k]['is_disabled'] = '';
|
||||
} else {
|
||||
temp_spec[i]['value'][k]['is_disabled'] = 'spec-items-disabled';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
goods_spec_choose: temp_spec,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 选择规格数据
|
||||
choice_spec_data() {
|
||||
var spec = [];
|
||||
var temp_spec = this.goods_spec_choose;
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
|
||||
spec.push({
|
||||
type: temp_spec[i]['name'],
|
||||
value: temp_spec[i]['value'][k]['name'],
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return spec;
|
||||
},
|
||||
|
||||
// 获取规格详情
|
||||
get_spec_detail() {
|
||||
// 获取规格值
|
||||
var spec = this.goods_selected_spec();
|
||||
|
||||
// 存在规格的时候是否已完全选择规格
|
||||
var sku_count = this.goods_spec_choose.length;
|
||||
var active_count = spec.length;
|
||||
if (spec.length <= 0 || active_count < sku_count) {
|
||||
var buy_number = parseInt(this.buy_number);
|
||||
var buy_min_number = parseInt(this.goods.buy_min_number || 1);
|
||||
var buy_max_number = parseInt(this.goods.buy_max_number || 0);
|
||||
if (buy_number < buy_min_number) {
|
||||
buy_number = buy_min_number;
|
||||
}
|
||||
if (buy_max_number > 0 && buy_number > buy_max_number) {
|
||||
buy_number = buy_max_number;
|
||||
}
|
||||
this.setData({
|
||||
goods_spec_base_price: this.goods.price,
|
||||
goods_spec_base_original_price: this.goods.original_price || 0,
|
||||
goods_spec_base_inventory: this.goods.inventory,
|
||||
goods_spec_base_buy_min_number: 0,
|
||||
goods_spec_base_buy_max_number: 0,
|
||||
buy_number: buy_number,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
var data = this.params;
|
||||
data['id'] = this.goods.id;
|
||||
data['spec'] = JSON.stringify(spec);
|
||||
data['stock'] = this.buy_number;
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('specdetail', 'goods'),
|
||||
method: 'POST',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
this.goods_spec_detail_back_handle(res.data.data);
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 商品规格详情返回数据处理
|
||||
goods_spec_detail_back_handle(data) {
|
||||
var spec_base = data.spec_base;
|
||||
var buy_number = parseInt(this.buy_number);
|
||||
var spec_buy_min_number = parseInt(spec_base.buy_min_number || 1);
|
||||
var spec_buy_max_number = parseInt(spec_base.buy_max_number || 0);
|
||||
if (spec_buy_min_number > 0 && buy_number < spec_buy_min_number) {
|
||||
buy_number = spec_buy_min_number;
|
||||
}
|
||||
if (spec_buy_max_number > 0 && buy_number > spec_buy_max_number) {
|
||||
buy_number = spec_buy_max_number;
|
||||
}
|
||||
this.setData({
|
||||
goods_spec_base_price: spec_base.price,
|
||||
goods_spec_base_original_price: spec_base.original_price || 0,
|
||||
goods_spec_base_inventory: parseInt(spec_base.inventory || 0),
|
||||
goods_spec_base_buy_min_number: spec_buy_min_number,
|
||||
goods_spec_base_buy_max_number: spec_buy_max_number,
|
||||
buy_number: buy_number,
|
||||
});
|
||||
|
||||
// 调用父级
|
||||
this.$emit("BackSuccessEvent", {
|
||||
buy_number: this.buy_number,
|
||||
base_price: this.goods_spec_base_price,
|
||||
base_original_price: this.goods_spec_base_original_price,
|
||||
base_inventory: this.goods_spec_base_inventory,
|
||||
base_buy_min_number: this.goods_spec_base_buy_min_number,
|
||||
base_buy_max_number: this.goods_spec_base_buy_max_number,
|
||||
back_data: data
|
||||
});
|
||||
},
|
||||
|
||||
// 已选的商品规格
|
||||
goods_selected_spec() {
|
||||
var spec = [];
|
||||
var temp_spec = this.goods_spec_choose;
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
|
||||
spec.push({
|
||||
type: temp_spec[i]['name'],
|
||||
value: temp_spec[i]['value'][k]['name'],
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return spec;
|
||||
},
|
||||
|
||||
// 不能选择规格处理
|
||||
spec_handle_dont(key, is_init = 0) {
|
||||
var temp_spec = this.goods_spec_choose || [];
|
||||
if (temp_spec.length <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 是否不能选择
|
||||
key = parseInt(key);
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if (i > key) {
|
||||
temp_spec[i]['value'][k]['is_dont'] = 'spec-dont-choose';
|
||||
temp_spec[i]['value'][k]['is_disabled'] = '';
|
||||
temp_spec[i]['value'][k]['is_active'] = '';
|
||||
} else {
|
||||
if (is_init == 1) {
|
||||
temp_spec[i]['value'][k]['is_active'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 当只有一个规格的时候
|
||||
if (key == 0 && temp_spec.length == 1) {
|
||||
temp_spec[i]['value'][k]['is_disabled'] = (temp_spec[i]['value'][k]['is_only_level_one'] || null) != null && parseInt(temp_spec[i]['value'][k]['inventory'] || 0) <= 0 ? 'spec-items-disabled' : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
goods_spec_choose: temp_spec,
|
||||
});
|
||||
},
|
||||
|
||||
// 数量输入事件
|
||||
goods_buy_number_blur(e) {
|
||||
var number = parseInt(e.detail.value) || 1;
|
||||
if (isNaN(number)) {
|
||||
number = this.goods.buy_min_number || 1;
|
||||
}
|
||||
this.goods_buy_number_func(number);
|
||||
},
|
||||
|
||||
// 数量操作事件
|
||||
goods_buy_number_event(e) {
|
||||
var type = parseInt(e.currentTarget.dataset.type || 0);
|
||||
var temp_number = parseInt(this.buy_number);
|
||||
var number = type == 0 ? temp_number - 1 : temp_number + 1;
|
||||
this.goods_buy_number_func(number);
|
||||
},
|
||||
|
||||
// 数量处理方法
|
||||
goods_buy_number_func(number) {
|
||||
var buy_min_number = parseInt(this.goods.buy_min_number || 1);
|
||||
var buy_max_number = parseInt(this.goods.buy_max_number || 0);
|
||||
var spec_buy_min_number = parseInt(this.goods_spec_base_buy_min_number || 0);
|
||||
var spec_buy_max_number = parseInt(this.goods_spec_base_buy_max_number || 0);
|
||||
var inventory = parseInt(this.goods_spec_base_inventory || 0);
|
||||
var inventory_unit = this.goods.inventory_unit;
|
||||
|
||||
// 最小起购数量
|
||||
var min = spec_buy_min_number > 0 ? spec_buy_min_number : buy_min_number;
|
||||
if (min > 0 && number < min) {
|
||||
number = min;
|
||||
app.globalData.showToast(this.$t('recommend-detail.recommend-detail.265vyu') + min + inventory_unit);
|
||||
}
|
||||
|
||||
// 最大购买数量
|
||||
var max = spec_buy_max_number > 0 ? spec_buy_max_number : buy_max_number;
|
||||
if (max > 0 && number > max) {
|
||||
number = max;
|
||||
app.globalData.showToast(this.$t('goods-category.goods-category.z1eh3v') + max + inventory_unit);
|
||||
}
|
||||
|
||||
// 是否超过库存数量
|
||||
if (number > inventory) {
|
||||
number = inventory;
|
||||
app.globalData.showToast(this.$t('recommend-detail.recommend-detail.2sis3v') + inventory + inventory_unit);
|
||||
}
|
||||
|
||||
this.setData({ buy_number: number });
|
||||
|
||||
// 存在规格的时候是否已完全选择规格
|
||||
var spec = this.goods_selected_spec();
|
||||
var sku_count = this.goods_spec_choose.length;
|
||||
var active_count = spec.length;
|
||||
if (sku_count > 0 && active_count < sku_count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
var data = this.params;
|
||||
data['id'] = this.goods.id;
|
||||
data['spec'] = spec;
|
||||
data['stock'] = this.buy_number;
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('stock', 'goods'),
|
||||
method: 'POST',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
this.goods_spec_detail_back_handle(res.data.data);
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 详情图片查看
|
||||
goods_detail_images_view_event(e) {
|
||||
var value = e.currentTarget.dataset.value || null;
|
||||
if (value != null) {
|
||||
uni.previewImage({
|
||||
current: value,
|
||||
urls: [value],
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 规格确认事件
|
||||
spec_confirm_event(e = null) {
|
||||
var user = app.globalData.get_user_info(this, 'spec_confirm_event');
|
||||
if (user != false) {
|
||||
// 规格
|
||||
var temp_data = this.goods_spec_choose;
|
||||
var sku_count = temp_data.length;
|
||||
var active_count = 0;
|
||||
var spec = [];
|
||||
if (sku_count > 0) {
|
||||
for (var i in temp_data) {
|
||||
for (var k in temp_data[i]['value']) {
|
||||
if ((temp_data[i]['value'][k]['is_active'] || null) != null) {
|
||||
active_count++;
|
||||
spec.push({
|
||||
type: temp_data[i]['name'],
|
||||
value: temp_data[i]['value'][k]['name'],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (active_count < sku_count) {
|
||||
app.globalData.showToast(this.$t('goods-detail.goods-detail.6brk57'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 操作类型
|
||||
var type = (e == null) ? this.buy_event_type : (e.currentTarget.dataset.type || this.buy_event_type);
|
||||
var value = (e == null) ? null : (e.currentTarget.dataset.value || null);
|
||||
var business = (e == null) ? null : (e.currentTarget.dataset.business || null);
|
||||
switch (type) {
|
||||
// 展示型、商品页面规格选择展示型 拨打电话操作
|
||||
case 'show':
|
||||
case 'spec-show':
|
||||
app.globalData.call_tel(value || app.globalData.get_config('config.common_app_customer_service_tel'));
|
||||
break;
|
||||
|
||||
// 购买
|
||||
case 'buy':
|
||||
// 进入订单确认页面
|
||||
var data = {
|
||||
buy_type: 'goods',
|
||||
goods_data: encodeURIComponent(
|
||||
base64.encode(
|
||||
JSON.stringify([
|
||||
{
|
||||
goods_id: this.goods.id,
|
||||
stock: this.buy_number,
|
||||
spec: spec,
|
||||
},
|
||||
])
|
||||
)
|
||||
)
|
||||
};
|
||||
// 转换数据
|
||||
var data_params = encodeURIComponent(base64.encode(JSON.stringify(data)));
|
||||
|
||||
// 是否互联网医院插件-开处方
|
||||
if(business == 'plugins-hospital') {
|
||||
app.globalData.url_open('/pages/plugins/hospital/prescription/prescription?data=' + data_params);
|
||||
} else {
|
||||
// 默认进去订单确认页面
|
||||
app.globalData.url_open('/pages/buy/buy?data=' + data_params);
|
||||
}
|
||||
// 关闭弹窗
|
||||
this.popup_close_event();
|
||||
break;
|
||||
|
||||
// 加入购物车
|
||||
case 'cart':
|
||||
this.goods_cart_event(spec);
|
||||
break;
|
||||
|
||||
default:
|
||||
app.globalData.showToast(this.$t('goods-buy.goods-buy.4maexq') + type + ')');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 加入购物车事件
|
||||
goods_cart_event(spec) {
|
||||
var data = this.params;
|
||||
data['goods_id'] = this.goods.id;
|
||||
data['spec'] = JSON.stringify(spec);
|
||||
data['stock'] = this.buy_number;
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('save', 'cart'),
|
||||
method: 'POST',
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
// 是否成功提示
|
||||
if (this.is_success_tips == 1) {
|
||||
app.globalData.showToast(res.data.msg, 'success');
|
||||
}
|
||||
var cart_number = res.data.data.buy_number;
|
||||
|
||||
// 调用父级
|
||||
this.$emit('CartSuccessEvent', {
|
||||
goods_id: this.goods.id,
|
||||
spec: spec,
|
||||
stock: this.buy_number,
|
||||
cart_number: cart_number,
|
||||
back_data: this.back_data,
|
||||
goods_spec_choose: this.goods_spec_choose,
|
||||
});
|
||||
|
||||
// 是否返回定义来源返回
|
||||
if (parseInt(this.params.is_opt_buy_status || 0) == 1 && this.is_opt_back == 1) {
|
||||
setTimeout(function () {
|
||||
uni.navigateBack();
|
||||
}, 1000);
|
||||
} else {
|
||||
// 关闭购买弹窗窗口
|
||||
this.popup_close_event();
|
||||
}
|
||||
} else {
|
||||
if (app.globalData.is_login_check(res.data, this, 'spec_confirm_event')) {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.goods-spec-choice-container .close {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
.goods-spec-base {
|
||||
height: 230rpx;
|
||||
}
|
||||
.goods-spec-base .spec-images {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.goods-spec-base-content {
|
||||
position: absolute;
|
||||
left: 220rpx;
|
||||
top: 0;
|
||||
}
|
||||
.goods-spec-choice-content {
|
||||
max-height: 50vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.goods-spec-choice-container .item .spec .spec-btn {
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.goods-spec-choice-container .item .spec .spec-btn:not(:last-child) {
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
.goods-spec-choice-container .item .spec .spec-btn .spec-images {
|
||||
width: 40rpx;
|
||||
height: 40rpx !important;
|
||||
}
|
||||
.goods-spec-choice-container .spec-dont-choose {
|
||||
color: #b4b3b3 !important;
|
||||
background-color: #ffffff !important;
|
||||
border: 1px solid #ebeaea !important;
|
||||
}
|
||||
.goods-spec-choice-container .spec-dont-choose .spec-images {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.goods-spec-choice-container .spec-items-disabled {
|
||||
color: #d2cfcf !important;
|
||||
background-color: #ffffff !important;
|
||||
border: 1px dashed #d5d5d5 !important;
|
||||
}
|
||||
.goods-spec-choice-container .spec-items-disabled .spec-images {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.goods-spec-choice-container .goods-buy-number {
|
||||
height: 70rpx;
|
||||
}
|
||||
.goods-spec-choice-container .number-content {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 0;
|
||||
background: #eee;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
.goods-spec-choice-container .number-content .number-submit {
|
||||
width: 80rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.goods-spec-choice-container .number-content .number-input {
|
||||
width: 50px;
|
||||
}
|
||||
.goods-spec-choice-container .number-content .number-submit,
|
||||
.goods-spec-choice-container .number-content .number-input {
|
||||
padding: 0;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
}
|
||||
.goods-spec-choice-container .buy-nav-btn-number-0 .item,
|
||||
.goods-spec-choice-container .buy-nav-btn-number-1 .item {
|
||||
width: 100% !important;
|
||||
}
|
||||
.goods-spec-choice-container .buy-nav-btn-number-2 .item {
|
||||
width: 50% !important;
|
||||
}
|
||||
.goods-spec-choice-container .buy-nav-btn-number-3 .item {
|
||||
width: 33.33% !important;
|
||||
}
|
||||
.goods-spec-choice-container .buy-nav-btn-number-4 .item {
|
||||
width: 25% !important;
|
||||
}
|
||||
</style>
|
||||
127
components/goods-comments/goods-comments.vue
Normal file
127
components/goods-comments/goods-comments.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<block v-if="(propData || null) != null && propData.length > 0">
|
||||
<view v-for="(item, index) in propData" :key="index" class="goods-comment-item flex-row" :class="propClass">
|
||||
<image class="avatar dis-block margin-right-xs" :src="item.user.avatar || common_static_url + 'default-user.png'" mode="aspectFit"></image>
|
||||
<view class="base-nav flex-1 flex-width margin-left-sm" :class="propIsReply ? 'is-reply' : ''">
|
||||
<view class="oh nav padding-bottom-sm">
|
||||
<view class="">
|
||||
<text class="va-m">{{ item.user.user_name_view }}</text>
|
||||
<view class="dis-inline-block va-m margin-left-sm">
|
||||
<uni-rate :value="item.rating" :readonly="true" :is-fill="false" :size="14" />
|
||||
</view>
|
||||
<view class="fr">
|
||||
<text class="cr-grey text-size-xs">{{ item.add_time_date }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="base-content oh padding-vertical-sm">
|
||||
<view class="content cr-base text-size-sm">{{ item.content }}</view>
|
||||
<view v-if="(item.images || null) != null && item.images.length > 0" class="image-list oh margin-top-lg">
|
||||
<block v-for="(iv, ix) in item.images" :key="ix">
|
||||
<image class="image br radius" @tap="comment_images_show_event" :data-index="index" :data-ix="ix" :src="iv" mode="aspectFit"></image>
|
||||
</block>
|
||||
</view>
|
||||
<view v-if="(item.msg || null) != null" class="spec cr-grey margin-top-lg">{{ item.msg }}</view>
|
||||
<block v-if="propIsReply">
|
||||
<view v-if="item.is_reply == 1 && (item.reply || null) != null" class="reply br-t-dashed margin-top-sm padding-top-sm text-size-sm">
|
||||
<text class="cr-base">{{$t('goods-comments.goods-comments.s65197')}}</text>
|
||||
<text class="reply-desc cr-main-pair">{{ item.reply }}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="tc spacing-mb flex-row jc-c align-c margin-top-xxxxl">
|
||||
<image :src="common_static_url + 'no-comment.png'" mode="widthFix" class="no-comment margin-right-main" />
|
||||
<view class="cr-grey-d">{{$t('goods-comments.goods-comments.1p1r2e')}}</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
var common_static_url = app.globalData.get_static_url('common');
|
||||
export default {
|
||||
props: {
|
||||
propData: {
|
||||
type: [Array,String],
|
||||
default: '',
|
||||
},
|
||||
// 是否需要显示管理员回复
|
||||
propIsReply: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 额外样式控制
|
||||
propClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
common_static_url: common_static_url,
|
||||
};
|
||||
},
|
||||
|
||||
created: function () {},
|
||||
|
||||
methods: {
|
||||
// 评价图片预览
|
||||
comment_images_show_event(e) {
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var ix = e.currentTarget.dataset.ix;
|
||||
uni.previewImage({
|
||||
current: this.propData[index]['images'][ix],
|
||||
urls: this.propData[index]['images'],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
/**
|
||||
* 商品评价
|
||||
*/
|
||||
.goods-comment-item {
|
||||
padding-bottom: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.goods-comment-item .avatar {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #e2e2e2;
|
||||
}
|
||||
.goods-comment-item .base-nav {
|
||||
border-bottom: 2rpx solid #f5f5f5;
|
||||
}
|
||||
.goods-comment-item .base-nav.is-reply {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.goods-comment-item:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.goods-comment-item:last-of-type .base-nav {
|
||||
border: 0;
|
||||
}
|
||||
.goods-comment-item .base-content .content,
|
||||
.goods-comment-item .base-content .reply {
|
||||
line-height: 46rpx;
|
||||
}
|
||||
.goods-comment-item .base-content .image-list .image {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
.goods-comment-item .base-content .image-list .image:not(:last-child) {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.no-comment {
|
||||
width: 174rpx;
|
||||
}
|
||||
</style>
|
||||
395
components/goods-list/goods-list.vue
Normal file
395
components/goods-list/goods-list.vue
Normal file
@@ -0,0 +1,395 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view class="plugins-goods" :class="data.style_type == 2 ? propStyleTypeTowClass : ''" v-if="(data || null) != null && (data.goods_list || null) != null && data.goods_list.length > 0">
|
||||
<view v-if="(data.title || null) != null || (data.vice_title || null) != null" class="spacing-nav-title flex-row align-c jc-sb text-size-xs">
|
||||
<view class="title-left">
|
||||
<text v-if="(data.title || null) != null" class="text-wrapper" :class="data.style_type == 2 ? '' : 'title-left-border'" :style="'color:' + (data.color || '#333') + ';'">{{ data.title }}</text>
|
||||
<text v-if="(data.vice_title || null) != null" class="vice-name margin-left-sm cr-grey-9">{{ data.vice_title }}</text>
|
||||
</view>
|
||||
<text v-if="(data[propMoreUrlKey] || null) != null" :data-value="data[propMoreUrlKey]" @tap="url_event" class="arrow-right padding-right cr-grey cp">{{ $t('common.more') }}</text>
|
||||
</view>
|
||||
<view class="wh-auto oh pr goods-list">
|
||||
<!-- 默认图文 -->
|
||||
<block v-if="(data.style_type || 0) == 0">
|
||||
<view class="goods-data-list">
|
||||
<view v-for="(item, index) in data.goods_list" :key="index" class="item oh padding-main border-radius-main bg-white oh pr spacing-mb">
|
||||
<!-- 商品主体内容 -->
|
||||
<view class="cp" :data-index="index" :data-value="item.goods_url" @tap="goods_event">
|
||||
<image class="goods-img fl radius" :src="item.images" mode="aspectFit"></image>
|
||||
<view class="base fr">
|
||||
<view class="multi-text">{{ item.title }}</view>
|
||||
<view v-if="(item.simple_desc || null) != null" class="cr-grey single-text margin-top-sm text-size-sm">{{ item.simple_desc }}</view>
|
||||
<view v-if="(item.show_field_price_status || 0) == 1"class="flex-row jc-sb align-c margin-top-main pr">
|
||||
<block v-if="(propPriceField || null) != null && item[propPriceField] != undefined">
|
||||
<view class="base-bottom">
|
||||
<text v-if="propIsShowPriceIcon && (item.price_icon || null) != null" class="bg-red br-red cr-white text-size-xs padding-left-sm padding-right-sm round va-m margin-right-xs">{{ item.price_icon }}</text>
|
||||
<text class="sales-price va-m text-size-xs va-m">{{ item.show_price_symbol }}</text>
|
||||
<text class="sales-price va-m">{{ item[propPriceField] }}</text>
|
||||
<text class="cr-grey text-size-xs va-m">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="(item.is_error || 0) == 0 && is_show_cart">
|
||||
<view v-if="propOpenCart" class="bg-white right-cart-icon pr" :data-index="index" @tap.stop="goods_cart_event">
|
||||
<iconfont name="icon-cart-inc" size="48rpx" :color="theme_color"></iconfont>
|
||||
<view class="cart-badge-icon pa">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 标签插件 -->
|
||||
<view v-if="(propLabel || null) != null && propLabel.data.length > 0" :class="'plugins-label oh pa plugins-label-' + ((propLabel.base.is_user_goods_label_icon || 0) == 0 ? 'text' : 'img') + ' plugins-label-' + (propLabel.base.user_goods_show_style || 'top-left')">
|
||||
<block v-for="(lv, li) in propLabel.data" :key="li">
|
||||
<view v-if="(lv.goods_ids || null) != null && lv.goods_ids.indexOf(item.id) != -1" class="lv dis-inline-block va-m" :data-value="(propLabel.base.is_user_goods_label_url || 0) == 1 ? lv.url || '' : ''" @tap="url_event">
|
||||
<view v-if="(propLabel.base.is_user_goods_label_icon || 0) == 0" class="round cr-white bg-main text-size-xs fl" :style="('background-color:'+(lv.bg_color || '#666'))+' !important;'+('color:'+(lv.text_color || '#fff'))+' !important;'">
|
||||
{{ lv.name }}
|
||||
</view>
|
||||
<block v-else>
|
||||
<image v-if="(lv.icon || null) != null" class="dis-block" :src="lv.icon" mode="scaleToFill"></image>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 九方格 -->
|
||||
<block v-else-if="data.style_type == 1">
|
||||
<view class="goods-data-grid-list flex-row flex-wrap">
|
||||
<view v-for="(item, index) in data.goods_list" :key="index" class="item oh border-radius-main bg-white oh pr spacing-mb">
|
||||
<!-- 商品主体内容 -->
|
||||
<view class="cp" :data-index="index" :data-value="item.goods_url" @tap="goods_event">
|
||||
<image class="goods-img dis-block wh-auto" :src="item.images" mode="widthFix"></image>
|
||||
<view class="base padding-horizontal-main margin-top-sm">
|
||||
<view class="goods-title multi-text">{{ item.title }}</view>
|
||||
<view v-if="(item.show_field_price_status || 0) == 1" class="margin-top-sm flex-row jc-sb align-c pr">
|
||||
<view :class="propIsOpenGridBtnSet ? 'open-grid-btn' : ''">
|
||||
<block v-if="(propPriceField || null) != null && item[propPriceField] != undefined">
|
||||
<text v-if="propIsShowPriceIcon && (item.price_icon || null) != null" class="bg-red br-red cr-white text-size-xs padding-left-sm padding-right-sm round va-m margin-right-xs">{{ item.price_icon }}</text>
|
||||
<text class="sales-price va-m text-size-xs va-m">{{ item.show_price_symbol }}</text>
|
||||
<text class="sales-price va-m">{{ item[propPriceField] }}</text>
|
||||
<text class="cr-grey text-size-xs va-m">{{ item.show_price_unit }}</text>
|
||||
</block>
|
||||
</view>
|
||||
<block v-if="propIsOpenGridBtnSet">
|
||||
<view class="pa bottom-0 right-0" :disabled="grid_btn_config.disabled" @tap="url_event" :style="[{ color: grid_btn_config.color }, { 'background-color': grid_btn_config.bg_color }, { padding: grid_btn_config.padding }, { 'border-radius': grid_btn_config.border_radius }, { 'font-size': grid_btn_config.font_size }]">
|
||||
{{ grid_btn_config.name }}
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<block v-if="(item.is_error || 0) == 0 && is_show_cart">
|
||||
<view v-if="propOpenCart" class="bg-white pr" :data-index="index" @tap.stop="goods_cart_event">
|
||||
<iconfont name="icon-cart-inc" size="48rpx" :color="theme_color"></iconfont>
|
||||
<view class="cart-badge-icon pa">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 标签插件 -->
|
||||
<view v-if="(propLabel || null) != null && propLabel.data.length > 0" :class="'plugins-label oh pa plugins-label-' + ((propLabel.base.is_user_goods_label_icon || 0) == 0 ? 'text' : 'img') + ' plugins-label-' + (propLabel.base.user_goods_show_style || 'top-left')">
|
||||
<block v-for="(lv, li) in propLabel.data" :key="li">
|
||||
<view v-if="(lv.goods_ids || null) != null && lv.goods_ids.indexOf(item.id) != -1" class="lv dis-inline-block va-m" :data-value="(propLabel.base.is_user_goods_label_url || 0) == 1 ? lv.url || '' : ''" @tap="url_event">
|
||||
<view v-if="(propLabel.base.is_user_goods_label_icon || 0) == 0" class="round cr-white bg-main text-size-xs fl" :style="('background-color:'+(lv.bg_color || '#666'))+' !important;'+('color:'+(lv.text_color || '#fff'))+' !important;'">
|
||||
{{ lv.name }}
|
||||
</view>
|
||||
<block v-else>
|
||||
<image v-if="(lv.icon || null) != null" class="dis-block" :src="lv.icon" mode="scaleToFill"></image>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 滚动 -->
|
||||
<view v-else-if="data.style_type == 2" class="rolling-horizontal border-radius-main oh">
|
||||
<view class="goods-data-rolling-list scroll-view-horizontal">
|
||||
<swiper class="swiper" :vertical="false" :autoplay="propIsAutoPlay" :circular="false" :display-multiple-items="(data.multiple_items || null) == null ? (data.goods_list.length < 3 ? data.goods_list.length : 3) : data.goods_list.length < data.multiple_items ? data.goods_list.length : data.multiple_items" interval="3000">
|
||||
<block v-for="(item, index) in data.goods_list" :key="index">
|
||||
<swiper-item>
|
||||
<view class="item bg-white border-radius-main margin-right-main oh pr ht-auto pr">
|
||||
<!-- 商品主体内容 -->
|
||||
<view class="cp" :data-index="index" :data-value="item.goods_url" @tap="goods_event">
|
||||
<image class="goods-img dis-block wh-auto" :src="item.images" mode="scaleToFill"></image>
|
||||
<view class="padding-left-sm padding-right-sm margin-top-sm">
|
||||
<view class="single-text text-size-xs">{{ item.title }}</view>
|
||||
<view v-if="(item.show_field_price_status || 0) == 1" class="margin-top-xs flex-row align-c">
|
||||
<block v-if="(item.is_error || 0) == 0 && is_show_cart">
|
||||
<view v-if="propOpenCart" class="bg-white right-cart-icon pr" :data-index="index" @tap.stop="goods_cart_event">
|
||||
<iconfont name="icon-cart-inc" size="28rpx" :color="theme_color" propClass="pr top-xs margin-right-xs"></iconfont>
|
||||
<view class="cart-badge-icon pa">
|
||||
<component-badge :propNumber="item.user_cart_count || 0"></component-badge>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="(propPriceField || null) != null && item[propPriceField] != undefined">
|
||||
<view class="flex-1 flex-width">
|
||||
<text v-if="propIsShowPriceIcon && (item.price_icon || null) != null" class="bg-red br-red cr-white text-size-xs padding-left-sm padding-right-sm round va-m margin-right-xs">{{ item.price_icon }}</text>
|
||||
<text class="sales-price va-m text-size-xs va-m">{{ item.show_price_symbol }}</text>
|
||||
<text class="sales-price va-m">{{ item[propPriceField] }}</text>
|
||||
<text class="cr-grey text-size-xs va-m">{{ item.show_price_unit }}</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 标签插件 -->
|
||||
<view v-if="(propLabel || null) != null && propLabel.data.length > 0" :class="'plugins-label oh pa plugins-label-' + ((propLabel.base.is_user_goods_label_icon || 0) == 0 ? 'text' : 'img') + ' plugins-label-' + (propLabel.base.user_goods_show_style || 'top-left')">
|
||||
<block v-for="(lv, li) in propLabel.data" :key="li">
|
||||
<view v-if="(lv.goods_ids || null) != null && lv.goods_ids.indexOf(item.id) != -1" class="lv dis-inline-block va-m" :data-value="(propLabel.base.is_user_goods_label_url || 0) == 1 ? lv.url || '' : ''" @tap="url_event">
|
||||
<view v-if="(propLabel.base.is_user_goods_label_icon || 0) == 0" class="round cr-white bg-main text-size-xs fl" :style="('background-color:'+(lv.bg_color || '#666'))+' !important;'+('color:'+(lv.text_color || '#fff'))+' !important;'">
|
||||
{{ lv.name }}
|
||||
</view>
|
||||
<block v-else>
|
||||
<image v-if="(lv.icon || null) != null" class="dis-block" :src="lv.icon" mode="scaleToFill"></image>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</block>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品购买 -->
|
||||
<component-goods-buy v-if="is_show_cart" ref="goods_buy" v-on:CartSuccessEvent="goods_cart_back_event"></component-goods-buy>
|
||||
|
||||
<!-- 购物车抛物线 -->
|
||||
<component-cart-para-curve v-if="is_show_cart" ref="cart_para_curve"></component-cart-para-curve>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentBadge from '@/components/badge/badge';
|
||||
import componentGoodsBuy from '@/components/goods-buy/goods-buy';
|
||||
import componentCartParaCurve from '@/components/cart-para-curve/cart-para-curve';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
data: null,
|
||||
is_show_cart: false,
|
||||
theme_color: app.globalData.get_theme_color(),
|
||||
grid_btn_config: {
|
||||
bg_color: '#D8D8D8',
|
||||
color: '#fff',
|
||||
name: this.$t('goods-list.goods-list.nr77jf'),
|
||||
disabled: false,
|
||||
border_radius: '24rpx',
|
||||
padding: '6rpx 16rpx',
|
||||
font_size: '24rpx',
|
||||
},
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentBadge,
|
||||
componentGoodsBuy,
|
||||
componentCartParaCurve,
|
||||
},
|
||||
props: {
|
||||
// 价格符号
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol(),
|
||||
},
|
||||
// 列表数据
|
||||
propData: {
|
||||
type: [Array, Object],
|
||||
default: [],
|
||||
},
|
||||
// 模式2默认class
|
||||
propStyleTypeTowClass: {
|
||||
type: String,
|
||||
default: 'bg-white border-radius-main padding-main spacing-mb',
|
||||
},
|
||||
// 更多url地址
|
||||
propMoreUrlKey: {
|
||||
type: String,
|
||||
default: 'url',
|
||||
},
|
||||
// 关键字url地址
|
||||
propKeywordsUrl: {
|
||||
type: String,
|
||||
default: '/pages/goods-search/goods-search?keywords=',
|
||||
},
|
||||
// 滚动自动播放
|
||||
propIsAutoPlay: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 标签数据
|
||||
propLabel: {
|
||||
type: [Array, Object, String],
|
||||
default: null,
|
||||
},
|
||||
// 展示加购抛物线
|
||||
propIsCartParaCurve: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 展示价格icon图标
|
||||
propIsShowPriceIcon: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 展示价格字段
|
||||
propPriceField: {
|
||||
type: String,
|
||||
default: 'min_price',
|
||||
},
|
||||
// 来源
|
||||
propSource: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 当开启时以前的按钮将失效
|
||||
propIsOpenGridBtnSet: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 九宫格 按钮样式, ----- 需要和propIsOpenGridBtnSet一起使用
|
||||
propGridBtnConfig: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
// 是否开启购物车按钮 ------ 滚动使用
|
||||
propOpenCart: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否开启购物车数量同步到底部导航
|
||||
propIsCartNumberTabBarBadgeSync: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propData(value, old_value) {
|
||||
this.setData({
|
||||
data: value,
|
||||
});
|
||||
},
|
||||
propIsOpenGridBtnSet(newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
this.setData({
|
||||
grid_btn_config: Object.assign({}, this.grid_btn_config, this.propGridBtnConfig),
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
var is_app_mourning = app.globalData.is_app_mourning();
|
||||
var is_show_cart = app.globalData.data.is_goods_list_show_cart_opt == 1 ? (is_app_mourning && this.propSource == 'index' ? false : true) : false;
|
||||
this.setData({
|
||||
data: this.propData,
|
||||
is_show_cart: is_show_cart,
|
||||
grid_btn_config: Object.assign({}, this.grid_btn_config, this.propGridBtnConfig),
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 加入购物车
|
||||
goods_cart_event(e) {
|
||||
if ((this.$refs.goods_buy || null) != null) {
|
||||
var index = e.currentTarget.dataset.index || 0;
|
||||
var goods = this.propData.goods_list[index];
|
||||
// 开启购物车抛物线效果则展示提示操作
|
||||
var is_success_tips = this.propIsCartParaCurve ? 0 : 1;
|
||||
this.$refs.goods_buy.init(
|
||||
goods,
|
||||
{
|
||||
buy_event_type: 'cart',
|
||||
is_direct_cart: 1,
|
||||
is_success_tips: is_success_tips,
|
||||
},
|
||||
{
|
||||
index: index,
|
||||
pos: e,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// 加入购物车成功回调
|
||||
goods_cart_back_event(e) {
|
||||
// 增加数量
|
||||
var back = e.back_data;
|
||||
var new_data = this.data;
|
||||
var goods = new_data['goods_list'][back.index];
|
||||
goods['user_cart_count'] = parseInt(goods['user_cart_count'] || 0) + parseInt(e.stock);
|
||||
if (goods['user_cart_count'] > 99) {
|
||||
goods['user_cart_count'] = '99+';
|
||||
}
|
||||
new_data['goods_list'][back.index] = goods;
|
||||
this.setData({
|
||||
data: new_data,
|
||||
});
|
||||
|
||||
// 抛物线
|
||||
if (this.propIsCartParaCurve && (this.$refs.cart_para_curve || null) != null) {
|
||||
this.$refs.cart_para_curve.init(null, back.pos, goods.images);
|
||||
}
|
||||
|
||||
// 购物车总数
|
||||
var cart_total = e.cart_number || 0;
|
||||
|
||||
// 购物车导航角标
|
||||
if (this.propIsCartNumberTabBarBadgeSync) {
|
||||
app.globalData.set_tab_bar_badge('cart', cart_total);
|
||||
}
|
||||
|
||||
// 当前页面
|
||||
var page = app.globalData.current_page().split('?');
|
||||
switch (page[0]) {
|
||||
// 商品详情页面
|
||||
case 'pages/goods-detail/goods-detail':
|
||||
// 商品搜索
|
||||
case 'pages/goods-search/goods-search':
|
||||
var res = app.globalData.get_page_object(page[0]);
|
||||
if (res.length > 0) {
|
||||
for (var i in res) {
|
||||
res[i].$vm.goods_cart_count_handle(cart_total);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.$emit('CartSuccessEvent', { ...e, ...{ goods_list: new_data.goods_list, goods: goods } });
|
||||
},
|
||||
|
||||
// 商品事件
|
||||
goods_event(e) {
|
||||
// 商品数据缓存处理
|
||||
var goods = this.data.goods_list[e.currentTarget.dataset.index];
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
|
||||
// 调用公共打开url地址
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
|
||||
// 购物车角标变化回调
|
||||
goods_badge_change() {
|
||||
this.$emit('goods_badge_change');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
362
components/goods-spec-choice/goods-spec-choice.vue
Normal file
362
components/goods-spec-choice/goods-spec-choice.vue
Normal file
@@ -0,0 +1,362 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event" :propIndex="propIndex">
|
||||
<view class="goods-spec-choice-container padding-main bg-white pr">
|
||||
<view class="close fr oh">
|
||||
<view class="fr" @tap.stop="popup_close_event">
|
||||
<iconfont name="icon-close-o" size="28rpx" color="#999"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-spec-choice-content">
|
||||
<!-- 商品规格 -->
|
||||
<view v-if="spec.length > 0" class="goods-spec-choose">
|
||||
<view v-for="(item, key) in spec" :key="key" class="item padding-top-xxl padding-bottom-xxl">
|
||||
<view class="text-size-sm">{{item.name}}</view>
|
||||
<view v-if="item.value.length > 0" class="spec margin-top-sm">
|
||||
<block v-for="(items, keys) in item.value" :key="keys">
|
||||
<button @tap.stop="goods_spec_choice_event" :data-key="key" :data-keys="keys" type="default" size="mini" hover-class="none" :class="'round '+items.is_active + ' ' + items.is_dont + ' ' + items.is_disabled">
|
||||
<image v-if="(items.images || null) != null" :src="items.images" mode="scaleToFill" class="va-m dis-inline-block round margin-right-sm"></image>
|
||||
<text class="va-m">{{items.name}}</text>
|
||||
</button>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<button class="bg-main br-main cr-white text-size-sm round" type="default" @tap.stop="spec_confirm_event" hover-class="none">{{$t('index.index.7w75zb')}}</button>
|
||||
</view>
|
||||
</component-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentPopup from "@/components/popup/popup";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
popup_status: false,
|
||||
goods_id: 0,
|
||||
spec: [],
|
||||
buy_min_number: 1,
|
||||
out_value: ''
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
componentPopup
|
||||
},
|
||||
props: {
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 100
|
||||
}
|
||||
},
|
||||
|
||||
created: function() {},
|
||||
|
||||
methods: {
|
||||
// 获取数据
|
||||
init(goods_id, spec, buy_min_number = 1, out_value = '') {
|
||||
this.setData({
|
||||
popup_status: true,
|
||||
goods_id: goods_id,
|
||||
spec: spec || [],
|
||||
buy_min_number: buy_min_number || 1,
|
||||
out_value: out_value,
|
||||
});
|
||||
|
||||
// 不能选择规格处理
|
||||
this.spec_handle_dont(0, 1);
|
||||
},
|
||||
|
||||
// 购买弹层关闭
|
||||
popup_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false
|
||||
});
|
||||
},
|
||||
|
||||
// 规格事件
|
||||
goods_spec_choice_event(e) {
|
||||
var key = e.currentTarget.dataset.key || 0;
|
||||
var keys = e.currentTarget.dataset.keys || 0;
|
||||
this.goods_spec_choice_handle(key, keys);
|
||||
},
|
||||
|
||||
// 规格选择处理
|
||||
goods_spec_choice_handle(key, keys) {
|
||||
var temp_spec = this.spec;
|
||||
// 不能选择和禁止选择跳过
|
||||
if ((temp_spec[key]['value'][keys]['is_dont'] || null) == null && (temp_spec[key]['value'][keys]['is_disabled'] || null) == null) {
|
||||
// 规格选择
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if ((temp_spec[i]['value'][k]['is_dont'] || null) == null && (temp_spec[i]['value'][k]['is_disabled'] || null) == null) {
|
||||
if (key == i) {
|
||||
if (keys == k && (temp_spec[i]['value'][k]['is_active'] || null) == null) {
|
||||
temp_spec[i]['value'][k]['is_active'] = 'cr-white bg-main br-main';
|
||||
} else {
|
||||
temp_spec[i]['value'][k]['is_active'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
spec: temp_spec
|
||||
});
|
||||
|
||||
// 不能选择规格处理
|
||||
this.spec_handle_dont(key);
|
||||
|
||||
// 获取下一个规格类型
|
||||
this.get_spec_type(key);
|
||||
|
||||
// 获取规格详情
|
||||
this.get_spec_detail();
|
||||
}
|
||||
},
|
||||
|
||||
// 获取下一个规格类型
|
||||
get_spec_type(key) {
|
||||
var temp_spec = this.spec;
|
||||
var active_index = parseInt(key) + 1;
|
||||
var sku_count = app.globalData.get_length(temp_spec);
|
||||
if (active_index <= 0 || active_index >= sku_count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取规格值
|
||||
var spec = [];
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
|
||||
spec.push({
|
||||
type: temp_spec[i]['name'],
|
||||
value: temp_spec[i]['value'][k]['name']
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spec.length <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('spectype', 'goods'),
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: this.goods_id,
|
||||
spec: JSON.stringify(spec)
|
||||
},
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
var spec_type = res.data.data.spec_type;
|
||||
var spec_count = spec.length;
|
||||
var index = spec_count > 0 ? spec_count : 0;
|
||||
if (index < sku_count) {
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if (index == i) {
|
||||
temp_spec[i]['value'][k]['is_dont'] = '';
|
||||
var temp_value = temp_spec[i]['value'][k]['name'];
|
||||
var temp_status = false;
|
||||
for (var t in spec_type) {
|
||||
if (spec_type[t] == temp_value) {
|
||||
temp_status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (temp_status == true) {
|
||||
temp_spec[i]['value'][k]['is_disabled'] = '';
|
||||
} else {
|
||||
temp_spec[i]['value'][k]['is_disabled'] = 'spec-items-disabled';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
spec: temp_spec
|
||||
});
|
||||
}
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 获取规格详情
|
||||
get_spec_detail() {
|
||||
// 获取规格值
|
||||
var spec = this.goods_selected_spec();
|
||||
|
||||
// 存在规格的时候是否已完全选择规格
|
||||
var sku_count = this.spec.length;
|
||||
var active_count = spec.length;
|
||||
if (spec.length <= 0 || active_count < sku_count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('specdetail', 'goods'),
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: this.goods_id,
|
||||
spec: JSON.stringify(spec),
|
||||
stock: this.buy_min_number
|
||||
},
|
||||
dataType: 'json',
|
||||
success: res => {
|
||||
if (res.data.code != 0) {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 已选的商品规格
|
||||
goods_selected_spec() {
|
||||
var spec = [];
|
||||
var temp_spec = this.spec;
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
|
||||
spec.push({
|
||||
type: temp_spec[i]['name'],
|
||||
value: temp_spec[i]['value'][k]['name']
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return spec;
|
||||
},
|
||||
|
||||
// 不能选择规格处理
|
||||
spec_handle_dont(key, is_init = 0) {
|
||||
var temp_spec = this.spec || [];
|
||||
if (temp_spec.length <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 是否不能选择
|
||||
key = parseInt(key);
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if (i > key) {
|
||||
temp_spec[i]['value'][k]['is_dont'] = 'spec-dont-choose';
|
||||
temp_spec[i]['value'][k]['is_disabled'] = '';
|
||||
temp_spec[i]['value'][k]['is_active'] = '';
|
||||
} else {
|
||||
if(is_init == 1) {
|
||||
temp_spec[i]['value'][k]['is_active'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 当只有一个规格的时候
|
||||
if (key == 0 && temp_spec.length == 1) {
|
||||
temp_spec[i]['value'][k]['is_disabled'] = (temp_spec[i]['value'][k]['is_only_level_one'] || null) != null && (temp_spec[i]['value'][k]['inventory'] || 0) <= 0 ? 'spec-items-disabled' : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
spec: temp_spec
|
||||
});
|
||||
},
|
||||
|
||||
// 规格确认事件
|
||||
spec_confirm_event(e) {
|
||||
var temp_spec = this.spec;
|
||||
var sku_count = temp_spec.length;
|
||||
var active_count = 0;
|
||||
var spec = [];
|
||||
if (sku_count > 0) {
|
||||
for (var i in temp_spec) {
|
||||
for (var k in temp_spec[i]['value']) {
|
||||
if ((temp_spec[i]['value'][k]['is_active'] || null) != null) {
|
||||
active_count++;
|
||||
spec.push({
|
||||
type: temp_spec[i]['name'],
|
||||
value: temp_spec[i]['value'][k]['name']
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (active_count < sku_count) {
|
||||
app.globalData.showToast(this.$t('goods-detail.goods-detail.6brk57'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
this.setData({
|
||||
popup_status: false
|
||||
});
|
||||
|
||||
// 调用父级
|
||||
this.$emit('specConfirmEvent', {
|
||||
goods_id: this.goods_id,
|
||||
spec: spec,
|
||||
stock: this.buy_min_number,
|
||||
out_value: this.out_value,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.goods-spec-choice-container .close {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
.goods-spec-choice-content {
|
||||
max-height: 50vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.goods-spec-choice-container .item .spec button {
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.goods-spec-choice-container .item .spec button:not(:last-child) {
|
||||
margin-right: 25rpx;
|
||||
}
|
||||
.goods-spec-choice-container .item .spec button image {
|
||||
width: 40rpx;
|
||||
height: 40rpx !important;
|
||||
}
|
||||
.goods-spec-choice-container .spec-dont-choose {
|
||||
color: #b4b3b3 !important;
|
||||
background-color: #ffffff !important;
|
||||
border: 1px solid #ebeaea !important;
|
||||
}
|
||||
.goods-spec-choice-container .spec-dont-choose image {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.goods-spec-choice-container .spec-items-disabled {
|
||||
color: #d2cfcf !important;
|
||||
background-color: #ffffff !important;
|
||||
border: 1px dashed #d5d5d5 !important;
|
||||
}
|
||||
.goods-spec-choice-container .spec-items-disabled image {
|
||||
opacity: 0.3;
|
||||
}
|
||||
</style>
|
||||
140
components/icon-nav/icon-nav.vue
Normal file
140
components/icon-nav/icon-nav.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(propData || null) != null && (propData.data || null) != null && propData.data.length > 0 && swiper_data.length > 0" class="icon-nav-list" :class="propData.data.length > 5 ? 'swiper-height-max' : 'swiper-height-min'">
|
||||
<uni-swiper-dot class="uni-swiper-dot-box" mode="default" :dots-styles="dots_styles" @clickItem="click_item" :info="swiper_data" :current="current">
|
||||
<swiper class="swiper-box" :autoplay="autoplay" :duration="duration" @change="swiper_change" :current="swiper_dot_index">
|
||||
<swiper-item v-for="(swiper_item_data, i) in swiper_data" :key="i">
|
||||
<view class="swiper-item flex-row flex-wrap" :class="'swiper-item' + i">
|
||||
<view v-for="(item, j) in swiper_item_data" :key="j" class="swiper-item item">
|
||||
<view :class="'item-content ' + ((item.bg_color || null) == null ? 'item-exposed' : '')" :data-value="item.event_value" :data-type="item.event_type" @tap="navigation_event" :style="(item.bg_color || null) == null ? '' : 'background-color:' + item.bg_color + ';'">
|
||||
<image class="image" :src="item.images_url" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="title">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</uni-swiper-dot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
swiper_data: [],
|
||||
autoplay: false,
|
||||
duration: 500,
|
||||
styleIndex: -1,
|
||||
current: 0,
|
||||
swiper_dot_index: 0,
|
||||
dots_styles: {
|
||||
backgroundColor: '#eee',
|
||||
bottom: '0',
|
||||
border: '0',
|
||||
color: '#fff',
|
||||
selectedBackgroundColor: app.globalData.get_theme_color(),
|
||||
selectedBorder: '0',
|
||||
},
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propData: {
|
||||
type: [Array, Object],
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propData(value, old_value) {
|
||||
this.handle_data();
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
this.handle_data();
|
||||
},
|
||||
methods: {
|
||||
navigation_event(e) {
|
||||
app.globalData.operation_event(e);
|
||||
},
|
||||
// 数据处理
|
||||
handle_data() {
|
||||
if((this.propData || null) != null && (this.propData.data || null) != null && this.propData.data.length > 0) {
|
||||
this.swiper_data = app.globalData.group_arry(this.propData.data, 10);
|
||||
}
|
||||
},
|
||||
swiper_change(e) {
|
||||
this.current = e.detail.current;
|
||||
},
|
||||
click_item(e) {
|
||||
this.swiper_dot_index = e;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.icon-nav-list {
|
||||
overflow: hidden;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.icon-nav-list .item {
|
||||
width: 20%;
|
||||
float: left;
|
||||
padding: 16rpx 0;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.icon-nav-list .item .item-content {
|
||||
border-radius: 50%;
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
-webkit-box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
|
||||
box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
|
||||
}
|
||||
|
||||
.icon-nav-list .item .item-content,
|
||||
.icon-nav-list .item .image {
|
||||
width: 50rpx !important;
|
||||
height: 50rpx !important;
|
||||
}
|
||||
|
||||
.icon-nav-list .item .item-exposed {
|
||||
padding: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.icon-nav-list .item .item-exposed,
|
||||
.icon-nav-list .item .item-exposed .image {
|
||||
width: 90rpx !important;
|
||||
height: 90rpx !important;
|
||||
}
|
||||
|
||||
.icon-nav-list .item .title {
|
||||
margin-top: 12rpx;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.swiper-height-min /deep/ .swiper-box {
|
||||
height: 180rpx;
|
||||
}
|
||||
|
||||
.swiper-height-max /deep/ .swiper-box {
|
||||
height: 360rpx;
|
||||
}
|
||||
</style>
|
||||
49
components/iconfont/iconfont.vue
Normal file
49
components/iconfont/iconfont.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<view class="iconfont-container" :class="propClass" :style="'display:'+propContainerDisplay+';'">
|
||||
<text class="iconfont" :class="name" :style="[{ color: color }, { 'font-size': size }]" @tap="$emit('click', $event)"></text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '28rpx',
|
||||
},
|
||||
propClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propContainerDisplay: {
|
||||
type: String,
|
||||
default: 'inline-block',
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* iconfont.css全局注册需要将src切换成绝对路径 */
|
||||
/* @/static/icon/ */
|
||||
@import url('@/static/icon/iconfont.css');
|
||||
/* @import url('https://at.alicdn.com/t/c/font_4227145_kbr2f9jt68b.css'); */
|
||||
.iconfont {
|
||||
display: flex;
|
||||
font-size: inherit;
|
||||
overflow: hidden;
|
||||
/* 因icon大小被设置为和字体大小一致,而span等标签的下边缘会和字体的基线对齐,故需设置一个往下的偏移比例,来纠正视觉上的未对齐效果 */
|
||||
vertical-align: -0.15em;
|
||||
outline: none;
|
||||
/* 定义元素的颜色,currentColor是一个变量,这个变量的值就表示当前元素的color值,如果当前元素未设置color值,则从父元素继承 */
|
||||
fill: currentcolor;
|
||||
}
|
||||
</style>
|
||||
1359
components/layout/layout.vue
Normal file
1359
components/layout/layout.vue
Normal file
File diff suppressed because it is too large
Load Diff
246
components/magic-list/magic-list.vue
Normal file
246
components/magic-list/magic-list.vue
Normal file
@@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(data_goods_list || null) != null && data_goods_list.length > 0">
|
||||
<view v-for="(item, index) in data_goods_list" :key="index" class="plugins-magic-content border-radius-main oh spacing-mb">
|
||||
<view v-if="(item.data || null) != null && item.data.length > 0" :style="(item.bg_images || null) !== null ? 'background-image: url(' + item.bg_images + ');background-size: auto 100%;' : (((item.is_text_white || 0) == 1) ? 'background: linear-gradient(180deg, '+theme_color+' 0%, '+theme_color_light+' 80%);' : 'background: #fff;')">
|
||||
<!-- 上下滚动 -->
|
||||
<view v-if="item.show_style == 0" :class="'hot-list flex-row flex-wrap padding-vertical-main '+(((item.is_text_white || 0) == 1) ? 'is-text-white' : '')">
|
||||
<block v-for="(items, indexs) in item.data" :key="indexs">
|
||||
<block v-if="(items.data || null) != null && items.data.length > 0">
|
||||
<view :class="'group-item '+(item.data.length%2 != 0 && item.data.length-1 === indexs ? 'wh-auto' : 'flex-width-half')">
|
||||
<view class="padding-horizontal-main">
|
||||
<view class="flex-row align-c" :data-value="items.url" @tap="url_event">
|
||||
<text :class="'text-size fw-b single-text cr-'+(((item.is_text_white || 0) == 1) ? 'white' : 'black')">{{ items.title }}</text>
|
||||
<view class="hot-go margin-left-sm">
|
||||
<block v-if="(items.icon || null) !== null">
|
||||
<image :src="items.icon" mode="heightFix" class="ht-auto"></image>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<view :class="'single-text text-size-xs margin-top-xs cr-'+(((item.is_text_white || 0) == 1) ? 'white' : 'grey-9')">{{ items.describe }}</view>
|
||||
<swiper class="swiper-list border-radius-main oh" circular :autoplay="(items.rolling_time || null) !== null ? true : false" :vertical="propVertical" :interval="(items.rolling_time || null) !== null ? Number(items.rolling_time) * 1000 : '6000'" :duration="propDuration">
|
||||
<swiper-item v-for="(itemss, indexss) in items.data" :key="indexss">
|
||||
<view class="swiper-item">
|
||||
<view :class="'flex-row gap-10 goods-item-number-'+itemss.length">
|
||||
<view v-for="(gv, gi) in itemss" :key="gi" :class="'bg-white border-radius-main oh flex-width-half '+(itemss.length % 2 != 0 && itemss.length-1 == gi ? 'wh-auto' : '')">
|
||||
<view class="tc" :data-index="index" :data-indexs="indexs" :data-indexss="indexss" :data-gi="gi" :data-value="(gv.goods_url || null) !== null ? gv.goods_url : ''" @tap="goods_event">
|
||||
<image :src="(gv.images || null) !== null ? gv.images : ''" :mode="itemss.length % 2 != 0 && itemss.length-1 == gi ? 'aspectFit' : 'scaleToFill'" :class="'swiper-img wh-auto dis-block '+(((item.is_text_white || 0) == 1) ? '' : 'border-radius-main')"> </image>
|
||||
<view v-if="(gv.show_field_price_status || 0) == 1" :class="'price tc single-text text-line-1 '+(((item.is_text_white || 0) == 1) ? 'padding-horizontal-xs padding-bottom-xs' : '')">
|
||||
<text class="sales-price va-m text-size-xss va-b">{{ gv.show_price_symbol }}</text>
|
||||
<text class="sales-price va-m text-size-xs">{{ gv.min_price }}</text>
|
||||
<text class="va-m text-size-xss cr-grey">{{ gv.show_price_unit }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 1切换滚动、2切换九宫格、3切换滚动 -->
|
||||
<view v-else-if="item.show_style == 1 || item.show_style == 2 || item.show_style == 3" class="switch-tabs-item-list pr padding-top-main">
|
||||
<view class="scroll-view-horizontal padding-left-main">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" :scroll-with-animation="true" :scroll-into-view="'switch-tabs-item-' + (show_style1_active_index[index] || 0)">
|
||||
<block v-for="(items, indexs) in item.data" :key="indexs">
|
||||
<view :class="'tc cp dis-inline-block '+(indexs > 0 ? 'margin-left-xxl' : '')" :id="'switch-tabs-item-' + indexs" :data-index="index" :data-indexs="indexs" @tap="switch_tabs_event">
|
||||
<image v-if="(items.icon || null) != null" :src="items.icon" class="switch-tabs-item-icon va-m margin-right-xs" mode="aspectFit"></image>
|
||||
<text :class="'text-size va-m cr-'+(((item.is_text_white || 0) == 1) ? 'white' : 'black')+' '+((show_style1_active_index[index] || 0) == indexs ? 'fw-b cr-'+(((item.is_text_white || 0) == 1) ? 'white' : 'main') : '')">{{ items.title }} </text>
|
||||
<view class="lh-xs">
|
||||
<iconfont name="icon-down-mark" size="36rpx" :color="(show_style1_active_index[index] || 0) == indexs ? (((item.is_text_white || 0) == 1) ? '#fff' : theme_color) : 'transparent'" propClass="lh-xs"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<block v-for="(items, indexs) in item.data" :key="indexs">
|
||||
<view v-if="(show_style1_active_index[index] || 0) == indexs">
|
||||
<view v-if="(items.url || null) != null" :data-value="items.url" @tap="url_event" class="padding-right cp pa top-xxxxxl right-0">
|
||||
<text :class="'text-size-xs va-m cr-'+(((item.is_text_white || 0) == 1) ? 'white' : 'grey')">{{ $t('common.more') }}</text>
|
||||
<view class="dis-inline-block va-m lh-xs">
|
||||
<iconfont name="icon-arrow-right" size="24rpx" :color="((item.is_text_white || 0) == 1) ? '#f5f5f5' : '#999'"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="(items.describe || null) != null" :class="'text-size-xs single-text padding-vertical-sm padding-horizontal-main cr-'+(((item.is_text_white || 0) == 1) ? 'white' : 'grey')">{{items.describe}}</view>
|
||||
<view :class="(item.show_style == 1 || item.show_style == 2) ? 'padding-horizontal-main padding-top-sm' : (item.show_style == 3 ? 'padding-top-xs padding-bottom-main' : '')">
|
||||
<component-goods-list :propData="{ style_type: parseInt(item.show_style)-1, goods_list: items.goods_list }" :propLabel="propLabel" :propCurrencySymbol="propCurrencySymbol" :propIsAutoPlay="(items.rolling_time || null) != null" :propIsCartParaCurve="true" propSource="index" propStyleTypeTowClass="border-radius-main padding-horizontal-main padding-top-xs"></component-goods-list>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentGoodsList from '@/components/goods-list/goods-list';
|
||||
export default {
|
||||
name: 'recommend-hot',
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
theme_color: app.globalData.get_theme_color(),
|
||||
theme_color_light: app.globalData.get_theme_color(null, true),
|
||||
data_goods_list: [],
|
||||
show_style1_active_index: {},
|
||||
};
|
||||
},
|
||||
props: {
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol(),
|
||||
},
|
||||
propData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propVertical: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propDuration: {
|
||||
type: Number,
|
||||
default: 1000,
|
||||
},
|
||||
// 标签数据
|
||||
propLabel: {
|
||||
type: [Array, Object, String],
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
components: {
|
||||
componentGoodsList
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propData(value, old_value) {
|
||||
this.set_data(value);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.set_data(this.propData);
|
||||
},
|
||||
methods: {
|
||||
// 商品事件
|
||||
goods_event(e) {
|
||||
// 商品数据缓存处理
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var indexs = e.currentTarget.dataset.indexs;
|
||||
var indexss = e.currentTarget.dataset.indexss;
|
||||
var gi = e.currentTarget.dataset.gi;
|
||||
var goods = this.data_goods_list[index]['data'][indexs]['data'][indexss][gi];
|
||||
app.globalData.goods_data_cache_handle(goods.id, goods);
|
||||
|
||||
// 调用公共打开url地址
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
},
|
||||
|
||||
// tabs切换
|
||||
switch_tabs_event(e) {
|
||||
var temp = this.show_style1_active_index || {};
|
||||
temp[e.currentTarget.dataset.index] = e.currentTarget.dataset.indexs;
|
||||
this.setData({
|
||||
show_style1_active_index: temp
|
||||
});
|
||||
},
|
||||
|
||||
// 轮播数据处理
|
||||
set_data(data) {
|
||||
let goods = data.goods;
|
||||
goods.forEach((item) => {
|
||||
switch(parseInt(item.show_style || 0)) {
|
||||
// 上下滚动数据处理
|
||||
case 0 :
|
||||
item.data.forEach((items, indexs) => {
|
||||
let swiper_data = [];
|
||||
if (item.data.length % 2 == 0) {
|
||||
// 偶数
|
||||
swiper_data = app.globalData.group_arry(items.goods_list, 2);
|
||||
} else {
|
||||
// 奇数
|
||||
if (item.data.length === indexs + 1) {
|
||||
swiper_data = app.globalData.group_arry(items.goods_list, 4);
|
||||
} else {
|
||||
swiper_data = app.globalData.group_arry(items.goods_list, 2);
|
||||
}
|
||||
}
|
||||
items.data = swiper_data;
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
data_goods_list: goods,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.plugins-magic-content .hot-list {
|
||||
gap: 10rpx 0;
|
||||
}
|
||||
.plugins-magic-content .hot-list > .flex-width-half {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.plugins-magic-content .hot-list > .flex-width-half:nth-last-of-type(1),
|
||||
.plugins-magic-content .hot-list > .flex-width-half:nth-last-of-type(2) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.plugins-magic-content .hot-list > .flex-width-half:nth-child(even) {
|
||||
position: relative;
|
||||
}
|
||||
.plugins-magic-content .hot-list > .flex-width-half:nth-child(even)::before {
|
||||
content: '';
|
||||
height: 80%;
|
||||
width: 2rpx;
|
||||
border-left: 2rpx solid rgb(232 232 232 / 28%);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.plugins-magic-content .hot-list.is-text-white > .flex-width-half:nth-child(even)::before {
|
||||
border-left: 2rpx solid rgb(255 245 245 / 9%);
|
||||
}
|
||||
.plugins-magic-content .hot-list .swiper-list {
|
||||
height: 216rpx;
|
||||
}
|
||||
.plugins-magic-content .hot-list .swiper-list .swiper-item {
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
.plugins-magic-content .hot-list .swiper-list .swiper-img {
|
||||
height: 140rpx !important;
|
||||
}
|
||||
.plugins-magic-content .hot-go {
|
||||
height: 34rpx;
|
||||
line-height: 34rpx;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换滚动、切换九宫格、切换滚动
|
||||
*/
|
||||
.plugins-magic-content .switch-tabs-item-list > .scroll-view-horizontal {
|
||||
padding-right: 140rpx;
|
||||
}
|
||||
.plugins-magic-content .switch-tabs-item-list .switch-tabs-item-icon {
|
||||
width: 32rpx !important;
|
||||
height: 32rpx !important;
|
||||
}
|
||||
</style>
|
||||
107
components/nav-back/nav-back.vue
Normal file
107
components/nav-back/nav-back.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view class="pa-w" :class="(propFixed ? 'pf z-i left-0 top-0 right-0' : '') + ' ' + propClass" :style="'padding-top:' + (status_bar_height > 0 ? status_bar_height + 5 : 0) + 'px;background-color:rgba(255,255,255,' + opacity + ');' + propStyle">
|
||||
<view v-if="(propName || null) != null || propIsRightSlot || is_show_back" class="nav-back padding-horizontal-main round va-m flex-row align-c" :class="(opacity > 0.3 ? 'cr-black ' : 'cr-white ') + (status_bar_height > 0 ? '' : 'padding-vertical-main')">
|
||||
<view v-if="(propName || null) != null" :class="'text-size-md tc pa left-0 right-0 padding-top-xs ' + propNameClass" :style="propNameOpacity ? (opacity ? 'color:rgba(51,51,51,' + opacity + ')' : '') : ''">{{ propName }}</view>
|
||||
<view v-if="is_show_back" @tap="top_nav_left_back_event" class="dis-inline-block">
|
||||
<iconfont name="icon-arrow-left" size="40rpx" propClass="pr top-xs z-i" :color="(client_value == 'alipay' || client_value == 'baidu') ? 'transparent' : propColor"></iconfont>
|
||||
</view>
|
||||
<slot v-if="propIsRightSlot" name="right"></slot>
|
||||
</view>
|
||||
<slot name="content"></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
name: 'back',
|
||||
props: {
|
||||
// 是否显示返回按钮
|
||||
propIsShowBack: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 最外层class
|
||||
propClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 最外层style
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 是否需要定位
|
||||
propFixed: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 箭头颜色
|
||||
propColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 标题名称
|
||||
propName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 标题名称class
|
||||
propNameClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 标题是否需要透明
|
||||
propNameOpacity: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否有左侧卡槽内容
|
||||
propIsRightSlot: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
client_value: app.globalData.application_client_type(),
|
||||
status_bar_height: 0,
|
||||
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-KUAISHOU || MP-ALIPAY || H5 || APP
|
||||
status_bar_height: parseInt(app.globalData.get_system_info('statusBarHeight', 0, true)),
|
||||
// #endif
|
||||
// 顶部返回导航背景透明度
|
||||
opacity: 0,
|
||||
};
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.setData({
|
||||
is_show_back: this.propIsShowBack && !app.globalData.is_tabbar_pages()
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
var self = this;
|
||||
uni.$on('onPageScroll', function (e) {
|
||||
var top = e.scrollTop > 47 ? 1 : e.scrollTop / 47;
|
||||
self.setData({
|
||||
opacity: top,
|
||||
});
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
top_nav_left_back_event() {
|
||||
app.globalData.page_back_prev_event();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.nav-back {
|
||||
height: 30px;
|
||||
padding-bottom: 10px !important;
|
||||
}
|
||||
</style>
|
||||
101
components/nav-more/nav-more.vue
Normal file
101
components/nav-more/nav-more.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view class="more cr-black padding-top-main padding-bottom-sm flex-row flex-wrap align-c" :class="propClass" @tap="open_popup">
|
||||
<text v-if="isMoreText">{{ $t('common.more_null') }}</text>
|
||||
<iconfont name="icon-category-more"></iconfont>
|
||||
</view>
|
||||
<!-- 弹窗 -->
|
||||
<component-popup :propShow="popup_status" :propIsBar="propIsBar" propPosition="top" :propMask="true" :propTop="propTop" @onclose="quick_close_event">
|
||||
<view class="padding-top-lg">
|
||||
<view class="padding-left-main padding-bottom-main">{{ $t('recommend-form.recommend-form.7gc30l') }}</view>
|
||||
<view class="divider-b">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<view class="tc padding-vertical-lg" @tap="quick_close_event">
|
||||
<text class="padding-right-sm">{{ $t('nav-more.nav-more.h9g4b1') }}</text>
|
||||
<iconfont name="icon-arrow-top" color="#ccc"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</component-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentPopup from '@/components/popup/popup';
|
||||
export default {
|
||||
name: 'more',
|
||||
components: {
|
||||
componentPopup,
|
||||
},
|
||||
props: {
|
||||
propData: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
// 顶部定位的距离
|
||||
propTop: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propStatus: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
themeBtn: {
|
||||
type: String,
|
||||
default: '1',
|
||||
},
|
||||
isMoreText: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
propStatus(newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
this.setData({
|
||||
popup_status: newVal,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
popup_status: false,
|
||||
propIsBar: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 打开弹窗
|
||||
open_popup() {
|
||||
this.$emit('open-popup', true);
|
||||
},
|
||||
// 关闭弹窗
|
||||
quick_close_event(e) {
|
||||
this.$emit('open-popup', false);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.more {
|
||||
width: 30rpx;
|
||||
padding: 15rpx 20rpx;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 101;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
329
components/no-data/no-data.vue
Normal file
329
components/no-data/no-data.vue
Normal file
@@ -0,0 +1,329 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<!-- 是否有网络 -->
|
||||
<view v-if="network_type_value == 'none' && not_network_await_status == 0" class="network-type-tips wh-auto tc bs-bb padding-horizontal-main">
|
||||
<view class="cr-base text-size">{{$t('no-data.no-data.1u202v')}}</view>
|
||||
<view class="cr-grey margin-top-sm">{{$t('no-data.no-data.imw8f1')}}{{title}}{{$t('no-data.no-data.q87572')}}</view>
|
||||
<view class="margin-top-lg tc">
|
||||
<button type="default" class="br-main bg-main cr-white round padding-horizontal-xxl" size="mini" @tap="open_setting_event">{{ $t('setup.setup.377uwg') }}</button>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<!-- 1 加载中(0loog, 1名称) -->
|
||||
<view v-if="propStatus == 1 && network_type_value != 'none'" :class="'no-data-box tc no-data-loading '+(is_loading_use_skeleton == 1 && (propPage || null) != null ? 'skeleton' : '')">
|
||||
<block v-if="is_loading_use_skeleton == 1 && (propPage || null) != null">
|
||||
<!-- 是否展示头站位 -->
|
||||
<view v-if="propIsHeader" class="skeleton-header"></view>
|
||||
<!-- 首页 -->
|
||||
<block v-if="propPage == 'home'">
|
||||
<x-skeleton propType="banner"></x-skeleton>
|
||||
<x-skeleton propType="menu"></x-skeleton>
|
||||
<x-skeleton propType="waterfall"></x-skeleton>
|
||||
<x-skeleton propType="list" propRowNumber="4"></x-skeleton>
|
||||
</block>
|
||||
<!-- 商品分类-整体内容 -->
|
||||
<block v-else-if="propPage == 'goods-category'">
|
||||
<x-skeleton propType="menu" propRowNumber="1"></x-skeleton>
|
||||
<view class="goods-category-content flex-row jc-sb">
|
||||
<view class="left">
|
||||
<x-skeleton :propConfig="skeleton_goods_category_left_config"></x-skeleton>
|
||||
</view>
|
||||
<view class="right">
|
||||
<x-skeleton propType="list" propRowNumber="7"></x-skeleton>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 商品分类-内容项 -->
|
||||
<block v-else-if="propPage == 'goods-category-item'">
|
||||
<x-skeleton propType="list" propRowNumber="6"></x-skeleton>
|
||||
</block>
|
||||
<!-- 购物车 -->
|
||||
<block v-else-if="propPage == 'cart'">
|
||||
<x-skeleton propType="list" propRowNumber="3"></x-skeleton>
|
||||
<x-skeleton propType="waterfall" propRowNumber="4"></x-skeleton>
|
||||
</block>
|
||||
<!-- 商品详情 -->
|
||||
<block v-else-if="propPage == 'goods'">
|
||||
<x-skeleton propType="banner" propHeightNumber="600"></x-skeleton>
|
||||
<x-skeleton propType="text"></x-skeleton>
|
||||
<x-skeleton propType="info"></x-skeleton>
|
||||
<x-skeleton propType="waterfall" propRowNumber="4"></x-skeleton>
|
||||
</block>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view v-if="loading_content_type == 1" class="loading-title-animation">
|
||||
<text class="title">{{title}}</text>
|
||||
</view>
|
||||
<view v-else class="loading-logo-content" :style="'margin-top: '+propLoadingLogoTop+';'">
|
||||
<view class="loading-logo" :style="'background-image: url('+loading_logo+')'"></view>
|
||||
<view class="loading-border" :style="'background-image: url('+loading_logo_border+')'"></view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 2 处理错误 -->
|
||||
<view v-else-if="propStatus == 2" class="no-data-box tc">
|
||||
<image class="image" :src="static_dir + 'error.png'" mode="widthFix"></image>
|
||||
<view class="no-data-tips">{{propMsg || $t('form.form.bniyyt')}}</view>
|
||||
<view v-if="propBackBtn" class="margin-top-xxxl tc">
|
||||
<button type="default" size="mini" class="bg-grey-e br-grey cr-base round" @tap="back_event">{{$t('common.return')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 0 默认没有数据 -->
|
||||
<view v-else-if="propStatus == 0" class="no-data-box tc">
|
||||
<image class="image" :src="propUrl ? propUrl : static_dir + 'empty.png'" mode="widthFix"></image>
|
||||
<view class="no-data-tips">{{propMsg || $t('common.no_relevant_data_tips')}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
static_dir: '/static/images/common/',
|
||||
is_loading_use_skeleton: app.globalData.data.is_loading_use_skeleton,
|
||||
loading_logo_border: app.globalData.data.static_url+'static/common/svg/loading-border.svg',
|
||||
loading_logo: app.globalData.get_application_logo_square() || app.globalData.data.static_url+'favicon.ico',
|
||||
loading_content_type: app.globalData.data.loading_content_type,
|
||||
title: app.globalData.get_application_title(),
|
||||
network_type_value: '',
|
||||
not_network_await_status: 0,
|
||||
|
||||
// 骨架屏配置
|
||||
// 商品分类内容-左侧
|
||||
skeleton_goods_category_left_config: {
|
||||
padding: '30rpx',
|
||||
gridRows: 19,
|
||||
gridColumns: 1,
|
||||
gridRowsGap: '30rpx',
|
||||
headShow: true,
|
||||
headWidth: '200rpx',
|
||||
headHeight: '60rpx',
|
||||
headBorderRadius: '16rpx',
|
||||
textShow: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propStatus: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
propMsg: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propBackBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propNetworkTimeNum: {
|
||||
type: Number,
|
||||
default: 40,
|
||||
},
|
||||
propPage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIsHeader: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propLoadingLogoTop: {
|
||||
type: String,
|
||||
default: '50%',
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
self = this;
|
||||
uni.getNetworkType({
|
||||
success: function (res) {
|
||||
// 当前网络
|
||||
self.network_type_value = res.networkType;
|
||||
// 无网络进入等待网络中
|
||||
if(self.network_type_value == 'none') {
|
||||
self.not_network_await_status = 1;
|
||||
}
|
||||
|
||||
// 定时处理
|
||||
self.countdown(self);
|
||||
}
|
||||
});
|
||||
},
|
||||
// #ifndef VUE2
|
||||
destroyed() {
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
unmounted() {
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
// 定时任务
|
||||
countdown(self) {
|
||||
// 销毁之前的任务
|
||||
clearInterval(self.timer);
|
||||
|
||||
// 没有网络则启动定时任务
|
||||
if(self.network_type_value == 'none') {
|
||||
var temp_num = self.propNetworkTimeNum;
|
||||
self.timer = setInterval(function () {
|
||||
// 读取网络状态
|
||||
uni.getNetworkType({
|
||||
success: function (res) {
|
||||
self.network_type_value = res.networkType;
|
||||
// 已经有网络了则结束定时任务、并正常继续等待走加载过程
|
||||
if(self.network_type_value != 'none') {
|
||||
clearInterval(self.timer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 每次减1
|
||||
temp_num--;
|
||||
|
||||
// 0则结束
|
||||
if(temp_num <= 0) {
|
||||
// 销毁任务
|
||||
clearInterval(self.timer);
|
||||
// 无需等待网络
|
||||
self.not_network_await_status = 0;
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
|
||||
// 返回事件
|
||||
back_event(e) {
|
||||
app.globalData.page_back_prev_event();
|
||||
},
|
||||
|
||||
// 打开权限管理中心
|
||||
open_setting_event() {
|
||||
app.globalData.open_setting_event();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.no-data-box {
|
||||
padding: 15% 0;
|
||||
}
|
||||
.no-data-box .image {
|
||||
width: 160rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.no-data-box .no-data-tips {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
.no-data-loading .title {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/**
|
||||
* 名称加载
|
||||
*/
|
||||
.loading-title-animation,
|
||||
.network-type-tips {
|
||||
padding-top: 25%;
|
||||
}
|
||||
.loading-title-animation {
|
||||
background: #e7e7e7 -webkit-linear-gradient(left, #c6c6c6 0%, #c6c6c6 90%) no-repeat 0 0;
|
||||
background-size: 20% 100%;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-size: 60rpx;
|
||||
font-weight: bold;
|
||||
-webkit-animation: loading-text-animation 2s linear infinite;
|
||||
animation: loading-text-animation 2s linear infinite;
|
||||
}
|
||||
@-webkit-keyframes loading-text-animation {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
@keyframes loading-text-animation {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* logo加载
|
||||
*/
|
||||
.loading-logo-content {
|
||||
position: absolute;
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
left: calc(50% - 70rpx);
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
margin-top: 50%;
|
||||
}
|
||||
.loading-logo-content .loading-logo {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 30rpx;
|
||||
top: 30rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
opacity: 0.8;
|
||||
background-size: contain;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.loading-logo-content .loading-border {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 168rpx;
|
||||
height: 168rpx;
|
||||
left: -14rpx;
|
||||
top: -14rpx;
|
||||
opacity: 0.8;
|
||||
background-size: contain;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 骨架屏
|
||||
*/
|
||||
.skeleton-header {
|
||||
/* #ifndef H5 || APP */
|
||||
padding-top: var(--status-bar-height);
|
||||
padding-bottom: 55px;
|
||||
/* #endif */
|
||||
}
|
||||
.no-data-box.skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
.no-data-loading .goods-category-content > .left {
|
||||
width: 30%;
|
||||
}
|
||||
.no-data-loading .goods-category-content > .right {
|
||||
width: 70%;
|
||||
}
|
||||
</style>
|
||||
444
components/online-service/online-service.vue
Normal file
444
components/online-service/online-service.vue
Normal file
@@ -0,0 +1,444 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<block v-if="online_service_status == 1">
|
||||
<!-- 是否商品页样式 -->
|
||||
<view v-if="propIsGoods == true" class="goods-chat-container fl cp">
|
||||
<block v-if="is_chat == 1">
|
||||
<view @tap="chat_event">
|
||||
<image class="icon" :src="chat_icon" mode="scaleToFill"></image>
|
||||
<text class="text dis-block text-size-xs cr-grey">{{$t('online-service.online-service.4l6k22')}}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<!-- #ifdef MP-WEIXIN || MP-TOUTIAO || MP-BAIDU || MP-KUAISHOU -->
|
||||
<button class="chat-btn" open-type="contact" :show-message-card="propCard" :send-message-title="propTitle" :send-message-path="propPath" :send-message-img="propImg">
|
||||
<image class="icon" :src="chat_icon" mode="scaleToFill"></image>
|
||||
<text class="text dis-block text-size-xs cr-grey">{{$t('online-service.online-service.4l6k22')}}</text>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<button class="chat-btn alipay-contact" open-type="contact">
|
||||
<contact-button class="alipay-chat-btn" :tnt-inst-id="mini_alipay_tnt_inst_id" :scene="mini_alipay_scene" :alipay-card-no="mini_alipay_openid || ''" :icon="chat_icon" size="40rpx*40rpx" />
|
||||
<text class="text dis-block text-size-xs cr-grey">{{$t('online-service.online-service.4l6k22')}}</text>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP -->
|
||||
<button class="chat-btn" type="default" @tap="call_event">
|
||||
<image class="icon" :src="chat_icon" mode="scaleToFill"></image>
|
||||
<text class="text dis-block text-size-xs cr-grey">{{$t('online-service.online-service.4l6k22')}}</text>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
</block>
|
||||
</view>
|
||||
<!-- 默认浮动展示-可拖拽位置 -->
|
||||
<view v-else>
|
||||
<block v-if="is_online_service_fixed == 1">
|
||||
<block v-if="propIsMovable">
|
||||
<movable-area class="online-service-movable-container" :style="'height: calc(100% - '+height_dec+'rpx);top:'+top+'rpx;'">
|
||||
<movable-view direction="all" :x="x" :y="y" :animation="false" :class="'online-service-event-submit '+(propIsSpread ? ' spread' : '')">
|
||||
<block v-if="propIsSpread">
|
||||
<view class="ring"></view>
|
||||
<view class="ring"></view>
|
||||
</block>
|
||||
<block v-if="is_chat == 1">
|
||||
<button class="chat-btn" type="default" :class="common_ent" @tap="chat_event">
|
||||
<image class="icon dis-block" :src="chat_image"></image>
|
||||
</button>
|
||||
</block>
|
||||
<block v-else>
|
||||
<!-- #ifdef MP-WEIXIN || MP-TOUTIAO || MP-BAIDU -->
|
||||
<button class="chat-btn" open-type="contact" :class="common_ent" :show-message-card="propCard" :send-message-title="propTitle" :send-message-path="propPath" :send-message-img="propImg">
|
||||
<image class="icon dis-block" :src="chat_image"></image>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<button class="chat-btn" open-type="contact" :class="'alipay-contact '+common_ent">
|
||||
<contact-button class="alipay-chat-btn" :tnt-inst-id="mini_alipay_tnt_inst_id" :scene="mini_alipay_scene" :alipay-card-no="mini_alipay_openid || ''" :icon="chat_image" size="40rpx*40rpx" />
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP -->
|
||||
<button class="chat-btn" type="default" :class="common_ent" @tap="call_event">
|
||||
<image class="icon dis-block" :src="chat_image"></image>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
</block>
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="online-service-movable-container" :style="'height: calc(100% - '+height_dec+'rpx);top:'+top+'rpx;'">
|
||||
<view :class="'online-service-event-submit '+(propIsSpread ? ' spread' : '')">
|
||||
<block v-if="propIsSpread">
|
||||
<view class="ring"></view>
|
||||
<view class="ring"></view>
|
||||
</block>
|
||||
<block v-if="is_chat == 1">
|
||||
<button class="chat-btn" type="default" :class="common_ent" @tap="chat_event">
|
||||
<image class="icon dis-block" :src="chat_image"></image>
|
||||
</button>
|
||||
</block>
|
||||
<block v-else>
|
||||
<!-- #ifdef MP-WEIXIN || MP-TOUTIAO || MP-BAIDU -->
|
||||
<button class="chat-btn" open-type="contact" :class="common_ent" :show-message-card="propCard" :send-message-title="propTitle" :send-message-path="propPath" :send-message-img="propImg">
|
||||
<image class="icon dis-block" :src="chat_image"></image>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<button class="chat-btn alipay-contact" :class="common_ent" open-type="contact">
|
||||
<contact-button class="alipay-chat-btn" :tnt-inst-id="mini_alipay_tnt_inst_id" :scene="mini_alipay_scene" :alipay-card-no="mini_alipay_openid || ''" :icon="chat_image" size="40rpx*40rpx" />
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP -->
|
||||
<button class="chat-btn" type="default" :class="common_ent" @tap="call_event">
|
||||
<image class="icon dis-block" :src="chat_image"></image>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
common_static_url: app.globalData.get_static_url('common'),
|
||||
client_value: app.globalData.application_client_type(),
|
||||
is_chat: 0,
|
||||
chat_url: null,
|
||||
chat_icon: '',
|
||||
chat_image: '',
|
||||
common_app_customer_service_tel: null,
|
||||
common_app_customer_service_custom: null,
|
||||
common_app_customer_service_company_weixin_corpid: null,
|
||||
common_app_customer_service_company_weixin_url: null,
|
||||
online_service_status: 0,
|
||||
is_online_service_fixed: app.globalData.data.is_online_service_fixed,
|
||||
mini_alipay_tnt_inst_id: null,
|
||||
mini_alipay_scene: null,
|
||||
mini_alipay_openid: null,
|
||||
system: null,
|
||||
x: 0,
|
||||
y: 0,
|
||||
top: 0,
|
||||
height_dec: 0,
|
||||
is_first: 1,
|
||||
common_ent: ''
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propIsGoods: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsBar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsNav: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propCard: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propImg: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propPath: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propIsGrayscale: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propIsChat: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
propChatUrl: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propChatIcon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propChatImage: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
propIsSpread: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
propIsMovable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 是否灰度
|
||||
propIsGrayscale(value, old_value) {
|
||||
this.common_ent = value ? 'grayscale' : '';
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function(e) {
|
||||
this.init_config();
|
||||
|
||||
// 非首次进入则重新初始化配置接口
|
||||
if (this.is_first == 0) {
|
||||
app.globalData.init_config();
|
||||
}
|
||||
|
||||
// 数据设置
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var width = app.globalData.window_width_handle(system.windowWidth);
|
||||
var height = app.globalData.window_height_handle(system);
|
||||
|
||||
// 页面是否定义导航
|
||||
var top_h = this.propIsNav ? 130 : 0;
|
||||
this.setData({
|
||||
is_first: 0,
|
||||
system: system,
|
||||
chat_icon: this.propChatIcon || this.common_static_url+'chat-icon.png',
|
||||
chat_image: this.propChatImage || this.common_static_url+'online-service-icon.png',
|
||||
// 位置坐标
|
||||
x: width - 65,
|
||||
y: height - 380,
|
||||
// 展示位置处理
|
||||
top: top_h,
|
||||
height_dec: top_h,
|
||||
// #ifdef H5 || APP
|
||||
top: 210,
|
||||
height_dec: this.propIsBar ? 310 : 210,
|
||||
// #endif
|
||||
// 是否灰度
|
||||
common_ent: this.propIsGrayscale ? 'grayscale' : ''
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 初始化配置
|
||||
init_config(status) {
|
||||
// 客服优先级顺序( 客服系统 -> 自定义客服 -> 企业微信客服(仅app+h5+微信小程序生效) -> 各端平台客服 -> 电话客服 )
|
||||
if ((status || false) == true) {
|
||||
// 是否使用客服系统
|
||||
var is_chat = app.globalData.get_config('plugins_base.chat.data.is_mobile_chat', 0);
|
||||
var chat_url = app.globalData.get_config('plugins_base.chat.data.chat_url');
|
||||
var is_online_service = app.globalData.get_config('config.common_app_is_online_service', 0);
|
||||
if(is_chat == 1 && (chat_url != null || (this.propChatUrl || null) != null)) {
|
||||
this.setData({
|
||||
is_chat: is_chat,
|
||||
chat_url: this.propChatUrl || chat_url,
|
||||
online_service_status: is_online_service,
|
||||
});
|
||||
} else {
|
||||
var online_service_url = app.globalData.get_config('config.common_app_customer_service_custom', null);
|
||||
this.setData({
|
||||
common_app_customer_service_tel: app.globalData.get_config('config.common_app_customer_service_tel', null),
|
||||
common_app_customer_service_custom: (online_service_url == null || (online_service_url[this.client_value] || null) == null) ? null : online_service_url[this.client_value],
|
||||
common_app_customer_service_company_weixin_corpid: app.globalData.get_config('config.common_app_customer_service_company_weixin_corpid', null),
|
||||
common_app_customer_service_company_weixin_url: app.globalData.get_config('config.common_app_customer_service_company_weixin_url', null),
|
||||
online_service_status: is_online_service,
|
||||
});
|
||||
|
||||
// 存在自定义客服和微信企业客服则走客服模式
|
||||
if((this.common_app_customer_service_custom || null) != null || ((this.common_app_customer_service_company_weixin_corpid || null) != null && (this.common_app_customer_service_company_weixin_url || null) != null)) {
|
||||
this.setData({
|
||||
is_chat: 1
|
||||
});
|
||||
}
|
||||
|
||||
// 对应平台没有提供客服的、[电话,自定义客服,企业微信客服]必须存在一个,则关闭在线客服
|
||||
if(['qq', 'h5', 'ios', 'android'].indexOf(this.client_value) != -1 && (this.common_app_customer_service_tel || null) == null && (this.common_app_customer_service_custom || null) == null) {
|
||||
var temp_service_status = this.online_service_status;
|
||||
if(this.client_value == 'qq') {
|
||||
temp_service_status = 0;
|
||||
} else {
|
||||
// h5,app是否配置企业微信客服
|
||||
if((this.common_app_customer_service_company_weixin_corpid || null) == null && (this.common_app_customer_service_company_weixin_url || null) == null) {
|
||||
temp_service_status = 0;
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
online_service_status: temp_service_status
|
||||
});
|
||||
}
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
// 在线客服开启,获取用户openid
|
||||
if(this.online_service_status == 1)
|
||||
{
|
||||
this.setData({
|
||||
mini_alipay_tnt_inst_id: app.globalData.get_config('config.common_app_mini_alipay_tnt_inst_id'),
|
||||
mini_alipay_scene: app.globalData.get_config('config.common_app_mini_alipay_scene'),
|
||||
mini_alipay_openid: app.globalData.get_user_cache_info('alipay_openid')
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
} else {
|
||||
app.globalData.is_config(this, 'init_config');
|
||||
}
|
||||
},
|
||||
|
||||
// 客服事件
|
||||
chat_event() {
|
||||
// 在线客服系统
|
||||
if((this.chat_url || null) != null) {
|
||||
app.globalData.chat_entry_handle(this.chat_url);
|
||||
} else {
|
||||
// 自定义客服
|
||||
if((this.common_app_customer_service_custom || null) != null) {
|
||||
app.globalData.url_open(this.common_app_customer_service_custom);
|
||||
} else {
|
||||
// 企业微信客服
|
||||
if((this.common_app_customer_service_company_weixin_corpid || null) != null && (this.common_app_customer_service_company_weixin_url || null) != null) {
|
||||
// #ifdef APP
|
||||
// app打开企业微信客服
|
||||
plus.share.getServices(res => {
|
||||
var wechat = res.find(i => i.id === 'weixin')
|
||||
if(wechat) {
|
||||
wechat.openCustomerServiceChat({
|
||||
corpid: this.common_app_customer_service_company_weixin_corpid,
|
||||
url: this.common_app_customer_service_company_weixin_url,
|
||||
});
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序打开企业微信客服
|
||||
uni.openCustomerServiceChat({
|
||||
extInfo: {url: this.common_app_customer_service_company_weixin_url},
|
||||
corpId: this.common_app_customer_service_company_weixin_corpid,
|
||||
showMessageCard: this.propCard,
|
||||
sendMessageTitle: this.propTitle,
|
||||
sendMessagePath: this.propPath,
|
||||
sendMessageImg: this.propImg,
|
||||
});
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
app.globalData.url_open(this.common_app_customer_service_company_weixin_url);
|
||||
// #endif
|
||||
} else {
|
||||
// 电话客服
|
||||
this.call_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 客服电话
|
||||
call_event() {
|
||||
app.globalData.call_tel(this.common_app_customer_service_tel);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.online-service-movable-container {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
.online-service-event-submit {
|
||||
pointer-events: auto;
|
||||
}
|
||||
.online-service-event-submit,
|
||||
.online-service-event-submit .chat-btn {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.online-service-event-submit .chat-btn {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.online-service-event-submit .icon {
|
||||
width: 50px !important;
|
||||
height: 50px !important;
|
||||
position: relative;
|
||||
}
|
||||
.goods-chat-container .chat-btn {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
line-height: initial;
|
||||
font-size: 24rpx;
|
||||
background: transparent;
|
||||
}
|
||||
.goods-chat-container .icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin: 10rpx 0 5rpx 0;
|
||||
}
|
||||
.goods-chat-container .text {
|
||||
margin-top: -10rpx;
|
||||
}
|
||||
/* #ifdef MP-ALIPAY */
|
||||
.goods-chat-container .alipay-contact {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
.goods-chat-container .alipay-contact .text {
|
||||
margin-top: -5rpx;
|
||||
}
|
||||
.online-service-event-submit .alipay-chat-btn {
|
||||
line-height: initial;
|
||||
display: block;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
/**
|
||||
* 呼吸灯
|
||||
*/
|
||||
.spread {
|
||||
background-color: rgba(238, 73, 70,0.4);
|
||||
border-radius: 100%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.spread .ring {
|
||||
/* 速度为1.5 * 层数 = 实际运行速度,速度修改则 animation-delay 属性也修改相同速度 */
|
||||
animation: pulsing 1.5s ease-out infinite;
|
||||
}
|
||||
/* 速度为1*层数 */
|
||||
.spread .ring:nth-of-type(1) {
|
||||
-webkit-animation-delay: -1.5s;
|
||||
animation-delay: -1.5s;
|
||||
}
|
||||
|
||||
/* 速度为1*层数 */
|
||||
.spread .ring:nth-of-type(2) {
|
||||
-webkit-animation-delay: -2s;
|
||||
animation-delay: -2s;
|
||||
}
|
||||
@keyframes pulsing {
|
||||
100% {
|
||||
transform: scale(1.35);
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
173
components/panel-content/panel-content.vue
Normal file
173
components/panel-content/panel-content.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<!-- 简洁的数据,一般列表展示使用 -->
|
||||
<view v-if="propIsTerse" class="content margin-top cp">
|
||||
<block v-if="data != null && data_field.length > 0">
|
||||
<block v-for="(item, index) in data_field" :key="index">
|
||||
<view v-if="(item.is_hide || 0) == 0" class="single-text margin-top-xs">
|
||||
<text class="cr-grey margin-right-xl">{{ item.name }}</text>
|
||||
<text class="cr-base">
|
||||
<block v-if="item.type == 'images'">
|
||||
<image :src="data[item.field]" mode="aspectFit" class="radius panel-item-images"></image>
|
||||
</block>
|
||||
<text v-else>{{ data[item.field] }}</text>
|
||||
</text>
|
||||
<view v-if="(item.is_copy || 0) == 1" class="dis-inline-block margin-left" data-event="copy" :data-value="data[item.field]" @tap.stop="text_event_handle">
|
||||
<iconfont name="icon-copy" size="28rpx" class="cr-grey"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="propIsItemShowMax > 0 && propIsItemShowMax < data_field.length" @tap.stop="item_more_event" class="margin-top-sm tc">
|
||||
<text class="cr-grey-c margin-right-sm">{{ $t('common.view_more') }}</text>
|
||||
<iconfont :name="'icon-arrow-' + (more_status ? 'top' : 'bottom')" size="28rpx" color="#ccc"></iconfont>
|
||||
</view>
|
||||
</block>
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- 详情面板数据 -->
|
||||
<view v-else class="padding-horizontal-main padding-top-main">
|
||||
<view class="panel-item padding-main border-radius-main bg-white spacing-mb">
|
||||
<view v-if="(propTitle || null) != null" class="br-b padding-bottom-main fw-b text-size">{{ propTitle }}</view>
|
||||
<view class="panel-content oh">
|
||||
<block v-if="data != null && data_field.length > 0">
|
||||
<block v-for="(item, index) in data_field" :key="index">
|
||||
<view v-if="(item.is_hide || 0) == 0" class="item br-b-f5 oh padding-vertical-main">
|
||||
<view class="title fl padding-right-main cr-grey">{{ item.name }}</view>
|
||||
<view class="content fl br-l padding-left-main">
|
||||
<block v-if="item.type == 'images'">
|
||||
<image :src="data[item.field]" mode="aspectFit" class="panel-item-images"></image>
|
||||
</block>
|
||||
<text v-else>{{ data[item.field] }}</text>
|
||||
<view v-if="(item.is_copy || 0) == 1" class="dis-inline-block margin-left" data-event="copy" :data-value="data[item.field]" @tap.stop="text_event_handle">
|
||||
<iconfont name="icon-copy" size="28rpx" class="cr-grey lh-il"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="propIsItemShowMax > 0 && propIsItemShowMax < data_field.length" @tap="item_more_event" class="margin-top-sm tc">
|
||||
<text class="cr-grey-c margin-right-sm">{{ $t('common.view_more') }}</text>
|
||||
<iconfont :name="'icon-arrow-' + (more_status ? 'top' : 'bottom')" size="28rpx" color="#ccc"></iconfont>
|
||||
</view>
|
||||
</block>
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentNoData from '@/components/no-data/no-data';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
data: null,
|
||||
data_field: [],
|
||||
more_status: false,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentNoData,
|
||||
},
|
||||
props: {
|
||||
// 标题
|
||||
propTitle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 数据
|
||||
propData: {
|
||||
type: [Object, String],
|
||||
default: '',
|
||||
},
|
||||
// 数据字段
|
||||
propDataField: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
// 数据项最大展示数量(0则显示全部)
|
||||
propIsItemShowMax: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 指定字段
|
||||
propAppointField: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 排除字段
|
||||
propExcludeField: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 无数据提示状态
|
||||
propNoDataStatus: {
|
||||
type: [Number, String],
|
||||
default: 3,
|
||||
},
|
||||
// 无数据提示内容
|
||||
propNoDataMsg: {
|
||||
type: [String],
|
||||
default: '',
|
||||
},
|
||||
// 是否简洁的模式展示
|
||||
propIsTerse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据改变
|
||||
propData(value, old_value) {
|
||||
this.data = value;
|
||||
},
|
||||
},
|
||||
// 页面被展示
|
||||
created: function (e) {
|
||||
this.setData({
|
||||
data: this.propData,
|
||||
});
|
||||
this.data_field_handle(this.propDataField);
|
||||
},
|
||||
methods: {
|
||||
// 数据字段处理
|
||||
data_field_handle(data) {
|
||||
var appoint = (this.propAppointField || null) == null ? [] : this.propAppointField.split(',');
|
||||
var exclude = (this.propExcludeField || null) == null ? [] : this.propExcludeField.split(',');
|
||||
var temp_data = [];
|
||||
var index = 0;
|
||||
for (var i in data) {
|
||||
if ((exclude.length == 0 && appoint.length > 0 && appoint.indexOf(data[i]['field']) != -1) || (appoint.length == 0 && (exclude.length == 0 || exclude.indexOf(data[i]['field']) == -1))) {
|
||||
data[i]['is_hide'] = (data[i]['is_hide'] || 0) == 0 ? (index >= this.propIsItemShowMax && this.propIsItemShowMax > 0 ? 1 : 0) : 0;
|
||||
temp_data.push(data[i]);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
data_field: temp_data,
|
||||
});
|
||||
},
|
||||
|
||||
// 文本事件
|
||||
text_event_handle(e) {
|
||||
app.globalData.text_event_handle(e);
|
||||
},
|
||||
|
||||
// 数据项更多事件
|
||||
item_more_event(e) {
|
||||
this.data_field_handle(this.data_field);
|
||||
this.setData({
|
||||
more_status: !this.more_status,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.panel-item-images {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
</style>
|
||||
922
components/payment/payment.vue
Normal file
922
components/payment/payment.vue
Normal file
@@ -0,0 +1,922 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<!-- 支付二维码展示 -->
|
||||
<component-popup :propShow="popup_view_pay_qrcode_is_show" propPosition="bottom" @onclose="popup_view_pay_qrcode_event_close">
|
||||
<view class="padding-top-xxxl padding-bottom-xxxl padding-left-xxxl padding-right-xxxl tc">
|
||||
<block v-if="(popup_view_pay_data || null) == null || (popup_view_pay_data.qrcode_url || null) == null || (popup_view_pay_data.name || null) == null || (popup_view_pay_data.order_no || null) == null">
|
||||
<text class="cr-grey">{{$t('payment.payment.973g2e')}}</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="fw-b text-size cr-base margin-bottom-sm">{{ popup_view_pay_data.name }}</view>
|
||||
<image :src="popup_view_pay_data.qrcode_url" mode="aspectFit" class="dis-block auto max-w"></image>
|
||||
<view v-if="(popup_view_pay_data.msg || null) != null" class="cr-yellow margin-top-sm">{{ popup_view_pay_data.msg }}</view>
|
||||
<!-- #ifdef H5 -->
|
||||
<view v-if="popup_view_pay_data.pay_url != null" class="margin-top-xl">
|
||||
<a :href="popup_view_pay_data.pay_url" target="_blank" class="dis-inline-block cr-green">{{$t('payment.payment.z3y296')}}</a>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</block>
|
||||
</view>
|
||||
</component-popup>
|
||||
<!-- 支付方式 popup -->
|
||||
<component-popup :propShow="is_show_payment_popup" propPosition="bottom" @onclose="payment_popup_event_close">
|
||||
<view class="poupon-title padding-main tc text-size-md pr">{{$t('payment.payment.iu792d')}}<iconfont name="icon-close-o" propClass="pa right-0 margin-right-main margin-top-xs" size="30rpx" color="#999" @tap="payment_popup_event_close"></iconfont>
|
||||
</view>
|
||||
<view class="payment-price tc padding-top-sm padding-bottom-sm br-b">
|
||||
<text class="text-size-md">{{ propCurrencySymbol }}</text>
|
||||
{{ propPayPrice }}
|
||||
</view>
|
||||
<view v-if="payment_list.length > 0" class="oh">
|
||||
<view class="payment-list">
|
||||
<scroll-view scroll-y="true" class="scroll-y wh-auto">
|
||||
<view v-for="(item, index) in payment_list" :key="index" class="item br-b flex-row jc-sb align-c" :data-value="item.id" @tap="checked_payment">
|
||||
<view class="flex-1">
|
||||
<image v-if="(item.logo || null) != null" class="icon va-m margin-right-sm" :src="item.logo" mode="widthFix"></image>
|
||||
<text class="va-m">{{ item.name }}</text>
|
||||
<text v-if="(item.tips || null) !== null" class="va-m cr-red">({{ item.tips }})</text>
|
||||
</view>
|
||||
<iconfont :name="payment_id == item.id ? 'icon-zhifu-yixuan' : 'icon-zhifu-weixuan'" size="44rpx" :color="payment_id == item.id ? '#E22C08' : '#ccc'"></iconfont>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="payment-submit">
|
||||
<view class="bottom-line-exclude">
|
||||
<button class="bg-main br-main cr-white round text-size" type="default" hover-class="none" @tap="popup_payment_event" :disabled="submit_disabled_status">{{$t('payment.payment.25r53g')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="padding-top-xxxl padding-bottom-xxxl oh bg-white tc cr-grey">{{$t('payment.payment.058a46')}}</view>
|
||||
</component-popup>
|
||||
|
||||
<!-- 支付html展示 -->
|
||||
<component-popup :propShow="popup_view_pay_html_is_show" propPosition="bottom" @onclose="popup_view_pay_html_event_close">
|
||||
<view class="popup-pay-html-content padding-top-xxxl padding-bottom-xxxl padding-left-xxxl padding-right-xxxl tc">
|
||||
<block v-if="(popup_view_pay_data || null) == null">
|
||||
<text class="cr-grey">{{$t('payment.payment.973g2e')}}</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<mp-html :content="popup_view_pay_data" />
|
||||
</block>
|
||||
</view>
|
||||
</component-popup>
|
||||
|
||||
<!-- 支付中提示弹窗 -->
|
||||
<view v-if="payment_confirm_modal_status" class="payment-confirm-modal">
|
||||
<view class="content padding-xl margin-xxl tc bg-white border-radius-main">
|
||||
<view class="padding-vertical-xxxxl">{{$t('common.payment_in_text')}}</view>
|
||||
<view class="margin-top-lg">
|
||||
<button type="default" size="mini" class="bg-white br-black cr-black text-size-sm round margin-right-xxxxl" data-type="0" @tap="payment_confirm_event">{{$t('common.not_have_name')}}</button>
|
||||
<button type="default" size="mini" class="bg-main br-main cr-white text-size-sm round margin-left-xxxxl" data-type="1" @tap="payment_confirm_event">{{$t('order.order.s8g966')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import base64 from '@/common/js/lib/base64.js';
|
||||
import componentPopup from '@/components/popup/popup';
|
||||
export default {
|
||||
name: 'pay',
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
// 支付方式列表
|
||||
payment_list: [],
|
||||
// 弹窗开关
|
||||
is_show_payment_popup: false,
|
||||
popup_view_pay_qrcode_is_show: false,
|
||||
// 支付弹窗展示数据
|
||||
popup_view_pay_data: null,
|
||||
// 定时器
|
||||
pay_statuc_check_timer: null,
|
||||
// 支付id
|
||||
payment_id: 0,
|
||||
submit_disabled_status: true,
|
||||
order_id: 0,
|
||||
popup_view_pay_html_is_show: false,
|
||||
// 打开url地址定时任务和状态
|
||||
open_pay_url_timer: null,
|
||||
open_pay_url_status: true,
|
||||
// 支付返回数据
|
||||
pay_response_data: {},
|
||||
// 支付确认弹窗
|
||||
payment_confirm_modal_status: false,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
propCurrencySymbol: {
|
||||
type: String,
|
||||
default: app.globalData.currency_symbol(),
|
||||
},
|
||||
propPayUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propQrcodeUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propPaymentList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
propIsShowPayment: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 订单id
|
||||
propTempPayValue: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
// 订单id参数名,默认为id
|
||||
propPayDataKey: {
|
||||
type: String,
|
||||
default: 'id',
|
||||
},
|
||||
// 订单下标 ---- 用于处理支付成功后前端修改成功状态
|
||||
propTempPayIndex: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
// 支付id 值为0表示没有配置支付方式
|
||||
propPaymentId: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
// 默认支付id 值为0表示没有默认
|
||||
propDefaultPaymentId: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
// 付款金额
|
||||
propPayPrice: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
// 支付跳转页面------跳转成功页面---后返回的页面
|
||||
propToPageBack: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
// 指定所有页面跳转到指定页面------除现金支付外
|
||||
propToPage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 现金支付-指定跳转页面----不进入充值成功页面:不配置则表示不跳转
|
||||
propToAppointPage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 支付失败跳转页面------不传则停留在当前页面
|
||||
propToFailPage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
//是否需要关闭页面进行跳转
|
||||
propIsRedirectTo: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 判断错误时是否需要弹窗提示
|
||||
propIsFailAlert: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
componentPopup,
|
||||
},
|
||||
watch: {
|
||||
// 支付方式是否改变
|
||||
propPaymentList(value, old_value) {
|
||||
this.setData({
|
||||
payment_list: value,
|
||||
});
|
||||
},
|
||||
// 是否显示支付方式
|
||||
propIsShowPayment(new_val, old_val) {
|
||||
if (new_val !== old_val) {
|
||||
let bool = true;
|
||||
if (this.payment_list.length == 1) {
|
||||
bool = false;
|
||||
this.setData({
|
||||
payment_id: this.payment_list[0].id,
|
||||
});
|
||||
} else {
|
||||
let self = this;
|
||||
self.payment_list.forEach((item) => {
|
||||
let new_payment_id = Number(self.propPaymentId) == 0 ? self.propDefaultPaymentId : Number(self.propPaymentId);
|
||||
if (item.id == new_payment_id) {
|
||||
bool = false;
|
||||
}
|
||||
});
|
||||
this.setData({
|
||||
payment_id: Number(this.propPaymentId) == 0 ? this.propDefaultPaymentId : Number(this.propPaymentId),
|
||||
});
|
||||
}
|
||||
|
||||
this.setData({
|
||||
is_show_payment_popup: new_val,
|
||||
submit_disabled_status: bool,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.setData({
|
||||
payment_list: this.propPaymentList,
|
||||
payment_id: Number(this.propPaymentId) == 0 ? this.propDefaultPaymentId : Number(this.propPaymentId),
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 支付弹窗关闭
|
||||
payment_popup_event_close(e) {
|
||||
this.setData({
|
||||
is_show_payment_popup: false,
|
||||
});
|
||||
this.$emit('close-payment-popup', false);
|
||||
},
|
||||
// 支付二维码展示窗口事件
|
||||
popup_view_pay_qrcode_event_close(e) {
|
||||
// 关闭弹窗
|
||||
this.setData({
|
||||
popup_view_pay_qrcode_is_show: false,
|
||||
});
|
||||
// 清除定时和支付数据
|
||||
clearInterval(this.pay_statuc_check_timer);
|
||||
},
|
||||
|
||||
// 选择支付方式
|
||||
checked_payment(e) {
|
||||
this.setData({
|
||||
payment_id: e.currentTarget.dataset.value,
|
||||
submit_disabled_status: false,
|
||||
});
|
||||
},
|
||||
|
||||
// 支付弹窗发起支付
|
||||
popup_payment_event() {
|
||||
if (this.submit_disabled_status) {
|
||||
app.globalData.showToast(this.$t('payment.payment.x6d585'));
|
||||
return false;
|
||||
}
|
||||
this.setData({
|
||||
is_show_payment_popup: false,
|
||||
});
|
||||
this.pay_handle(this.propTempPayValue, this.payment_id);
|
||||
this.$emit('close-payment-popup', false);
|
||||
},
|
||||
|
||||
// 支付方法
|
||||
pay_handle(order_id, payment_id = 0, payment_list = []) {
|
||||
// 没有指定支付方式则使用属性传过来的值
|
||||
if((payment_list || null) != null && payment_list.length > 0) {
|
||||
this.setData({
|
||||
payment_list: payment_list
|
||||
});
|
||||
}
|
||||
// 没有支付方式
|
||||
if((payment_id || 0) == 0) {
|
||||
this.pay_handle_event(order_id, payment_id);
|
||||
} else {
|
||||
// 循环匹配支付方式
|
||||
this.payment_list.forEach((item) => {
|
||||
if (item.id == payment_id) {
|
||||
if (item.payment == 'WalletPay') {
|
||||
var self = this;
|
||||
uni.showModal({
|
||||
title: self.$t('common.warm_tips'),
|
||||
content: self.$t('payment.payment.011cj4'),
|
||||
confirmText: self.$t('common.confirm'),
|
||||
cancelText: self.$t('common.not_yet'),
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
self.pay_handle_event(order_id, payment_id);
|
||||
} else {
|
||||
self.order_item_pay_fail_handle(null, order_id, self.$t('paytips.paytips.6mpsl7'));
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.pay_handle_event(order_id, payment_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 支付处理
|
||||
pay_handle_event(order_id, payment_id = 0) {
|
||||
// 没有指定支付方式则不匹配支付标识
|
||||
var payment = null;
|
||||
if((payment_id || 0) != 0) {
|
||||
// #ifdef H5
|
||||
// 微信环境判断是否已有web_openid、不存在则不继续执行跳转到插件进行授权
|
||||
if (!app.globalData.is_user_weixin_web_openid(order_id, payment_id || this.payment_id, this.propToAppointPage)) {
|
||||
return false;
|
||||
}
|
||||
// #endif
|
||||
// 支付方式
|
||||
for (var i in this.payment_list) {
|
||||
if (this.payment_list[i]['id'] == (payment_id || this.payment_id)) {
|
||||
payment = this.payment_list[i];
|
||||
}
|
||||
}
|
||||
if (payment == null) {
|
||||
app.globalData.showToast(this.$t('payment.payment.7ihx9u'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 请求数据
|
||||
var post_data = {
|
||||
[this.propPayDataKey]: order_id,
|
||||
payment_id: payment_id || this.payment_id,
|
||||
};
|
||||
// h5自定义重定向地址
|
||||
// #ifdef H5
|
||||
var redirect_url = app.globalData.page_url_protocol(this.propToAppointPage || app.globalData.get_page_url(false));
|
||||
post_data['redirect_url'] = encodeURIComponent(base64.encode(redirect_url));
|
||||
// 存在支付标识、指定支付方式使用respond_url返回地址、移除重定向地址
|
||||
if(payment != null) {
|
||||
var respond_arr = ['PayPal', 'UniPayment'];
|
||||
if (respond_arr.indexOf(payment.payment) != -1) {
|
||||
post_data['respond_url'] = post_data['redirect_url'];
|
||||
delete post_data['redirect_url'];
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
// 请求支付接口
|
||||
uni.showLoading({
|
||||
title: this.$t('payment.payment.e1f54e'),
|
||||
mask: true
|
||||
});
|
||||
if (this.propPayUrl) {
|
||||
uni.request({
|
||||
url: this.propPayUrl,
|
||||
method: 'POST',
|
||||
data: post_data,
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
uni.hideLoading();
|
||||
var data = res.data.data;
|
||||
this.setData({
|
||||
pay_response_data: data || {}
|
||||
});
|
||||
if (res.data.code == 0) {
|
||||
// 是否直接支付成功
|
||||
if ((data.is_success || 0) == 1) {
|
||||
// 数据设置
|
||||
this.order_item_pay_success_handle(data, order_id, false);
|
||||
app.globalData.showToast(this.$t('paytips.paytips.679rxu'), 'success');
|
||||
setTimeout(() => {
|
||||
this.to_success_page_event();
|
||||
}, 2000);
|
||||
} else {
|
||||
// 支付方式类型
|
||||
let payment_type = Number(data.is_payment_type || 0);
|
||||
switch (payment_type) {
|
||||
// 正常线上支付
|
||||
case 0:
|
||||
// #ifdef APP
|
||||
this.app_pay_handle(this, data, order_id);
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
// 头条是否非普通版本支持
|
||||
if(parseInt(data.data.pay_type || 0) == 1) {
|
||||
this.toutiao_transaction_pay_handle(this, data, order_id);
|
||||
} else {
|
||||
this.mp_pay_handle(this, data, order_id);
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU
|
||||
this.mp_pay_handle(this, data, order_id);
|
||||
// #endif
|
||||
// #ifdef MP-KUAISHOU
|
||||
this.kuaishou_pay_handle(this, data, order_id);
|
||||
// #endif
|
||||
// #ifdef MP-QQ
|
||||
this.qq_pay_handle(this, data, order_id);
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
this.h5_pay_handle(this, data, order_id);
|
||||
// #endif
|
||||
break;
|
||||
// 线下支付
|
||||
case 1:
|
||||
// 现金支付
|
||||
let self = this;
|
||||
uni.showModal({
|
||||
content: res.data.msg,
|
||||
showCancel: false,
|
||||
confirmText: self.$t('common.confirm'),
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
self.to_other(order_id);
|
||||
} else {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6mpsl7'));
|
||||
}
|
||||
},
|
||||
});
|
||||
break;
|
||||
// 钱包支付
|
||||
case 2:
|
||||
this.order_item_pay_success_handle(data, order_id);
|
||||
break;
|
||||
// 默认
|
||||
default:
|
||||
app.globalData.showToast(this.$t('payment.payment.vhx5dv'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 是否返回html代码展示、则提示错误
|
||||
if (res.data.code == -6666 && (data || null) != null) {
|
||||
this.setData({
|
||||
popup_view_pay_data: data,
|
||||
popup_view_pay_html_is_show: true,
|
||||
});
|
||||
} else {
|
||||
this.order_item_pay_fail_handle(data, order_id, res.data.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: (res) => {
|
||||
uni.hideLoading();
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
app.globalData.showToast(this.$t('payment.payment.597s8b'));
|
||||
}
|
||||
},
|
||||
// APP支付
|
||||
app_pay_handle(self, data, order_id) {
|
||||
var arr = {
|
||||
Alipay: 'alipay',
|
||||
Weixin: 'wxpay',
|
||||
PayPal: 'paypal'
|
||||
}
|
||||
var pay_value = arr[data.payment.payment] || null;
|
||||
if(pay_value != null) {
|
||||
uni.getProvider({
|
||||
service: 'payment',
|
||||
success: function (res) {
|
||||
if(~res.provider.indexOf(pay_value)) {
|
||||
var pay_data = ((data.data.pay_data || null) == null) ? data.data : data.data.pay_data;
|
||||
uni.requestPayment({
|
||||
provider: pay_value,
|
||||
orderInfo: pay_data,
|
||||
success: function (res) {
|
||||
// 是否需要回调捕获
|
||||
var call_back_url = data.data.call_back_url || null;
|
||||
if(call_back_url != null) {
|
||||
uni.request({url: call_back_url, method: 'GET'});
|
||||
}
|
||||
|
||||
// 成功处理数据
|
||||
self.order_item_pay_success_handle(data, order_id);
|
||||
},
|
||||
fail: function (err) {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6y488i'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
app.globalData.showToast(data.payment.payment+self.$t('payment.payment.bv637f'));
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 先清除定时任务
|
||||
if(self.open_pay_url_timer != null) {
|
||||
clearTimeout(self.open_pay_url_timer);
|
||||
}
|
||||
// 显示加载层
|
||||
uni.showLoading({
|
||||
title: self.$t('common.loading_in_text'),
|
||||
mask: true
|
||||
});
|
||||
// 设置打开url状态
|
||||
self.setData({
|
||||
open_pay_url_status: true
|
||||
});
|
||||
// 打开url
|
||||
plus.runtime.openURL(data.data, function(error) {
|
||||
uni.hideLoading();
|
||||
// 打开url失败、并进入提示失败环节
|
||||
self.setData({
|
||||
open_pay_url_status: false
|
||||
});
|
||||
self.order_item_pay_fail_handle(data, order_id, error.message+'('+error.code+')');
|
||||
});
|
||||
// 定时3秒后提示用户确认支付状态
|
||||
self.open_pay_url_timer = setTimeout(function() {
|
||||
if(self.open_pay_url_status) {
|
||||
uni.hideLoading();
|
||||
uni.showModal({
|
||||
content: self.$t('payment.payment.sdfs31'),
|
||||
showCancel: true,
|
||||
cancelText: self.$t('common.not_have_name'),
|
||||
confirmText: self.$t('order.order.s8g966'),
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
self.order_item_pay_success_handle(data, order_id);
|
||||
} else {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6y488i'));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
},
|
||||
// 快手小程序
|
||||
kuaishou_pay_handle(self, data, order_id) {
|
||||
uni.pay({
|
||||
orderInfo: data.data,
|
||||
serviceId: '1',
|
||||
success: (res) => {
|
||||
// 数据设置
|
||||
self.order_item_pay_success_handle(data, order_id);
|
||||
},
|
||||
fail: (res) => {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6y488i'));
|
||||
},
|
||||
});
|
||||
},
|
||||
// 头条小程序非普通交易支付处理
|
||||
toutiao_transaction_pay_handle(self, data, order_id) {
|
||||
if(!uni.canIUse('requestOrder') || !uni.canIUse('getOrderPayment')) {
|
||||
app.globalData.showToast(self.$t('payment.payment.4dszme'));
|
||||
return false;
|
||||
}
|
||||
uni.requestOrder({
|
||||
data: data.data.data,
|
||||
byteAuthorization: data.data.auth,
|
||||
success: (res) => {
|
||||
uni.getOrderPayment({
|
||||
orderId: res.orderId,
|
||||
success: (res) => {
|
||||
// 数据设置
|
||||
self.order_item_pay_success_handle(data, order_id);
|
||||
},
|
||||
fail: (res) => {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6y488i'));
|
||||
}
|
||||
});
|
||||
},
|
||||
fail: (res) => {
|
||||
app.globalData.showToast(res.errMsg+'('+res.errNo+')');
|
||||
}
|
||||
});
|
||||
},
|
||||
// 小程序: 微信、支付宝、百度、头条、QQ
|
||||
mp_pay_handle(self, data, order_id) {
|
||||
// 是否打开另一个小程序
|
||||
if (typeof data.data != 'string' && (data.data.appid || null) != null && (data.data.path || null) != null && (data.data.order_no || null) != null) {
|
||||
uni.navigateToMiniProgram({
|
||||
appId: data.data.appid,
|
||||
path: data.data.path,
|
||||
extraData: data.data.extra_data || {},
|
||||
success(res) {
|
||||
// 支付状态验证
|
||||
self.pay_status_check_handle(self, data, order_id);
|
||||
|
||||
// 提示弹窗
|
||||
self.setData({
|
||||
payment_confirm_modal_status: true,
|
||||
});
|
||||
},
|
||||
fail(res) {
|
||||
app.globalData.showToast(self.$t('paytips.paytips.6y488i'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.requestPayment({
|
||||
// #ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO
|
||||
orderInfo: data.data,
|
||||
// #endif
|
||||
// #ifdef MP-QQ
|
||||
package: data.data,
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
timeStamp: data.data.timeStamp,
|
||||
nonceStr: data.data.nonceStr,
|
||||
package: data.data.package,
|
||||
signType: data.data.signType,
|
||||
paySign: data.data.paySign,
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
service: 5,
|
||||
// #endif
|
||||
success: (res) => {
|
||||
// #ifdef MP-ALIPAY
|
||||
if (res.resultCode != 9000) {
|
||||
self.order_item_pay_fail_handle(data, order_id, res.memo || self.$t('paytips.paytips.6y488i'));
|
||||
return false;
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
if (res.code != 0) {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6y488i'));
|
||||
return false;
|
||||
}
|
||||
// #endif
|
||||
// 数据设置
|
||||
self.order_item_pay_success_handle(data, order_id);
|
||||
},
|
||||
fail: (res) => {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6y488i'));
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
// QQ支付处理
|
||||
qq_pay_handle(self, data, order_id) {
|
||||
// 是否微信支付
|
||||
if (data.payment.payment == 'Weixin') {
|
||||
uni.requestWxPayment({
|
||||
url: data.data,
|
||||
referer: app.globalData.data.request_url,
|
||||
success: function (res) {
|
||||
app.globalData.alert({
|
||||
msg: self.$t('payment.payment.k2i010'),
|
||||
is_show_cancel: 0,
|
||||
});
|
||||
// 支付接口调用成功,但是不知道是否支付成功,所以需要重新获取列表数据
|
||||
self.$emit('reset-event');
|
||||
},
|
||||
fail: function (res) {
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('paytips.paytips.6y488i'));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
self.mp_pay_handle(self, data, order_id);
|
||||
}
|
||||
},
|
||||
// h5支付处理
|
||||
h5_pay_handle(self, data, order_id) {
|
||||
// 字符串则为跳转地址直接进入
|
||||
if (typeof data.data == 'string') {
|
||||
window.location.href = data.data;
|
||||
} else {
|
||||
var status = false;
|
||||
// 微信jsapi
|
||||
if (data.payment.payment == 'Weixin' && (data.data.appId || null) != null && (data.data.timeStamp || null) != null && (data.data.nonceStr || null) != null && (data.data.package || null) != null && (data.data.signType || null) != null && (data.data.paySign || null) != null) {
|
||||
status = true;
|
||||
|
||||
function onBridgeReady() {
|
||||
WeixinJSBridge.invoke(
|
||||
'getBrandWCPayRequest',
|
||||
{
|
||||
appId: data.data.appId,
|
||||
timeStamp: data.data.timeStamp,
|
||||
nonceStr: data.data.nonceStr,
|
||||
package: data.data.package,
|
||||
signType: data.data.signType,
|
||||
paySign: data.data.paySign,
|
||||
},
|
||||
function (res) {
|
||||
if (res.err_msg == 'get_brand_wcpay_request:ok') {
|
||||
// 数据设置
|
||||
self.order_item_pay_success_handle(data, order_id);
|
||||
} else {
|
||||
self.order_item_pay_fail_handle(data, order_id, res.err_msg);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
if (typeof WeixinJSBridge == 'undefined') {
|
||||
if (document.addEventListener) {
|
||||
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
|
||||
} else if (document.attachEvent) {
|
||||
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
|
||||
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
|
||||
}
|
||||
} else {
|
||||
onBridgeReady();
|
||||
}
|
||||
}
|
||||
// 二维码展示
|
||||
if ((data.data.qrcode_url || null) != null && (data.data.name || null) != null && (data.data.order_no || null) != null) {
|
||||
status = true;
|
||||
// 显示支付窗口
|
||||
self.setData({
|
||||
popup_view_pay_data: data.data,
|
||||
popup_view_pay_qrcode_is_show: true,
|
||||
});
|
||||
// 状态验证
|
||||
self.pay_status_check_handle(self, data, order_id);
|
||||
}
|
||||
// 返回html表单
|
||||
if ((data.data.html || null) != null) {
|
||||
status = true;
|
||||
var div = document.createElement('paydivform');
|
||||
div.innerHTML = data.data.html;
|
||||
document.body.appendChild(div);
|
||||
var fm = document.forms;
|
||||
var fm_len = fm.length;
|
||||
if (fm_len > 0) {
|
||||
fm[fm_len - 1].submit();
|
||||
}
|
||||
}
|
||||
// 未匹配到的支付处理方式
|
||||
if (!status) {
|
||||
app.globalData.showToast(data.payment.name + self.$t('payment.payment.2rw3qh'));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 支付状态验证处理
|
||||
pay_status_check_handle(self, data, order_id) {
|
||||
// 先清除已存在的定时
|
||||
clearInterval(self.pay_statuc_check_timer);
|
||||
// 定时校验支付状态
|
||||
var timer = setInterval(function () {
|
||||
uni.request({
|
||||
url: self.propQrcodeUrl,
|
||||
method: 'POST',
|
||||
data: {
|
||||
order_no: data.data.order_no,
|
||||
},
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
// 清除定时、支付数据、弹窗
|
||||
clearInterval(self.pay_statuc_check_timer);
|
||||
self.setData({
|
||||
popup_view_pay_data: null,
|
||||
popup_view_pay_qrcode_is_show: false,
|
||||
payment_confirm_modal_status: false,
|
||||
});
|
||||
// 数据设置
|
||||
self.order_item_pay_success_handle(data, order_id);
|
||||
} else {
|
||||
// -333支付中、其它状态则提示错误
|
||||
if (res.data.code != -333) {
|
||||
clearInterval(self.pay_statuc_check_timer);
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
clearInterval(self.pay_statuc_check_timer);
|
||||
self.order_item_pay_fail_handle(data, order_id, self.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
}, 3000);
|
||||
self.setData({
|
||||
pay_statuc_check_timer: timer,
|
||||
});
|
||||
},
|
||||
|
||||
// 支付确认弹窗事件
|
||||
payment_confirm_event(e) {
|
||||
// 关闭弹窗清除定时任务
|
||||
this.setData({
|
||||
payment_confirm_modal_status: false,
|
||||
});
|
||||
clearInterval(this.pay_statuc_check_timer);
|
||||
// 回调处理
|
||||
if(parseInt(e.currentTarget.dataset.type || 0) == 1) {
|
||||
this.order_item_pay_success_handle(this.pay_response_data, this.order_id);
|
||||
} else {
|
||||
this.order_item_pay_fail_handle(this.pay_response_data, this.order_id, this.$t('paytips.paytips.6y488i'));
|
||||
}
|
||||
},
|
||||
|
||||
// 支付成功数据设置 data:后台返回的参数, order_id: 订单id,is_to_page,是否需要跳转页面的参数控制
|
||||
order_item_pay_success_handle(data, order_id, is_to_page = true) {
|
||||
let back_data = {
|
||||
data: data,
|
||||
order_id: order_id,
|
||||
temp_pay_index: this.propTempPayIndex,
|
||||
payment_id: this.payment_id,
|
||||
is_to_page: is_to_page,
|
||||
};
|
||||
this.$emit('pay-success', back_data);
|
||||
if (is_to_page) {
|
||||
this.to_success_page_event();
|
||||
}
|
||||
},
|
||||
// 支付失败数据设置 data:后台返回的参数, order_id: 订单id, msg: 错误提示信息
|
||||
order_item_pay_fail_handle(data, order_id, msg) {
|
||||
let back_data = {
|
||||
data: data,
|
||||
order_id: order_id,
|
||||
temp_pay_index: this.propTempPayIndex,
|
||||
payment_id: this.payment_id,
|
||||
};
|
||||
this.$emit('pay-fail', back_data);
|
||||
this.to_fail_page_event(msg);
|
||||
},
|
||||
// 成功跳转
|
||||
to_success_page_event() {
|
||||
if (this.propToPage) {
|
||||
// 跳转支付页面
|
||||
app.globalData.url_open(this.propToPage, true);
|
||||
} else {
|
||||
let url_data = {
|
||||
code: '9000',
|
||||
};
|
||||
url_data = Object.assign({}, url_data, this.propToPageBack);
|
||||
// 跳转支付页面
|
||||
app.globalData.url_open('/pages/paytips/paytips?params=' + encodeURIComponent(base64.encode(JSON.stringify(url_data))), this.propIsRedirectTo);
|
||||
}
|
||||
},
|
||||
// 失败跳转
|
||||
to_fail_page_event(msg) {
|
||||
let to_fail_page = this.propToFailPage || null;
|
||||
if (to_fail_page != null) {
|
||||
let join = (to_fail_page.indexOf('?') == -1) ? '?' : '&';
|
||||
to_fail_page += join+'msg='+msg;
|
||||
if (this.propIsFailAlert) {
|
||||
// 现金支付
|
||||
uni.showModal({
|
||||
content: msg,
|
||||
showCancel: false,
|
||||
confirmText: this.$t('common.confirm'),
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
// 跳转支付页面
|
||||
app.globalData.url_open(to_fail_page, true);
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// 跳转支付页面
|
||||
app.globalData.url_open(to_fail_page, true);
|
||||
}
|
||||
} else {
|
||||
if (msg) {
|
||||
app.globalData.showToast(msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
to_other(order_id) {
|
||||
if (this.propToAppointPage) {
|
||||
// 跳转订单列表页
|
||||
app.globalData.url_open(this.propToAppointPage, true);
|
||||
}
|
||||
},
|
||||
// 页面卸载
|
||||
onUnload(e) {
|
||||
clearInterval(this.pay_statuc_check_timer);
|
||||
},
|
||||
// 支付html展示窗口事件
|
||||
popup_view_pay_html_event_close(e) {
|
||||
this.setData({
|
||||
popup_view_pay_html_is_show: false,
|
||||
});
|
||||
this.to_other();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
.payment-price {
|
||||
font-size: 80rpx;
|
||||
}
|
||||
.payment-list .scroll-y {
|
||||
max-height: 430rpx;
|
||||
}
|
||||
.payment-list .item {
|
||||
padding: 28rpx 28rpx 28rpx 32rpx;
|
||||
}
|
||||
.payment-list .icon {
|
||||
width: 50rpx;
|
||||
height: 50rpx !important;
|
||||
}
|
||||
.payment-submit {
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付确认弹窗
|
||||
*/
|
||||
.payment-confirm-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
z-index: 100;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.payment-confirm-modal .content {
|
||||
margin-top: 60%;
|
||||
z-index: 101;
|
||||
}
|
||||
</style>
|
||||
214
components/popup/popup.vue
Normal file
214
components/popup/popup.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<view :class="theme_view + ' ' + propMostClass">
|
||||
<view :class="'popup ' + (propClassname || '') + ' ' + (propShow ? 'popup-show' : 'popup-hide') + ' ' + (propAnimation ? 'animation' : '')" :disable-scroll="propDisablescroll">
|
||||
<view class="popup-mask" :style="'z-index: ' + propIndex + ';'" v-if="propMask" @tap="on_mask_tap"></view>
|
||||
<view :class="'popup-content popup-' + (propPosition || 'bottom') + ' ' + (propIsRadius ? '' : 'popup-radius-0') + ' ' + (propIsBar ? 'popup-bar' : '') + ' ' + (propPosition === 'bottom' ? 'bottom-line-exclude' : '')" :style="popup_content_style + propStyle">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
popup_content_style: '',
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
// 最外层的class
|
||||
propMostClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 内层class
|
||||
propClassname: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propShow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propPosition: {
|
||||
type: String,
|
||||
default: 'bottom',
|
||||
},
|
||||
propMask: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propAnimation: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propDisablescroll: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsBar: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 弹窗是否需要圆角 默认需要
|
||||
propIsRadius: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propIndex: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
// 需要携带单位后缀
|
||||
propTop: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
propBottom: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propStyle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 监听状态
|
||||
propShow(value, old_value) {
|
||||
this.init_handle();
|
||||
},
|
||||
},
|
||||
// 组建创建
|
||||
created: function () {
|
||||
this.init_handle();
|
||||
},
|
||||
methods: {
|
||||
// 事件处理
|
||||
on_mask_tap: function on_mask_tap() {
|
||||
this.$emit(
|
||||
'onclose',
|
||||
{
|
||||
detail: {},
|
||||
},
|
||||
{}
|
||||
);
|
||||
},
|
||||
// 初初始化处理
|
||||
init_handle() {
|
||||
var tabbar_height = 0;
|
||||
if(this.propPosition == 'bottom') {
|
||||
// 弹窗从底部弹出,获取底部菜单高度、如果当前为底部菜单页面则增加底部间距
|
||||
if(app.globalData.data.is_use_native_tabbar != 1 && app.globalData.is_tabbar_pages()) {
|
||||
tabbar_height = (app.globalData.app_system_tabbar_height_value()*2)+20;
|
||||
} else {
|
||||
var height = (app.globalData.current_page(false) == 'pages/diy/diy') ? app.globalData.app_diy_tabbar_height_value() : 0;
|
||||
tabbar_height = (height > 0) ? (height*2)+20 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 左边距位置处理
|
||||
var left = 0;
|
||||
// #ifdef H5
|
||||
// 处理内容左边距、避免父级设置内边距影响
|
||||
var width = uni.getSystemInfoSync().windowWidth;
|
||||
if (width > 960) {
|
||||
left = (width - 800) / 2;
|
||||
}
|
||||
// #endif
|
||||
this.setData({
|
||||
popup_content_style: 'left:' + left + 'px;' + (this.propTop ? 'top:' + this.propTop : '') + ';' + (this.propBottom ? 'bottom:' + this.propBottom : '') + ';padding-bottom:' + tabbar_height + 'rpx;',
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.popup {
|
||||
opacity: 0;
|
||||
}
|
||||
.popup-content {
|
||||
position: fixed;
|
||||
background: #fff;
|
||||
z-index: 101;
|
||||
overflow: hidden;
|
||||
}
|
||||
.popup-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
}
|
||||
.popup-left {
|
||||
transform: translateX(-100%);
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.popup-right {
|
||||
transform: translateX(100%);
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.popup-top {
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
.popup-bottom {
|
||||
bottom: var(--window-bottom);
|
||||
width: 100vw;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
.popup-show {
|
||||
opacity: 1;
|
||||
}
|
||||
.popup-hide {
|
||||
transition: all 1s linear;
|
||||
}
|
||||
.popup-show .popup-content {
|
||||
transform: none;
|
||||
}
|
||||
.popup-show .popup-mask {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.popup.animation .popup-mask,
|
||||
.popup.animation .popup-content {
|
||||
transition: all 0.35s linear;
|
||||
}
|
||||
.popup-top {
|
||||
border-bottom-right-radius: 20rpx;
|
||||
border-bottom-left-radius: 20rpx;
|
||||
}
|
||||
.popup-bottom {
|
||||
border-top-right-radius: 20rpx;
|
||||
border-top-left-radius: 20rpx;
|
||||
}
|
||||
.popup-left {
|
||||
border-top-right-radius: 20rpx;
|
||||
border-bottom-right-radius: 20rpx;
|
||||
}
|
||||
.popup-right {
|
||||
border-top-left-radius: 20rpx;
|
||||
border-bottom-left-radius: 20rpx;
|
||||
}
|
||||
.popup-radius-0 {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
.popup-bar {
|
||||
/* #ifdef H5 || APP */
|
||||
bottom: var(--window-bottom) !important;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
131
components/popupscreen/popupscreen.vue
Normal file
131
components/popupscreen/popupscreen.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(data || null) != null && status == 1" class="plugins-popupscreen wh-auto ht-auto">
|
||||
<view class="content pr">
|
||||
<image class="dis-block auto" :src="data.images" mode="widthFix" :data-value="data.images_url || ''" @tap="url_event"></image>
|
||||
<view class="tc margin-top-xl">
|
||||
<view class="close cp round padding-sm auto" @tap.stop="close_event">
|
||||
<iconfont name="icon-close-o" size="28rpx" color="#cacaca"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
data: null,
|
||||
status: 0,
|
||||
cache_key: 'plugins_popupscreen_cache_key',
|
||||
timer: null,
|
||||
};
|
||||
},
|
||||
props: {},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.init_config();
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化配置
|
||||
init_config(status) {
|
||||
if ((status || false) == true) {
|
||||
this.setData({
|
||||
data: app.globalData.get_config('plugins_base.popupscreen.data') || null,
|
||||
});
|
||||
this.init();
|
||||
} else {
|
||||
app.globalData.is_config(this, 'init_config');
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化
|
||||
init() {
|
||||
var data = this.data || null;
|
||||
if (data != null && parseInt(data.is_app_enable || 0) == 1 && parseInt(data.is_valid || 0) == 1) {
|
||||
// 是否全局
|
||||
var temp_status = true;
|
||||
if(parseFloat(data.is_overall || 0) == 0) {
|
||||
// 非首页则不展示
|
||||
if(!app.globalData.is_tabbar_home()) {
|
||||
temp_status = false;
|
||||
}
|
||||
}
|
||||
if(temp_status) {
|
||||
// 不存在关闭缓存或者超过间隔时间则显示
|
||||
var key = this.cache_key;
|
||||
var cv = parseInt(uni.getStorageSync(key)) || 0;
|
||||
var pv = parseInt(data.interval_time) || 86400;
|
||||
if (cv == 0 || cv + pv < app.globalData.get_timestamp()) {
|
||||
// 是否开启自动关闭
|
||||
var timer = null;
|
||||
var ct = parseInt(data.close_time) || 0;
|
||||
if (ct > 0) {
|
||||
var self = this;
|
||||
timer = setTimeout(function () {
|
||||
self.setData({
|
||||
status: 0,
|
||||
});
|
||||
uni.setStorage({
|
||||
key: key,
|
||||
data: app.globalData.get_timestamp(),
|
||||
});
|
||||
}, ct * 1000);
|
||||
}
|
||||
this.setData({
|
||||
status: 1,
|
||||
timer: timer,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 关闭事件
|
||||
close_event(e) {
|
||||
this.setData({
|
||||
status: 0,
|
||||
});
|
||||
uni.setStorage({
|
||||
key: this.cache_key,
|
||||
data: app.globalData.get_timestamp(),
|
||||
});
|
||||
clearInterval(this.timer);
|
||||
},
|
||||
|
||||
// url事件
|
||||
url_event(e) {
|
||||
app.globalData.url_event(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.plugins-popupscreen {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
background-color: rgb(0 0 0 / 0.3);
|
||||
}
|
||||
.plugins-popupscreen .close {
|
||||
right: 10%;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
background-color: rgb(4 4 4 / 0.3);
|
||||
border: solid 1px #a9a9a9;
|
||||
}
|
||||
.plugins-popupscreen .content {
|
||||
margin-top: calc(50vh - 200rpx) !important;
|
||||
}
|
||||
.plugins-popupscreen .content image {
|
||||
width: 600rpx;
|
||||
}
|
||||
</style>
|
||||
265
components/quick-nav/quick-nav.vue
Normal file
265
components/quick-nav/quick-nav.vue
Normal file
@@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<!-- 开启事件 -->
|
||||
<movable-area v-if="propIsBtn && quick_status == 1" :class="'quick-movable-container ' + common_ent" :style="'height: calc(100% - ' + height_dec + 'rpx);top:' + top + 'rpx;'">
|
||||
<movable-view direction="all" :x="x" :y="y" :animation="false" class="quick-event-submit" @tap="quick_open_event">
|
||||
<image class="image" :src="common_static_url + 'quick-icon.png'" mode="widthFix"></image>
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<component-popup :propShow="popup_status" :propIsBar="propIsBar" propPosition="bottom" @onclose="quick_close_event">
|
||||
<view :class="'nav-popup-container ' + common_ent">
|
||||
<view class="close oh">
|
||||
<view class="fr" @tap.stop="quick_close_event">
|
||||
<iconfont name="icon-close-o" size="28rpx" color="#999"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
<view class="nav-popup-content">
|
||||
<view v-if="data_list.length > 0" class="nav-data-list">
|
||||
<view v-for="(item, index) in data_list" :key="index" class="item cp">
|
||||
<view :class="'item-content ' + ((item.bg_color || null) == null ? 'item-exposed' : '')" :data-value="item.event_value" :data-type="item.event_type" @tap="navigation_event" :style="(item.bg_color || null) == null ? '' : 'background-color:' + item.bg_color + ';'">
|
||||
<image class="image" :src="item.images_url" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="title">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<!-- 提示信息 -->
|
||||
<component-no-data :propStatus="0"></component-no-data>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</component-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentPopup from '@/components/popup/popup';
|
||||
import componentNoData from '@/components/no-data/no-data';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
common_static_url: app.globalData.get_static_url('common'),
|
||||
popup_status: false,
|
||||
quick_status: 0,
|
||||
data_list: [],
|
||||
system: null,
|
||||
x: 0,
|
||||
y: 0,
|
||||
top: 0,
|
||||
height_dec: 0,
|
||||
is_first: 1,
|
||||
common_ent: '',
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentPopup,
|
||||
componentNoData,
|
||||
},
|
||||
props: {
|
||||
propIsBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propIsBar: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsNav: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsGrayscale: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 是否灰度
|
||||
propIsGrayscale(value, old_value) {
|
||||
this.common_ent = value ? 'grayscale' : '';
|
||||
},
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.init_config();
|
||||
|
||||
// 页面是否定义导航
|
||||
var value = this.propIsNav ? 100 : 0;
|
||||
this.top = value;
|
||||
this.height_dec = value;
|
||||
// #ifdef H5 || APP
|
||||
this.top = 140;
|
||||
this.height_dec = this.propIsBar ? 280 : 140;
|
||||
// #endif
|
||||
|
||||
// 非首次进入则重新初始化配置接口
|
||||
if (this.is_first == 0) {
|
||||
app.globalData.init_config();
|
||||
}
|
||||
|
||||
// 数据设置
|
||||
var system = app.globalData.get_system_info(null, null, true);
|
||||
var height = app.globalData.window_height_handle(system);
|
||||
var width = app.globalData.window_width_handle(system.windowWidth);
|
||||
this.setData({
|
||||
is_first: 0,
|
||||
system: system,
|
||||
x: width - 65,
|
||||
y: height - 280,
|
||||
// 是否灰度
|
||||
common_ent: this.propIsGrayscale ? 'grayscale' : '',
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 初始化配置
|
||||
init_config(status) {
|
||||
if ((status || false) == true) {
|
||||
var data_list = app.globalData.get_config('quick_nav') || [];
|
||||
this.setData({
|
||||
data_list: data_list,
|
||||
quick_status: (data_list.length > 0) ? (app.globalData.get_config('config.home_navigation_main_quick_status') || 0) : 0,
|
||||
});
|
||||
} else {
|
||||
app.globalData.is_config(this, 'init_config');
|
||||
}
|
||||
},
|
||||
|
||||
// 弹层开启
|
||||
quick_open_event(e) {
|
||||
this.setData({
|
||||
popup_status: true,
|
||||
data_list: app.globalData.get_config('quick_nav') || [],
|
||||
});
|
||||
},
|
||||
|
||||
// 弹层关闭
|
||||
quick_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
},
|
||||
|
||||
// 操作事件
|
||||
navigation_event(e) {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
app.globalData.operation_event(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
/**
|
||||
* 按钮
|
||||
*/
|
||||
.quick-movable-container {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.quick-event-submit {
|
||||
pointer-events: auto;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.quick-event-submit .image {
|
||||
width: 50px !important;
|
||||
height: 50px !important;
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
border-radius: 100%;
|
||||
box-shadow: 0 0 6rpx 10rpx rgba(89, 181, 255, 15%);
|
||||
background: #59b5ff;
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹窗
|
||||
*/
|
||||
.nav-popup-container {
|
||||
padding: 20rpx 10rpx 0 10rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.nav-popup-container .close {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 20rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.nav-popup-content {
|
||||
max-height: 80vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
.nav-data-list {
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.nav-data-list .item {
|
||||
width: calc(25% - 60rpx);
|
||||
float: left;
|
||||
padding: 30rpx;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.nav-data-list .item-content {
|
||||
border-radius: 50%;
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
-webkit-box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
|
||||
box-shadow: 0 2px 12px rgb(226 226 226 / 95%);
|
||||
}
|
||||
|
||||
.nav-data-list .item-content,
|
||||
.nav-data-list .item .image {
|
||||
width: 70rpx !important;
|
||||
height: 70rpx !important;
|
||||
}
|
||||
|
||||
.nav-data-list .item .item-exposed {
|
||||
padding: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.nav-data-list .item .item-exposed,
|
||||
.nav-data-list .item .item-exposed .image {
|
||||
width: 110rpx !important;
|
||||
height: 110rpx !important;
|
||||
}
|
||||
|
||||
.nav-data-list .item .title {
|
||||
margin-top: 10rpx;
|
||||
font-size: 28rpx !important;
|
||||
text-align: center;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
1117
components/realstore-cart/realstore-cart.vue
Normal file
1117
components/realstore-cart/realstore-cart.vue
Normal file
File diff suppressed because it is too large
Load Diff
233
components/realstore-list/realstore-list.vue
Normal file
233
components/realstore-list/realstore-list.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view v-if="(data_list || null) != null && data_list.length > 0" class="plugins-realstore-data-list oh">
|
||||
<block v-for="(item, index) in data_list" :key="index">
|
||||
<view class="item bg-white padding-top-xl padding-bottom-sm padding-horizontal-main border-radius-main pr spacing-mb" :class="item.status_info.type === 2 ? 'opacity' : ''" :data-index="index" :data-value="item.url+propRealstoreDetailQuery" @tap="realstore_item_event">
|
||||
<view class="base oh flex-row">
|
||||
<!-- 基础内容 -->
|
||||
<image :src="item.logo" mode="widthFix" class="logo circle br"></image>
|
||||
<view class="base-right flex-1 flex-width">
|
||||
<view class="title fw-b text-size single-text tl">
|
||||
<text v-if="(item.alias || null) != null" class="va-m title-icon border-radius-sm br-main cr-main text-size-xs padding-horizontal-xs margin-right-xs">{{ item.alias }}</text>
|
||||
<text class="va-m">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="margin-top-sm padding-top-xs text-size-xs cr-grey">
|
||||
<view v-if="(item.status_info.time || null) != null" class="flex-row align-c">
|
||||
<iconfont name="icon-time pr top-xs cr-grey-9"></iconfont>
|
||||
<view :class="'status-icon text-size-xs divider-r padding-left-xs padding-right-sm margin-right-sm ' + (item.status_info.status == 1 ? 'cr-green' : item.status_info.type == 1 ? 'cr-red' : 'cr-grey-c')">
|
||||
{{ item.status_info.msg }}
|
||||
</view>
|
||||
{{ item.status_info.time }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row jc-sb align-c br-t-dashed margin-top-main padding-top-sm">
|
||||
<!-- 地址 -->
|
||||
<view class="address-content single-text cr-base margin-left-xs dis-inline-block text-size-xs oh cp tl" :data-value="item.province_name + item.city_name + item.county_name + item.address" @tap.stop="text_copy_event">
|
||||
<view class="dis-inline-block va-m cr-grey-9 margin-top-sm">
|
||||
<iconfont name="icon-map-address"></iconfont>
|
||||
</view>
|
||||
<text class="va-m margin-left-xs">{{ item.province_name }}{{ item.city_name }}{{ item.county_name }}{{ item.address }}</text>
|
||||
</view>
|
||||
<view v-if="(item.distance || null) != null" class="text-size-xs cr-grey-c pa address-distance">{{$t('extraction-address.extraction-address.42v8tv')}}{{ item.distance }}</view>
|
||||
</view>
|
||||
<!-- 右侧操作 -->
|
||||
<view class="icon-list pa">
|
||||
<view v-if="(item.service_data || null) != null && (item.service_data.service_tel || null) != null" class="icon-item dis-inline-block tc cp" :data-value="item.service_data.service_tel" @tap.stop="tel_event">
|
||||
<iconfont name="icon-tel" size="30rpx"></iconfont>
|
||||
</view>
|
||||
<!-- #ifndef MP-KUAISHOU -->
|
||||
<view v-if="item.lat != 0 && item.lng != 0" class="icon-item dis-inline-block tc cp" :data-index="index" @tap.stop="address_map_event">
|
||||
<iconfont name="icon-send" size="30rpx"></iconfont>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
data_list: [],
|
||||
favor_user: [],
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propIsFavor: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propIsChoice: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsChoiceBackType: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIsOpenRealstoreRedirect: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propData: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propFavorUser: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
propRealstoreDetailQuery: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 数据
|
||||
propData(value, old_value) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function (e) {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
// 初始化
|
||||
init() {
|
||||
var data_list = ((this.propData || null) == null || (this.propData.data || null) == null || this.propData.data.length == 0) ? [] : this.propData.data;
|
||||
this.setData({
|
||||
data_list: data_list,
|
||||
favor_user: this.propFavorUser,
|
||||
});
|
||||
this.data_list_handle();
|
||||
},
|
||||
|
||||
// 数据列表处理
|
||||
data_list_handle() {
|
||||
var temp_data_list = this.data_list;
|
||||
for (var i in temp_data_list) {
|
||||
temp_data_list[i]["is_favor"] = this.favor_user.indexOf(temp_data_list[i]["id"]) == -1 ? 0 : 1;
|
||||
}
|
||||
this.setData({
|
||||
data_list: temp_data_list,
|
||||
});
|
||||
},
|
||||
|
||||
// 收藏事件
|
||||
favor_event(e) {
|
||||
if (!app.globalData.is_single_page_check()) {
|
||||
return false;
|
||||
}
|
||||
var user = app.globalData.get_user_info(this, "favor_event");
|
||||
if (user != false) {
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var info = this.data_list[index];
|
||||
uni.showLoading({
|
||||
title: this.$t('common.processing_in_text'),
|
||||
});
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url("reversal", "favor", "realstore"),
|
||||
method: "POST",
|
||||
data: {
|
||||
id: info.id,
|
||||
},
|
||||
dataType: "json",
|
||||
success: (res) => {
|
||||
uni.hideLoading();
|
||||
if (res.data.code == 0) {
|
||||
var temp_data = this.data_list;
|
||||
var temp_favor = this.favor_user;
|
||||
temp_data[index]["is_favor"] = res.data.data.status;
|
||||
if (res.data.data.status == 1) {
|
||||
if (temp_favor.indexOf(info.id) == -1) {
|
||||
temp_favor.push(info.id);
|
||||
}
|
||||
} else {
|
||||
if (temp_favor.indexOf(info.id) != -1) {
|
||||
temp_favor.splice(index, 1);
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
data_list: temp_data,
|
||||
favor_user: temp_favor,
|
||||
});
|
||||
app.globalData.showToast(res.data.msg, "success");
|
||||
} else {
|
||||
if (app.globalData.is_login_check(res.data, this, "favor_event")) {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 电话
|
||||
tel_event(e) {
|
||||
app.globalData.call_tel(e);
|
||||
},
|
||||
|
||||
// 剪切板
|
||||
text_copy_event(e) {
|
||||
app.globalData.text_copy_event(e);
|
||||
},
|
||||
|
||||
// 地图查看
|
||||
address_map_event(e) {
|
||||
var info = this.data_list[e.currentTarget.dataset.index] || {};
|
||||
if (info.lat == 0 || info.lng == 0) {
|
||||
app.globalData.showToast(this.$t('user-order-detail.user-order-detail.i876o3'));
|
||||
return false;
|
||||
}
|
||||
var address = (info.province_name || "") + (info.city_name || "") + (info.county_name || "") + (info.address || "");
|
||||
app.globalData.open_location(info.lng, info.lat, info.name, address);
|
||||
},
|
||||
|
||||
// 门店事件
|
||||
realstore_item_event(e) {
|
||||
// 是否选择模式
|
||||
if(this.propIsChoice) {
|
||||
// 存储门店缓存
|
||||
var data = this.data_list[e.currentTarget.dataset.index];
|
||||
uni.setStorageSync(app.globalData.data.cache_realstore_detail_choice_key, {
|
||||
data: data,
|
||||
status: 1
|
||||
});
|
||||
|
||||
// 回调事件
|
||||
this.$emit('onChoiceEvent', data);
|
||||
|
||||
// 选择回调类型
|
||||
switch(this.propIsChoiceBackType) {
|
||||
// 返回上一个页面
|
||||
case 'back' :
|
||||
app.globalData.page_back_prev_event();
|
||||
break;
|
||||
// 进入门店详情页面
|
||||
case 'realstore-detail' :
|
||||
app.globalData.url_open(data.url, this.propIsOpenRealstoreRedirect);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
app.globalData.url_event(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style></style>
|
||||
234
components/region-picker/region-picker.vue
Normal file
234
components/region-picker/region-picker.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<component-popup :propShow="propShow" propPosition="bottom" @onclose="popup_close_event">
|
||||
<view class="flex-row jc-sb align-c padding-main">
|
||||
<text class="cr-grey" @tap="popup_close_event">{{$t('common.cancel')}}</text>
|
||||
<text class="cr-blue" @tap="sub_ragion_event">{{$t('common.confirm')}}</text>
|
||||
</view>
|
||||
<view class="g-dp-ctt-wrapper">
|
||||
<picker-view class="picker-view" :indicator-style="indicatorStyle" :value="columns_index[0]" data-column="0" @change="changeHandler">
|
||||
<picker-view-column>
|
||||
<view class="g-dp-ctt-wp-item" v-for="(item, a) in columns[0]" :key="item.id">{{ item.name }}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
|
||||
<picker-view class="picker-view" :indicator-style="indicatorStyle" :value="columns_index[1]" data-column="1" @change="changeHandler">
|
||||
<picker-view-column>
|
||||
<view class="g-dp-ctt-wp-item" v-for="(item, b) in columns[1]" :key="item.id">{{ item.name }}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
|
||||
<picker-view class="picker-view" :indicator-style="indicatorStyle" :value="columns_index[2]" data-column="2" @change="changeHandler">
|
||||
<picker-view-column>
|
||||
<view class="g-dp-ctt-wp-item" v-for="(item, c) in columns[2]" :key="item.id">{{ item.name }}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
</component-popup>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
import componentPopup from "@/components/popup/popup";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
columns: [[0], [0], [0]],
|
||||
// 下标
|
||||
columns_index: [[0], [0], [0]],
|
||||
indicatorStyle: `height: ${uni.upx2px(88)}px;`,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
componentPopup,
|
||||
},
|
||||
props: {
|
||||
propShow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propProvinceId: {
|
||||
type: [String,Number],
|
||||
default: "",
|
||||
},
|
||||
propCityId: {
|
||||
type: [String,Number],
|
||||
default: "",
|
||||
},
|
||||
propCountyId: {
|
||||
type: [String,Number],
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
propShow(new_val, old_val) {
|
||||
if (new_val) {
|
||||
this.getProvince();
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 地区初始化匹配索引
|
||||
get_region_value(index, id) {
|
||||
var data = this.columns[index];
|
||||
var data_id = id;
|
||||
var list_index = [];
|
||||
data.forEach((d, i) => {
|
||||
if (d.id == data_id) {
|
||||
list_index = [i];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
this.$set(this.columns_index, index, list_index);
|
||||
},
|
||||
// picker 滚动change事件
|
||||
changeHandler(e) {
|
||||
const { dataset, value } = e.target;
|
||||
if (dataset.column == 0) {
|
||||
if (this.columns[0][value[0]].id) {
|
||||
this.$set(this.columns_index, dataset.column, value);
|
||||
this.$set(this.columns_index, 1, [0]);
|
||||
this.$set(this.columns_index, 2, [0]);
|
||||
this.getCity(this.columns[0][value[0]].id, true);
|
||||
}
|
||||
} else if (dataset.column == 1) {
|
||||
if (this.columns[1][value[0]].id) {
|
||||
this.$set(this.columns_index, dataset.column, value);
|
||||
this.$set(this.columns_index, 2, [0]);
|
||||
this.getArea(this.columns[1][value[0]].id, true);
|
||||
}
|
||||
} else if (dataset.column == 2) {
|
||||
this.$set(this.columns_index, dataset.column, value);
|
||||
}
|
||||
},
|
||||
|
||||
// 获取省
|
||||
getProvince() {
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url("index", "region"),
|
||||
method: "POST",
|
||||
data: {},
|
||||
dataType: "json",
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
var data = res.data.data;
|
||||
this.$set(this.columns, 0, data);
|
||||
this.getCity(this.propProvinceId ? this.propProvinceId : data[0].id);
|
||||
if (this.propProvinceId) {
|
||||
this.get_region_value(0, this.propProvinceId);
|
||||
}
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('extraction-apply.extraction-apply.fo7y6c'));
|
||||
},
|
||||
});
|
||||
},
|
||||
// 获取市
|
||||
getCity(province_id, init = false) {
|
||||
if (province_id) {
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url("index", "region"),
|
||||
method: "POST",
|
||||
data: {
|
||||
pid: province_id,
|
||||
},
|
||||
dataType: "json",
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
var data = res.data.data;
|
||||
this.$set(this.columns, 1, data);
|
||||
if (init) {
|
||||
this.getArea(data[0].id);
|
||||
} else {
|
||||
this.getArea(this.propCityId ? this.propCityId : data[0].id);
|
||||
if (this.propCityId) {
|
||||
this.get_region_value(1, this.propCityId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('extraction-apply.extraction-apply.b6qg7b'));
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
// 获取区
|
||||
getArea(city_id, init = false) {
|
||||
if (city_id) {
|
||||
// 加载loding
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url("index", "region"),
|
||||
method: "POST",
|
||||
data: {
|
||||
pid: city_id,
|
||||
},
|
||||
dataType: "json",
|
||||
success: (res) => {
|
||||
if (res.data.code == 0) {
|
||||
var data = res.data.data;
|
||||
this.$set(this.columns, 2, data);
|
||||
if (!init) {
|
||||
if (this.propCountyId) {
|
||||
this.get_region_value(2, this.propCountyId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
app.globalData.showToast(this.$t('extraction-apply.extraction-apply.5s5734'));
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
// 关闭按钮
|
||||
popup_close_event(e) {
|
||||
this.$emit("onclose", false);
|
||||
},
|
||||
//提交按钮
|
||||
sub_ragion_event(e) {
|
||||
let province = this.columns[0][this.columns_index[0]];
|
||||
let city = this.columns[1][this.columns_index[1]];
|
||||
let areal = this.columns[2][this.columns_index[2]];
|
||||
this.popup_close_event();
|
||||
this.$emit("call-back", province, city, areal);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
::v-deep .popup-bottom {
|
||||
border-radius: 0;
|
||||
}
|
||||
.picker-view {
|
||||
width: 32%; height: 480rpx
|
||||
}
|
||||
.picker-view-column {
|
||||
height: 480rpx !important;
|
||||
}
|
||||
.g-dp-ctt-wrapper {
|
||||
height: 480upx;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.g-dp-ctt-wp-item {
|
||||
width: 100%;
|
||||
height: 88upx;
|
||||
line-height: 88upx;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 30upx;
|
||||
}
|
||||
</style>
|
||||
262
components/search/search.vue
Normal file
262
components/search/search.vue
Normal file
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<view :class="'search-content pr round '+propSize" :style="'background:' + propBgColor + ';' + ((propBrColor || null) != null ? 'border:1px solid ' + propBrColor + ';' : '')">
|
||||
<view class="search-icon dis-inline-block pa" :style="'padding:' + propPadding" @tap="search_icon_event">
|
||||
<iconfont :name="propIcon" :color="propIconColor" size="24rpx"></iconfont>
|
||||
</view>
|
||||
<input
|
||||
type="text"
|
||||
confirm-type="search"
|
||||
:class="'input round wh-auto dis-block '+propClass"
|
||||
:placeholder="(propPlaceholder || propPlaceholderValue || this.$t('search.search.660us5'))"
|
||||
:placeholder-class="propPlaceholderClass"
|
||||
:value="propDefaultValue"
|
||||
:focus="propFocus"
|
||||
@input="search_input_value_event"
|
||||
@confirm="search_submit_confirm_event"
|
||||
@focus="search_input_focus_event"
|
||||
@blur="search_input_blur_event"
|
||||
:style="'color:' + propTextColor + ';'"
|
||||
/>
|
||||
<button v-if="propIsBtn" class="search-btn pa bg-main" size="mini" type="default" @tap="search_submit_confirm_event">{{$t('common.search')}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
input_value: '',
|
||||
};
|
||||
},
|
||||
components: {},
|
||||
props: {
|
||||
propUrl: {
|
||||
type: String,
|
||||
default: '/pages/goods-search/goods-search',
|
||||
},
|
||||
propFormName: {
|
||||
type: String,
|
||||
default: 'keywords',
|
||||
},
|
||||
propDefaultValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propPlaceholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propPlaceholderValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propPlaceholderClass: {
|
||||
type: String,
|
||||
default: 'cr-grey-c',
|
||||
},
|
||||
propClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propTextColor: {
|
||||
type: String,
|
||||
default: '#666',
|
||||
},
|
||||
propBgColor: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
propBrColor: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propIsRequired: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
propIsOnEvent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsOnFocusEvent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsOnBlurEvent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsOnInputEvent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIcon: {
|
||||
type: String,
|
||||
default: 'icon-search-max',
|
||||
},
|
||||
propIconColor: {
|
||||
type: String,
|
||||
default: '#ccc',
|
||||
},
|
||||
propIsIconOnEvent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propIsBtn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propSize: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
propFocus: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
propPadding: {
|
||||
type: String,
|
||||
default: '16rpx 20rpx 0 20rpx;',
|
||||
},
|
||||
},
|
||||
// 属性值改变监听
|
||||
watch: {
|
||||
// 默认值
|
||||
propDefaultValue(value, old_value) {
|
||||
this.setData({
|
||||
input_value: value,
|
||||
});
|
||||
}
|
||||
},
|
||||
// 页面被展示
|
||||
created: function () {
|
||||
this.setData({
|
||||
input_value: this.propDefaultValue
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// 搜索输入事件
|
||||
search_input_value_event(e) {
|
||||
this.setData({
|
||||
input_value: e.detail.value,
|
||||
});
|
||||
// 是否回调事件
|
||||
if (this.propIsOnInputEvent) {
|
||||
this.$emit('oninput', e.detail.value);
|
||||
}
|
||||
},
|
||||
|
||||
// 搜索失去焦点事件
|
||||
search_input_blur_event(e) {
|
||||
this.setData({
|
||||
input_value: e.detail.value,
|
||||
});
|
||||
// 是否回调事件
|
||||
if (this.propIsOnBlurEvent) {
|
||||
this.$emit('onblur', e.detail.value);
|
||||
}
|
||||
},
|
||||
|
||||
// 搜索获取焦点事件
|
||||
search_input_focus_event(e) {
|
||||
this.setData({
|
||||
input_value: e.detail.value,
|
||||
});
|
||||
// 是否回调事件
|
||||
if (this.propIsOnFocusEvent) {
|
||||
this.$emit('onfocus', e.detail.value);
|
||||
}
|
||||
},
|
||||
|
||||
// 搜索确认事件
|
||||
search_submit_confirm_event() {
|
||||
// 是否验证必须要传值
|
||||
var value = this.input_value || this.propPlaceholderValue;
|
||||
if (this.propIsRequired && value === '') {
|
||||
app.globalData.showToast(this.$t('search.search.ic9b89'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 是否回调事件
|
||||
if (this.propIsOnEvent) {
|
||||
this.$emit('onsearch', value);
|
||||
} else {
|
||||
// 进入搜索页面
|
||||
app.globalData.url_open(this.propUrl + '?' + this.propFormName + '=' + value);
|
||||
}
|
||||
},
|
||||
|
||||
// 搜索确认(外部调用直接跳转搜索)
|
||||
search_submit_confirm(value = '') {
|
||||
app.globalData.url_open(this.propUrl + '?' + this.propFormName + '=' + value);
|
||||
},
|
||||
|
||||
// icon事件
|
||||
search_icon_event() {
|
||||
// 是否回调事件
|
||||
if (this.propIsIconOnEvent) {
|
||||
this.$emit('onicon', {});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.search-content .search-icon {
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
line-height: 28rpx;
|
||||
height: 42rpx;
|
||||
}
|
||||
.search-content .input {
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
padding: 0 32rpx 0 64rpx;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
background: transparent;
|
||||
}
|
||||
.search-content .search-btn {
|
||||
width: 106rpx;
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 30rpx;
|
||||
padding: 0;
|
||||
color: #fff;
|
||||
right: 6rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.search-content.sm .search-icon {
|
||||
padding-top: 18rpx;
|
||||
}
|
||||
.search-content.sm .input {
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.search-content.sm .search-btn {
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
|
||||
.search-content.md .search-icon {
|
||||
padding-top: 22rpx;
|
||||
}
|
||||
.search-content.md .input {
|
||||
height: 66rpx;
|
||||
line-height: 66rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.search-content.md .search-btn {
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
}
|
||||
</style>
|
||||
299
components/share-popup/share-popup.vue
Normal file
299
components/share-popup/share-popup.vue
Normal file
@@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<view :class="theme_view">
|
||||
<component-popup :propShow="popup_status" propPosition="bottom" @onclose="popup_close_event">
|
||||
<view class="share-popup bg-white">
|
||||
<view class="close fr oh">
|
||||
<view class="fr" @tap.stop="popup_close_event">
|
||||
<iconfont name="icon-close-o" size="28rpx" color="#999"></iconfont>
|
||||
</view>
|
||||
</view>
|
||||
<view class="share-popup-content">
|
||||
<!-- #ifdef MP-ALIPAY -->
|
||||
<view class="share-items oh cp" @tap="share_base_event">
|
||||
<image class="image" :src="common_static_url + 'share-user-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.h04xiy') }}</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO || MP-KUAISHOU -->
|
||||
<view class="share-items oh cp">
|
||||
<button class="btn dis-block br-0 ht-auto" type="default" size="mini" open-type="share" hover-class="none" @tap="popup_close_event">
|
||||
<image class="image" :src="common_static_url + 'share-user-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.h04xiy') }}</text>
|
||||
</button>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP -->
|
||||
<block v-if="is_app_weixin">
|
||||
<view class="share-items oh cp" data-scene="WXSceneSession" data-provider="weixin" @tap="share_app_event">
|
||||
<image class="image" :src="common_static_url + 'share-user-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.rhs2c5') }}</text>
|
||||
</view>
|
||||
<view class="share-items oh cp" data-scene="WXSceneTimeline" data-provider="weixin" @tap="share_app_event">
|
||||
<image class="image" :src="common_static_url + 'share-friend-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.mv9l10') }}</text>
|
||||
</view>
|
||||
<view class="share-items oh cp" data-scene="WXSceneFavorite" data-provider="weixin" @tap="share_app_event">
|
||||
<image class="image" :src="common_static_url + 'share-favor-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.f08y38') }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="is_app_qq">
|
||||
<view class="share-items oh cp" data-provider="qq" @tap="share_app_event">
|
||||
<image class="image":src="common_static_url + 'share-qq-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.1242w9') }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 || APP -->
|
||||
<view class="share-items oh cp" @tap="share_url_copy_event">
|
||||
<image class="image" :src="common_static_url + 'share-url-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.1oh013') }}</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<view v-if="is_goods_poster == 1 && (goods_id || 0) != 0" class="share-items oh cp" @tap="poster_event">
|
||||
<image class="image" :src="common_static_url + 'share-poster-icon.png'" mode="scaleToFill"></image>
|
||||
<text class="cr-grey text-size-xs single-text">{{ $t('share-popup.share-popup.dcp2qu') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</component-popup>
|
||||
|
||||
<!-- 用户基础 -->
|
||||
<component-user-base ref="user_base"></component-user-base>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
const app = getApp();
|
||||
var common_static_url = app.globalData.get_static_url('common');
|
||||
import componentPopup from '@/components/popup/popup';
|
||||
import componentUserBase from '@/components/user-base/user-base';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
theme_view: app.globalData.get_theme_value_view(),
|
||||
common_static_url: common_static_url,
|
||||
popup_status: false,
|
||||
type: null,
|
||||
is_goods_poster: 0,
|
||||
goods_id: 0,
|
||||
url: null,
|
||||
images: null,
|
||||
title: null,
|
||||
summary: null,
|
||||
is_app_weixin: true,
|
||||
is_app_qq: true,
|
||||
share_info: {},
|
||||
};
|
||||
},
|
||||
|
||||
components: {
|
||||
componentPopup,
|
||||
componentUserBase,
|
||||
},
|
||||
|
||||
created: function () {},
|
||||
|
||||
methods: {
|
||||
// 初始配置
|
||||
init(config = {}) {
|
||||
if (!app.globalData.is_single_page_check()) {
|
||||
return false;
|
||||
}
|
||||
this.setData({
|
||||
popup_status: config.status == undefined ? true : config.status,
|
||||
type: config.type == undefined ? null : config.type,
|
||||
is_goods_poster: config.is_goods_poster || 0,
|
||||
goods_id: config.goods_id || 0,
|
||||
goods_id: config.goods_id || 0,
|
||||
url: config.url || null,
|
||||
images: config.images || null,
|
||||
title: config.title || null,
|
||||
summary: config.summary || null,
|
||||
share_info: config.share_info || {},
|
||||
});
|
||||
|
||||
// 用户头像和昵称设置提示
|
||||
if ((this.$refs.user_base || null) != null) {
|
||||
this.$refs.user_base.init('share');
|
||||
}
|
||||
|
||||
// #ifdef APP
|
||||
// app分享通道隔离
|
||||
uni.getProvider({
|
||||
service: 'share',
|
||||
success: (result) => {
|
||||
var provider = result.provider || [];
|
||||
this.setData({
|
||||
is_app_weixin: provider.indexOf('weixin') != -1,
|
||||
is_app_qq: provider.indexOf('qq') != -1,
|
||||
});
|
||||
},
|
||||
fail: (error) => {},
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
|
||||
// 弹层关闭
|
||||
popup_close_event(e) {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
},
|
||||
|
||||
// url链接地址复制分享
|
||||
share_url_copy_event() {
|
||||
var url = app.globalData.get_page_url();
|
||||
// 增加分享标识
|
||||
if(url.indexOf('referrer') == -1) {
|
||||
var uid = app.globalData.get_user_cache_info('id') || null;
|
||||
if(uid != null) {
|
||||
var join = url.indexOf('?') == -1 ? '?' : '&';
|
||||
url += join+'referrer='+uid;
|
||||
}
|
||||
}
|
||||
app.globalData.text_copy_event(url);
|
||||
},
|
||||
|
||||
// 基础分享事件
|
||||
share_base_event() {
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
uni.pageScrollTo({
|
||||
scrollTop: 0,
|
||||
duration: 300,
|
||||
complete: (res) => {
|
||||
setTimeout(function () {
|
||||
uni.showShareMenu();
|
||||
}, 500);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 商品海报分享
|
||||
poster_event() {
|
||||
var user = app.globalData.get_user_info(this, 'poster_event');
|
||||
if (user != false) {
|
||||
uni.showLoading({
|
||||
title: this.$t('detail.detail.6xvl35'),
|
||||
});
|
||||
uni.request({
|
||||
url: app.globalData.get_request_url('goodsposter', 'distribution', 'distribution'),
|
||||
method: 'POST',
|
||||
data: { goods_id: this.goods_id },
|
||||
dataType: 'json',
|
||||
success: (res) => {
|
||||
uni.hideLoading();
|
||||
|
||||
if (res.data.code == 0) {
|
||||
uni.previewImage({
|
||||
current: res.data.data,
|
||||
urls: [res.data.data],
|
||||
});
|
||||
} else {
|
||||
if (app.globalData.is_login_check(res.data, this, 'poster_event')) {
|
||||
app.globalData.showToast(res.data.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
app.globalData.showToast(this.$t('common.internet_error_tips'));
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// app分享
|
||||
share_app_event(e) {
|
||||
// 分享参数
|
||||
var provider = e.currentTarget.dataset.provider;
|
||||
var scene = e.currentTarget.dataset.scene || null;
|
||||
// 分享基础数据
|
||||
var share = app.globalData.share_content_handle(this.share_info || {});
|
||||
var img = this.images || share.img;
|
||||
var url = this.url || share.url;
|
||||
var title = this.title || share.title;
|
||||
var summary = this.summary || share.desc;
|
||||
var type = this.type === null ? ((img || null) == null ? 1 : 0) : this.type;
|
||||
var miniProgram = {};
|
||||
|
||||
// #ifdef APP
|
||||
// 分享到好友,是否走微信小程序,则获取微信小程序原始id
|
||||
if (scene == 'WXSceneSession') {
|
||||
var weixin_original_id = app.globalData.get_config('config.common_app_mini_weixin_share_original_id') || null;
|
||||
if (weixin_original_id != null) {
|
||||
type = 5;
|
||||
miniProgram = {
|
||||
id: weixin_original_id,
|
||||
path: url.split('#')[1],
|
||||
type: 0,
|
||||
webUrl: url,
|
||||
};
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 关闭分享弹窗
|
||||
this.setData({
|
||||
popup_status: false,
|
||||
});
|
||||
// 调用分享组件
|
||||
uni.share({
|
||||
provider: provider,
|
||||
scene: scene,
|
||||
type: type,
|
||||
href: url,
|
||||
title: title,
|
||||
summary: summary,
|
||||
imageUrl: img,
|
||||
miniProgram: miniProgram,
|
||||
success: function (res) {},
|
||||
fail: function (err) {},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.share-popup {
|
||||
padding: 20rpx 10rpx 0 10rpx;
|
||||
position: relative;
|
||||
}
|
||||
.share-popup .close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
padding: 20rpx;
|
||||
}
|
||||
.share-popup-content {
|
||||
padding: 0 20rpx;
|
||||
text-align: left;
|
||||
}
|
||||
.share-popup-content .share-items {
|
||||
padding: 30rpx 0;
|
||||
min-height: 85rpx;
|
||||
display: flex;
|
||||
}
|
||||
.share-popup-content .share-items:not(:first-child) {
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
.share-popup-content .share-items .btn {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
}
|
||||
.share-popup-content .share-items .image {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
vertical-align: middle;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
.share-popup-content .share-items .single-text {
|
||||
width: calc(100% - 100rpx);
|
||||
line-height: 85rpx;
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user