Compare commits

...

48 Commits

Author SHA1 Message Date
38ade75046 fix(diy-map): 替换cover-view为div解决z-index失效问题
移除ns-login组件中不必要的z-index设置
2026-01-24 09:20:01 +08:00
1e51abd7cd docs: 更新本地配置示例文件添加IVD数商模式配置
添加2812环境的IVD数商模式配置,并增加本地开发测试平台选项
2026-01-23 17:09:42 +08:00
0939449aa7 fix(ns-login): 修复complete-info-wrap弹窗层级问题 2026-01-23 17:09:05 +08:00
29b5cfda6f fix: 在页面加载时统一隐藏首页按钮
在多个页面的onLoad生命周期中添加this.$util.hideHomeButton()调用,确保页面加载时即隐藏首页按钮,避免显示不一致问题。同时调整category.vue中onShow的逻辑顺序。
2026-01-23 11:54:31 +08:00
ceca4e5956 fix: 在多个页面添加隐藏首页按钮功能
为统一处理首页按钮显示逻辑,在会员页、联系页和商品分类页的onShow生命周期中添加了hideHomeButton调用
2026-01-23 11:36:15 +08:00
aa9d2e64d2 feat(util): 添加隐藏微信小程序首页按钮功能
添加 hideHomeButton 方法用于在微信小程序环境中隐藏首页按钮,提升用户体验
2026-01-23 11:18:55 +08:00
e8ccb87266 feat(脚本): 增强微信小程序补丁脚本功能
- 添加新的 npm scripts 支持不同模式运行补丁脚本
- 支持命令行参数 --no-zip 和 --mode 控制 ZIP 文件生成和运行模式
- 自动复制项目配置文件到目标目录
- 更新使用说明文档
2026-01-23 10:12:30 +08:00
153c84266a chore: 更新项目配置文件和微信小程序名称
- 将项目名称从'lucky_shop'改为'mp-weixin'
- 在project.config.json中添加include数组和多个新配置项
- 启用enhance功能并添加编译相关设置
2026-01-23 09:25:58 +08:00
7ae7a1d3bd chore(uniapp): 增加拷贝文本超时检测提示功能 2026-01-17 15:30:02 +08:00
1ebb94e9e2 chore: 调整隐私协议及注册服务展示样式 2026-01-17 13:52:19 +08:00
9b53540f91 Merge branch 'dev/1.0' of http://git.aigc-quickapp.com/Uniapp/lucky_shop into dev/1.0 2026-01-16 18:11:00 +08:00
2a36fa2b60 chore(build): 调整默认小程序AppID及site.js文件 2026-01-16 18:07:59 +08:00
2223636184 Merge branch 'dev/1.0' of http://git.aigc-quickapp.com/Uniapp/lucky_shop into dev/1.0 2026-01-16 18:00:31 +08:00
6144dc72b8 chore:非 h5 平台 :key 不支持表达式的问题 2026-01-16 18:00:03 +08:00
47e1c2372d chore(sass): 编译器从node-sass转移成dart-sass 2026-01-16 17:52:33 +08:00
5b9bef9214 chore(build): 调整个别组件的位置,减少对主包尺寸的影响 2026-01-16 15:34:04 +08:00
08880a15df fix(电子名片): 再使用视频号组件的时候,严格转换数据类型 2026-01-16 10:47:52 +08:00
e40e6e73b2 chore(build): 调整ai-chat-message组件的位置,减少对主包尺寸的影响 2026-01-16 10:34:00 +08:00
dd4176998b Merge branch 'feat/personnel_channel' into dev/1.0 2026-01-16 10:16:40 +08:00
2896817435 chore: 删除不需要的页面及demo组件 2026-01-16 08:49:46 +08:00
dc956761a0 Merge branch 'feat/personnel_channel' into dev/1.0 2026-01-15 18:14:50 +08:00
36fd0621fd fix(视频号组件): padding 影响布局 2026-01-15 18:05:30 +08:00
1e6cd55f0a chore:中英文切换按钮能切换英文 2026-01-15 15:10:46 +08:00
f7fcf7fb27 chore:点击英文按钮,页面不是空白了 2026-01-15 15:01:39 +08:00
28359f2f16 fix(视频号组件): 整体控制是否显示观看次数没有生效 2026-01-15 14:58:36 +08:00
c6a8bc04f2 chore:解决了siteInfo,bgUrl错误 2026-01-15 14:08:32 +08:00
82df9ddbac chore:加了中英文切换按钮 2026-01-14 18:24:42 +08:00
e8fb35b310 chore:智能体客服正常运行 2026-01-13 18:26:11 +08:00
286fcc2142 chore:合并了之前智能客服的代码 2026-01-13 16:42:06 +08:00
2280ff68fa Merge branch 'feat-ai-agent-kefu' into xindeznkf
chore:合并了提交
2026-01-13 15:57:35 +08:00
5747b256c6 chore:改了webd的基础路径为common 2026-01-09 17:54:18 +08:00
09b285016c chore:修改了快应用发行文档 2026-01-09 17:34:06 +08:00
72c12a79fd chore:修改了快应用的发行文档 2026-01-09 17:18:43 +08:00
84f4ad83c2 chore:增加了快应用打包步骤 2026-01-09 15:45:19 +08:00
1512c60109 chore:修改快应用发布 2026-01-09 11:52:29 +08:00
5b41dee46c Merge remote-tracking branch 'remotes/origin/dev/1.0' into dev/1.0 2026-01-09 11:34:19 +08:00
8fedeafe63 chore:修改了小程序打包步骤 2026-01-09 10:41:45 +08:00
f3bb6a1782 chore:智能体客服和原来的客服都在 2025-12-17 15:43:37 +08:00
2a0489d4b2 chore:能正常运行 2025-12-17 11:17:50 +08:00
ca74d4f8e5 chore: 要明确集成微信及支付宝原生客服 2025-12-17 09:19:19 +08:00
d9c9599cb2 chore: 集成统一客服服务 2025-12-16 16:54:39 +08:00
142a97d65c revert: pages/contact/contact.vue 回退到最初状态 2025-12-16 15:52:18 +08:00
b945583857 chore: 优化公共端都支持打开企业微信客服的方法 2025-12-16 15:41:15 +08:00
88debacf8c chore: 使用全局的wxworkConfig配置作为参数 2025-12-16 14:41:45 +08:00
9d12b02463 chore: 将wxworkConfig放到全局配置中 2025-12-16 14:41:15 +08:00
23e81114e9 chore: 后端init接口数据为wxwork_config 2025-12-16 10:54:57 +08:00
08583aa8aa chore: 企业微信客服组件完全独立 2025-12-15 15:04:45 +08:00
5e536afeae feat: 新增打开企业微信客服组件 2025-12-15 14:26:01 +08:00
136 changed files with 4911 additions and 2273 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
/.hbuilderx /.hbuilderx
/.idea /.idea
/node_modules /node_modules
/iconfont-preview.html

View File

@@ -38,6 +38,10 @@ const localDevConfig = ({
uniacid: 1, uniacid: 1,
domain: 'https://test.aigc-quickapp.com', domain: 'https://test.aigc-quickapp.com',
}, },
'local-2': { // 测试平台
uniacid: 2,
domain: 'http://localhost:8050/',
},
})['2811']; // 选择要使用的环境配置 })['2811']; // 选择要使用的环境配置
export default localDevConfig; export default localDevConfig;

View File

@@ -18,6 +18,10 @@ const localDevConfig = ({
uniacid: 2811, uniacid: 2811,
domain: 'https://xcx6.aigc-quickapp.com/', domain: 'https://xcx6.aigc-quickapp.com/',
}, },
'2812': { // IVD数商模式
uniacid: 2812,
domain: 'https://xcx6.aigc-quickapp.com/',
},
'2724': { // 生物菌肥 '2724': { // 生物菌肥
uniacid: 2724, uniacid: 2724,
domain: 'https://xcx.aigc-quickapp.com/', domain: 'https://xcx.aigc-quickapp.com/',
@@ -42,6 +46,10 @@ const localDevConfig = ({
uniacid: 2, uniacid: 2,
domain: 'http://localhost:8050/', domain: 'http://localhost:8050/',
}, },
})['2811']; // 选择要使用的环境配置 'local-2-dev': { // 本地开发测试平台
uniacid: 2,
domain: 'http://localhost:8050/',
},
})['2812']; // 选择要使用的环境配置
export default localDevConfig; export default localDevConfig;

View File

@@ -314,7 +314,7 @@
@import './common/css/iconfont.css'; @import './common/css/iconfont.css';
@import './common/css/icondiy.css'; // 自定义图标库 @import './common/css/icondiy.css'; // 自定义图标库
@import './common/css/icon/extend.css'; // 扩展图标库 @import './common/css/icon/extend.css'; // 扩展图标库
page{ page {
background: #f4f6fa; background: #f4f6fa;
} }
</style> </style>

View File

@@ -123,7 +123,7 @@ image {
} }
.choose-store { .choose-store {
/deep/ .uni-popup__wrapper{ ::v-deep .uni-popup__wrapper{
background: none!important; background: none!important;
} }
} }

View File

