-
diff --git a/components-diy/diy-channel-list.vue b/components-diy/diy-channel-list.vue
index de6746e..f114b2c 100644
--- a/components-diy/diy-channel-list.vue
+++ b/components-diy/diy-channel-list.vue
@@ -6,13 +6,13 @@
:duration="value.carousel.duration || 500" :circular="value.carousel.circular || false"
:style="swiperHeight" class="channel-swiper">
-
-
-
-
+
+
+
+
@@ -22,9 +22,9 @@
-
@@ -36,9 +36,9 @@
-
@@ -190,6 +190,25 @@ export default {
}
return slides;
+ },
+ /**
+ * 视频封面样式
+ * 根据aspectRatio属性动态计算封面样式
+ * @returns {Object} 封面样式对象
+ */
+ computedCoverStyle() {
+ const aspectRatio = this.value?.aspectRatio || '16:9';
+ let paddingTop = '56.25%'; // 默认 16:9 比例
+
+ if (aspectRatio === '3:4') {
+ paddingTop = '133.33%'; // 3:4 比例
+ }
+
+ return {
+ width: '100%',
+ height: '0',
+ paddingTop: paddingTop
+ };
}
},
methods: {
@@ -259,69 +278,12 @@ export default {
/**
* 列表布局样式
- * 支持 2 列和 3 列布局
*/
.channel-list {
- display: flex;
- flex-wrap: wrap;
- gap: 16rpx;
- padding: 32rpx;
- box-sizing: border-box;
-
- .channel-item {
- // 默认 3 列布局
- flex: 0 0 calc(33.3333333% - 10rpx);
- box-sizing: border-box;
-
- &:nth-child(3n) {
- margin-right: 0;
- }
- }
-
- // 2 列布局
- &.row1-of2 {
- .channel-item {
- flex: 0 0 calc(50% - 8rpx);
-
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(2n) {
- margin-right: 0;
- }
- }
- }
-
- // 4 列布局
- &.row1-of4 {
- .channel-item {
- flex: 0 0 calc(25% - 12rpx);
-
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(4n) {
- margin-right: 0;
- }
- }
- }
-
- // 1 列布局
- &.row1-of1 {
- .channel-item {
- flex: 0 0 100%;
-
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(1n) {
- margin-right: 0;
- }
- }
- }
+ display: grid;
+ grid-template-columns: repeat(var(--row-count, 2), 1fr);
+ gap: 8px;
+ padding: 16px 16px 0px;
}
/**
@@ -333,15 +295,17 @@ export default {
box-sizing: border-box;
.uni-scroll-view-content {
- display: flex;
- flex-wrap: wrap;
+ display: grid;
+ grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 16rpx;
}
// 单滑动模式
&.singleSlide {
.uni-scroll-view-content {
+ display: flex;
flex-wrap: nowrap;
+ gap: 16rpx;
}
.channel-nav-item {
@@ -354,56 +318,33 @@ export default {
display: flex;
flex-direction: column;
box-sizing: border-box;
- // 默认 3 列布局
- flex: 0 0 calc(33.3333333% - 10rpx);
+ }
- &:nth-child(3n) {
- margin-right: 0;
+ // 1 列布局
+ &.row1-of1 {
+ .uni-scroll-view-content {
+ grid-template-columns: 1fr;
}
}
// 2 列布局
&.row1-of2 {
- .channel-nav-item {
- flex: 0 0 calc(50% - 8rpx);
+ .uni-scroll-view-content {
+ grid-template-columns: repeat(2, 1fr);
+ }
+ }
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(2n) {
- margin-right: 0;
- }
+ // 3 列布局
+ &.row1-of3 {
+ .uni-scroll-view-content {
+ grid-template-columns: repeat(3, 1fr);
}
}
// 4 列布局
&.row1-of4 {
- .channel-nav-item {
- flex: 0 0 calc(25% - 12rpx);
-
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(4n) {
- margin-right: 0;
- }
- }
- }
-
- // 1 列布局
- &.row1-of1 {
- .channel-nav-item {
- flex: 0 0 100%;
-
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(1n) {
- margin-right: 0;
- }
+ .uni-scroll-view-content {
+ grid-template-columns: repeat(4, 1fr);
}
}
}
@@ -426,65 +367,36 @@ export default {
box-sizing: border-box;
.swiper-slide-content {
- display: flex;
- flex-wrap: wrap;
+ display: grid;
+ grid-template-columns: repeat(var(--row-count, 2), 1fr);
gap: 16rpx;
padding: 16rpx;
box-sizing: border-box;
.channel-item {
- // 默认 3 列布局
- flex: 0 0 calc(33.3333333% - 10rpx);
+ display: flex;
+ flex-direction: column;
box-sizing: border-box;
-
- &:nth-child(3n) {
- margin-right: 0;
- }
- }
-
- // 轮播模式下的 2 列布局
- &.row1-of2 {
- .channel-item {
- flex: 0 0 calc(50% - 8rpx);
-
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(2n) {
- margin-right: 0;
- }
- }
- }
-
- // 轮播模式下的 4 列布局
- &.row1-of4 {
- .channel-item {
- flex: 0 0 calc(25% - 12rpx);
-
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
-
- &:nth-child(4n) {
- margin-right: 0;
- }
- }
}
// 轮播模式下的 1 列布局
&.row1-of1 {
- .channel-item {
- flex: 0 0 100%;
+ grid-template-columns: 1fr;
+ }
- &:nth-child(3n) {
- margin-right: 16rpx;
- }
+ // 轮播模式下的 2 列布局
+ &.row1-of2 {
+ grid-template-columns: repeat(2, 1fr);
+ }
- &:nth-child(1n) {
- margin-right: 0;
- }
- }
+ // 轮播模式下的 3 列布局
+ &.row1-of3 {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ // 轮播模式下的 4 列布局
+ &.row1-of4 {
+ grid-template-columns: repeat(4, 1fr);
}
}
}
@@ -500,76 +412,54 @@ export default {
.channel-swiper .swiper-slide-content {
gap: 12rpx;
padding: 12rpx;
-
- .channel-item,
- .channel-nav-item {
- // 默认 3 列布局
- flex: 0 0 calc(33.3333333% - 8rpx);
-
- &:nth-child(3n) {
- margin-right: 0;
- }
- }
-
- // 小屏幕上的 2 列布局
- &.row1-of2 {
-
- .channel-item,
- .channel-nav-item {
- flex: 0 0 calc(50% - 6rpx);
-
- &:nth-child(3n) {
- margin-right: 12rpx;
- }
-
- &:nth-child(2n) {
- margin-right: 0;
- }
- }
- }
-
- // 小屏幕上的 4 列布局
- &.row1-of4 {
-
- .channel-item,
- .channel-nav-item {
- flex: 0 0 calc(25% - 9rpx);
-
- &:nth-child(3n) {
- margin-right: 12rpx;
- }
-
- &:nth-child(4n) {
- margin-right: 0;
- }
- }
- }
-
- // 小屏幕上的 1 列布局
- &.row1-of1 {
-
- .channel-item,
- .channel-nav-item {
- flex: 0 0 100%;
-
- &:nth-child(3n) {
- margin-right: 12rpx;
- }
-
- &:nth-child(1n) {
- margin-right: 0;
- }
- }
- }
}
// 小屏幕上的单滑动模式
.channel-nav {
&.singleSlide {
+ .uni-scroll-view-content {
+ gap: 12rpx;
+ }
+
.channel-nav-item {
width: 240rpx;
}
}
}
}
+
+/**
+ * 视频比例样式调整
+ * 根据不同的视频比例调整布局
+ */
+
+// // 3:4 比例的视频卡片样式
+// .channel-video.ratio-3-4 {
+// // 调整视频卡片的整体高度
+// /deep/ .video-cover-wrap {
+// padding-top: 133.33%; // 3:4 比例
+// }
+
+// // 列表模式下的3:4比例调整
+// &.list-mode {
+// /deep/ .video-cover-wrap {
+// padding-top: 133.33%; // 3:4 比例
+// }
+// }
+// }
+
+// // 16:9 比例的视频卡片样式(默认)
+// .channel-video.ratio-16-9 {
+// // 保持默认的16:9比例
+// /deep/ .video-cover-wrap {
+// padding-top: 56.25%; // 16:9 比例
+// }
+
+// // 列表模式下的16:9比例保持默认
+// &.list-mode {
+// /deep/ .video-cover-wrap {
+// padding-top: 56.25%; // 16:9 比例
+// }
+// }
+// }
\ No newline at end of file
diff --git a/components-diy/diy-channel-video.vue b/components-diy/diy-channel-video.vue
index 1b8f143..cb1de1f 100644
--- a/components-diy/diy-channel-video.vue
+++ b/components-diy/diy-channel-video.vue
@@ -2,7 +2,7 @@
-
+
@@ -23,11 +23,10 @@
-
+
-
-
-
+
+
{{ value.viewCount }}次观看
@@ -81,15 +80,6 @@ export default {
type: Boolean,
default: false
},
- /**
- * 视频高度(仅适用于嵌入式播放)
- * @type {number}
- * @default 220
- */
- videoHeight: {
- type: Number,
- default: 220
- },
/**
* 标题显示行数
* @type {number}
@@ -104,17 +94,6 @@ export default {
type: Boolean,
default: true
},
- /**
- * 视频比例
- * @type {string}
- * @default '16:9'
- * @options '16:9', '3:4'
- */
- aspectRatio: {
- type: String,
- default: '16:9',
- validator: (value) => ['16:9', '3:4'].includes(value)
- },
/**
* 视频封面图样式
* 采用 16:9 比例的响应式高度
@@ -159,32 +138,6 @@ export default {
return enableEmbedMode;
// #endif
return false
- },
- /**
- * 播放按钮图标
- * @returns {string}
- */
- playIcon() {
- // #ifdef MP-WEIXIN
- return wechatChannelConfig.icon.playIcon
- // #endif
- return ''
- },
- /**
- * 计算视频封面类名
- * 根据环境和宽高比生成适当的 CSS 类
- * @returns {Array}
- */
- videoCoverClass() {
- const classes = [];
- // #ifdef MP-WEIXIN
- classes.push('mp-weixin');
- // #endif
- // #ifndef MP-WEIXIN
- classes.push('h5');
- // #endif
- classes.push(`ratio-${this.aspectRatio.replace(':', '-')}`);
- return classes;
}
},
methods: {
@@ -202,31 +155,6 @@ export default {
\ No newline at end of file
+// }
\ No newline at end of file
From c6a8bc04f24832da969aeb83c26c3bee8802dc6d Mon Sep 17 00:00:00 2001
From: jinhhanhan <1683105490@qq.com>
Date: Thu, 15 Jan 2026 14:08:32 +0800
Subject: [PATCH 077/100] =?UTF-8?q?chore=EF=BC=9A=E8=A7=A3=E5=86=B3?=
=?UTF-8?q?=E4=BA=86siteInfo=EF=BC=8CbgUrl=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pages/index/index.vue | 499 +++++++++++++++++++++---------------------
1 file changed, 254 insertions(+), 245 deletions(-)
diff --git a/pages/index/index.vue b/pages/index/index.vue
index cdab934..cde454c 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -1,246 +1,255 @@
-
-
-
-
-
-
-
-
-
- {{ siteInfo.site_name }}
- {{ followOfficialAccount.welcomeMsg }}
-
-
- {{ isEnEnv ? 'Follow Official Account' : '关注公众号'
- }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 关注了解更多
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
\ No newline at end of file
From b3cc86d088d427a8a63c350db8c27ab6c574689f Mon Sep 17 00:00:00 2001
From: ZF sun <34314687@qq.com>
Date: Thu, 15 Jan 2026 14:37:39 +0800
Subject: [PATCH 078/100] chore: .local.config.js.example
---
.local.config.js.example | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/.local.config.js.example b/.local.config.js.example
index 28cf028..6386cb0 100644
--- a/.local.config.js.example
+++ b/.local.config.js.example
@@ -38,6 +38,10 @@ const localDevConfig = ({
uniacid: 1,
domain: 'https://test.aigc-quickapp.com',
},
+ 'local-2': { // 测试平台
+ uniacid: 2,
+ domain: 'http://localhost:8050/',
+ },
})['2811']; // 选择要使用的环境配置
export default localDevConfig;
\ No newline at end of file
From 28359f2f1624c637d3b4d1d577e4cabee5807f8e Mon Sep 17 00:00:00 2001
From: ZF sun <34314687@qq.com>
Date: Thu, 15 Jan 2026 14:58:36 +0800
Subject: [PATCH 079/100] =?UTF-8?q?fix(=E8=A7=86=E9=A2=91=E5=8F=B7?=
=?UTF-8?q?=E7=BB=84=E4=BB=B6):=20=E6=95=B4=E4=BD=93=E6=8E=A7=E5=88=B6?=
=?UTF-8?q?=E6=98=AF=E5=90=A6=E6=98=BE=E7=A4=BA=E8=A7=82=E7=9C=8B=E6=AC=A1?=
=?UTF-8?q?=E6=95=B0=E6=B2=A1=E6=9C=89=E7=94=9F=E6=95=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components-diy/diy-channel-list.vue | 4 ++++
components-diy/diy-channel-video.vue | 11 ++++++++---
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/components-diy/diy-channel-list.vue b/components-diy/diy-channel-list.vue
index c4c47b6..fa4c049 100644
--- a/components-diy/diy-channel-list.vue
+++ b/components-diy/diy-channel-list.vue
@@ -11,6 +11,7 @@
@@ -24,6 +25,7 @@
@@ -38,6 +40,7 @@
@@ -71,6 +74,7 @@ export default {
* @property {number} topAroundRadius - 顶部圆角半径
* @property {number} bottomAroundRadius - 底部圆角半径
* @property {Object} ornament - 装饰效果配置
+ * @property {boolean} showViewCount - 是否显示播放量,可选值:true, false
* @property {number} titleLineClamp - 标题显示行数
* @property {string} aspectRatio - 视频比例,可选值:16:9, 3:4
* @property {boolean} showPlayBtn - 是否显示播放按钮
diff --git a/components-diy/diy-channel-video.vue b/components-diy/diy-channel-video.vue
index cb1de1f..66d1061 100644
--- a/components-diy/diy-channel-video.vue
+++ b/components-diy/diy-channel-video.vue
@@ -17,7 +17,7 @@
{{ value.videoTitle }}
- {{ value.viewCount }}次观看
+ {{ value.viewCount }}次观看
@@ -28,7 +28,7 @@
-
+
{{ value.viewCount }}次观看
@@ -37,7 +37,7 @@
{{ value.videoTitle }}
- {{ value.viewCount }}次观看
+ {{ value.viewCount }}次观看
@@ -80,6 +80,11 @@ export default {
type: Boolean,
default: false
},
+ /** 是否显示观看次数,由父组件可以整体配置 */
+ showViewCount: {
+ type: Boolean,
+ default: true
+ },
/**
* 标题显示行数
* @type {number}
From f7fcf7fb2770630fe41b727460ea15b4fa52dcfd Mon Sep 17 00:00:00 2001
From: jinhhanhan <1683105490@qq.com>
Date: Thu, 15 Jan 2026 15:01:39 +0800
Subject: [PATCH 080/100] =?UTF-8?q?chore:=E7=82=B9=E5=87=BB=E8=8B=B1?=
=?UTF-8?q?=E6=96=87=E6=8C=89=E9=92=AE=EF=BC=8C=E9=A1=B5=E9=9D=A2=E4=B8=8D?=
=?UTF-8?q?=E6=98=AF=E7=A9=BA=E7=99=BD=E4=BA=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components/hover-nav/hover-nav.vue | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/components/hover-nav/hover-nav.vue b/components/hover-nav/hover-nav.vue
index d93bb08..2a064fc 100644
--- a/components/hover-nav/hover-nav.vue
+++ b/components/hover-nav/hover-nav.vue
@@ -185,12 +185,29 @@ export default {
uni.showToast({ title: '暂无联系电话', icon: 'none' });
}
},
- 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);
- },
+ /**
+ * 切换中英文语言,并刷新当前页面(保留所有参数)
+ */
+ toggleLanguage() {
+ this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
+ const targetLang = this.langIndexMap[this.currentLangIndex];
+
+ uni.setStorageSync('lang', targetLang);
+
+ const pages = getCurrentPages();
+ if (pages.length === 0) return;
+
+ const currentPage = pages[pages.length - 1];
+ const route = currentPage.route;
+
+ console.log('【调试】切换语言:', targetLang, '路径:', route);
+
+ if (uni.getSystemInfoSync().platform === 'browser') {
+ window.location.reload();
+ } else {
+ uni.redirectTo({ url: `/${route}` });
+ }
+ },
openKefuSelectPopup() {
const kefuNames = this.kefuList.map(item => item.name);
uni.showActionSheet({
From 1e6cd55f0a43977939c592c0de4097ebac2d0693 Mon Sep 17 00:00:00 2001
From: jinhhanhan <1683105490@qq.com>
Date: Thu, 15 Jan 2026 15:10:46 +0800
Subject: [PATCH 081/100] =?UTF-8?q?chore=EF=BC=9A=E4=B8=AD=E8=8B=B1?=
=?UTF-8?q?=E6=96=87=E5=88=87=E6=8D=A2=E6=8C=89=E9=92=AE=E8=83=BD=E5=88=87?=
=?UTF-8?q?=E6=8D=A2=E8=8B=B1=E6=96=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/js/lang.js | 312 +++++++++++++----------------
components/hover-nav/hover-nav.vue | 19 +-
2 files changed, 141 insertions(+), 190 deletions(-)
diff --git a/common/js/lang.js b/common/js/lang.js
index c8ca741..613012d 100644
--- a/common/js/lang.js
+++ b/common/js/lang.js
@@ -1,205 +1,161 @@
import { langConfig } from './config-external.js';
-
// 缓存已加载的语言包
const loadedLangPacks = {};
// 处理页面目录映射
function processRoutePath(route) {
- let routeParts = route.split("/");
+ let routeParts = route.split("/");
- // ---- 处理页面目录映射 分包造成的,需要根据实际目录结构进行映射----
- // 先处理特殊的分包路径
- if (routeParts[0] === 'pages_tool') {
- // pages_tool 分包下的页面,直接使用子目录作为语言包路径
- routeParts = [routeParts[1], ...routeParts.slice(2)];
- } else if (routeParts[0] === 'pages_goods') {
- // pages_goods 分包映射到 goods 目录
- routeParts[0] = 'goods';
- } else if (routeParts[0] === 'pages_member') {
- // pages_member 分包映射到 member 目录
- routeParts[0] = 'member';
- } else if (routeParts[0] === 'pages_order') {
- // pages_order 分包映射到 order 目录
- routeParts[0] = 'order';
- } else if (routeParts[0] === 'pages_promotion') {
- // pages_promotion 分包特殊处理
- const promotionModules = ['point', 'fenxiao', 'merch'];
- if (routeParts[1] && promotionModules.includes(routeParts[1])) {
- routeParts = [routeParts[1], ...routeParts.slice(2)];
- }
- }
- // ---- 处理页面目录映射 ----
-
- // 去掉pages目录,只保留子目录
- if (routeParts[0] === 'pages') {
- routeParts = routeParts.slice(1);
- }
-
- return routeParts.join("/");
+ // ---- 处理页面目录映射 分包造成的,需要根据实际目录结构进行映射----
+ if (routeParts[0] === 'pages_tool') {
+ routeParts = [routeParts[1], ...routeParts.slice(2)];
+ } else if (routeParts[0] === 'pages_goods') {
+ routeParts[0] = 'goods';
+ } else if (routeParts[0] === 'pages_member') {
+ routeParts[0] = 'member';
+ } else if (routeParts[0] === 'pages_order') {
+ routeParts[0] = 'order';
+ } else if (routeParts[0] === 'pages_promotion') {
+ const promotionModules = ['point', 'fenxiao', 'merch'];
+ if (routeParts[1] && promotionModules.includes(routeParts[1])) {
+ routeParts = [routeParts[1], ...routeParts.slice(2)];
+ }
+ }
+ // ---- 处理页面目录映射 ----
+
+ if (routeParts[0] === 'pages') {
+ routeParts = routeParts.slice(1);
+ }
+
+ return routeParts.join("/");
}
// 加载语言包(同步方式)
function loadLangPackSync(lang, path) {
- try {
- if (loadedLangPacks[`${lang}_${path}`]) {
- return loadedLangPacks[`${lang}_${path}`];
- }
- const langData = require(`@/lang/${lang}/${path}.js`).lang;
- loadedLangPacks[`${lang}_${path}`] = langData;
- return langData;
- } catch (error) {
- console.error(`加载语言包 ${lang}/${path} 失败:`, error);
- return {};
- }
+ try {
+ if (loadedLangPacks[`${lang}_${path}`]) {
+ return loadedLangPacks[`${lang}_${path}`];
+ }
+ const langData = require(`@/lang/${lang}/${path}.js`).lang;
+ loadedLangPacks[`${lang}_${path}`] = langData;
+ return langData;
+ } catch (error) {
+ console.error(`加载语言包 ${lang}/${path} 失败:`, error);
+ return {};
+ }
}
export default {
- langList: langConfig.langList,
- /**
- * * 解析多语言
- * @param {Object} field
- */
- lang(field) {
- let _this = getCurrentPages()[getCurrentPages().length - 1];
- if (!_this) return;
+ langList: langConfig.langList,
+ /**
+ * 解析多语言
+ */
+ lang(field) {
+ let _this = getCurrentPages()[getCurrentPages().length - 1];
+ if (!_this) return;
- const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
+ const locale = uni.getStorageSync('lang') || "zh-cn";
- let value = ''; // 存放解析后的语言值
- let langPath = ''; // 存放当前页面语言包路径
+ let value = '';
+ let langPath = '';
- try {
- //公共语言包(同步加载)
- var lang = loadLangPackSync(locale, 'common');
-
- //当前页面语言包(同步加载)
- let route = _this.route;
- langPath = processRoutePath(route);
-
- // 加载当前页面语言包
- let currentPageLang = loadLangPackSync(locale, langPath);
+ try {
+ var lang = loadLangPackSync(locale, 'common');
+
+ let route = _this.route;
+ langPath = processRoutePath(route);
+
+ let currentPageLang = loadLangPackSync(locale, langPath);
- // 合并语言包
- let mergedLang = { ...lang, ...currentPageLang };
+ let mergedLang = { ...lang, ...currentPageLang };
- // 解析字段
- var arr = field.split(".");
- if (arr.length > 1) {
- // 处理嵌套属性,如 common.currencySymbol
- let temp = mergedLang;
- let found = true;
- for (let key of arr) {
- if (temp[key] !== undefined) {
- temp = temp[key];
- } else {
- found = false;
- break;
- }
- }
- value = found ? temp : field;
- } else {
- value = mergedLang[field] !== undefined ? mergedLang[field] : field;
- }
-
- } catch (e) {
- console.error('解析语言包失败:', e, { langPath, field, locale });
- value = field;
- }
+ var arr = field.split(".");
+ if (arr.length > 1) {
+ let temp = mergedLang;
+ let found = true;
+ for (let key of arr) {
+ if (temp[key] !== undefined) {
+ temp = temp[key];
+ } else {
+ found = false;
+ break;
+ }
+ }
+ value = found ? temp : field;
+ } else {
+ value = mergedLang[field] !== undefined ? mergedLang[field] : field;
+ }
+
+ } catch (e) {
+ console.error('解析语言包失败:', e, { langPath, field, locale });
+ value = field;
+ }
- if (arguments.length > 1) {
- //有参数,需要替换
- for (var i = 1; i < arguments.length; i++) {
- value = value.replace("{" + (i - 1) + "}", arguments[i]);
- }
- }
- if (value == undefined || (value == 'title' && field == 'title')) value = ''; // field
+ if (arguments.length > 1) {
+ for (var i = 1; i < arguments.length; i++) {
+ value = value.replace("{" + (i - 1) + "}", arguments[i]);
+ }
+ }
+ if (value == undefined || (value == 'title' && field == 'title')) value = '';
- // 多语言调试,注释后可以关闭控制台输出
- if (field == value) {
- console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
- }
+ if (field == value) {
+ console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
+ }
- return value;
- },
- /**
- * * 切换语言
- * @param {String} value 语言值
- * @param {String} url 切换后跳转的页面url
- */
- change(value, url = '/pages_tool/member/index') {
- let _this = getCurrentPages()[getCurrentPages().length - 1];
- if (!_this) return;
+ return value;
+ },
+ /**
+ * 切换语言
+ */
+ change(value, url = '/pages_tool/member/index') {
+ let _this = getCurrentPages()[getCurrentPages().length - 1];
+ if (!_this) return;
- uni.setStorageSync("lang", value);
- const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
+ uni.setStorageSync("lang", value);
+ const locale = uni.getStorageSync('lang') || "zh-cn";
- // 清空已加载的语言包缓存
- for (let key in loadedLangPacks) {
- if (!key.startsWith(locale)) {
- delete loadedLangPacks[key];
- }
- }
+ // ✅ 关键修复:清空所有语言包缓存(不再保留任何旧缓存)
+ for (let key in loadedLangPacks) {
+ delete loadedLangPacks[key];
+ }
- this.refresh();
+ this.refresh();
- if (url) {
- uni.reLaunch({ url: url });
- }
- },
- //刷新标题、tabbar
- refresh() {
- let _this = getCurrentPages()[getCurrentPages().length - 1];
- if (!_this) return;
- const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
-
- this.title(this.lang("title"));
-
- //设置tabbar的文字语言
- // uni.setTabBarItem({
- // index: 0,
- // text: this.lang("tabBar.home")
- // });
- // uni.setTabBarItem({
- // index: 1,
- // text: this.lang("tabBar.category")
- // });
- // uni.setTabBarItem({
- // index: 2,
- // text: this.lang("tabBar.cart")
- // });
- // uni.setTabBarItem({
- // index: 3,
- // text: this.lang("tabBar.member")
- // });
- },
- title(str) {
- if (str) {
- uni.setNavigationBarTitle({
- title: str,
- success: function (res) {
- },
- fail: function (err) {
- }
- });
- }
- },
- // 获取语言包列表
- list() {
- var list = [];
- try {
- //公共语言包
- for (var i = 0; i < langConfig.langList.length; i++) {
- let langType = langConfig.langList[i];
- let item = loadLangPackSync(langType, 'common');
- list.push({
- name: item.common ? item.common.name : langType,
- value: langType
- });
- }
- } catch (e) {
- console.error('获取语言包列表失败:', e);
- }
- return list;
- }
-}
+ if (url) {
+ uni.reLaunch({ url: url });
+ }
+ },
+ //刷新标题、tabbar
+ refresh() {
+ let _this = getCurrentPages()[getCurrentPages().length - 1];
+ if (!_this) return;
+ const locale = uni.getStorageSync('lang') || "zh-cn";
+
+ this.title(this.lang("title"));
+ },
+ title(str) {
+ if (str) {
+ uni.setNavigationBarTitle({
+ title: str
+ });
+ }
+ },
+ // 获取语言包列表
+ list() {
+ var list = [];
+ try {
+ for (var i = 0; i < langConfig.langList.length; i++) {
+ let langType = langConfig.langList[i];
+ let item = loadLangPackSync(langType, 'common');
+ list.push({
+ name: item.common ? item.common.name : langType,
+ value: langType
+ });
+ }
+ } catch (e) {
+ console.error('获取语言包列表失败:', e);
+ }
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/components/hover-nav/hover-nav.vue b/components/hover-nav/hover-nav.vue
index 2a064fc..f2b1d7a 100644
--- a/components/hover-nav/hover-nav.vue
+++ b/components/hover-nav/hover-nav.vue
@@ -192,20 +192,15 @@ export default {
this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
const targetLang = this.langIndexMap[this.currentLangIndex];
- uni.setStorageSync('lang', targetLang);
-
- const pages = getCurrentPages();
- if (pages.length === 0) return;
-
- const currentPage = pages[pages.length - 1];
- const route = currentPage.route;
-
- console.log('【调试】切换语言:', targetLang, '路径:', route);
+ // 调用语言切换逻辑(设置 storage + 清空缓存)
+ this.$langConfig.change(targetLang);
+ // H5 环境需要强制刷新页面才能生效
if (uni.getSystemInfoSync().platform === 'browser') {
- window.location.reload();
- } else {
- uni.redirectTo({ url: `/${route}` });
+ // 延迟 100ms 确保 change() 执行完成
+ setTimeout(() => {
+ window.location.reload();
+ }, 100);
}
},
openKefuSelectPopup() {
From 36fd0621fd232cd81b4cf036fe88fe90b9f64d6c Mon Sep 17 00:00:00 2001
From: ZF sun <34314687@qq.com>
Date: Thu, 15 Jan 2026 17:26:02 +0800
Subject: [PATCH 082/100] =?UTF-8?q?fix(=E8=A7=86=E9=A2=91=E5=8F=B7?=
=?UTF-8?q?=E7=BB=84=E4=BB=B6):=20padding=20=E5=BD=B1=E5=93=8D=E5=B8=83?=
=?UTF-8?q?=E5=B1=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components-diy/diy-channel-list.vue | 210 ++++++++++++++++++++++++----
pages_tool/contact/contact.vue | 2 +-
2 files changed, 186 insertions(+), 26 deletions(-)
diff --git a/components-diy/diy-channel-list.vue b/components-diy/diy-channel-list.vue
index fa4c049..a7b582f 100644
--- a/components-diy/diy-channel-list.vue
+++ b/components-diy/diy-channel-list.vue
@@ -1,5 +1,5 @@
-
+
+ :show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
+ :play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
@@ -25,24 +24,26 @@
+ :show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
+ :play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
+ :class="['channel-nav', value.showStyle == 'fixed' ? 'fixed-layout' : 'singleSlide', 'row1-of' + value.rowCount]"
+ :scroll-x="true"
+ :scroll-y="false"
+ :enhanced="true"
+ :bounces="false">
-
+
+ :show-view-count="value.showViewCount" :cover-style="computedCoverStyle"
+ :play-btn-style="value.playBtnStyle" :aspect-ratio="value.aspectRatio" />
@@ -107,6 +108,14 @@ export default {
// 组件创建时的逻辑
// 可以在这里进行初始化操作,如获取页面宽度等
},
+ mounted() {
+ // 组件挂载后添加鼠标拖拽滚动功能
+ if (!['fixed', 'carousel'].includes(this.value?.showStyle)) {
+ this.$nextTick(() => {
+ this.addMouseDragScroll();
+ });
+ }
+ },
watch: {
/**
* 组件刷新监听
@@ -134,24 +143,24 @@ export default {
* @returns {string} 样式字符串
*/
componentStyle() {
- let style = '';
+ const style = {};
// 背景色
if (this.value?.componentBgColor) {
- style += 'background-color:' + this.value?.componentBgColor + ';';
+ style.backgroundColor = this.value?.componentBgColor;
}
// 圆角样式
if (this.value?.componentAngle == 'round') {
- style += 'border-top-left-radius:' + (2 * this.value?.topAroundRadius) + 'rpx;';
- style += 'border-top-right-radius:' + (2 * this.value?.topAroundRadius) + 'rpx;';
- style += 'border-bottom-left-radius:' + (2 * this.value?.bottomAroundRadius) + 'rpx;';
- style += 'border-bottom-right-radius:' + (2 * this.value?.bottomAroundRadius) + 'rpx;';
+ style.borderTopLeftRadius = (2 * this.value?.topAroundRadius) + 'rpx';
+ style.borderTopRightRadius = (2 * this.value?.topAroundRadius) + 'rpx';
+ style.borderBottomLeftRadius = (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;
},
@@ -180,7 +189,7 @@ export default {
height = [510, 280, 220, 180][this.value.rowCount - 1];
}
}
-
+
return 'height:' + (2 * height) + 'rpx';
},
@@ -289,6 +298,105 @@ export default {
item.coverUrl = wechatChannelConfig.video.defaultCoverUrl;
// #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
}
}
}
@@ -297,6 +405,10 @@ export default {
-```
-
-## 注意事项
-
-1. 组件已适配项目中已有的 `ns-loading` 组件
-2. 需要配置对应的图标字体文件
-3. 音频播放功能在 H5 和 APP 端支持较好
-4. 文件预览功能依赖平台能力
-5. 语音输入功能需要用户授权麦克风权限
\ No newline at end of file
diff --git a/components/ai-chat-message/demo.vue b/components/ai-chat-message/demo.vue
deleted file mode 100644
index dad9d5f..0000000
--- a/components/ai-chat-message/demo.vue
+++ /dev/null
@@ -1,288 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/components/wxwork-contact/CHANGELOG.md b/components/wxwork-contact/CHANGELOG.md
deleted file mode 100644
index bbd49e1..0000000
--- a/components/wxwork-contact/CHANGELOG.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# 企业微信联系客服组件更新日志
-
-## v2.0.0 - 集成全局Store配置
-
-### 新增功能
-- ✅ 企业微信配置集成到全局Store
-- ✅ 从 `/api/config/init` 统一获取配置
-- ✅ 支持props覆盖全局配置
-- ✅ 优化配置获取逻辑
-
-### 变更内容
-1. **Store集成**:
- - 在 `store/index.js` 中添加 `wxworkConfig` 状态
- - 添加 `setWxworkConfig` mutation
- - 在 `init` action 中从 `/api/config/init` 获取企业微信配置
-
-2. **组件优化**:
- - `wxwork-contact.vue` 组件现在优先从全局Store获取配置
- - 支持通过props覆盖全局配置
- - 移除单独的API调用,使用统一配置
-
-3. **页面集成**:
- - `pages/contact/contact.vue` 页面简化配置获取逻辑
- - 直接使用全局Store中的企业微信配置
-
-### 配置格式
-后端 `/api/config/init` 需要返回以下格式的企业微信配置:
-
-```json
-{
- "code": 0,
- "data": {
- // ... 其他配置 ...
- "wxwork": {
- "corp_id": "企业ID",
- "agent_id": "应用ID",
- "contact_id": "客服ID",
- "contact_url": "活码链接",
- "timestamp": "时间戳",
- "nonceStr": "随机字符串",
- "signature": "签名",
- "enabled": true
- }
- }
-}
-```
-
-### 使用方式
-```vue
-
-
-
-
-
-```
-
-## v1.0.0 - 初始版本
-
-### 功能
-- 企业微信JS-SDK封装
-- 基础联系客服组件
-- 支持小程序和H5环境
-- 活码跳转和SDK两种方式
\ No newline at end of file
diff --git a/components/wxwork-contact/README.md b/components/wxwork-contact/README.md
deleted file mode 100644
index ce09d20..0000000
--- a/components/wxwork-contact/README.md
+++ /dev/null
@@ -1,484 +0,0 @@
-# 企业微信联系客服组件
-
-## 功能说明
-
-这个组件实现了在小程序中点击"联系客服"后,自动跳转到企业微信添加对应销售的功能。
-
-## 关键前提条件
-
-### ⚠️ 重要提醒
-微信小程序与企业微信互通有严格的平台限制和权限要求,使用前请确保满足以下所有条件:
-
-### 1. 微信小程序环境要求
-- **平台限制**:功能仅在微信小程序环境中可用
-- **基础库版本**:需要微信小程序基础库 2.3.0 及以上版本
-- **用户环境**:用户需要在微信中打开小程序
-
-### 2. 企业微信配置要求
-- **企业认证**:企业微信账号必须完成企业认证
-- **客户联系功能**:需要开通企业微信"客户联系"功能
-- **应用权限**:企业微信应用需要有客户联系相关权限
-
-### 3. 互通配置要求
-- **关联配置**:小程序必须与企业微信进行关联配置
-- **权限申请**:需要在微信开放平台和企业微信后台分别申请相应权限
-- **域名白名单**:相关域名需要在小程序和企业微信后台都配置白名单
-
-### 4. 跳转权限要求
-- **小程序AppID**:需要在企业微信中配置允许跳转的小程序AppID
-- **企业微信AppID**:需要在微信开放平台配置关联的企业微信AppID
-- **业务域授权**:需要配置业务域授权,允许跨平台跳转
-
-### 5. 开发调试要求
-- **测试环境**:需要在测试环境中验证跳转功能
-- **权限验证**:确保所有必要的API权限已申请并生效
-- **兼容性测试**:在不同微信版本中进行兼容性测试
-
-### 6. 具体配置要求
-
-| 条件 | 说明 |
-|------|------|
-| **小程序与企业微信绑定** | 在企业微信管理后台 → 「应用管理」→「小程序」中关联你的微信小程序AppID |
-| **配置可信域名** | 如果涉及网页跳转或回调,需在企业微信后台配置业务域名 |
-| **使用企业微信服务商 or 自建应用** | 若需高级功能(如获取客户详情),需有企业微信管理员权限或通过服务商代开发 |
-
-## 使用方法
-
-### 1. 基础用法
-
-```vue
-
-
-```
-
-### 组件架构
-
-### 分层设计
-```
-调用方 (页面组件)
- ↓ 传递配置参数
-wxwork-contact 组件
- ↓ 调用SDK
-wxwork-jssdk.js
- ↓ 调用企业微信API
-企业微信服务
-```
-
-### 组件设计原则
-
-- **独立性**:组件不直接依赖全局Store,所有配置通过props传递
-- **职责分离**:组件只负责UI展示和企业微信SDK调用,配置管理由调用方负责
-- **灵活配置**:支持调用者覆盖任何配置参数
-
-## 版本信息
-
-### v3.0.0 - 统一客服服务重构版本
-- 创建 `CustomerService` 统一客服处理服务
-- 重构 `ns-contact.vue` 和 `hover-nav.vue` 消除重复代码
-- 提供统一的客服处理接口和平台适配
-- 完善错误处理和降级机制
-- 支持所有客服类型的统一调用
-
-### v2.0.0 - Store集成版本
-- 企业微信配置集成到全局Store
-- 从 `/api/config/init` 统一获取配置
-- 组件完全独立,通过props接收配置
-- 支持全局配置和局部覆盖
-
-### v1.0.0 - 初始版本
-- 基础企业微信联系功能
-- 支持活码跳转和JS-SDK两种方式
-
-### 2. 属性说明
-
-| 属性 | 类型 | 默认值 | 说明 |
-|------|------|--------|------|
-| btnText | String | '添加企业微信客服' | 按钮文字 |
-| corpId | String | - | 企业ID(必需) |
-| agentId | String | '' | 应用ID |
-| timestamp | String | '' | 时间戳 |
-| nonceStr | String | '' | 随机字符串 |
-| signature | String | '' | 签名 |
-| contactId | String | '' | 客服ID或活码配置ID |
-| contactUrl | String | '' | 活码链接 |
-| showConfirm | Boolean | true | 是否显示确认弹窗 |
-
-### 3. 在联系页面中使用
-
-在 `pages/contact/contact.vue` 中已集成使用示例:
-
-```vue
-
-
-```
-
-## 配置说明
-
-### 后端接口需求
-
-企业微信配置已集成到 `/api/config/init` 接口中,返回以下格式的数据:
-
-```json
-{
- "code": 0,
- "data": {
- // ... 其他配置 ...
- "wxwork": {
- "corp_id": "企业ID",
- "agent_id": "应用ID",
- "contact_id": "客服ID",
- "contact_url": "活码链接",
- "timestamp": "时间戳",
- "nonceStr": "随机字符串",
- "signature": "签名",
- "enabled": true
- }
- }
-}
-```
-
-### 全局Store集成
-
-企业微信配置通过以下方式集成到全局状态管理:
-
-1. **Store状态**:在 `store/index.js` 中添加 `wxworkConfig` 状态
-2. **配置获取**:在 `init` action 中从 `/api/config/init` 获取企业微信配置
-3. **状态更新**:使用 `setWxworkConfig` mutation 更新配置
-4. **持久化**:配置自动保存到本地存储
-
-### 企业微信配置步骤
-
-1. **获取企业微信活码**:
- - 登录企业微信管理后台
- - 进入"客户联系" -> "配置" -> "联系我"
- - 创建活码,获取配置ID或直接获取活码链接
-
-2. **配置参数**:
- - `corp_id`: 企业ID(在企业微信后台获取)
- - `agent_id`: 企业微信应用ID
- - `contact_id`: 客服的用户ID
- - `contact_url`: 企业微信活码链接(推荐使用活码链接)
- - `timestamp`: 生成签名的时间戳
- - `nonceStr`: 生成签名的随机字符串
- - `signature`: JS-SDK签名
-
-## 典型业务流程示例
-
-### 目标
-用户在小程序中点击"联系客服",自动添加对应的企业微信销售。
-
-### 步骤
-1. **后端调用企业微信 API** 创建「联系我」二维码(可带场景值,如 user_id=123)。
-2. **前端在小程序中展示该二维码(或生成跳转链接)**。
-3. **用户长按识别 → 打开企业微信 → 添加客服**。
-4. **企业微信收到添加事件 → 通过 API 获取 external_userid → 关联到原小程序用户**。
-
-## 实现原理
-
-### 方案1:企业微信活码跳转(推荐)
-- 使用企业微信活码链接
-- 通过 `uni.navigateToMiniProgram` 跳转到企业微信小程序
-- 直接添加对应的销售为联系人
-
-### 方案2:JS-SDK方式
-- 使用企业微信JS-SDK
-- 调用 `openUserProfile` 接口打开用户资料
-- 用户手动添加联系人
-
-## 注意事项
-
-### 功能限制
-1. **小程序环境**:需要在微信小程序环境中使用
-2. **权限配置**:确保小程序有跳转企业微信的权限
-3. **降级处理**:当企业微信不可用时,会降级到原有客服方式
-4. **用户体验**:建议添加确认弹窗,避免误操作
-
-### 前提条件验证
-5. **权限检查**:使用前需要验证所有必需权限是否生效
-6. **配置完整性**:确保所有配置参数都已正确设置
-7. **网络环境**:确保用户网络环境允许访问企业微信服务
-8. **版本兼容**:检查微信版本和企业微信版本兼容性
-
-### 调试建议
-9. **错误监控**:添加适当的错误日志和用户反馈机制
-10. **性能优化**:避免频繁的SDK初始化和配置获取
-11. **安全考虑**:敏感配置信息应在服务端处理,前端不暴露
-
-## 兼容性
-
-- 微信小程序:✅ 支持
-- H5环境:✅ 支持跳转活码链接
-- 其他平台:降级处理
-
-## 文件结构
-
-```
-components/wxwork-contact/
-├── wxwork-contact.vue # 主组件
-└── README.md # 说明文档
-
-components/ns-contact/
-└── ns-contact.vue # 统一客服组件(重构后)
-
-components/hover-nav/
-└── hover-nav.vue # 悬浮导航组件(重构后)
-
-common/js/
-├── wxwork-jssdk.js # 企业微信JS-SDK封装
-└── customer-service.js # 客服统一处理服务(新增)
-
-store/
-└── index.js # 全局Store,包含wxworkConfig状态管理
-
-pages/contact/
-└── contact.vue # 联系页面,集成企业微信功能
-```
-
-## 系统梳理与优化 (v3.1.0)
-
-### 🔧 已修复的问题
-
-#### 1. **App.vue 配置恢复**
-- ✅ 修复了企业微信配置 (`wxworkConfig`) 在应用启动时的恢复
-- ✅ 确保所有配置都能正确从本地存储恢复到Store
-
-#### 2. **客服服务参数传递**
-- ✅ 修复了 `openCustomerServiceChat` 参数传递错误
-- ✅ 正确传递 `sendMessageTitle`、`sendMessagePath`、`sendMessageImg`
-
-#### 3. **组件配置访问**
-- ✅ 在 `ns-contact.vue` 和 `hover-nav.vue` 中添加 computed 属性
-- ✅ 确保能够正确访问 `servicerConfig`
-
-#### 4. **企业微信服务优化**
-- ✅ 改进参数传递,支持自定义消息参数
-- ✅ 统一处理函数调用方式
-
-### 🛡️ 新增功能
-
-#### 1. **配置验证机制**
-```javascript
-const validation = this.customerService.validateConfig();
-if (!validation.isValid) {
- // 处理配置错误
-}
-```
-
-#### 2. **错误处理增强**
-- ✅ 添加配置错误弹窗
-- ✅ 改进错误日志记录
-- ✅ 警告信息提示
-
-#### 3. **类型安全**
-- ✅ 完善参数类型检查
-- ✅ 空值和异常情况处理
-
-### 📋 当前系统状态
-
-| 组件 | 状态 | 功能完整性 |
-|------|------|-----------|
-| **customer-service.js** | ✅ 完成 | 统一客服处理服务 |
-| **ns-contact.vue** | ✅ 修复 | 支持所有客服类型 |
-| **hover-nav.vue** | ✅ 修复 | 集成统一客服服务 |
-| **App.vue** | ✅ 修复 | 配置完整恢复 |
-| **contact.vue** | ⚠️ 待优化 | 仍使用原始方式 |
-
-### 🔄 待优化项
-
-#### 1. **contact.vue 页面重构**
-- 建议集成统一客服服务
-- 添加企业微信客服按钮
-- 统一UI交互体验
-
-#### 2. **加载状态反馈**
-- 客服功能调用时的loading状态
-- 网络请求的进度指示
-
-#### 3. **用户体验优化**
-- 客服按钮的点击反馈
-- 错误状态的友好提示
-
-### 🧪 测试建议
-
-1. **配置验证测试**:
- - 测试各种配置缺失情况
- - 验证错误提示准确性
-
-2. **平台兼容测试**:
- - 微信小程序客服功能
- - H5环境跳转
- - 支付宝小程序客服
-
-3. **企业微信功能测试**:
- - 活码链接跳转
- - 降级处理机制
- - 参数传递正确性
-
-### 📖 使用最佳实践
-
-```javascript
-// 推荐使用方式
-const customerService = createCustomerService(this);
-
-// 带配置验证的调用
-if (customerService.isConfigAvailable()) {
- customerService.handleCustomerClick({
- sendMessageTitle: '商品咨询',
- sendMessagePath: '/pages/goods/detail',
- sendMessageImg: 'product-image.jpg'
- });
-}
-```
-
-## 重构说明 (v3.0.0)
-
-### 统一客服处理服务
-
-为了解决代码重复问题,我们创建了 `CustomerService` 类来统一处理所有客服逻辑:
-
-#### 主要改进
-1. **代码复用**:消除 `ns-contact.vue` 和 `hover-nav.vue` 中的重复代码
-2. **统一接口**:提供一致的客服处理API
-3. **平台适配**:自动处理不同平台的客服配置
-4. **类型安全**:完善的错误处理和降级机制
-
-#### 使用方式
-
-**1. 在组件中导入**
-```javascript
-import { createCustomerService } from '@/common/js/customer-service.js';
-```
-
-**2. 初始化服务**
-```javascript
-created() {
- this.customerService = createCustomerService(this);
- this.buttonConfig = this.customerService.getButtonConfig();
-}
-```
-
-**3. 处理客服点击**
-```javascript
-methods: {
- contactServicer() {
- this.customerService.handleCustomerClick({
- niushop: this.niushop,
- sendMessageTitle: this.sendMessageTitle,
- sendMessagePath: this.sendMessagePath,
- sendMessageImg: this.sendMessageImg
- });
- }
-}
-```
-
-#### 核心方法
-
-| 方法名 | 用途 | 参数 |
-|--------|------|------|
-| `handleCustomerClick(options)` | 统一处理客服点击 | 客服配置选项 |
-| `getButtonConfig()` | 获取按钮配置 | - |
-| `getServiceType()` | 获取客服类型 | - |
-| `openWxworkService()` | 打开企业微信客服 | 是否使用原方式 |
-
-#### 支持的客服类型
-
-- `wxwork` - 企业微信客服
-- `third` - 第三方客服
-- `niushop` - 牛商客服
-- `weapp` - 微信小程序客服
-- `aliapp` - 支付宝小程序客服
-- `none` - 无客服(显示提示)
-
-## 常见问题 (FAQ)
-
-### Q: contact_id 是小程序ID吗?
-A: 不是的。`contact_id` 是**企业微信中客服人员的用户ID**,具体说明如下:
-
-- **定义**:企业微信系统内部分配给客服人员的唯一标识符
-- **获取方式**:通过企业微信管理后台的"客户联系" → "配置" → "联系我"功能创建活码时获得
-- **用途**:用于指定具体客服人员,当用户点击"联系客服"时,系统通过这个ID知道应该添加哪个企业微信客服人员
-
-### Q: contact_id 和小程序ID的区别?
-A: 两者的作用完全不同:
-
-| 字段 | 用途 | 获取方式 |
-|------|------|----------|
-| **contact_id** | 指定具体的企业微信客服人员 | 企业微信管理后台获取 |
-| **小程序AppID** | 识别整个微信小程序应用 | 微信开放平台获取 |
-
-在业务流程中:
-1. 用户在小程序中点击"联系客服"
-2. 系统使用 `contact_id` 打开对应的企业微信客服人员资料
-3. 用户添加该企业微信客服为联系人
-
-所以 `contact_id` 是企业微信客服的ID,不是小程序的ID。
-
-### Q: wxwork_contact_url 从哪里来?
-A: `wxwork_contact_url` 应该来自全局Store中的 `wxworkConfig`,而不是 `servicerConfig`:
-
-**正确的配置来源**:
-- ✅ `this.$store.state.wxworkConfig.contact_url` - 企业微信配置
-- ❌ `this.config.wxwork_contact_url` - 错误的配置路径
-
-**配置获取流程**:
-1. **后端接口**:`/api/config/init` 返回 `wxwork_config` 数据
-2. **Store存储**:`setWxworkConfig` 将配置保存到 `wxworkConfig` 状态
-3. **组件使用**:通过 `this.$store.state.wxworkConfig.contact_url` 访问
-
-**代码修正示例**:
-```javascript
-// 错误 ❌
-if (this.config.wxwork_contact_url) { ... }
-
-// 正确 ✅
-const wxworkConfig = this.$store.state?.wxworkConfig;
-if (wxworkConfig?.contact_url) { ... }
-```
-
-**字段对应关系**:
-| 后端字段 | Store字段 | 组件使用 |
-|---------|----------|----------|
-| `contact_url` | `contact_url` | `wxworkConfig.contact_url` |
-
-### Q: navigateToMiniProgram 中的企业微信小程序AppID 是指我的业务小程序ID吗?
-A: 不是的!`appId: 'wxeb490c6f9b154ef9'` 是**企业微信官方小程序的AppID**,不是你的业务小程序ID。
-
-**两者的区别**:
-
-| 小程序类型 | AppID示例 | 用途 | 所有者 |
-|-----------|----------|------|--------|
-| **企业微信官方小程序** | `wxeb490c6f9b154ef9` | 展示企业联系人详情页面 | 腾讯企业微信团队 |
-| **你的业务小程序** | 你的AppID | 你的业务功能(电商、服务等) | 你的企业/组织 |
-
-**业务流程**:
-```
-用户小程序 (你的业务)
- ↓ 点击"联系客服"
-navigateToMiniProgram 跳转到
-企业微信官方小程序 (wxeb490c6f9b154ef9)
- ↓ 展示联系人详情
-用户添加客服人员到企业微信
-```
-
-**关键点**:
-- 这个AppID是企业微信官方小程序,通常是固定值
-- 用于跳转到企业微信环境展示联系人详情
-- 不需要替换成你自己的小程序AppID |
\ No newline at end of file
diff --git a/pages/dify-chat/dify-chat.vue b/pages/dify-chat/dify-chat.vue
deleted file mode 100644
index f00cf88..0000000
--- a/pages/dify-chat/dify-chat.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pages_tool/kefu-demo/index.json b/pages_tool/kefu-demo/index.json
deleted file mode 100644
index 90b9bd8..0000000
--- a/pages_tool/kefu-demo/index.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "navigationBarTitleText": "智能客服演示",
- "navigationBarBackgroundColor": "#ffffff",
- "navigationBarTextStyle": "black",
- "backgroundColor": "#f5f5f5"
-}
\ No newline at end of file
diff --git a/pages_tool/kefu-demo/index.vue b/pages_tool/kefu-demo/index.vue
deleted file mode 100644
index 6b9de75..0000000
--- a/pages_tool/kefu-demo/index.vue
+++ /dev/null
@@ -1,704 +0,0 @@
-
-
-
-
-
-
-
- 1. 智能客服聊天接口
-
-
-
-
-
- 回复结果:
- {{ chatResult }}
-
-
-
-
-
- 2. 创建新会话接口
-
-
- 会话信息:
- 会话ID: {{ conversationInfo.conversationId }}
- 创建时间: {{ conversationInfo.createdAt }}
-
-
-
-
-
- 3. 获取会话历史接口
-
-
-
- 历史记录 ({{ historyData.total }}条):
-
-
- {{ msg.role }}:
- {{ msg.content }}
- {{ msg.created_at }}
-
-
-
-
-
-
-
- 4. 系统健康检查
-
-
-
-
-
- 健康检查结果:
- 状态: {{ healthResult.status }}
- 检查ID: {{ healthResult.checkId }}
- 时间: {{ healthResult.timestamp }}
- 通过检查: {{ healthResult.passed_checks }}/{{ healthResult.total_checks }}
-
- 组件状态:
-
- {{ key }}: {{ component.status }}
- {{ component.message }}
- 响应时间: {{ component.response_time_ms }}ms
-
-
-
-
-
-
-
- 5. 获取服务配置信息
-
-
- 服务配置:
- 服务名称: {{ serviceInfoResult.serviceInfo?.name }}
- 服务版本: {{ serviceInfoResult.serviceInfo?.version }}
- 启用状态: {{ serviceInfoResult.serviceInfo?.enabled ? '已启用' : '未启用' }}
-
- 可用功能:
-
- {{ feature }}: {{ enabled ? '✓' : '✗' }}
-
-
-
- API端点:
-
- {{ name }}: {{ endpoint }}
-
-
-
-
-
-
-
- 6. 清除会话历史
-
-
-
-
-
- 清除结果:
- 删除消息数: {{ clearResult.deletedMessages }}
- 删除会话数: {{ clearResult.deletedConversations }}
-
-
-
-
-
- 7. 流式聊天测试
-
-
-
-
-
- 流式回复:
- {{ streamResult }}
-
-
-
-
-
- 8. 完整服务检查
-
-
-
-
-
- 9. 服务状态检查(兼容)
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/scripts/iconfontcss-generate-preview.js b/scripts/iconfontcss-generate-preview.js
deleted file mode 100644
index 3f6d58c..0000000
--- a/scripts/iconfontcss-generate-preview.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// generate-preview.js
-const fs = require('fs');
-const path = require('path');
-
-function generateIconfontPreview(cssPath, outputPath) {
- const cssContent = fs.readFileSync(cssPath, 'utf8');
-
- // 解析图标
- const iconRegex = /\.(icon-[^:]+):before\s*{\s*content:\s*["']\\([^"']+)["']/g;
- const icons = [];
- let match;
-
- while ((match = iconRegex.exec(cssContent)) !== null) {
- icons.push({
- className: match[1],
- unicode: '\\' + match[2]
- });
- }
-
- // 计算引入css文件相对于 outputPath的路径
- const relativeCssPath = path.relative(path.dirname(outputPath), cssPath);
-
- // 生成 HTML
- const html = `
-
-
- Iconfont Preview
-
-
-
-
- Iconfont Preview (${icons.length} icons)
-
- ${icons.map(icon => `
-
- `).join('')}
-
-
-`;
-
- fs.writeFileSync(outputPath, html);
- console.log(`预览已生成: ${outputPath}`);
-}
-
-// 使用
-const cssPath = path.join(__dirname, '../common/css/iconfont.css');
-const outputPath = path.join(__dirname, '../iconfont-preview.html');
-generateIconfontPreview(cssPath, outputPath);
\ No newline at end of file
From dd4176998bfb547aaf638256432c9f9dd4942085 Mon Sep 17 00:00:00 2001
From: ZF sun <34314687@qq.com>
Date: Fri, 16 Jan 2026 10:16:40 +0800
Subject: [PATCH 084/100] Merge branch 'feat/personnel_channel' into dev/1.0
---
common/js/config.js | 10 +-
common/js/customer-service.js | 146 ++++++-----
common/js/lang.js | 312 +++++++++++++-----------
common/js/util.js | 2 +
components/hover-nav/hover-nav.vue | 229 +++++-------------
lang/en-us/common.js | 63 ++---
lang/zh-cn/common.js | 7 +
pages.json | 6 +
pages/index/index.vue | 375 ++++++++++++++---------------
pages_tool/ai-chat/index.json | 10 -
pages_tool/ai-chat/index.vue | 2 +-
11 files changed, 571 insertions(+), 591 deletions(-)
delete mode 100644 pages_tool/ai-chat/index.json
diff --git a/common/js/config.js b/common/js/config.js
index 4b3fbbc..ec8d65b 100644
--- a/common/js/config.js
+++ b/common/js/config.js
@@ -77,18 +77,16 @@ export default {
* 然后将 site.js 文件放到 `unpackage\dist\build\mp-weixin\` 目录下面
*/
// 商户ID
- uniacid: 1, //825
+ uniacid: uniacid, //825
//api请求地址
- baseUrl: 'https://dev.aigc-quickapp.com/',
- // baseUrl: 'http://localhost:8010/',
+ baseUrl: domain,
// 图片域名
- imgDomain: 'https://dev.aigc-quickapp.com/',
- //imgDomain: 'http://localhost:8010/',
+ imgDomain: domain,
// H5端域名
- h5Domain: 'https://dev.aigc-quickapp.com/',
+ h5Domain: domain,
// // api请求地址
// baseUrl: 'https://tsaas.liveplatform.cn/',
diff --git a/common/js/customer-service.js b/common/js/customer-service.js
index 4960919..bd1b508 100644
--- a/common/js/customer-service.js
+++ b/common/js/customer-service.js
@@ -2,13 +2,68 @@
* 客服统一处理服务
* 整合各种客服方式,提供统一的调用接口
*/
-export class CustomerService {
- constructor(vueInstance, externalConfig = null) {
+class CustomerService {
+ constructor(vueInstance, externalConfig = {}) {
+ if (!vueInstance.$lang) {
+ throw new Error('CustomerService 必须在 Vue 实例中初始化');
+ }
+
this.vm = vueInstance;
this.externalConfig = externalConfig; // 外部传入的最新配置(优先级最高)
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 外部最新配置
@@ -82,7 +137,7 @@ export class CustomerService {
validateConfig() {
const config = this.getPlatformConfig();
const wxworkConfig = this.getWxworkConfig();
-
+
const result = {
isValid: true,
errors: [],
@@ -122,35 +177,11 @@ export class CustomerService {
}
/**
- * 跳转到Dify客服页面
+ * 跳转到AI客服页面
*/
- openDifyService() {
- try {
- if (this.vm.setAiUnreadCount) {
- 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'
- });
- }
+ openAIKeFuService() {
+ const vm = this.vm;
+ vm.$util.redirectTo(vm.$util.AI_CHAT_PAGE_URL);
}
/**
@@ -170,7 +201,7 @@ export class CustomerService {
}
const config = this.getPlatformConfig();
- const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
+ const { niushop = {}, sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
if (config.type === 'none') {
this.showNoServicePopup();
@@ -180,7 +211,7 @@ export class CustomerService {
// 核心分支:根据最新的type处理
switch (config.type) {
case 'aikefu':
- this.openDifyService();
+ this.openAIKeFuService();
break;
case 'wxwork':
this.openWxworkService(false, config, options);
@@ -211,7 +242,7 @@ export class CustomerService {
openWxworkService(useOriginalService = false, servicerConfig = null, options = {}) {
const config = servicerConfig || this.getPlatformConfig();
const wxworkConfig = this.getWxworkConfig();
- const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
+ const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
// #ifdef MP-WEIXIN
if (wxworkConfig?.enable && wxworkConfig?.contact_url && !useOriginalService) {
@@ -292,7 +323,7 @@ export class CustomerService {
* @param {Object} options 选项参数
*/
handleCustomWeappService(config, options = {}) {
- const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options;
+ const { sendMessageTitle = '', sendMessagePath = '', sendMessageImg = '' } = options || {};
if (config.customServiceUrl) {
let url = config.customServiceUrl;
@@ -300,11 +331,11 @@ export class CustomerService {
if (sendMessageTitle) params.push(`title=${encodeURIComponent(sendMessageTitle)}`);
if (sendMessagePath) params.push(`path=${encodeURIComponent(sendMessagePath)}`);
if (sendMessageImg) params.push(`img=${encodeURIComponent(sendMessageImg)}`);
-
+
if (params.length > 0) {
url += (url.includes('?') ? '&' : '?') + params.join('&');
}
-
+
uni.navigateTo({
url: url,
fail: (err) => {
@@ -328,7 +359,7 @@ export class CustomerService {
// #ifdef H5
window.open(config.thirdPartyServiceUrl, '_blank');
// #endif
-
+
// #ifdef MP-WEIXIN
if (config.thirdPartyMiniAppId) {
wx.navigateToMiniProgram({
@@ -381,7 +412,7 @@ export class CustomerService {
console.log('支付宝小程序客服', config);
switch (config.type) {
case 'aikefu':
- this.openDifyService();
+ this.openAIKeFuService();
break;
case 'third':
this.openThirdService(config);
@@ -395,26 +426,29 @@ export class CustomerService {
/**
* 拨打电话
*/
- makePhoneCall() {
- this.vm.$api.sendRequest({
- url: '/api/site/shopcontact',
- success: res => {
- if (res.code === 0 && res.data?.mobile) {
+ makePhoneCall(mobileNumber) {
+ if (mobileNumber) {
+ return uni.makePhoneCall({
+ phoneNumber: mobileNumber
+ });
+ }
+
+ // 从缓存中获取电话信息
+ uni.getStorage({
+ key: 'shopInfo',
+ success: (res) => {
+ const shopInfo = res.data;
+ const mobile = shopInfo?.mobile ?? '';
+ if (mobile) {
uni.makePhoneCall({
- phoneNumber: res.data.mobile
- });
+ phoneNumber: mobile
+ });
} else {
uni.showToast({
title: '暂无客服电话',
icon: 'none'
- });
+ });
}
- },
- fail: () => {
- uni.showToast({
- title: '获取客服电话失败',
- icon: 'none'
- });
}
});
}
@@ -424,8 +458,8 @@ export class CustomerService {
*/
showNoServicePopup() {
const siteInfo = this.vm.$store.state.siteInfo || {};
- const message = siteInfo?.site_tel
- ? `请联系客服,客服电话是${siteInfo.site_tel}`
+ const message = siteInfo?.site_tel
+ ? `请联系客服,客服电话是${siteInfo.site_tel}`
: '抱歉,商家暂无客服,请线下联系';
uni.showModal({
@@ -506,6 +540,6 @@ export class CustomerService {
* @param {Object} externalConfig 外部最新配置
* @returns {CustomerService} 客服服务实例
*/
-export function createCustomerService(vueInstance, externalConfig = null) {
+export function createCustomerService(vueInstance, externalConfig = {}) {
return new CustomerService(vueInstance, externalConfig);
}
\ No newline at end of file
diff --git a/common/js/lang.js b/common/js/lang.js
index 613012d..c8ca741 100644
--- a/common/js/lang.js
+++ b/common/js/lang.js
@@ -1,161 +1,205 @@
import { langConfig } from './config-external.js';
+
// 缓存已加载的语言包
const loadedLangPacks = {};
// 处理页面目录映射
function processRoutePath(route) {
- let routeParts = route.split("/");
+ let routeParts = route.split("/");
- // ---- 处理页面目录映射 分包造成的,需要根据实际目录结构进行映射----
- if (routeParts[0] === 'pages_tool') {
- routeParts = [routeParts[1], ...routeParts.slice(2)];
- } else if (routeParts[0] === 'pages_goods') {
- routeParts[0] = 'goods';
- } else if (routeParts[0] === 'pages_member') {
- routeParts[0] = 'member';
- } else if (routeParts[0] === 'pages_order') {
- routeParts[0] = 'order';
- } else if (routeParts[0] === 'pages_promotion') {
- const promotionModules = ['point', 'fenxiao', 'merch'];
- if (routeParts[1] && promotionModules.includes(routeParts[1])) {
- routeParts = [routeParts[1], ...routeParts.slice(2)];
- }
- }
- // ---- 处理页面目录映射 ----
-
- if (routeParts[0] === 'pages') {
- routeParts = routeParts.slice(1);
- }
-
- return routeParts.join("/");
+ // ---- 处理页面目录映射 分包造成的,需要根据实际目录结构进行映射----
+ // 先处理特殊的分包路径
+ if (routeParts[0] === 'pages_tool') {
+ // pages_tool 分包下的页面,直接使用子目录作为语言包路径
+ routeParts = [routeParts[1], ...routeParts.slice(2)];
+ } else if (routeParts[0] === 'pages_goods') {
+ // pages_goods 分包映射到 goods 目录
+ routeParts[0] = 'goods';
+ } else if (routeParts[0] === 'pages_member') {
+ // pages_member 分包映射到 member 目录
+ routeParts[0] = 'member';
+ } else if (routeParts[0] === 'pages_order') {
+ // pages_order 分包映射到 order 目录
+ routeParts[0] = 'order';
+ } else if (routeParts[0] === 'pages_promotion') {
+ // pages_promotion 分包特殊处理
+ const promotionModules = ['point', 'fenxiao', 'merch'];
+ if (routeParts[1] && promotionModules.includes(routeParts[1])) {
+ routeParts = [routeParts[1], ...routeParts.slice(2)];
+ }
+ }
+ // ---- 处理页面目录映射 ----
+
+ // 去掉pages目录,只保留子目录
+ if (routeParts[0] === 'pages') {
+ routeParts = routeParts.slice(1);
+ }
+
+ return routeParts.join("/");
}
// 加载语言包(同步方式)
function loadLangPackSync(lang, path) {
- try {
- if (loadedLangPacks[`${lang}_${path}`]) {
- return loadedLangPacks[`${lang}_${path}`];
- }
- const langData = require(`@/lang/${lang}/${path}.js`).lang;
- loadedLangPacks[`${lang}_${path}`] = langData;
- return langData;
- } catch (error) {
- console.error(`加载语言包 ${lang}/${path} 失败:`, error);
- return {};
- }
+ try {
+ if (loadedLangPacks[`${lang}_${path}`]) {
+ return loadedLangPacks[`${lang}_${path}`];
+ }
+ const langData = require(`@/lang/${lang}/${path}.js`).lang;
+ loadedLangPacks[`${lang}_${path}`] = langData;
+ return langData;
+ } catch (error) {
+ console.error(`加载语言包 ${lang}/${path} 失败:`, error);
+ return {};
+ }
}
export default {
- langList: langConfig.langList,
- /**
- * 解析多语言
- */
- lang(field) {
- let _this = getCurrentPages()[getCurrentPages().length - 1];
- if (!_this) return;
+ langList: langConfig.langList,
+ /**
+ * * 解析多语言
+ * @param {Object} field
+ */
+ lang(field) {
+ let _this = getCurrentPages()[getCurrentPages().length - 1];
+ if (!_this) return;
- const locale = uni.getStorageSync('lang') || "zh-cn";
+ const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
- let value = '';
- let langPath = '';
+ let value = ''; // 存放解析后的语言值
+ let langPath = ''; // 存放当前页面语言包路径
- try {
- var lang = loadLangPackSync(locale, 'common');
-
- let route = _this.route;
- langPath = processRoutePath(route);
-
- let currentPageLang = loadLangPackSync(locale, langPath);
+ try {
+ //公共语言包(同步加载)
+ var lang = loadLangPackSync(locale, 'common');
+
+ //当前页面语言包(同步加载)
+ let route = _this.route;
+ langPath = processRoutePath(route);
+
+ // 加载当前页面语言包
+ let currentPageLang = loadLangPackSync(locale, langPath);
- let mergedLang = { ...lang, ...currentPageLang };
+ // 合并语言包
+ let mergedLang = { ...lang, ...currentPageLang };
- var arr = field.split(".");
- if (arr.length > 1) {
- let temp = mergedLang;
- let found = true;
- for (let key of arr) {
- if (temp[key] !== undefined) {
- temp = temp[key];
- } else {
- found = false;
- break;
- }
- }
- value = found ? temp : field;
- } else {
- value = mergedLang[field] !== undefined ? mergedLang[field] : field;
- }
-
- } catch (e) {
- console.error('解析语言包失败:', e, { langPath, field, locale });
- value = field;
- }
+ // 解析字段
+ var arr = field.split(".");
+ if (arr.length > 1) {
+ // 处理嵌套属性,如 common.currencySymbol
+ let temp = mergedLang;
+ let found = true;
+ for (let key of arr) {
+ if (temp[key] !== undefined) {
+ temp = temp[key];
+ } else {
+ found = false;
+ break;
+ }
+ }
+ value = found ? temp : field;
+ } else {
+ value = mergedLang[field] !== undefined ? mergedLang[field] : field;
+ }
+
+ } catch (e) {
+ console.error('解析语言包失败:', e, { langPath, field, locale });
+ value = field;
+ }
- if (arguments.length > 1) {
- for (var i = 1; i < arguments.length; i++) {
- value = value.replace("{" + (i - 1) + "}", arguments[i]);
- }
- }
- if (value == undefined || (value == 'title' && field == 'title')) value = '';
+ if (arguments.length > 1) {
+ //有参数,需要替换
+ for (var i = 1; i < arguments.length; i++) {
+ value = value.replace("{" + (i - 1) + "}", arguments[i]);
+ }
+ }
+ if (value == undefined || (value == 'title' && field == 'title')) value = ''; // field
- if (field == value) {
- console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
- }
+ // 多语言调试,注释后可以关闭控制台输出
+ if (field == value) {
+ console.warn(`警告: 字段 ${field} 在语言包 ${langPath} 中未找到对应值,使用默认值 ${field} 当前语言: ${locale}`);
+ }
- return value;
- },
- /**
- * 切换语言
- */
- change(value, url = '/pages_tool/member/index') {
- let _this = getCurrentPages()[getCurrentPages().length - 1];
- if (!_this) return;
+ return value;
+ },
+ /**
+ * * 切换语言
+ * @param {String} value 语言值
+ * @param {String} url 切换后跳转的页面url
+ */
+ change(value, url = '/pages_tool/member/index') {
+ let _this = getCurrentPages()[getCurrentPages().length - 1];
+ if (!_this) return;
- uni.setStorageSync("lang", value);
- const locale = uni.getStorageSync('lang') || "zh-cn";
+ uni.setStorageSync("lang", value);
+ const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
- // ✅ 关键修复:清空所有语言包缓存(不再保留任何旧缓存)
- for (let key in loadedLangPacks) {
- delete loadedLangPacks[key];
- }
+ // 清空已加载的语言包缓存
+ for (let key in loadedLangPacks) {
+ if (!key.startsWith(locale)) {
+ delete loadedLangPacks[key];
+ }
+ }
- this.refresh();
+ this.refresh();
- if (url) {
- uni.reLaunch({ url: url });
- }
- },
- //刷新标题、tabbar
- refresh() {
- let _this = getCurrentPages()[getCurrentPages().length - 1];
- if (!_this) return;
- const locale = uni.getStorageSync('lang') || "zh-cn";
-
- this.title(this.lang("title"));
- },
- title(str) {
- if (str) {
- uni.setNavigationBarTitle({
- title: str
- });
- }
- },
- // 获取语言包列表
- list() {
- var list = [];
- try {
- for (var i = 0; i < langConfig.langList.length; i++) {
- let langType = langConfig.langList[i];
- let item = loadLangPackSync(langType, 'common');
- list.push({
- name: item.common ? item.common.name : langType,
- value: langType
- });
- }
- } catch (e) {
- console.error('获取语言包列表失败:', e);
- }
- return list;
- }
-}
\ No newline at end of file
+ if (url) {
+ uni.reLaunch({ url: url });
+ }
+ },
+ //刷新标题、tabbar
+ refresh() {
+ let _this = getCurrentPages()[getCurrentPages().length - 1];
+ if (!_this) return;
+ const locale = uni.getStorageSync('lang') || "zh-cn"; //设置语言
+
+ this.title(this.lang("title"));
+
+ //设置tabbar的文字语言
+ // uni.setTabBarItem({
+ // index: 0,
+ // text: this.lang("tabBar.home")
+ // });
+ // uni.setTabBarItem({
+ // index: 1,
+ // text: this.lang("tabBar.category")
+ // });
+ // uni.setTabBarItem({
+ // index: 2,
+ // text: this.lang("tabBar.cart")
+ // });
+ // uni.setTabBarItem({
+ // index: 3,
+ // text: this.lang("tabBar.member")
+ // });
+ },
+ title(str) {
+ if (str) {
+ uni.setNavigationBarTitle({
+ title: str,
+ success: function (res) {
+ },
+ fail: function (err) {
+ }
+ });
+ }
+ },
+ // 获取语言包列表
+ list() {
+ var list = [];
+ try {
+ //公共语言包
+ for (var i = 0; i < langConfig.langList.length; i++) {
+ let langType = langConfig.langList[i];
+ let item = loadLangPackSync(langType, 'common');
+ list.push({
+ name: item.common ? item.common.name : langType,
+ value: langType
+ });
+ }
+ } catch (e) {
+ console.error('获取语言包列表失败:', e);
+ }
+ return list;
+ }
+}
diff --git a/common/js/util.js b/common/js/util.js
index 24036f4..8d9cb2f 100644
--- a/common/js/util.js
+++ b/common/js/util.js
@@ -13,6 +13,7 @@ export const CATEGORY_PAGE_URL = '/pages_goods/category';
export const CONTACT_PAGE_URL = '/pages_tool/contact/contact';
export const MEMBER_PAGE_URL = '/pages_tool/member/index';
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 配置)
export const systemTabBarList = [
@@ -119,6 +120,7 @@ export default {
CONTACT_PAGE_URL,
INDEX_PAGE_URL,
LOGIN_PAGE_URL,
+ AI_CHAT_PAGE_URL,
/**
* 页面跳转
diff --git a/components/hover-nav/hover-nav.vue b/components/hover-nav/hover-nav.vue
index f2b1d7a..3ef65a7 100644
--- a/components/hover-nav/hover-nav.vue
+++ b/components/hover-nav/hover-nav.vue
@@ -1,64 +1,43 @@
-
-
-
-
- 🤖
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
{{ currentLangDisplayName }}
+
+
+ 🤖
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -77,17 +56,12 @@ export default {
return {
pageCount: 0,
fixBtnShow: true,
+
shopInfo: null,
currentLangIndex: 0,
langIndexMap: {},
- kefuList: [
- { id: 'weixin-official', name: '微信官方客服', isOfficial: true, type: 'weapp' },
- { id: 'custom-kefu', name: '自定义在线客服', isOfficial: false, type: 'custom' },
- { id: 'qyweixin-kefu', name: '企业微信客服', isOfficial: false, type: 'qyweixin' }
- ],
- selectedKefu: null,
+
customerService: null,
- buttonConfig: null,
};
},
computed: {
@@ -111,13 +85,8 @@ export default {
return !!this.shopInfo?.ischina;
},
enableAIChat() {
- const defaultEnable = true;
- if (!this.shopInfo) return defaultEnable;
- return this.shopInfo.hasOwnProperty('enableAIChat')
- ? !!this.shopInfo.enableAIChat
- : defaultEnable;
+ return !!this.shopInfo?.enableAIChat;
},
-
currentLangDisplayName() {
const lang = this.langIndexMap[this.currentLangIndex];
return lang === 'zh-cn' ? 'EN' : 'CN';
@@ -127,39 +96,22 @@ export default {
},
customButtonStyle() {
return this.shopInfo?.floatingButton?.button || {};
- },
- customTextStyle() {
- return this.shopInfo?.floatingButton?.text || {};
- },
- unreadCount() {
- return this.$store.state.aiUnreadCount || 0;
- }
- },
- watch: {
- shopInfo: {
- handler(newVal) {
- // 可在此添加额外逻辑(如埋点、通知等),当前无需操作
- },
- immediate: true
}
},
created() {
+ this.customerService = createCustomerService(this);
this.initLanguage();
- this.pageCount = getCurrentPages().length;
-
uni.getStorage({
key: 'shopInfo',
success: (e) => {
- console.log('【调试】当前 shopInfo:', e.data);
this.shopInfo = e.data;
- },
- fail: () => {
- console.warn('未获取到 shopInfo,使用默认设置');
- // shopInfo 为 null,computed 会自动返回默认值,无需手动赋值
}
});
},
methods: {
+ /**
+ * 初始化多语言配置
+ */
initLanguage() {
this.langList = this.$langConfig.list();
this.langIndexMap = {};
@@ -178,78 +130,41 @@ export default {
this.currentLangIndex = 0;
}
},
+ /**
+ * 电话联系客服
+ */
call() {
- if (this.tel) {
- uni.makePhoneCall({ phoneNumber: this.tel + '' });
- } else {
- uni.showToast({ title: '暂无联系电话', icon: 'none' });
- }
+ this.customerService.makePhoneCall(this.tel);
},
/**
* 切换中英文语言,并刷新当前页面(保留所有参数)
*/
- toggleLanguage() {
- this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
- const targetLang = this.langIndexMap[this.currentLangIndex];
-
- // 调用语言切换逻辑(设置 storage + 清空缓存)
- this.$langConfig.change(targetLang);
-
- // H5 环境需要强制刷新页面才能生效
- if (uni.getSystemInfoSync().platform === 'browser') {
- // 延迟 100ms 确保 change() 执行完成
- setTimeout(() => {
- window.location.reload();
- }, 100);
- }
- },
- openKefuSelectPopup() {
- const kefuNames = this.kefuList.map(item => item.name);
- uni.showActionSheet({
- itemList: kefuNames,
- success: (res) => {
- this.selectedKefu = this.kefuList[res.tapIndex];
- this.reinitCustomerService(this.selectedKefu);
- this.handleSelectedKefu();
- }
- });
- },
- reinitCustomerService(kefu) {
- this.customerService = createCustomerService(this, kefu);
- this.buttonConfig = this.customerService.getButtonConfig();
- },
- handleSelectedKefu() {
- const kefu = this.selectedKefu;
- if (!kefu) return;
+ toggleLanguage() {
+ this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
+ const targetLang = this.langIndexMap[this.currentLangIndex];
- if (kefu.isOfficial) {
- uni.openCustomerServiceConversation({
- sessionFrom: 'weapp',
- showMessageCard: true
- });
- } else if (kefu.id === 'custom-kefu') {
- this.customerService.handleCustomerClick();
- } else if (kefu.id === 'qyweixin-kefu') {
- this.customerService.handleQyWeixinKefuClick();
- }
+ // 调用语言切换逻辑(设置 storage + 清空缓存)
+ this.$langConfig.change(targetLang);
},
+
+ /**
+ * 打开 AI 智能助手
+ */
openAIChat() {
- uni.navigateTo({
- url: '/pages_tool/ai-chat/index',
- success: () => {
- console.log('✅ AI 客服跳转成功');
- },
- fail: (err) => {
- console.error('❌ 跳转失败:', err);
- uni.showToast({ title: '跳转失败,请重试', icon: 'none' });
- }
- });
+ this.$util.redirectTo(this.$util.AI_CHAT_PAGE_URL);
+ },
+ openCustomerSelectPopup() {
+ if (this.customerService) {
+ this.customerService.openCustomerSelectPopupDialog();
+ } else {
+ uni.showToast({ title: '客服初始化中,请稍后重试', icon: 'none' });
+ }
}
}
}
-
-
\ No newline at end of file
diff --git a/pages_tool/ai-chat/index.json b/pages_tool/ai-chat/index.json
deleted file mode 100644
index 370e1ed..0000000
--- a/pages_tool/ai-chat/index.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "navigationBarBackgroundColor": "#ff4544",
- "navigationBarTextStyle": "white",
- "backgroundColor": "#f8f8f8",
- "enablePullDownRefresh": false,
- "onReachBottomDistance": 50,
- "usingComponents": {
- "ai-chat-message": "/components/ai-chat-message/ai-chat-message"
- }
-}
\ No newline at end of file
diff --git a/pages_tool/ai-chat/index.vue b/pages_tool/ai-chat/index.vue
index 39b3658..3b901cc 100644
--- a/pages_tool/ai-chat/index.vue
+++ b/pages_tool/ai-chat/index.vue
@@ -531,7 +531,7 @@ export default {
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/components_usage_documentation.md b/docs/components_usage_documentation.md
new file mode 100644
index 0000000..1a1ad65
--- /dev/null
+++ b/docs/components_usage_documentation.md
@@ -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
\ No newline at end of file
diff --git a/pages/contact/contact.vue b/pages/contact/contact.vue
deleted file mode 100644
index 62984d6..0000000
--- a/pages/contact/contact.vue
+++ /dev/null
@@ -1,511 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- 在线留言
-
-
-
-
-
-
-
-
-
-
-
-
-
- 在线留言
-
-
-
-
-
-
-
-
-
-
- {{item.realname}}
- {{item.position}}
-
- {{item.address}}
-
-
- {{item.mobile}}
- 一键拨打
-
-
-
- {{item.email}}
- 立即导航
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/components/goods-detail-view/detail.js b/pages_goods/_components/goods-detail-view/detail.js
similarity index 100%
rename from components/goods-detail-view/detail.js
rename to pages_goods/_components/goods-detail-view/detail.js
diff --git a/components/goods-detail-view/goods-detail-view.vue b/pages_goods/_components/goods-detail-view/goods-detail-view.vue
similarity index 75%
rename from components/goods-detail-view/goods-detail-view.vue
rename to pages_goods/_components/goods-detail-view/goods-detail-view.vue
index 3a6a6cb..0020ac9 100644
--- a/components/goods-detail-view/goods-detail-view.vue
+++ b/pages_goods/_components/goods-detail-view/goods-detail-view.vue
@@ -3,16 +3,21 @@
-
+
-
+
-
-
+
+
-
+
@@ -24,13 +29,16 @@
-
+
- {{ $lang('video') }}
- {{ $lang('image') }}
+ {{
+ $lang('video') }}
+ {{ $lang('image') }}
@@ -40,19 +48,20 @@
-
+
-
-
- {{$lang('send')}}
+
+
+ {{ $lang('send') }}
- {{$lang('express')}}
-
+ {{ $lang('express') }}
+
@@ -63,7 +72,7 @@
-
-
+
服务
-
+
-
-
-
+
+
+
{{ item.service_name }}
@@ -96,30 +111,32 @@
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
- {{goodsSkuDetail.merchinfo.merch_name}}
- 官方认证商家,值得信赖!
-
+
+
+ {{ goodsSkuDetail.merchinfo.merch_name }}
+ 官方认证商家,值得信赖!
+
@@ -136,7 +153,8 @@
-
+
{{ item.name }}
@@ -158,11 +176,16 @@
-
-
-
-
-
+
+
+
+
+
{{ item.service_name }}
@@ -187,17 +210,19 @@
-
+
-
-
+
+
{{ item.store_name }}
- 距离{{ item.distance > 1 ? item.distance + 'km' : item.distance * 1000 + 'm' }}
+ 距离{{ item.distance > 1 ? item.distance + 'km' : item.distance *
+ 1000 + 'm' }}
营业时间:{{ item.open_date }}
@@ -228,7 +253,7 @@
-
-
+
@@ -268,12 +294,18 @@
-
-
+
+
-
- {{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1] }}
+
+ {{ item.member_name[0] }}***{{ item.member_name[item.member_name.length - 1]
+ }}
{{ item.member_name }}
@@ -286,7 +318,8 @@
{{ item.content }}
-
+
@@ -294,8 +327,9 @@
-
-
+
+
规格属性
@@ -304,7 +338,8 @@
{{ item.attr_value_name }}
-
+
展开
@@ -315,24 +350,25 @@
-
+
- {{$lang('details')}}
+ {{ $lang('details') }}
-
-
-
-
+
+
+
+
-
+
@@ -419,25 +455,30 @@
\ No newline at end of file
diff --git a/components/ns-goods-promotion/ns-goods-promotion.vue b/pages_goods/_components/ns-goods-promotion/ns-goods-promotion.vue
similarity index 100%
rename from components/ns-goods-promotion/ns-goods-promotion.vue
rename to pages_goods/_components/ns-goods-promotion/ns-goods-promotion.vue
diff --git a/components/pengpai-fadein-out/pengpai-fadein-out.vue b/pages_goods/_components/pengpai-fadein-out/pengpai-fadein-out.vue
similarity index 100%
rename from components/pengpai-fadein-out/pengpai-fadein-out.vue
rename to pages_goods/_components/pengpai-fadein-out/pengpai-fadein-out.vue
diff --git a/pages_goods/detail.vue b/pages_goods/detail.vue
index 2328b31..5e7d1f1 100644
--- a/pages_goods/detail.vue
+++ b/pages_goods/detail.vue
@@ -519,12 +519,19 @@