Compare commits
3 Commits
def8a6cf6f
...
release/v1
| Author | SHA1 | Date | |
|---|---|---|---|
| e19fef785f | |||
| 92ae114c5c | |||
| b25c366a5b |
@@ -42,6 +42,14 @@ const localDevConfig = ({
|
|||||||
uniacid: 2,
|
uniacid: 2,
|
||||||
domain: 'http://localhost:8050/',
|
domain: 'http://localhost:8050/',
|
||||||
},
|
},
|
||||||
})['1']; // 选择要使用的环境配置
|
'47': { // 修改弹窗
|
||||||
|
uniacid: 47,
|
||||||
|
domain: 'https://5g.aigc-quickapp.com/',
|
||||||
|
},
|
||||||
|
'2075': { //
|
||||||
|
uniacid: 2075,
|
||||||
|
domain: 'https://xcx.aigc-quickapp.com/',
|
||||||
|
},
|
||||||
|
})['47']; // 选择要使用的环境配置
|
||||||
|
|
||||||
export default localDevConfig;
|
export default localDevConfig;
|
||||||
@@ -120,7 +120,6 @@
|
|||||||
<text>{{ showMarketPrice(item) }}</text>
|
<text>{{ showMarketPrice(item) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- <view class="right-wrap" v-if="value.template == 2 || value.template == 4">
|
<!-- <view class="right-wrap" v-if="value.template == 2 || value.template == 4">
|
||||||
<block v-if="item.is_virtual">
|
<block v-if="item.is_virtual">
|
||||||
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
@@ -213,7 +212,6 @@
|
|||||||
<text>{{ showMarketPrice(item) }}</text>
|
<text>{{ showMarketPrice(item) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="right-wrap" v-if="value.template == 2">
|
<view class="right-wrap" v-if="value.template == 2">
|
||||||
<block v-if="item.is_virtual">
|
<block v-if="item.is_virtual">
|
||||||
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
<view class="color-base-bg select-sku" @tap.stop="toDetail(item)">立即购买</view>
|
||||||
@@ -720,25 +718,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* 发送商品信息到智能客服
|
|
||||||
* @param {Object} item 商品信息
|
|
||||||
*/
|
|
||||||
sendToAIChat(item) {
|
|
||||||
const productInfo = {
|
|
||||||
goods_id: item.goods_id,
|
|
||||||
goods_name: item.goods_name,
|
|
||||||
price: this.showPrice(item),
|
|
||||||
image: this.goodsImg(item.goods_image),
|
|
||||||
category_id: item.category_id
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.setStorageSync('selectedProduct', productInfo)
|
|
||||||
|
|
||||||
uni.navigateTo({
|
|
||||||
url: '/pages_tool/ai-chat/index'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
diyRedirectTo(link) {
|
diyRedirectTo(link) {
|
||||||
if (!link) return;
|
if (!link) return;
|
||||||
this.$util.diyRedirectTo(JSON.parse(link));
|
this.$util.diyRedirectTo(JSON.parse(link));
|
||||||
@@ -1405,6 +1384,4 @@ export default {
|
|||||||
color: var(--main-color);
|
color: var(--main-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -53,19 +53,9 @@
|
|||||||
|
|
||||||
<!-- 视频播放弹窗 -->
|
<!-- 视频播放弹窗 -->
|
||||||
<uni-popup ref="videoPopup" type="center" style="background:transparent;width:100%;height:100%;">
|
<uni-popup ref="videoPopup" type="center" style="background:transparent;width:100%;height:100%;">
|
||||||
<view class="video-container" :style="popupVideoStyle">
|
<view class="video-container" style="position:fixed;top:30%;width:100%;left:0;">
|
||||||
<video
|
<video class="adaptive-video" :autoPauseIfNavigate="true" :autoPauseIfOpenNative="true"
|
||||||
ref="popupVideoRef"
|
:autoplay="false" :enableAutoRotation="true" id="myVideo" :src="video_url" :controls="true"></video>
|
||||||
class="adaptive-video"
|
|
||||||
:autoPauseIfNavigate="true"
|
|
||||||
:autoPauseIfOpenNative="true"
|
|
||||||
:autoplay="false"
|
|
||||||
:enableAutoRotation="true"
|
|
||||||
id="myVideo"
|
|
||||||
:src="video_url"
|
|
||||||
:controls="true"
|
|
||||||
@loadedmetadata="onPopupVideoLoaded"
|
|
||||||
></video>
|
|
||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
@@ -136,38 +126,12 @@ export default {
|
|||||||
isIndicatorDots() {
|
isIndicatorDots() {
|
||||||
return this.value.carousel.type != 'hide' &&
|
return this.value.carousel.type != 'hide' &&
|
||||||
1 != Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount));
|
1 != Math.ceil(this.value.list.length / (this.value.pageCount * this.value.rowCount));
|
||||||
},
|
|
||||||
|
|
||||||
// 弹窗视频容器样式
|
|
||||||
popupVideoStyle() {
|
|
||||||
let style = 'position:fixed;width:100%;left:0;';
|
|
||||||
|
|
||||||
if (this.popupVideoRatio) {
|
|
||||||
// 根据视频比例设置位置
|
|
||||||
if (this.popupVideoRatio === 'portrait') {
|
|
||||||
// 竖屏视频:居中显示,使用9/16比例
|
|
||||||
style += 'top:50%;transform:translateY(-50%);';
|
|
||||||
style += 'aspect-ratio: 9 / 16;';
|
|
||||||
} else {
|
|
||||||
// 横屏视频:靠近顶部显示,使用16/9比例
|
|
||||||
style += 'top:20%;';
|
|
||||||
style += 'aspect-ratio: 16 / 9;';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 默认:居中显示,使用竖屏比例
|
|
||||||
style += 'top:50%;transform:translateY(-50%);';
|
|
||||||
style += 'aspect-ratio: 9 / 16;';
|
|
||||||
}
|
|
||||||
|
|
||||||
return style;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 显示视频播放弹窗
|
// 显示视频播放弹窗
|
||||||
showVideo(item) {
|
showVideo(item) {
|
||||||
this.video_url = item.videoUrl;
|
this.video_url = item.videoUrl;
|
||||||
// 重置视频比例为null,等待新的检测结果
|
|
||||||
this.popupVideoRatio = null;
|
|
||||||
this.$refs.videoPopup.open();
|
this.$refs.videoPopup.open();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -175,39 +139,6 @@ export default {
|
|||||||
imgError(index) {
|
imgError(index) {
|
||||||
// 图片加载失败的处理逻辑
|
// 图片加载失败的处理逻辑
|
||||||
console.log('图片加载失败:', index);
|
console.log('图片加载失败:', index);
|
||||||
},
|
|
||||||
|
|
||||||
// 弹窗视频加载完成事件
|
|
||||||
onPopupVideoLoaded(event) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
let width = 0;
|
|
||||||
let height = 0;
|
|
||||||
|
|
||||||
// H5 端:获取真实视频宽高
|
|
||||||
// #ifdef H5
|
|
||||||
const video = this.$refs.popupVideoRef;
|
|
||||||
if (video) {
|
|
||||||
width = video.videoWidth || 0;
|
|
||||||
height = video.videoHeight || 0;
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// 微信小程序端:通过事件对象获取视频宽高
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
if (event && event.detail) {
|
|
||||||
width = event.detail.width || 0;
|
|
||||||
height = event.detail.height || 0;
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
if (width && height) {
|
|
||||||
this.popupVideoRatio = width >= height ? 'landscape' : 'portrait';
|
|
||||||
console.log(`弹窗视频宽高比检测: ${width}x${height}, 比例: ${this.popupVideoRatio}`);
|
|
||||||
} else {
|
|
||||||
// 获取失败,默认竖屏
|
|
||||||
this.popupVideoRatio = 'portrait';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="video-container" :style="containerStyle">
|
<video data-component-name="diy-video" class="diy-video" :src="$util.img(value.videoUrl)"
|
||||||
<!-- H5端使用原生video标签 -->
|
:poster="$util.img(value.imageUrl)" :style="videoWarpCss" objectFit="cover"
|
||||||
<!-- #ifdef H5 -->
|
@tap="handlerClick(value.videoUrl)"></video>
|
||||||
<video
|
|
||||||
ref="videoRef"
|
|
||||||
data-component-name="diy-video"
|
|
||||||
class="diy-video h5-video"
|
|
||||||
:src="videoUrl"
|
|
||||||
:poster="posterUrl"
|
|
||||||
:style="videoWarpCss"
|
|
||||||
controls
|
|
||||||
preload="metadata"
|
|
||||||
@loadedmetadata="onVideoLoaded"
|
|
||||||
@click="handlerClick(videoUrl)"
|
|
||||||
></video>
|
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- 微信小程序端使用uni-app的video组件 -->
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<video
|
|
||||||
ref="videoRef"
|
|
||||||
data-component-name="diy-video"
|
|
||||||
class="diy-video mp-video"
|
|
||||||
:src="videoUrl"
|
|
||||||
:poster="posterUrl"
|
|
||||||
:style="videoWarpCss"
|
|
||||||
controls
|
|
||||||
@loadedmetadata="onVideoLoaded"
|
|
||||||
@error="onVideoError"
|
|
||||||
></video>
|
|
||||||
<!-- #endif -->
|
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -44,160 +15,27 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {};
|
||||||
videoRatio: null, // 视频比例:'landscape'(横屏)或 'portrait'(竖屏)
|
|
||||||
videoUrl: '',
|
|
||||||
posterUrl: ''
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.initVideoData();
|
|
||||||
},
|
},
|
||||||
|
created() { },
|
||||||
mixins: [DiyMinx],
|
mixins: [DiyMinx],
|
||||||
watch: {
|
watch: {
|
||||||
value: {
|
// 组件刷新监听
|
||||||
immediate: true,
|
componentRefresh: function (nval) { }
|
||||||
handler(newVal) {
|
|
||||||
if (newVal) {
|
|
||||||
this.initVideoData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
videoWarpCss: function () {
|
videoWarpCss: function () {
|
||||||
var obj = '';
|
var obj = '';
|
||||||
if (this.value && this.value.componentAngle == 'round') {
|
if (this.value.componentAngle == 'round') {
|
||||||
obj += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
obj += 'border-top-left-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
||||||
obj += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
obj += 'border-top-right-radius:' + this.value.topAroundRadius * 2 + 'rpx;';
|
||||||
obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
obj += 'border-bottom-left-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
||||||
obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
obj += 'border-bottom-right-radius:' + this.value.bottomAroundRadius * 2 + 'rpx;';
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
},
|
|
||||||
// 动态计算容器比例
|
|
||||||
containerStyle() {
|
|
||||||
let style = '';
|
|
||||||
|
|
||||||
if (this.videoRatio === 'landscape') {
|
|
||||||
// 横屏视频:16/9比例
|
|
||||||
style += 'aspect-ratio: 16 / 9;';
|
|
||||||
} else if (this.videoRatio === 'portrait') {
|
|
||||||
// 竖屏视频:9/16比例
|
|
||||||
style += 'aspect-ratio: 9 / 16;';
|
|
||||||
} else {
|
|
||||||
// 未加载完成 → 默认使用竖屏比例
|
|
||||||
style += 'aspect-ratio: 9 / 16;';
|
|
||||||
}
|
|
||||||
|
|
||||||
return style;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 初始化视频数据
|
|
||||||
initVideoData() {
|
|
||||||
this.videoUrl = this.getVideoUrl();
|
|
||||||
this.posterUrl = this.getPosterUrl();
|
|
||||||
// H5端:预加载视频获取宽高
|
|
||||||
// #ifdef H5
|
|
||||||
this.preloadVideoForRatio();
|
|
||||||
// #endif
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取视频URL
|
|
||||||
getVideoUrl() {
|
|
||||||
if (!this.value || !this.value.videoUrl) return '';
|
|
||||||
const videoUrl = this.value.videoUrl;
|
|
||||||
// 如果是完整的http/https链接,直接使用
|
|
||||||
if (videoUrl.indexOf('http://') === 0 || videoUrl.indexOf('https://') === 0) {
|
|
||||||
return videoUrl;
|
|
||||||
}
|
|
||||||
// 否则使用$util.img()处理
|
|
||||||
return this.$util.img(videoUrl);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取封面图URL
|
|
||||||
getPosterUrl() {
|
|
||||||
if (!this.value || !this.value.imageUrl) return '';
|
|
||||||
return this.$util.img(this.value.imageUrl);
|
|
||||||
},
|
|
||||||
|
|
||||||
// H5端:预加载视频获取宽高比例
|
|
||||||
preloadVideoForRatio() {
|
|
||||||
const videoUrl = this.videoUrl;
|
|
||||||
if (!videoUrl) return;
|
|
||||||
|
|
||||||
console.log('H5端预加载视频获取比例:', videoUrl);
|
|
||||||
|
|
||||||
const video = document.createElement('video');
|
|
||||||
video.preload = 'metadata';
|
|
||||||
video.src = videoUrl;
|
|
||||||
video.muted = true;
|
|
||||||
video.playsInline = true;
|
|
||||||
|
|
||||||
video.addEventListener('loadedmetadata', () => {
|
|
||||||
const width = video.videoWidth;
|
|
||||||
const height = video.videoHeight;
|
|
||||||
console.log('H5端预加载获取视频宽高:', width, height);
|
|
||||||
|
|
||||||
if (width && height) {
|
|
||||||
this.videoRatio = width >= height ? 'landscape' : 'portrait';
|
|
||||||
console.log('H5端视频比例判定:', this.videoRatio, width >= height ? '横屏' : '竖屏');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
video.addEventListener('error', (e) => {
|
|
||||||
console.error('H5端预加载视频失败:', e);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 触发加载
|
|
||||||
video.load();
|
|
||||||
},
|
|
||||||
|
|
||||||
// 视频加载完成事件(组件内video标签)
|
|
||||||
onVideoLoaded(event) {
|
|
||||||
console.log('视频组件 loadedmetadata 事件触发');
|
|
||||||
|
|
||||||
let width = 0;
|
|
||||||
let height = 0;
|
|
||||||
|
|
||||||
// #ifdef H5
|
|
||||||
if (event && event.target) {
|
|
||||||
width = event.target.videoWidth || 0;
|
|
||||||
height = event.target.videoHeight || 0;
|
|
||||||
console.log('H5端组件视频宽高:', width, height);
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
if (event && event.detail) {
|
|
||||||
width = event.detail.width || 0;
|
|
||||||
height = event.detail.height || 0;
|
|
||||||
console.log('微信小程序端视频宽高:', width, height);
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
if (width && height) {
|
|
||||||
this.videoRatio = width >= height ? 'landscape' : 'portrait';
|
|
||||||
console.log('视频比例最终判定:', this.videoRatio);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 视频播放事件
|
|
||||||
onVideoPlay() {
|
|
||||||
console.log('视频开始播放');
|
|
||||||
},
|
|
||||||
|
|
||||||
// 视频暂停事件
|
|
||||||
onVideoPause() {
|
|
||||||
console.log('视频暂停');
|
|
||||||
},
|
|
||||||
|
|
||||||
// 视频错误事件
|
|
||||||
onVideoError(event) {
|
|
||||||
console.error('视频加载失败:', event);
|
|
||||||
},
|
|
||||||
|
|
||||||
async handlerClick(videoUrl) {
|
async handlerClick(videoUrl) {
|
||||||
await this.__$emitEvent({
|
await this.__$emitEvent({
|
||||||
eventName: 'video-tap', data: videoUrl, promiseCallback: (event, handler, awaitedResult) => {
|
eventName: 'video-tap', data: videoUrl, promiseCallback: (event, handler, awaitedResult) => {
|
||||||
@@ -210,32 +48,11 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.video-container {
|
video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 基础样式 */
|
.diy-video>>>.uni-video-container {
|
||||||
.diy-video {
|
background-color: transparent;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* H5端样式 */
|
|
||||||
/* #ifdef H5 */
|
|
||||||
.h5-video {
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
/* #endif */
|
|
||||||
|
|
||||||
/* 微信小程序端样式 */
|
|
||||||
/* #ifdef MP-WEIXIN */
|
|
||||||
.mp-video {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
/* #endif */
|
|
||||||
</style>
|
</style>
|
||||||
@@ -71,14 +71,11 @@
|
|||||||
"scope.userLocation" : {
|
"scope.userLocation" : {
|
||||||
"desc" : "为了更好地为您提供服务"
|
"desc" : "为了更好地为您提供服务"
|
||||||
},
|
},
|
||||||
|
"scope.writePhotosAlbum" : {
|
||||||
|
"desc" : "为了更好地为您提供服务"
|
||||||
|
},
|
||||||
"scope.userClipboard" : {
|
"scope.userClipboard" : {
|
||||||
"desc" : "为了方便您复制信息"
|
"desc" : "为了方便您复制信息"
|
||||||
},
|
|
||||||
"scope.camera" : {
|
|
||||||
"desc" : "用于拍照上传头像"
|
|
||||||
},
|
|
||||||
"scope.writePhotosAlbum" : {
|
|
||||||
"desc" : "用于从相册选择和保存头像"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requiredPrivateInfos" : [ "chooseLocation", "getLocation", "chooseAddress" ],
|
"requiredPrivateInfos" : [ "chooseLocation", "getLocation", "chooseAddress" ],
|
||||||
|
|||||||
@@ -17,10 +17,6 @@
|
|||||||
}}</view>
|
}}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- <view class="page-header" v-if="diyData.global && diyData.global.navBarSwitch" :style="{ backgroundImage: bgImg }">
|
|
||||||
<ns-navbar :title-color="textNavColor" :data="diyData.global" :scrollTop="scrollTop" :isBack="false"/>
|
|
||||||
</view> -->
|
|
||||||
|
|
||||||
<diy-index-page v-if="topIndexValue" ref="indexPage" :value="topIndexValue" :bgUrl="bgUrl"
|
<diy-index-page v-if="topIndexValue" ref="indexPage" :value="topIndexValue" :bgUrl="bgUrl"
|
||||||
:scrollTop="scrollTop" :diyGlobal="diyData.global" class="diy-index-page">
|
:scrollTop="scrollTop" :diyGlobal="diyData.global" class="diy-index-page">
|
||||||
<template v-slot:components>
|
<template v-slot:components>
|
||||||
@@ -43,35 +39,17 @@
|
|||||||
<view @touchmove.prevent.stop>
|
<view @touchmove.prevent.stop>
|
||||||
<uni-popup ref="uniPopupWindow" type="center" class="wap-floating" :maskClick="false">
|
<uni-popup ref="uniPopupWindow" type="center" class="wap-floating" :maskClick="false">
|
||||||
<view class="small-bot">
|
<view class="small-bot">
|
||||||
<!-- <view class="adver-time" wx:if="{{startadv.params.style=='default'&&startadv.params.canclose==1}}">
|
|
||||||
<view bindtap="adverclose">跳过</view>
|
|
||||||
<view class="time">{{clock}}s</view>
|
|
||||||
</view>
|
|
||||||
<view class="adver-time" wx:if="{{startadv.params.style=='default'&&startadv.params.canclose==0}}">
|
|
||||||
<view class="time" style="line-height: 64rpx;">{{clock}}s</view>
|
|
||||||
</view> -->
|
|
||||||
<swiper autoplay="true" :circular="true" indicator-active-color="#fff"
|
<swiper autoplay="true" :circular="true" indicator-active-color="#fff"
|
||||||
indicator-color="rgba(255,255,255,0.6)" :indicator-dots="true" interval="3000">
|
indicator-color="rgba(255,255,255,0.6)" :indicator-dots="true" interval="3000">
|
||||||
<swiper-item v-for="(item, index) in adv.list" :key="index">
|
<swiper-item v-for="(item, index) in adv.list" :key="index">
|
||||||
<image class="slide-image" @click="$util.diyRedirectTo(item.link)" height="100%"
|
<image class="slide-image" @click="$util.diyRedirectTo(item.link)" height="100%"
|
||||||
:src="$util.img(item.imageUrl)" width="100%"></image>
|
:src="$util.img(item.imageUrl)" width="100%"></image>
|
||||||
<!-- <image bindtap="adverclose" class="slide-image" height="100%" src="{{item.imgurl}}" width="100%" wx:if="{{item.click==1}}"></image> -->
|
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
<view bindtap="adverclose" class="small-bot-close" @click="closePopupWindow">
|
<view bindtap="adverclose" class="small-bot-close" @click="closePopupWindow">
|
||||||
<i class="iconfont icon-round-close" style="color:#fff"></i>
|
<i class="iconfont icon-round-close" style="color:#fff"></i>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- <view class="image-wrap">
|
|
||||||
<swiper class="swiper" style="width:100%;height: 1200rpx;" :autoplay="true" interval="3000" circular="true" :indicator-dots="true" indicator-color="#000" indicator-active-color="red">
|
|
||||||
<swiper-item class="swiper-item" v-for="(item, index) in adv.list" :key="index" v-if="item.imageUrl" @click="$util.diyRedirectTo(item.link)">
|
|
||||||
<view class="item">
|
|
||||||
<image :src="$util.img(item.imageUrl)" mode="aspectFit" :show-menu-by-longpress="true"/>
|
|
||||||
</view>
|
|
||||||
</swiper-item>
|
|
||||||
</swiper>
|
|
||||||
</view>
|
|
||||||
<text class="iconfont icon-round-close" @click="closePopupWindow"></text> -->
|
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -101,7 +79,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
|
|
||||||
<!-- 选择门店弹出框,定位当前位置,展示最近的一个门店 -->
|
<!-- 选择门店弹出框 -->
|
||||||
<view @touchmove.prevent.stop class="choose-store">
|
<view @touchmove.prevent.stop class="choose-store">
|
||||||
<uni-popup ref="chooseStorePopup" type="center" :maskClick="false" class="choose-store">
|
<uni-popup ref="chooseStorePopup" type="center" :maskClick="false" class="choose-store">
|
||||||
<view class="choose-store-popup">
|
<view class="choose-store-popup">
|
||||||
@@ -136,8 +114,27 @@
|
|||||||
</view>
|
</view>
|
||||||
</uni-popup>
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<hover-nav :need="true"></hover-nav>
|
<hover-nav :need="true"></hover-nav>
|
||||||
<!-- 隐私协议 -->
|
|
||||||
|
<!-- 隐私协议弹窗 UI (新增) -->
|
||||||
|
<view v-if="showPrivacyModal" class="privacy-modal-mask" @touchmove.prevent>
|
||||||
|
<view class="privacy-modal-container">
|
||||||
|
<view class="modal-header">用户隐私保护提示</view>
|
||||||
|
<view class="modal-body">
|
||||||
|
<text>感谢您使用本应用,在使用前您应当阅读并同意</text>
|
||||||
|
<text class="link" @click="viewPrivacy('privacy')">《隐私条款》</text>
|
||||||
|
<text class="link" @click="viewPrivacy('agreement')">《用户服务协议》</text>
|
||||||
|
<text>,当点击同意并继续时,即表示您已理解并同意该条款内容,该条款将对您产生法律约束力;如您不同意,将无法继续使用相关功能。</text>
|
||||||
|
</view>
|
||||||
|
<view class="modal-footer">
|
||||||
|
<view class="btn btn-disagree" @click="handleDisagree">不同意</view>
|
||||||
|
<view class="btn btn-agree" @click="handleAgree">同意并继续</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 隐私协议组件 (原有) -->
|
||||||
<privacy-popup ref="privacyPopup"></privacy-popup>
|
<privacy-popup ref="privacyPopup"></privacy-popup>
|
||||||
<to-top v-if="showTop" @toTop="scrollToTopNative()"></to-top>
|
<to-top v-if="showTop" @toTop="scrollToTopNative()"></to-top>
|
||||||
<ns-login ref="login"></ns-login>
|
<ns-login ref="login"></ns-login>
|
||||||
@@ -146,14 +143,132 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
import diyJs from '@/common/js/diy.js';
|
import diyJs from '@/common/js/diy.js';
|
||||||
import scroll from '@/common/js/scroll-view.js';
|
import scroll from '@/common/js/scroll-view.js';
|
||||||
import indexJs from './public/js/index.js';
|
import indexJs from './public/js/index.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [diyJs, scroll, indexJs]
|
mixins: [diyJs, scroll, indexJs],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
minScrollTop: 100,
|
||||||
|
wechatQrcode: '',
|
||||||
|
diyRoute: '/pages/index/index',
|
||||||
|
showPrivacyModal: false // 新增:控制隐私弹窗显示
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
// #ifdef H5
|
||||||
|
if (option.module && option.module == 'locationPicker') {
|
||||||
|
option.name = '';
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.name = option.name || 'DIY_VIEW_INDEX';
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.getFollowQrcode();
|
||||||
|
// 页面显示时检查隐私设置
|
||||||
|
this.checkPrivacySetting();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.unsubscribe = this.$eventBus?.onMany([
|
||||||
|
'rubik-cube-tap',
|
||||||
|
'picture-tap',
|
||||||
|
'text-tap',
|
||||||
|
'goods-list-tap',
|
||||||
|
'presale-tap',
|
||||||
|
'notes-tap',
|
||||||
|
'merch-list-tap',
|
||||||
|
'map-tap',
|
||||||
|
'img-ads-tap',
|
||||||
|
'many-goods-list-tap',
|
||||||
|
'search-tap',
|
||||||
|
], this._handleDiyGroupInteractionEvent);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.unsubscribe) this.unsubscribe();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 检查隐私弹窗逻辑
|
||||||
|
checkPrivacySetting() {
|
||||||
|
// 模拟检查本地存储,看用户是否已经同意过
|
||||||
|
// 实际项目中请替换为你真实的存储逻辑
|
||||||
|
const hasAgreed = uni.getStorageSync('HAS_AGREED_PRIVACY');
|
||||||
|
if (!hasAgreed) {
|
||||||
|
// 延迟显示,防止遮挡页面渲染
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showPrivacyModal = true;
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户点击同意
|
||||||
|
handleAgree() {
|
||||||
|
// 保存同意状态
|
||||||
|
uni.setStorageSync('HAS_AGREED_PRIVACY', true);
|
||||||
|
this.showPrivacyModal = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 用户点击不同意
|
||||||
|
handleDisagree() {
|
||||||
|
// 微信小程序环境下,不同意通常退出小程序
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.exitMiniProgram();
|
||||||
|
// #endif
|
||||||
|
// H5 或 App 下可以提示或直接不显示内容
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
uni.showToast({
|
||||||
|
title: '您已拒绝协议,无法使用',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
// 这里可以选择关闭页面或保持弹窗
|
||||||
|
// this.showPrivacyModal = false;
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查看具体条款(可选功能)
|
||||||
|
viewPrivacy(type) {
|
||||||
|
// 这里可以跳转到具体的条款页面,或者使用你现有的 privacy-popup 组件
|
||||||
|
// 假设你有现成的组件逻辑:
|
||||||
|
if (this.$refs.privacyPopup) {
|
||||||
|
// 假设 privacy-popup 组件有一个 show 方法
|
||||||
|
// this.$refs.privacyPopup.show(type);
|
||||||
|
}
|
||||||
|
uni.showToast({
|
||||||
|
title: '请在此处实现查看条款逻辑',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getFollowQrcode() {
|
||||||
|
if (!this.$util.isWeiXin()) return;
|
||||||
|
this.$api.sendRequest({
|
||||||
|
url: '/wechat/api/wechat/followqrcode',
|
||||||
|
success: res => {
|
||||||
|
if (res.code >= 0 && res.data) {
|
||||||
|
this.wechatQrcode = res.data.qrcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
officialAccountsOpen() {
|
||||||
|
this.$refs.officialAccountsPopup.open();
|
||||||
|
},
|
||||||
|
officialAccountsClose() {
|
||||||
|
this.$refs.officialAccountsPopup.close();
|
||||||
|
},
|
||||||
|
_handleDiyGroupInteractionEvent(payload) {
|
||||||
|
// #ifdef H5
|
||||||
|
return true;
|
||||||
|
// #endif
|
||||||
|
if (this.storeToken) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.$refs.login?.open();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -199,6 +314,74 @@ export default {
|
|||||||
.small-bot-close i {
|
.small-bot-close i {
|
||||||
font-size: 60rpx;
|
font-size: 60rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 新增:隐私弹窗样式 */
|
||||||
|
.privacy-modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6); // 半透明背景
|
||||||
|
z-index: 9999; // 确保层级最高
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.privacy-modal-container {
|
||||||
|
width: 80%;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
padding: 40rpx 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: #007aff; // 蓝色链接
|
||||||
|
margin: 0 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-disagree {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-agree {
|
||||||
|
background-color: #07c160; // 微信绿
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.swiper ::v-deep .uni-swiper-dots-horizontal {
|
.swiper ::v-deep .uni-swiper-dots-horizontal {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
minScrollTop: 100, // 设置回到顶端按钮显示要求,最小页面滚动距离
|
minScrollTop: 100, // 设置回到顶端按钮显示要求,最小页面滚动距离
|
||||||
wechatQrcode: '', // 公众号二维码
|
wechatQrcode: '', // 公众号二维码
|
||||||
diyRoute: '/pages/index/index'
|
diyRoute: '/pages/index/index',
|
||||||
|
showPrivacyModal: false // 新增:控制隐私弹窗显示的变量
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad(option) {
|
onLoad(option) {
|
||||||
@@ -19,6 +20,9 @@ export default {
|
|||||||
onShow() {
|
onShow() {
|
||||||
// 获取关注公众号二维码
|
// 获取关注公众号二维码
|
||||||
this.getFollowQrcode();
|
this.getFollowQrcode();
|
||||||
|
|
||||||
|
// 打开隐私弹窗
|
||||||
|
this.openPrivacyModal();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// 监听图片、文字、商品列表等组件的点击事件
|
// 监听图片、文字、商品列表等组件的点击事件
|
||||||
@@ -41,6 +45,39 @@ export default {
|
|||||||
if (this.unsubscribe) this.unsubscribe();
|
if (this.unsubscribe) this.unsubscribe();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 检查隐私设置(保留原有逻辑,如果不需要可删除)
|
||||||
|
checkPrivacySetting() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.$refs.privacyPopup) {
|
||||||
|
this.$refs.privacyPopup.proactive();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增:打开隐私弹窗的方法
|
||||||
|
openPrivacyModal() {
|
||||||
|
// 延迟一点执行,防止页面加载卡顿
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showPrivacyModal = true;
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增:处理用户点击“同意并继续”
|
||||||
|
handlePrivacyAgree() {
|
||||||
|
this.showPrivacyModal = false;
|
||||||
|
// 这里可以添加保存到本地存储的逻辑,表示用户已同意
|
||||||
|
uni.setStorageSync('hasAgreedPrivacy', true);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增:处理用户点击“不同意”
|
||||||
|
handlePrivacyDisagree() {
|
||||||
|
this.showPrivacyModal = false;
|
||||||
|
// 如果不同意,通常退出小程序或关闭页面
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// 关注公众号
|
// 关注公众号
|
||||||
getFollowQrcode() {
|
getFollowQrcode() {
|
||||||
if (!this.$util.isWeiXin()) return;
|
if (!this.$util.isWeiXin()) return;
|
||||||
@@ -79,4 +116,4 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
@@ -2,11 +2,6 @@
|
|||||||
<view>
|
<view>
|
||||||
<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">
|
||||||
<!-- AI客服悬浮按钮 -->
|
|
||||||
<view class="ai-chat-float-btn" @tap.stop="$emit('aiChatClick')" v-if="goodsSkuDetail">
|
|
||||||
<text class="iconfont">🤖</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 弹幕 -->
|
<!-- 弹幕 -->
|
||||||
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai"
|
<pengpai-fadein-out v-if="goodsSkuDetail.barrage_show && goodsSkuDetail.barrageData" ref="pengpai"
|
||||||
:duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true"
|
:duration="1600" :wait="1900" :top="200" :left="0" :radius="60" :loop="true"
|
||||||
@@ -486,29 +481,4 @@ export default {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '@/common/css/goods_detail.scss';
|
@import '@/common/css/goods_detail.scss';
|
||||||
</style>
|
</style>
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
.ai-chat-float-btn {
|
|
||||||
position: fixed;
|
|
||||||
right: 20rpx;
|
|
||||||
top: 100rpx;
|
|
||||||
width: 80rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #ffffff;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
|
|
||||||
z-index: 9999;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-chat-float-btn:active {
|
|
||||||
transform: scale(0.9);
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ai-chat-float-btn .iconfont {
|
|
||||||
font-size: 40rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
</view> -->
|
</view> -->
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
|
|
||||||
<goods-detail-view :goodsSkuDetail="goodsSkuDetail" ref="goodsDetailView" @aiChatClick="sendToAIChat(goodsSkuDetail)">
|
<goods-detail-view :goodsSkuDetail="goodsSkuDetail" ref="goodsDetailView">
|
||||||
<!-- 价格区域 -->
|
<!-- 价格区域 -->
|
||||||
<template v-slot:price>
|
<template v-slot:price>
|
||||||
<!-- 限时折扣 -->
|
<!-- 限时折扣 -->
|
||||||
@@ -531,28 +531,7 @@ export default {
|
|||||||
goodsDetailView,
|
goodsDetailView,
|
||||||
nsGoodsPromotion
|
nsGoodsPromotion
|
||||||
},
|
},
|
||||||
mixins: [base, detail, scroll],
|
mixins: [base, detail, scroll]
|
||||||
methods: {
|
|
||||||
/**
|
|
||||||
* 发送商品信息到智能客服
|
|
||||||
* @param {Object} item 商品信息
|
|
||||||
*/
|
|
||||||
sendToAIChat(item) {
|
|
||||||
const productInfo = {
|
|
||||||
goods_id: item.goods_id || '',
|
|
||||||
goods_name: item.goods_name || '',
|
|
||||||
price: item.discount_price || item.member_price || item.price || '',
|
|
||||||
image: item.sku_image || '',
|
|
||||||
category_id: item.category_id || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.setStorageSync('selectedProduct', productInfo)
|
|
||||||
|
|
||||||
uni.navigateTo({
|
|
||||||
url: '/pages_tool/ai-chat/index'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -661,5 +640,4 @@ export default {
|
|||||||
height: 72rpx;
|
height: 72rpx;
|
||||||
line-height: 72rpx;
|
line-height: 72rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -108,13 +108,11 @@
|
|||||||
<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
|
||||||
ref="videoRef"
|
|
||||||
:src="message.url"
|
:src="message.url"
|
||||||
:poster="message.cover"
|
:poster="message.cover"
|
||||||
:controls="true"
|
:controls="true"
|
||||||
:autoplay="false"
|
:autoplay="false"
|
||||||
class="video-element"
|
class="video-element"
|
||||||
@loadedmetadata="onVideoLoaded(message, $event)"
|
|
||||||
@play="onVideoPlay(message)"
|
@play="onVideoPlay(message)"
|
||||||
@pause="onVideoPause(message)">
|
@pause="onVideoPause(message)">
|
||||||
</video>
|
</video>
|
||||||
@@ -139,6 +137,19 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 商品卡片 -->
|
||||||
|
<view v-else-if="message.type === 'product'" class="product-content">
|
||||||
|
<view class="product-card" @click="viewProduct(message)">
|
||||||
|
<view class="product-image">
|
||||||
|
<image :src="message.image" mode="aspectFill" />
|
||||||
|
</view>
|
||||||
|
<view class="product-info">
|
||||||
|
<text class="product-title">{{ message.title }}</text>
|
||||||
|
<text class="product-price color-base-text">¥{{ message.price }}</text>
|
||||||
|
<text class="product-desc">{{ message.description }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 加载中状态 -->
|
<!-- 加载中状态 -->
|
||||||
<view v-else-if="message.type === 'loading'" class="loading-content">
|
<view v-else-if="message.type === 'loading'" class="loading-content">
|
||||||
@@ -171,10 +182,10 @@
|
|||||||
<!-- 输入区域 -->
|
<!-- 输入区域 -->
|
||||||
<view class="input-area">
|
<view class="input-area">
|
||||||
<view class="input-tools">
|
<view class="input-tools">
|
||||||
<button class="tool-btn" @click="showMoreTools" style="display: none;">
|
<button class="tool-btn" @click="showMoreTools">
|
||||||
<text class="iconfont icon-plus">...</text>
|
<text class="iconfont icon-plus">...</text>
|
||||||
</button>
|
</button>
|
||||||
<button class="tool-btn" @click="toggleVoiceInput" style="display: none;">
|
<button class="tool-btn" @click="toggleVoiceInput">
|
||||||
<text class="iconfont" :class="voiceInputing ? 'icon-stop' : 'icon-voice'">🎤</text>
|
<text class="iconfont" :class="voiceInputing ? 'icon-stop' : 'icon-voice'">🎤</text>
|
||||||
</button>
|
</button>
|
||||||
</view>
|
</view>
|
||||||
@@ -269,7 +280,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 头像选择弹窗 -->
|
<!-- 头像选择弹窗 -->
|
||||||
<view v-if="showAvatarSelector" class="avatar-selector-popup" style="pointer-events: auto;">
|
<view v-if="showAvatarSelector" class="avatar-selector-popup">
|
||||||
<view class="avatar-selector-mask" @click="closeAvatarSelector"></view>
|
<view class="avatar-selector-mask" @click="closeAvatarSelector"></view>
|
||||||
<view class="avatar-selector-panel">
|
<view class="avatar-selector-panel">
|
||||||
<view class="avatar-selector-header">
|
<view class="avatar-selector-header">
|
||||||
@@ -288,6 +299,10 @@
|
|||||||
<text class="iconfont icon-album"></text>
|
<text class="iconfont icon-album"></text>
|
||||||
<text>从相册选择</text>
|
<text>从相册选择</text>
|
||||||
</button>
|
</button>
|
||||||
|
<button class="avatar-select-action" @click="takeAvatarWithCamera">
|
||||||
|
<text class="iconfont icon-camera"></text>
|
||||||
|
<text>拍照上传</text>
|
||||||
|
</button>
|
||||||
<button class="avatar-select-action cancel" @click="closeAvatarSelector">
|
<button class="avatar-select-action cancel" @click="closeAvatarSelector">
|
||||||
<text>取消</text>
|
<text>取消</text>
|
||||||
</button>
|
</button>
|
||||||
@@ -399,13 +414,12 @@ export default {
|
|||||||
// 默认头像路径
|
// 默认头像路径
|
||||||
defaultAvatar: '/static/images/default-avatar.png',
|
defaultAvatar: '/static/images/default-avatar.png',
|
||||||
// 头像选择弹窗控制
|
// 头像选择弹窗控制
|
||||||
showAvatarSelector: false, // 头像选择弹窗控制
|
showAvatarSelector: false,
|
||||||
// 新增:用户昵称相关
|
// 新增:用户昵称相关
|
||||||
localUserNickname: '', // 当前用户昵称
|
localUserNickname: '', // 当前用户昵称
|
||||||
defaultNickname: '我', // 默认昵称
|
defaultNickname: '我', // 默认昵称
|
||||||
showNicknameEditor: false, // 昵称编辑弹窗控制
|
showNicknameEditor: false, // 昵称编辑弹窗控制
|
||||||
tempNickname: '', // 昵称编辑临时值
|
tempNickname: '', // 昵称编辑临时值
|
||||||
|
|
||||||
// Dify API相关
|
// Dify API相关
|
||||||
currentConversationId: null,
|
currentConversationId: null,
|
||||||
isAIServiceAvailable: true,
|
isAIServiceAvailable: true,
|
||||||
@@ -598,67 +612,20 @@ export default {
|
|||||||
|
|
||||||
// 从相册选择头像
|
// 从相册选择头像
|
||||||
chooseAvatarFromAlbum() {
|
chooseAvatarFromAlbum() {
|
||||||
console.log('选择从相册选择头像')
|
this.selectAvatar('album')
|
||||||
this.selectAvatar()
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 统一头像选择方法 - 仅从相册选择
|
// 拍照上传头像
|
||||||
selectAvatar() {
|
takeAvatarWithCamera() {
|
||||||
console.log('开始选择头像')
|
this.selectAvatar('camera')
|
||||||
|
},
|
||||||
|
|
||||||
// #ifdef H5
|
// 统一头像选择方法
|
||||||
// H5环境下的处理 - 仅从相册选择
|
selectAvatar(sourceType) {
|
||||||
const input = document.createElement('input')
|
|
||||||
input.type = 'file'
|
|
||||||
input.accept = 'image/*'
|
|
||||||
input.style.display = 'none'
|
|
||||||
|
|
||||||
// 监听文件选择
|
|
||||||
input.onchange = (e) => {
|
|
||||||
const file = e.target.files[0]
|
|
||||||
if (file) {
|
|
||||||
// 创建临时URL
|
|
||||||
const tempFilePath = URL.createObjectURL(file)
|
|
||||||
|
|
||||||
// 1. 本地预览更新
|
|
||||||
this.localUserAvatar = tempFilePath
|
|
||||||
|
|
||||||
// 2. 持久化缓存(支持页面刷新后保留)
|
|
||||||
const reader = new FileReader()
|
|
||||||
reader.onload = (e) => {
|
|
||||||
const base64 = e.target.result
|
|
||||||
uni.setStorageSync('user_avatar', base64)
|
|
||||||
}
|
|
||||||
reader.readAsDataURL(file)
|
|
||||||
|
|
||||||
// 3. 通知父组件(可选,用于同步到服务器等场景)
|
|
||||||
this.$emit('avatar-changed', tempFilePath)
|
|
||||||
|
|
||||||
// 4. 关闭弹窗
|
|
||||||
this.closeAvatarSelector()
|
|
||||||
|
|
||||||
// 5. 提示成功
|
|
||||||
uni.showToast({
|
|
||||||
title: '头像更换成功',
|
|
||||||
icon: 'success',
|
|
||||||
duration: 1500
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// 用户取消选择
|
|
||||||
this.closeAvatarSelector()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发点击
|
|
||||||
input.click()
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
// 微信小程序环境下,使用uni.chooseImage - 仅从相册选择
|
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 1, // 仅选择1张
|
count: 1, // 仅选择1张
|
||||||
sizeType: ['compressed'], // 压缩图片
|
sizeType: ['compressed'], // 压缩图片
|
||||||
sourceType: ['album'], // 仅从相册选择
|
sourceType: [sourceType], // 来源:相册/相机
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
const tempFilePath = res.tempFilePaths[0]
|
const tempFilePath = res.tempFilePaths[0]
|
||||||
|
|
||||||
@@ -684,14 +651,12 @@ export default {
|
|||||||
fail: (error) => {
|
fail: (error) => {
|
||||||
console.error('选择头像失败:', error)
|
console.error('选择头像失败:', error)
|
||||||
// 权限拒绝处理
|
// 权限拒绝处理
|
||||||
if (error.errMsg && error.errMsg.includes('deny')) {
|
if (error.errMsg.includes('deny')) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '请开启相册权限',
|
title: '请开启相册/相机权限',
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
} else if (error.errMsg && error.errMsg.includes('cancel')) {
|
|
||||||
// 用户取消选择,不显示错误提示
|
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '头像选择失败,请重试',
|
title: '头像选择失败,请重试',
|
||||||
@@ -699,11 +664,8 @@ export default {
|
|||||||
duration: 2000
|
duration: 2000
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 关闭弹窗
|
|
||||||
this.closeAvatarSelector()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// #endif
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 新增:打开昵称编辑弹窗
|
// 新增:打开昵称编辑弹窗
|
||||||
@@ -877,14 +839,19 @@ export default {
|
|||||||
},
|
},
|
||||||
(completeResult) => {
|
(completeResult) => {
|
||||||
// 流结束回调
|
// 流结束回调
|
||||||
|
let finalContent = '';
|
||||||
let convId = '';
|
let convId = '';
|
||||||
|
|
||||||
if (typeof completeResult !== 'string') {
|
if (typeof completeResult === 'string') {
|
||||||
|
finalContent = completeResult;
|
||||||
|
} else {
|
||||||
|
finalContent = completeResult.content || '';
|
||||||
convId = completeResult.conversation_id || '';
|
convId = completeResult.conversation_id || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记流式结束
|
// 更新最终内容
|
||||||
streamMessage.isStreaming = false;
|
streamMessage.isStreaming = false;
|
||||||
|
streamMessage.content = finalContent;
|
||||||
|
|
||||||
// 添加操作按钮
|
// 添加操作按钮
|
||||||
streamMessage.actions = [
|
streamMessage.actions = [
|
||||||
@@ -916,10 +883,12 @@ export default {
|
|||||||
},
|
},
|
||||||
(completeResult) => {
|
(completeResult) => {
|
||||||
// 流结束回调
|
// 流结束回调
|
||||||
|
let finalContent = completeResult?.content || '';
|
||||||
let convId = completeResult?.conversation_id || '';
|
let convId = completeResult?.conversation_id || '';
|
||||||
|
|
||||||
// 标记流式结束
|
// 更新最终内容
|
||||||
streamMessage.isStreaming = false;
|
streamMessage.isStreaming = false;
|
||||||
|
streamMessage.content = finalContent;
|
||||||
|
|
||||||
// 添加操作按钮
|
// 添加操作按钮
|
||||||
streamMessage.actions = [
|
streamMessage.actions = [
|
||||||
@@ -1227,42 +1196,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 视频加载完成事件
|
|
||||||
onVideoLoaded(message, event) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
let width = 0;
|
|
||||||
let height = 0;
|
|
||||||
|
|
||||||
// H5端:通过video元素获取真实视频宽高
|
|
||||||
// #ifdef H5
|
|
||||||
const video = this.$refs.videoRef;
|
|
||||||
if (video) {
|
|
||||||
width = video.videoWidth || 0;
|
|
||||||
height = video.videoHeight || 0;
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// 微信小程序端:通过事件对象获取视频宽高
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
if (event && event.detail) {
|
|
||||||
width = event.detail.width || 0;
|
|
||||||
height = event.detail.height || 0;
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
if (width && height) {
|
|
||||||
// 判断视频方向:宽度 >= 高度为横屏,否则为竖屏
|
|
||||||
const videoRatio = width >= height ? 'landscape' : 'portrait';
|
|
||||||
console.log(`AI聊天视频宽高比检测: ${width}x${height}, 比例: ${videoRatio}`);
|
|
||||||
|
|
||||||
// 动态设置视频样式
|
|
||||||
// 这里可以添加逻辑来动态调整视频播放器的样式
|
|
||||||
// 例如:message.videoRatio = videoRatio;
|
|
||||||
// 然后在模板中根据message.videoRatio调整样式
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 视频播放
|
// 视频播放
|
||||||
onVideoPlay(message) {
|
onVideoPlay(message) {
|
||||||
this.$emit('video-play', message)
|
this.$emit('video-play', message)
|
||||||
@@ -1286,6 +1219,10 @@ export default {
|
|||||||
this.$emit('link-open', message)
|
this.$emit('link-open', message)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 查看商品
|
||||||
|
viewProduct(message) {
|
||||||
|
this.$emit('product-view', message)
|
||||||
|
},
|
||||||
|
|
||||||
// 处理操作
|
// 处理操作
|
||||||
handleAction(action, message) {
|
handleAction(action, message) {
|
||||||
@@ -1479,24 +1416,6 @@ export default {
|
|||||||
this.$emit('location-selected', locationMessage)
|
this.$emit('location-selected', locationMessage)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 清空聊天记录
|
|
||||||
clearMessages() {
|
|
||||||
// 清空消息数组
|
|
||||||
this.messages = []
|
|
||||||
// 重置消息 ID
|
|
||||||
this.messageId = 0
|
|
||||||
// 清除会话 ID
|
|
||||||
this.currentConversationId = null
|
|
||||||
aiService.clearConversationId()
|
|
||||||
this.clearConversationIdFromLocal()
|
|
||||||
// 重置历史偏移量
|
|
||||||
this.historyOffset = 0
|
|
||||||
// 触发清空事件
|
|
||||||
this.$emit('messages-cleared')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2859,132 +2778,6 @@ $radius-lg: 36rpx;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 商品选择弹窗样式 */
|
|
||||||
.product-selector-popup {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 9999;
|
|
||||||
|
|
||||||
.product-selector-mask {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-selector-panel {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 90%;
|
|
||||||
max-width: 800rpx;
|
|
||||||
max-height: 80vh;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.product-selector-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20rpx;
|
|
||||||
border-bottom: 1rpx solid #e8edf3;
|
|
||||||
|
|
||||||
text {
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #4e5969;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-btn {
|
|
||||||
padding: 0;
|
|
||||||
background: none;
|
|
||||||
|
|
||||||
.iconfont {
|
|
||||||
font-size: 32rpx;
|
|
||||||
color: #8492a6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-selector-content {
|
|
||||||
display: flex;
|
|
||||||
height: 60vh;
|
|
||||||
|
|
||||||
.category-list {
|
|
||||||
width: 200rpx;
|
|
||||||
border-right: 1rpx solid #e8edf3;
|
|
||||||
|
|
||||||
.category-item {
|
|
||||||
padding: 20rpx;
|
|
||||||
text-align: center;
|
|
||||||
border-bottom: 1rpx solid #e8edf3;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #6c8ebf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-list {
|
|
||||||
flex: 1;
|
|
||||||
padding: 20rpx;
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
text-align: center;
|
|
||||||
padding: 40rpx;
|
|
||||||
color: #8492a6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty {
|
|
||||||
text-align: center;
|
|
||||||
padding: 40rpx;
|
|
||||||
color: #8492a6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-item {
|
|
||||||
display: flex;
|
|
||||||
padding: 15rpx;
|
|
||||||
border-bottom: 1rpx solid #e8edf3;
|
|
||||||
|
|
||||||
.product-image {
|
|
||||||
width: 120rpx;
|
|
||||||
height: 120rpx;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
margin-right: 15rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-info {
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
.product-name {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
color: #4e5969;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-price {
|
|
||||||
color: #f56c6c;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式适配 */
|
/* 响应式适配 */
|
||||||
@media (max-width: 750rpx) {
|
@media (max-width: 750rpx) {
|
||||||
.ai-chat-container {
|
.ai-chat-container {
|
||||||
|
|||||||
@@ -257,20 +257,6 @@ export default {
|
|||||||
// ========== 初始化页面 ==========
|
// ========== 初始化页面 ==========
|
||||||
initChat() {
|
initChat() {
|
||||||
console.log('AI聊天页面初始化');
|
console.log('AI聊天页面初始化');
|
||||||
|
|
||||||
// 检查是否有从商品分类传递过来的商品信息
|
|
||||||
const selectedProduct = uni.getStorageSync('selectedProduct')
|
|
||||||
if (selectedProduct) {
|
|
||||||
console.log('检测到选择的商品:', selectedProduct)
|
|
||||||
|
|
||||||
// 清除存储的商品信息,避免重复发送
|
|
||||||
uni.removeStorageSync('selectedProduct')
|
|
||||||
|
|
||||||
// 延迟发送商品信息,确保聊天组件已经初始化
|
|
||||||
setTimeout(() => {
|
|
||||||
this.sendProductToAI(selectedProduct)
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async initNavigation() {
|
async initNavigation() {
|
||||||
@@ -497,20 +483,6 @@ export default {
|
|||||||
console.log('视频暂停:', message);
|
console.log('视频暂停:', message);
|
||||||
},
|
},
|
||||||
|
|
||||||
sendProductToAI(product) {
|
|
||||||
if (!this.$refs.chat) {
|
|
||||||
console.error('聊天组件未初始化')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const productContent = `我想了解以下商品的详细信息:\n商品名称:${product.goods_name}\n价格:¥${product.price}\n商品ID:${product.goods_id}`
|
|
||||||
|
|
||||||
console.log('商品信息已发送到AI客服:', productContent)
|
|
||||||
|
|
||||||
// 使用sendMessageWithContent方法发送商品信息
|
|
||||||
this.$refs.chat.sendMessageWithContent(productContent)
|
|
||||||
},
|
|
||||||
|
|
||||||
onLinkOpen(message) {
|
onLinkOpen(message) {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '打开链接',
|
title: '打开链接',
|
||||||
|
|||||||
@@ -134,9 +134,8 @@ async function main() {
|
|||||||
// 2) 创建 ZIP 文件(如果未指定 --no-zip)
|
// 2) 创建 ZIP 文件(如果未指定 --no-zip)
|
||||||
if (!options.noZip) {
|
if (!options.noZip) {
|
||||||
const cwd = path.join(__dirname, '..');
|
const cwd = path.join(__dirname, '..');
|
||||||
const buildDir = options.mode === 'production' ? 'build' : 'dev';
|
const sourceDir = path.join(cwd, 'unpackage', 'dist', 'build', 'mp-weixin');
|
||||||
const sourceDir = path.join(cwd, 'unpackage', 'dist', buildDir, 'mp-weixin');
|
const destDir = path.join(cwd, 'unpackage', 'dist', 'build');
|
||||||
const destDir = path.join(cwd, 'unpackage', 'dist', buildDir);
|
|
||||||
const zipFilePath = await createZipWithSystemCommand(sourceDir, destDir);
|
const zipFilePath = await createZipWithSystemCommand(sourceDir, destDir);
|
||||||
console.log(`ZIP 文件路径: ${zipFilePath}`);
|
console.log(`ZIP 文件路径: ${zipFilePath}`);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user