@@ -870,13 +870,13 @@
// 海报 // 海报
// .uni-popup__wrapper-box // .uni-popup__wrapper-box
.poster-layer { .poster-layer {
/deep/ .uni-popup__wrapper.center { ::v-deep .uni-popup__wrapper.center {
width: 100vw!important; width: 100vw!important;
height: 100vh!important; height: 100vh!important;
background: none!important; background: none!important;
} }
/deep/ .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
max-width: 100vw!important; max-width: 100vw!important;
max-height: 100vh!important; max-height: 100vh!important;
background: none!important; background: none!important;

View File

@@ -559,7 +559,7 @@ scroll-view ::-webkit-scrollbar {
background-color: transparent; background-color: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
width: 0; width: 0;
height: 0; height: 0;
background-color: transparent; background-color: transparent;
@@ -609,7 +609,7 @@ scroll-view ::-webkit-scrollbar {
font-weight: 500!important; font-weight: 500!important;
} }
/deep/ .reward-popup .uni-popup__wrapper-box { ::v-deep .reward-popup .uni-popup__wrapper-box {
background: none !important; background: none !important;
max-width: unset !important; max-width: unset !important;
max-height: unset !important; max-height: unset !important;
@@ -618,7 +618,7 @@ scroll-view ::-webkit-scrollbar {
// #ifdef H5 // #ifdef H5
// 下拉加载动画【页面】 // 下拉加载动画【页面】
/deep/ body uni-page-refresh div{ ::v-deep body uni-page-refresh div{
width: 14rpx !important; width: 14rpx !important;
height: 14rpx !important; height: 14rpx !important;
background-color: #ccc; background-color: #ccc;
@@ -626,7 +626,7 @@ scroll-view ::-webkit-scrollbar {
clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important; clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important;
animation:.6s backgroundChange linear infinite; animation:.6s backgroundChange linear infinite;
} }
/deep/ body uni-page-refresh div::after{ ::v-deep body uni-page-refresh div::after{
content: ""; content: "";
position: absolute; position: absolute;
left: -22rpx; left: -22rpx;
@@ -636,7 +636,7 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc; background-color: #ccc;
animation:.5s backgroundChange linear infinite; animation:.5s backgroundChange linear infinite;
} }
/deep/ body uni-page-refresh div::before{ ::v-deep body uni-page-refresh div::before{
content: ""; content: "";
position: absolute; position: absolute;
right: -22rpx; right: -22rpx;
@@ -646,15 +646,15 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc; background-color: #ccc;
animation:.7s backgroundChange linear infinite; animation:.7s backgroundChange linear infinite;
} }
/deep/ body uni-page-refresh > div > div{ ::v-deep body uni-page-refresh > div > div{
display: none !important; display: none !important;
} }
// 下拉加载动画【scroll-view】 // 下拉加载动画【scroll-view】
/deep/ body .uni-scroll-view-refresher{ ::v-deep body .uni-scroll-view-refresher{
background-color: transparent !important; background-color: transparent !important;
} }
/deep/ body .uni-scroll-view-refresher div{ ::v-deep body .uni-scroll-view-refresher div{
left: 50%; left: 50%;
top: 50%; top: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
@@ -666,7 +666,7 @@ scroll-view ::-webkit-scrollbar {
clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important; clip: rect(-152rpx, 90rpx, 90rpx, -30rpx) !important;
animation:.6s backgroundChange linear infinite; animation:.6s backgroundChange linear infinite;
} }
/deep/ body .uni-scroll-view-refresher div::after{ ::v-deep body .uni-scroll-view-refresher div::after{
content: ""; content: "";
position: absolute; position: absolute;
left: -22rpx; left: -22rpx;
@@ -676,7 +676,7 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc; background-color: #ccc;
animation:.5s backgroundChange linear infinite; animation:.5s backgroundChange linear infinite;
} }
/deep/ body .uni-scroll-view-refresher div::before{ ::v-deep body .uni-scroll-view-refresher div::before{
content: ""; content: "";
position: absolute; position: absolute;
right: -22rpx; right: -22rpx;
@@ -686,7 +686,7 @@ scroll-view ::-webkit-scrollbar {
background-color: #ccc; background-color: #ccc;
animation:.7s backgroundChange linear infinite; animation:.7s backgroundChange linear infinite;
} }
/deep/ body .uni-scroll-view-refresher > div > div{ ::v-deep body .uni-scroll-view-refresher > div > div{
display: none !important; display: none !important;
} }
@keyframes backgroundChange { @keyframes backgroundChange {

View File

@@ -1,4 +1,4 @@
// 修复图片垂直对齐问题,解决两张图片上下有空白缝隙问题 // 修复图片垂直对齐问题,解决两张图片上下有空白缝隙问题
/deep/ ._img { ::v-deep ._img {
vertical-align: top; vertical-align: top;
} }

View File

@@ -377,7 +377,7 @@ view {
} }
} }
/deep/ .goods-form { ::v-deep .goods-form {
display: flex; display: flex;
align-items: center; align-items: center;
position: relative; position: relative;
@@ -1354,7 +1354,7 @@ view {
border-bottom: 2rpx solid #F4F4F6; border-bottom: 2rpx solid #F4F4F6;
} }
/deep/ .form-wrap { ::v-deep .form-wrap {
margin: 0 24rpx; margin: 0 24rpx;
.icon-right { .icon-right {

View File

@@ -116,7 +116,7 @@ class ConfigExternal {
try { try {
// 动态加载主题配置 // 动态加载主题配置
const themeData = require(`@/common/js/style_color.js`)['default'][theme]; const themeData = require(`@/common/js/style_color.js`)['default'][theme];
console.log('async themeData => ', themeData); // console.log('async themeData => ', themeData);
this.loadedConfigs[`theme_${theme}`] = themeData; this.loadedConfigs[`theme_${theme}`] = themeData;
resolve(themeData); resolve(themeData);
} catch (error) { } catch (error) {

View File

@@ -2,13 +2,68 @@
* 客服统一处理服务 * 客服统一处理服务
* 整合各种客服方式,提供统一的调用接口 * 整合各种客服方式,提供统一的调用接口
*/ */
export class CustomerService { class CustomerService {
constructor(vueInstance, externalConfig = null) { constructor(vueInstance, externalConfig = {}) {
if (!vueInstance.$lang) {
throw new Error('CustomerService 必须在 Vue 实例中初始化');
}
this.vm = vueInstance; this.vm = vueInstance;
this.externalConfig = externalConfig; // 外部传入的最新配置(优先级最高) this.externalConfig = externalConfig; // 外部传入的最新配置(优先级最高)
this.latestPlatformConfig = null; this.latestPlatformConfig = null;
} }
getSupoortKeFuList() {
if (!this.vm) return [];
const vm = this.vm;
return [
{
id: 'weixin-official',
name: vm.$lang('customer.weChatKefu'),
isOfficial: true,
type: 'weapp'
},
{
id: 'custom-kefu',
name: vm.$lang('customer.systemKefu'),
isOfficial: false
},
{
id: 'qyweixin-kefu',
name: vm.$lang('customer.weChatWorkKefu'),
isOfficial: false
},
]
}
/**
* 打开客服选择弹窗
*/
openCustomerSelectPopupDialog() {
const kefu_list = this.getSupoortKeFuList();
const kefuNames = kefu_list.map(item => item.name);
uni.showActionSheet({
itemList: kefuNames,
success: (res) => {
const kefu = kefu_list[res.tapIndex];
this.externalConfig = kefu ?? this.externalConfig ?? {};
if (kefu.isOfficial) {
uni.openCustomerServiceConversation({
sessionFrom: 'weapp',
showMessageCard: true
});
} else if (kefu.id === 'custom-kefu') {
this.handleCustomerClick();
} else if (kefu.id === 'qyweixin-kefu') {
this.handleQyWeixinKefuClick();
}
}
});
}
/** /**
* 强制刷新配置(支持传入外部配置) * 强制刷新配置(支持传入外部配置)
* @param {Object} externalConfig 外部最新配置 * @param {Object} externalConfig 外部最新配置
@@ -122,35 +177,11 @@ export class CustomerService {
} }
/** /**
* 跳转到Dify客服页面 * 跳转到AI客服页面
*/ */
openDifyService() { openAIKeFuService() {
try { const vm = this.vm;
if (this.vm.setAiUnreadCount) { vm.$util.redirectTo(vm.$util.AI_CHAT_PAGE_URL);
this.vm.setAiUnreadCount(0);
}
// 强制跳转,忽略框架层的封装
uni.redirectTo({
url: '/pages_tool/ai-chat/index',
fail: (err) => {
// 兜底使用window.location跳转H5
// #ifdef H5
window.location.href = '/pages_tool/ai-chat/index';
// #endif
console.error('跳转Dify客服失败:', err);
uni.showToast({
title: '跳转客服失败',
icon: 'none'
});
}
});
} catch (e) {
console.error('跳转Dify客服异常:', e);
uni.showToast({
title: '跳转客服失败',
icon: 'none'
});
}
} }
/** /**
@@ -170,7 +201,7 @@ export class CustomerService {
} }
const config = this.getPlatformConfig(); const config = this.getPlatformConfig();
const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options; const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
if (config.type === 'none') { if (config.type === 'none') {
this.showNoServicePopup(); this.showNoServicePopup();
@@ -180,7 +211,7 @@ export class CustomerService {
// 核心分支根据最新的type处理 // 核心分支根据最新的type处理
switch (config.type) { switch (config.type) {
case 'aikefu': case 'aikefu':
this.openDifyService(); this.openAIKeFuService();
break; break;
case 'wxwork': case 'wxwork':
this.openWxworkService(false, config, options); this.openWxworkService(false, config, options);
@@ -211,7 +242,7 @@ export class CustomerService {
openWxworkService(useOriginalService = false, servicerConfig = null, options = {}) { openWxworkService(useOriginalService = false, servicerConfig = null, options = {}) {
const config = servicerConfig || this.getPlatformConfig(); const config = servicerConfig || this.getPlatformConfig();
const wxworkConfig = this.getWxworkConfig(); const wxworkConfig = this.getWxworkConfig();
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options; const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
if (wxworkConfig?.enable && wxworkConfig?.contact_url && !useOriginalService) { if (wxworkConfig?.enable && wxworkConfig?.contact_url && !useOriginalService) {
@@ -292,7 +323,7 @@ export class CustomerService {
* @param {Object} options 选项参数 * @param {Object} options 选项参数
*/ */
handleCustomWeappService(config, options = {}) { handleCustomWeappService(config, options = {}) {
const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options; const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
if (config.customServiceUrl) { if (config.customServiceUrl) {
let url = config.customServiceUrl; let url = config.customServiceUrl;
@@ -381,7 +412,7 @@ export class CustomerService {
console.log('支付宝小程序客服', config); console.log('支付宝小程序客服', config);
switch (config.type) { switch (config.type) {
case 'aikefu': case 'aikefu':
this.openDifyService(); this.openAIKeFuService();
break; break;
case 'third': case 'third':
this.openThirdService(config); this.openThirdService(config);
@@ -395,13 +426,22 @@ export class CustomerService {
/** /**
* 拨打电话 * 拨打电话
*/ */
makePhoneCall() { makePhoneCall(mobileNumber) {
this.vm.$api.sendRequest({ if (mobileNumber) {
url: '/api/site/shopcontact', return uni.makePhoneCall({
success: res => { phoneNumber: mobileNumber
if (res.code === 0 && res.data?.mobile) { });
}
// 从缓存中获取电话信息
uni.getStorage({
key: 'shopInfo',
success: (res) => {
const shopInfo = res.data;
const mobile = shopInfo?.mobile ?? '';
if (mobile) {
uni.makePhoneCall({ uni.makePhoneCall({
phoneNumber: res.data.mobile phoneNumber: mobile
}); });
} else { } else {
uni.showToast({ uni.showToast({
@@ -409,12 +449,6 @@ export class CustomerService {
icon: 'none' icon: 'none'
}); });
} }
},
fail: () => {
uni.showToast({
title: '获取客服电话失败',
icon: 'none'
});
} }
}); });
} }
@@ -506,6 +540,6 @@ export class CustomerService {
* @param {Object} externalConfig 外部最新配置 * @param {Object} externalConfig 外部最新配置
* @returns {CustomerService} 客服服务实例 * @returns {CustomerService} 客服服务实例
*/ */
export function createCustomerService(vueInstance, externalConfig = null) { export function createCustomerService(vueInstance, externalConfig = {}) {
return new CustomerService(vueInstance, externalConfig); return new CustomerService(vueInstance, externalConfig);
} }

View File

@@ -69,6 +69,10 @@ export default {
servicerConfig() { servicerConfig() {
return this.$store.state.servicerConfig; return this.$store.state.servicerConfig;
}, },
// 企业微信配置
wxworkConfig() {
return this.$store.state.wxworkConfig;
},
diySeckillInterval() { diySeckillInterval() {
return this.$store.state.diySeckillInterval; return this.$store.state.diySeckillInterval;
}, },

148
common/js/uniapp.utils.js Normal file
View File

@@ -0,0 +1,148 @@
/**
* 将常用的Uniapp提供的函数存放到这里按需引用
*/
/**
* 显示错误信息
* @param {Exception} err
* @param {Boolean} useModal
*/
const showError = (err, useModal = false) => {
const content = err?.message || err?.errMsg || err?.toString();
if (!useModal) {
uni.showToast({
title: content,
icon: 'none',
duration: 3000
});
} else {
uni.showModal({
title: '错误提示',
content,
showCancel: false,
})
}
}
/**
* 打电话
* @param {string} mobile 电话号码
*/
export const makePhoneCall = (mobile) => {
try {
uni.makePhoneCall({
phoneNumber: `${mobile}`,
success(e) {
console.log(e);
}
});
} catch (err) {
showError(err);
}
}
/**
* 拷贝文本(返回 Promise
* @param {*} text
* @param {*} options
* @returns {Promise} 返回 Promise成功时 resolve失败时 reject
*/
export const copyTextAsync = (text, { copySuccess = '', copyFailed = '' } = {}) => {
return new Promise((resolve, reject) => {
// 输入验证
if (!text && text !== '') {
const error = new Error('复制文本不能为空');
showError(error);
reject(error);
return;
}
// 超时监测
const timeoutId = setTimeout(() => {
let error = new Error('复制操作长时间无响应,请检查相关权限及配置是否正确');
// #ifdef MP-WEIXIN
error = new Error([
'复制操作长时间无响应!',
'原因:',
'1.微信平台->用户隐私保护指引->"剪贴板"功能未添加或审核未通过;',
'2.微信平台对剪贴板API调用频率有限制'
].join('\r\n'));
// #endif
showError(error, true);
reject(error);
}, 5000);
try {
uni.setClipboardData({
data: `${text}`,
success: (res) => {
clearTimeout(timeoutId);
try {
if (copySuccess) {
uni.showToast({
title: copySuccess,
icon: 'success',
duration: 2000
});
}
} catch (e) {
showError(e);
}
resolve(res);
},
fail: (err) => {
clearTimeout(timeoutId);
try {
uni.showToast({
title: err.message || err.errMsg || copyFailed || '复制失败',
icon: 'none',
duration: 2000
});
} catch (e) {
showError(e);
}
reject(err);
}
});
} catch (err) {
clearTimeout(timeoutId);
showError(err);
reject(err);
}
});
}
/**
* 拷贝文本(回调形式,兼容旧代码)
* @param {*} text
* @param {*} options
* @param {Function} callback 回调函数,接收 (success, error) 参数
*/
export const copyText = (text, options = {}, callback) => {
copyTextAsync(text, options)
.then(res => {
if (callback) callback(true, null);
})
.catch(err => {
if (callback) callback(false, err);
});
}
/**
* 打开定位
* @param {Object} options
*/
export const openLocation = ({ latitude, longitude, name } = {}) => {
try {
uni.openLocation({
latitude,
longitude,
name,
});
} catch (err) {
showError(err);
}
}

View File

@@ -13,6 +13,7 @@ export const CATEGORY_PAGE_URL = '/pages_goods/category';
export const CONTACT_PAGE_URL = '/pages_tool/contact/contact'; export const CONTACT_PAGE_URL = '/pages_tool/contact/contact';
export const MEMBER_PAGE_URL = '/pages_tool/member/index'; export const MEMBER_PAGE_URL = '/pages_tool/member/index';
export const LOGIN_PAGE_URL = '/pages_tool/login/login'; export const LOGIN_PAGE_URL = '/pages_tool/login/login';
export const AI_CHAT_PAGE_URL = '/pages_tool/ai-chat/index';
// 当前最新的tabBar.list (参见pages.json 中的tabBar.list 配置) // 当前最新的tabBar.list (参见pages.json 中的tabBar.list 配置)
export const systemTabBarList = [ export const systemTabBarList = [
@@ -119,6 +120,7 @@ export default {
CONTACT_PAGE_URL, CONTACT_PAGE_URL,
INDEX_PAGE_URL, INDEX_PAGE_URL,
LOGIN_PAGE_URL, LOGIN_PAGE_URL,
AI_CHAT_PAGE_URL,
/** /**
* 页面跳转 * 页面跳转
@@ -606,6 +608,33 @@ export default {
/**
* 打开微信企业客服
* @param {Function} fallbackFunc 降级处理函数
*/
openWxWorkServiceChat(fallbackFunc) {
// #ifdef MP-WEIXIN
let wxworkConfig = store.state?.wxworkConfig
if (wxworkConfig?.enable && wxworkConfig?.contact_url) {
// 直接使用活码链接跳转
wx.navigateToMiniProgram({
appId: 'wxeb490c6f9b154ef9', // 是企业微信官方小程序的AppID固定值, 由腾讯企业微信团队维护, 不需要修改,用于展示"添加企业微信联系人"的官方页面)
path: `pages/contacts/externalContactDetail?url=${encodeURIComponent(wxworkConfig?.contact_url)}`,
success: () => {
console.log('跳转企业微信成功');
},
fail: (err) => {
console.error('跳转企业微信失败:', err);
// 降级处理:使用原有客服方式
fallbackFunc && fallbackFunc();
}
});
} else {
fallbackFunc && fallbackFunc();
}
// #endif
},
/** /**
* 自定义模板的跳转链接 * 自定义模板的跳转链接
* @param {Object} link * @param {Object} link
@@ -667,16 +696,19 @@ export default {
// #endif // #endif
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
wx.openCustomerServiceChat({ this.openWxWorkServiceChat(() => {
extInfo: { wx.openCustomerServiceChat({
url: config.wxwork_url extInfo: {
}, url: config.wxwork_url
corpId: config.corpid, },
showMessageCard: true, corpId: config.corpid,
sendMessageTitle: 'this.sendMessageTitle', showMessageCard: true,
sendMessagePath: 'this.sendMessagePath', sendMessageTitle: 'this.sendMessageTitle',
sendMessageImg: 'this.sendMessageImg' sendMessagePath: 'this.sendMessagePath',
sendMessageImg: 'this.sendMessageImg'
});
}); });
// #endif // #endif
break; break;
case 'third': case 'third':
@@ -811,6 +843,15 @@ export default {
uni.navigateBack(); uni.navigateBack();
} }
}, },
/**
* 隐藏“返回首页/小房子”按钮
* 这个函数用到页面show, onshow 的生命周期时
*/
hideHomeButton() {
// #ifdef MP-WEIXIN
wx.hideHomeButton();
// #endif
},
/** /**
* *
* @param val 转化时间字符串 (转化时分秒) * @param val 转化时间字符串 (转化时分秒)
@@ -1170,7 +1211,7 @@ export default {
let _isQuickApp = false; let _isQuickApp = false;
try { try {
const ua = navigator?.userAgent?.toLowerCase(); const ua = navigator?.userAgent?.toLowerCase();
console.log('ua = ', ua); // console.log('ua = ', ua);
_isQuickApp = ua.indexOf('quickapp') !== -1; _isQuickApp = ua.indexOf('quickapp') !== -1;
if (!_isQuickApp) { if (!_isQuickApp) {

View File

@@ -365,7 +365,7 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar { ::v-deep .uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
width: 0; width: 0;
@@ -374,7 +374,7 @@ export default {
background: transparent; background: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -1160,7 +1160,7 @@ export default {
.right-wrap { .right-wrap {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: end; justify-content: flex-end;
.num { .num {
width: auto; width: auto;
@@ -1314,7 +1314,7 @@ export default {
} }
} }
/deep/ .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper-box {
border-radius: 0; border-radius: 0;
} }
@@ -1348,7 +1348,7 @@ export default {
justify-content: center; justify-content: center;
} }
/deep/ .loading-layer { ::v-deep .loading-layer {
background: #fff !important; background: #fff !important;
} }

View File

@@ -548,7 +548,7 @@ export default {
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.category-page-wrap { .category-page-wrap {
width: 100vw; width: 100vw;
// height: calc(100vh - var(--tab-bar-height, 0)); // height: calc(100vh - var(--tab-bar-height, 0));
@@ -818,7 +818,7 @@ export default {
z-index: 2; z-index: 2;
} }
/deep/ .template-four { ::v-deep .template-four {
position: relative; position: relative;
z-index: 1; z-index: 1;

View File

@@ -1,5 +1,5 @@
<template> <template>
<view :style="[componentStyle, { '--row-count': value.rowCount }]"> <view class="channel-list-container" :style="[componentStyle, { '--row-count': value.rowCount }]">
<!-- 轮播模式 --> <!-- 轮播模式 -->
<swiper v-if="value.showStyle == 'carousel' && carouselConfig.type != 'hide'" :indicator-dots="isIndicatorDots" <swiper v-if="value.showStyle == 'carousel' && carouselConfig.type != 'hide'" :indicator-dots="isIndicatorDots"
:autoplay="carouselConfig.autoplay || false" :interval="carouselConfig.interval || 3000" :autoplay="carouselConfig.autoplay || false" :interval="carouselConfig.interval || 3000"
@@ -11,8 +11,8 @@
<!-- 视频号视频卡片轮播模式 --> <!-- 视频号视频卡片轮播模式 -->
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true" <diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn" :title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
:cover-style="computedCoverStyle" :play-btn-style="value.playBtnStyle" :show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
:aspect-ratio="value.aspectRatio" /> :play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
</view> </view>
</view> </view>
</swiper-item> </swiper-item>
@@ -24,22 +24,26 @@
<!-- 视频号视频卡片列表模式 --> <!-- 视频号视频卡片列表模式 -->
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true" <diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn" :title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
:cover-style="computedCoverStyle" :play-btn-style="value.playBtnStyle" :show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
:aspect-ratio="value.aspectRatio" /> :play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
</view> </view>
</view> </view>
<!-- 其他布局模式如滚动布局 --> <!-- 其他布局模式如滚动布局 -->
<scroll-view v-else <scroll-view v-else
:class="['channel-nav', value.showStyle == 'fixed' ? 'fixed-layout' : value.showStyle, 'row1-of' + value.rowCount]" :class="['channel-nav', value.showStyle == 'fixed' ? 'fixed-layout' : 'singleSlide', 'row1-of' + value.rowCount]"
:scroll-x="value.showStyle == 'singleSlide'"> :scroll-x="true"
:scroll-y="false"
:enhanced="true"
:bounces="false">
<view class="uni-scroll-view-content"> <view class="uni-scroll-view-content">
<view v-for="(item, index) in value.list" :key="index" :class="['channel-nav-item', value.mode]"> <view v-for="(item, index) in value.list" :key="index"
:class="['channel-nav-item', value.mode, 'row1-of' + value.rowCount]">
<!-- 视频号视频卡片滚动模式 --> <!-- 视频号视频卡片滚动模式 -->
<diy-channel-video :value="item" @video-play="playVideo" :list-mode="true" <diy-channel-video :value="item" @video-play="playVideo" :list-mode="true"
:title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn" :title-line-clamp="value.titleLineClamp" :show-play-btn="value.showPlayBtn"
:cover-style="computedCoverStyle" :play-btn-style="value.playBtnStyle" :show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
:aspect-ratio="value.aspectRatio" /> :play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
@@ -71,6 +75,7 @@ export default {
* @property {number} topAroundRadius - 顶部圆角半径 * @property {number} topAroundRadius - 顶部圆角半径
* @property {number} bottomAroundRadius - 底部圆角半径 * @property {number} bottomAroundRadius - 底部圆角半径
* @property {Object} ornament - 装饰效果配置 * @property {Object} ornament - 装饰效果配置
* @property {boolean} showViewCount - 是否显示播放量可选值true, false
* @property {number} titleLineClamp - 标题显示行数 * @property {number} titleLineClamp - 标题显示行数
* @property {string} aspectRatio - 视频比例可选值16:9, 3:4 * @property {string} aspectRatio - 视频比例可选值16:9, 3:4
* @property {boolean} showPlayBtn - 是否显示播放按钮 * @property {boolean} showPlayBtn - 是否显示播放按钮
@@ -103,6 +108,14 @@ export default {
// 组件创建时的逻辑 // 组件创建时的逻辑
// 可以在这里进行初始化操作,如获取页面宽度等 // 可以在这里进行初始化操作,如获取页面宽度等
}, },
mounted() {
// 组件挂载后添加鼠标拖拽滚动功能
if (!['fixed', 'carousel'].includes(this.value?.showStyle)) {
this.$nextTick(() => {
this.addMouseDragScroll();
});
}
},
watch: { watch: {
/** /**
* 组件刷新监听 * 组件刷新监听
@@ -130,24 +143,24 @@ export default {
* @returns {string} 样式字符串 * @returns {string} 样式字符串
*/ */
componentStyle() { componentStyle() {
let style = ''; const style = {};
// 背景色 // 背景色
if (this.value?.componentBgColor) { if (this.value?.componentBgColor) {
style += 'background-color:' + this.value?.componentBgColor + ';'; style.backgroundColor = this.value?.componentBgColor;
} }
// 圆角样式 // 圆角样式
if (this.value?.componentAngle == 'round') { if (this.value?.componentAngle == 'round') {
style += 'border-top-left-radius:' + (2 * this.value?.topAroundRadius) + 'rpx;'; style.borderTopLeftRadius = (2 * this.value?.topAroundRadius) + 'rpx';
style += 'border-top-right-radius:' + (2 * this.value?.topAroundRadius) + 'rpx;'; style.borderTopRightRadius = (2 * this.value?.topAroundRadius) + 'rpx';
style += 'border-bottom-left-radius:' + (2 * this.value?.bottomAroundRadius) + 'rpx;'; style.borderBottomLeftRadius = (2 * this.value?.bottomAroundRadius) + 'rpx';
style += 'border-bottom-right-radius:' + (2 * this.value?.bottomAroundRadius) + 'rpx;'; style.borderBottomRightRadius = (2 * this.value?.bottomAroundRadius) + 'rpx';
} }
// 装饰效果:阴影 // 装饰效果:阴影
style += 'box-shadow:' + (this.value?.ornament?.type == 'shadow' ? '0 0 10rpx ' + this.value?.ornament?.color : '') + ';'; style.boxShadow = this.value?.ornament?.type == 'shadow' ? '0 0 10rpx ' + this.value?.ornament?.color : '';
// 装饰效果:边框 // 装饰效果:边框
style += 'border:' + (this.value?.ornament?.type == 'stroke' ? '2rpx solid ' + this.value?.ornament?.color : '') + ';'; style.border = this.value?.ornament?.type == 'stroke' ? '2rpx solid ' + this.value?.ornament?.color : '';
return style; return style;
}, },
@@ -285,6 +298,105 @@ export default {
item.coverUrl = wechatChannelConfig.video.defaultCoverUrl; item.coverUrl = wechatChannelConfig.video.defaultCoverUrl;
// #endif // #endif
} }
},
/**
* 添加鼠标拖拽滚动功能
* 在Web环境中实现与微信小程序相同的拖拽滚动效果
*/
addMouseDragScroll() {
// 只在Web环境中添加
// #ifndef MP
console.log('addMouseDragScroll called');
let isDragging = false;
let startX = 0;
let startScrollLeft = 0;
let currentScrollElement = null;
// 查找最近的可滚动祖先元素
const findScrollableParent = (element) => {
while (element && element !== document) {
const style = window.getComputedStyle(element);
if (style.overflowX === 'auto' || style.overflowX === 'scroll') {
return element;
}
element = element.parentElement;
}
return null;
};
// 鼠标按下事件
const handleMouseDown = (e) => {
// 检查是否点击在组件内
if (this.$el.contains(e.target)) {
console.log('mousedown event in component:', e);
// 查找可滚动元素
currentScrollElement = findScrollableParent(e.target);
if (currentScrollElement) {
console.log('Found scrollable element:', currentScrollElement);
isDragging = true;
startX = e.pageX;
startScrollLeft = currentScrollElement.scrollLeft;
currentScrollElement.style.cursor = 'grabbing';
}
}
};
// 鼠标移动事件
const handleMouseMove = (e) => {
if (!isDragging || !currentScrollElement) return;
console.log('mousemove event:', e);
e.preventDefault();
const dx = e.pageX - startX;
currentScrollElement.scrollLeft = startScrollLeft - dx;
console.log('scrollLeft:', currentScrollElement.scrollLeft);
};
// 鼠标释放事件
const handleMouseUp = () => {
if (isDragging && currentScrollElement) {
console.log('mouseup event');
currentScrollElement.style.cursor = 'grab';
}
isDragging = false;
currentScrollElement = null;
};
// 添加全局事件监听器
document.addEventListener('mousedown', handleMouseDown);
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
document.addEventListener('mouseleave', handleMouseUp);
console.log('Global mouse event listeners added');
// 组件销毁时移除事件监听器
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('mousedown', handleMouseDown);
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
document.removeEventListener('mouseleave', handleMouseUp);
console.log('Global mouse event listeners removed');
});
// 为所有.channel-nav元素添加必要的样式
setTimeout(() => {
const channelNavs = document.querySelectorAll('.channel-nav');
console.log('Found channel-nav elements:', channelNavs.length);
channelNavs.forEach(element => {
element.style.overflowX = 'auto';
element.style.overflowY = 'hidden';
element.style.whiteSpace = 'nowrap';
element.style.width = '100%';
element.style.maxWidth = '100%';
element.style.cursor = 'grab';
element.style.userSelect = 'none'; // 防止文本选择
console.log('Added styles to channel-nav:', element);
});
}, 100); // 延迟执行确保DOM已完全渲染
console.log('Mouse drag scroll setup completed');
// #endif
} }
} }
} }
@@ -293,6 +405,10 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import './css/common-channel.scss'; @import './css/common-channel.scss';
.channel-list-container {
padding: 16px 16px 0px;
}
/** /**
* 列表布局样式 * 列表布局样式
*/ */
@@ -300,7 +416,6 @@ export default {
display: grid; display: grid;
grid-template-columns: repeat(var(--row-count, 2), 1fr); grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 8px; gap: 8px;
padding: 16px 16px 0px;
} }
/** /**
@@ -308,13 +423,36 @@ export default {
* 支持固定布局和滚动布局 * 支持固定布局和滚动布局
*/ */
.channel-nav { .channel-nav {
padding: 16rpx;
box-sizing: border-box; box-sizing: border-box;
padding: 16rpx;
// 确保在H5环境中可以水平滚动
overflow-x: auto;
white-space: nowrap;
// 隐藏滚动条但保留滚动功能
::-webkit-scrollbar {
display: none;
}
scrollbar-width: none;
-ms-overflow-style: none;
// 启用触摸滚动和鼠标拖拽滚动
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
.uni-scroll-view-content { .uni-scroll-view-content {
/* #ifdef MP-WEIXIN */
display: flex;
flex-wrap: nowrap;
gap: 16rpx;
/* #endif */
/* #ifndef MP-WEIXIN */
display: grid; display: grid;
grid-template-columns: repeat(var(--row-count, 2), 1fr); grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 16rpx; gap: 16rpx;
/* #endif */
} }
// 单滑动模式 // 单滑动模式
@@ -323,6 +461,7 @@ export default {
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
gap: 16rpx; gap: 16rpx;
white-space: nowrap;
} }
.channel-nav-item { .channel-nav-item {
@@ -335,33 +474,59 @@ export default {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box; box-sizing: border-box;
/* #ifdef MP-WEIXIN */
&.row1-of1 {
width: 100%;
}
&.row1-of2 {
width: calc(50% - 8rpx);
}
&.row1-of3 {
width: calc(33.333% - 10.67rpx);
}
&.row1-of4 {
width: calc(25% - 12rpx);
}
/* #endif */
} }
// 1 列布局 // 1 列布局
&.row1-of1 { &.row1-of1 {
.uni-scroll-view-content { .uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: 1fr; grid-template-columns: 1fr;
// #endif
} }
} }
// 2 列布局 // 2 列布局
&.row1-of2 { &.row1-of2 {
.uni-scroll-view-content { .uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
// #endif
} }
} }
// 3 列布局 // 3 列布局
&.row1-of3 { &.row1-of3 {
.uni-scroll-view-content { .uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
// #endif
} }
} }
// 4 列布局 // 4 列布局
&.row1-of4 { &.row1-of4 {
.uni-scroll-view-content { .uni-scroll-view-content {
// #ifndef MP-WEIXIN
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
// #endif
} }
} }
} }
@@ -387,7 +552,6 @@ export default {
display: grid; display: grid;
grid-template-columns: repeat(var(--row-count, 2), 1fr); grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 16rpx; gap: 16rpx;
padding: 16rpx;
box-sizing: border-box; box-sizing: border-box;
.channel-item { .channel-item {
@@ -453,13 +617,13 @@ export default {
// // 3:4 比例的视频卡片样式 // // 3:4 比例的视频卡片样式
// .channel-video.ratio-3-4 { // .channel-video.ratio-3-4 {
// // 调整视频卡片的整体高度 // // 调整视频卡片的整体高度
// /deep/ .video-cover-wrap { // ::v-deep .video-cover-wrap {
// padding-top: 133.33%; // 3:4 比例 // padding-top: 133.33%; // 3:4 比例
// } // }
// // 列表模式下的3:4比例调整 // // 列表模式下的3:4比例调整
// &.list-mode { // &.list-mode {
// /deep/ .video-cover-wrap { // ::v-deep .video-cover-wrap {
// padding-top: 133.33%; // 3:4 比例 // padding-top: 133.33%; // 3:4 比例
// } // }
// } // }
@@ -468,13 +632,13 @@ export default {
// // 16:9 比例的视频卡片样式(默认) // // 16:9 比例的视频卡片样式(默认)
// .channel-video.ratio-16-9 { // .channel-video.ratio-16-9 {
// // 保持默认的16:9比例 // // 保持默认的16:9比例
// /deep/ .video-cover-wrap { // ::v-deep .video-cover-wrap {
// padding-top: 56.25%; // 16:9 比例 // padding-top: 56.25%; // 16:9 比例
// } // }
// // 列表模式下的16:9比例保持默认 // // 列表模式下的16:9比例保持默认
// &.list-mode { // &.list-mode {
// /deep/ .video-cover-wrap { // ::v-deep .video-cover-wrap {
// padding-top: 56.25%; // 16:9 比例 // padding-top: 56.25%; // 16:9 比例
// } // }
// } // }

View File

@@ -17,7 +17,7 @@
<view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }} <view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }}
</view> </view>
<!-- 视频统计信息 --> <!-- 视频统计信息 -->
<view class="video-stats" v-if="value.showViewCount">{{ value.viewCount }}次观看</view> <view class="video-stats" v-if="showViewCount && value.showViewCount">{{ value.viewCount }}次观看</view>
</view> </view>
</view> </view>
@@ -28,7 +28,7 @@
<view class="channel-play-btn" v-if="showPlayBtn" :style="[playBtnStyle]"> <view class="channel-play-btn" v-if="showPlayBtn" :style="[playBtnStyle]">
<view class="play-icon-css"></view> <view class="play-icon-css"></view>
</view> </view>
<view class="video-stats-overlay" v-if="value.showViewCount"> <view class="video-stats-overlay" v-if="showViewCount && value.showViewCount">
{{ value.viewCount }}次观看 {{ value.viewCount }}次观看
</view> </view>
</view> </view>
@@ -37,7 +37,7 @@
<view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }} <view class="video-title" :style="{ '--title-line-clamp': titleLineClamp }">{{ value.videoTitle }}
</view> </view>
<!-- 视频统计信息非列表模式下显示 --> <!-- 视频统计信息非列表模式下显示 -->
<view class="video-stats" v-if="value.showViewCount && !listMode">{{ value.viewCount }}次观看</view> <view class="video-stats" v-if="showViewCount && value.showViewCount && !listMode">{{ value.viewCount }}次观看</view>
</view> </view>
</view> </view>
</view> </view>
@@ -80,6 +80,11 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
/** 是否显示观看次数,由父组件可以整体配置 */
showViewCount: {
type: Boolean,
default: true
},
/** /**
* 标题显示行数 * 标题显示行数
* @type {number} * @type {number}

View File

@@ -488,7 +488,7 @@ export default {
} }
// 风格一 // 风格一
/deep/.coupon-style-one { ::v-deep .coupon-style-one {
height: 110rpx; height: 110rpx;
.coupon-item-box { .coupon-item-box {
@@ -534,7 +534,7 @@ export default {
} }
// 风格二 // 风格二
/deep/.coupon-style-two { ::v-deep .coupon-style-two {
height: 96rpx; height: 96rpx;
.coupon-item-box { .coupon-item-box {
@@ -591,7 +591,7 @@ export default {
background-size: 100% 100%; background-size: 100% 100%;
} }
/deep/.coupon-style-three { ::v-deep .coupon-style-three {
height: 284rpx; height: 284rpx;
padding: 20rpx; padding: 20rpx;
box-sizing: border-box; box-sizing: border-box;
@@ -638,7 +638,7 @@ export default {
} }
// 风格四 // 风格四
/deep/.coupon-style-four { ::v-deep .coupon-style-four {
height: 108rpx; height: 108rpx;
.coupon-item-box { .coupon-item-box {
@@ -997,7 +997,7 @@ export default {
} }
//风格七 //风格七
/deep/ .coupon-style-seven { ::v-deep .coupon-style-seven {
.wrap { .wrap {
display: flex; display: flex;
} }
@@ -1075,7 +1075,7 @@ export default {
} }
} }
/deep/.uni-scroll-view ::-webkit-scrollbar { ::v-deep .uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
width: 0; width: 0;
@@ -1084,7 +1084,7 @@ export default {
background: transparent; background: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -274,7 +274,7 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar { ::v-deep .uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
width: 0; width: 0;
@@ -283,7 +283,7 @@ export default {
background: transparent; background: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -280,39 +280,39 @@ export default {
} }
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
/deep/.uni-scroll-view::-webkit-scrollbar { ::v-deep .uni-scroll-view::-webkit-scrollbar {
display: none; display: none;
} }
.swiper /deep/ .uni-swiper-dots-horizontal { .swiper ::v-deep .uni-swiper-dots-horizontal {
bottom: 25rpx; bottom: 25rpx;
} }
.swiper-left /deep/ .uni-swiper-dots-horizontal { .swiper-left ::v-deep .uni-swiper-dots-horizontal {
left: 40rpx; left: 40rpx;
transform: translate(0); transform: translate(0);
} }
.swiper-right /deep/ .uni-swiper-dots-horizontal { .swiper-right ::v-deep .uni-swiper-dots-horizontal {
right: 40rpx; right: 40rpx;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
transform: translate(0); transform: translate(0);
} }
.carousel-angle /deep/ .uni-swiper-dots-horizontal .uni-swiper-dot { .carousel-angle ::v-deep .uni-swiper-dots-horizontal .uni-swiper-dot {
width: 24rpx; width: 24rpx;
border-radius: 0; border-radius: 0;
height: 8rpx; height: 8rpx;
} }
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot { .swiper.ns-indicator-dots ::v-deep .uni-swiper-dot {
width: 18rpx; width: 18rpx;
height: 6rpx; height: 6rpx;
border-radius: 4rpx; border-radius: 4rpx;
} }
.swiper.ns-indicator-dots /deep/ .uni-swiper-dot-active { .swiper.ns-indicator-dots ::v-deep .uni-swiper-dot-active {
width: 36rpx; width: 36rpx;
} }
</style> </style>

View File

@@ -732,7 +732,7 @@ export default {
margin-top: 100rpx; margin-top: 100rpx;
} }
/deep/.uni-scroll-view::-webkit-scrollbar { ::v-deep .uni-scroll-view::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
} }

View File

@@ -1,6 +1,6 @@
<template> <template>
<view data-component-name="diy-kefu" class="diy-kefu" :style="style"> <view data-component-name="diy-kefu" class="diy-kefu" :style="style">
<view class="fui-list-group merchgroup" v-for="(item, index) in value.list"> <view class="fui-list-group merchgroup" v-for="(item, index) in value.list" :key="index">
<view class="fui-list jump" v-if="index == 0"> <view class="fui-list jump" v-if="index == 0">
<view class="fui-list-media"> <view class="fui-list-media">
<image class="round" :src="$util.img(item.imageUrl)" style="border-radius:6rpx"></image> <image class="round" :src="$util.img(item.imageUrl)" style="border-radius:6rpx"></image>

View File

@@ -3,11 +3,18 @@
<view class="fui-list-group merchgroup" style="margin-top:0" v-for="(item, index) in value.list"> <view class="fui-list-group merchgroup" style="margin-top:0" v-for="(item, index) in value.list">
<map id="map" style="width: 100%; height:600rpx" scale="12" :markers="markerst" bindupdated="bindupdated" <map id="map" style="width: 100%; height:600rpx" scale="12" :markers="markerst" bindupdated="bindupdated"
:longitude="item.lng" :latitude="item.lat" show-location> :longitude="item.lng" :latitude="item.lat" show-location>
<cover-view <!-- <cover-view
style="position:absolute;right:10px;bottom:30rpx;z-index:99999;background:#4390FF;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;" style="position:absolute;right:10px;bottom:30rpx;z-index:99999;background:#4390FF;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;"
@click="handlerClick(item)" @tap="handlerClick(item)"> @click="handlerClick(item)" @tap="handlerClick(item)">
<cover-view style="font-size:24rpx">一键导航</cover-view> <cover-view style="font-size:24rpx">一键导航</cover-view>
</cover-view> </cover-view> -->
<!-- 使用非原生cover-view, 解决原生cover-view组件渲染机制z-index失效的问题 -->
<div
style="position:absolute;right:12rpx;bottom:48rpx;z-index:1;background:#4390FF;padding:0rpx 20rpx;border-radius:8rpx;color: #fff;"
@click="handlerClick(item)">
<span style="font-size:24rpx;color: #fff;">一键导航</span>
</div>
</map> </map>
</view> </view>

View File

@@ -1380,11 +1380,11 @@ export default {
} }
} }
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: none !important; background: none !important;
} }
/deep/ .member-info-style4 .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .member-info-style4 .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: #fff !important; background: #fff !important;
} }
@@ -1484,8 +1484,8 @@ export default {
} }
</style> </style>
<style scoped> <style scoped>
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom, .member-complete-info-popup ::v-deep .uni-popup__wrapper.bottom,
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom .uni-popup__wrapper-box { .member-complete-info-popup ::v-deep .uni-popup__wrapper.bottom .uni-popup__wrapper-box {
border-top-left-radius: 30rpx !important; border-top-left-radius: 30rpx !important;
border-top-right-radius: 30rpx !important; border-top-right-radius: 30rpx !important;
} }

View File

@@ -319,7 +319,7 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar { ::v-deep .uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
width: 0; width: 0;
@@ -328,7 +328,7 @@ export default {
background: transparent; background: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -391,7 +391,7 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar { ::v-deep .uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
width: 0; width: 0;
@@ -400,7 +400,7 @@ export default {
background: transparent; background: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -276,7 +276,7 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/.uni-scroll-view ::-webkit-scrollbar { ::v-deep .uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
width: 0; width: 0;
@@ -285,7 +285,7 @@ export default {
background: transparent; background: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -257,7 +257,7 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/ .uni-input-placeholder { ::v-deep .uni-input-placeholder {
overflow: initial; overflow: initial;
} }

View File

@@ -536,7 +536,7 @@ scroll-view ::-webkit-scrollbar {
touch-action: none; touch-action: none;
} }
/deep/.uni-scroll-view ::-webkit-scrollbar { ::v-deep .uni-scroll-view ::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
width: 0; width: 0;
@@ -545,7 +545,7 @@ scroll-view ::-webkit-scrollbar {
background: transparent; background: transparent;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;

View File

@@ -140,7 +140,7 @@ export default {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
/deep/ .uni-scroll-view-content { ::v-deep .uni-scroll-view-content {
display: flex; display: flex;
align-items: center; align-items: center;
} }
@@ -148,7 +148,7 @@ export default {
&.between { &.between {
justify-content: space-between; justify-content: space-between;
/deep/.uni-scroll-view-content { ::v-deep .uni-scroll-view-content {
justify-content: space-between; justify-content: space-between;
} }
} }

View File

@@ -1,6 +0,0 @@
{
"component": true,
"usingComponents": {
"ns-loading": "../ns-loading/ns-loading"
}
}

View File

@@ -156,11 +156,11 @@
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background-color: #000; background-color: #000;
} }
/deep/.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
max-width: 100%; max-width: 100%;
width: 100%; width: 100%;
} }

View File

@@ -1,243 +1,249 @@
<template> <template>
<!-- 悬浮按钮 --> <!-- 悬浮按钮 -->
<view v-if="pageCount == 1 || need" class="fixed-box" <view v-if="pageCount == 1 || need" class="fixed-box" :style="[customContainerStyle, {
:style="[{ height: fixBtnShow ? '400rpx' : '320rpx' }, customContainerStyle]"> height: fixBtnShow ? '400rpx' : '320rpx',
<!-- <view class="btn-item" v-if="fixBtnShow" @click="$util.redirectTo('/pages/index/index')"> --> backgroundImage: bgUrl ? `url(${bgUrl})` : '',
<!-- 切换语言按钮 --> backgroundSize: 'cover'
<button class="btn-item" v-if="fixBtnShow && isLanguageSwitchEnabled" @click="toggleLanguage()" }]">
:style="[{ backgroundSize: '100% 100%' }, customButtonStyle]">
<text :style="customTextStyle">{{ currentLangDisplayName }}</text>
</button>
<!-- 客服按钮 -->
<!-- #ifdef MP-WEIXIN -->
<button class="btn-item" v-if="fixBtnShow" hoverClass="none" openType="contact" sessionFrom="weapp"
showMessageCard="true"
:style="[{ backgroundImage: 'url(' + (kefuimg ? kefuimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="icox icox-kefu" v-if="!kefuimg"></text>
<!-- <view>首页</view> -->
</button>
<!-- #endif -->
<view class="btn-item" v-if="fixBtnShow" @click="call()"
:style="[{ backgroundImage: 'url(' + (phoneimg ? phoneimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
<!-- <view>我的</view> -->
</view>
<!-- <view class="btn-item icon-xiala" v-if="fixBtnShow" @click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)"> <!-- 中英文切换按钮 -->
<text class="iconfont icon-unfold"></text> <view v-if="isLanguageSwitchEnabled && fixBtnShow" class="btn-item common-bg" @click="toggleLanguage">
</view> <text>{{ currentLangDisplayName }}</text>
<view class="btn-item switch" v-else :class="{ show: fixBtnShow }" </view>
@click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
<view class="">快捷</view> <!-- AI 智能助手 -->
<view>导航</view> <view v-if="fixBtnShow && enableAIChat" class="btn-item common-bg" @click="openAIChat"
</view> --> :style="{ backgroundImage: aiAgentimg ? `url(${aiAgentimg})` : '', backgroundSize: '100% 100%' }">
</view> <text class="ai-icon" v-if="!aiAgentimg">🤖</text>
</view>
<!-- 微信小程序客服按钮 -->
<!-- #ifdef MP-WEIXIN -->
<button class="btn-item common-bg" hoverClass="none" openType="contact" sessionFrom="weapp" showMessageCard="true"
:style="[{ backgroundImage: kefuimg ? `url(${kefuimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="icox icox-kefu" v-if="!kefuimg"></text>
</button>
<!-- #endif -->
<!-- 普通客服仅当未启用 AI 时显示 -->
<!-- #ifdef H5 -->
<template v-if="fixBtnShow">
<button class="btn-item common-bg" hoverClass="none" @click="openCustomerSelectPopup"
:style="[{ backgroundImage: kefuimg ? `url(${kefuimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="icox icox-kefu" v-if="!kefuimg"></text>
</button>
</template>
<!-- #endif -->
<!-- 电话按钮始终显示 -->
<view v-if="fixBtnShow" class="btn-item common-bg" @click="call()"
:style="[{ backgroundImage: phoneimg ? `url(${phoneimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
</view>
</view>
</template> </template>
<script> <script>
import { createCustomerService } from '@/common/js/customer-service.js';
export default { export default {
name: 'hover-nav', name: 'hover-nav',
props: { props: {
need: { need: { type: Boolean, default: false }
type: Boolean, },
default: false data() {
} return {
}, pageCount: 0,
data() { fixBtnShow: true,
return {
pageCount: 0,
fixBtnShow: true,
tel: '',
kefuimg: '',
phoneimg: '',
shopInfo: null, // 店铺信息对象
// --- 语言切换相关 --- shopInfo: null,
currentLangIndex: 0, // 当前选中的语言索引 currentLangIndex: 0,
langIndexMap: {}, // 语言索引到语言值的映射 langIndexMap: {},
isLanguageSwitchEnabled: false, // 是否启用语言切换
// --- 其他 --- customerService: null,
}; };
}, },
created() { computed: {
// 初始化语言设置 // 安全读取 shopInfo 中的字段,避免 undefined 报错
this.initLanguage(); bgUrl() {
return this.shopInfo?.bgUrl || '';
},
aiAgentimg() {
return this.shopInfo?.aiAgentimg || '';
},
kefuimg() {
return this.shopInfo?.kefuimg || this.$util.getDefaultImage().kefu;
},
phoneimg() {
return this.shopInfo?.phoneimg || this.$util.getDefaultImage().phone;
},
tel() {
return this.shopInfo?.mobile || '';
},
isLanguageSwitchEnabled() {
return !!this.shopInfo?.ischina;
},
enableAIChat() {
return !!this.shopInfo?.enableAIChat;
},
currentLangDisplayName() {
const lang = this.langIndexMap[this.currentLangIndex];
return lang === 'zh-cn' ? 'EN' : 'CN';
},
customContainerStyle() {
return this.shopInfo?.floatingButton?.container || {};
},
customButtonStyle() {
return this.shopInfo?.floatingButton?.button || {};
}
},
created() {
this.customerService = createCustomerService(this);
this.initLanguage();
uni.getStorage({
key: 'shopInfo',
success: (e) => {
this.shopInfo = e.data;
}
});
},
methods: {
this.kefuimg = this.$util.getDefaultImage().kefu /**
this.phoneimg = this.$util.getDefaultImage().phone * 初始化多语言配置
this.pageCount = getCurrentPages().length; */
initLanguage() {
this.langList = this.$langConfig.list();
this.langIndexMap = {};
for (let i = 0; i < this.langList.length; i++) {
this.langIndexMap[i] = this.langList[i].value;
}
const savedLang = uni.getStorageSync('lang');
if (savedLang) {
for (let i = 0; i < this.langList.length; i++) {
if (this.langList[i].value === savedLang) {
this.currentLangIndex = i;
break;
}
}
} else {
this.currentLangIndex = 0;
}
},
// 从店铺信息中获取相关信息 /**
uni.getStorage({ * 电话联系客服
key: 'shopInfo', */
success: (e) => { call() {
console.log(`获取到的shopInfo:${JSON.stringify(e.data)}`) this.customerService.makePhoneCall(this.tel);
this.shopInfo = e.data; },
// 从店铺信息中获取手机号 /**
this.tel = e.data.mobile * 切换中英文语言,并刷新当前页面(保留所有参数)
// 从店铺信息中获取是否启用语言切换 */
this.isLanguageSwitchEnabled = e.data.ischina; toggleLanguage() {
} this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
}) const targetLang = this.langIndexMap[this.currentLangIndex];
},
computed: {
currentLangDisplayName() {
// 语言切换按钮显示名称当前语言为中文时显示EN否则显示CN
// 根据 langIndexMap 获取当前语言值
const lang = this.langIndexMap[this.currentLangIndex];
return lang == 'zh-cn' ? 'EN' : 'CN';
},
// 获取容器的自定义样式 // 调用语言切换逻辑(设置 storage + 清空缓存)
customContainerStyle() { this.$langConfig.change(targetLang);
// 只返回非空的样式属性,确保不覆盖原有的默认样式 },
return this.shopInfo?.floatingButton?.container || {};
},
// 获取按钮的自定义样式 /**
customButtonStyle() { * 打开 AI 智能助手
// 只返回非空的样式属性,确保不覆盖原有的默认样式 */
return this.shopInfo?.floatingButton?.button || {}; openAIChat() {
}, this.$util.redirectTo(this.$util.AI_CHAT_PAGE_URL);
},
// 获取文本的自定义样式 /**
customTextStyle() { * 打开客服选择对话框
// 只返回非空的样式属性,确保不覆盖原有的默认样式 */
return this.shopInfo?.floatingButton?.text || {}; openCustomerSelectPopup() {
} this.customerService.openCustomerSelectPopupDialog();
}, }
methods: { }
initLanguage() { }
// 初始化语言列表
this.langList = this.$langConfig.list();
// 初始化语言索引映射
for (let i = 0; i < this.langList.length; i++) {
this.langIndexMap[i] = this.langList[i].value;
}
// 获取存储的语言设置
const savedLang = uni.getStorageSync('lang');
if (savedLang) {
for (let i = 0; i < this.langList.length; i++) {
if (this.langList[i].value == savedLang) {
this.currentLangIndex = i;
break;
}
}
} else {
this.currentLangIndex = 0;
}
},
//拨打电话
call() {
uni.makePhoneCall({
phoneNumber: this.tel + ''
})
},
toggleLanguage() {
// 切换语言索引
this.currentLangIndex = this.currentLangIndex == 0 ? 1 : 0;
const targetLang = this.langIndexMap[this.currentLangIndex];
// 获取当前页面路由
let currentRoute = this.$util.getCurrentRoute().path;
// 切换语言并重新加载当前页面
this.$langConfig.change(targetLang, currentRoute);
}
}
};
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.container-box { .fixed-box {
width: 100%; position: fixed;
right: 0rpx;
.item-wrap { bottom: 240rpx;
border-radius: 10rpx; /* #ifdef H5 */
bottom: 320rpx;
.image-box { /* #endif */
border-radius: 10rpx; z-index: 10;
} border-radius: 120rpx;
padding: 20rpx 0;
image { display: flex;
width: 100%; justify-content: center;
height: auto; flex-direction: column;
border-radius: 10rpx; width: 100rpx;
will-change: transform; box-sizing: border-box;
} transition: 0.3s;
} overflow: hidden;
} }
//悬浮按钮 .btn-item {
.fixed-box { display: flex;
position: fixed; justify-content: center;
right: 0rpx; text-align: center;
bottom: 240rpx; flex-direction: column;
// #ifdef H5 line-height: 1;
bottom: 320rpx; margin: 14rpx 0;
// #endif transition: 0.1s;
z-index: 10; color: var(--hover-nav-text-color);
border-radius: 120rpx; border-radius: 40rpx;
padding: 20rpx 0; width: 80rpx;
display: flex; height: 80rpx;
justify-content: center; padding: 0;
flex-direction: column; overflow: hidden;
width: 100rpx; }
box-sizing: border-box;
transition: 0.3s;
overflow: hidden;
.btn-item { /* 定义共同的背景颜色 */
display: flex; .common-bg {
justify-content: center; background-color: var(--hover-nav-bg-color);
text-align: center; /* 使用变量以保持一致性 */
flex-direction: column; }
line-height: 1;
margin: 14rpx 0;
transition: 0.1s;
background: var(--hover-nav-bg-color);
color: var(--hover-nav-text-color);
border-radius: 40rpx;
width: 80rpx;
height: 80rpx;
padding: 0;
overflow: hidden;
text { .btn-item text {
font-size: 28rpx; font-size: 28rpx;
} }
.iconfont,
.icox {
font-size: 36rpx;
font-weight: bold;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 40rpx;
/* 确保图标本身也是圆形 */
}
view { .iconfont,
font-size: 26rpx; .icox {
font-weight: bold; font-size: 36rpx;
} font-weight: bold;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
margin: 14rpx 0;
border-radius: 50rpx;
width: 80rpx;
height: 80rpx;
padding: 0;
position: relative;
}
&.show { .iconfont text,
transform: rotate(180deg); .icox text {
} font-size: 36rpx;
font-weight: bold;
}
&.switch {}
&.icon-xiala {
margin: 0; .ai-icon {
margin-top: 0.1rpx; font-size: 40rpx;
} width: 100%;
} height: 100%;
display: flex;
align-items: center;
justify-content: center;
} }
</style> </style>

View File

@@ -3,28 +3,37 @@
<slot></slot> <slot></slot>
<!-- #ifdef MP-ALIPAY --> <!-- #ifdef MP-ALIPAY -->
<view class="contact-button" @click="contactServicer"> <view class="contact-button" @click="contactServicer">
<contact-button :tnt-inst-id="config.instid" :scene="config.scene" size="1000rpx" v-if="config.type == 'aliapp'"/> <contact-button :tnt-inst-id="config.instid" :scene="config.scene" size="1000rpx"
v-if="config.type == 'aliapp'" />
</view> </view>
<!-- #endif --> <!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<button <!-- #ifdef MP-WEIXIN -->
type="default" <!-- 微信小程序官方客服按钮 -->
hover-class="none" <button v-if="useOfficialService" type="default" hover-class="none" open-type="contact"
:open-type="openType" class="contact-button" sessionFrom="weapp" showMessageCard="true"
class="contact-button" :send-message-title="sendMessageTitle" :send-message-path="sendMessagePath"
@click="contactServicer" :send-message-img="sendMessageImg"></button>
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath" <!-- 微信小程序自定义客服按钮 -->
:send-message-img="sendMessageImg" <button v-else type="default" hover-class="none" class="contact-button" @click="contactServicer"></button>
:show-message-card="true"></button>
<!-- #endif --> <!-- #endif -->
<!-- #ifndef MP-WEIXIN && MP-ALIPAY -->
<!-- 其他平台保持原逻辑 -->
<button type="default" hover-class="none" :open-type="openType" class="contact-button" @click="contactServicer"
:send-message-title="sendMessageTitle" :send-message-path="sendMessagePath"
:send-message-img="sendMessageImg" :show-message-card="true"></button>
<!-- #endif -->
<uni-popup ref="servicePopup" type="center"> <uni-popup ref="servicePopup" type="center">
<view class="service-popup-wrap"> <view class="service-popup-wrap">
<view class="head-wrap" @click="$refs.servicePopup.close()"> <view class="head-wrap" @click="$refs.servicePopup.close()">
<text>联系客服</text> <text>联系客服</text>
<text class="iconfont icon-close"></text> <text class="iconfont icon-close"></text>
</view> </view>
<view class="body-wrap">{{ siteInfo.site_tel ? '请联系客服,客服电话是' + siteInfo.site_tel : '抱歉,商家暂无客服,请线下联系' }}</view> <view class="body-wrap">{{ siteInfo.site_tel ? '请联系客服,客服电话是' + siteInfo.site_tel : '抱歉,商家暂无客服,请线下联系' }}
</view>
</view> </view>
</uni-popup> </uni-popup>
</view> </view>
@@ -32,140 +41,130 @@
<!-- 客服组件 --> <!-- 客服组件 -->
<script> <script>
export default { import { createCustomerService } from '@/common/js/customer-service.js';
name: 'ns-contact',
props: { export default {
niushop: { name: 'ns-contact',
type: Object, props: {
default: function() { niushop: {
return {}; type: Object,
} default: function () {
}, return {};
sendMessageTitle: {
type: String,
default: ''
},
sendMessagePath: {
type: String,
default: ''
},
sendMessageImg: {
type: String,
default: ''
} }
}, },
data() { sendMessageTitle: {
return { type: String,
config: null, default: ''
openType: ''
};
}, },
created() { sendMessagePath: {
if (this.servicerConfig) { type: String,
// #ifdef H5 default: ''
this.config = this.servicerConfig.h5;
// #endif
// #ifdef MP-WEIXIN
this.config = this.servicerConfig.weapp;
if (this.config.type == 'weapp') this.openType = 'contact';
// #endif
// #ifdef MP-ALIPAY
this.config = this.servicerConfig.aliapp;
if (this.config.type == 'aliapp') this.openType = 'contact';
// #endif
}
}, },
methods: { sendMessageImg: {
/** type: String,
* 联系客服 default: ''
*/
contactServicer() {
if (this.config.type == 'none') {
this.$refs.servicePopup.open();
}
if (this.openType == 'contact') return;
switch (this.config.type) {
case 'wxwork':
// #ifdef H5
location.href = this.config.wxwork_url;
// #endif
// #ifdef MP-WEIXIN
wx.openCustomerServiceChat({
extInfo: { url: this.config.wxwork_url },
corpId: this.config.corpid,
showMessageCard: true,
sendMessageTitle: this.sendMessageTitle,
sendMessagePath: this.sendMessagePath,
sendMessageImg: this.sendMessageImg
});
// #endif
break;
case 'third':
location.href = this.config.third_url;
break;
case 'niushop':
this.$util.redirectTo('/pages_tool/chat/room', this.niushop);
break;
default:
this.makePhoneCall();
}
},
/**
* 店铺联系方式
*/
makePhoneCall() {
this.$api.sendRequest({
url: '/api/site/shopcontact',
success: res => {
if (res.code == 0 && res.data.mobile) uni.makePhoneCall({
phoneNumber: res.data
.mobile
});
}
});
}
} }
}; },
data() {
return {
customerService: null,
buttonConfig: null
};
},
computed: {
/**
* 是否使用官方客服
*/
useOfficialService() {
if (!this.buttonConfig) return true;
// #ifdef MP-WEIXIN
// 如果是微信小程序,检查配置
if (this.buttonConfig.type === 'weapp') {
// 默认使用官方客服除非明确设置为false
return this.buttonConfig.useOfficial !== false;
}
// #endif
return false;
},
/**
* 客服配置
*/
config() {
return this.customerService?.getPlatformConfig() || {};
},
/**
* 打开类型
*/
openType() {
return this.buttonConfig?.openType || '';
}
},
created() {
// 初始化客服服务
this.customerService = createCustomerService(this);
this.buttonConfig = this.customerService.getButtonConfig();
},
methods: {
/**
* 联系客服
*/
contactServicer() {
// 如果是微信/支付宝小程序客服,由系统自动处理
if (this.buttonConfig.openType === 'contact') {
return;
}
// 使用统一客服处理
this.customerService.handleCustomerClick({
niushop: this.niushop,
sendMessageTitle: this.sendMessageTitle,
sendMessagePath: this.sendMessagePath,
sendMessageImg: this.sendMessageImg
});
}
}
};
</script> </script>
<style lang="scss"> <style lang="scss">
.contact-wrap { .contact-wrap {
width: 100%;
height: 100%;
position: relative;
.contact-button {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: relative; position: absolute;
left: 0;
top: 0;
z-index: 5;
padding: 0;
margin: 0;
opacity: 0;
overflow: hidden;
}
}
.contact-button { .service-popup-wrap {
width: 100%; width: 600rpx;
height: 100%;
position: absolute; .head-wrap {
left: 0; display: flex;
top: 0; justify-content: space-between;
z-index: 5; align-items: center;
padding: 0; padding: 0 30rpx;
margin: 0; height: 90rpx;
opacity: 0;
overflow: hidden;
}
} }
.service-popup-wrap { .body-wrap {
width: 600rpx; text-align: center;
padding: 30rpx;
.head-wrap { height: 100rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
height: 90rpx;
}
.body-wrap {
text-align: center;
padding: 30rpx;
height: 100rpx;
}
} }
}
</style> </style>

View File

@@ -843,15 +843,15 @@ export default {
z-index: 5; z-index: 5;
} }
/deep/ .uni-popup__wrapper { ::v-deep .uni-popup__wrapper {
background: transparent !important; background: transparent !important;
} }
/deep/ .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: transparent !important; background: transparent !important;
} }
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: transparent !important; background: transparent !important;
} }
</style> </style>

View File

@@ -17,7 +17,7 @@
<style lang="scss"> <style lang="scss">
.mp-html{ .mp-html{
/deep/ img{ ::v-deep img{
width:100% !important; width:100% !important;
display:block; display:block;
} }

View File

@@ -146,7 +146,7 @@
}; };
</script> </script>
<style scoped> <style scoped>
.register-box /deep/ .uni-scroll-view { .register-box ::v-deep .uni-scroll-view {
background: unset !important; background: unset !important;
} }
@@ -155,11 +155,11 @@
overflow-y: scroll; overflow-y: scroll;
} }
.register-box /deep/.uni-popup__wrapper-box { .register-box ::v-deep .uni-popup__wrapper-box {
overflow: unset !important; overflow: unset !important;
} }
.reward-popup /deep/.uni-popup__wrapper { .reward-popup ::v-deep .uni-popup__wrapper {
background: none; background: none;
} }
</style> </style>

View File

@@ -27,7 +27,7 @@ export default {
<style> <style>
/* 回到顶部的按钮 */ /* 回到顶部的按钮 */
.mescroll-totop { .mescroll-totop {
z-index: 99; z-index: 2147483647;
position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */ position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */
right: 46rpx !important; right: 46rpx !important;
bottom: 272rpx !important; bottom: 272rpx !important;

View File

@@ -0,0 +1,834 @@
# 组件使用情况文档
提示词:请重新帮我分析 components 及 uni_modules 目录下的组件,被哪些页面/组件使用按照Vue组件精确引用次数由多到少来排序并更新到该文档中。
## 1. 组件目录结构
### 1.1 components 目录包含以下组件:
- chat-message
- hover-nav
- l-time
- loading-cover
- mescroll
- ns-adv
- ns-chat
- ns-contact
- ns-copyright
- ns-empty
- ns-form
- ns-goods-action
- ns-goods-action-button
- ns-goods-action-icon
- ns-goods-recommend
- ns-goods-sku
- ns-loading
- ns-login
- ns-mp-html
- ns-navbar
- ns-payment
- ns-progress
- ns-select-time
- ns-switch
- ns-video-player-popup
- payment
- pick-regions
- privacy-popup
- register-reward
- sx-rate
- to-top
- uv-count-to
- wxwork-contact
- xiao-star-component
- yuyue-date
### 1.2 uni_modules 目录包含以下组件:
- mp-html
- uni-badge
- uni-calendar
- uni-count-down
- uni-datetime-picker
- uni-drawer
- uni-grid
- uni-grid-item
- uni-icons
- uni-nav-bar
- uni-number-box
- uni-popup
- uni-popup-sku
- uni-popup-sku-category
- uni-scss
- uni-status-bar
- uni-tag
- x-skeleton
## 2. 组件使用情况详细列表(按引用次数排序)
### 2.1 loading-cover 组件78次引用
**文件路径**components/loading-cover/loading-cover.vue
**引用情况**
- pages_tool/form/formdata.vue
- pages_goods/detail.vue
- pages_order/_components/common-payment/common-payment.vue
- pages_tool/recharge/order_list.vue
- pages_tool/recharge/list.vue
- pages_tool/pay/index.vue
- pages_tool/pay/result.vue
- pages_tool/order/refund_type_select.vue
- pages_tool/order/refund_goods_select.vue
- pages_tool/order/refund_detail.vue
- pages_tool/order/detail_virtual.vue
- pages_tool/order/evaluate.vue
- pages_tool/order/logistics.vue
- pages_tool/order/refund.vue
- pages_tool/order/refund_batch.vue
- pages_tool/member/withdrawal.vue
- pages_tool/member/withdrawal_detail.vue
- pages_tool/notice/detail.vue
- pages_tool/notice/list.vue
- pages_tool/member/point.vue
- pages_tool/member/point_detail.vue
- pages_tool/member/invite_friends.vue
- pages_tool/member/level.vue
- pages_tool/member/level_growth_rules.vue
- pages_tool/member/coupon.vue
- pages_tool/member/footprint.vue
- pages_tool/member/card_buy.vue
- pages_tool/member/collection.vue
- pages_tool/member/balance.vue
- pages_tool/member/balance_detail.vue
- pages_tool/member/account.vue
- pages_tool/member/account_edit.vue
- pages_tool/member/address.vue
- pages_tool/member/address_edit.vue
- pages_tool/member/apply_withdrawal.vue
- pages_tool/login/login.vue
- pages_tool/help/detail.vue
- pages_tool/help/list.vue
- pages_tool/goods/coupon.vue
- pages_tool/goods/coupon_receive.vue
- pages_tool/goods/evaluate.vue
- pages_tool/files/list.vue
- pages_tool/form/form.vue
- pages_tool/goods/brand.vue
- pages_tool/article/detail.vue
- pages_tool/article/list.vue
- pages_promotion/point/list.vue
- pages_promotion/point/order_list.vue
- pages_promotion/point/payment.vue
- pages_promotion/point/detail.vue
- pages_promotion/merch/merchcategory.vue
- pages_promotion/merch/detail.vue
- pages_promotion/fenxiao/withdrawal_detail.vue
- pages_promotion/fenxiao/withdraw_list.vue
- pages_promotion/fenxiao/withdraw_apply.vue
- pages_promotion/fenxiao/ranking_list.vue
- pages_promotion/fenxiao/relation.vue
- pages_promotion/fenxiao/team.vue
- pages_promotion/fenxiao/order.vue
- pages_promotion/fenxiao/order_detail.vue
- pages_promotion/fenxiao/promote.vue
- pages_promotion/fenxiao/promote_code.vue
- pages_promotion/fenxiao/index.vue
- pages_promotion/fenxiao/level.vue
- pages_promotion/fenxiao/goods_list.vue
- pages_promotion/fenxiao/apply.vue
- pages_promotion/fenxiao/bill.vue
- pages_promotion/fenxiao/child_fenxiao.vue
- pages_order/detail_point.vue
- pages_order/list.vue
- pages_order/detail.vue
- pages_order/detail_local_delivery.vue
- pages_order/detail_pickup.vue
- pages_goods/list.vue
- pages_goods/cart.vue
- pages_goods/category.vue
- components-diy/diy-category-item.vue
### 2.2 uni-popup 组件66次引用
**文件路径**uni_modules/uni-popup/components/uni-popup/uni-popup.vue
**引用情况**
- pages_goods/_components/goods-detail-view/goods-detail-view.vue
- pages_tool/member/index.vue
- pages_goods/detail.vue
- pages_order/payment.vue
- pages_order/_components/common-payment/common-payment.vue
- pages_tool/contact/contact.vue
- components/ns-contact/ns-contact.vue
- pages/index/index.vue
- components/ns-video-player-popup/ns-video-player-popup.vue
- pages/contact/contact.vue
- uni_modules/uni-popup-sku/components/uni-popup-sku/uni-popup-sku.vue
- uni_modules/uni-popup-sku-category/components/uni-popup-sku-category/uni-popup-sku-category.vue
- pages_tool/recharge/list.vue
- pages_tool/pay/result.vue
- pages_tool/order/refund_type_select.vue
- pages_tool/order/refund.vue
- pages_tool/order/refund_batch.vue
- pages_tool/member/invite_friends.vue
- pages_tool/member/level.vue
- pages_tool/member/card_buy.vue
- pages_tool/member/collection.vue
- pages_tool/member/card.vue
- pages_tool/login/login.vue
- pages_tool/index/diy.vue
- pages_tool/cases/index.vue
- pages_promotion/point/list.vue
- pages_promotion/point/payment.vue
- pages_promotion/merch/public/category.scss
- pages_promotion/point/detail.vue
- pages_promotion/merch/merchcategory.vue
- pages_promotion/merch/detail.vue
- pages_promotion/fenxiao/promote_code.vue
- pages_promotion/fenxiao/index.vue
- pages_promotion/fenxiao/level.vue
- pages_promotion/fenxiao/goods_list.vue
- pages_promotion/fenxiao/apply.vue
- pages_order/detail_point.vue
- pages_order/detail.vue
- pages_goods/list.vue
- pages_goods/public/css/cart.scss
- pages_goods/cart.vue
- pages_goods/category.vue
- components/yuyue-date/yuyue-date.vue
- components/register-reward/register-reward.vue
- components/pick-regions/pick-regions.vue
- components/ns-select-time/ns-select-time.vue
- components/payment/payment.vue
- components/ns-payment/ns-payment.vue
- components/ns-goods-sku/ns-goods-sku.vue
- components/ns-login/ns-login.vue
- pages_tool/_components/ns-new-gift/ns-new-gift.vue
- components/ns-goods-sku/ns-goods-sku-category.vue
- pages_tool/_components/ns-birthday-gift/ns-birthday-gift.vue
- components/chat-message/chat-message.vue
- components-diy/diy-video-list.vue
- components-diy/diy-payment-qrcode.vue
- components-diy/diy-notice.vue
- components-diy/diy-member-info.vue
- components-diy/diy-index-page.vue
- components-diy/diy-category.vue
- components-diy/diy-category-item.vue
### 2.3 mescroll 组件63次引用
**文件路径**components/mescroll/
**引用情况**
- pages_order/_components/common-payment/common-payment.vue
- pages_tool/contact/contact.vue
- lang/zh-cn/common.js
- lang/en-us/common.js
- pages.json
- pages/index/index.vue
- pages_tool/recharge/order_list.vue
- pages_tool/recharge/list.vue
- pages_tool/order/logistics.vue
- pages_tool/member/withdrawal.vue
- pages_tool/notice/list.vue
- pages_tool/order/activist.vue
- pages_tool/member/public/js/collection.js
- pages_tool/member/point_detail.vue
- pages_tool/member/coupon.vue
- pages_tool/member/footprint.vue
- pages_tool/member/collection.vue
- pages_tool/member/balance.vue
- pages_tool/member/balance_detail.vue
- pages_tool/member/account.vue
- pages_tool/member/address.vue
- pages_tool/goods/coupon.vue
- pages_tool/goods/evaluate.vue
- pages_tool/files/list.vue
- pages_tool/goods/brand.vue
- pages_tool/article/list.vue
- pages_promotion/point/goods_list.vue
- pages_promotion/point/list.vue
- pages_promotion/point/order_list.vue
- pages_promotion/merch/public/js/list.js
- pages_promotion/merch/detail.vue
- pages_promotion/fenxiao/withdraw_list.vue
- pages_promotion/fenxiao/ranking_list.vue
- pages_promotion/fenxiao/relation.vue
- pages_promotion/fenxiao/team.vue
- pages_promotion/fenxiao/public/js/goods_list.js
- pages_promotion/fenxiao/order.vue
- pages_promotion/fenxiao/goods_list.vue
- pages_promotion/fenxiao/bill.vue
- pages_promotion/fenxiao/child_fenxiao.vue
- pages_order/list.vue
- pages_goods/public/js/list.js
- pages_goods/list.vue
- components/to-top/to-top.vue
- components-diy/diy-index-page.vue
- components/ns-loading/ns-loading.vue
### 2.4 ns-login 组件53次引用
**文件路径**components/ns-login/ns-login.vue
**引用情况**
- pages_tool/form/formdata.vue
- pages_goods/detail.vue
- pages_order/_components/common-payment/common-payment.vue
- pages/index/index.vue
- pages_tool/recharge/order_list.vue
- pages_tool/pay/cashier.vue
- pages_tool/member/point.vue
- pages_tool/member/invite_friends.vue
- pages_tool/member/level.vue
- pages_tool/member/coupon.vue
- pages_tool/member/footprint.vue
- pages_tool/member/info.vue
- pages_tool/member/info_edit.vue
- pages_tool/member/card_buy.vue
- pages_tool/member/collection.vue
- pages_tool/member/card.vue
- pages_tool/member/balance.vue
- pages_tool/member/balance_detail.vue
- pages_tool/member/account.vue
- pages_tool/member/address.vue
- pages_tool/goods/coupon.vue
- pages_tool/goods/coupon_receive.vue
- pages_tool/form/form.vue
- pages_promotion/point/list.vue
- pages_promotion/point/order_list.vue
- pages_promotion/point/detail.vue
- pages_promotion/merch/merchcategory.vue
- pages_promotion/fenxiao/withdraw_list.vue
- pages_promotion/fenxiao/relation.vue
- pages_promotion/fenxiao/team.vue
- pages_promotion/fenxiao/order.vue
- pages_promotion/fenxiao/order_detail.vue
- pages_promotion/fenxiao/promote.vue
- pages_promotion/fenxiao/promote_code.vue
- pages_promotion/fenxiao/index.vue
- pages_promotion/fenxiao/child_fenxiao.vue
- pages_order/list.vue
- pages_goods/cart.vue
- pages_goods/category.vue
- components/ns-goods-sku/ns-goods-sku.vue
- components/ns-goods-sku/ns-goods-sku-index.vue
- components/ns-goods-sku/ns-goods-sku-category.vue
- pages_goods/_components/goods-detail-view/goods-detail-view.vue
- components-diy/diy-search.vue
- components-diy/diy-quick-nav.vue
- components-diy/diy-notes.vue
- components-diy/diy-member-info.vue
- components-diy/diy-member-my-order.vue
- components-diy/diy-image-nav.vue
- components-diy/diy-graphic-nav.vue
- components-diy/diy-digit.vue
- components-diy/diy-coupon.vue
### 2.5 ns-empty 组件37次引用
**文件路径**components/ns-empty/ns-empty.vue
**引用情况**
- pages_tool/form/formdata.vue
- pages_order/_components/common-payment/common-payment.vue
- pages_tool/seal/medium/search.vue
- pages_tool/recharge/order_list.vue
- pages_tool/pay/cashier.vue
- pages_tool/member/withdrawal.vue
- pages_tool/notice/list.vue
- pages_tool/order/activist.vue
- pages_tool/member/point_detail.vue
- pages_tool/member/invite_friends.vue
- pages_tool/member/coupon.vue
- pages_tool/member/footprint.vue
- pages_tool/member/card_buy.vue
- pages_tool/member/collection.vue
- pages_tool/member/balance_detail.vue
- pages_tool/help/list.vue
- pages_tool/goods/coupon.vue
- pages_tool/goods/evaluate.vue
- pages_tool/files/list.vue
- pages_tool/form/form.vue
- pages_tool/goods/brand.vue
- pages_tool/article/list.vue
- pages_promotion/point/goods_list.vue
- pages_promotion/point/order_list.vue
- pages_promotion/merch/detail.vue
- pages_promotion/fenxiao/withdraw_list.vue
- pages_promotion/fenxiao/ranking_list.vue
- pages_promotion/fenxiao/relation.vue
- pages_promotion/fenxiao/team.vue
- pages_promotion/fenxiao/order.vue
- pages_promotion/fenxiao/goods_list.vue
- pages_promotion/fenxiao/bill.vue
- pages_promotion/fenxiao/child_fenxiao.vue
- pages_order/list.vue
- pages_goods/list.vue
- pages_goods/cart.vue
- components-diy/diy-index-page.vue
### 2.6 privacy-popup 组件26次引用
**文件路径**components/privacy-popup/privacy-popup.vue
**引用情况**
- pages_tool/member/index.vue
- pages_goods/detail.vue
- pages/index/index.vue
- pages_tool/webview/webview.vue
- pages_tool/notice/detail.vue
- pages_tool/notice/list.vue
- pages_tool/help/detail.vue
- pages_tool/help/list.vue
- pages_tool/index/diy.vue
- pages_tool/goods/coupon.vue
- pages_tool/goods/coupon_receive.vue
- pages_tool/files/list.vue
- pages_tool/goods/brand.vue
- pages_tool/article/detail.vue
- pages_tool/article/list.vue
- pages_promotion/point/goods_list.vue
- pages_promotion/point/list.vue
- pages_promotion/point/detail.vue
- pages_promotion/merch/detail.vue
- pages_promotion/fenxiao/promote.vue
- pages_promotion/fenxiao/promote_code.vue
- pages_promotion/fenxiao/goods_list.vue
- pages_goods/list.vue
- pages_goods/cart.vue
- pages_goods/category.vue
- components/ns-login/ns-login.vue
### 2.7 x-skeleton 组件19次引用
**文件路径**uni_modules/x-skeleton/components/x-skeleton/x-skeleton.vue
**引用情况**
- pages.json
- components-diy/diy-article.vue
- components-diy/diy-seckill.vue
- components-diy/diy-store-label.vue
- components-diy/diy-presale.vue
- components-diy/diy-pinfan.vue
- components-diy/diy-pintuan.vue
- components-diy/diy-notes.vue
- components-diy/diy-merch-list.vue
- components-diy/diy-live.vue
- components-diy/diy-groupbuy.vue
- components-diy/diy-goods-recommend.vue
- components-diy/diy-goods-brand.vue
- components-diy/diy-goods-list.vue
- components-diy/diy-coupon.vue
- components-diy/diy-bargain.vue
### 2.8 ns-goods-sku 组件13次引用
**文件路径**components/ns-goods-sku/
**引用情况**
- pages_goods/detail.vue
- pages.json
- store/index.js
- pages_promotion/point/detail.vue
- pages_promotion/merch/detail.vue
- pages_goods/list.vue
- pages_goods/cart.vue
- components-diy/diy-goods-list.vue
- components-diy/diy-category.vue
### 2.9 to-top 组件11次引用
**文件路径**components/to-top/to-top.vue
**引用情况**
- pages_goods/detail.vue
- pages_tool/contact/contact.vue
- pages/index/index.vue
- pages_tool/member/level.vue
- pages_tool/member/level_growth_rules.vue
- pages_promotion/point/detail.vue
- pages_goods/cart.vue
- components/mescroll/mescroll-uni.vue
- pages_goods/_components/goods-detail-view/goods-detail-view.vue
- common/css/goods_detail.scss
### 2.10 ns-goods-recommend 组件10次引用
**文件路径**components/ns-goods-recommend/ns-goods-recommend.vue
**引用情况**
- pages_tool/pay/result.vue
- pages_tool/member/collection.vue
- pages_tool/member/card.vue
- pages_promotion/fenxiao/level.vue
- pages_order/detail_point.vue
- pages_order/detail.vue
- pages_goods/cart.vue
- pages_goods/_components/goods-detail-view/goods-detail-view.vue
### 2.11 ns-payment 组件9次引用
**文件路径**components/ns-payment/ns-payment.vue
**引用情况**
- pages_tool/recharge/list.vue
- pages_tool/member/card_buy.vue
- pages_promotion/point/order_list.vue
- pages_promotion/point/payment.vue
- pages_order/detail_point.vue
- pages_order/list.vue
- pages_order/detail.vue
### 2.12 ns-adv 组件8次引用
**文件路径**components/ns-adv/ns-adv.vue
**引用情况**
- pages_tool/files/list.vue
- pages_tool/goods/brand.vue
- pages_tool/article/list.vue
- pages_promotion/point/list.vue
- pages_promotion/point/public/css/list.scss
- pages_promotion/fenxiao/public/css/follow.scss
### 2.13 ns-form 组件8次引用
**文件路径**components/ns-form/ns-form.vue
**引用情况**
- pages_goods/detail.vue
- pages_order/_components/common-payment/common-payment.vue
- pages_tool/form/form.vue
- pages_tool/_components/ns-newform/ns-newform.vue
- components/ns-goods-sku/ns-goods-sku.vue
- common/css/order_parment.scss
### 2.14 uni-icons 组件8次引用
**文件路径**uni_modules/uni-icons/components/uni-icons/uni-icons.vue
**引用情况**
- uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
- uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue
- uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
### 2.15 ns-contact 组件7次引用
**文件路径**components/ns-contact/ns-contact.vue
**引用情况**
- pages_tool/order/refund_detail.vue
- pages_tool/member/contact.vue
- pages_order/detail_point.vue
- pages_order/detail.vue
- components/ns-goods-action-icon/ns-goods-action-icon.vue
### 2.16 ns-copyright 组件7次引用
**文件路径**components/ns-copyright/ns-copyright.vue
**引用情况**
- pages_tool/member/index.vue
- pages/index/index.vue
- pages_tool/index/diy.vue
- pages_promotion/fenxiao/promote.vue
- pages_promotion/fenxiao/index.vue
- pages_goods/_components/goods-detail-view/goods-detail-view.vue
### 2.17 hover-nav 组件6次引用
**文件路径**components/hover-nav/hover-nav.vue
**引用情况**
- pages_tool/member/index.vue
- pages_tool/contact/contact.vue
- pages/index/index.vue
- pages/contact/contact.vue
### 2.18 pick-regions 组件6次引用
**文件路径**components/pick-regions/pick-regions.vue
**引用情况**
- pages_tool/member/info_edit.vue
- pages_tool/member/address_edit.vue
- pages_tool/_components/ns-newform/ns-newform.vue
- components/ns-form/ns-form.vue
### 2.19 ns-navbar 组件6次引用
**文件路径**components/ns-navbar/ns-navbar.vue
**引用情况**
- pages_tool/member/index.vue
- pages_goods/detail.vue
- pages/index/index.vue
- pages_tool/index/diy.vue
### 2.20 uni-drawer 组件4次引用
**文件路径**uni_modules/uni-drawer/components/uni-drawer/uni-drawer.vue
**引用情况**
- pages_promotion/point/goods_list.vue
- pages_promotion/merch/detail.vue
- pages_goods/list.vue
### 2.21 uni-calendar 组件4次引用
**文件路径**uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue
**引用情况**
- uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar.vue
- uni_modules/uni-datetime-picker/components/uni-datetime-picker/calendar-item.vue
### 2.22 chat-message 组件4次引用
**文件路径**components/chat-message/chat-message.vue
**引用情况**
- pages_tool/ai-chat/index.vue
- pages_tool/ai-chat/ai-chat-message.vue
### 2.23 ns-switch 组件4次引用
**文件路径**components/ns-switch/ns-switch.vue
**引用情况**
- pages_order/_components/common-payment/common-payment.vue
- components/payment/payment.vue
- components/ns-payment/ns-payment.vue
### 2.24 register-reward 组件4次引用
**文件路径**components/register-reward/register-reward.vue
**引用情况**
- pages_tool/login/login.vue
- components/ns-login/ns-login.vue
### 2.25 sx-rate 组件4次引用
**文件路径**components/sx-rate/sx-rate.vue
**引用情况**
- pages_tool/order/evaluate.vue
### 2.26 uni-count-down 组件3次引用
**文件路径**uni_modules/uni-count-down/components/uni-count-down/uni-count-down.vue
**引用情况**
- pages_goods/detail.vue
- pages_order/list.vue
- pages_order/detail.vue
### 2.27 uni-badge 组件3次引用
**文件路径**uni_modules/uni-badge/components/uni-badge/uni-badge.vue
**引用情况**
- uni_modules/uni-grid-item/components/uni-grid-item/uni-grid-item.vue
### 2.28 uni-grid 组件3次引用
**文件路径**uni_modules/uni-grid/components/uni-grid/uni-grid.vue
**引用情况**
- pages_tool/goods/brand.vue
### 2.29 ns-loading 组件5次引用
**文件路径**components/ns-loading/ns-loading.vue
**引用情况**
- pages_tool/ai-chat/ai-chat-message.vue
- components/mescroll/mescroll-uni.vue
- components-diy/diy-index-page.vue
### 2.30 ns-goods-action 组件5次引用
**文件路径**components/ns-goods-action/ns-goods-action.vue
**引用情况**
- pages_goods/detail.vue
- components/ns-goods-action-icon/ns-goods-action-icon.vue
- components/ns-goods-action-button/ns-goods-action-button.vue
### 2.31 ns-chat 组件5次引用
**文件路径**components/ns-chat/
**引用情况**
- components/chat-message/chat-message.vue
### 2.32 ns-select-time 组件3次引用
**文件路径**components/ns-select-time/ns-select-time.vue
**引用情况**
- pages_order/_components/common-payment/common-payment.vue
- pages_promotion/point/payment.vue
### 2.33 uv-count-to 组件3次引用
**文件路径**components/uv-count-to/uv-count-to.vue
**引用情况**
- components-diy/diy-digit.vue
### 2.34 ns-video-player-popup 组件3次引用
**文件路径**components/ns-video-player-popup/ns-video-player-popup.vue
**引用情况**
- pages_tool/contact/contact.vue
### 2.35 l-time 组件3次引用
**文件路径**components/l-time/l-time.vue
**引用情况**
- common/css/icondiy.css
### 2.36 pengpai-fadein-out 组件3次引用
**文件路径**components/pengpai-fadein-out/pengpai-fadein-out.vue
**引用情况**
- pages_goods/_components/goods-detail-view/goods-detail-view.vue
### 2.37 ns-progress 组件2次引用
**文件路径**components/ns-progress/ns-progress.vue
**引用情况**
- pages_tool/member/level.vue
### 2.38 payment 组件2次引用
**文件路径**components/payment/payment.vue
**引用情况**:无直接引用
### 2.39 uni-popup-sku 组件2次引用
**文件路径**uni_modules/uni-popup-sku/components/uni-popup-sku/uni-popup-sku.vue
**引用情况**:无直接引用
### 2.40 uni-popup-sku-category 组件2次引用
**文件路径**uni_modules/uni-popup-sku-category/components/uni-popup-sku-category/uni-popup-sku-category.vue
**引用情况**:无直接引用
### 2.41 uni-datetime-picker 组件13次引用
**文件路径**uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue
**引用情况**
- components/yuyue-date/yuyue-date.vue
### 2.42 ns-mp-html 组件1次引用
**文件路径**components/ns-mp-html/ns-mp-html.vue
**引用情况**:无引用
### 2.43 wxwork-contact 组件1次引用
**文件路径**components/wxwork-contact/wxwork-contact.vue
**引用情况**:无引用
### 2.44 xiao-star-component 组件1次引用
**文件路径**components/xiao-star-component/xiao-star-component.vue
**引用情况**:无引用
### 2.45 yuyue-date 组件1次引用
**文件路径**components/yuyue-date/yuyue-date.vue
**引用情况**:无引用
### 2.46 uni-nav-bar 组件1次引用
**文件路径**uni_modules/uni-nav-bar/components/uni-nav-bar/uni-nav-bar.vue
**引用情况**:无直接引用
### 2.47 uni-number-box 组件1次引用
**文件路径**uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue
**引用情况**:无直接引用
### 2.48 uni-status-bar 组件1次引用
**文件路径**uni_modules/uni-status-bar/components/uni-status-bar/uni-status-bar.vue
**引用情况**:无直接引用
### 2.49 uni-tag 组件1次引用
**文件路径**uni_modules/uni-tag/components/uni-tag/uni-tag.vue
**引用情况**:无直接引用
### 2.50 mp-html 组件1次引用
**文件路径**uni_modules/mp-html/components/mp-html/mp-html.vue
**引用情况**:无直接引用
### 2.51 uni-scss 组件1次引用
**文件路径**uni_modules/uni-scss/components/uni-scss/
**引用情况**:无直接引用
### 2.52 uni-grid-item 组件1次引用
**文件路径**uni_modules/uni-grid-item/components/uni-grid-item/uni-grid-item.vue
**引用情况**:无直接引用
## 3. 组件使用统计
### 3.1 使用最广泛的组件前10
1. loading-cover - 78个引用
2. uni-popup - 66个引用
3. mescroll - 63个引用
4. ns-login - 53个引用
5. ns-empty - 37个引用
6. privacy-popup - 26个引用
7. x-skeleton - 19个引用
8. ns-goods-sku - 13个引用
9. to-top - 11个引用
10. ns-goods-recommend - 10个引用
### 3.2 未被使用的组件
- ns-mp-html
- wxwork-contact
- xiao-star-component
- yuyue-date
- uni-nav-bar
- uni-number-box
- uni-status-bar
- uni-tag
- mp-html
- uni-scss
## 4. 总结
本项目的组件使用情况较为集中,核心组件如 loading-cover、uni-popup、mescroll、ns-login 等被广泛应用于多个页面。同时,也存在部分组件未被使用的情况,这些组件可能是为未来功能预留的,或者是已经被其他组件替代的。
通过本文档,可以清晰了解每个组件的使用范围,为后续的组件优化和维护提供参考。
**更新时间**2026-01-16

View File

@@ -21,6 +21,13 @@ export const lang = {
searchTip: 'Please enter search keywords' searchTip: 'Please enter search keywords'
}, },
//customer service
customer: {
weChatKefu: 'WeChat Customer Service',
systemKefu: 'System Customer Service',
weChatWorkKefu: 'WeChat Work Customer Service',
},
login: 'Login/Register', login: 'Login/Register',
loginTips: 'Click to login and enjoy more exciting information', loginTips: 'Click to login and enjoy more exciting information',
toLogin: 'Go to login', toLogin: 'Go to login',

View File

@@ -21,6 +21,13 @@ export const lang = {
searchTip: '请输入搜索关键词' searchTip: '请输入搜索关键词'
}, },
//客服
customer: {
weChatKefu: '微信客服',
systemKefu: '专属客服',
weChatWorkKefu: '企业微信客服',
},
login: '登录/注册', login: '登录/注册',
loginTpis: '点击登录 享受更多精彩信息', loginTpis: '点击登录 享受更多精彩信息',
toLogin: '去登录', toLogin: '去登录',

View File

@@ -58,7 +58,7 @@
"quickapp" : {}, "quickapp" : {},
/* */ /* */
"mp-weixin" : { "mp-weixin" : {
"appid" : "wx29215aa1bd97bbd6", "appid" : "wx5e649e2286b29bdf",
"setting" : { "setting" : {
"urlCheck" : false, "urlCheck" : false,
"postcss" : false, "postcss" : false,
@@ -66,7 +66,7 @@
"minified" : true "minified" : true
}, },
"usingComponents" : true, "usingComponents" : true,
"lazyCodeLoading": "requiredComponents", "lazyCodeLoading" : "requiredComponents",
"permission" : { "permission" : {
"scope.userLocation" : { "scope.userLocation" : {
"desc" : "为了更好地为您提供服务" "desc" : "为了更好地为您提供服务"
@@ -130,5 +130,5 @@
"uniStatistics" : { "uniStatistics" : {
"version" : "2" "version" : "2"
}, },
"sassImplementationName" : "node-sass" "sassImplementationName" : "dart-sass"
} }

View File

@@ -19,8 +19,8 @@ https://unpkg.com/jweixin-module/out/index.js
## 使用 ## 使用
```js ```js
var wx = require('jweixin-module') var jweixin = require('jweixin-module')
wx.ready(function(){ jweixin.ready(function(){
// TODO // TODO
}); });
``` ```

File diff suppressed because one or more lines are too long

View File

@@ -1,60 +1,26 @@
{ {
"_from": "jweixin-module",
"_id": "jweixin-module@1.4.1",
"_inBundle": false,
"_integrity": "sha512-2R2oa1lYhAsclfjKSf3DP4ZiP1dcrQUbM7aklbeJA+UAg/LS7MqoA6UbTy1cs4sbB34z62K4bKW0Z9iazD8ejg==",
"_location": "/jweixin-module",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "jweixin-module",
"name": "jweixin-module", "name": "jweixin-module",
"escapedName": "jweixin-module", "version": "1.6.0",
"rawSpec": "", "description": "微信JS-SDK",
"saveSpec": null, "main": "lib/index.js",
"fetchSpec": "latest" "scripts": {},
}, "repository": {
"_requiredBy": [ "type": "git",
"#USER", "url": "git+https://github.com/zhetengbiji/jweixin-module.git"
"/" },
], "keywords": [
"_resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.4.1.tgz", "wxjssdk",
"_shasum": "1fc8fa42622243f6c35651d272cd587debf56cd1", "weixin",
"_spec": "jweixin-module", "jweixin",
"_where": "E:\\demo\\niushop_uniapp", "wechat",
"author": { "jssdk",
"name": "Shengqiang Guo" "wx"
}, ],
"bugs": { "author": "Shengqiang Guo",
"url": "https://github.com/zhetengbiji/jweixin-module/issues" "license": "ISC",
}, "bugs": {
"bundleDependencies": false, "url": "https://github.com/zhetengbiji/jweixin-module/issues"
"deprecated": false, },
"description": "微信JS-SDK", "homepage": "https://github.com/zhetengbiji/jweixin-module#readme",
"devDependencies": { "devDependencies": {}
"textfile": "^1.2.0",
"uglify-js": "^3.4.9"
},
"homepage": "https://github.com/zhetengbiji/jweixin-module#readme",
"keywords": [
"wxjssdk",
"weixin",
"jweixin",
"wechat",
"jssdk",
"wx"
],
"license": "ISC",
"main": "out/index.js",
"name": "jweixin-module",
"repository": {
"type": "git",
"url": "git+https://github.com/zhetengbiji/jweixin-module.git"
},
"scripts": {
"build": "node build",
"prepublish": "npm run build"
},
"version": "1.4.1"
} }

377
package-lock.json generated
View File

@@ -8,6 +8,7 @@
"jweixin-module": "^1.6.0" "jweixin-module": "^1.6.0"
}, },
"devDependencies": { "devDependencies": {
"dart-sass": "^1.25.0",
"terser-webpack-plugin": "^5.3.10", "terser-webpack-plugin": "^5.3.10",
"zion-uniapp-mp-load-package": "^1.0.13" "zion-uniapp-mp-load-package": "^1.0.13"
} }
@@ -368,6 +369,59 @@
"ajv": "^6.9.1" "ajv": "^6.9.1"
} }
}, },
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/anymatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/browserslist": { "node_modules/browserslist": {
"version": "4.23.3", "version": "4.23.3",
"resolved": "https://repo.huaweicloud.com/repository/npm/browserslist/-/browserslist-4.23.3.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/browserslist/-/browserslist-4.23.3.tgz",
@@ -449,6 +503,74 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/dart-sass": {
"version": "1.25.0",
"resolved": "https://registry.npmmirror.com/dart-sass/-/dart-sass-1.25.0.tgz",
"integrity": "sha512-syNOAstJXAmvD3RifcDk3fiPMyYE2fY8so6w9gf2/wNlKpG0zyH+oiXubEYVOy1WAWkzOc72pbAxwx+3OU4JJA==",
"deprecated": "This package has been renamed to 'sass'.",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": ">=2.0.0 <4.0.0"
},
"bin": {
"dart-sass": "sass.js"
},
"engines": {
"node": ">=8.9.0"
}
},
"node_modules/dart-sass/node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/dart-sass/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/dart-sass/node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://repo.huaweicloud.com/repository/npm/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz",
@@ -567,6 +689,47 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/glob-to-regexp": { "node_modules/glob-to-regexp": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://repo.huaweicloud.com/repository/npm/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
@@ -593,6 +756,52 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/jest-worker": { "node_modules/jest-worker": {
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://repo.huaweicloud.com/repository/npm/jest-worker/-/jest-worker-27.5.1.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/jest-worker/-/jest-worker-27.5.1.tgz",
@@ -701,6 +910,16 @@
"license": "MIT", "license": "MIT",
"peer": true "peer": true
}, },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://repo.huaweicloud.com/repository/npm/picocolors/-/picocolors-1.0.1.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/picocolors/-/picocolors-1.0.1.tgz",
@@ -881,6 +1100,19 @@
} }
} }
}, },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.13.0", "version": "6.13.0",
"resolved": "https://repo.huaweicloud.com/repository/npm/undici-types/-/undici-types-6.13.0.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/undici-types/-/undici-types-6.13.0.tgz",
@@ -1318,6 +1550,39 @@
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
"anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"dependencies": {
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
}
}
},
"binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true
},
"braces": {
"version": "3.0.3",
"resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
"fill-range": "^7.1.1"
}
},
"browserslist": { "browserslist": {
"version": "4.23.3", "version": "4.23.3",
"resolved": "https://repo.huaweicloud.com/repository/npm/browserslist/-/browserslist-4.23.3.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/browserslist/-/browserslist-4.23.3.tgz",
@@ -1357,6 +1622,48 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true "dev": true
}, },
"dart-sass": {
"version": "1.25.0",
"resolved": "https://registry.npmmirror.com/dart-sass/-/dart-sass-1.25.0.tgz",
"integrity": "sha512-syNOAstJXAmvD3RifcDk3fiPMyYE2fY8so6w9gf2/wNlKpG0zyH+oiXubEYVOy1WAWkzOc72pbAxwx+3OU4JJA==",
"dev": true,
"requires": {
"chokidar": ">=2.0.0 <4.0.0"
},
"dependencies": {
"chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"fsevents": "~2.3.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
}
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
},
"readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"requires": {
"picomatch": "^2.2.1"
}
}
}
},
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://repo.huaweicloud.com/repository/npm/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz",
@@ -1445,6 +1752,31 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true "dev": true
}, },
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"optional": true
},
"glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"glob-to-regexp": { "glob-to-regexp": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://repo.huaweicloud.com/repository/npm/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
@@ -1465,6 +1797,36 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true "dev": true
}, },
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"requires": {
"binary-extensions": "^2.0.0"
}
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true
},
"is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"jest-worker": { "jest-worker": {
"version": "27.5.1", "version": "27.5.1",
"resolved": "https://repo.huaweicloud.com/repository/npm/jest-worker/-/jest-worker-27.5.1.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/jest-worker/-/jest-worker-27.5.1.tgz",
@@ -1544,6 +1906,12 @@
"dev": true, "dev": true,
"peer": true "peer": true
}, },
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
"picocolors": { "picocolors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://repo.huaweicloud.com/repository/npm/picocolors/-/picocolors-1.0.1.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/picocolors/-/picocolors-1.0.1.tgz",
@@ -1649,6 +2017,15 @@
"terser": "^5.26.0" "terser": "^5.26.0"
} }
}, },
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"undici-types": { "undici-types": {
"version": "6.13.0", "version": "6.13.0",
"resolved": "https://repo.huaweicloud.com/repository/npm/undici-types/-/undici-types-6.13.0.tgz", "resolved": "https://repo.huaweicloud.com/repository/npm/undici-types/-/undici-types-6.13.0.tgz",

View File

@@ -1,8 +1,12 @@
{ {
"scripts": { "scripts": {
"mp-weixin": "node scripts/mp-weixin.patch.js" "mp-weixin": "node scripts/mp-weixin.patch.js",
"mp-weixin:patch": "node scripts/mp-weixin.patch.js --no-zip",
"mp-weixin:dev": "node scripts/mp-weixin.patch.js --mode development",
"mp-weixin:dev:patch": "node scripts/mp-weixin.patch.js --mode development --no-zip"
}, },
"devDependencies": { "devDependencies": {
"dart-sass": "^1.25.0",
"terser-webpack-plugin": "^5.3.10", "terser-webpack-plugin": "^5.3.10",
"zion-uniapp-mp-load-package": "^1.0.13" "zion-uniapp-mp-load-package": "^1.0.13"
}, },

View File

@@ -315,6 +315,12 @@
//*****************其他模块26****************** //*****************其他模块26******************
"root": "pages_tool", "root": "pages_tool",
"pages": [ "pages": [
{
"path": "ai-chat/index",
"style": {
"navigationBarTitleText": "AI 客服"
}
},
{ {
"path": "agreement/contenr", "path": "agreement/contenr",
"style": { "style": {

View File

@@ -201,7 +201,7 @@ export default {
} }
</style> </style>
<style scoped> <style scoped>
.swiper /deep/ .uni-swiper-dots-horizontal { .swiper ::v-deep .uni-swiper-dots-horizontal {
left: 40%; left: 40%;
bottom: 40px bottom: 40px
} }
@@ -214,26 +214,26 @@ export default {
width: 80%; width: 80%;
} }
/deep/.diy-index-page .uni-popup .uni-popup__wrapper-box { ::v-deep .diy-index-page .uni-popup .uni-popup__wrapper-box {
border-radius: 0; border-radius: 0;
} }
/deep/ .placeholder { ::v-deep .placeholder {
height: 0; height: 0;
} }
/deep/::-webkit-scrollbar { ::v-deep ::-webkit-scrollbar {
width: 0; width: 0;
height: 0; height: 0;
background-color: transparent; background-color: transparent;
display: none; display: none;
} }
/deep/ .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
/deep/ .mescroll-totop { ::v-deep .mescroll-totop {
/* #ifdef H5 */ /* #ifdef H5 */
right: 28rpx !important; right: 28rpx !important;
bottom: 200rpx !important; bottom: 200rpx !important;

View File

@@ -59,7 +59,7 @@
} }
} }
.official-accounts-inner /deep/ .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box { .official-accounts-inner ::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
overflow: inherit; overflow: inherit;
} }
.official-accounts-wrap { .official-accounts-wrap {

View File

@@ -3,16 +3,21 @@
<view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''"> <view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''">
<view class="goods-container"> <view class="goods-container">
<!-- 弹幕 --> <!-- 弹幕 -->
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai" :duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true" :info="goodsSkuDetail.barrageData"/> <pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai"
:duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true"
:info="goodsSkuDetail.barrageData" />
<!-- 商品媒体信息 --> <!-- 商品媒体信息 -->
<view class="goods-media" :style="{height: goodsSkuDetail.swiperHeight}"> <view class="goods-media" :style="{ height: goodsSkuDetail.swiperHeight }">
<!-- 商品图片 --> <!-- 商品图片 -->
<view class="goods-img" :class="{ show: switchMedia == 'img' }"> <view class="goods-img" :class="{ show: switchMedia == 'img' }">
<swiper class="swiper" @change="swiperChange" :interval="swiperInterval" :autoplay="swiperAutoplay" autoplay="true" interval="4000" circular="true"> <swiper class="swiper" @change="swiperChange" :interval="swiperInterval"
<swiper-item v-for="(item, index) in goodsSkuDetail.sku_images" :key="index" :item-id="'goods_id_' + index"> :autoplay="swiperAutoplay" autoplay="true" interval="4000" circular="true">
<swiper-item v-for="(item, index) in goodsSkuDetail.sku_images" :key="index"
:item-id="'goods_id_' + index">
<view class="item" @click="previewMedia(index)"> <view class="item" @click="previewMedia(index)">
<image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)" mode="aspectFit" /> <image :src="$util.img(item, { size: 'big' })" @error="swiperImageError(index)"
mode="aspectFit" />
</view> </view>
</swiper-item> </swiper-item>
</swiper> </swiper>
@@ -24,13 +29,16 @@
<!-- 商品视频 --> <!-- 商品视频 -->
<view class="goods-video" :class="{ show: switchMedia == 'video' }"> <view class="goods-video" :class="{ show: switchMedia == 'video' }">
<video id="goodsVideo" :src="$util.img(goodsSkuDetail.video_url)" :poster="$util.img(goodsSkuDetail.sku_image, { size: 'big' })" objectFit="cover"></video> <video id="goodsVideo" :src="$util.img(goodsSkuDetail.video_url)"
:poster="$util.img(goodsSkuDetail.sku_image, { size: 'big' })" objectFit="cover"></video>
</view> </view>
<!-- 切换视频图片 --> <!-- 切换视频图片 -->
<view class="media-mode" v-if="goodsSkuDetail.video_url != ''"> <view class="media-mode" v-if="goodsSkuDetail.video_url != ''">
<text :class="{ 'color-base-bg': switchMedia == 'video' }" @click="switchMedia = 'video'">{{ $lang('video') }}</text> <text :class="{ 'color-base-bg': switchMedia == 'video' }" @click="switchMedia = 'video'">{{
<text :class="{ 'color-base-bg': switchMedia == 'img' }" @click="(switchMedia = 'img'), videoContext.pause()">{{ $lang('image') }}</text> $lang('video') }}</text>
<text :class="{ 'color-base-bg': switchMedia == 'img' }"
@click="(switchMedia = 'img'), videoContext.pause()">{{ $lang('image') }}</text>
</view> </view>
</view> </view>
@@ -45,14 +53,15 @@
<slot name="entrance"></slot> <slot name="entrance"></slot>
<!-- 配送 --> <!-- 配送 -->
<!-- @click="$refs.deliveryType.open()" --> <!-- @click="$refs.deliveryType.open()" -->
<view class="item delivery-type" v-if="goodsSkuDetail.is_virtual == 0" > <view class="item delivery-type" v-if="goodsSkuDetail.is_virtual == 0">
<view class="label">{{$lang('send')}}</view> <view class="label">{{ $lang('send') }}</view>
<block v-if="deliveryType"> <block v-if="deliveryType">
<view class="box"> <view class="box">
<block v-for="(item, index) in deliveryType" :key="index"> <block v-for="(item, index) in deliveryType" :key="index">
<text v-if="goodsSkuDetail.support_trade_type.indexOf(index) != -1">{{$lang('express')}}</text> <text
<!-- {{ item.name }} --> v-if="goodsSkuDetail.support_trade_type.indexOf(index) != -1">{{ $lang('express') }}</text>
<!-- {{ item.name }} -->
</block> </block>
</view> </view>
<text class="iconfont icon-right"></text> <text class="iconfont icon-right"></text>
@@ -63,7 +72,7 @@
</view> </view>
<!-- 门店 --> <!-- 门店 -->
<!-- <view class="item store-wrap" @click="openStoreListPopup()" v-if="addonIsExist.store && globalStoreInfo && isShowStore"> <!-- <view class="item store-wrap" @click="openStoreListPopup()" v-if="addonIsExist.store && globalStoreInfo && isShowStore">
<view class="label">门店</view> <view class="label">门店</view>
<view class="list-wrap"> <view class="list-wrap">
<view class="name-wrap"> <view class="name-wrap">
@@ -80,15 +89,21 @@
<text class="iconfont icon-right"></text> <text class="iconfont icon-right"></text>
</view> --> </view> -->
<view class="item service" @click="openMerchantsServicePopup()" v-if="goodsSkuDetail.goods_service.length"> <view class="item service" @click="openMerchantsServicePopup()"
v-if="goodsSkuDetail.goods_service.length">
<view class="label">服务</view> <view class="label">服务</view>
<view class="list-wrap"> <view class="list-wrap">
<view class="item-wrap" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index" v-if="index < 3"> <view class="item-wrap" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index"
v-if="index < 3">
<view class="item-wrap-box"> <view class="item-wrap-box">
<view class="item-wrap-icon"> <view class="item-wrap-icon">
<text class="iconfont icon-dui" v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text> <text class="iconfont icon-dui"
<image class="icon-img" v-else-if="item.icon.iconType == 'img'" :src=" $util.img(item.icon.imageUrl)" /> v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'" :icon="item.icon.icon" :value="item.icon.style ? item.icon.style : null"></diy-icon> <image class="icon-img" v-else-if="item.icon.iconType == 'img'"
:src="$util.img(item.icon.imageUrl)" />
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'"
:icon="item.icon.icon"
:value="item.icon.style ? item.icon.style : null"></diy-icon>
</view> </view>
<text>{{ item.service_name }}</text> <text>{{ item.service_name }}</text>
</view> </view>
@@ -99,27 +114,29 @@
</view> </view>
<!--多规格区域--> <!--多规格区域-->
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.sku_spec_format"> <view class="newdetail margin-bottom" v-if="goodsSkuDetail.sku_spec_format">
<!-- 入口区域 --> <!-- 入口区域 -->
<slot name="skuspec"></slot> <slot name="skuspec"></slot>
</view> </view>
<view class="newdetail margin-bottom" v-if="goodsSkuDetail.merch_id > 0"> <view class="newdetail margin-bottom" v-if="goodsSkuDetail.merch_id > 0">
<!-- 入口区域 --> <!-- 入口区域 -->
<slot name="entrance"></slot> <slot name="entrance"></slot>
<!-- 商家 --> <!-- 商家 -->
<view class="item store-wrap" @click="$util.redirectTo('/pages_promotion/merch/detail', { merch_id: goodsSkuDetail.merch_id })"> <view class="item store-wrap"
@click="$util.redirectTo('/pages_promotion/merch/detail', { merch_id: goodsSkuDetail.merch_id })">
<view class="list-wrap" style="display: flex;"> <view class="list-wrap" style="display: flex;">
<view class="name-wrap"> <view class="name-wrap">
<image :src="$util.img(goodsSkuDetail.merchinfo.merch_image)" mode="widthFix" style="width: 100rpx;height: 100rpx;border-radius: 50rpx;"></image> <image :src="$util.img(goodsSkuDetail.merchinfo.merch_image)" mode="widthFix"
style="width: 100rpx;height: 100rpx;border-radius: 50rpx;"></image>
</view> </view>
<view class="other-wrap"> <view class="other-wrap">
<view class="address" style="margin-left: 30rpx;"> <view class="address" style="margin-left: 30rpx;">
<view>{{goodsSkuDetail.merchinfo.merch_name}}</view> <view>{{ goodsSkuDetail.merchinfo.merch_name }}</view>
<view style="font-size: 24rpx;color: #888;">官方认证商家值得信赖</view> <view style="font-size: 24rpx;color: #888;">官方认证商家值得信赖</view>
</view> </view>
</view> </view>
</view> </view>
<text class="iconfont icon-right"></text> <text class="iconfont icon-right"></text>
@@ -136,7 +153,8 @@
</view> </view>
<scroll-view scroll-y class="type-body"> <scroll-view scroll-y class="type-body">
<block v-for="(item, index) in deliveryType" :key="index"> <block v-for="(item, index) in deliveryType" :key="index">
<view class="type-item" :class="{ 'not-support': goodsSkuDetail.support_trade_type.indexOf(index) == -1 }"> <view class="type-item"
:class="{ 'not-support': goodsSkuDetail.support_trade_type.indexOf(index) == -1 }">
<text class="iconfont" :class="item.icon"></text> <text class="iconfont" :class="item.icon"></text>
<view class="content"> <view class="content">
<view class="title">{{ item.name }}</view> <view class="title">{{ item.name }}</view>
@@ -158,11 +176,16 @@
<text class="iconfont icon-close"></text> <text class="iconfont icon-close"></text>
</view> </view>
<scroll-view scroll-y> <scroll-view scroll-y>
<view class="item" :class="{ 'empty-desc': !item.desc }" v-for="(item, index) in goodsSkuDetail.goods_service" :key="index"> <view class="item" :class="{ 'empty-desc': !item.desc }"
<view class="item-icon" :class="{'empty-desc':!item.desc}"> v-for="(item, index) in goodsSkuDetail.goods_service" :key="index">
<text class="iconfont icon-dui color-base-text" v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text> <view class="item-icon" :class="{ 'empty-desc': !item.desc }">
<image class="icon-img" v-else-if="item.icon.iconType == 'img'" :src=" $util.img(item.icon.imageUrl)" /> <text class="iconfont icon-dui color-base-text"
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'" :icon="item.icon.icon" :value="item.icon.style ? item.icon.style : null"></diy-icon> v-if="!item.icon || (!item.icon.imageUrl && !item.icon.icon)"></text>
<image class="icon-img" v-else-if="item.icon.iconType == 'img'"
:src="$util.img(item.icon.imageUrl)" />
<diy-icon class="icon-box" v-else-if="item.icon.iconType == 'icon'"
:icon="item.icon.icon"
:value="item.icon.style ? item.icon.style : null"></diy-icon>
</view> </view>
<view class="info-wrap"> <view class="info-wrap">
<text class="title">{{ item.service_name }}</text> <text class="title">{{ item.service_name }}</text>
@@ -187,17 +210,19 @@
</view> </view>
<scroll-view scroll-y> <scroll-view scroll-y>
<view class="store-list-content"> <view class="store-list-content">
<view class="list-item" v-for="(item, index) in storeList.data" :key="index" @click="selectStore(item)"> <view class="list-item" v-for="(item, index) in storeList.data" :key="index"
@click="selectStore(item)">
<view class="item-box"> <view class="item-box">
<view class="item-image"> <view class="item-image">
<image :src="$util.img(item.store_image)" v-if="item.store_image"/> <image :src="$util.img(item.store_image)" v-if="item.store_image" />
<image :src="$util.getDefaultImage().store" v-else/> <image :src="$util.getDefaultImage().store" v-else />
</view> </view>
<view class="item-info"> <view class="item-info">
<view class="item-title"> <view class="item-title">
<text class="title">{{ item.store_name }}</text> <text class="title">{{ item.store_name }}</text>
<text class="distance color-base-text" v-if="item.distance"> <text class="distance color-base-text" v-if="item.distance">
距离{{ item.distance > 1 ? item.distance + 'km' : item.distance * 1000 + 'm' }} 距离{{ item.distance > 1 ? item.distance + 'km' : item.distance *
1000 + 'm' }}
</text> </text>
</view> </view>
<view class="item-time" v-if="item.open_date">营业时间{{ item.open_date }} <view class="item-time" v-if="item.open_date">营业时间{{ item.open_date }}
@@ -228,7 +253,7 @@
</view> </view>
<!-- 促销 --> <!-- 促销 -->
<!-- <view class="community-model" @touchmove.prevent.stop @click.stop="onCloseCommunity()" v-show="isCommunity"> <!-- <view class="community-model" @touchmove.prevent.stop @click.stop="onCloseCommunity()" v-show="isCommunity">
<view class="community-model-content" @click.stop> <view class="community-model-content" @click.stop>
<view class="community-model-content-radius"> <view class="community-model-content-radius">
<view>添加社群</view> <view>添加社群</view>
@@ -247,7 +272,8 @@
<slot name="articipation"></slot> <slot name="articipation"></slot>
<!-- 商品评价 --> <!-- 商品评价 -->
<view class="group-wrap" v-if="evaluateConfig.evaluate_show == 1 && goodsSkuDetail.isinformation == 0" style="display: none;"> <view class="group-wrap" v-if="evaluateConfig.evaluate_show == 1 && goodsSkuDetail.isinformation == 0"
style="display: none;">
<view class="goods-evaluate" @click="toEvaluateDetail(goodsSkuDetail.goods_id)"> <view class="goods-evaluate" @click="toEvaluateDetail(goodsSkuDetail.goods_id)">
<view class="tit"> <view class="tit">
<!-- <view class="tit" :class="{ active: goodsEvaluate.content }"> --> <!-- <view class="tit" :class="{ active: goodsEvaluate.content }"> -->
@@ -268,12 +294,18 @@
<view class="evaluator"> <view class="evaluator">
<view class="evaluator-info"> <view class="evaluator-info">
<view class="evaluator-face"> <view class="evaluator-face">
<image v-if="item.member_headimg" :src="$util.img(item.member_headimg)" @error="item.member_headimg = $util.getDefaultImage().head" mode="aspectFill" /> <image v-if="item.member_headimg" :src="$util.img(item.member_headimg)"
<image v-else :src="$util.getDefaultImage().head" @error="item.member_headimg = $util.getDefaultImage().head" mode="aspectFill" /> @error="item.member_headimg = $util.getDefaultImage().head"
mode="aspectFill" />
<image v-else :src="$util.getDefaultImage().head"
@error="item.member_headimg = $util.getDefaultImage().head"
mode="aspectFill" />
</view> </view>
<view class="evaluator-name-wrap"> <view class="evaluator-name-wrap">
<text class="evaluator-name using-hidden" v-if="item.member_name.length > 2 && item.is_anonymous == 1"> <text class="evaluator-name using-hidden"
{{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1] }} v-if="item.member_name.length > 2 && item.is_anonymous == 1">
{{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1]
}}
</text> </text>
<text class="evaluator-name using-hidden" v-else>{{ item.member_name }}</text> <text class="evaluator-name using-hidden" v-else>{{ item.member_name }}</text>
<view v-if="item.scores" class="evaluator-xing"> <view v-if="item.scores" class="evaluator-xing">
@@ -286,7 +318,8 @@
<view class="cont margin-top">{{ item.content }}</view> <view class="cont margin-top">{{ item.content }}</view>
<scroll-view scroll-x="true"> <scroll-view scroll-x="true">
<view class="evaluate-img" v-if="item.images"> <view class="evaluate-img" v-if="item.images">
<view class="img-box" v-for="(img, img_index) in item.images" :key="img_index" @click="previewEvaluate(index, img_index, 'images')"> <view class="img-box" v-for="(img, img_index) in item.images" :key="img_index"
@click="previewEvaluate(index, img_index, 'images')">
<image :src="$util.img(img)" mode="aspectFill" /> <image :src="$util.img(img)" mode="aspectFill" />
</view> </view>
</view> </view>
@@ -295,7 +328,8 @@
</view> </view>
</view> </view>
<view class="goods-attr" v-if="goodsSkuDetail.goods_attr_format && goodsSkuDetail.goods_attr_format.length > 0"> <view class="goods-attr"
v-if="goodsSkuDetail.goods_attr_format && goodsSkuDetail.goods_attr_format.length > 0">
<view class="title">规格属性</view> <view class="title">规格属性</view>
<view class="attr-wrap"> <view class="attr-wrap">
<block v-for="(item, index) in goodsSkuDetail.goods_attr_format" :key="index"> <block v-for="(item, index) in goodsSkuDetail.goods_attr_format" :key="index">
@@ -304,7 +338,8 @@
<text class="value-name">{{ item.attr_value_name }}</text> <text class="value-name">{{ item.attr_value_name }}</text>
</view> </view>
</block> </block>
<view class="attr-action" v-if="goodsSkuDetail.goods_attr_format.length > 4" @click="switchGoodsAttr"> <view class="attr-action" v-if="goodsSkuDetail.goods_attr_format.length > 4"
@click="switchGoodsAttr">
<block v-if="!goodsAttrShow"> <block v-if="!goodsAttrShow">
展开<text class="iconfont icon-iconangledown"></text> 展开<text class="iconfont icon-iconangledown"></text>
</block> </block>
@@ -320,19 +355,20 @@
<!-- 详情 --> <!-- 详情 -->
<view class="goods-detail-tab"> <view class="goods-detail-tab">
<view class="detail-tab"> <view class="detail-tab">
<view class="tab-item">{{$lang('details')}}</view> <view class="tab-item">{{ $lang('details') }}</view>
</view> </view>
<view class="detail-content active"> <view class="detail-content active">
<view class="detail-content-item"> <view class="detail-content-item">
<view class="goods-details" v-if="goodsSkuDetail.goods_content"> <view class="goods-details" v-if="goodsSkuDetail.goods_content">
<!-- <rich-text :nodes="goodsSkuDetail.goods_content" @click="showImg($event)" :data-nodes="goodsSkuDetail.goods_content"></rich-text> --> <!-- <rich-text :nodes="goodsSkuDetail.goods_content" @click="showImg($event)" :data-nodes="goodsSkuDetail.goods_content"></rich-text> -->
<!-- {{goodsSkuDetail.goods_content}} --> <!-- {{goodsSkuDetail.goods_content}} -->
<mp-html :content="goodsSkuDetail.goods_content" /> <mp-html :content="goodsSkuDetail.goods_content" />
<!-- :loading="loading" @preview="preview" @navigate="navigate" --> <!-- :loading="loading" @preview="preview" @navigate="navigate" -->
</view> </view>
<view class="goods-details active" v-else></view> <view class="goods-details active" v-else></view>
<view class="goods-details" v-if="service && service.is_display == 1 && service.content"> <view class="goods-details" v-if="service && service.is_display == 1 && service.content">
<rich-text :nodes="service.content" @click="showImg($event)" :data-nodes="service.content"></rich-text> <rich-text :nodes="service.content" @click="showImg($event)"
:data-nodes="service.content"></rich-text>
</view> </view>
</view> </view>
</view> </view>
@@ -419,25 +455,30 @@
</template> </template>
<script> <script>
// //
import scroll from '@/common/js/scroll-view.js'; import scroll from '@/common/js/scroll-view.js';
import detail from './detail.js'; import detail from './detail.js';
export default { import pengpaiFadeinOut from '../pengpai-fadein-out/pengpai-fadein-out.vue';
name: 'goods-detail-view',
props: { export default {
goodsSkuDetail: { name: 'goods-detail-view',
type: Object, props: {
default: () => { goodsSkuDetail: {
return {}; type: Object,
} default: () => {
return {};
} }
}, }
mixins: [scroll, detail] },
}; components: {
pengpaiFadeinOut
},
mixins: [scroll, detail]
};
</script> </script>
<style lang="scss"> <style lang="scss">
@import '@/common/css/goods_detail.scss'; @import '@/common/css/goods_detail.scss';
</style> </style>
<style scoped></style> <style scoped></style>

View File

@@ -376,13 +376,13 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: none; background: none;
max-height: unset !important; max-height: unset !important;
overflow-y: hidden !important; overflow-y: hidden !important;
} }
/deep/ .uni-popup__wrapper { ::v-deep .uni-popup__wrapper {
border-radius: 20rpx 20rpx 0 0; border-radius: 20rpx 20rpx 0 0;
} }

View File

@@ -30,13 +30,13 @@ export default {
}; };
}, },
onLoad() { onLoad() {
this.$util.hideHomeButton();
//刷新多语言 //刷新多语言
this.$langConfig.refresh(); this.$langConfig.refresh();
uni.hideTabBar();
this.getDiyInfo(); this.getDiyInfo();
}, },
onShow() { onShow() {
this.$util.hideHomeButton();
if (this.$refs.category) this.$refs.category[0].pageShow(); if (this.$refs.category) this.$refs.category[0].pageShow();
}, },
onUnload() { onUnload() {
@@ -74,38 +74,38 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/ .uni-popup__wrapper.uni-center { ::v-deep .uni-popup__wrapper.uni-center {
background: rgba(0, 0, 0, 0.6); background: rgba(0, 0, 0, 0.6);
} }
/deep/ .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper-box {
border-radius: 0 !important; border-radius: 0 !important;
} }
/deep/ .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
overflow-y: visible; overflow-y: visible;
} }
/deep/ .loading-layer { ::v-deep .loading-layer {
background: #fff !important; background: #fff !important;
} }
// 分类四一级展开 // 分类四一级展开
/deep/ .category-template-4 .template-four .uni-popup__wrapper-box { ::v-deep .category-template-4 .template-four .uni-popup__wrapper-box {
border-radius: 0px 0px 14px 14px !important; border-radius: 0px 0px 14px 14px !important;
overflow: hidden; overflow: hidden;
} }
/deep/ .category-template-4 .content-wrap .categoty-goods-wrap .goods-list { ::v-deep .category-template-4 .content-wrap .categoty-goods-wrap .goods-list {
margin-top: 30rpx; margin-top: 30rpx;
} }
/deep/ .category-template-4 .content-wrap .goods-list .goods-item .footer-wrap .right-wrap .num-action { ::v-deep .category-template-4 .content-wrap .goods-list .goods-item .footer-wrap .right-wrap .num-action {
width: 46rpx; width: 46rpx;
height: 46rpx; height: 46rpx;
} }
/deep/ .uni-page-refresh-inner .uni-page-refresh__path { ::v-deep .uni-page-refresh-inner .uni-page-refresh__path {
stroke: rgb(1, 1, 1) !important; stroke: rgb(1, 1, 1) !important;
} }
</style> </style>

