| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- <template>
- <px-popup-bottom ref="popup" :visible.sync="localVisible" title=" " radius="32" maxHeight="1024" @close="handleClose">
- <view class="product-spec">
- <!-- 商品信息 -->
- <view class="pro-info">
- <view class="img-box" @click="showImg(productValueSelect.image)">
- <image
- :src="productValueSelect.image==null||productValueSelect.image==''?product.image:productValueSelect.image"
- mode="aspectFill"></image>
- </view>
- <view class="info-text">
- <view class="product-name">{{(product.productName || product.title) || '产品名称'}}</view>
- <view class="price">
- <text class="title">会员价</text>
- <text class="unit">¥</text><text
- class="bold">{{splitPrice(productValueSelect.price).integer}}</text>.{{splitPrice(productValueSelect.price).decimal}}
- </view>
- <view class="desc-box">
- <text class="text">月售{{product.sales || '0'}}件</text>
- <text v-if="selectedSpec" class="text">库存{{selectedSpec.stock || 0}}件</text>
- </view>
- </view>
- </view>
- <!-- 规格 -->
- <view v-if="productSpecs && productSpecs.length > 0" class="spec-box">
- <view class="title">规格</view>
- <view class="spec-list">
- <view v-for="(spec, index) in productSpecs" :key="index"
- :class="selectedSpec && selectedSpec.id == spec.id ? 'item active':'item'" @click="selectSpec(spec)">
- {{ spec.sku || '默认规格' }}
- </view>
- </view>
- </view>
- <!-- 数量 -->
- <view class="price-num">
- <view class="label">数量</view>
- <view class="num-box">
- <view class="img-box" @click="lessNum()">
- <image v-if="specNum <= 1" src="https://cdn.his.cdwjyyh.com/images/jian.png" mode=""></image>
- <image v-else src="https://cdn.his.cdwjyyh.com/images/jian2.png" mode=""></image>
- </view>
- <input type="number" @change="changeNum" v-model="specNum" />
- <view class="img-box" @click="addNum()">
- <image src="https://cdn.his.cdwjyyh.com/images/add.png" mode=""></image>
- </view>
- </view>
- </view>
- <button :class="isSubmitting?'btnsel sub-btn':'sub-btn'" :disabled="isSubmitting"
- @click="submit">{{ isSubmitting ? (isBuyMode ? '正在跳转...' : '订单生成中...') : (isBuyMode ? '立即购买' : '确定') }}</button>
- </view>
- </px-popup-bottom>
- </template>
- <script>
- import PxPopupBottom from '@/components/px-popup-bottom/px-popup-bottom.vue'
- import { addCart, getProductValues } from '@/api/index'
- export default {
- name: 'ProductSpecPopup',
- components: {
- PxPopupBottom
- },
- props: {
- visible: {
- type: Boolean,
- default: false
- },
- product: {
- type: Object,
- default: () => ({})
- },
- isBuyMode: {
- type: Boolean,
- default: false
- }
- },
- data() {
- return {
- localVisible: false,
- productValueSelect: {
- image: '',
- price: 0
- },
- specNum: 1,
- isSubmitting: false,
- productSpecs: [],
- selectedSpec: null
- }
- },
- watch: {
- visible: {
- handler(newVal) {
- this.localVisible = newVal
- if (newVal && this.product) {
- this.initData()
- this.getProductValuesList()
- }
- },
- immediate: true
- },
- localVisible: {
- handler(newVal) {
- if (!newVal) {
- this.$emit('update:visible', false)
- }
- }
- },
- product: {
- handler(newVal) {
- if (newVal && this.localVisible) {
- this.initData()
- this.getProductValuesList()
- }
- },
- deep: true
- }
- },
- methods: {
- // 处理弹窗关闭
- handleClose() {
- this.localVisible = false
- this.$emit('update:visible', false)
- },
- initData() {
- this.specNum = 1
- this.isSubmitting = false
- this.selectedSpec = null
- this.productValueSelect = {
- image: this.product.image || this.product.firstImage || '',
- price: this.product.price || 0
- }
- },
- // 获取商品规格列表
- getProductValuesList() {
- const productId = this.product.id || this.product.productId
- if (!productId) return
- getProductValues(productId).then(
- res => {
- if (res.code == 200) {
- console.log("获取商品规格列表", res.data)
- // 保存商品规格列表
- this.productSpecs = res.data || []
- // 默认选择第一个规格
- if (res.data && res.data.length > 0) {
- this.selectedSpec = res.data[0]
- this.productValueSelect = {
- image: res.data[0].image || this.product.image || this.product.firstImage || '',
- price: res.data[0].price || 0
- }
- }
- }
- },
- rej => {
- console.error("获取商品规格列表失败", rej)
- }
- )
- },
- // 分割价格
- splitPrice(price) {
- const priceStr = parseFloat(price).toFixed(2).toString()
- return {
- integer: priceStr.split('.')[0],
- decimal: priceStr.split('.')[1]
- }
- },
- // 显示图片
- showImg(image) {
- console.log('显示图片:', image)
- // 可以实现图片预览功能
- },
- // 减少数量
- lessNum() {
- if (this.specNum > 1) {
- this.specNum--
- }
- },
- // 增加数量
- addNum() {
- this.specNum++
- },
- // 改变数量
- changeNum(e) {
- let value = parseInt(e.target.value)
- if (isNaN(value) || value < 1) {
- value = 1
- }
- this.specNum = value
- },
- // 选择规格
- selectSpec(spec) {
- console.log('选择商品规格:', spec)
- this.selectedSpec = spec
- this.productValueSelect = {
- image: spec.image || this.product.image || this.product.firstImage || '',
- price: spec.price || 0,
- sales: spec.sales || 0
- }
- },
- // 提交
- submit() {
- console.log('提交订单')
- this.isSubmitting = true
-
- if (this.isBuyMode) {
- // 购买模式:跳转到订单确认页面
- console.log('立即购买:', this.product, this.specNum)
- this.isSubmitting = false
- this.localVisible = false
- this.$emit('update:visible', false)
- // 跳转到订单确认页面,传递商品信息和数量
- uni.navigateTo({
- url: `/pages_shopping/shopping/confirmCreateOrder?productId=${this.product.productId}&buyNum=${this.specNum}&attrValueId=${this.selectedSpec ? this.selectedSpec.id : ''}&indexBuy=true`
- })
- } else {
- // 添加购物车模式:调用添加购物车接口
- addCart({
- productId: this.product.id || this.product.productId,
- cartNum: this.specNum,
- attrValueId: this.selectedSpec ? this.selectedSpec.id : '' // 使用选中的规格ID
- }).then(res => {
- if (res.code == 200) {
- uni.showToast({
- title: '添加购物车成功',
- icon: 'success'
- })
- // 通知父组件更新购物车数量
- this.$emit('cart-updated')
- this.localVisible = false
- this.$emit('update:visible', false)
- } else {
- uni.showToast({
- title: res.msg || '添加购物车失败',
- icon: 'none'
- })
- }
- this.isSubmitting = false
- }).catch(error => {
- console.error('添加购物车失败:', error)
- uni.showToast({
- title: '网络错误,请重试',
- icon: 'none'
- })
- this.isSubmitting = false
- })
- }
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .product-spec {
- padding: 40rpx 30rpx;
- .pro-info {
- display: flex;
- align-items: center;
- .img-box {
- width: 200rpx;
- height: 200rpx;
- background: #FFFFFF;
- border-radius: 16rpx;
- overflow: hidden;
- margin-right: 30rpx;
- image {
- width: 100%;
- height: 100%;
- }
- }
- .product-name {
- font-weight: 600;
- font-size: 32rpx;
- color: #333333;
- }
- .info-text {
- height: 200rpx;
- display: flex;
- flex-direction: column;
- .price {
- margin-top: 16rpx;
- font-weight: 600;
- font-size: 26rpx;
- color: #FA341E;
- .title {
- font-weight: 500;
- font-size: 24rpx;
- color: #FF5030;
- margin-right: 8rpx;
- }
- .unit {
- font-size: 20rpx;
- color: #FA341E;
- }
- .bold {
- font-size: 48upx;
- font-weight: 600;
- color: #FA341E;
- }
- }
- .desc-box {
- margin-top: 16rpx;
- display: flex;
- flex-direction: column;
- padding-bottom: 9rpx;
- .text {
- font-size: 26rpx;
- font-family: PingFang SC;
- font-weight: 500;
- color: #999999;
- margin-top: 27rpx;
- line-height: 1;
- &:first-child {
- margin-top: 0;
- }
- }
- }
- }
- }
- .spec-box {
- padding-top: 50rpx;
- .title {
- font-size: 34rpx;
- font-family: PingFang SC;
- font-weight: bold;
- color: #111111;
- line-height: 1;
- }
- .spec-list {
- display: flex;
- flex-wrap: wrap;
- margin-top: 30rpx;
- .item {
- box-sizing: border-box;
- padding: 12rpx 24rpx;
- font-size: 28rpx;
- color: #333333;
- background: #F5F7FA;
- border-radius: 28rpx 28rpx 28rpx 28rpx;
- margin-right: 24rpx;
- margin-bottom: 30rpx;
- &.active {
- font-size: 24rpx;
- color: #02B176;
- background: #EBFAF6;
- border: 2rpx solid #02B176;
- }
- }
- }
- }
- .price-num {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-top: 14rpx;
- .label {
- font-size: 34rpx;
- font-family: PingFang SC;
- font-weight: bold;
- color: #111111;
- }
- .num-box {
- display: flex;
- align-items: center;
- .img-box {
- width: 60rpx;
- height: 60rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- image {
- width: 25rpx;
- height: 25rpx;
- }
- }
- input {
- width: 60rpx;
- height: 60rpx;
- line-height: 60rpx;
- font-size: 28rpx;
- font-family: PingFang SC;
- font-weight: 500;
- color: #111111;
- background: #F5F7FA;
- text-align: center;
- border: none;
- }
- }
- }
- .sub-btn {
- width: 100%;
- height: 88rpx;
- line-height: 88rpx;
- text-align: center;
- font-size: 30rpx;
- font-family: PingFang SC;
- font-weight: bold;
- color: #FFFFFF;
- border-radius: 44rpx;
- margin-top: 30rpx;
- background: linear-gradient(136deg, #38D97D 0%, #02B176 100%);
- border: none;
-
- &.btnsel {
- opacity: 0.6;
- }
- }
- }
- </style>
|