买单修改

This commit is contained in:
chenhao 2026-06-11 10:30:24 +08:00
parent 9463c13b91
commit 7ad64cea7c
17 changed files with 175 additions and 109 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

@ -62,17 +62,20 @@ function handleResponse(response) {
/** /**
* 处理 token 失效 * 处理 token 失效
*/ */
function handleUnauthorized() { function handleUnauthorized(requestToken) {
// 如果 localStorage 中本来就没有 token说明是未登录状态不做处理 // 只有本次请求发出时携带的 token 失效,才清除登录状态
if (!localStorage.getItem('member_token')) { if (!requestToken) {
return;
}
// 如果本地 token 已经被新的登录流程更新,不处理旧请求的 401/403
if (localStorage.getItem('member_token') !== requestToken) {
return; return;
} }
// 清除登录状态
localStorage.removeItem('member_token'); localStorage.removeItem('member_token');
localStorage.removeItem('member_username'); localStorage.removeItem('member_username');
// 跳转到登录页
if (window.location.hash !== '#/Login') { if (window.location.hash !== '#/Login') {
window.location.href = '#/Login'; window.location.href = '#/Login';
} }
@ -81,10 +84,10 @@ function handleUnauthorized() {
/** /**
* 统一错误处理 * 统一错误处理
*/ */
function handleError(err) { function handleError(err, requestToken) {
// token 失效 // token 失效
if (err.status === ERR_CODE.UNAUTHORIZED || err.status === ERR_CODE.FORBIDDEN) { if (err.status === ERR_CODE.UNAUTHORIZED || err.status === ERR_CODE.FORBIDDEN) {
handleUnauthorized(); handleUnauthorized(requestToken);
} }
return Promise.reject(err); return Promise.reject(err);
} }
@ -120,14 +123,16 @@ function fetchWithTimeout(url, options, timeout = DEFAULT_TIMEOUT) {
* @returns {Promise} * @returns {Promise}
*/ */
export function request(url, data, method = 'POST', timeout = DEFAULT_TIMEOUT) { export function request(url, data, method = 'POST', timeout = DEFAULT_TIMEOUT) {
const requestToken = localStorage.getItem('member_token');
return fetchWithTimeout(BASE_URL + url, { return fetchWithTimeout(BASE_URL + url, {
method, method,
headers: getHeaders(), headers: getHeaders(),
body: JSON.stringify(data), 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) => { export const get = (url, params, timeout = DEFAULT_TIMEOUT) => {
const requestToken = localStorage.getItem('member_token');
let query = ''; let query = '';
if (params) { if (params) {
query = '?' + new URLSearchParams(params).toString(); query = '?' + new URLSearchParams(params).toString();
@ -135,7 +140,7 @@ export const get = (url, params, timeout = DEFAULT_TIMEOUT) => {
return fetchWithTimeout(BASE_URL + url + query, { return fetchWithTimeout(BASE_URL + url + query, {
method: 'GET', method: 'GET',
headers: getHeaders(), 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); 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', method: 'POST',
headers, headers,
body: formData, body: formData,
}, timeout).then(handleResponse).catch(handleError); }, timeout).then(handleResponse).catch(err => handleError(err, token));
} }
/** /**

View File

@ -52,16 +52,16 @@ datadicStore.init()
const userStore = useUserStore() const userStore = useUserStore()
// 全局前置守卫 // 全局前置守卫
router.beforeEach((to, from, next) => { // router.beforeEach((to, from, next) => {
if (to.meta.noLogin) { // if (to.meta.noLogin) {
return next(); // return next();
} // }
const isLogin = userStore.isLogin; // const isLogin = userStore.isLogin;
if (!isLogin) { // if (!isLogin) {
return next({ name: 'Login', query: { redirect: to.fullPath } }); // return next({ name: 'Login', query: { redirect: to.fullPath } });
} // }
next(); // next();
}); // });
app.config.globalProperties.$datadic = { app.config.globalProperties.$datadic = {
get: (code) => dictCache[code] || null, get: (code) => dictCache[code] || null,

View File

@ -320,20 +320,6 @@ const routes = [
component: () => import('./views/User/Checkout/CheckoutTrade.vue'), component: () => import('./views/User/Checkout/CheckoutTrade.vue'),
meta: { title: '订单详情' } 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', path: '/SyncAuth',
name: 'SyncAuth', name: 'SyncAuth',

View File

@ -3426,6 +3426,11 @@
.top { .top {
.box; .box;
.box-align-center; .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; padding: 0 4vw;
height: 12vw; height: 12vw;
background-color: #ffffff; background-color: #ffffff;
@ -3452,7 +3457,7 @@
} }
.list { .list {
padding: 0 4vw; padding: 16vw 4vw 0;
margin-top: 4vw; margin-top: 4vw;
.item { .item {

View File

@ -17,7 +17,7 @@ export default {
}, },
methods: { methods: {
back() { back() {
this.$router.back(); this.$navigate('/My');
} }
} }
} }

View File

@ -86,6 +86,12 @@ export default {
Promise.all([ Promise.all([
this.$get('/v1/client/DUsersClient').then(data => { this.$get('/v1/client/DUsersClient').then(data => {
this.wallet.Balance = data.data.zijin; this.wallet.Balance = data.data.zijin;
if (data.data.userlevelname === '会员') {
this.$showFailToast('您还未购买礼包产品成为VIP暂不能提现')
setTimeout(() => {
this.$navigate('/My')
}, 1500);
}
}).catch(err => { }).catch(err => {
this.$showFailToast(err.message); this.$showFailToast(err.message);
}), }),
@ -94,6 +100,7 @@ export default {
}) })
]) ])
}, },
selectCard(item) { selectCard(item) {
this.card = item; this.card = item;

View File

@ -26,9 +26,9 @@
<span>付款时间</span> <span>付款时间</span>
<p>{{ $formatGMT(data.paytime, 'yyyy-MM-dd HH:mm:ss') }}</p> <p>{{ $formatGMT(data.paytime, 'yyyy-MM-dd HH:mm:ss') }}</p>
</div> </div>
<div class="detail" v-if="data.payway"> <div class="detail" v-if="data.paychannelname">
<span>支付方式</span> <span>支付方式</span>
<p>{{ data.payway }}</p> <p>{{ data.paychannelname }}</p>
</div> </div>
<div class="detail"> <div class="detail">
<span>交易单号</span> <span>交易单号</span>
@ -53,13 +53,13 @@
<span>用户实付金额</span> <span>用户实付金额</span>
<p>¥{{ data.paymoney?.toFixed(2) }}</p> <p>¥{{ data.paymoney?.toFixed(2) }}</p>
</div> </div>
<hr>
<div class="detail" v-if="data.discountratio"> <div class="detail" v-if="data.discountratio">
<span>商家惠利比例</span> <span>商家惠利比例</span>
<p>{{ data.discountratio }}%</p> <p>{{ data.discountratio }}%</p>
</div> </div>
<hr>
<div class="detail"> <div class="detail">
<span>商家惠利金额</span> <span>商家惠利金额</span>
<p>-¥{{ data.discount }}</p> <p>-¥{{ data.discount }}</p>

View File

@ -24,9 +24,7 @@
</div> </div>
</div> </div>
<div class="save-btn"> <div class="save-btn">
<van-button type="primary" color="#ca2904" round block :loading="loading" @click="handleSave">{{ loading ? <van-button type="primary" color="#ca2904" round block :loading="loading"> 长按图片保存 </van-button>
'生成中...' : ('保存图片')
}}</van-button>
</div> </div>
</div> </div>
</BasePage> </BasePage>
@ -69,47 +67,40 @@ export default {
this.bgLoaded = true this.bgLoaded = true
}, },
async generateImage() { async generateImage() {
if (this.loading) return if (this.loading) return
this.loading = true this.loading = true
try { try {
await this.$nextTick() 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 const el = this.$refs.paycodeOriginalRef
if (!el) { if (!el) throw new Error('Element not found')
throw new Error('Element not found')
} // <img>vue - qr img
this.generatedImage = await toDataURL(el, { format: 'png', pixelRatio: 3, useCORS: true }) 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) { } catch (e) {
console.error('生成收款码失败:', e) console.error('生成收款码失败:', e)
this.$showFailToast('生成失败') this.$showFailToast('生成失败')
} finally { } finally {
this.loading = false 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
}
},
}, },
} }
</script> </script>

View File

@ -75,19 +75,19 @@
<div class="datecount"> <div class="datecount">
<div class="dc-item"> <div class="dc-item">
<span>{{ active == 0 ? '今日' : '本月' }}营业额</span> <span>{{ active == 0 ? '当日' : '当月' }}营业额</span>
<b>{{ chartData.yingyee?.toFixed(2) }}</b> <b>{{ chartData.yingyee?.toFixed(2) }}</b>
</div> </div>
<div class="dc-item"> <div class="dc-item">
<span>{{ active == 0 ? '今日' : '本月' }}抵扣积分</span> <span>{{ active == 0 ? '当日' : '当月' }}应收</span>
<b>{{ chartData.yingshou?.toFixed(2) }}</b> <b>{{ chartData.yingshou?.toFixed(2) }}</b>
</div> </div>
<div class="dc-item"> <div class="dc-item">
<span>{{ active == 0 ? '今日' : '本月' }}订单数</span> <span>{{ active == 0 ? '当日' : '当月' }}订单数</span>
<b>{{ chartData.dingdanshu }}</b> <b>{{ chartData.dingdanshu }}</b>
</div> </div>
<div class="dc-item"> <div class="dc-item">
<span>{{ active == 0 ? '今日' : '本月' }}收入</span> <span>{{ active == 0 ? '当日' : '当月' }}惠利金额</span>
<b>{{ chartData.youhui?.toFixed(2) }}</b> <b>{{ chartData.youhui?.toFixed(2) }}</b>
</div> </div>
</div> </div>
@ -173,10 +173,24 @@ export default {
this.chart = window.echarts.init(this.$refs.chartRef); this.chart = window.echarts.init(this.$refs.chartRef);
} }
const dates = this.chartData.orderchart.map(item => item.adddate?.slice(5)); 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({ this.chart.setOption({
tooltip: { 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}<br/>${params.seriesName}${Number(params.value || 0).toFixed(2)}`;
}
}, },
grid: { grid: {
left: '12%', left: '12%',
@ -200,9 +214,12 @@ export default {
} }
}, },
series: [{ series: [{
name: '营业额',
data: values, data: values,
type: 'line', type: 'line',
smooth: true, smooth: true,
showSymbol: true,
symbolSize: 6,
lineStyle: { color: '#e4bb4e', width: 2 }, lineStyle: { color: '#e4bb4e', width: 2 },
itemStyle: { color: '#e4bb4e' }, itemStyle: { color: '#e4bb4e' },
areaStyle: { 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() { getCount() {
this.$get('/v1/client/DShopsClient/statistics').then(res => { this.$get('/v1/client/DShopsClient/statistics').then(res => {

View File

@ -38,7 +38,8 @@
</van-cell> </van-cell>
<!-- 微信支付 --> <!-- 微信支付 -->
<van-cell title="微信支付" is-link @click="payMethod = ['wechat']" v-if="orderInfo.mallstate !== 5"> <van-cell title="微信支付" is-link @click="payMethod = ['wechat']"
v-if="orderInfo.mallstate !== 5 && $isWechat()">
<template #icon> <template #icon>
<img class="pay-icon" src="/img/pay_weixin.png" /> <img class="pay-icon" src="/img/pay_weixin.png" />
</template> </template>
@ -232,6 +233,17 @@ export default {
} }
.pay { .pay {
&::before {
content: '';
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
background: #fff;
z-index: -1;
}
text-align: center; text-align: center;
padding-top: 16.667vw; padding-top: 16.667vw;

View File

@ -7,7 +7,7 @@
<b style="#d2220d">{{ data.statename }}</b> <b style="#d2220d">{{ data.statename }}</b>
</div> </div>
<div class="_address"> <div class="_address" v-if="data.mallstate !== 4">
<div class="icon"> <div class="icon">
<img src="/img/address.png"> <img src="/img/address.png">
</div> </div>
@ -22,7 +22,15 @@
</div> </div>
</div> </div>
<div class="_goods"> <div class="_goods" v-if="data.mallstate === 4">
<img :src="$file(data.shopimg)">
<div class="c">
<div class="name">
<span>{{ data.shopname }}</span>
</div>
</div>
</div>
<div class="_goods" v-else>
<img :src="$file(data.proimg)"> <img :src="$file(data.proimg)">
<div class="c"> <div class="c">
<div class="name"> <div class="name">
@ -146,6 +154,10 @@
发货时间 发货时间
<span>{{ $formatGMT(data.exporttime, 'yyyy-MM-dd HH:mm:ss') }}</span> <span>{{ $formatGMT(data.exporttime, 'yyyy-MM-dd HH:mm:ss') }}</span>
</p> </p>
<p v-if="data.mallstate === 4">
完成时间
<span>{{ $formatGMT(data.paytime, 'yyyy-MM-dd HH:mm:ss') }}</span>
</p>
<p v-if="data.receipttime"> <p v-if="data.receipttime">
完成时间 完成时间
<span>{{ $formatGMT(data.receipttime, 'yyyy-MM-dd HH:mm:ss') }}</span> <span>{{ $formatGMT(data.receipttime, 'yyyy-MM-dd HH:mm:ss') }}</span>

View File

@ -37,8 +37,9 @@
<span>{{ item.proskuname }}</span> <span>{{ item.proskuname }}</span>
<p>x{{ item.buynums }}</p> <p>x{{ item.buynums }}</p>
</div> </div>
<div class="concession"> <div class="concession" v-if="item.mallstate !== 4">
<span v-if="item.mallstate !== 5">¥{{ item.proskusaleprice?.toFixed(2) }}</span> <span v-if="item.mallstate !== 5">¥{{ item.proskusaleprice?.toFixed(2)
}}</span>
<span v-else>{{ item.proskusaleprice?.toFixed(2) }}积分</span> <span v-else>{{ item.proskusaleprice?.toFixed(2) }}积分</span>
<p v-if="item.discountratio && item.mallstate !== 5">惠利{{ item.discountratio }}%</p> <p v-if="item.discountratio && item.mallstate !== 5">惠利{{ item.discountratio }}%</p>
</div> </div>
@ -54,9 +55,10 @@
<b :class="'b' + item.state">{{ item.statename }}</b> <b :class="'b' + item.state">{{ item.statename }}</b>
<div class="btn_box"> <div class="btn_box">
<button v-if="item.state === 0" @click="cancelTrade(item)">取消订单</button> <button v-if="item.state === 0" @click="cancelTrade(item)">取消订单</button>
<button v-if="!item.shopname" @click="$navigate(`TradeDetail?ordernum=${item.ordernum}`)">查看详情</button> <button @click="$navigate(`TradeDetail?ordernum=${item.ordernum}`)">查看详情</button>
<button v-else @click="$navigate(`MerchantTradeDetail?id=${item.ordernum}`)">查看详情</button> <!-- <button v-else @click="$navigate(`MerchantTradeDetail?id=${item.ordernum}`)">查看详情</button> -->
<button v-if="item.state === 3 || item.state === 4" @click="showLogistics(item)">物流信息</button> <button v-if="item.state === 3 || item.state === 4 && item.mallstate !== 4"
@click="showLogistics(item)">物流信息</button>
<button v-if="item.state === 3" @click="confirmReceipt(item)">确认收货</button> <button v-if="item.state === 3" @click="confirmReceipt(item)">确认收货</button>
<!-- <button v-if="item.state === 3" @click="refundTrade(item)">退款</button> --> <!-- <button v-if="item.state === 3" @click="refundTrade(item)">退款</button> -->

View File

@ -88,7 +88,8 @@ export default {
"shopuserid": '' "shopuserid": ''
}, },
jifenDeduction: 0, jifenDeduction: 0,
quanDeduction: 0 quanDeduction: 0,
lastChecked: ''
} }
}, },
computed: { computed: {
@ -119,16 +120,21 @@ export default {
}) })
}, },
toggleDeduction(type) { toggleDeduction(type) {
if (type === 'jifen') { const target = type === 'jifen' ? '1' : '2';
if (!this.data.user.xiaofeijifen || this.data.user.xiaofeijifen <= 0) return; if (type === 'jifen' && (!this.data.user.xiaofeijifen || this.data.user.xiaofeijifen <= 0)) return;
this.checked = '1' if (type === 'quan' && (!this.data.user.xiaofeiquan || this.data.user.xiaofeiquan <= 0)) return;
this.req.isjifen = this.checked === '1';
this.req.ishuiyuanka = false; if (this.lastChecked === target) {
} else if (type === 'quan') { //
if (!this.data.user.xiaofeiquan || this.data.user.xiaofeiquan <= 0) return; this.checked = '';
this.checked = '2';
this.req.ishuiyuanka = this.checked === '2';
this.req.isjifen = false; 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() { calcDeduction() {

View File

@ -222,14 +222,11 @@ export default {
components: { ManagerPopup }, components: { ManagerPopup },
computed: { computed: {
}, },
beforeRouteEnter(to, from, next) {
if (!localStorage.getItem('member_token')) {
next({ name: 'Login', query: { redirect: to.fullPath } });
} else {
next();
}
},
mounted() { mounted() {
if (!localStorage.getItem('member_token')) {
this.$router.replace({ name: 'Login', query: { redirect: this.$route.fullPath } });
return;
}
this.init(); this.init();
this.$get('/v1/client/HWxinfoClient/qrcode').then(res => { this.$get('/v1/client/HWxinfoClient/qrcode').then(res => {
this.FollowQRCode = res.data; this.FollowQRCode = res.data;

View File

@ -150,9 +150,9 @@ export default {
}, },
}); });
}); });
}
} else { } else {
window.open(`https://uri.amap.com/navigation?to=${lon},${lat},${fullAddress}&mode=car&src=shop`, '_blank'); window.location.href = `https://uri.amap.com/navigation?to=${lon},${lat},${encodeURIComponent(fullAddress)}&mode=car&src=shop`;
}
} }
}, },
} }

View File

@ -180,7 +180,7 @@
{{ data.total.totalsum?.toFixed(2) }} {{ data.total.totalsum?.toFixed(2) }}
</b> </b>
<button class="r" @click="$navigate('Cashout')"> <button class="r" @click="toCashout">
提现 提现
</button> </button>
</div> </div>
@ -317,6 +317,7 @@ export default {
loading: false, loading: false,
showTerm: false, showTerm: false,
list: [], list: [],
isVIP: ''
} }
}, },
methods: { methods: {
@ -326,11 +327,23 @@ export default {
}).catch(err => { }).catch(err => {
this.$showFailToast(err.message || '加载失败'); this.$showFailToast(err.message || '加载失败');
}) })
this.$get('/v1/client/DUsersClient').then(data => {
this.$get('/v1/client/DUsermoneysClient/select').then(res => { this.isVIP = data.data.userlevelname;
// console.log(res.data);
}) })
// 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) { onconfirm(value) {
this.date = this.currentDate; this.date = this.currentDate;