diff --git a/public/img/paycode.jpg b/public/img/paycode.jpg
index 0ca3cf3..c445dcb 100644
Binary files a/public/img/paycode.jpg and b/public/img/paycode.jpg differ
diff --git a/src/api/http.js b/src/api/http.js
index 79ac8d9..ec9ed4d 100644
--- a/src/api/http.js
+++ b/src/api/http.js
@@ -62,17 +62,20 @@ function handleResponse(response) {
/**
* 处理 token 失效
*/
-function handleUnauthorized() {
- // 如果 localStorage 中本来就没有 token,说明是未登录状态,不做处理
- if (!localStorage.getItem('member_token')) {
+function handleUnauthorized(requestToken) {
+ // 只有本次请求发出时携带的 token 失效,才清除登录状态
+ if (!requestToken) {
+ return;
+ }
+
+ // 如果本地 token 已经被新的登录流程更新,不处理旧请求的 401/403
+ if (localStorage.getItem('member_token') !== requestToken) {
return;
}
- // 清除登录状态
localStorage.removeItem('member_token');
localStorage.removeItem('member_username');
- // 跳转到登录页
if (window.location.hash !== '#/Login') {
window.location.href = '#/Login';
}
@@ -81,10 +84,10 @@ function handleUnauthorized() {
/**
* 统一错误处理
*/
-function handleError(err) {
+function handleError(err, requestToken) {
// token 失效
if (err.status === ERR_CODE.UNAUTHORIZED || err.status === ERR_CODE.FORBIDDEN) {
- handleUnauthorized();
+ handleUnauthorized(requestToken);
}
return Promise.reject(err);
}
@@ -120,14 +123,16 @@ function fetchWithTimeout(url, options, timeout = DEFAULT_TIMEOUT) {
* @returns {Promise}
*/
export function request(url, data, method = 'POST', timeout = DEFAULT_TIMEOUT) {
+ const requestToken = localStorage.getItem('member_token');
return fetchWithTimeout(BASE_URL + url, {
method,
headers: getHeaders(),
body: JSON.stringify(data),
- }, timeout).then(handleResponse).catch(handleError);
+ }, timeout).then(handleResponse).catch(err => handleError(err, requestToken));
}
export const get = (url, params, timeout = DEFAULT_TIMEOUT) => {
+ const requestToken = localStorage.getItem('member_token');
let query = '';
if (params) {
query = '?' + new URLSearchParams(params).toString();
@@ -135,7 +140,7 @@ export const get = (url, params, timeout = DEFAULT_TIMEOUT) => {
return fetchWithTimeout(BASE_URL + url + query, {
method: 'GET',
headers: getHeaders(),
- }, timeout).then(handleResponse).catch(handleError);
+ }, timeout).then(handleResponse).catch(err => handleError(err, requestToken));
};
export const post = (url, data, timeout = DEFAULT_TIMEOUT) => request(url, data, 'POST', timeout);
@@ -159,7 +164,7 @@ export function postForm(url, formData, timeout = DEFAULT_TIMEOUT) {
method: 'POST',
headers,
body: formData,
- }, timeout).then(handleResponse).catch(handleError);
+ }, timeout).then(handleResponse).catch(err => handleError(err, token));
}
/**
diff --git a/src/main.js b/src/main.js
index a4ac13d..fc2901b 100644
--- a/src/main.js
+++ b/src/main.js
@@ -52,16 +52,16 @@ datadicStore.init()
const userStore = useUserStore()
// 全局前置守卫
-router.beforeEach((to, from, next) => {
- if (to.meta.noLogin) {
- return next();
- }
- const isLogin = userStore.isLogin;
- if (!isLogin) {
- return next({ name: 'Login', query: { redirect: to.fullPath } });
- }
- next();
-});
+// router.beforeEach((to, from, next) => {
+// if (to.meta.noLogin) {
+// return next();
+// }
+// const isLogin = userStore.isLogin;
+// if (!isLogin) {
+// return next({ name: 'Login', query: { redirect: to.fullPath } });
+// }
+// next();
+// });
app.config.globalProperties.$datadic = {
get: (code) => dictCache[code] || null,
diff --git a/src/router.js b/src/router.js
index 832bfd8..c0485e5 100644
--- a/src/router.js
+++ b/src/router.js
@@ -320,20 +320,6 @@ const routes = [
component: () => import('./views/User/Checkout/CheckoutTrade.vue'),
meta: { title: '订单详情' }
},
- // {
- // path: '/Refresh',
- // name: 'Refresh',
- // component: { render: () => null },
- // meta: { noLogin: true },
- // beforeRouteEnter(to, from, next) {
- // next(vm => {
- // setTimeout(() => {
- // const redirect = to.query.redirect || '/Home'
- // vm.$router.replace(decodeURIComponent(redirect))
- // }, 50)
- // })
- // }
- // },
{
path: '/SyncAuth',
name: 'SyncAuth',
diff --git a/src/styles/ch.less b/src/styles/ch.less
index a90a8e5..21c1644 100644
--- a/src/styles/ch.less
+++ b/src/styles/ch.less
@@ -3426,6 +3426,11 @@
.top {
.box;
.box-align-center;
+ position: fixed;
+ left: 0;
+ right: 0;
+ top: calc(var(--van-nav-bar-height, 46px) + env(safe-area-inset-top));
+ z-index: 998;
padding: 0 4vw;
height: 12vw;
background-color: #ffffff;
@@ -3452,7 +3457,7 @@
}
.list {
- padding: 0 4vw;
+ padding: 16vw 4vw 0;
margin-top: 4vw;
.item {
diff --git a/src/views/404.vue b/src/views/404.vue
index b7e3b43..d209de8 100644
--- a/src/views/404.vue
+++ b/src/views/404.vue
@@ -17,7 +17,7 @@ export default {
},
methods: {
back() {
- this.$router.back();
+ this.$navigate('/My');
}
}
}
diff --git a/src/views/Cashout/Cashout.vue b/src/views/Cashout/Cashout.vue
index 97a35ac..fb20b25 100644
--- a/src/views/Cashout/Cashout.vue
+++ b/src/views/Cashout/Cashout.vue
@@ -86,6 +86,12 @@ export default {
Promise.all([
this.$get('/v1/client/DUsersClient').then(data => {
this.wallet.Balance = data.data.zijin;
+ if (data.data.userlevelname === '会员') {
+ this.$showFailToast('您还未购买礼包产品成为VIP,暂不能提现!')
+ setTimeout(() => {
+ this.$navigate('/My')
+ }, 1500);
+ }
}).catch(err => {
this.$showFailToast(err.message);
}),
@@ -94,6 +100,7 @@ export default {
})
])
+
},
selectCard(item) {
this.card = item;
diff --git a/src/views/Merchant/MerchantTradeDetail.vue b/src/views/Merchant/MerchantTradeDetail.vue
index 3b15980..47b3054 100644
--- a/src/views/Merchant/MerchantTradeDetail.vue
+++ b/src/views/Merchant/MerchantTradeDetail.vue
@@ -26,9 +26,9 @@
付款时间:
{{ $formatGMT(data.paytime, 'yyyy-MM-dd HH:mm:ss') }}
-
+
支付方式:
-
{{ data.payway }}
+
{{ data.paychannelname }}
交易单号:
@@ -53,13 +53,13 @@
用户实付金额:
¥{{ data.paymoney?.toFixed(2) }}
+
+
+
商家惠利比例:
{{ data.discountratio }}%
-
-
-
商家惠利金额:
-¥{{ data.discount }}
diff --git a/src/views/Merchant/PayCode.vue b/src/views/Merchant/PayCode.vue
index fd0770b..9f34f87 100644
--- a/src/views/Merchant/PayCode.vue
+++ b/src/views/Merchant/PayCode.vue
@@ -24,9 +24,7 @@
- {{ loading ?
- '生成中...' : ('保存图片')
- }}
+ 长按图片保存
@@ -69,47 +67,40 @@ export default {
this.bgLoaded = true
},
+
async generateImage() {
if (this.loading) return
this.loading = true
try {
await this.$nextTick()
- // Wait for fonts with fallback for WeChat/Safari compatibility
- if (document.fonts && document.fonts.ready) {
- await document.fonts.ready
- }
- await new Promise(resolve => setTimeout(resolve, 500))
const el = this.$refs.paycodeOriginalRef
- if (!el) {
- throw new Error('Element not found')
- }
- this.generatedImage = await toDataURL(el, { format: 'png', pixelRatio: 3, useCORS: true })
+ if (!el) throw new Error('Element not found')
+
+ // 等待元素内所有
加载完成(覆盖背景、商家头像、vue - qr 渲染完成的 img)
+ const imgs = Array.from(el.querySelectorAll('img'))
+ await Promise.all(imgs.map(img => {
+ if (img.complete && img.naturalWidth > 0) return
+ Promise.resolve()
+ return new Promise(resolve => {
+ img.onload = img.onerror = resolve
+ })
+ }))
+
+ // 等 vue-qr 内部的 canvas 真正画出来(vue-qr 内部用 canvas 绘图)
+ await new Promise(resolve => setTimeout(resolve, 100))
+
+ this.generatedImage = await toDataURL(el, {
+ format: 'png',
+ pixelRatio: 3, useCORS: true
+ })
} catch (e) {
console.error('生成收款码失败:', e)
this.$showFailToast('生成失败')
} finally {
this.loading = false
}
- },
+ }
- async handleSave() {
- if (this.loading) return
- try {
- this.loading = true
- if (!this.generatedImage) {
- await this.generateImage()
- }
- if (this.generatedImage) {
- downloadByDataURL(this.generatedImage, `收款码_${this.shopname}`)
- this.$showSuccessToast('保存成功')
- }
- } catch (e) {
- console.error('保存失败:', e)
- this.$showFailToast('保存失败')
- } finally {
- this.loading = false
- }
- },
},
}
diff --git a/src/views/Merchant/Statistics.vue b/src/views/Merchant/Statistics.vue
index 7d54777..3ab8547 100644
--- a/src/views/Merchant/Statistics.vue
+++ b/src/views/Merchant/Statistics.vue
@@ -75,19 +75,19 @@
- {{ active == 0 ? '今日' : '本月' }}营业额(元)
+ {{ active == 0 ? '当日' : '当月' }}营业额(元)
{{ chartData.yingyee?.toFixed(2) }}
- {{ active == 0 ? '今日' : '本月' }}抵扣积分
+ {{ active == 0 ? '当日' : '当月' }}应收(元)
{{ chartData.yingshou?.toFixed(2) }}
- {{ active == 0 ? '今日' : '本月' }}订单数
+ {{ active == 0 ? '当日' : '当月' }}订单数
{{ chartData.dingdanshu }}
- {{ active == 0 ? '今日' : '本月' }}收入(元)
+ {{ active == 0 ? '当日' : '当月' }}惠利金额(元)
{{ chartData.youhui?.toFixed(2) }}
@@ -173,10 +173,24 @@ export default {
this.chart = window.echarts.init(this.$refs.chartRef);
}
const dates = this.chartData.orderchart.map(item => item.adddate?.slice(5));
- const values = this.chartData.orderchart.map(item => item.ordermoney);
+ const values = this.chartData.orderchart.map(item => Number(item.ordermoney || 0));
+ this.chart.clear();
+ this.chart.off('click');
+ this.chart.getZr().off('click');
this.chart.setOption({
tooltip: {
- trigger: 'axis'
+ show: true,
+ // tooltip 触发方式:item 表示点击/滑过数据点显示
+ trigger: 'item',
+ triggerOn: 'mousemove|click',
+ renderMode: 'html',
+ confine: true,
+ // tooltip 弹框样式在这里配置,不写则使用 ECharts 默认样式
+ // extraCssText: 'z-index:999999;box-shadow:0 2px 8px rgba(0,0,0,.15);',
+ // tooltip 展示内容在这里配置
+ formatter(params) {
+ return `${params.name}
${params.seriesName}:${Number(params.value || 0).toFixed(2)}`;
+ }
},
grid: {
left: '12%',
@@ -200,9 +214,12 @@ export default {
}
},
series: [{
+ name: '营业额',
data: values,
type: 'line',
smooth: true,
+ showSymbol: true,
+ symbolSize: 6,
lineStyle: { color: '#e4bb4e', width: 2 },
itemStyle: { color: '#e4bb4e' },
areaStyle: {
@@ -213,6 +230,19 @@ export default {
}
}]
});
+ // 扩大点击范围:点击图表区域时,自动显示离点击位置最近的数据点 tooltip
+ this.chart.getZr().on('click', event => {
+ if (!values.length) return;
+ const pointInPixel = [event.offsetX, event.offsetY];
+ if (!this.chart.containPixel('grid', pointInPixel)) return;
+ const pointInGrid = this.chart.convertFromPixel({ seriesIndex: 0 }, pointInPixel);
+ const dataIndex = Math.max(0, Math.min(values.length - 1, Math.round(pointInGrid[0])));
+ this.chart.dispatchAction({
+ type: 'showTip',
+ seriesIndex: 0,
+ dataIndex
+ });
+ });
},
getCount() {
this.$get('/v1/client/DShopsClient/statistics').then(res => {
diff --git a/src/views/Trade/Pay.vue b/src/views/Trade/Pay.vue
index 21e0713..ed8ddaf 100644
--- a/src/views/Trade/Pay.vue
+++ b/src/views/Trade/Pay.vue
@@ -38,7 +38,8 @@
-
+
@@ -232,6 +233,17 @@ export default {
}
.pay {
+ &::before {
+ content: '';
+ width: 100vw;
+ height: 100vh;
+ position: fixed;
+ left: 0;
+ top: 0;
+ background: #fff;
+ z-index: -1;
+ }
+
text-align: center;
padding-top: 16.667vw;
diff --git a/src/views/Trade/TradeDetail.vue b/src/views/Trade/TradeDetail.vue
index b6fa79d..5e88042 100644
--- a/src/views/Trade/TradeDetail.vue
+++ b/src/views/Trade/TradeDetail.vue
@@ -7,7 +7,7 @@
{{ data.statename }}
-
-
+
+
![]()
+
+
+ {{ data.shopname }}
+
+
+
+
@@ -146,6 +154,10 @@
发货时间
{{ $formatGMT(data.exporttime, 'yyyy-MM-dd HH:mm:ss') }}
+
+ 完成时间
+ {{ $formatGMT(data.paytime, 'yyyy-MM-dd HH:mm:ss') }}
+
完成时间
{{ $formatGMT(data.receipttime, 'yyyy-MM-dd HH:mm:ss') }}
diff --git a/src/views/Trade/Tradelist.vue b/src/views/Trade/Tradelist.vue
index 317b23a..d9f6f85 100644
--- a/src/views/Trade/Tradelist.vue
+++ b/src/views/Trade/Tradelist.vue
@@ -37,8 +37,9 @@
{{ item.proskuname }}
x{{ item.buynums }}
-
-
¥{{ item.proskusaleprice?.toFixed(2) }}
+
+
¥{{ item.proskusaleprice?.toFixed(2)
+ }}
{{ item.proskusaleprice?.toFixed(2) }}积分
惠利{{ item.discountratio }}%
@@ -54,9 +55,10 @@
{{ item.statename }}
-
-
-
+
+
+
diff --git a/src/views/User/Checkout/Checkout.vue b/src/views/User/Checkout/Checkout.vue
index 88ba8fe..1371fb0 100644
--- a/src/views/User/Checkout/Checkout.vue
+++ b/src/views/User/Checkout/Checkout.vue
@@ -88,7 +88,8 @@ export default {
"shopuserid": ''
},
jifenDeduction: 0,
- quanDeduction: 0
+ quanDeduction: 0,
+ lastChecked: ''
}
},
computed: {
@@ -119,16 +120,21 @@ export default {
})
},
toggleDeduction(type) {
- if (type === 'jifen') {
- if (!this.data.user.xiaofeijifen || this.data.user.xiaofeijifen <= 0) return;
- this.checked = '1'
- this.req.isjifen = this.checked === '1';
- this.req.ishuiyuanka = false;
- } else if (type === 'quan') {
- if (!this.data.user.xiaofeiquan || this.data.user.xiaofeiquan <= 0) return;
- this.checked = '2';
- this.req.ishuiyuanka = this.checked === '2';
+ const target = type === 'jifen' ? '1' : '2';
+ if (type === 'jifen' && (!this.data.user.xiaofeijifen || this.data.user.xiaofeijifen <= 0)) return;
+ if (type === 'quan' && (!this.data.user.xiaofeiquan || this.data.user.xiaofeiquan <= 0)) return;
+
+ if (this.lastChecked === target) {
+ // 再次点击同一项:取消选中
+ this.checked = '';
this.req.isjifen = false;
+ this.req.ishuiyuanka = false;
+ this.lastChecked = '';
+ } else {
+ this.checked = target;
+ this.req.isjifen = target === '1';
+ this.req.ishuiyuanka = target === '2';
+ this.lastChecked = target;
}
},
calcDeduction() {
diff --git a/src/views/User/My.vue b/src/views/User/My.vue
index 69da65f..25a1a8b 100644
--- a/src/views/User/My.vue
+++ b/src/views/User/My.vue
@@ -222,14 +222,11 @@ export default {
components: { ManagerPopup },
computed: {
},
- beforeRouteEnter(to, from, next) {
- if (!localStorage.getItem('member_token')) {
- next({ name: 'Login', query: { redirect: to.fullPath } });
- } else {
- next();
- }
- },
mounted() {
+ if (!localStorage.getItem('member_token')) {
+ this.$router.replace({ name: 'Login', query: { redirect: this.$route.fullPath } });
+ return;
+ }
this.init();
this.$get('/v1/client/HWxinfoClient/qrcode').then(res => {
this.FollowQRCode = res.data;
diff --git a/src/views/User/ShopInfo.vue b/src/views/User/ShopInfo.vue
index fe7b441..f6f7348 100644
--- a/src/views/User/ShopInfo.vue
+++ b/src/views/User/ShopInfo.vue
@@ -150,9 +150,9 @@ export default {
},
});
});
+ } else {
+ window.location.href = `https://uri.amap.com/navigation?to=${lon},${lat},${encodeURIComponent(fullAddress)}&mode=car&src=shop`;
}
- } else {
- window.open(`https://uri.amap.com/navigation?to=${lon},${lat},${fullAddress}&mode=car&src=shop`, '_blank');
}
},
}
diff --git a/src/views/User/Wallet/Balance.vue b/src/views/User/Wallet/Balance.vue
index 77b9ca6..0c3f3f2 100644
--- a/src/views/User/Wallet/Balance.vue
+++ b/src/views/User/Wallet/Balance.vue
@@ -180,7 +180,7 @@
{{ data.total.totalsum?.toFixed(2) }}
-
@@ -317,6 +317,7 @@ export default {
loading: false,
showTerm: false,
list: [],
+ isVIP: ''
}
},
methods: {
@@ -326,11 +327,23 @@ export default {
}).catch(err => {
this.$showFailToast(err.message || '加载失败');
})
-
- this.$get('/v1/client/DUsermoneysClient/select').then(res => {
- // console.log(res.data);
+ this.$get('/v1/client/DUsersClient').then(data => {
+ this.isVIP = data.data.userlevelname;
})
+ // this.$get('/v1/client/DUsermoneysClient/select').then(res => {
+ // // console.log(res.data);
+ // })
+ },
+ toCashout() {
+ if (this.isVIP === '会员') {
+ this.$showFailToast('您还未购买礼包产品成为VIP,暂不能提现!')
+ setTimeout(() => {
+ // this.$navigate('/My')
+ }, 1500);
+ return
+ }
+ this.$navigate('Cashout');
},
onconfirm(value) {
this.date = this.currentDate;