mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-06-21 09:30:24 +08:00
feat(礼品卡管理): 添加礼品卡选择、绑定、激活及列表功能
- 在购物车API中新增选择礼品卡的接口 - 在促销API中添加获取、绑定和激活礼品卡的接口 - 在订单详情和支付页面中展示礼品卡抵扣信息 - 新增“我的礼品卡”页面,支持礼品卡的查看、绑定和激活功能 - 更新路由配置以支持礼品卡相关页面
This commit is contained in:
@@ -92,6 +92,21 @@ export function selectCoupon (params) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择礼品卡
|
||||
* @param way 购物车购买:CART/立即购买:BUY_NOW/拼团购买:PINTUAN / 积分购买:POINT
|
||||
* @param credentialId 礼品卡凭证 id;used=false 且不传则清空全部
|
||||
* @param used 使用 true / 弃用 false
|
||||
*/
|
||||
export function selectGiftCard (params) {
|
||||
return request({
|
||||
url: '/buyer/trade/carts/select/giftCard',
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 可用优惠券数量
|
||||
*/
|
||||
|
||||
@@ -57,3 +57,50 @@ export function pointGoodsDetail (id) {
|
||||
id
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询当前客户礼品卡
|
||||
*/
|
||||
export function getGiftCardCashMemberCardPage (params) {
|
||||
return request({
|
||||
url: '/buyer/promotion/giftCardCash/memberCard',
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定礼品卡(卡号 + 兑换码/卡密)
|
||||
*/
|
||||
export function bindGiftCardCashMemberCard (data) {
|
||||
return request({
|
||||
url: '/buyer/promotion/giftCardCash/memberCard/bind',
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活礼品卡
|
||||
*/
|
||||
export function activateGiftCardCashMemberCard (memberCardId) {
|
||||
return request({
|
||||
url: `/buyer/promotion/giftCardCash/memberCard/${memberCardId}/activate`,
|
||||
method: Method.POST,
|
||||
needToken: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单页可用礼品卡列表
|
||||
*/
|
||||
export function getAvailableGiftCardCashMemberCards () {
|
||||
return request({
|
||||
url: '/buyer/promotion/giftCardCash/memberCard/available',
|
||||
method: Method.GET,
|
||||
needToken: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -231,6 +231,14 @@
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
<div v-if="order.order.priceDetailDTO.giftCardPrice">
|
||||
<span>礼品卡抵扣:</span
|
||||
><span
|
||||
>-{{
|
||||
order.order.priceDetailDTO.giftCardPrice || 0 | unitPrice("¥")
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
<div v-if="order.order.discountPrice">
|
||||
<span>活动优惠:</span
|
||||
><span>-{{ order.order.discountPrice | unitPrice("¥") }}</span>
|
||||
|
||||
461
buyer/src/pages/home/userCenter/MyGiftCards.vue
Normal file
461
buyer/src/pages/home/userCenter/MyGiftCards.vue
Normal file
@@ -0,0 +1,461 @@
|
||||
<template>
|
||||
<div class="wrapper my-gift-cards">
|
||||
<card _Title="我的礼品卡" />
|
||||
|
||||
<div class="bind-section mb_20">
|
||||
<div class="section-title">兑换礼品卡</div>
|
||||
<Form ref="bindForm" :model="bindForm" :rules="bindRules" inline class="bind-form">
|
||||
<FormItem label="卡号" prop="cardNo" :label-width="60">
|
||||
<Input v-model="bindForm.cardNo" placeholder="请输入卡号" maxlength="64" style="width: 220px" />
|
||||
</FormItem>
|
||||
<FormItem label="兑换码" prop="cardSecret" :label-width="70">
|
||||
<Input
|
||||
v-model="bindForm.cardSecret"
|
||||
type="password"
|
||||
placeholder="请输入兑换码(卡密)"
|
||||
maxlength="128"
|
||||
style="width: 220px"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem :label-width="0">
|
||||
<Button type="primary" :loading="bindSubmitting" @click="submitBind">兑换</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<Tabs v-model="statusTab" class="status-tabs mb_16" @on-click="onStatusTab">
|
||||
<TabPane label="可用" name="AVAILABLE" />
|
||||
<TabPane label="不可用" name="UNAVAILABLE" />
|
||||
<TabPane label="待激活" name="PENDING_ACTIVATION" />
|
||||
</Tabs>
|
||||
|
||||
<div class="card-list-wrap">
|
||||
<Spin v-if="loading" fix />
|
||||
<template v-if="!loading">
|
||||
<empty v-if="list.length === 0" />
|
||||
<div v-else class="gift-card-grid">
|
||||
<div v-for="item in list" :key="item.id || item.cardNo" class="gcc-card-item">
|
||||
<div class="gcc-card-header">
|
||||
<div class="gcc-header-pattern" aria-hidden="true" />
|
||||
<div class="gcc-header-inner">
|
||||
<div class="gcc-header-left">
|
||||
<div class="gcc-title">{{ item.giftCardName || "礼品卡" }}</div>
|
||||
<div class="gcc-face">面值{{ formatYuan(item.faceValue) }}元</div>
|
||||
<div class="gcc-cardno">{{ item.cardNo }}</div>
|
||||
</div>
|
||||
<div class="gcc-header-right">
|
||||
<div class="gcc-type">现金卡</div>
|
||||
<div class="gcc-expire">{{ formatValidity(item) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gcc-card-body">
|
||||
<div class="gcc-row">
|
||||
当前余额:<span class="gcc-strong" v-if="item.balance != null">¥{{ item.balance | unitPrice }}</span><span class="gcc-strong" v-else>—</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="gcc-action"
|
||||
:class="{
|
||||
'is-disabled': primaryActionDisabled || pendingActivateLocked || isActivating(item),
|
||||
}"
|
||||
:disabled="primaryActionDisabled || pendingActivateLocked || isActivating(item)"
|
||||
@click="onCardPrimaryAction(item)"
|
||||
>
|
||||
<span v-if="isActivating(item)">提交中...</span>
|
||||
<span v-else>{{ primaryActionLabel }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="page-size">
|
||||
<Page
|
||||
:current="params.pageNumber"
|
||||
:page-size="params.pageSize"
|
||||
:page-size-opts="[10, 20, 50]"
|
||||
:total="total"
|
||||
show-sizer
|
||||
show-total
|
||||
size="small"
|
||||
transfer
|
||||
@on-change="changePage"
|
||||
@on-page-size-change="changePageSize"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Modal v-model="noticeModal" title="使用须知" footer-hide width="520">
|
||||
<p class="gcc-notice-text">
|
||||
请在有效期内使用本礼品卡;消费时将优先使用卡内余额。具体使用范围以活动规则为准。如有疑问请联系客服。
|
||||
</p>
|
||||
<div class="gcc-notice-footer">
|
||||
<Button type="primary" @click="noticeModal = false">我知道了</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getGiftCardCashMemberCardPage,
|
||||
bindGiftCardCashMemberCard,
|
||||
activateGiftCardCashMemberCard,
|
||||
} from "@/api/promotion.js";
|
||||
|
||||
export default {
|
||||
name: "MyGiftCards",
|
||||
data() {
|
||||
return {
|
||||
statusTab: "AVAILABLE",
|
||||
loading: false,
|
||||
total: 0,
|
||||
list: [],
|
||||
params: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
memberCardStatus: "AVAILABLE",
|
||||
},
|
||||
bindSubmitting: false,
|
||||
bindForm: {
|
||||
cardNo: "",
|
||||
cardSecret: "",
|
||||
},
|
||||
bindRules: {
|
||||
cardNo: [{ required: true, message: "请输入卡号", trigger: "blur" }],
|
||||
cardSecret: [{ required: true, message: "请输入兑换码", trigger: "blur" }],
|
||||
},
|
||||
noticeModal: false,
|
||||
serviceHotline: "12221111",
|
||||
activatingId: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
primaryActionLabel() {
|
||||
if (this.statusTab === "PENDING_ACTIVATION") {
|
||||
return "激活自用";
|
||||
}
|
||||
if (this.statusTab === "AVAILABLE") {
|
||||
return "去使用";
|
||||
}
|
||||
return "不可用";
|
||||
},
|
||||
primaryActionDisabled() {
|
||||
return this.statusTab === "UNAVAILABLE";
|
||||
},
|
||||
pendingActivateLocked() {
|
||||
return this.statusTab === "PENDING_ACTIVATION" && !!this.activatingId;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
formatYuan(val) {
|
||||
if (val == null || val === "") {
|
||||
return "—";
|
||||
}
|
||||
const n = Number(val);
|
||||
if (Number.isNaN(n)) {
|
||||
return String(val);
|
||||
}
|
||||
return Number.isInteger(n) ? String(n) : n.toFixed(2).replace(/\.?0+$/, "");
|
||||
},
|
||||
formatValidity(row) {
|
||||
const t = row && row.expireTime;
|
||||
if (!t) {
|
||||
return "长期有效";
|
||||
}
|
||||
const d = new Date(t);
|
||||
if (Number.isNaN(d.getTime())) {
|
||||
return "长期有效";
|
||||
}
|
||||
if (d.getFullYear() >= 2099) {
|
||||
return "长期有效";
|
||||
}
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
return `${y}-${m}-${day} 到期`;
|
||||
},
|
||||
onStatusTab(name) {
|
||||
this.statusTab = name;
|
||||
this.params.memberCardStatus = name;
|
||||
this.params.pageNumber = 1;
|
||||
this.getList();
|
||||
},
|
||||
getList() {
|
||||
this.loading = true;
|
||||
const p = { ...this.params };
|
||||
if (p.memberCardStatus) {
|
||||
p.memberCardStatus = String(p.memberCardStatus);
|
||||
}
|
||||
getGiftCardCashMemberCardPage(p)
|
||||
.then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success && res.result) {
|
||||
this.list = res.result.records || [];
|
||||
this.total = res.result.total || 0;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
changePage(val) {
|
||||
this.params.pageNumber = val;
|
||||
this.getList();
|
||||
},
|
||||
changePageSize(val) {
|
||||
this.params.pageNumber = 1;
|
||||
this.params.pageSize = val;
|
||||
this.getList();
|
||||
},
|
||||
resetBindForm() {
|
||||
this.bindForm = { cardNo: "", cardSecret: "" };
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.bindForm) {
|
||||
this.$refs.bindForm.resetFields();
|
||||
}
|
||||
});
|
||||
},
|
||||
submitBind() {
|
||||
this.$refs.bindForm.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
this.bindSubmitting = true;
|
||||
bindGiftCardCashMemberCard({
|
||||
cardNo: String(this.bindForm.cardNo).trim(),
|
||||
cardSecret: String(this.bindForm.cardSecret).trim(),
|
||||
})
|
||||
.then((res) => {
|
||||
this.bindSubmitting = false;
|
||||
if (res.success) {
|
||||
this.$Message.success(res.message || "兑换成功");
|
||||
this.resetBindForm();
|
||||
this.params.pageNumber = 1;
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.bindSubmitting = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
onCardPrimaryAction(item) {
|
||||
if (this.primaryActionDisabled) {
|
||||
return;
|
||||
}
|
||||
if (this.statusTab === "PENDING_ACTIVATION") {
|
||||
const memberCardId = this.resolveMemberCardId(item);
|
||||
if (!memberCardId) {
|
||||
this.$Message.error("卡片信息异常,无法激活");
|
||||
return;
|
||||
}
|
||||
this.activatingId = memberCardId;
|
||||
activateGiftCardCashMemberCard(memberCardId)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success(res.message || "激活成功");
|
||||
this.getList();
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.activatingId = "";
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.statusTab === "AVAILABLE") {
|
||||
this.$router.push({ path: "/goodsList" });
|
||||
}
|
||||
},
|
||||
resolveMemberCardId(row) {
|
||||
if (!row) {
|
||||
return "";
|
||||
}
|
||||
return row.memberCardId != null && row.memberCardId !== ""
|
||||
? String(row.memberCardId)
|
||||
: row.id != null && row.id !== ""
|
||||
? String(row.id)
|
||||
: "";
|
||||
},
|
||||
isActivating(item) {
|
||||
const id = this.resolveMemberCardId(item);
|
||||
return !!this.activatingId && this.activatingId === id;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.my-gift-cards {
|
||||
.bind-section {
|
||||
padding: 16px 18px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e8eaec;
|
||||
@include white_background_color();
|
||||
}
|
||||
.section-title {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 14px;
|
||||
@include title_color($light_title_color);
|
||||
}
|
||||
.bind-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
gap: 4px 8px;
|
||||
}
|
||||
.status-tabs {
|
||||
::v-deep .ivu-tabs-bar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.card-list-wrap {
|
||||
position: relative;
|
||||
min-height: 200px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
.gift-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 20px 18px;
|
||||
align-items: start;
|
||||
}
|
||||
.gcc-card-item {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
|
||||
@include white_background_color();
|
||||
}
|
||||
.gcc-card-header {
|
||||
position: relative;
|
||||
min-height: 128px;
|
||||
padding: 0;
|
||||
background: linear-gradient(125deg, #ff9a4a 0%, #ff7729 42%, #ff8f3d 100%);
|
||||
}
|
||||
.gcc-header-pattern {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0.22;
|
||||
pointer-events: none;
|
||||
background-image: repeating-linear-gradient(
|
||||
-36deg,
|
||||
transparent,
|
||||
transparent 5px,
|
||||
rgba(255, 255, 255, 0.45) 5px,
|
||||
rgba(255, 255, 255, 0.45) 6px
|
||||
);
|
||||
}
|
||||
.gcc-header-inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
padding: 16px 14px 14px;
|
||||
color: #fff;
|
||||
}
|
||||
.gcc-header-left {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-right: 8px;
|
||||
}
|
||||
.gcc-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.gcc-face {
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
opacity: 0.95;
|
||||
}
|
||||
.gcc-cardno {
|
||||
margin-top: 22px;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.02em;
|
||||
opacity: 0.75;
|
||||
word-break: break-all;
|
||||
}
|
||||
.gcc-header-right {
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.gcc-type {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.gcc-expire {
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.gcc-card-body {
|
||||
padding: 14px 14px 16px;
|
||||
}
|
||||
.gcc-row {
|
||||
font-size: 13px;
|
||||
line-height: 1.85;
|
||||
@include title_color($light_title_color);
|
||||
}
|
||||
.gcc-muted {
|
||||
color: #999;
|
||||
}
|
||||
.gcc-strong {
|
||||
color: #ff6b22;
|
||||
font-weight: 600;
|
||||
}
|
||||
.gcc-link {
|
||||
color: $theme_color;
|
||||
cursor: pointer;
|
||||
}
|
||||
.gcc-service {
|
||||
color: #515a6e;
|
||||
}
|
||||
.gcc-action {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-top: 14px;
|
||||
padding: 10px 16px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
color: #e95b6c;
|
||||
background: #faf4f5;
|
||||
transition: opacity 0.2s, background 0.2s;
|
||||
}
|
||||
.gcc-action:hover:not(.is-disabled) {
|
||||
background: #f5e8ea;
|
||||
}
|
||||
.gcc-action.is-disabled {
|
||||
color: #c5c8ce;
|
||||
cursor: not-allowed;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
.page-size {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.gcc-notice-text {
|
||||
line-height: 1.7;
|
||||
color: #515a6e;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.gcc-notice-footer {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
@@ -195,6 +195,60 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 礼品卡 -->
|
||||
<div class="invoice pay-gcc-module">
|
||||
<div class="pay-gcc-head">
|
||||
<div class="pay-gcc-title">
|
||||
使用礼品卡
|
||||
<span class="pay-gcc-deduct">
|
||||
(已抵扣 <span class="pay-gcc-deduct-num">{{ giftCardDeductAmount | unitPrice("¥") }}</span
|
||||
>)
|
||||
</span>
|
||||
</div>
|
||||
<a href="javascript:void(0)" class="pay-gcc-help" @click.prevent="giftCardNoticeModal = true">
|
||||
使用说明 <Icon type="ios-help-circle-outline" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="pay-gcc-body">
|
||||
<div class="pay-gcc-panel">
|
||||
<div class="pay-gcc-grid-wrap">
|
||||
<div v-if="giftCardList.length === 0" class="pay-gcc-empty">暂无可用礼品卡</div>
|
||||
<div v-else class="pay-gcc-cards">
|
||||
<div
|
||||
v-for="(item, index) in giftCardList"
|
||||
:key="item.id || index"
|
||||
class="pay-gcc-item"
|
||||
@click="toggleGiftCard(item)"
|
||||
>
|
||||
<div class="pay-gcc-item-inner">
|
||||
<div class="pay-gcc-pattern" aria-hidden="true" />
|
||||
<div class="pay-gcc-item-main">
|
||||
<div class="pay-gcc-top-row">
|
||||
<div class="pay-gcc-left">
|
||||
<div class="pay-gcc-name">{{ item.giftCardName || "礼品卡" }}</div>
|
||||
<div class="pay-gcc-face">面值{{ formatGiftFaceValue(item.faceValue) }}元</div>
|
||||
</div>
|
||||
<div class="pay-gcc-right-meta">
|
||||
<div class="pay-gcc-type">现金卡</div>
|
||||
<div class="pay-gcc-valid">{{ formatGiftExpire(item) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pay-gcc-balance-row">
|
||||
<span class="pay-gcc-amt">¥{{ item.balance != null ? (item.balance | unitPrice) : "0.00" }}</span>
|
||||
<span class="pay-gcc-bal-label">余额</span>
|
||||
</div>
|
||||
<div class="pay-gcc-no">{{ item.cardNo }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isGiftCardSelected(item)" class="pay-gcc-corner">
|
||||
<Icon type="md-checkmark" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 订单价格 -->
|
||||
<div class="order-price">
|
||||
<div>
|
||||
@@ -209,6 +263,9 @@
|
||||
<div v-if="priceDetailDTO.couponPrice > 0">
|
||||
<span>优惠券金额:</span><span>-{{ priceDetailDTO.couponPrice | unitPrice("¥") }}</span>
|
||||
</div>
|
||||
<div v-if="giftCardDeductAmount > 0">
|
||||
<span>礼品卡抵扣:</span><span>-{{ giftCardDeductAmount | unitPrice("¥") }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="$route.query.way === 'POINTS'">
|
||||
<span>应付积分:</span><span class="actrual-price">{{ priceDetailDTO.payPoint }}</span>
|
||||
@@ -238,6 +295,14 @@
|
||||
<invoice-modal ref="invModal" :invoiceData="invoiceData" @change="getInvMsg" />
|
||||
<!-- 选择地址模态框 -->
|
||||
<address-manage ref="address" :id="addrId" @change="addrChange"></address-manage>
|
||||
<Modal v-model="giftCardNoticeModal" title="礼品卡使用说明" footer-hide width="520">
|
||||
<p class="pay-gcc-notice-p">
|
||||
请在礼品卡有效期内使用;结算时勾选礼品卡即可按规则抵扣订单金额,可与优惠券等活动叠加规则以平台说明为准。放弃勾选或取消抵扣将恢复对应余额。
|
||||
</p>
|
||||
<div class="pay-gcc-notice-foot">
|
||||
<Button type="primary" @click="giftCardNoticeModal = false">我知道了</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -250,6 +315,7 @@ import {
|
||||
createTrade,
|
||||
selectAddr,
|
||||
selectCoupon,
|
||||
selectGiftCard,
|
||||
setShipMethod,
|
||||
setStoreAddressId,
|
||||
shippingMethodList,
|
||||
@@ -282,6 +348,30 @@ export default {
|
||||
""
|
||||
);
|
||||
},
|
||||
giftCardDeductAmount() {
|
||||
if (this.tradeGiftCardDeductTotal != null && Number(this.tradeGiftCardDeductTotal) > 0) {
|
||||
return Number(this.tradeGiftCardDeductTotal);
|
||||
}
|
||||
const items = this.giftCardDeductItems || [];
|
||||
let sum = 0;
|
||||
items.forEach((it) => {
|
||||
sum += Number(it.deductAmount || 0);
|
||||
});
|
||||
if (sum > 0) {
|
||||
return sum;
|
||||
}
|
||||
const p = this.priceDetailDTO || {};
|
||||
const n = Number(
|
||||
p.giftCardPrice != null
|
||||
? p.giftCardPrice
|
||||
: p.giftCardDiscountPrice != null
|
||||
? p.giftCardDiscountPrice
|
||||
: p.memberCardPrice != null
|
||||
? p.memberCardPrice
|
||||
: 0
|
||||
);
|
||||
return Number.isFinite(n) ? n : 0;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -326,6 +416,11 @@ export default {
|
||||
usedCouponId: [], // 已使用优惠券id
|
||||
selectedCoupon: {}, // 已选优惠券对象
|
||||
storeId: '', //店铺Id
|
||||
giftCardList: [], // TradeDTO.canUseGiftCards
|
||||
giftCardNoticeModal: false,
|
||||
giftCardDeductItems: [], // 已选礼品卡抵扣明细(TradeDTO.giftCardDeductItems)
|
||||
tradeGiftCardDeductTotal: null, // TradeDTO.giftCardDeductTotal
|
||||
selectedGiftCardCredentialIds: [], // 已选凭证 id,与 deductItems 同步
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@@ -476,12 +571,110 @@ export default {
|
||||
this.$forceUpdate();
|
||||
});
|
||||
}
|
||||
this.giftCardDeductItems = Array.isArray(res.result.giftCardDeductItems)
|
||||
? res.result.giftCardDeductItems
|
||||
: [];
|
||||
this.tradeGiftCardDeductTotal =
|
||||
res.result.giftCardDeductTotal != null && res.result.giftCardDeductTotal !== ""
|
||||
? Number(res.result.giftCardDeductTotal)
|
||||
: null;
|
||||
this.giftCardList = Array.isArray(res.result.canUseGiftCards) ? res.result.canUseGiftCards : [];
|
||||
this.syncGiftCardSelectionFromCart(res.result);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$Spin.hide();
|
||||
});
|
||||
},
|
||||
syncGiftCardSelectionFromCart(result) {
|
||||
if (!result) {
|
||||
this.selectedGiftCardCredentialIds = [];
|
||||
return;
|
||||
}
|
||||
const selectedIds = result.selectedGiftCardIds;
|
||||
if (Array.isArray(selectedIds) && selectedIds.length) {
|
||||
this.selectedGiftCardCredentialIds = selectedIds
|
||||
.map((id) => (id != null && id !== "" ? String(id) : ""))
|
||||
.filter(Boolean);
|
||||
return;
|
||||
}
|
||||
const items = Array.isArray(result.giftCardDeductItems) ? result.giftCardDeductItems : [];
|
||||
if (items.length) {
|
||||
this.selectedGiftCardCredentialIds = items
|
||||
.map((it) => (it.credentialId != null && it.credentialId !== "" ? String(it.credentialId) : ""))
|
||||
.filter(Boolean);
|
||||
return;
|
||||
}
|
||||
const pd = result.priceDetailDTO || {};
|
||||
const id =
|
||||
result.selectedGiftCardCredentialId ||
|
||||
result.usedGiftCardCredentialId ||
|
||||
pd.selectedGiftCardCredentialId ||
|
||||
pd.usedGiftCardCredentialId ||
|
||||
(result.selectedGiftCard && (result.selectedGiftCard.id || result.selectedGiftCard.credentialId)) ||
|
||||
(result.giftCardCashSelected && result.giftCardCashSelected.id) ||
|
||||
null;
|
||||
this.selectedGiftCardCredentialIds =
|
||||
id != null && id !== "" ? [String(id)] : [];
|
||||
},
|
||||
formatGiftFaceValue(val) {
|
||||
if (val == null || val === "") {
|
||||
return "—";
|
||||
}
|
||||
const n = Number(val);
|
||||
if (Number.isNaN(n)) {
|
||||
return String(val);
|
||||
}
|
||||
return Number.isInteger(n) ? String(n) : n.toFixed(2).replace(/\.?0+$/, "");
|
||||
},
|
||||
formatGiftExpire(row) {
|
||||
const t = row && row.expireTime;
|
||||
if (!t) {
|
||||
return "长期有效";
|
||||
}
|
||||
const d = new Date(t);
|
||||
if (Number.isNaN(d.getTime())) {
|
||||
return "长期有效";
|
||||
}
|
||||
if (d.getFullYear() >= 2099) {
|
||||
return "长期有效";
|
||||
}
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
return `${y}-${m}-${day} 到期`;
|
||||
},
|
||||
toggleGiftCard(item) {
|
||||
if (!item || item.id == null || item.id === "") {
|
||||
return;
|
||||
}
|
||||
if (this.isGiftCardSelected(item)) {
|
||||
this.useGiftCard(item.id, false);
|
||||
} else {
|
||||
this.useGiftCard(item.id, true);
|
||||
}
|
||||
},
|
||||
isGiftCardSelected(item) {
|
||||
if (!item || !this.selectedGiftCardCredentialIds.length) {
|
||||
return false;
|
||||
}
|
||||
const id = item.id != null ? String(item.id) : "";
|
||||
return id && this.selectedGiftCardCredentialIds.includes(id);
|
||||
},
|
||||
useGiftCard(credentialId, used) {
|
||||
const params = {
|
||||
way: this.$route.query.way,
|
||||
used,
|
||||
};
|
||||
if (credentialId != null && credentialId !== "") {
|
||||
params.credentialId = String(credentialId);
|
||||
}
|
||||
selectGiftCard(params).then((res) => {
|
||||
if (res.success) {
|
||||
this.init();
|
||||
}
|
||||
});
|
||||
},
|
||||
getCouponNum() {
|
||||
// 获取可用优惠券数量
|
||||
couponNum({ way: this.$route.query.way }).then((res) => {
|
||||
@@ -1189,4 +1382,189 @@ export default {
|
||||
max-height: 260px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.pay-gcc-module {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.pay-gcc-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.pay-gcc-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
.pay-gcc-deduct {
|
||||
margin-left: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
color: #666;
|
||||
}
|
||||
.pay-gcc-deduct-num {
|
||||
color: #e54d42;
|
||||
font-weight: 600;
|
||||
}
|
||||
.pay-gcc-help {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
.pay-gcc-help:hover {
|
||||
color: $theme_color;
|
||||
}
|
||||
.pay-gcc-body {
|
||||
min-height: 120px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.pay-gcc-panel {
|
||||
position: relative;
|
||||
}
|
||||
.pay-gcc-grid-wrap {
|
||||
position: relative;
|
||||
min-height: 100px;
|
||||
}
|
||||
.pay-gcc-empty {
|
||||
padding: 24px 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
.pay-gcc-cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 18px;
|
||||
}
|
||||
.pay-gcc-item {
|
||||
position: relative;
|
||||
width: 280px;
|
||||
max-width: 100%;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.pay-gcc-item:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.pay-gcc-item-inner {
|
||||
position: relative;
|
||||
min-height: 150px;
|
||||
background: linear-gradient(135deg, #ff9a4a 0%, #ff7729 48%, #e86a1f 100%);
|
||||
}
|
||||
.pay-gcc-pattern {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0.2;
|
||||
pointer-events: none;
|
||||
background-image: repeating-linear-gradient(
|
||||
-32deg,
|
||||
transparent,
|
||||
transparent 5px,
|
||||
rgba(255, 255, 255, 0.45) 5px,
|
||||
rgba(255, 255, 255, 0.45) 6px
|
||||
);
|
||||
}
|
||||
.pay-gcc-item-main {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: 14px 14px 12px;
|
||||
color: #fff;
|
||||
}
|
||||
.pay-gcc-top-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
.pay-gcc-name {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.pay-gcc-face {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
opacity: 0.92;
|
||||
}
|
||||
.pay-gcc-right-meta {
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.pay-gcc-type {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.pay-gcc-valid {
|
||||
margin-top: 6px;
|
||||
font-size: 11px;
|
||||
opacity: 0.9;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pay-gcc-balance-row {
|
||||
margin-top: 14px;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
}
|
||||
.pay-gcc-amt {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.pay-gcc-bal-label {
|
||||
font-size: 13px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.pay-gcc-no {
|
||||
margin-top: 10px;
|
||||
font-size: 11px;
|
||||
opacity: 0.75;
|
||||
word-break: break-all;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.pay-gcc-corner {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.pay-gcc-corner::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -22px;
|
||||
bottom: -22px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
background: #e54d42;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.pay-gcc-corner .ivu-icon {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
bottom: 3px;
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
z-index: 1;
|
||||
}
|
||||
.pay-gcc-notice-p {
|
||||
line-height: 1.75;
|
||||
color: #515a6e;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.pay-gcc-notice-foot {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
theme="light"
|
||||
width="auto"
|
||||
:active-name="$route.name"
|
||||
:open-names="['订单中心', '会员中心', '账户中心']"
|
||||
:open-names="['订单中心', '会员中心']"
|
||||
@on-select="onSelect"
|
||||
>
|
||||
<div class="user-icon">
|
||||
|
||||
@@ -81,27 +81,25 @@ const member = [{
|
||||
icon: '',
|
||||
title: '我的等级',
|
||||
path: 'MemberGrade'
|
||||
}
|
||||
],
|
||||
display: true
|
||||
}];
|
||||
|
||||
// 账户中心
|
||||
const user = [{
|
||||
icon: '',
|
||||
title: '账户中心',
|
||||
menus: [{
|
||||
},
|
||||
{
|
||||
icon: '',
|
||||
title: '我的优惠券',
|
||||
path: 'Coupons'
|
||||
},
|
||||
{
|
||||
icon: '',
|
||||
title: '资金管理',
|
||||
title: '我的余额',
|
||||
path: 'MoneyManagement'
|
||||
}],
|
||||
},
|
||||
{
|
||||
icon: '',
|
||||
title: '我的礼品卡',
|
||||
path: 'MyGiftCards'
|
||||
}
|
||||
],
|
||||
display: true
|
||||
}]
|
||||
}];
|
||||
|
||||
// 活动中心
|
||||
// const activity = [{
|
||||
@@ -171,6 +169,6 @@ const user = [{
|
||||
// ]
|
||||
// wholesale[0], shop[0]
|
||||
let menuList = []
|
||||
menuList.push(order[0], member[0], user[0])
|
||||
menuList.push(order[0], member[0])
|
||||
|
||||
export default menuList
|
||||
|
||||
@@ -76,15 +76,16 @@ const MsgDetail = (resolve) =>
|
||||
require(["@/pages/home/memberCenter/memberMsg/MsgDetail"], resolve);
|
||||
|
||||
/*
|
||||
* 会员中心
|
||||
* 账户中心
|
||||
* */
|
||||
* 会员中心(我的优惠券、我的余额等)
|
||||
*/
|
||||
const Coupons = (resolve) =>
|
||||
require(["@/pages/home/userCenter/Coupons"], resolve);
|
||||
const MyTracks = (resolve) =>
|
||||
require(["@/pages/home/userCenter/MyTracks"], resolve);
|
||||
const MoneyManagement = (resolve) =>
|
||||
require(["@/pages/home/userCenter/MoneyManagement"], resolve);
|
||||
const MyGiftCards = (resolve) =>
|
||||
require(["@/pages/home/userCenter/MyGiftCards"], resolve);
|
||||
|
||||
const Home = (resolve) => require(["@/pages/user/Home"], resolve);
|
||||
|
||||
@@ -261,6 +262,13 @@ export default new Router({
|
||||
path: "MoneyManagement",
|
||||
name: "MoneyManagement",
|
||||
component: MoneyManagement,
|
||||
meta: { title: "我的余额" },
|
||||
},
|
||||
{
|
||||
path: "MyGiftCards",
|
||||
name: "MyGiftCards",
|
||||
component: MyGiftCards,
|
||||
meta: { title: "我的礼品卡" },
|
||||
},
|
||||
{
|
||||
path: "Complain",
|
||||
@@ -271,6 +279,7 @@ export default new Router({
|
||||
path: "Coupons",
|
||||
name: "Coupons",
|
||||
component: Coupons,
|
||||
meta: { title: "我的优惠券" },
|
||||
},
|
||||
{
|
||||
path: "CommentList",
|
||||
|
||||
Reference in New Issue
Block a user