View File

@@ -519,12 +519,19 @@
</template> </template>
<script> <script>
import detail from './public/js/detail.js';
import scroll from '@/common/js/scroll-view.js'; import scroll from '@/common/js/scroll-view.js';
import goodsDetailBase from '@/common/js/goods_detail_base.js'; import base from '@/common/js/goods_detail_base.js';
import detail from './public/js/detail.js';
import goodsDetailView from './_components/goods-detail-view/goods-detail-view.vue';
import nsGoodsPromotion from './_components/ns-goods-promotion/ns-goods-promotion.vue';
export default { export default {
mixins: [goodsDetailBase, detail, scroll] components: {
goodsDetailView,
nsGoodsPromotion
},
mixins: [base, detail, scroll]
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -540,18 +547,18 @@ export default {
</style> </style>
<style scoped> <style scoped>
/deep/ .action-icon-wrap .iconfont.icon-shouye1 { ::v-deep .action-icon-wrap .iconfont.icon-shouye1 {
font-size: 40rpx; font-size: 40rpx;
} }
/deep/ .uni-video-cover { ::v-deep .uni-video-cover {
background: none; background: none;
} }
/deep/ .uni-video-cover-duration { ::v-deep .uni-video-cover-duration {
display: none; display: none;
} }
/deep/ .uni-video-cover-play-button { ::v-deep .uni-video-cover-play-button {
border-radius: 50%; border-radius: 50%;
border: 4rpx solid #fff; border: 4rpx solid #fff;
width: 120rpx; width: 120rpx;
@@ -563,7 +570,7 @@ export default {
max-height: initial !important; max-height: initial !important;
} }
/deep/ .sku-layer .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper-box {
overflow-y: initial !important; overflow-y: initial !important;
} }
@@ -590,46 +597,46 @@ export default {
width: initial; width: initial;
} }
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
/deep/ .goods-action-button.active1 { ::v-deep .goods-action-button.active1 {
padding-left: 10px; padding-left: 10px;
} }
/deep/ .goods-action-button.active2 { ::v-deep .goods-action-button.active2 {
padding-right: 10px; padding-right: 10px;
} }
/deep/ .goods-action-button.active3 { ::v-deep .goods-action-button.active3 {
padding: 0 10px; padding: 0 10px;
} }
/deep/ .goods-action-button.active4 { ::v-deep .goods-action-button.active4 {
padding: 0 10px; padding: 0 10px;
} }
/deep/ .uni-popup__wrapper.bottom { ::v-deep .uni-popup__wrapper.bottom {
border-radius: 24rpx 24rpx 0 0; border-radius: 24rpx 24rpx 0 0;
} }
/deep/ .goods-action-button.active1 .action-buttom-wrap { ::v-deep .goods-action-button.active1 .action-buttom-wrap {
height: 72rpx; height: 72rpx;
line-height: 72rpx; line-height: 72rpx;
} }
/deep/ .goods-action-button.active2 .action-buttom-wrap { ::v-deep .goods-action-button.active2 .action-buttom-wrap {
height: 72rpx; height: 72rpx;
line-height: 72rpx; line-height: 72rpx;
} }
/deep/ .goods-action-button.active3 .action-buttom-wrap { ::v-deep .goods-action-button.active3 .action-buttom-wrap {
height: 72rpx; height: 72rpx;
line-height: 72rpx; line-height: 72rpx;
margin: 20rpx 0; margin: 20rpx 0;
} }
/deep/ .goods-action-button.active4 .action-buttom-wrap { ::v-deep .goods-action-button.active4 .action-buttom-wrap {
height: 72rpx; height: 72rpx;
line-height: 72rpx; line-height: 72rpx;
} }

View File

@@ -324,7 +324,7 @@ export default {
} }
/deep/ .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
</style> </style>

View File

@@ -177,18 +177,18 @@
} }
} }
/deep/ .decrease { ::v-deep .decrease {
width: 52rpx; width: 52rpx;
height: 52rpx; height: 52rpx;
line-height: 48rpx; line-height: 48rpx;
font-size: 40rpx; font-size: 40rpx;
border-radius: 10rpx 0px 0px 10rpx; border-radius: 10rpx 0px 0px 10rpx;
} }
/deep/ input { ::v-deep input {
height: 52rpx; height: 52rpx;
line-height: 52rpx; line-height: 52rpx;
} }
/deep/ .increase { ::v-deep .increase {
width: 52rpx; width: 52rpx;
height: 52rpx; height: 52rpx;
line-height: 48rpx; line-height: 48rpx;

View File

@@ -635,9 +635,6 @@
<script> <script>
import payment from './payment.js'; import payment from './payment.js';
export default { export default {
name: 'common-payment', name: 'common-payment',
data() { data() {

View File

@@ -835,7 +835,7 @@ export default {
margin-bottom: 30rpx; margin-bottom: 30rpx;
} }
/deep/ .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
</style> </style>

View File

@@ -296,7 +296,7 @@ export default {
@import './public/css/detail.scss'; @import './public/css/detail.scss';
</style> </style>
<style scoped> <style scoped>
/deep/ .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
</style> </style>

View File

@@ -460,11 +460,11 @@ export default {
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
/deep/ .uni-page { ::v-deep .uni-page {
overflow: hidden; overflow: hidden;
} }
/deep/ .mescroll-upwarp { ::v-deep .mescroll-upwarp {
padding-bottom: 100rpx; padding-bottom: 100rpx;
} }
</style> </style>

View File

@@ -5,7 +5,12 @@
</template> </template>
<script> <script>
import commonPayment from './_components/common-payment/common-payment.vue';
export default { export default {
components: {
commonPayment
},
data() { data() {
return { return {
api: { api: {
@@ -90,15 +95,15 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: none; background: none;
max-height: unset !important; max-height: unset !important;
overflow-y: hidden !important; overflow-y: hidden !important;
} }
/deep/ .uni-popup__wrapper { ::v-deep .uni-popup__wrapper {
border-radius: 20rpx 20rpx 0 0; border-radius: 20rpx 20rpx 0 0;
} }
/deep/ .uni-popup { ::v-deep .uni-popup {
z-index: 8; z-index: 8;
} }
</style> </style>

View File

@@ -104,7 +104,7 @@ view {
} }
} }
/deep/ #action-date .uni-countdown .uni-countdown__number { ::v-deep #action-date .uni-countdown .uni-countdown__number {
border: none !important; border: none !important;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 !important;

View File

@@ -353,7 +353,7 @@ $margin-both: 24rpx;
} }
} }
/deep/ #action-date .uni-countdown .uni-countdown__number { ::v-deep #action-date .uni-countdown .uni-countdown__number {
border: none !important; border: none !important;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 !important;

View File

@@ -421,11 +421,11 @@
width: 100%; width: 100%;
} }
/deep/.uni-scroll-view { ::v-deep .uni-scroll-view {
background-color: #fff; background-color: #fff;
} }
/deep/.uni-scroll-view::-webkit-scrollbar { ::v-deep .uni-scroll-view::-webkit-scrollbar {
/* 隐藏滚动条,但依旧具备可以滚动的功能 */ /* 隐藏滚动条,但依旧具备可以滚动的功能 */
display: none; display: none;
} }
@@ -802,7 +802,7 @@
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
/deep/ .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper-box {
border-radius: 20rpx; border-radius: 20rpx;
} }
</style> </style>

View File

@@ -84,11 +84,11 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
/deep/ .empty { ::v-deep .empty {
margin-top: 0 !important; margin-top: 0 !important;
} }
/deep/ .member-point .mescroll-uni-content { ::v-deep .member-point .mescroll-uni-content {
overflow: hidden; overflow: hidden;
} }

View File

@@ -144,7 +144,7 @@ export default {
} }
</style> </style>
<style lang="scss"> <style lang="scss">
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }

View File

@@ -583,18 +583,18 @@ export default {
@import './public/css/index.scss'; @import './public/css/index.scss';
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
/deep/ .uni-popup__wrapper { ::v-deep .uni-popup__wrapper {
height: auto; height: auto;
} }
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box, ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box,
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box { .uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box {
background: none; background: none;
max-height: unset !important; max-height: unset !important;
overflow-y: hidden !important; overflow-y: hidden !important;
} }
/deep/ .uni-popup__wrapper { ::v-deep .uni-popup__wrapper {
border-radius: 20rpx 20rpx 0 0; border-radius: 20rpx 20rpx 0 0;
} }
</style> </style>

View File

@@ -299,21 +299,21 @@
@import './public/css/level.scss'; @import './public/css/level.scss';
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: none; background: none;
max-height: unset !important; max-height: unset !important;
overflow-y: hidden !important; overflow-y: hidden !important;
} }
/deep/ .uni-popup__wrapper { ::v-deep .uni-popup__wrapper {
border-radius: 20rpx 20rpx 0 0; border-radius: 20rpx 20rpx 0 0;
} }
/deep/ .uni-popup { ::v-deep .uni-popup {
z-index: 8; z-index: 8;
} }
/deep/ .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
</style> </style>

