mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-08-06 02:47:29 +08:00
feat(buyer): 增强商品详情与支付逻辑
- 引入 buyerLogin 工具,优化商品详情页的链接跳转逻辑,确保未登录用户能正确重定向到登录页面 - 更新商品 SKU 详情 API,支持未登录状态下的访问 - 修改支付 API,新增 skipMessage 参数以控制支付提示信息 - 改进商品列表与支付页面的用户体验,确保更流畅的操作流程 - 规范化商品类型与库存提示,提升用户体验
This commit is contained in:
@@ -33,12 +33,13 @@ export function goodsDetail (goodsId) {
|
||||
});
|
||||
}
|
||||
|
||||
// id获取商品Sku详情
|
||||
// id获取商品Sku详情(支持未登录浏览,登录后可选携带 token)
|
||||
export function goodsSkuDetail (params) {
|
||||
return request({
|
||||
url: `/buyer/goods/goods/sku/${params.goodsId}/${params.skuId}`,
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
needToken: false,
|
||||
optionalToken: true,
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,12 +24,13 @@ export function tradeDetail (params) {
|
||||
* @param payClient 调起方式 可用值:APP,NATIVE,JSAPI,H5
|
||||
* @param sn 订单编号
|
||||
*/
|
||||
export function pay (params) {
|
||||
export function pay (params, config = {}) {
|
||||
return request({
|
||||
url: `/buyer/payment/cashier/pay/${params.paymentMethod}/${params.paymentClient}`,
|
||||
needToken: true,
|
||||
method: Method.GET,
|
||||
params
|
||||
params,
|
||||
skipMessage: !!config.skipMessage,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ export function applyThird (params) {
|
||||
export function getDetailById (id) {
|
||||
return request({
|
||||
url: `/buyer/store/store/get/detail/${id}`,
|
||||
needToken: true,
|
||||
needToken: false,
|
||||
optionalToken: true,
|
||||
method: Method.GET
|
||||
})
|
||||
}
|
||||
|
||||
@@ -259,7 +259,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="add-buy-car-box">
|
||||
<div class="item-select">
|
||||
<div class="item-select-title">
|
||||
@@ -339,6 +338,14 @@
|
||||
@click="buyNow"
|
||||
>立即购买</el-button
|
||||
>
|
||||
<el-alert
|
||||
v-if="isECouponGoods"
|
||||
class="e-coupon-after-sale-notice"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
:title="eCouponAfterSaleHint()"
|
||||
/>
|
||||
<el-tooltip content="观看视频" v-if="skuDetail.goodsVideo">
|
||||
<img class="view-video" @click="showGoodsVideo = true" :src="playIcon" alt="">
|
||||
</el-tooltip>
|
||||
@@ -374,6 +381,7 @@ import {
|
||||
getECouponMaxBuyNum,
|
||||
createEmptyPromotionMap,
|
||||
resolveECouponCartType,
|
||||
eCouponAfterSaleHint,
|
||||
E_COUPON_CART_BUY_NOW,
|
||||
E_COUPON_CART_PINTUAN,
|
||||
E_COUPON_CART_POINTS,
|
||||
@@ -476,6 +484,7 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
eCouponAfterSaleHint,
|
||||
// 初始化video
|
||||
initVideo(){
|
||||
if(!this.goodsVideo ){
|
||||
@@ -724,8 +733,8 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// 用户登录才会判断是否收藏
|
||||
if (this.Cookies.getItem("userInfo")) {
|
||||
// 用户登录才会判断是否收藏(须同时有 token,避免残留 userInfo 触发 401 跳转登录)
|
||||
if (this.Cookies.getItem("accessToken") && this.Cookies.getItem("userInfo")) {
|
||||
isCollection("GOODS", this.skuDetail.id).then((res) => {
|
||||
if (res.success && res.result) {
|
||||
this.isCollected = true;
|
||||
@@ -1052,6 +1061,22 @@ export default {
|
||||
border-top: 1px dotted $border_color;
|
||||
}
|
||||
|
||||
.e-coupon-after-sale-notice {
|
||||
width: fit-content;
|
||||
max-width: 420px;
|
||||
flex: 0 0 auto;
|
||||
padding: 4px 10px;
|
||||
|
||||
:deep(.el-alert__content) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:deep(.el-alert__title) {
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.add-buy-car-row {
|
||||
margin-top: 25px;
|
||||
|
||||
|
||||
@@ -28,6 +28,14 @@ export function isECouponOrder(orderType) {
|
||||
return orderType === E_COUPON_ORDER_TYPE;
|
||||
}
|
||||
|
||||
/** 详情页提示:卡密交付后不支持买家售后(FR-B-04) */
|
||||
export const E_COUPON_AFTER_SALE_HINT =
|
||||
"卡密交付后不支持买家售后,请确认商品信息后再购买。";
|
||||
|
||||
export function eCouponAfterSaleHint() {
|
||||
return E_COUPON_AFTER_SALE_HINT;
|
||||
}
|
||||
|
||||
/** 可售库存:E_COUPON 读 SKU quantity(由卡池 syncSkuStock 同步) */
|
||||
export function getECouponStock(sku) {
|
||||
if (!sku) return 0;
|
||||
@@ -132,23 +140,19 @@ function normalizeCardKeyFulfillLine(source) {
|
||||
};
|
||||
}
|
||||
|
||||
/** 汇总 E_COUPON 主单行 + 满赠子单摘要的履约行 */
|
||||
export function collectCardKeyFulfillLines(orderItems = [], giftSummaries = []) {
|
||||
/** 汇总当前订单 orderItems 中的卡密履约行(不含满赠子单;赠品卡密在赠品子单详情单独查看) */
|
||||
export function collectCardKeyFulfillLines(orderItems = []) {
|
||||
const lines = [];
|
||||
(orderItems || []).forEach((item) => {
|
||||
if (!isCardKeyFulfillApplicable(item)) return;
|
||||
lines.push(normalizeCardKeyFulfillLine(item));
|
||||
});
|
||||
(giftSummaries || []).forEach((gift) => {
|
||||
lines.push(normalizeCardKeyFulfillLine({ ...gift, isGift: true }));
|
||||
});
|
||||
return lines;
|
||||
}
|
||||
|
||||
export function orderHasCardKeySection({ orderItems, giftSummaries, isECouponOrder } = {}) {
|
||||
export function orderHasCardKeySection({ orderItems, isECouponOrder } = {}) {
|
||||
if (isECouponOrder) return true;
|
||||
if (Array.isArray(giftSummaries) && giftSummaries.length > 0) return true;
|
||||
if (collectCardKeyFulfillLines(orderItems, []).length > 0) return true;
|
||||
if (collectCardKeyFulfillLines(orderItems).length > 0) return true;
|
||||
return (orderItems || []).some(
|
||||
(item) =>
|
||||
item.goodsType === E_COUPON_GOODS_TYPE ||
|
||||
@@ -167,15 +171,14 @@ export function flattenCardKeyFulfillLines(lines, withGoodsName = false) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
/** 订单是否含已交付或可展示的卡密行(含满赠 E_COUPON 子单行) */
|
||||
export function orderHasCardKeyContent(orderItems, giftSummaries) {
|
||||
const lines = collectCardKeyFulfillLines(orderItems, giftSummaries);
|
||||
return flattenCardKeyFulfillLines(lines).length > 0;
|
||||
/** 当前订单是否含已交付卡密(仅 orderItems,不含满赠子单) */
|
||||
export function orderHasCardKeyContent(orderItems) {
|
||||
return flattenCardKeyFulfillLines(collectCardKeyFulfillLines(orderItems)).length > 0;
|
||||
}
|
||||
|
||||
/** 扁平化订单项卡密(仅 cardKeyDelivered 且含 cardKeys;兼容旧逻辑) */
|
||||
export function flattenOrderCardKeys(orderItems, withGoodsName = false, giftSummaries) {
|
||||
const lines = collectCardKeyFulfillLines(orderItems, giftSummaries);
|
||||
/** 扁平化当前订单 orderItems 卡密 */
|
||||
export function flattenOrderCardKeys(orderItems, withGoodsName = false) {
|
||||
const lines = collectCardKeyFulfillLines(orderItems);
|
||||
if (lines.some((line) => line.status)) {
|
||||
return flattenCardKeyFulfillLines(lines, withGoodsName);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import storage from "@/plugins/storage";
|
||||
import { fetchAndApplyTheme } from "@/utils/theme";
|
||||
import { getThemeSetting } from "@/api/common.js";
|
||||
import config from "@/config";
|
||||
import { openLink } from "@/utils/buyerLogin";
|
||||
|
||||
const { aMapSecurityJsCode, inputMaxLength } = config;
|
||||
|
||||
@@ -36,12 +37,7 @@ app.config.globalProperties.Cookies = storage;
|
||||
app.config.globalProperties.$inputMaxLength = inputMaxLength;
|
||||
|
||||
app.config.globalProperties.linkTo = function (url) {
|
||||
if (!url) return;
|
||||
if (url.substr(0, 1) === "/") {
|
||||
window.open(location.origin + url, "_blank");
|
||||
} else {
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
openLink(url, router);
|
||||
};
|
||||
|
||||
app.config.globalProperties.connectCs = function (
|
||||
|
||||
@@ -140,8 +140,8 @@ export default {
|
||||
if (!this.goodsMsg.data.intro) {
|
||||
this.goodsMsg.data.intro = ''
|
||||
}
|
||||
// 判断是否收藏
|
||||
if (this.Cookies.getItem("userInfo")) {
|
||||
// 判断是否收藏(须同时有 token,避免未登录/ token 失效时误跳登录页)
|
||||
if (this.Cookies.getItem("accessToken") && this.Cookies.getItem("userInfo")) {
|
||||
isStoreCollection("STORE", this.goodsMsg.data.storeId).then((res) => {
|
||||
if (res.success && res.result) {
|
||||
this.storeCollected = true;
|
||||
|
||||
@@ -125,6 +125,7 @@ import { Message } from "@/utils/message";
|
||||
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
|
||||
import GoodsClassNav from "@/components/nav/GoodsClassNav";
|
||||
import * as apiGoods from "@/api/goods";
|
||||
import { isBuyerLoggedIn, redirectToLogin } from "@/utils/buyerLogin";
|
||||
export default {
|
||||
name: "GoodsList",
|
||||
beforeRouteEnter(to, from, next) {
|
||||
@@ -201,12 +202,15 @@ export default {
|
||||
this.getGoodsList();
|
||||
},
|
||||
goGoodsDetail(skuId, goodsId) {
|
||||
// 跳转商品详情
|
||||
let routeUrl = this.$router.resolve({
|
||||
const location = {
|
||||
path: "/goodsDetail",
|
||||
query: { skuId, goodsId },
|
||||
});
|
||||
window.open(routeUrl.href, "_blank");
|
||||
};
|
||||
if (!isBuyerLoggedIn()) {
|
||||
redirectToLogin(this.$router, location);
|
||||
return;
|
||||
}
|
||||
window.open(this.$router.resolve(location).href, "_blank");
|
||||
},
|
||||
goShopPage(id) {
|
||||
if (!id) {
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
</template>
|
||||
<div v-else style="color: #999; margin-left: 5px">未开发票</div>
|
||||
</div>
|
||||
<!-- 卡密信息(E_COUPON 主单或满赠子单,以 cardKeyFulfillStatus 为准) -->
|
||||
<!-- 卡密信息(当前订单 orderItems;满赠赠品卡密在赠品子单详情查看) -->
|
||||
<div class="order-card ecoupon-card-keys" v-if="hasCardKeySection">
|
||||
<h3>卡密信息</h3>
|
||||
<div
|
||||
@@ -140,9 +140,6 @@
|
||||
:key="line.key"
|
||||
class="ecoupon-fulfill-block"
|
||||
>
|
||||
<div v-if="cardKeyFulfillLines.length > 1" class="ecoupon-fulfill-title">
|
||||
{{ line.goodsName || (line.isGift ? "满赠电子卡券" : "电子卡券") }}
|
||||
</div>
|
||||
<el-alert
|
||||
v-if="line.status !== 'DELIVERED'"
|
||||
:type="cardKeyFulfillAlertType(line.status)"
|
||||
@@ -158,13 +155,6 @@
|
||||
<div class="ecoupon-card-keys-pc">
|
||||
<el-table border :data="lineCardKeyRows(line)" style="width: 100%">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column
|
||||
v-if="cardKeyFulfillLines.length > 1"
|
||||
prop="goodsName"
|
||||
label="商品"
|
||||
min-width="120"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="cardNo" label="卡号" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="cardSecret" label="卡密" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="allocatedTime" label="发卡时间" width="170" />
|
||||
@@ -446,36 +436,25 @@ export default {
|
||||
isNonPhysicalOrder() {
|
||||
return this.isVirtualOrder || this.isECouponOrder;
|
||||
},
|
||||
/** 是否展示卡密区块(含满赠 E_COUPON 子单 giftECouponOrders) */
|
||||
/** 是否展示卡密区块(仅当前订单 orderItems) */
|
||||
hasCardKeySection() {
|
||||
return orderHasCardKeySection({
|
||||
orderItems: this.order.orderItems,
|
||||
giftSummaries: this.order.giftECouponOrders,
|
||||
isECouponOrder: this.isECouponOrder,
|
||||
});
|
||||
},
|
||||
cardKeyFulfillLines() {
|
||||
return collectCardKeyFulfillLines(
|
||||
this.order.orderItems,
|
||||
this.order.giftECouponOrders
|
||||
);
|
||||
return collectCardKeyFulfillLines(this.order.orderItems);
|
||||
},
|
||||
ecouponCardKeyRows() {
|
||||
return flattenOrderCardKeys(
|
||||
this.order.orderItems,
|
||||
false,
|
||||
this.order.giftECouponOrders
|
||||
);
|
||||
return flattenOrderCardKeys(this.order.orderItems, false);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
cardKeyFulfillAlertType,
|
||||
resolveCardKeyFulfillMessage,
|
||||
lineCardKeyRows(line) {
|
||||
return (line.cardKeys || []).map((ck) => ({
|
||||
...ck,
|
||||
goodsName: line.goodsName,
|
||||
}));
|
||||
return line.cardKeys || [];
|
||||
},
|
||||
copyCardKey(row) {
|
||||
const text = `卡号:${row.cardNo || ""}\n卡密:${row.cardSecret || ""}`;
|
||||
@@ -821,12 +800,6 @@ table {
|
||||
border-top: 1px dashed #eee;
|
||||
}
|
||||
|
||||
.ecoupon-fulfill-title {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ecoupon-card-keys-pc {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -11,19 +11,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="pay-way">{{params.paymentMethod === 'ALIPAY' ? '支付宝支付' : '微信支付'}}</div>
|
||||
<div class="pay-way">{{ payWayName }}支付</div>
|
||||
<div class="qrcode">
|
||||
<div style="width:200px;height:200px;border:1px solid #eee;">
|
||||
<vue-qr :text="qrcode" :margin="0" colorDark="#000" colorLight="#fff" :size="200"></vue-qr>
|
||||
<div class="qrcode-box">
|
||||
<div v-if="payLoading" class="qrcode-status">正在生成支付二维码...</div>
|
||||
<div v-else-if="payError" class="qrcode-status qrcode-status--error">
|
||||
<p>{{ payError }}</p>
|
||||
<p class="qrcode-status-tip">您可点击「重新支付」重试,或返回选择其他支付方式</p>
|
||||
</div>
|
||||
<vue-qr
|
||||
v-else
|
||||
:text="qrcode"
|
||||
:margin="0"
|
||||
colorDark="#000"
|
||||
colorLight="#fff"
|
||||
:size="200"
|
||||
/>
|
||||
</div>
|
||||
<div class="intro">
|
||||
<el-icon><Iphone /></el-icon> 请使用{{params.paymentMethod === 'ALIPAY' ? '支付宝' : '微信'}}扫码付款
|
||||
<div v-if="!payError" class="intro">
|
||||
<el-icon><Iphone /></el-icon> 请使用{{ payWayName }}扫码付款
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-div">
|
||||
<p class="mb_10">支付成功后自动跳转,如未跳转请点击按钮手动跳转。。。</p>
|
||||
<div>
|
||||
<el-button @click="handlePay">重新支付</el-button>
|
||||
<el-button :loading="payLoading" @click="handlePay">重新支付</el-button>
|
||||
<el-button type="success" @click="$router.push('/payDone')">支付成功</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,47 +53,79 @@ export default {
|
||||
components: { vueQr, Iphone },
|
||||
data () {
|
||||
return {
|
||||
qrcode: '', // 二维码
|
||||
params: this.$route.query, // 参数
|
||||
interval: null, // 定时器
|
||||
num: 0 // 商品数
|
||||
qrcode: '',
|
||||
params: this.$route.query,
|
||||
interval: null,
|
||||
num: 0,
|
||||
payLoading: false,
|
||||
payError: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 获取支付二维码
|
||||
handlePay () {
|
||||
const params = this.$route.query;
|
||||
pay(params).then(res => {
|
||||
if (res.success) {
|
||||
this.qrcode = res.result;
|
||||
this.num = 0;
|
||||
this.interval = setInterval(this.callback, 5000);
|
||||
} else {
|
||||
Message.error(res.message)
|
||||
}
|
||||
});
|
||||
computed: {
|
||||
payWayName () {
|
||||
return this.params.paymentMethod === 'ALIPAY' ? '支付宝' : '微信';
|
||||
},
|
||||
callback () { // 支付回调接口
|
||||
this.num++;
|
||||
if (this.num >= 7) {
|
||||
},
|
||||
methods: {
|
||||
formatPayError (rawMessage) {
|
||||
const message = (rawMessage || '').trim();
|
||||
if (!message || message === '支付业务异常,请稍后重试') {
|
||||
return `${this.payWayName}支付暂不可用,请稍后重试或选择其他支付方式`;
|
||||
}
|
||||
return message;
|
||||
},
|
||||
clearPayPoll () {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
let params = JSON.parse(JSON.stringify(this.$route.query));
|
||||
},
|
||||
handlePay () {
|
||||
this.clearPayPoll();
|
||||
const params = this.$route.query;
|
||||
this.payLoading = true;
|
||||
this.payError = '';
|
||||
this.qrcode = '';
|
||||
pay(params, { skipMessage: true })
|
||||
.then((res) => {
|
||||
this.payLoading = false;
|
||||
if (res.success && res.result) {
|
||||
this.qrcode = res.result;
|
||||
this.num = 0;
|
||||
this.interval = setInterval(this.callback, 5000);
|
||||
return;
|
||||
}
|
||||
this.payError = this.formatPayError(res.message);
|
||||
Message.error(this.payError);
|
||||
})
|
||||
.catch((err) => {
|
||||
this.payLoading = false;
|
||||
this.payError = this.formatPayError(err?.message || err?.data?.message);
|
||||
Message.error(this.payError);
|
||||
});
|
||||
},
|
||||
callback () {
|
||||
this.num++;
|
||||
if (this.num >= 7) {
|
||||
this.clearPayPoll();
|
||||
}
|
||||
const params = JSON.parse(JSON.stringify(this.$route.query));
|
||||
delete params.paymentMethod;
|
||||
delete params.paymentClient;
|
||||
payCallback(params).then(res => {
|
||||
payCallback(params).then((res) => {
|
||||
if (res.result) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
this.$router.push({path: '/payDone', query: {orderType: this.$route.query.orderType}});
|
||||
this.clearPayPoll();
|
||||
this.$router.push({ path: '/payDone', query: { orderType: this.$route.query.orderType } });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.handlePay();
|
||||
}
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.clearPayPoll();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@@ -125,6 +169,33 @@ export default {
|
||||
margin: 30px 0 0 70px;
|
||||
}
|
||||
|
||||
.qrcode-box {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.qrcode-status {
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.qrcode-status--error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.qrcode-status-tip {
|
||||
margin-top: 8px;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.intro {
|
||||
background-color: #ff7674;
|
||||
height: 40px;
|
||||
@@ -143,6 +214,9 @@ export default {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
cursor: pointer;
|
||||
color: #409eff;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.price {
|
||||
@@ -153,4 +227,7 @@ export default {
|
||||
.head-right {
|
||||
font-weight: bold;
|
||||
}
|
||||
.mb_10 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
@click="goGoodsDetail(item.id)"
|
||||
>
|
||||
<div class="goods-show-img">
|
||||
<img :src="item.goodsSku.thumbnail" />
|
||||
<img :src="itemThumbnail(item)" />
|
||||
</div>
|
||||
<div class="goods-show-price">
|
||||
<span>
|
||||
@@ -26,7 +26,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="goods-show-detail">
|
||||
<span>{{ item.goodsSku.goodsName }}</span>
|
||||
<span>{{ itemGoodsName(item) }}</span>
|
||||
</div>
|
||||
<div class="goods-show-num">
|
||||
已有<span>{{ item.commentNum || 0 }}</span>人评价
|
||||
@@ -70,6 +70,13 @@ export default {
|
||||
this.getCate()
|
||||
},
|
||||
methods: {
|
||||
/** 列表 API 返回 PointsGoods(thumbnail/goodsName 在顶层);详情 API 才有 goodsSku */
|
||||
itemThumbnail (item) {
|
||||
return item?.goodsSku?.thumbnail || item?.thumbnail || ''
|
||||
},
|
||||
itemGoodsName (item) {
|
||||
return item?.goodsSku?.goodsName || item?.goodsName || ''
|
||||
},
|
||||
getList () { // 获取列表
|
||||
pointGoods(this.params).then(res => {
|
||||
if (res.success) {
|
||||
|
||||
@@ -70,7 +70,6 @@ service.interceptors.request.use(
|
||||
|
||||
const accessToken = Storage.getItem("accessToken");
|
||||
if (accessToken && (config.needToken || config.optionalToken)) {
|
||||
config.headers["accessToken"] = accessToken;
|
||||
try {
|
||||
const jwtData = JSON.parse(
|
||||
decodeURIComponent(
|
||||
@@ -80,12 +79,23 @@ service.interceptors.request.use(
|
||||
)
|
||||
)
|
||||
);
|
||||
if (jwtData.exp < Math.round(new Date() / 1000)) {
|
||||
refresh({ response: { config } });
|
||||
const expired = jwtData.exp < Math.round(new Date() / 1000);
|
||||
if (expired) {
|
||||
if (config.needToken) {
|
||||
return refresh({ response: { config } });
|
||||
}
|
||||
// 公开接口:丢弃过期 token,匿名继续请求,避免浏览商品时被引导登录
|
||||
Storage.removeItem("accessToken");
|
||||
Storage.removeItem("refreshToken");
|
||||
} else {
|
||||
config.headers["accessToken"] = accessToken;
|
||||
}
|
||||
} catch {
|
||||
Storage.removeItem("accessToken");
|
||||
Storage.removeItem("refreshToken");
|
||||
if (config.needToken) {
|
||||
return refresh({ response: { config } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
buyer/src/utils/buyerLogin.js
Normal file
59
buyer/src/utils/buyerLogin.js
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 买家端登录态与商品详情跳转校验
|
||||
*
|
||||
* @author Mike
|
||||
* @date 2026-08-05
|
||||
*/
|
||||
import storage from "@/plugins/storage";
|
||||
|
||||
export function isBuyerLoggedIn() {
|
||||
const rawUserInfo = storage.getItem("userInfo");
|
||||
if (rawUserInfo) {
|
||||
try {
|
||||
return !!JSON.parse(rawUserInfo).username;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !!storage.getItem("accessToken");
|
||||
}
|
||||
|
||||
export function parseInternalLink(url) {
|
||||
const [path, search = ""] = url.split("?");
|
||||
const query = {};
|
||||
if (search) {
|
||||
new URLSearchParams(search).forEach((value, key) => {
|
||||
query[key] = value;
|
||||
});
|
||||
}
|
||||
return { path, query };
|
||||
}
|
||||
|
||||
export function isGoodsDetailPath(path) {
|
||||
return path === "/goodsDetail";
|
||||
}
|
||||
|
||||
export function redirectToLogin(router, location) {
|
||||
router.push({
|
||||
path: "/login",
|
||||
query: {
|
||||
rePath: location.path,
|
||||
query: JSON.stringify(location.query || {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** 内部链接跳转;访问商品详情前校验登录(首页装修、列表等共用) */
|
||||
export function openLink(url, router) {
|
||||
if (!url) return;
|
||||
if (url.charAt(0) !== "/") {
|
||||
window.open(url, "_blank");
|
||||
return;
|
||||
}
|
||||
const location = parseInternalLink(url);
|
||||
if (!isBuyerLoggedIn() && isGoodsDetailPath(location.path)) {
|
||||
redirectToLogin(router, location);
|
||||
return;
|
||||
}
|
||||
window.open(router.resolve(url).href, "_blank");
|
||||
}
|
||||
Reference in New Issue
Block a user