Refactor(云灵AI):礼品商品轮播效果实现

This commit is contained in:
lifizer
2026-04-15 18:59:18 +08:00
parent 1d8b75e2d2
commit bca2513d22
6 changed files with 339 additions and 21 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
<view class="order-shop">
<view class="shop-name">
<image
:src="webUrl + '/aiChat/icon-04.png'"
:src="webUrl + '/aiChat/icon-57.png'"
class="icon"
mode="widthFix"
/>
+101 -10
View File
@@ -3,8 +3,11 @@ import {
getCompletionsV3,
deleteChatItemByConversationId,
// getAnalyzeKeywordsV1,
getAnalyzeKeywordsChangeV1
getAnalyzeKeywordsChangeV3
} from '@/api/chat/index'
import {
postCartAdd
} from '@/api/store'
import { VUE_APP_API_URL } from '@/config'
import settings from '@/config/baseSetting.js'
import { formatAiMsgContent } from '../utils/aiChat'
@@ -46,6 +49,7 @@ export const chatMixinsV2 = {
isScrollToBottom: false,
// 状态栏高度
statusBarHeight: 20,
bottomSafeDistance: 0,
fileHttpStr: Object.freeze(VUE_APP_API_URL + settings.sysPrefix),
keyboardHeight: 0,
optionsFrom: '',
@@ -75,7 +79,9 @@ export const chatMixinsV2 = {
audioAyy: [],
isPlayAudio: false,
audioContext: null,
audioPlayId: ''
audioPlayId: '',
showGiftBtn: false,
buyLoading: false
}
},
computed: {
@@ -118,6 +124,7 @@ export const chatMixinsV2 = {
// #endif
// 状态栏高度
_this.statusBarHeight = statusBar
_this.bottomSafeDistance = e.safeAreaInsets.bottom
}
})
_this.createdCallbak()
@@ -226,6 +233,19 @@ export const chatMixinsV2 = {
conversationId: '',
prompt,
listQuestion: [],
// 特产商品
goodsList: [],
// 礼品商品
giftGoodsList: [],
// 非遗文化
ichList: [],
// 千县名品
qianxianList: [],
// 抽奖
prizeList: [],
// 店铺
shopList: [],
// 订单
orderList: [],
type: -2,
showMoreInfo: {}
@@ -315,6 +335,11 @@ export const chatMixinsV2 = {
this.chatMessageList[this.chatMessageListLength - 1].orderList = message.listCards || []
}
}
if (contentType ==='shop') {
if (!finish && message.listCards) {
this.chatMessageList[this.chatMessageListLength - 1].shopList = message.listCards || []
}
}
this.$forceUpdate()
this.$nextTick(() => {
this.scrollToBottomHandle()
@@ -346,23 +371,39 @@ export const chatMixinsV2 = {
console.log('send failed (' + err.code + ')')
}
},
analyzeKeywordsChangeHandle(conversationId, showMoreInfo) {
getAnalyzeKeywordsChangeV1({
conversationId,
...showMoreInfo
analyzeKeywordsChangeHandle(conversationId, item) {
let listKey = ''
// 抽奖和订单查询没有换一换
if (item.goodsList.length > 0) {
listKey = 'goodsList'
}
if (item.giftGoodsList.length > 0) {
listKey = 'giftGoodsList'
}
if (item.ichList.length > 0) {
listKey = 'ichList'
}
if (item.qianxianList.length > 0) {
listKey = 'qianxianList'
}
if (item.shopList.length > 0) {
listKey = 'shopList'
}
getAnalyzeKeywordsChangeV3({
conversationId
}).then(res => {
const { success, data } = res
if (success) {
let resultItems = []
let changeList = []
let idx = -1
this.chatMessageList.map((item, index) => {
if (item.conversationId === conversationId) {
resultItems = data.resultItems || []
changeList = data.list || []
idx = index
}
})
if (idx > -1) {
this.$set(this.chatMessageList[idx].showMoreInfo, 'resultItems', resultItems)
if (idx > -1 && listKey) {
this.$set(this.chatMessageList[idx], 'listKey', changeList)
this.$forceUpdate()
}
}
@@ -377,6 +418,56 @@ export const chatMixinsV2 = {
}
})
},
productItemBuyNowClickHandle(item) {
this.showGiftBtn = false
this.cart_num = 1
this.addToCart(item)
},
productItemGiftBuyClickHandle(item) {
this.showGiftBtn = true
this.cart_num = 1
this.addToCart(item)
},
buyNowOrGiftBuyReq(type) {
const _this = this
if (_this.buyLoading) {
return
}
_this.buyLoading = true
postCartAdd({
productId: _this.m_id,
cartNum: _this.attr.productSelect.cart_num,
new: 1,
uniqueId: _this.attr.productSelect !== undefined ? _this.attr.productSelect.unique : ''
}).then(function (res) {
try {
_this.$set(_this.attr, 'cartAttr', false)
const { cartId } = res.data
if (type === 1) {
uni.navigateTo({
url: '/pages/order/OrderSubmission/index?id=' + cartId
})
return
}
if(type === 2) {
uni.navigateTo({
url: '/pkg_user/views/gift/gift?cartId=' + cartId
})
return
}
} catch (error) {
console.log(error)
}
}).catch(error => {
uni.showToast({
title: error.msg,
icon: "none",
duration: 5000
})
}).finally(() => {
_this.buyLoading = false
})
},
hotelItemClickHandle(item) {
this.audioStopHandle()
this.$yrouter.push({
+224 -8
View File
@@ -38,7 +38,7 @@
})">播放</button> -->
<block v-if="chatMessageListLength < 1">
<view class="home-wrap">
<view class="home-focus-wrap">
<view class="home-focus-wrap" style="display: none;">
<view class="focus-guide-wrap">
<view class="guide-left">
<image
@@ -53,6 +53,49 @@
</view>
</view>
</view>
<!-- 这里实现商品轮播 -->
<view class="recommend-goods-wrap" v-if="recommendGoodsList.length > 0">
<swiper
class="goods-swiper"
:indicator-dots="false"
:autoplay="false"
previous-margin="120rpx"
next-margin="120rpx"
circular
@change="onSwiperChange"
>
<swiper-item
v-for="(item, index) in recommendGoodsList"
:key="index"
>
<view
class="goods-item"
:class="{ 'active': currentSwiperIndex === index }"
@click="productItemClickHandle(item)"
>
<view class="supplier">
<image
:src="webUrl + '/aiChat/icon-57.png'"
class="icon"
mode="widthFix"
/>
<text class="s-name">{{ item.supplierName || '供应商名称' }}</text>
<u-icon name="arrow-right" color="#999" size="12"></u-icon>
</view>
<view class="title one-t">{{ item.productName || item.name || '商品名称' }}</view>
<image :src="item.image || item.img" class="p-img" mode="aspectFill" />
<view class="price">
<text class="unit"></text>
<text class="num">{{ item.price || '0.00' }}</text>
</view>
<view class="actions">
<view class="btn-buy" @click.stop="productItemBuyNowClickHandle(item)">立即下单</view>
<view class="btn-gift" @click.stop="productItemGiftBuyClickHandle(item)">送给朋友</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
<view class="topic-wrap">
<view class="title">
<view class="title-left">大家都在问</view>
@@ -225,9 +268,9 @@
</view>
</view>
</view>
<view v-if="item.showMoreInfo.showType === '店铺'" class="list-wrap">
<view v-if="item.shopList.length > 0" class="list-wrap">
<view
v-for="(hotel, hotelIndex) in item.showMoreInfo.resultItems"
v-for="(hotel, hotelIndex) in item.shopList"
:key="hotelIndex"
class="product-item"
@click="hotelItemClickHandle(hotel)"
@@ -314,12 +357,21 @@
/>
</view>
</view>
<view v-if="item.showMoreInfo.showType !== '优惠活动' && item.orderList.length === 0" class="change-btn">
<view
v-if="item.shopList.length > 0 ||
item.goodsList.length > 0 ||
item.giftGoodsList.length > 0 ||
item.ichList.length > 0 ||
item.qianxianList.length > 0 ||
item.shopList.length > 0
"
class="change-btn"
>
<image
:src="webUrl + '/aiChat/icon-change.png'"
class="icon"
mode="widthFix"
@click="analyzeKeywordsChangeHandle(item.conversationId, item.showMoreInfo)"
@click="analyzeKeywordsChangeHandle(item.conversationId, item)"
/>
</view>
</view>
@@ -413,11 +465,24 @@
:status-bar-height="statusBarHeight"
@enter-history="audioStopHandle"
/>
<ProductWindow
ref="attrWindow"
:attr="attr"
:cart-num="cart_num"
:show-ok="!showGiftBtn"
:is-gift="showGiftBtn"
:padding-bottom="bottomSafeDistance + 'px'"
ok-text="立即购买"
@changeFun="changeFun"
@ok="buyNowOrGiftBuyReq(1)"
@gift="buyNowOrGiftBuyReq(2)"
/>
</view>
</template>
<script>
import { chatMixinsV2 } from '../mixins/chatMixinsV2.js'
import goCartMixin from '@/mixins/goCartMixins'
import {
getAiSystemInfoSetting,
getAiSystemInfoTopic
@@ -425,21 +490,69 @@ import {
import AiHistoryList from '../components/historyList'
import BottomSend from '../components/bottomSend.vue'
import OrderItem from '../components/orderItem.vue'
import ProductWindow from '@/components/ProductWindow'
export default {
name: 'AiChatIndexPage',
components: {
AiHistoryList,
BottomSend,
OrderItem
OrderItem,
ProductWindow
},
mixins: [chatMixinsV2],
mixins: [chatMixinsV2, goCartMixin],
data() {
return {
cityName: '',
animationWidth: '150%',
animationStr: '',
settingInfo: {},
topicList: []
topicList: [],
currentSwiperIndex: 0,
recommendGoodsList: [
{
supplierName: '供应商名称',
productName: '云南枇杷花蜜',
image: 'https://resource.xdd618.com/最近喜欢上了独龙玉手镯_3_若瑜_来自小红书网页版-20250616101810.jpg',
price: '65.00',
id: 334
},
{
supplierName: '供应商名称',
productName: '云南枇杷花蜜',
image: 'https://resource.xdd618.com/最近喜欢上了独龙玉手镯_3_若瑜_来自小红书网页版-20250616101810.jpg',
price: '65.00',
id: 334
},
{
supplierName: '供应商名称',
productName: '云南枇杷花蜜',
image: 'https://resource.xdd618.com/最近喜欢上了独龙玉手镯_3_若瑜_来自小红书网页版-20250616101810.jpg',
price: '65.00',
id: 334
},
{
supplierName: '供应商名称',
productName: '云南枇杷花蜜',
image: 'https://resource.xdd618.com/最近喜欢上了独龙玉手镯_3_若瑜_来自小红书网页版-20250616101810.jpg',
price: '65.00',
id: 334
},
{
supplierName: '供应商名称',
productName: '云南枇杷花蜜',
image: 'https://resource.xdd618.com/最近喜欢上了独龙玉手镯_3_若瑜_来自小红书网页版-20250616101810.jpg',
price: '65.00',
id: 334
},
{
supplierName: '供应商名称',
productName: '云南枇杷花蜜',
image: 'https://resource.xdd618.com/最近喜欢上了独龙玉手镯_3_若瑜_来自小红书网页版-20250616101810.jpg',
price: '65.00',
id: 334
}
],
onlyOneToAddCart: false
}
},
onLoad(options) {
@@ -505,6 +618,9 @@ export default {
this.createNewHandle()
}
},
onSwiperChange(e) {
this.currentSwiperIndex = e.detail.current
},
pageContainerBeforeleave() {
if (!this.chatNumber) {
if (getCurrentPages().length > 1) {
@@ -591,6 +707,106 @@ export default {
}
}
}
.recommend-goods-wrap {
width: 100%;
padding: 24rpx 0;
.goods-swiper {
width: 100%;
height: 724rpx;
}
.goods-item {
display: block;
width: 460rpx;
margin: 0 auto;
padding: 24rpx;
box-sizing: border-box;
background: #fff;
border-radius: 20rpx;
box-shadow: 0rpx 6rpx 30rpx rgba(0,0,0,0.16);
white-space: normal;
transition: all 0.3s ease;
transform: scale(0.9);
opacity: 0.8;
&.active {
transform: scale(1);
opacity: 1;
}
.supplier {
display: flex;
align-items: center;
font-size: 24rpx;
color: #666;
margin-bottom: 16rpx;
.icon {
display: block;
width: 28rpx;
height: 28rpx;
}
.s-name {
flex: 1;
margin: 0 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 16rpx;
line-height: 40rpx;
}
.p-img {
width: 412rpx;
height: 412rpx;
margin-bottom: 16rpx;
border-radius: 12rpx;
background-color: #f5f5f5;
}
.price {
color: #C52733;
text-align: center;
margin-bottom: 16rpx;
.unit {
font-size: 28rpx;
font-weight: bold;
}
.num {
font-size: 36rpx;
font-weight: bold;
}
}
.actions {
display: flex;
justify-content: center;
.btn-buy {
width: 160rpx;
height: 56rpx;
margin: 0 12rpx;
line-height: 56rpx;
text-align: center;
background: #C52733;
color: #fff;
font-size: 24rpx;
border-radius: 28rpx;
}
.btn-gift {
width: 160rpx;
height: 56rpx;
margin: 0 12rpx;
line-height: 52rpx;
text-align: center;
background: #fff;
color: #C52733;
font-size: 24rpx;
border-radius: 28rpx;
border: 2rpx solid #C52733;
box-sizing: border-box;
}
}
}
}
.topic-wrap {
width: 100%;
.title {
+5
View File
@@ -49,3 +49,8 @@ export function getHolidayData(params) {
export function getCompletionsV3(params) {
return request.get('/v1/chat/intent/recognize', params, { login: true })
}
// 通过关键字-搜索列表-换一换
export function getAnalyzeKeywordsChangeV3(data) {
return request.post('/v1/chat/goods/refresh', data, { login: true })
}
+5 -1
View File
@@ -73,7 +73,7 @@
color="#C52733"
@click="$emit('ok')"
:disabled="(attr.productSelect.stock === 0 && attr.cartAttr)"
>加入购物车</u-button>
>{{ okText }}</u-button>
</view>
<view class="v12-px-2 v12-mt-3" v-if="isGift">
<u-button
@@ -118,6 +118,10 @@ export default {
cartNum: {
type: Number,
default: () => 1
},
okText: {
type: String,
default: '加入购物车'
}
},
data() {
+3 -1
View File
@@ -35,6 +35,8 @@ export default {
},
cart_num: 1,
CartCount: 0,
// 只有一个规格时直接加入购物车;AI聊天界面则不直接加入购物车,每次都要显示规格选择弹窗
onlyOneToAddCart: true
}
},
methods: {
@@ -112,7 +114,7 @@ export default {
// 是否单一规格
const onlyOne = Object.keys(data.productValue).length === 1
if(onlyOne) {
if(onlyOne && this.onlyOneToAddCart) {
this.handleOk(() => this.getCartCount())
return
}