View File

@@ -1,8 +1,8 @@
/deep/ .fixed { ::v-deep .fixed {
position: relative; position: relative;
top: 0; top: 0;
} }
/deep/ .empty { ::v-deep .empty {
margin-top: 0 !important; margin-top: 0 !important;
} }
.cart-empty { .cart-empty {

View File

@@ -333,7 +333,7 @@ export default {
background-color: #f5f5f5 !important; background-color: #f5f5f5 !important;
} }
/deep/ .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
</style> </style>

View File

@@ -228,38 +228,38 @@
<style lang="scss"> <style lang="scss">
@import './public/category.scss'; @import './public/category.scss';
/deep/ .uni-popup__wrapper.uni-center { ::v-deep .uni-popup__wrapper.uni-center {
background: rgba(0, 0, 0, 0.6); background: rgba(0, 0, 0, 0.6);
} }
/deep/ .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper-box {
border-radius: 0 !important; border-radius: 0 !important;
} }
/deep/ .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
overflow-y: visible; overflow-y: visible;
} }
/deep/ .loading-layer { ::v-deep .loading-layer {
background: #fff !important; background: #fff !important;
} }
// 分类四一级展开 // 分类四一级展开
/deep/ .category-template-4 .template-four .uni-popup__wrapper-box { ::v-deep .category-template-4 .template-four .uni-popup__wrapper-box {
border-radius: 0px 0px 14px 14px !important; border-radius: 0px 0px 14px 14px !important;
overflow: hidden; overflow: hidden;
} }
/deep/ .category-template-4 .content-wrap .categoty-goods-wrap .goods-list { ::v-deep .category-template-4 .content-wrap .categoty-goods-wrap .goods-list {
margin-top: 30rpx; margin-top: 30rpx;
} }
/deep/ .category-template-4 .content-wrap .goods-list .goods-item .footer-wrap .right-wrap .num-action { ::v-deep .category-template-4 .content-wrap .goods-list .goods-item .footer-wrap .right-wrap .num-action {
width: 46rpx; width: 46rpx;
height: 46rpx; height: 46rpx;
} }
/deep/ .uni-page-refresh-inner .uni-page-refresh__path { ::v-deep .uni-page-refresh-inner .uni-page-refresh__path {
stroke: rgb(1, 1, 1) !important; stroke: rgb(1, 1, 1) !important;
} }
</style> </style>

