4 Commits
4 changed files with 383 additions and 58 deletions
+13
View File
@@ -885,6 +885,18 @@ export const chatMixinsV2 = {
this.currentGiftStepIndex--
}
},
clearCurrentGiftStepData() {
const currentStep = this.giftBuyOptions[this.currentGiftStepIndex]
if (!currentStep) return
if (currentStep.type === 'option_card') {
const nextSelections = { ...this.giftSelections }
delete nextSelections[currentStep.id]
this.giftSelections = nextSelections
} else if (currentStep.type === 'price_input') {
this.giftBudget = ''
}
},
nextGiftStep() {
const currentStep = this.giftBuyOptions[this.currentGiftStepIndex]
let hasSelection = false
@@ -912,6 +924,7 @@ export const chatMixinsV2 = {
}
},
skipGiftStep() {
this.clearCurrentGiftStepData()
if (this.currentGiftStepIndex < this.giftBuyOptions.length - 1) {
this.currentGiftStepIndex++
} else {
+12
View File
@@ -148,3 +148,15 @@ export function aiGiftImageStatus(params) {
login: true
})
}
/**
* 获取商品以前使用过的AI礼品卡图片
* @param {*} params
* @returns
*/
export function aiGiftImageHistory(params) {
return request.get("/giftCard/aiGiftImages/history?productId=" + params.productId, {
login: true
})
}
@@ -0,0 +1,164 @@
<template>
<u-popup
:show="show"
mode="bottom"
round="40rpx"
:customStyle="{height: '600rpx'}"
@close="close"
>
<view class="cover-picker v12-pt-4">
<swiper
:current="currentIndex"
:autoplay="false"
:circular="true"
:indicator-dots="false"
@change="onChange"
previous-margin="180rpx"
next-margin="180rpx"
class="cover-swiper"
>
<swiper-item v-for="(item, i) in list" :key="i" class="cover-swiper-item" :class="{'n-actived' : currentIndex !== i}">
<view class="cover-item" :class="{'ios-cover': isIOS}">
<view class="img-wrap">
<image :src="item.cover" class="cover-image" mode="widthFix" />
</view>
</view>
</swiper-item>
</swiper>
<view class="v12-justify-center">
<view class="cover-confirm" @click="confirm">
确定
</view>
</view>
<view class="tips">礼包封面在对方领取时展示</view>
<view class="tips tips2">*图片由云灵AI生成仅供参考</view>
</view>
</u-popup>
</template>
<script>
export default {
props: {
index: {
type: Number,
default: 0
},
show: {
type: Boolean,
default: true
},
list: {
type: Array,
default: () => []
}
},
data() {
return {
currentIndex: this.index
}
},
computed: {
isIOS() {
return uni.getSystemInfoSync().osName === 'ios'
}
},
watch: {
index(val) {
this.currentIndex = val
},
show(val) {
if (val) {
this.currentIndex = this.index
}
}
},
methods: {
close() {
this.currentIndex = 0
this.$emit('update:show', false)
},
onChange(e) {
this.currentIndex = e.detail.current
this.$forceUpdate()
},
confirm() {
this.$emit('confirm', this.list[this.currentIndex])
this.$emit('update:show', false)
}
}
}
</script>
<style lang="less" scoped>
.n-actived{
.cover-item{
transform: scale(0.8);
margin-bottom: -70rpx !important;
}
}
.cover-swiper-item{
height: fit-content !important;
bottom: 0;
overflow: visible;
}
.img-wrap{
position: relative;
overflow: visible;
}
.tips{
font-size: 24rpx;
color: #999;
text-align: center;
margin-top: 20rpx;
}
.tips2{
color: #C52733;
}
.cover-swiper{
height: 800rpx;
}
.cover-picker {
.cover-title {
padding: 30rpx;
font-size: 32rpx;
font-weight: bold;
text-align: center;
margin-bottom: 30rpx;
}
.cover-item {
display: flex;
flex-direction: column;
align-items: center;
overflow: visible;
transition: all .3s ease-in-out;
margin-bottom: 30rpx;
.cover-image {
width: 420rpx;
// height: 580rpx;
border-radius: 16rpx;
transition: all .2s ease-in-out;
}
.cover-name {
margin-top: 20rpx;
font-size: 28rpx;
color: #333;
}
}
.cover-confirm {
margin-top: 40rpx;
width: 240rpx;
height: 80rpx;
border-radius: 16rpx;
font-size: 32rpx;
background-color: #C52733 !important;
color: #fff !important;
text-align: center;
line-height: 80rpx;
}
}
.ios-cover{
zoom: 1.01
}
</style>
+161 -25
View File
@@ -36,6 +36,7 @@
>
<view class="ai-cover-body">
<view class="ai-cover-container">
<view v-if="!showAiImgHistoryListSelect">
<view v-if="showGenerateBtn" class="prompt">
<textarea
v-model.trim="aiCoverDesc"
@@ -45,8 +46,12 @@
/>
<p class="prompt-tips">{{ aiCoverDesc.length }}/300</p>
</view>
<view v-else class="imgs-list-wrap">
<view class="img-item" v-for="(item, index) in aiCoverImgsList" :key="index">
<view v-else class="imgs-list-wrap ai-img-list-wrap">
<view
v-for="(item, index) in aiCoverImgsList"
:key="index"
class="img-item"
>
<image
:src="item.cover"
:class="{
@@ -59,8 +64,39 @@
</view>
</view>
</view>
<view v-else>
<view
:class="{'scrollable': aiHistoryCoverImgsList.length > 3}"
class="imgs-list-wrap"
>
<view
v-for="(item, index) in aiHistoryCoverImgsList"
:key="index"
class="img-item"
>
<image
:src="item.cover"
:class="{
'active': item.id === selectedAiCoverImage.id
}"
mode="heightFix"
class="img-image"
@click="handleSelectAiHistoryCover(item)"
/>
</view>
</view>
</view>
</view>
<view class="ai-cover-bottom">
<block v-if="!showAiImgHistoryListSelect">
<view v-if="showGenerateBtn" class="btn-wrap">
<view
v-if="!aiCoverGenerateLoading && aiHistoryCoverImgsList.length > 0"
class="btn btn2"
@click="toggleShowAiImgHistoryListSelect(true)"
>
历史图片
</view>
<view class="btn" @click="handleGenerateAiCover">
{{ aiCoverGenerateLoading ? '礼包封面生成中...' : 'AI生成礼包封面' }}
<image v-if="!aiCoverGenerateLoading" :src="webUrl + '/page/gift/gift-tab-icon01.png'" class="icon"></image>
@@ -79,6 +115,17 @@
重新生成
</view>
</view>
</block>
<block v-else>
<view class="btn-wrap">
<view class="btn" @click="handleShowAiHistoryCoverPicker">
预览
</view>
<view class="btn btn2" @click="toggleShowAiImgHistoryListSelect(false)">
使用AI生成
</view>
</view>
</block>
</view>
</view>
</view>
@@ -232,6 +279,12 @@
:index="aiDefaultIndex"
@confirm="onAiCoverConfirm"
/>
<AiHistoryCoverPicker
:show.sync="showAiHistoryCoverPicker"
:list="aiHistoryCoverImgsList"
:index="aiHistoryDefaultIndex"
@confirm="onAiHistoryCoverConfirm"
/>
<passkeyborad
ref='payPwdPop'
showMoney
@@ -302,7 +355,8 @@ import {
fetchSojoumGroupBuyGiftCarousel,
computedSojoumGroupBuyGiftOrderPrice,
aiGiftImageGenerate,
aiGiftImageStatus
aiGiftImageStatus,
aiGiftImageHistory
} from '@/api/gift'
import {
getAiSystemInfoSetting
@@ -312,6 +366,7 @@ import {mapGetters} from "vuex";
import giftTips from './components/giftTips.vue'
import CoverPicker from './components/CoverPicker.vue'
import AiCoverPicker from './components/AiCoverPicker.vue'
import AiHistoryCoverPicker from './components/AiHistoryCoverPicker.vue'
import PayPicker from './components/PayPicker.vue';
import CouponsPopup from "@/components/CouponsPopup.vue"
export default {
@@ -319,6 +374,7 @@ export default {
giftTips,
CoverPicker,
AiCoverPicker,
AiHistoryCoverPicker,
PayPicker,
passkeyborad,
CouponsPopup
@@ -361,6 +417,7 @@ export default {
defaultIndex:0,
discount: null,
computedResult: {},
skipCouponIdWatch: false,
couponList: {
unusable: [],
usable: []
@@ -406,11 +463,19 @@ export default {
selectedAiCoverImage: {},
showAiCoverPicker: false,
pollInterval: null,
aiDefaultIndex: 0
aiDefaultIndex: 0,
aiHistoryDefaultIndex: 0,
showAiHistoryCoverPicker: false,
aiHistoryCoverImgsList: [],
showAiImgHistoryListSelect: false
}
},
watch: {
async couponId(value) {
if (this.skipCouponIdWatch) {
this.skipCouponIdWatch = false
return
}
if (this.isCountyLotteryGift) {
this.couponTitle = ''
if (Number(value || 0) !== 0) {
@@ -472,11 +537,27 @@ export default {
}
},
methods: {
// 將面切换
// 封面类型切换
toggleSelectCoverType(type) {
if (this.selectCoverType === type) return
this.selectCoverType = type
},
// 获取商品以前使用过的AI礼品卡图片
aiGiftImageHistoryReq() {
aiGiftImageHistory({
productId: this.goodsInfo.productId
}).then(res => {
const { success, data } = res
if (success && data) {
this.aiHistoryCoverImgsList = data || []
this.aiHistoryCoverImgsList.map(historyItem => {
historyItem.cover = historyItem.coverUrl,
historyItem.image = historyItem.shareUrl,
historyItem.name = historyItem.name || ''
})
}
})
},
handleGenerateAiCover() {
if (!this.aiCoverDesc || !this.aiCoverDesc.trim()) {
uni.showToast({
@@ -577,6 +658,11 @@ export default {
if (this.isCountyLotteryGift) return 0
return this.couponId || 0
},
setCouponIdSilently(value) {
if (this.couponId === value) return
this.skipCouponIdWatch = true
this.couponId = value
},
isCountyLotteryCartItem(item) {
return Number(
(item && item.drawActivityId) ||
@@ -591,7 +677,7 @@ export default {
if (!this.isCountyLotteryGift) return
this.couponTitle = ''
if (Number(this.couponId || 0) !== 0) {
this.couponId = 0
this.setCouponIdSilently(0)
}
},
adjustCoverListForProductStory(coverList, productInfo, defaultTemplate) {
@@ -636,10 +722,10 @@ export default {
if (this.isCountyLotteryGift) {
this.couponTitle = ''
if (this.couponId !== 0) {
this.couponId = 0
this.setCouponIdSilently(0)
}
} else if(useDefaultCouponId) {
this.couponId = res.data.result.defaultCouponId || 0
this.setCouponIdSilently(res.data.result.defaultCouponId || 0)
}
})
},
@@ -649,6 +735,27 @@ export default {
handleShowAiCover() {
this.showAiCoverPicker = true
},
handleShowAiHistoryCoverPicker() {
this.showAiHistoryCoverPicker = true
},
toggleShowAiImgHistoryListSelect(show) {
this.showAiImgHistoryListSelect = show
this.selectedAiCoverImage = {}
this.selectedCover = ''
this.giftImage = ''
this.templateId = ''
this.aiHistoryDefaultIndex = 0
this.aiDefaultIndex = 0
if (show) {
if (this.aiHistoryCoverImgsList.length > 0 && this.aiHistoryDefaultIndex === 0) {
const index = this.aiHistoryCoverImgsList.findIndex(item => item.isLastSelected)
if (index !== -1) {
this.aiHistoryDefaultIndex = index
}
this.handleSelectAiHistoryCover(this.aiHistoryCoverImgsList[this.aiHistoryDefaultIndex])
}
}
},
showCouponsPopup() {
if (this.isCountyLotteryGift) return
if (this.couponList.usable && this.couponList.usable.length === 0) return
@@ -664,7 +771,7 @@ export default {
if (this.couponList.usable && this.couponList.usable.length === 0) return
this.showPopup = !this.showPopup
if(!item.id) {
this.couponId = 0
this.setCouponIdSilently(0)
this.couponTitle = ''
if(this.isGroupBuy) {
this.computedTravelGroupPrice(false)
@@ -673,7 +780,7 @@ export default {
}
return
}
this.couponId = item.id
this.setCouponIdSilently(item.id)
this.couponTitle = item.couponTitle
if(this.isGroupBuy) {
this.computedTravelGroupPrice(false)
@@ -708,7 +815,7 @@ export default {
this.giftImage = this.selectedAiCoverImage.image
this.templateId = this.selectedAiCoverImage.id
}
this.couponId = ''
this.setCouponIdSilently('')
this.computedPrice(this.goodsInfo.cartNum)
})
},
@@ -745,10 +852,10 @@ export default {
if (this.isCountyLotteryGift) {
this.couponTitle = ''
if (this.couponId !== 0) {
this.couponId = 0
this.setCouponIdSilently(0)
}
} else if(!f) {
this.couponId = res.data.result.defaultCouponId || 0
this.setCouponIdSilently(res.data.result.defaultCouponId || 0)
this.$forceUpdate()
}
this.payPrice = res.data.result.payPrice
@@ -800,6 +907,16 @@ export default {
this.aiDefaultIndex = this.aiCoverImgsList.findIndex(item => item.id === cover.id)
}
},
onAiHistoryCoverConfirm(cover) {
// 封面图片
this.selectedCover = cover.cover
// 分享对话图片
this.giftImage = cover.image
if (this.selectCoverType === 'ai') {
this.selectedAiCoverImage = cover
this.aiHistoryDefaultIndex = this.aiHistoryCoverImgsList.findIndex(item => item.id === cover.id)
}
},
handleSelectAiCover(cover) {
this.selectedAiCoverImage = cover
this.aiDefaultIndex = this.aiCoverImgsList.findIndex(item => item.id === cover.id)
@@ -807,6 +924,13 @@ export default {
this.giftImage = cover.image
this.templateId = cover.id
},
handleSelectAiHistoryCover(cover) {
this.selectedAiCoverImage = cover
this.aiHistoryDefaultIndex = this.aiHistoryCoverImgsList.findIndex(item => item.id === cover.id)
this.selectedCover = cover.cover
this.giftImage = cover.image
this.templateId = cover.id
},
showTips() {
this.$refs.giftTips.showTips = true
},
@@ -817,25 +941,27 @@ export default {
}
this.loading = true
getGiftCardSendOrderConfirm(params).then(res => {
const temp = this.isGroupBuy ? res.data.giftCardTemplates : res.data.giftCardTemplates.filter(e => e.isTravelGroup === 0)
const hasSpecial = res.data.giftCardTemplates.map(e => e.id).includes(res.data.specialGiftCardTemplate.id)
const initialCoverList = hasSpecial ? [...temp] : [...temp, res.data.specialGiftCardTemplate]
const goodsInfo = res.data.cartInfo[0]
const { coverList, template } = this.adjustCoverListForProductStory(initialCoverList, goodsInfo && goodsInfo.productInfo, res.data.specialGiftCardTemplate)
const data = res.data
const temp = this.isGroupBuy ? data.giftCardTemplates : data.giftCardTemplates.filter(e => e.isTravelGroup === 0)
const hasSpecial = data.giftCardTemplates.map(e => e.id).includes(data.specialGiftCardTemplate.id)
const initialCoverList = hasSpecial ? [...temp] : [...temp, data.specialGiftCardTemplate]
const goodsInfo = data.cartInfo[0]
const { coverList, template } = this.adjustCoverListForProductStory(initialCoverList, goodsInfo && goodsInfo.productInfo, data.specialGiftCardTemplate)
this.coverList = coverList
this.giftNotice = res.data.giftCardGiftNotice
this.orderKey = res.data.orderKey
this.giftNotice = data.giftCardGiftNotice
this.orderKey = data.orderKey
this.goodsInfo = goodsInfo
this.syncCountyLotteryGiftFlag(goodsInfo)
this.templateId = template.id
this.selectedCover = template.cover
this.giftImage = template.image
this.blindImage = res.data.giftCardBlindBoxShareImage
this.blindImage = data.giftCardBlindBoxShareImage
this.defaultIndex = this.coverList.findIndex(item => item.id === this.templateId)
// if(!this.couponId) {
// this.couponId = res.data.couponList.usable[0] && res.data.couponList.usable[0].id || ''
// this.couponId = data.couponList.usable[0] && data.couponList.usable[0].id || ''
// }
this.computedPrice(this.goodsInfo.cartNum)
this.aiGiftImageHistoryReq()
this.isLoad = true
}).finally(() => {
this.loading = false
@@ -854,6 +980,7 @@ export default {
if (this.isCountyLotteryGift && this.isEligibleForDraw) {
this.showLotteryGiftPopup = true
}
this.aiGiftImageHistoryReq()
},
closeLotteryGiftPopup() {
this.showLotteryGiftPopup = false
@@ -1333,19 +1460,28 @@ export default {
}
.imgs-list-wrap {
display: flex;
justify-content: space-around;
justify-content: center;
align-items: baseline;
gap: 24rpx;
gap: 40rpx;
padding: 20rpx 0;
box-sizing: border-box;
&.scrollable {
justify-content: flex-start;
flex-wrap: nowrap;
overflow-x: auto;
}
}
.img-image {
display: block;
height: 176rpx;
flex-shrink: 0;
&.active {
transform: scale(1.2);
transform: scale(1.2) translateY(-16rpx);
}
}
.ai-img-list-wrap {
padding: 28rpx 0 20rpx 0;
}
}
.ai-cover-bottom {
margin-top: 12rpx;