View File

@@ -261,7 +261,7 @@
z-index: 2; z-index: 2;
} }
/deep/ .template-four { ::v-deep .template-four {
position: relative; position: relative;
z-index: 1; z-index: 1;
@@ -702,7 +702,7 @@
.right-wrap { .right-wrap {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: end; justify-content: flex-end;
.num { .num {
width: auto; width: auto;
@@ -856,7 +856,7 @@
} }
} }
/deep/ .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper-box {
border-radius: 0; border-radius: 0;
} }
@@ -890,7 +890,7 @@
justify-content: center; justify-content: center;
} }
/deep/ .loading-layer { ::v-deep .loading-layer {
background: #fff !important; background: #fff !important;
} }

View File

@@ -523,7 +523,7 @@ export default {
} }
</style> </style>
<style scoped> <style scoped>
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
} }
</style> </style>

View File

@@ -252,12 +252,12 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/deep/ .fixed { ::v-deep .fixed {
position: relative; position: relative;
top: 0; top: 0;
} }
/deep/ .empty { ::v-deep .empty {
padding-top: 0 !important; padding-top: 0 !important;
} }

View File

@@ -324,17 +324,17 @@ export default {
@import "@/common/css/order_parment.scss"; @import "@/common/css/order_parment.scss";
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
/deep/ .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
background: none; background: none;
max-height: unset !important; max-height: unset !important;
overflow-y: hidden !important; overflow-y: hidden !important;
} }
/deep/ .uni-popup__wrapper { ::v-deep .uni-popup__wrapper {
border-radius: 20rpx 20rpx 0 0; border-radius: 20rpx 20rpx 0 0;
} }
/deep/ .uni-popup { ::v-deep .uni-popup {
z-index: 8; z-index: 8;
} }
</style> </style>

View File

@@ -161,7 +161,7 @@
}; };
</script> </script>
<style scoped> <style scoped>
.register-box /deep/ .uni-scroll-view { .register-box ::v-deep .uni-scroll-view {
background: unset !important; background: unset !important;
} }
@@ -171,11 +171,11 @@
/* margin-top:350rpx; */ /* margin-top:350rpx; */
} }
/deep/ .uni-popup__wrapper-box { ::v-deep .uni-popup__wrapper-box {
background-color: transparent !important; background-color: transparent !important;
} }
/deep/ .birthday-title-hint uni-image { ::v-deep .birthday-title-hint uni-image {
width: 113rpx !important; width: 113rpx !important;
height: 24rpx !important; height: 24rpx !important;
} }

View File

@@ -168,17 +168,17 @@
</script> </script>
<style scoped> <style scoped>
/deep/ .newgift-content uni-image { ::v-deep .newgift-content uni-image {
width: 113rpx !important; width: 113rpx !important;
height: 24rpx !important; height: 24rpx !important;
} }
/deep/ .reward-popup .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box { ::v-deep .reward-popup .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
max-height: unset !important; max-height: unset !important;
overflow-y: unset; overflow-y: unset;
} }
.register-box /deep/ .uni-scroll-view { .register-box ::v-deep .uni-scroll-view {
background: unset !important; background: unset !important;
} }

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,10 +1,11 @@
@font-face {font-family: "iconfont"; @font-face {
src: url('~@/components/sx-rate/sx-rate/iconfont.eot?t=1574760464482'); /* IE9 */ font-family: "iconfont";
src: url('~@/components/sx-rate/sx-rate/iconfont.eot?t=1574760464482#iefix') format('embedded-opentype'), /* IE6-IE8 */ src: url('./fonts/iconfont.eot?t=1574760464482'); /* IE9 */
src: url('./fonts/iconfont.eot?t=1574760464482#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAK8AAsAAAAABnAAAAJwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAp8gQgBNgIkAwgLBgAEIAWEbQcuG6wFyA4lTcHACOEZBUg8fL/2O3f3fTHEkoh28SSayCSxkkgQG6Uz3UvYITu9Qr5K0Vh6Ij6f+8CXKzVBHDvWa6d0lSfK57mc3gQ6kGt8oBz3ojUG9QLqxYEU6B4YRVYqecPYBS7hMYG6QWF0dlOycoGxxFoViFuxkALGuYAksXRVKNccTOJdSTV7zbSAt/D78Y8XxmRKOavq5CZZAOK+7u2svLVode0TggR0vIQc84BEXNQmjugJxumpJ/SNAvsqD77ui8K3i71aBPvrrNIm6IfSe5K58ltNZ3BbU40Blkf9OmKsIW/Un1qddc4dcSma3ArIX7PPXdlxK5l2zJ+aD6TXnQqmu330wqpeWkYN/OnNm/0trU+YvqNR4UN99f+x/tApIFTfR7u39X4gKPnb9pOX5RAQB6DYyc/zOKCD4OUp6KiiPeqnapbAp56NdegrdhLo5wKq+3UG/0fWcyDpCsuWJVVWO5oZO29bXR0FwJ4uV2ONvTeTCVW9I1wVAylyVeNkYudR0rCOsqoN1M1JPd7QDdMTqYZZXQChwwYybT6Q63BIJvYSJX1eUNYReqi7CrsLGyZDbJqIEUWQAPLroJhWKhjHQUyj8mwkrJJROKsI+XyENeIw5LI4xXQqUiA8xxZNtZBHCAMZrJTDFPAcksmUUIWVEkQTlogQVQSbzdS9iUUr5cDUDgyhEIgAxFcHEqMpKTD+eMK09PlsiFAVGQpu6atJ5kMwDfHsEBcLpweZqlX06ruXVzSqCfEQBANiYEpyUAqYh8jIKEGq+nkSCI1gEY2IqURg28OYvlrW+nr5152AOsuUhV2fSy+EwgAAAA==') format('woff2'), url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAK8AAsAAAAABnAAAAJwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAp8gQgBNgIkAwgLBgAEIAWEbQcuG6wFyA4lTcHACOEZBUg8fL/2O3f3fTHEkoh28SSayCSxkkgQG6Uz3UvYITu9Qr5K0Vh6Ij6f+8CXKzVBHDvWa6d0lSfK57mc3gQ6kGt8oBz3ojUG9QLqxYEU6B4YRVYqecPYBS7hMYG6QWF0dlOycoGxxFoViFuxkALGuYAksXRVKNccTOJdSTV7zbSAt/D78Y8XxmRKOavq5CZZAOK+7u2svLVode0TggR0vIQc84BEXNQmjugJxumpJ/SNAvsqD77ui8K3i71aBPvrrNIm6IfSe5K58ltNZ3BbU40Blkf9OmKsIW/Un1qddc4dcSma3ArIX7PPXdlxK5l2zJ+aD6TXnQqmu330wqpeWkYN/OnNm/0trU+YvqNR4UN99f+x/tApIFTfR7u39X4gKPnb9pOX5RAQB6DYyc/zOKCD4OUp6KiiPeqnapbAp56NdegrdhLo5wKq+3UG/0fWcyDpCsuWJVVWO5oZO29bXR0FwJ4uV2ONvTeTCVW9I1wVAylyVeNkYudR0rCOsqoN1M1JPd7QDdMTqYZZXQChwwYybT6Q63BIJvYSJX1eUNYReqi7CrsLGyZDbJqIEUWQAPLroJhWKhjHQUyj8mwkrJJROKsI+XyENeIw5LI4xXQqUiA8xxZNtZBHCAMZrJTDFPAcksmUUIWVEkQTlogQVQSbzdS9iUUr5cDUDgyhEIgAxFcHEqMpKTD+eMK09PlsiFAVGQpu6atJ5kMwDfHsEBcLpweZqlX06ruXVzSqCfEQBANiYEpyUAqYh8jIKEGq+nkSCI1gEY2IqURg28OYvlrW+nr5152AOsuUhV2fSy+EwgAAAA==') format('woff2'),
url('~@/components/sx-rate/sx-rate/iconfont.woff?t=1574760464482') format('woff'), url('./fonts/iconfont.woff?t=1574760464482') format('woff'),
url('~@/components/sx-rate/sx-rate/iconfont.ttf?t=1574760464482') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ url('./fonts/iconfont.ttf?t=1574760464482') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('~@/components/sx-rate/sx-rate/iconfont.svg?t=1574760464482#iconfont') format('svg'); /* iOS 4.1- */ url('./fonts/iconfont.svg?t=1574760464482#iconfont') format('svg'); /* iOS 4.1- */
} }
.iconfont { .iconfont {

View File

@@ -188,10 +188,10 @@ export default {
</script> </script>
<style scoped> <style scoped>
@import './sx-rate/iconfont.css'; @import './iconfont.css';
</style> </style>
<style lang="scss"> <style lang="scss" scoped>
.rate-box { .rate-box {
min-height: 1.4em; min-height: 1.4em;
display: flex; display: flex;

View File

@@ -1,52 +1,187 @@
<template> <template>
<view style="padding: 20rpx;" :style="themeColor"> <view class="view-container" :style="themeColor">
<rich-text :nodes="content"></rich-text> <!-- 加载状态 -->
<view v-if="loading" class="loading-state">
<view class="loading-spinner"></view>
</view>
<!-- 空状态 -->
<view v-else-if="!content" class="empty-state">
<view class="empty-icon">📄</view>
<text class="empty-title">暂无内容</text>
<text class="empty-desc">该协议内容暂未设置</text>
<button class="empty-button" @click="getcontent">重新加载</button>
</view>
<!-- 内容状态 -->
<rich-text v-else :nodes="content"></rich-text>
<to-top v-if="showTop" @toTop="scrollToTopNative()"></to-top>
</view> </view>
</template> </template>
<script> <script>
import htmlParser from '@/common/js/html-parser'; import htmlParser from '@/common/js/html-parser';
import scroll from '@/common/js/scroll-view.js';
export default { export default {
data() { data() {
return { return {
content:'', content: '',
type:'', type: '',
uniacid:0 uniacid: 0,
}; loading: true
}, };
onLoad(option) { },
mixins: [scroll],
onLoad(option) {
this.type = option.type this.type = option.type
this.uniacid = option.uniacid?option.uniacid:0 this.uniacid = option.uniacid ? option.uniacid : 0
this.isIphoneX = this.$util.uniappIsIPhoneX() this.isIphoneX = this.$util.uniappIsIPhoneX()
this.getcontent() this.getcontent()
}, },
onShow() { onShow() {
}, },
methods: { methods: {
getcontent() { getcontent() {
this.loading = true
// privacy content // privacy content
var data = { var data = {
type:this.type type: this.type
} }
if(this.uniacid > 0) data.uniacid = this.uniacid if (this.uniacid > 0) data.uniacid = this.uniacid
this.$api.sendRequest({ this.$api.sendRequest({
url: '/api/config/agreement', url: '/api/config/agreement',
data:data, data: data,
success: res => { success: res => {
console.log(res.data.title) console.log(res.data.title)
uni.setNavigationBarTitle({ uni.setNavigationBarTitle({
title:res.data.title title: res.data.title
}) })
this.content = res.data.content this.content = res.data.content
this.loading = false
},
fail: () => {
this.loading = false
} }
}); });
} }
} }
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.view-container {
padding: 40rpx;
background: #ffffff;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06), 0 1rpx 2rpx rgba(0, 0, 0, 0.09);
margin: 4rpx 20rpx;
// max-width: 800rpx;
margin-left: auto;
margin-right: auto;
min-height: 100vh;
position: relative;
overflow: hidden;
}
// 增强纸张纹理效果
.view-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><defs><pattern id="grain" width="100" height="100" patternUnits="userSpaceOnUse"><circle cx="25" cy="25" r="0.5" fill="%23f5f5f5" opacity="0.3"/><circle cx="75" cy="75" r="0.3" fill="%23f0f0f0" opacity="0.2"/><circle cx="15" cy="85" r="0.4" fill="%23f8f8f8" opacity="0.25"/><circle cx="85" cy="15" r="0.2" fill="%23ebebeb" opacity="0.3"/><path d="M0 0L200 200M200 0L0 200" stroke="%23f2f2f2" stroke-width="0.3" fill="none" opacity="0.15"/></pattern></defs><rect width="200" height="200" fill="url(%23grain)"/></svg>');
opacity: 0.4;
pointer-events: none;
}
// 加载状态样式
.loading-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 60vh;
padding: 40rpx;
.loading-spinner {
width: 50rpx;
height: 50rpx;
border: 4rpx solid #f3f3f3;
border-top: 4rpx solid #6c8ebf;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 24rpx;
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
// 空状态样式
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 60vh;
padding: 40rpx;
text-align: center;
.empty-icon {
font-size: 120rpx;
margin-bottom: 32rpx;
opacity: 0.6;
}
.empty-title {
font-size: 32rpx;
font-weight: 600;
color: #4e5969;
margin-bottom: 16rpx;
}
.empty-desc {
font-size: 24rpx;
color: #8492a6;
margin-bottom: 40rpx;
line-height: 1.6;
}
.empty-button {
width: 200rpx;
height: 70rpx;
line-height: 70rpx;
background-color: #6c8ebf;
color: white;
border: none;
border-radius: 35rpx;
font-size: 26rpx;
font-weight: 500;
box-shadow: 0 2rpx 8rpx rgba(108, 142, 191, 0.3);
transition: all 0.3s ease;
&:hover {
background-color: #5a78a8;
transform: translateY(-2rpx);
box-shadow: 0 4rpx 12rpx rgba(108, 142, 191, 0.4);
}
}
}
::v-deep .mescroll-totop {
right: 27rpx !important;
bottom: 120rpx !important;
}
</style> </style>

View File

@@ -1,11 +1,7 @@
<template> <template>
<view class="ai-chat-container"> <view class="ai-chat-container">
<!-- 聊天消息列表 --> <!-- 聊天消息列表 -->
<scroll-view <scroll-view class="chat-messages" scroll-y :scroll-top="scrollTop" @scroll="onScroll"
class="chat-messages"
scroll-y
:scroll-top="scrollTop"
@scroll="onScroll"
:scroll-with-animation="false"> :scroll-with-animation="false">
<!-- 加载更多历史消息 --> <!-- 加载更多历史消息 -->
@@ -14,11 +10,7 @@
</view> </view>
<!-- 消息列表 --> <!-- 消息列表 -->
<view <view v-for="item in messagesWithKey" :key="item.__renderKey" class="message-item" :class="[item.role, { 'first-message': item.__index === 0 }]">
v-for="(message, index) in messages"
:key="`msg-${message.id || message.timestamp}-${index}`"
class="message-item"
:class="[message.role, { 'first-message': index === 0 }]">
<!-- 用户消息 --> <!-- 用户消息 -->
<view v-if="message.role === 'user'" class="user-message"> <view v-if="message.role === 'user'" class="user-message">
@@ -32,7 +24,7 @@
<view class="message-bubble"> <view class="message-bubble">
<text class="message-text">{{ message.content }}</text> <text class="message-text">{{ message.content }}</text>
</view> </view>
</view> </view>
</view> </view>
<!-- AI消息 --> <!-- AI消息 -->
@@ -85,21 +77,12 @@
<text class="audio-duration">{{ formatDuration(message.duration) }}</text> <text class="audio-duration">{{ formatDuration(message.duration) }}</text>
</view> </view>
<view class="audio-controls"> <view class="audio-controls">
<button <button class="play-btn" :class="{ playing: message.playing }" @click="toggleAudio(message)">
class="play-btn"
:class="{ playing: message.playing }"
@click="toggleAudio(message)">
<text class="iconfont" :class="message.playing ? 'icon-pause' : 'icon-play'"></text> <text class="iconfont" :class="message.playing ? 'icon-pause' : 'icon-play'"></text>
</button> </button>
<slider <slider class="audio-slider" :value="message.currentTime || 0" :max="message.duration || 0"
class="audio-slider" @changing="onAudioSliderChange" @change="onAudioSliderChangeEnd" activeColor="#8a9fb8"
:value="message.currentTime || 0" backgroundColor="#e8edf3" block-size="12" />
:max="message.duration || 0"
@changing="onAudioSliderChange"
@change="onAudioSliderChangeEnd"
activeColor="#8a9fb8"
backgroundColor="#e8edf3"
block-size="12" />
</view> </view>
</view> </view>
</view> </view>
@@ -107,14 +90,8 @@
<!-- 视频消息 --> <!-- 视频消息 -->
<view v-else-if="message.type === 'video'" class="video-content"> <view v-else-if="message.type === 'video'" class="video-content">
<view class="video-player"> <view class="video-player">
<video <video :src="message.url" :poster="message.cover" :controls="true" :autoplay="false"
:src="message.url" class="video-element" @play="onVideoPlay(message)" @pause="onVideoPause(message)">
:poster="message.cover"
:controls="true"
:autoplay="false"
class="video-element"
@play="onVideoPlay(message)"
@pause="onVideoPause(message)">
</video> </video>
<view class="video-info"> <view class="video-info">
<text class="video-title">{{ message.title || '视频消息' }}</text> <text class="video-title">{{ message.title || '视频消息' }}</text>
@@ -163,12 +140,8 @@
<!-- 操作按钮 --> <!-- 操作按钮 -->
<view class="message-actions" v-if="message.actions && message.actions.length > 0"> <view class="message-actions" v-if="message.actions && message.actions.length > 0">
<button <button v-for="action in message.actions" :key="action.id" class="action-btn"
v-for="action in message.actions" :class="[`iconfont`, action.icon, action.type]" @click="handleAction(action, message)">
:key="action.id"
class="action-btn"
:class="[`iconfont`, action.icon, action.type]"
@click="handleAction(action, message)">
{{ action.text }} {{ action.text }}
</button> </button>
</view> </view>
@@ -199,21 +172,11 @@
</view> </view>
<view class="input-container"> <view class="input-container">
<textarea <textarea v-model="inputText" class="message-input" placeholder="请输入您的问题..." :maxlength="500"
v-model="inputText" :auto-height="true" :show-confirm-bar="false" @confirm="sendMessage" @input="onInput" />
class="message-input"
placeholder="请输入您的问题..."
:maxlength="500"
:auto-height="true"
:show-confirm-bar="false"
@confirm="sendMessage"
@input="onInput" />
<!-- 发送按钮 --> <!-- 发送按钮 -->
<button <button class="send-btn" :class="{ disabled: !inputText.trim() }" @click="sendMessage"
class="send-btn"
:class="{ disabled: !inputText.trim() }"
@click="sendMessage"
:disabled="!inputText.trim()"> :disabled="!inputText.trim()">
<text>发送</text> <text>发送</text>
</button> </button>
@@ -271,11 +234,7 @@
</view> </view>
<view class="voice-content"> <view class="voice-content">
<view class="voice-wave" :class="{ recording: voiceInputing }"> <view class="voice-wave" :class="{ recording: voiceInputing }">
<view <view v-for="i in 8" :key="i" class="wave-bar" :style="{ animationDelay: (i * 0.1) + 's' }"></view>
v-for="i in 8"
:key="i"
class="wave-bar"
:style="{ animationDelay: (i * 0.1) + 's' }"></view>
</view> </view>
<text class="voice-tip">{{ voiceInputing ? '正在录音,松开结束' : '点击开始录音' }}</text> <text class="voice-tip">{{ voiceInputing ? '正在录音,松开结束' : '点击开始录音' }}</text>
</view> </view>
@@ -331,23 +290,15 @@
</view> </view>
<view class="nickname-editor-content"> <view class="nickname-editor-content">
<view class="nickname-input-container"> <view class="nickname-input-container">
<input <input v-model="tempNickname" class="nickname-input" placeholder="请输入您的新昵称" :maxlength="12" type="text" />
v-model="tempNickname"
class="nickname-input"
placeholder="请输入您的新昵称"
:maxlength="12"
type="text" />
</view> </view>
<view class="nickname-tip">昵称长度限制1-12个字符仅自己可见</view> <view class="nickname-tip">昵称长度限制1-12个字符仅自己可见</view>
<view class="nickname-editor-actions"> <view class="nickname-editor-actions">
<button class="nickname-action-btn cancel" @click="closeNicknameEditor"> <button class="nickname-action-btn cancel" @click="closeNicknameEditor">
<text>取消</text> <text>取消</text>
</button> </button>
<button <button class="nickname-action-btn confirm" :class="{ disabled: !tempNickname.trim() }"
class="nickname-action-btn confirm" :disabled="!tempNickname.trim()" @click="saveNickname">
:class="{ disabled: !tempNickname.trim() }"
:disabled="!tempNickname.trim()"
@click="saveNickname">
<text>保存</text> <text>保存</text>
</button> </button>
</view> </view>
@@ -398,7 +349,7 @@ export default {
default: 20 default: 20
} }
}, },
data(){ data() {
return { return {
messages: [], messages: [],
inputText: '', inputText: '',
@@ -432,34 +383,47 @@ export default {
currentConversationId: null, currentConversationId: null,
isAIServiceAvailable: true, isAIServiceAvailable: true,
aiServiceError: null, aiServiceError: null,
isLoadingHistory: false, // isLoadingHistory: false, //
shouldScrollToBottom: false, shouldScrollToBottom: false,
scrollTimer: null, scrollTimer: null,
lastScrollTop: 0, lastScrollTop: 0,
historyOffset: 0, historyOffset: 0,
isFetchingHistory: false isFetchingHistory: false
}
},
computed: {
// key
messagesWithKey() {
return this.messages.map((msg, idx) => {
const uniqueId = msg.id || msg.timestamp || idx;
return {
...msg,
__renderKey: `msg_${uniqueId}_${idx}`,
__index: idx // first-message
};
});
} }
}, },
onShow() { onShow() {
// ID // ID
const localConvId = this.getConversationIdFromLocal(); const localConvId = this.getConversationIdFromLocal();
if (localConvId) { if (localConvId) {
this.currentConversationId = localConvId; this.currentConversationId = localConvId;
aiService.setConversationId(localConvId); aiService.setConversationId(localConvId);
} else { } else {
this.currentConversationId = aiService.getConversationId(); this.currentConversationId = aiService.getConversationId();
} }
// historyOffset // historyOffset
this.loadChatHistoryIfExist().then(() => { this.loadChatHistoryIfExist().then(() => {
// //
this.historyOffset = this.messages.length; this.historyOffset = this.messages.length;
}); });
// this.historyOffset = 0; // this.historyOffset = 0;
}, },
// //
beforeDestroy() { beforeDestroy() {
if (this.scrollTimer) clearTimeout(this.scrollTimer); if (this.scrollTimer) clearTimeout(this.scrollTimer);
}, },
created() { created() {
this.messages = [...this.initialMessages] this.messages = [...this.initialMessages]
this.messageId = this.messages.length this.messageId = this.messages.length
@@ -468,42 +432,42 @@ export default {
this.initUserAvatarData() this.initUserAvatarData()
// //
this.initUserNicknameData() this.initUserNicknameData()
this.currentConversationId = aiService.getConversationId(); this.currentConversationId = aiService.getConversationId();
},
mounted() {
//
this.$nextTick(() => {
this.scrollToBottom()
})
}, },
mounted() {
//
this.$nextTick(() => {
this.scrollToBottom()
})
},
watch: { watch: {
messages: { messages: {
handler() { handler() {
this.$nextTick(() => { this.$nextTick(() => {
// //
if (!this.isLoadingHistory && this.shouldScrollToBottom) { if (!this.isLoadingHistory && this.shouldScrollToBottom) {
this.scrollToBottom() this.scrollToBottom()
// //
this.shouldScrollToBottom = false this.shouldScrollToBottom = false
} }
}) })
}, },
deep: true deep: true
} }
}, },
methods: { methods: {
// ID // ID
saveConversationIdToLocal(convId) { saveConversationIdToLocal(convId) {
if (convId) { if (convId) {
uni.setStorageSync('dify_conversation_id', convId); uni.setStorageSync('dify_conversation_id', convId);
} }
}, },
getConversationIdFromLocal() { getConversationIdFromLocal() {
return uni.getStorageSync('dify_conversation_id') || null; return uni.getStorageSync('dify_conversation_id') || null;
}, },
clearConversationIdFromLocal() { clearConversationIdFromLocal() {
uni.removeStorageSync('dify_conversation_id'); uni.removeStorageSync('dify_conversation_id');
}, },
// //
initAudioContext() { initAudioContext() {
// #ifdef H5 // #ifdef H5
@@ -512,18 +476,18 @@ export default {
} }
// #endif // #endif
}, },
onScroll(e) { onScroll(e) {
const currentScrollTop = e.detail.scrollTop; const currentScrollTop = e.detail.scrollTop;
this.lastScrollTop = currentScrollTop; this.lastScrollTop = currentScrollTop;
// 50ms // 50ms
if (this.scrollTimer) clearTimeout(this.scrollTimer); if (this.scrollTimer) clearTimeout(this.scrollTimer);
this.scrollTimer = setTimeout(() => { this.scrollTimer = setTimeout(() => {
// <20px // <20px
if (currentScrollTop < 20 && !this.isLoadingHistory && this.showLoadMore) { if (currentScrollTop < 20 && !this.isLoadingHistory && this.showLoadMore) {
this.loadMoreHistory(); this.loadMoreHistory();
} }
}, 50); }, 50);
}, },
// //
initUserAvatarData() { initUserAvatarData() {
// 1. // 1.
@@ -544,42 +508,42 @@ export default {
} }
}, },
// 👇 // 👇
async loadChatHistoryIfExist() { async loadChatHistoryIfExist() {
const convId = aiService.getConversationId(); const convId = aiService.getConversationId();
if (convId) { if (convId) {
try { try {
const history = await aiService.getChatHistory(); const history = await aiService.getChatHistory();
if (!history || !Array.isArray(history.messages)) { if (!history || !Array.isArray(history.messages)) {
console.warn('历史记录为空或格式无效'); console.warn('历史记录为空或格式无效');
return; return;
} }
this.messages = history.messages.map(msg => { this.messages = history.messages.map(msg => {
let content = ''; let content = '';
if (msg.role === 'user') { if (msg.role === 'user') {
content = msg.query || (typeof msg.inputs === 'string' ? msg.inputs : JSON.stringify(msg.inputs || '')) || ''; content = msg.query || (typeof msg.inputs === 'string' ? msg.inputs : JSON.stringify(msg.inputs || '')) || '';
} else { } else {
content = msg.answer || ''; content = msg.answer || '';
} }
return { return {
id: msg.message_id || (Date.now() + Math.random() * 10000), id: msg.message_id || (Date.now() + Math.random() * 10000),
role: msg.role === 'user' ? 'user' : 'assistant', role: msg.role === 'user' ? 'user' : 'assistant',
content: content, content: content,
timestamp: msg.created_at, timestamp: msg.created_at,
actions: msg.role !== 'user' ? [ actions: msg.role !== 'user' ? [
{ id: 1, text: '有帮助', type: 'like' }, { id: 1, text: '有帮助', type: 'like' },
{ id: 2, text: '没帮助', type: 'dislike' } { id: 2, text: '没帮助', type: 'dislike' }
] : [] ] : []
}; };
}); });
} catch (error) { } catch (error) {
console.error('加载历史记录失败:', error); console.error('加载历史记录失败:', error);
aiService.clearConversationId(); aiService.clearConversationId();
this.clearConversationIdFromLocal(); this.clearConversationIdFromLocal();
this.currentConversationId = null; this.currentConversationId = null;
} }
} }
}, },
// //
initUserNicknameData() { initUserNicknameData() {
// 1. // 1.
@@ -717,7 +681,7 @@ export default {
content: this.inputText.trim(), content: this.inputText.trim(),
timestamp: Date.now() timestamp: Date.now()
} }
this.shouldScrollToBottom = true this.shouldScrollToBottom = true
this.messages.push(userMessage) this.messages.push(userMessage)
this.inputText = '' this.inputText = ''
@@ -787,8 +751,8 @@ export default {
// ID // ID
if (response.conversationId) { if (response.conversationId) {
this.currentConversationId = response.conversationId; this.currentConversationId = response.conversationId;
aiService.setConversationId(response.conversationId); aiService.setConversationId(response.conversationId);
this.saveConversationIdToLocal(response.conversationId); this.saveConversationIdToLocal(response.conversationId);
} }
const aiMessage = { const aiMessage = {
@@ -823,52 +787,52 @@ export default {
// //
this.messages = this.messages.filter(msg => msg.type !== 'loading') this.messages = this.messages.filter(msg => msg.type !== 'loading')
this.shouldScrollToBottom = true this.shouldScrollToBottom = true
this.messages.push(streamMessage) this.messages.push(streamMessage)
// //
await aiService.sendStreamMessage( await aiService.sendStreamMessage(
userMessage, userMessage,
// //
(chunk) => { (chunk) => {
streamMessage.content += chunk streamMessage.content += chunk
this.$forceUpdate() // this.$nextTick() this.$forceUpdate() // this.$nextTick()
}, },
// //
(completeResult) => { (completeResult) => {
let finalContent = ''; let finalContent = '';
let convId = ''; let convId = '';
// //
if (typeof completeResult === 'string') { if (typeof completeResult === 'string') {
finalContent = completeResult; finalContent = completeResult;
} else { } else {
finalContent = completeResult.content || ''; finalContent = completeResult.content || '';
convId = completeResult.conversation_id || ''; // 👈 conversation_id convId = completeResult.conversation_id || ''; // 👈 conversation_id
} }
// //
streamMessage.isStreaming = false; streamMessage.isStreaming = false;
streamMessage.content = finalContent; streamMessage.content = finalContent;
// //
streamMessage.actions = [ streamMessage.actions = [
{ id: 1, text: '有帮助', type: 'like' }, { id: 1, text: '有帮助', type: 'like' },
{ id: 2, text: '没帮助', type: 'dislike' } { id: 2, text: '没帮助', type: 'dislike' }
]; ];
// conversation_id // conversation_id
if (convId) { if (convId) {
aiService.setConversationId(convId); aiService.setConversationId(convId);
} }
// //
this.$emit('ai-response', streamMessage); this.$emit('ai-response', streamMessage);
this.saveConversationIdToLocal(convId); this.saveConversationIdToLocal(convId);
this.currentConversationId = convId; this.currentConversationId = convId;
} }
); );
}, },
generateAIResponse(userMessage) { generateAIResponse(userMessage) {
const responses = { const responses = {
'你好': '您好我是AI智能客服很高兴为您服务有什么可以帮助您的吗', '你好': '您好我是AI智能客服很高兴为您服务有什么可以帮助您的吗',
@@ -915,8 +879,8 @@ export default {
return Math.floor(diff / 3600000) + '小时前' return Math.floor(diff / 3600000) + '小时前'
} else { } else {
return date.getMonth() + 1 + '月' + date.getDate() + '日 ' + return date.getMonth() + 1 + '月' + date.getDate() + '日 ' +
date.getHours().toString().padStart(2, '0') + ':' + date.getHours().toString().padStart(2, '0') + ':' +
date.getMinutes().toString().padStart(2, '0') date.getMinutes().toString().padStart(2, '0')
} }
}, },
@@ -945,76 +909,76 @@ export default {
}, },
// //
async loadMoreHistory() { async loadMoreHistory() {
if (!this.currentConversationId) { if (!this.currentConversationId) {
this.currentConversationId = this.getConversationIdFromLocal(); this.currentConversationId = this.getConversationIdFromLocal();
aiService.setConversationId(this.currentConversationId); aiService.setConversationId(this.currentConversationId);
} }
// //
if (!this.showLoadMore || !this.currentConversationId || this.isLoadingHistory) { if (!this.showLoadMore || !this.currentConversationId || this.isLoadingHistory) {
return; return;
} }
this.isFetchingHistory = true; this.isFetchingHistory = true;
this.isLoadingHistory = true; this.isLoadingHistory = true;
this.loadingText = '加载历史消息中...'; this.loadingText = '加载历史消息中...';
this.hasMoreHistory = true; this.hasMoreHistory = true;
try { try {
// historyOffsetmessages.length // historyOffsetmessages.length
const response = await aiService.getConversationHistory({ const response = await aiService.getConversationHistory({
conversation_id: this.currentConversationId, conversation_id: this.currentConversationId,
limit: 20, limit: 20,
offset: this.historyOffset // offset: this.historyOffset //
}); });
if (response.success && Array.isArray(response.messages) && response.messages.length > 0) { if (response.success && Array.isArray(response.messages) && response.messages.length > 0) {
const historyMessages = response.messages.map(msg => ({ const historyMessages = response.messages.map(msg => ({
id: msg.id || `history-${Date.now()}-${Math.random().toString(36).slice(2)}`, id: msg.id || `history-${Date.now()}-${Math.random().toString(36).slice(2)}`,
role: msg.role === 'user' ? 'user' : 'ai', role: msg.role === 'user' ? 'user' : 'ai',
type: 'text', type: 'text',
content: msg.content, content: msg.content,
timestamp: msg.create_time * 1000 timestamp: msg.create_time * 1000
})); }));
// 1. // 1.
const newMsgCount = historyMessages.length; const newMsgCount = historyMessages.length;
// 2. // 2.
this.messages = [...historyMessages, ...this.messages]; this.messages = [...historyMessages, ...this.messages];
// 3. // 3.
this.historyOffset += newMsgCount; this.historyOffset += newMsgCount;
// 4. DOM // 4. DOM
await this.$nextTick(); await this.$nextTick();
// DOM // DOM
const query = uni.createSelectorQuery().in(this); const query = uni.createSelectorQuery().in(this);
const heightPromises = []; const heightPromises = [];
for (let i = 0; i < newMsgCount; i++) { for (let i = 0; i < newMsgCount; i++) {
heightPromises.push(new Promise(resolve => { heightPromises.push(new Promise(resolve => {
query.select(`.message-item:nth-child(${i + 1})`).boundingClientRect(rect => { query.select(`.message-item:nth-child(${i + 1})`).boundingClientRect(rect => {
resolve(rect ? rect.height + 32 : 0); // 32rpx resolve(rect ? rect.height + 32 : 0); // 32rpx
}).exec(); }).exec();
})); }));
} }
// //
const heights = await Promise.all(heightPromises); const heights = await Promise.all(heightPromises);
const totalNewHeight = heights.reduce((sum, h) => sum + h, 0); const totalNewHeight = heights.reduce((sum, h) => sum + h, 0);
// 5. scrollTop // 5. scrollTop
this.scrollTop = totalNewHeight; this.scrollTop = totalNewHeight;
} else { } else {
// //
this.showLoadMore = false; this.showLoadMore = false;
} }
} catch (error) { } catch (error) {
console.error('加载历史失败:', error); console.error('加载历史失败:', error);
uni.showToast({ title: '加载历史失败', icon: 'none' }); uni.showToast({ title: '加载历史失败', icon: 'none' });
this.showLoadMore = false; this.showLoadMore = false;
} finally { } finally {
this.isLoadingHistory = false; this.isLoadingHistory = false;
this.isFetchingHistory = false; this.isFetchingHistory = false;
this.hasMoreHistory = false; this.hasMoreHistory = false;
this.loadingText = '加载更多历史消息'; this.loadingText = '加载更多历史消息';
} }
}, },
// //
showMoreTools() { showMoreTools() {
this.showToolsPanel = true this.showToolsPanel = true
@@ -1402,7 +1366,8 @@ $radius-lg: 36rpx;
padding: 24rpx 32rpx; padding: 24rpx 32rpx;
overflow-y: auto; overflow-y: auto;
box-sizing: border-box; box-sizing: border-box;
min-height: 0; /* 重要防止flex元素溢出 */ min-height: 0;
/* 重要防止flex元素溢出 */
.load-more { .load-more {
text-align: center; text-align: center;
@@ -1417,7 +1382,8 @@ $radius-lg: 36rpx;
margin-top: 24rpx; margin-top: 24rpx;
} }
.user-message, .ai-message { .user-message,
.ai-message {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
@@ -1448,25 +1414,24 @@ $radius-lg: 36rpx;
margin-left: 24rpx; margin-left: 24rpx;
max-width: calc(100% - 112rpx); max-width: calc(100% - 112rpx);
min-width: 0; min-width: 0;
width: 0; /* 添加这个属性防止flex元素溢出 */ width: 0;
/* 添加这个属性防止flex元素溢出 */
.message-nickname { .message-nickname {
font-size: 24rpx; font-size: 24rpx;
color: $color-text-light; color: $color-text-light;
margin-bottom: 8rpx; margin-bottom: 8rpx;
letter-spacing: 0.5rpx; letter-spacing: 0.5rpx;
// AI text-align: right;
&:not(.ai-message .message-nickname) { }
text-align: right;
} // AI -
// AI - .ai-nickname {
&.ai-nickname { text-align: left;
text-align: left; margin-left: 0;
margin-left: 0; padding-left: 0;
padding-left: 0; align-self: flex-start;
align-self: flex-start; margin-bottom: 4rpx;
margin-bottom: 4rpx;
}
} }
.message-bubble { .message-bubble {
@@ -1898,20 +1863,27 @@ $radius-lg: 36rpx;
text-align: right; text-align: right;
.message-bubble { .message-bubble {
background: linear-gradient(135deg, #ffadd2, #f783ac) !important; /* 粉色渐变 */ background: linear-gradient(135deg, #ffadd2, #f783ac) !important;
color: white !important; /* 粉色渐变 */
border-radius: 16rpx 16rpx 4rpx 16rpx; /* 右对齐气泡尖角适配 */ color: white !important;
box-shadow: 0 8rpx 20rpx rgba(247, 131, 172, 0.3) !important; border-radius: 16rpx 16rpx 4rpx 16rpx;
border: none !important; /* 右对齐气泡尖角适配 */
/* ✅ 关键:允许内容撑开高度 */ box-shadow: 0 8rpx 20rpx rgba(247, 131, 172, 0.3) !important;
min-height: auto; border: none !important;
height: auto; /* ✅ 关键:允许内容撑开高度 */
padding: 24rpx 32rpx; /* 保留内边距 */ min-height: auto;
display: inline-block; /* 让宽度也随内容收缩(可选) */ height: auto;
max-width: 80%; /* 防止过宽 */ padding: 24rpx 32rpx;
word-break: break-word; /* 保留内边距 */
white-space: pre-wrap; /* 保留用户输入的换行符 */ display: inline-block;
line-height: 1.6; /* 让宽度也随内容收缩(可选) */
max-width: 80%;
/* 防止过宽 */
word-break: break-word;
white-space: pre-wrap;
/* 保留用户输入的换行符 */
line-height: 1.6;
&::before { &::before {
content: ''; content: '';
position: absolute; position: absolute;
@@ -1919,7 +1891,8 @@ $radius-lg: 36rpx;
right: -14rpx; right: -14rpx;
width: 24rpx; width: 24rpx;
height: 24rpx; height: 24rpx;
background: #ffffff !important; /* 菱形改为白色 */ background: #ffffff !important;
/* 菱形改为白色 */
border-radius: 6rpx; border-radius: 6rpx;
transform: rotate(45deg); transform: rotate(45deg);
box-shadow: 4rpx -4rpx 4rpx rgba(0, 0, 0, 0.05); box-shadow: 4rpx -4rpx 4rpx rgba(0, 0, 0, 0.05);
@@ -1932,11 +1905,9 @@ $radius-lg: 36rpx;
left: -100%; left: -100%;
width: 50%; width: 50%;
height: 100%; height: 100%;
background: linear-gradient( background: linear-gradient(to right,
to right, rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.15) 100%);
rgba(255, 255, 255, 0.15) 100%
);
animation: shine 4s infinite linear; animation: shine 4s infinite linear;
} }
} }
@@ -1952,19 +1923,22 @@ $radius-lg: 36rpx;
align-items: flex-start; align-items: flex-start;
.message-bubble { .message-bubble {
background: linear-gradient(135deg, #dbeafe, #bfdbfe) !important; /* 蓝色浅渐变 */ background: linear-gradient(135deg, #dbeafe, #bfdbfe) !important;
color: #2c3e50 !important; /* 蓝色浅渐变 */
border-radius: 16rpx 16rpx 16rpx 4rpx; /* 左对齐气泡尖角适配 */ color: #2c3e50 !important;
box-shadow: 0 8rpx 20rpx rgba(191, 219, 254, 0.4) !important; border-radius: 16rpx 16rpx 16rpx 4rpx;
border: 1rpx solid #dbeafe !important; /* 左对齐气泡尖角适配 */
box-shadow: 0 8rpx 20rpx rgba(191, 219, 254, 0.4) !important;
border: 1rpx solid #dbeafe !important;
min-height: auto; min-height: auto;
height: auto; height: auto;
padding: 24rpx 32rpx; padding: 24rpx 32rpx;
display: inline-block; display: inline-block;
max-width: 80%; max-width: 80%;
word-break: break-word; word-break: break-word;
white-space: pre-wrap; white-space: pre-wrap;
line-height: 1.6; line-height: 1.6;
&::before { &::before {
content: ''; content: '';
position: absolute; position: absolute;
@@ -1972,7 +1946,8 @@ $radius-lg: 36rpx;
left: -14rpx; left: -14rpx;
width: 24rpx; width: 24rpx;
height: 24rpx; height: 24rpx;
background: #ffffff !important; /* 菱形改为白色 */ background: #ffffff !important;
/* 菱形改为白色 */
border-radius: 6rpx; border-radius: 6rpx;
transform: rotate(45deg); transform: rotate(45deg);
box-shadow: -4rpx 4rpx 4rpx rgba(0, 0, 0, 0.05); box-shadow: -4rpx 4rpx 4rpx rgba(0, 0, 0, 0.05);
@@ -2072,10 +2047,13 @@ $radius-lg: 36rpx;
font-size: 28rpx; font-size: 28rpx;
font-weight: 500; font-weight: 500;
border: none; border: none;
text-align: center; /* 兼容多端文字居中 */ text-align: center;
white-space: nowrap; /* 强制文字单行横向显示 */ /* 兼容多端文字居中 */
line-height: 1; /* 重置行高,避免文字垂直偏移 */ white-space: nowrap;
top:-10px; /* 强制文字单行横向显示 */
line-height: 1;
/* 重置行高,避免文字垂直偏移 */
top: -10px;
&.disabled { &.disabled {
background-color: $color-primary-light; background-color: $color-primary-light;
@@ -2098,19 +2076,21 @@ $radius-lg: 36rpx;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
pointer-events: none; /* 让鼠标事件穿透容器,不影响主内容交互 */ pointer-events: none;
z-index: 999; /* 基础弹窗层级 */ /* 让鼠标事件穿透容器,不影响主内容交互 */
z-index: 999;
/* 基础弹窗层级 */
/* 子弹窗需要开启 pointer-events否则点击无效 */ /* 子弹窗需要开启 pointer-events否则点击无效 */
> .tools-popup, >.tools-popup,
> .voice-popup, >.voice-popup,
> .avatar-selector-popup, >.avatar-selector-popup,
> .nickname-editor-popup { >.nickname-editor-popup {
pointer-events: auto; pointer-events: auto;
} }
/* 昵称编辑弹窗层级最高,避免被其他弹窗遮挡 */ /* 昵称编辑弹窗层级最高,避免被其他弹窗遮挡 */
> .nickname-editor-popup { >.nickname-editor-popup {
z-index: 1001; z-index: 1001;
} }
} }
@@ -2470,14 +2450,45 @@ $radius-lg: 36rpx;
border-radius: 4rpx; border-radius: 4rpx;
animation: none; animation: none;
&:nth-child(1) { height: 60rpx; animation-delay: 0s; } &:nth-child(1) {
&:nth-child(2) { height: 90rpx; animation-delay: 0.1s; } height: 60rpx;
&:nth-child(3) { height: 50rpx; animation-delay: 0.2s; } animation-delay: 0s;
&:nth-child(4) { height: 120rpx; animation-delay: 0.3s; } }
&:nth-child(5) { height: 70rpx; animation-delay: 0.4s; }
&:nth-child(6) { height: 100rpx; animation-delay: 0.5s; } &:nth-child(2) {
&:nth-child(7) { height: 80rpx; animation-delay: 0.6s; } height: 90rpx;
&:nth-child(8) { height: 40rpx; animation-delay: 0.7s; } animation-delay: 0.1s;
}
&:nth-child(3) {
height: 50rpx;
animation-delay: 0.2s;
}
&:nth-child(4) {
height: 120rpx;
animation-delay: 0.3s;
}
&:nth-child(5) {
height: 70rpx;
animation-delay: 0.4s;
}
&:nth-child(6) {
height: 100rpx;
animation-delay: 0.5s;
}
&:nth-child(7) {
height: 80rpx;
animation-delay: 0.6s;
}
&:nth-child(8) {
height: 40rpx;
animation-delay: 0.7s;
}
} }
} }
@@ -2645,10 +2656,13 @@ $radius-lg: 36rpx;
/* 动画定义 */ /* 动画定义 */
@keyframes dotPulse { @keyframes dotPulse {
0%, 100% {
0%,
100% {
opacity: 0.4; opacity: 0.4;
transform: scale(0.8); transform: scale(0.8);
} }
50% { 50% {
opacity: 1; opacity: 1;
transform: scale(1.2); transform: scale(1.2);
@@ -2656,10 +2670,13 @@ $radius-lg: 36rpx;
} }
@keyframes wave { @keyframes wave {
0%, 100% {
0%,
100% {
transform: scaleY(0.5); transform: scaleY(0.5);
opacity: 0.7; opacity: 0.7;
} }
50% { 50% {
transform: scaleY(1); transform: scaleY(1);
opacity: 1; opacity: 1;
@@ -2670,6 +2687,7 @@ $radius-lg: 36rpx;
0% { 0% {
left: -100%; left: -100%;
} }
100% { 100% {
left: 200%; left: 200%;
} }
@@ -2679,9 +2697,11 @@ $radius-lg: 36rpx;
0% { 0% {
background-position: 0% 50%; background-position: 0% 50%;
} }
50% { 50% {
background-position: 100% 50%; background-position: 100% 50%;
} }
100% { 100% {
background-position: 0% 50%; background-position: 0% 50%;
} }
@@ -2718,7 +2738,8 @@ $radius-lg: 36rpx;
.message-item { .message-item {
margin-bottom: 24rpx; margin-bottom: 24rpx;
.user-message, .ai-message { .user-message,
.ai-message {
.avatar { .avatar {
width: 72rpx; width: 72rpx;
height: 72rpx; height: 72rpx;

View File

@@ -0,0 +1,651 @@
<template>
<view class="ai-chat-page" :style="wrapperPageStyle">
<!--自定义导航头部 -->
<view class="custom-navbar" ref="pageHeader" v-if="showCustomNavbar">
<view class="header-left">
<button class="back-btn" v-show="showBackButton" @click="goBack">
<text class="iconfont icon-back"></text>
</button>
<!-- 占位元素确保布局平衡 -->
<view v-show="!showBackButton" class="placeholder"></view>
</view>
<view class="header-center">
<text class="header-subtitle">在线为您服务</text>
</view>
<view class="header-right">
<button class="menu-btn" v-show="showMenuButton" @click="showMenu">
<text class="iconfont icon-ellipsis"></text>
</button>
<!-- 占位元素确保布局平衡 -->
<view v-show="!showMenuButton" class="placeholder"></view>
</view>
</view>
<!-- 聊天内容区域 -->
<view class="chat-content"
:style="wrapperChatContentStyle"
>
<!-- AI聊天组件 -->
<ai-chat-message
ref="chat"
:initial-messages="initialMessages"
:user-avatar="userAvatar"
:ai-avatar="aiAvatar"
@message-sent="onMessageSent"
@ai-response="onAIResponse"
@action-click="onActionClick"
@history-loaded="onHistoryLoaded"
@file-preview="onFilePreview"
@audio-play="onAudioPlay"
@audio-pause="onAudioPause"
@video-play="onVideoPlay"
@video-pause="onVideoPause"
@link-open="onLinkOpen"
@product-view="onProductView"
@input-change="onInputChange" />
</view>
</view>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
import navigationHelper from '@/common/js/navigation';
import { EventSafety } from '@/common/js/event-safety';
import aiChatMessage from './ai-chat-message.vue';
export default {
components: {
aiChatMessage,
},
data() {
return {
initialMessages: [
{
id: 1,
role: 'ai',
type: 'text',
content: '您好我是AI智能客服很高兴为您服务\n\n我可以帮您\n• 解答产品相关问题\n• 处理订单问题\n• 提供技术支持\n• 推荐相关商品\n\n请告诉我您需要什么帮助',
timestamp: Date.now() - 60000,
actions: [
{ type: 'like', icon: 'icon-dianzan1', text: '喜欢', count: 0 },
{ type: 'dislike', icon: 'icon-dianzan1', text: '不喜欢', count: 0 }
]
}
],
// --- 系统导航栏/状态栏相关 ---
navBarHeight: 44, // uni-page-head 系统导航栏默认高度为44px
statusBarHeight: 0, // 状态栏高度默认0
// --- 自定义导航栏 ---
showCustomNavbar: true, // 是否显示自定义导航栏
showBackButton: false, // 是否显示返回按钮
showMenuButton: true, // 是否显示设置菜单按钮
// --- 聊天内容区域 ---
scrollViewHeight: '0px',
// 事件处理器引用(用于清理)
safeEventHandlers: new Map()
}
},
computed: {
...mapGetters([
'globalAIKefuConfig'
]),
/// ---- 关于AI客服的配置支持远程配置 ----
userAvatar() {
return this.globalAIKefuConfig?.userAvatar || '/static/images/user-avatar.png'
},
aiAvatar() {
return this.globalAIKefuConfig?.aiAvatar || '/static/images/ai-avatar.png'
},
/// ---- others ----
containerHeight() {
return `calc(100vh - ${this.navBarHeight + this.statusBarHeight}px)`
},
wrapperPageStyle() {
// #ifdef H5
return `top: ${this.navBarHeight + 'px'};`
// #endif
// #ifdef MP-WEIXIN
return `top: -1px;` // 微信小程序需要上移1px, 否则与系统导航栏出现1px的空隙
// #endif
return ``
},
wrapperChatContentStyle() {
return {
height: this.containerHeight,
paddingTop: this.showCustomNavbar ? '0' : (this.navHeight + 'px')
}
}
},
async onLoad(options) {
await this.initPage(options)
},
async onReady() {
await this.initNavigation()
},
onShow() {
},
onHide() {
},
onUnload() {
this.cleanup()
},
methods: {
// ========== 安全事件处理 ==========
setupSafeEventListeners() {
// 使用 EventSafety 包装事件处理器
const safeHandlers = {
serviceRequest: EventSafety.wrapEventHandler(
this.handleServiceRequest.bind(this),
{ onError: this.handleEventError.bind(this) }
),
navigationRequest: EventSafety.wrapEventHandler(
this.handleNavigationRequest.bind(this),
{ onError: this.handleEventError.bind(this) }
),
componentInteraction: EventSafety.wrapEventHandler(
this.handleComponentInteraction.bind(this),
{ onError: this.handleEventError.bind(this) }
)
}
// 注册事件监听
this.$on('service.requestComponentInfo', safeHandlers.serviceRequest)
this.$on('navigation.requestInfo', safeHandlers.navigationRequest)
this.$on('component.interaction', safeHandlers.componentInteraction)
// 保存处理器引用用于清理
this.safeEventHandlers.set('serviceRequest', safeHandlers.serviceRequest)
this.safeEventHandlers.set('navigationRequest', safeHandlers.navigationRequest)
this.safeEventHandlers.set('componentInteraction', safeHandlers.componentInteraction)
},
setupNavigationEvents() {
// 监听窗口大小变化
uni.onWindowResize((res) => {
console.log('窗口大小变化:', res.size)
this.calculateScrollViewHeight()
})
},
// ========== 事件处理方法 ==========
async handleServiceRequest(event) {
console.log('处理服务请求:', EventSafety.extractEventData(event))
// 安全地检查事件目标
if (event.matches('.service-component') ||
event.detail?.componentType === 'service') {
await this.processServiceRequest(event)
}
},
async handleNavigationRequest(event) {
console.log('处理导航请求:', event.type)
// 提供导航信息
this.emitNavigationInfo(event)
},
handleComponentInteraction(event) {
console.log('处理组件交互:', event.detail)
// 安全地处理组件交互
this.processComponentInteraction(event)
},
handleEventError(error, event) {
console.error('事件处理错误:', {
error: error.message,
eventType: event?.type,
component: this.$options.name
})
this.showError('操作失败,请重试')
},
// ========== 初始化页面 ==========
async initPage(options = {}) {
this.$langConfig.title('AI智能客服');
this.initChat()
},
// 初始化导航栏相关配置
async initNavigation() {
try {
// 获取导航栏高度
this.navBarHeight = await navigationHelper.getNavigationHeight(this, {forceRefresh: false})
// 获取状态栏高度
this.statusBarHeight = navigationHelper.getStatusBarHeight()
// 计算滚动视图高度
this.calculateScrollViewHeight()
// 注册导航相关事件
this.setupNavigationEvents()
} catch (error) {
console.error('初始化导航栏失败:', error)
this.setFallbackNavigationValues()
}
},
// 计算滚动视图高度
calculateScrollViewHeight() {
const safeArea = navigationHelper.getSafeAreaInsets()
const bottomInset = safeArea.bottom || 0
const inputHeight = 120 // 输入区域高度
this.scrollViewHeight = `calc(100vh - ${this.navBarHeight + this.statusBarHeight + inputHeight + bottomInset}px)`
},
// 备用高度设置
setFallbackNavigationValues() {
// #ifdef MP-WEIXIN
this.navBarHeight = 44
this.statusBarHeight = 20
// #endif
// #ifdef H5
this.navBarHeight = 44
this.statusBarHeight = 0
// #endif
// #ifdef APP-PLUS
this.navBarHeight = 88
this.statusBarHeight = 44
// #endif
},
cleanup() {
// 清理事件监听器
this.safeEventHandlers.forEach((handler, eventType) => {
this.$off(eventType, handler)
})
this.safeEventHandlers.clear()
console.log('组件清理完成')
},
showError(message) {
uni.showToast({
title: message,
icon: 'none',
duration: 2000
})
},
// 初始化聊天
initChat() {
// 可以在这里加载历史消息
console.log('AI聊天页面初始化')
},
// 返回上一页
goBack() {
uni.navigateBack()
},
// 显示菜单
showMenu() {
uni.showActionSheet({
itemList: ['清空聊天', '导出记录', '设置', '帮助'],
success: (res) => {
switch (res.tapIndex) {
case 0:
this.clearChat()
break
case 1:
this.exportChat()
break
case 2:
this.showSettings()
break
case 3:
this.showHelp()
break
}
}
})
},
// 清空聊天
clearChat() {
uni.showModal({
title: '提示',
content: '确定要清空聊天记录吗?',
success: (res) => {
if (res.confirm) {
this.$refs.chat.clearMessages()
// 重新添加欢迎消息
this.$refs.chat.addMessage({
id: Date.now(),
role: 'ai',
type: 'text',
content: '聊天记录已清空,有什么可以帮助您的吗?',
timestamp: Date.now()
})
}
}
})
},
// 导出聊天记录
exportChat() {
uni.showToast({
title: '功能开发中',
icon: 'none'
})
},
// 显示设置
showSettings() {
uni.navigateTo({
url: '/pages/settings/index'
})
},
// 显示帮助
showHelp() {
const helpMessage = {
id: Date.now(),
role: 'ai',
type: 'markdown',
content: `# 使用帮助
## 基本功能
- **发送消息**: 在输入框中输入文字后发送
- **语音输入**: 点击麦克风图标进行语音输入
- **附件发送**: 点击+号可以发送图片、文件、位置
## 消息类型
- **文本消息**: 普通文字对话
- **Markdown**: 支持格式化的文档内容
- **文件**: 支持各种文件格式预览
- **音频**: 支持语音消息播放
- **视频**: 支持视频播放
- **链接**: 支持网页链接跳转
- **商品**: 支持商品卡片展示
## 操作功能
- **点赞/踩**: 对AI回复进行评价
- **复制**: 长按消息可复制内容
- **转发**: 支持消息转发功能`,
timestamp: Date.now()
}
this.$refs.chat.addMessage(helpMessage)
},
// 用户发送消息
onMessageSent(message) {
console.log('用户发送消息:', message)
// 使用AI服务获取回复
// AI聊天组件内部已经集成了AI服务这里只需要监听事件
},
// AI回复消息
onAIResponse(message) {
console.log('AI回复消息:', message)
// 可以在这里处理AI回复后的逻辑
// 比如记录对话、更新状态等
},
// 生成AI回复
generateAIResponse(userMessage) {
const responses = [
'我理解您的需求,让我为您详细解答。',
'感谢您的提问,这是一个很好的问题。',
'根据您的问题,我建议您可以考虑以下几个方面:',
'这个问题很常见,让我为您提供一些解决方案。',
'我明白您的困惑,让我帮您分析一下。'
]
const randomResponse = responses[Math.floor(Math.random() * responses.length)]
const aiMessage = {
id: Date.now(),
role: 'ai',
type: 'text',
content: `${randomResponse}\n\n您的问题"${userMessage.content}"我已经收到,正在为您处理中...`,
timestamp: Date.now(),
actions: [
{ type: 'like', count: 0 },
{ type: 'dislike', count: 0 }
]
}
this.$refs.chat.addMessage(aiMessage)
this.$emit('ai-response', aiMessage)
},
// 操作按钮点击
onActionClick({ action, message }) {
console.log('操作点击:', action, message)
switch (action.type) {
case 'like':
uni.showToast({
title: '感谢您的反馈!',
icon: 'success'
})
break
case 'dislike':
uni.showToast({
title: '我们会改进服务',
icon: 'none'
})
break
}
},
// 历史消息加载完成
onHistoryLoaded(messages) {
console.log('历史消息加载完成:', messages.length)
},
// 文件预览
onFilePreview(message) {
console.log('文件预览:', message)
uni.showToast({
title: '打开文件: ' + message.fileName,
icon: 'none'
})
},
// 音频播放
onAudioPlay(message) {
console.log('音频播放:', message)
},
// 音频暂停
onAudioPause(message) {
console.log('音频暂停:', message)
},
// 视频播放
onVideoPlay(message) {
console.log('视频播放:', message)
},
// 视频暂停
onVideoPause(message) {
console.log('视频暂停:', message)
},
// 链接打开
onLinkOpen(message) {
console.log('链接打开:', message)
uni.showModal({
title: '打开链接',
content: `确定要打开链接:${message.url} 吗?`,
success: (res) => {
if (res.confirm) {
// #ifdef H5
window.open(message.url, '_blank')
// #endif
// #ifdef APP-PLUS
plus.runtime.openURL(message.url)
// #endif
}
}
})
},
// 商品查看
onProductView(message) {
console.log('商品查看:', message)
uni.showToast({
title: '查看商品: ' + message.title,
icon: 'none'
})
},
// 输入内容变化
onInputChange(value) {
console.log('输入内容:', value)
}
}
}
</script>
<style lang="scss">
/* 引入图标字体 */
@import url('@/common/css/iconfont.css');
/* 页面样式 */
.ai-chat-page {
display: flex;
flex-direction: column;
background-color: #f8f8f8;
overflow: hidden;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/* 自定义导航头部 */
.custom-navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 30rpx;
background-color: white;
border-bottom: 2rpx solid #eeeeee;
.header-left {
flex: 0 0 auto;
display: flex;
align-items: center;
.back-btn {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background-color: #f8f8f8;
display: flex;
align-items: center;
justify-content: center;
.iconfont {
font-size: 32rpx;
color: #666;
}
}
.placeholder {
width: 120rpx;
height: 60rpx;
}
}
.header-center {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 20rpx;
.header-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.header-subtitle {
font-size: 24rpx;
color: #999;
}
}
.header-right {
flex: 0 0 auto;
display: flex;
align-items: center;
.menu-btn {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background-color: #f8f8f8;
display: flex;
align-items: center;
justify-content: center;
.iconfont {
font-size: 32rpx;
color: #666;
}
}
.placeholder {
width: 120rpx;
height: 60rpx;
}
}
}
/* 聊天内容区域 */
.chat-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/* 底部tabBar占位样式 */
.page-bottom {
width: 100%;
background-color: transparent;
}
</style>

View File

@@ -114,7 +114,7 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/deep/ .fixed { ::v-deep .fixed {
position: relative; position: relative;
top: 0; top: 0;
} }

View File

@@ -11,7 +11,8 @@
style="background: #1daa39;width: 100%;border-radius: 10rpx;"> style="background: #1daa39;width: 100%;border-radius: 10rpx;">
<view class="bl bor" style="box-sizing: border-box;"> <view class="bl bor" style="box-sizing: border-box;">
<image mode="heightFix" :src="$util.img('public/static/img/liuyan.png')"></image> <image mode="heightFix" :src="$util.img('public/static/img/liuyan.png')"></image>
<view class="name bl line1" style="margin-top: 6rpx;">{{ $lang('onlineMessage') }}</view> <view class="name bl line1" style="margin-top: 6rpx;">{{ $lang('onlineMessage') }}
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -28,7 +29,8 @@
<view @click="tapMessage" class="view_li w50_li text-center"> <view @click="tapMessage" class="view_li w50_li text-center">
<view class="bl bor" style="box-sizing: border-box;"> <view class="bl bor" style="box-sizing: border-box;">
<image mode="heightFix" :src="$util.img('public/static/img/liuyan.png')"></image> <image mode="heightFix" :src="$util.img('public/static/img/liuyan.png')"></image>
<view class="name bl line1" style="margin-top: 6rpx;">{{ $lang('onlineMessage') }}</view> <view class="name bl line1" style="margin-top: 6rpx;">{{ $lang('onlineMessage') }}
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -52,7 +54,8 @@
<image mode="widthFix" :src="$util.img('public/static/img/boda.png')" <image mode="widthFix" :src="$util.img('public/static/img/boda.png')"
style="margin-top: 8rpx;margin-right: 10rpx;"></image> style="margin-top: 8rpx;margin-right: 10rpx;"></image>
<view style="flex: 1;">{{ item.mobile }}</view> <view style="flex: 1;">{{ item.mobile }}</view>
<view class="btn-container" @click="Tel(item.mobile)"><span class="contact-btn" style="background: #0054a5;">{{ $lang('call') }}</span> <view class="btn-container" @click="Tel(item.mobile)"><span class="contact-btn"
style="background: #0054a5;">{{ $lang('call') }}</span>
</view> </view>
</view> </view>
<view class="contact_name" v-if="item.email" <view class="contact_name" v-if="item.email"
@@ -60,7 +63,8 @@
<image mode="widthFix" :src="$util.img('public/static/img/emall.png')" <image mode="widthFix" :src="$util.img('public/static/img/emall.png')"
style="margin-top: 8rpx;margin-right: 10rpx;"></image> style="margin-top: 8rpx;margin-right: 10rpx;"></image>
<view style="flex: 1;">{{ item.email }}</view> <view style="flex: 1;">{{ item.email }}</view>
<view class="btn-container" @click="copy(item.email)"><span class="contact-btn" style="background: #0054a5;">{{ $lang('copy') }}</span> <view class="btn-container" @click="copy(item.email)"><span class="contact-btn"
style="background: #0054a5;">{{ $lang('copy') }}</span>
</view> </view>
</view> </view>
</view> </view>
@@ -72,11 +76,13 @@
<view class="section-title">企业文件</view> <view class="section-title">企业文件</view>
<view class="files-list"> <view class="files-list">
<view v-for="(file, index) in fileList" :key="index" class="file-item"> <view v-for="(file, index) in fileList" :key="index" class="file-item">
<image mode="aspectFill" :src="$util.img('public/static/img/pdf-icon.png')" class="file-icon"></image> <image mode="aspectFill" :src="$util.img('public/static/img/pdf-icon.png')"
class="file-icon"></image>
<view class="file-info"> <view class="file-info">
<view class="file-name">{{ file.name }}</view> <view class="file-name">{{ file.name }}</view>
<view class="file-actions"> <view class="file-actions">
<button class="file-btn share-btn" @click="shareFile(file)">{{ $lang('share') }}</button> <button class="file-btn share-btn" @click="shareFile(file)">{{ $lang('share')
}}</button>
</view> </view>
</view> </view>
</view> </view>
@@ -86,10 +92,12 @@
<view class="view_videos_container" v-if="showVideoListDiy && videoList.length > 0"> <view class="view_videos_container" v-if="showVideoListDiy && videoList.length > 0">
<view class="section-title">企业视频</view> <view class="section-title">企业视频</view>
<view class="videos-list"> <view class="videos-list">
<view v-for="(video, index) in videoList" :key="index" class="video-item" @click="playVideo(video)"> <view v-for="(video, index) in videoList" :key="index" class="video-item"
@click="playVideo(video)">
<image mode="aspectFill" :src="video.coverUrl" class="video-cover"></image> <image mode="aspectFill" :src="video.coverUrl" class="video-cover"></image>
<view class="video-play-btn"> <view class="video-play-btn">
<image mode="aspectFill" :src="$util.img('public/static/img/play-icon.png')" class="play-icon"></image> <image mode="aspectFill" :src="$util.img('public/static/img/play-icon.png')"
class="play-icon"></image>
</view> </view>
<view class="video-title">{{ video.title }}</view> <view class="video-title">{{ video.title }}</view>
</view> </view>
@@ -101,12 +109,12 @@
<diy-channel-list :value="{ <diy-channel-list :value="{
list: channelList, list: channelList,
showStyle: diyChannelSettings.channel_display_style, showStyle: diyChannelSettings.channel_display_style,
rowCount: diyChannelSettings.channel_row_count, rowCount: parseInt(diyChannelSettings.channel_row_count),
aspectRatio: diyChannelSettings.channel_aspect_ratio, aspectRatio: diyChannelSettings.channel_aspect_ratio,
showViewCount: diyChannelSettings.channel_show_view_count, showViewCount: Boolean(diyChannelSettings.channel_show_view_count),
titleLineClamp: diyChannelSettings.channel_title_line_clamp, titleLineClamp: parseInt(diyChannelSettings.channel_title_line_clamp),
showPlayBtn: diyChannelSettings.channel_show_play_btn, showPlayBtn: Boolean(diyChannelSettings.channel_show_play_btn),
}" @channel-video-click-play="onChannelVideoClickPlay"/> }" @channel-video-click-play="onChannelVideoClickPlay" />
</view> </view>
<!-- 地图 --> <!-- 地图 -->
@@ -115,13 +123,14 @@
:longitude="shop.longitude" :latitude="shop.latitude" show-location> :longitude="shop.longitude" :latitude="shop.latitude" show-location>
<cover-view <cover-view
style="position:absolute;right:10px;bottom:30rpx;z-index:9;background:#4d83ff;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;" style="position:absolute;right:10px;bottom:30rpx;z-index:9;background:#4d83ff;padding:5px 10px;wxcs_style_padding:10rpx 20rpx;border-radius:8rpx;color: #fff;"
@click="tomap"><cover-view style="font-size:24rpx">{{ $lang('oneClickNavigation') }}</cover-view> @click="tomap"><cover-view style="font-size:24rpx">{{ $lang('oneClickNavigation')
}}</cover-view>
</cover-view> </cover-view>
</map> </map>
</view> </view>
</view> </view>
</view> </view>
<!--留言弹窗--> <!--留言弹窗-->
<view class="goods-sku"> <view class="goods-sku">
<uni-popup ref="informationPopup" type="bottom" @change="change"> <uni-popup ref="informationPopup" type="bottom" @change="change">
@@ -136,50 +145,35 @@
<view class="fui-cell "> <view class="fui-cell ">
<view class="fui-cell-label ">{{ $lang('name') }}</view> <view class="fui-cell-label ">{{ $lang('name') }}</view>
<view class="fui-cell-info"> <view class="fui-cell-info">
<input <input id="input-realname" :value="Form.realname"
id="input-realname" @input="e => Form.realname = e.detail.value" class="fui-input"
:value="Form.realname" :placeholder="$lang('pleaseEnterName')" :key="formKey" />
@input="e => Form.realname = e.detail.value"
class="fui-input"
:placeholder="$lang('pleaseEnterName')"
:key="formKey"
/>
</view> </view>
</view> </view>
<view class="fui-cell "> <view class="fui-cell ">
<view class="fui-cell-label">{{ $lang('contactInfo') }}</view> <view class="fui-cell-label">{{ $lang('contactInfo') }}</view>
<view class="fui-cell-info"> <view class="fui-cell-info">
<input <input id="input-mobile" :value="Form.mobile"
id="input-mobile" @input="e => Form.mobile = e.detail.value" class="fui-input" maxlength="11"
:value="Form.mobile" :placeholder="$lang('pleaseEnterMobile')" type="number" :key="formKey" />
@input="e => Form.mobile = e.detail.value"
class="fui-input"
maxlength="11"
:placeholder="$lang('pleaseEnterMobile')"
type="number"
:key="formKey"
/>
</view> </view>
</view> </view>
<view class="fui-cell "> <view class="fui-cell ">
<view class="fui-cell-label" style="position: absolute;top:10px">{{ $lang('messageContent') }}</view> <view class="fui-cell-label" style="position: absolute;top:10px">{{
$lang('messageContent') }}</view>
<view class="fui-cell-info" style="margin-left: 160rpx;border: solid 2rpx #eee;"> <view class="fui-cell-info" style="margin-left: 160rpx;border: solid 2rpx #eee;">
<!-- <input v-model="Form.mailbox" class="fui-input" placeholder="请输入您的邮箱" type="text" ></input> --> <!-- <input v-model="Form.mailbox" class="fui-input" placeholder="请输入您的邮箱" type="text" ></input> -->
<textarea <textarea id="textarea-remark" :value="Form.remark"
id="textarea-remark" @input="e => Form.remark = e.detail.value" class="textarea"
:value="Form.remark" :placeholder="$lang('pleaseEnterMessage')"
@input="e => Form.remark = e.detail.value" style="font-size: 28rpx;padding: 10rpx;" :key="formKey"></textarea>
class="textarea"
:placeholder="$lang('pleaseEnterMessage')"
style="font-size: 28rpx;padding: 10rpx;"
:key="formKey"
></textarea>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
<view class="button-box"><button type="primary" @click="save()">{{ $lang('submit') }}</button></view> <view class="button-box"><button type="primary" @click="save()">{{ $lang('submit') }}</button>
</view>
</view> </view>
</uni-popup> </uni-popup>
</view> </view>
@@ -188,15 +182,14 @@
<diy-bottom-nav></diy-bottom-nav> <diy-bottom-nav></diy-bottom-nav>
<!-- 视频播放弹窗 --> <!-- 视频播放弹窗 -->
<ns-video-player-popup <ns-video-player-popup ref="videoPlayerPopup" :current-video="currentVideo"
ref="videoPlayerPopup" @popup-change="onVideoPopupChange"></ns-video-player-popup>
:current-video="currentVideo"
@popup-change="onVideoPopupChange"
></ns-video-player-popup>
</view> </view>
</template> </template>
<script> <script>
import { copyText, makePhoneCall, openLocation } from '@/common/js/uniapp.utils.js';
import scroll from '@/common/js/scroll-view.js'; import scroll from '@/common/js/scroll-view.js';
import shareUtil from '@/common/js/share.js'; import shareUtil from '@/common/js/share.js';
@@ -220,11 +213,11 @@ export default {
diyChannelSettings: { diyChannelSettings: {
channel_display_style: 'fixed', channel_display_style: 'fixed',
channel_aspect_ratio: '16:9', channel_aspect_ratio: '16:9',
channel_show_view_count: true, channel_show_view_count: true,
channel_row_count: 2, channel_row_count: 2,
channel_title_line_clamp: 2, channel_title_line_clamp: 2,
channel_show_play_btn: true, channel_show_play_btn: true,
}, // 自定义设置 }, // 自定义设置
ismessage: 0, ismessage: 0,
@@ -238,16 +231,16 @@ export default {
markers: [ markers: [
{ {
id: 1, id: 1,
/* width:20, //宽度 /* width:20, //宽度
height:20, //高度*/ height:20, //高度*/
// iconPath: '../../static/goal_weizhi.png', //目标位置图标路径 // iconPath: '../../static/goal_weizhi.png', //目标位置图标路径
//这里的经纬度是 目的地 的经纬度 //这里的经纬度是 目的地 的经纬度
latitude: 0, latitude: 0,
longitude: 0, longitude: 0,
callout: { callout: {
/* title:123, /* title:123,
content:'123' */ content:'123' */
} }
} }
], ],
landline: 0, landline: 0,
@@ -259,6 +252,7 @@ export default {
}; };
}, },
onLoad(option) { onLoad(option) {
this.$util.hideHomeButton();
this.$langConfig.refresh(); this.$langConfig.refresh();
this.$api.sendRequest({ this.$api.sendRequest({
url: '/api/member/personnel', url: '/api/member/personnel',
@@ -305,9 +299,12 @@ export default {
} }
} }
}, },
fail: res => {} fail: res => { }
}); });
}, },
onShow() {
this.$util.hideHomeButton();
},
methods: { methods: {
// 分享文件 // 分享文件
shareFile(file) { shareFile(file) {
@@ -439,36 +436,15 @@ export default {
}, },
Tel(m) { Tel(m) {
uni.makePhoneCall({ makePhoneCall(m);
phoneNumber: m + '',
success(e) {
console.log(e);
}
});
}, },
copy(text) { copy(text) {
uni.setClipboardData({ copyText(text, { copySuccess: this.$lang('copySuccess'), copyFailed: this.$lang('copyFailed') });
data: text,
success: () => {
uni.showToast({
title: this.$lang('copySuccess'),
icon: 'success',
duration: 2000
});
},
fail: (err) => {
uni.showToast({
title: err.message || err.errMsg || this.$lang('copyFailed'),
icon: 'none',
duration: 2000
});
}
});
}, },
tomap() { tomap() {
uni.openLocation({ openLocation({
latitude: parseFloat(this.shop.latitude), latitude: parseFloat(this.shop.latitude),
longitude: parseFloat(this.shop.longitude), longitude: parseFloat(this.shop.longitude),
name: this.$lang('oneClickNavigation'), name: this.$lang('oneClickNavigation'),
@@ -625,12 +601,13 @@ image {
position: relative; position: relative;
z-index: 0; z-index: 0;
} }
image { image {
max-width: 100%; max-width: 100%;
} }
.bl { .bl {
display: block; display: block;
} }
.line1 { .line1 {
@@ -669,12 +646,13 @@ image {
line-height: 20rpx; line-height: 20rpx;
border-radius: 10rpx; border-radius: 10rpx;
} }
.view_ul_100 .fl { .view_ul_100 .fl {
width: 10%; width: 10%;
} }
.view_ul_100 .fr { .view_ul_100 .fr {
/* padding-left: 30rpx;*/ /* padding-left: 30rpx;*/
width: 100%; width: 100%;
} }
@@ -696,25 +674,27 @@ image {
.list_cotact .view_ul_100>view { .list_cotact .view_ul_100>view {
padding: 20rpx 30rpx 0rpx 30rpx; padding: 20rpx 30rpx 0rpx 30rpx;
} }
.list_cotact .view_ul_two .view_li>view { .list_cotact .view_ul_two .view_li>view {
background-color: #fff; background-color: #fff;
padding: 20rpx 30rpx 0rpx 30rpx; padding: 20rpx 30rpx 0rpx 30rpx;
} }
.list_cotact .view_ul_two .view_li>view .address { .list_cotact .view_ul_two .view_li>view .address {
background-color: #5dc2d0; background-color: #5dc2d0;
color: #fff; color: #fff;
display: inline-block; display: inline-block;
font-size: 28rpx; font-size: 28rpx;
line-height: 48rpx; line-height: 48rpx;
margin-bottom: 30rpx; margin-bottom: 30rpx;
padding: 0 30rpx; padding: 0 30rpx;
width: auto; width: auto;
} }
.view_ul_two { .view_ul_two {
margin-top: 20rpx; margin-top: 20rpx;
} }
.contact_name { .contact_name {
color: rgba(71, 71, 71, .79); color: rgba(71, 71, 71, .79);
font-size: 24rpx; font-size: 24rpx;
@@ -883,11 +863,11 @@ image {
} }
} }
/deep/ .channel-list { ::v-deep .channel-list-container {
padding: 0rpx !important; padding: 0rpx !important;
} }
/deep/ .mescroll-totop { ::v-deep .mescroll-totop {
right: 27rpx !important; right: 27rpx !important;
/* #ifdef H5 */ /* #ifdef H5 */
bottom: 120rpx !important; bottom: 120rpx !important;
@@ -896,5 +876,4 @@ image {
bottom: 180rpx !important; bottom: 180rpx !important;
/* #endif */ /* #endif */
} }
</style> </style>

View File

@@ -138,7 +138,7 @@
border-radius: 80rpx; border-radius: 80rpx;
} }
/deep/ .form-wrap { ::v-deep .form-wrap {
background: #fff; background: #fff;
padding: 30rpx; padding: 30rpx;
border-radius: 32rpx; border-radius: 32rpx;

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