1.15提交

This commit is contained in:
zoujiandong 2026-01-15 18:38:21 +08:00
parent 00d0ec8a9b
commit cf6df28e8c
16 changed files with 683 additions and 180 deletions

View File

@ -23,7 +23,9 @@ const goods_api = {
createGoodsOrder(data) {
return request('/expertAPI/createGoodsOrder', data, 'post', true);
},
payGoodsOrder(data) {
return request('/expertAPI/payGoodsOrder', data, 'post', true);
},
getGoodsOrderList(data) {
return request('/expertAPI/goodsOrderList', data, 'post', true);
}

View File

@ -1541,7 +1541,7 @@
"list": [
{
"name": "",
"path": "pages/index/index",
"path": "pages_app/myWelfare/myWelfare",
"query": ""
}
]

View File

@ -256,6 +256,7 @@ const submit = () => {
.left{
text-align: left;
max-width: 125rpx;
width:auto!important;
}
.price{
color: #FF4D4F;

View File

@ -1,10 +1,11 @@
<template>
<view class="my-code-page">
<webview src="https://dev-wx.igandan.com/expert/expertcodeimg?expert_uuid=9UFkll2Xo57km6224XE&fromtype=doctor"></webview>
<!-- 顶部导航栏 -->
<navBar title="我的二维码" />
<!-- 内容 -->
<scroll-view scroll-y class="page-scroll">
<scroll-view scroll-y class="page-scroll" id="pageContent">
<!-- 顶部蓝色横幅 -->
<view class="blue-banner">
<up-image :src="bgImg" width="100%" mode="widthFix" ></up-image>
@ -59,7 +60,7 @@
<!-- 底部保存按钮 -->
<view class="save-bar">
<button class="save-btn" @click="onSave">保存二维码到手机</button>
<button class="save-btn" @click="onSave">保存到手机相册</button>
</view>
</view>
</template>
@ -78,72 +79,196 @@ const goBack = () => {
onShow(()=>{
userInfo.value = uni.getStorageSync('userInfo')
})
//
const handleSaveError = (err) => {
if (err.errMsg && (err.errMsg.includes('auth deny') || err.errMsg.includes('authorize'))) {
uni.showModal({
title: '权限提示',
content: '需要相册权限才能保存图片,请在设置中开启权限',
showCancel: false,
confirmText: '知道了'
});
} else {
uni.showToast({
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
}
};
const onSave = () => {
//
if (!userInfo.value.qrcode) {
uni.showToast({ title: '二维码不存在', icon: 'none' });
// #ifdef APP-PLUS
// App
if (typeof plus === 'undefined') {
uni.showToast({ title: '当前环境不支持此功能', icon: 'none' });
return;
}
//
uni.showLoading({ title: '保存中...' });
//
uni.downloadFile({
url: docUrl + userInfo.value.qrcode,
success: (res) => {
if (res.statusCode === 200) {
//
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
//
let timeoutTimer = setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: '操作超时,请重试',
icon: 'none',
duration: 2000
});
}, 15000); // 15
// webview
const currentWebview = plus.webview.currentWebview();
// 使 draw
currentWebview.draw({
bitmap: true,
success: (bitmap) => {
clearTimeout(timeoutTimer);
try {
// bitmap base64
const base64 = bitmap.toBase64DataURL('image/png', 1.0);
// base64
const base64Data = base64.indexOf(',') > -1 ? base64.split(',')[1] : base64;
//
const fileName = 'mycode_' + Date.now() + '.png';
const tempPath = `_doc/${fileName}`;
// 使 plus.io
plus.io.resolveLocalFileSystemURL('_doc', (entry) => {
entry.getFile(fileName, { create: true, exclusive: false }, (fileEntry) => {
fileEntry.createWriter((writer) => {
// base64 ArrayBuffer
const binaryString = atob(base64Data);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
writer.onwriteend = () => {
// bitmap
bitmap.recycle();
//
const localPath = plus.io.convertLocalFileSystemURL(fileEntry.fullPath);
//
uni.saveImageToPhotosAlbum({
filePath: localPath,
success: () => {
uni.hideLoading();
uni.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
});
},
fail: (err) => {
uni.hideLoading();
console.error('保存到相册失败:', err);
handleSaveError(err);
}
});
};
writer.onerror = (err) => {
uni.hideLoading();
console.error('写入文件失败:', err);
bitmap.recycle();
uni.showToast({
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
};
// Blob
try {
const blob = new Blob([bytes], { type: 'image/png' });
writer.write(blob);
} catch (e) {
// Blob ArrayBuffer
try {
writer.write(bytes.buffer);
} catch (e2) {
uni.hideLoading();
console.error('写入失败:', e2);
bitmap.recycle();
uni.showToast({
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
}
}
}, (err) => {
clearTimeout(timeoutTimer);
uni.hideLoading();
console.error('创建写入器失败:', err);
bitmap.recycle();
uni.showToast({
title: '保存成功',
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
},
fail: (err) => {
uni.hideLoading();
console.error('保存失败:', err);
//
if (err.errMsg.includes('auth deny') || err.errMsg.includes('authorize')) {
uni.showModal({
title: '权限提示',
content: '需要相册权限才能保存图片,请在设置中开启权限',
showCancel: false,
confirmText: '知道了'
});
} else {
uni.showToast({
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
}
}
});
}, (err) => {
clearTimeout(timeoutTimer);
uni.hideLoading();
console.error('获取文件失败:', err);
bitmap.recycle();
uni.showToast({
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
});
} else {
}, (err) => {
clearTimeout(timeoutTimer);
uni.hideLoading();
console.error('解析文件系统失败:', err);
bitmap.recycle();
uni.showToast({
title: '下载失败,请检查网络',
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
});
} catch (error) {
clearTimeout(timeoutTimer);
uni.hideLoading();
console.error('处理失败:', error);
if (bitmap && bitmap.recycle) {
bitmap.recycle();
}
uni.showToast({
title: '保存失败,请重试',
icon: 'none',
duration: 2000
});
}
},
fail: (err) => {
clearTimeout(timeoutTimer);
uni.hideLoading();
console.error('下载失败:', err);
console.error('截图失败:', err);
uni.showToast({
title: '下载失败,请检查网络',
title: '截图失败,请重试',
icon: 'none',
duration: 2000
});
}
});
// #endif
// #ifndef APP-PLUS
uni.showToast({ title: '此功能仅支持 App 端', icon: 'none' });
// #endif
};
</script>
@ -252,7 +377,7 @@ const onSave = () => {
.qr-card {
position: relative;
margin: -120rpx 30rpx 30rpx;
margin: 76rpx 30rpx 30rpx;
background: #ffffff;
border-radius: 20rpx;
padding: 140rpx 30rpx 30rpx;

View File

@ -164,13 +164,39 @@
</view>
</view>
</view>
<view class="signfix" @click="onSignClick">
<up-image :src="isSign ? signTrueImg : signFalseImg" width="154rpx" height="80rpx" ></up-image>
</view>
<unidialog :visible="hasSign" content="今日已签到,每天只能签到一次。<br>请明日继续哦~" @close="hasSign=false" :showCancel="true" cancelText="关闭"></unidialog>
<up-overlay :show="showSign" >
<view class="signwrap">
<view class="signbox">
<view class="close" @click="showSign=false"></view>
<view class="signbg">
<up-image :src="signImg" width="604rpx" height="964rpx" ></up-image>
</view>
<view class="signcontent">
<view class="day">今天是我们相识的第{{signInfo.gdxzday}}</view>
<view class="signtotal">本周共签到{{signInfo.totalDay}}</view>
<view class="signcontinue">已经连续签到{{signInfo.continuous_day}}</view>
<view class="tip">连续签到获取更多积分</view>
<view class="news" @click.stop="goNews">
{{signInfo.news.summary}}
</view>
</view>
</view>
</view>
</up-overlay>
</template>
<script setup>
import { ref, onMounted } from "vue";
import api from "@/api/api.js";
import docUrl from '@/utils/docUrl.js';
import {onBackPress} from '@dcloudio/uni-app';
import { reactive,ref,onMounted } from "vue";
import unidialog from '@/components/dialog/dialog.vue'
onBackPress(() => {
plus.runtime.quit();
return true;
@ -182,7 +208,9 @@ import myjifen_big from "@/static/myjifen_big.png"
import pointImg from "@/static/integralticket.png"
import buyPointImg from "@/static/buy_points.png"
import pointMallImg from "@/static/point_shop.png"
import signTrueImg from "@/static/signin_true.png"
import signFalseImg from "@/static/signin_false.png"
import dayjs from "dayjs"
//
const activeTab = ref("income");
const totalPoints = ref(0); // 0
@ -191,7 +219,14 @@ const checkinCount = ref(0); // 总签到次数
const meetingDays = ref(0); //
const loading = ref(false);
const error = ref(null);
const isSign = ref(false);
const hasSign = ref(false)
const showSign = ref(false)
const signInfo=reactive({
news:{
summary:''
}
})
// -
const incomeCurrentPage = ref(1);
const incomePageSize = ref(10);
@ -229,7 +264,7 @@ const goBack = () => {
const showRules = () => {
navTo({
url: '/pages_app/webview/webview?url='+encodeURIComponent(docUrl+'integral/integral_doctor.html')+'&title=积分规则'
url: '/pages_app/webview/webview?url='+encodeURIComponent('https://doc.igandan.com/app/integral/integral_doctor.html')+'&title=积分规则'
})
};
@ -273,6 +308,15 @@ const performCheckin = () => {
loading.value = false;
}, 1000);
};
const goNews=()=>{
let url=docUrl+signInfo.news.path;
const encoded = encodeURIComponent(url);
navTo({
url: `/pages_app/webview/webview?url=${encoded}`
});
}
//
const goToPointsCoupon = () => {
@ -290,6 +334,40 @@ const goToBuyPoints = () => {
url: "/pages_app/buyPoint/buyPoint",
});
};
const onSignClick = async () => {
if(isSign.value){
hasSign.value = true;
return;
}
try {
//
const res = await api.addBonusPointsN({
score_type:1
});
if (res && res.code ==1) {
//
isSign.value = true;
uni.showToast({
title: '签到成功,获得'+res.bonuspoints+'积分',
icon: 'none'
});
Object.assign(signInfo,res);
} else {
uni.showToast({
title: res?.msg || '签到失败',
icon: 'none'
});
}
} catch (error) {
console.error('签到失败:', error);
uni.showToast({
title: '签到失败,请重试',
icon: 'none'
});
}
};
const goToPointsMall = () => {
uni.navigateTo({
@ -399,7 +477,7 @@ const updateWeekDaysStatus = (checkedDates) => {
const now = new Date();
const currentDay = now.getDay(); // (0-6)
const currentDate = now.getDate(); //
//
const startOfWeek = new Date(now);
startOfWeek.setDate(currentDate - currentDay);
@ -419,9 +497,12 @@ const updateWeekDaysStatus = (checkedDates) => {
if (checkedDates && checkedDates.length > 0) {
checkedDates.forEach((dateStr) => {
//
const targetDate = new Date(dateStr);
const targetDateStr = targetDate.toISOString().split("T")[0];
if(dateStr == new Date().toISOString().split("T")[0]){
isSign.value = true;
}
// weekDays
const dayIndex = weekDays.value.findIndex(
(day) => day.date === targetDateStr
@ -455,7 +536,7 @@ const getBonusPointsList = async (page = 1, isLoadMore = false) => {
// transactionList
const formattedList = listData.map((item) => ({
type: item.score_type_name,
time: item.create_date,
time: dayjs(item.create_date).format('YYYY-MM-DD HH:mm'),
amount: item.score,
}));
@ -518,7 +599,7 @@ const getBonusPointsPayList = async (page = 1, isLoadMore = false) => {
// transactionList
const formattedList = listData.map((item) => ({
type: item.score_type_name,
time: item.create_date,
time: dayjs(item.create_date).format('YYYY-MM-DD HH:mm'),
amount: item.score, //
}));
@ -589,7 +670,7 @@ onMounted(() => {
});
</script>
<style scoped>
<style scoped lang="scss">
.my-point-page {
background-color: #f5f5f5;
@ -598,7 +679,12 @@ onMounted(() => {
/* 为底部导航留出空间 */
padding-bottom: 160rpx;
}
.signfix{
position: fixed;
bottom: 300rpx;
right: 0;
z-index: 10;
}
/* 每日签到进度条 */
.checkin-progress {
position: relative;
@ -695,7 +781,7 @@ onMounted(() => {
.day-text {
margin-bottom: 20rpx;
font-size: 24rpx;
font-size: 28rpx;
color: #fff;
}
@ -958,7 +1044,7 @@ onMounted(() => {
}
.amount-text.positive {
color: #27ae60;
color: #e74c3c;
}
.amount-text.negative {
@ -1104,7 +1190,7 @@ onMounted(() => {
right: 0;
background-color: #3cc7c0;
display: flex;
padding: 40rpx 0;
padding: 32rpx 0;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
z-index: 99;
}
@ -1157,4 +1243,132 @@ onMounted(() => {
bottom: 180rpx; /* 响应式下调整位置 */
}
}
.honorwrap{
width:100%;
height:100vh;
display: flex;
align-items: center;
justify-content: center;
.honorbox{
width:80%;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
min-height:200rpx;
background:linear-gradient(to bottom, #54049b, #da4ee2);
border-radius: 20rpx;
padding: 20rpx;
.row{
display: grid;
grid-template-columns: repeat(2, 1fr); /* 创建两列,每列等宽 */
gap: 20px;
.row_item{
font-size: 26rpx;
color: #da4ee2;
margin-right: 20rpx;
text-align: center;
padding: 10rpx 20rpx;
background:#fff;
white-space: nowrap;
border-radius: 10rpx;
border:1rpx solid #da4ee2;
}
}
.close_honor{
position: absolute;
top:20rpx;
right:20rpx;
}
.honor_image{
width:269rpx;
height:213rpx;
position: absolute;
top:-76rpx;
left:50%;
transform: translateX(-50%);
}
.content{
margin-top:73rpx;
background:#fff;
border-radius: 5rpx;
padding: 20rpx;
.content_title{
font-weight: bold;
padding: 35rpx 0 20rpx;
text-align: center;
font-size: 36rpx;
color: #da4ee2;
}
.content_content{
font-size: 26rpx;
color: #333;
margin-top: 20rpx;
line-height: 1.5;
}
}
}
}
.signwrap{
display: flex;
align-items: center;
justify-content: center;
height:100%;
.signbox{
display: flex;
flex-direction: column;
align-items: center;
position: relative;
z-index:0;
.close{
position:absolute;
right:0;
height:60rpx;
width:60rpx;
opacity: 0;
background:#fff;
z-index:2;
border-radius: 50%;
}
}
}
.signwrap .signcontent{
width:100%;
top:0;
position: absolute;
z-index:1;
}
.signwrap .signcontent .day{
margin-top: 384rpx;
text-align: center;
}
.signwrap .signtotal{
margin-top: 30rpx;
text-align: center;
font-size: 30rpx;
}
.signwrap .signcontinue{
font-size: 30rpx;
text-align: center;
}
.signwrap .signcontent .tip{
margin-top: 40rpx;
color:red;
font-size: 28rpx;
text-align: center;
}
.signwrap .signcontent .news{
margin: 196rpx 60rpx 0;
height: 116rpx;
font-size: 30rpx;
}
.signwrap .signbg{
width:604rpx;
height:964rpx;
}
</style>

View File

@ -211,11 +211,13 @@
}
}
const switchTab = (index) => {
activeTab.value = index;
if (index === 0) {
activeTab.value = index;
getWelfarePage();
} else if (index === 1) {
activeTab.value = index;
useWelfarePage();
} else if (index === 2) {
navTo({
@ -250,11 +252,29 @@
url: '/pages_app/zhinan/zhinan'
});
}else if(benefit.name == 'daicha'){
if(benefit.num == 0){
showDialog.value = true;
}else{
}
// if(benefit.num == 0){
// showDialog.value = true;
// }else{
plus.share.getServices(res => {
const wechat = res.find(i => i.id === 'weixin')
if (wechat) {
wechat.openCustomerServiceChat({
corpid: 'wwc72af5440141e84e',//
url: 'https://work.weixin.qq.com/kfid/kfceb116f7032dbbb91',
}, src => {
console.log("success:")
}, err => {
console.log("error:")
})
} else {
uni.showToast({
title: '当前环境不支持',
icon: "error"
});
}
});
//}
}
}
};
@ -267,7 +287,7 @@
const gofuliDetail = () => {
navTo({
url: '/pages_app/myPoint/myPoint'
url: '/pages_app/myWelfare/welfareDetail'
})
};
@ -277,15 +297,34 @@
})
};
const goRules = () => {
navTo({
url: '/pages_app/webview/webview?url='+encodeURIComponent(docUrl+'integral/integral_welfare.html')+'&title=福利规则'
url: '/pages_app/webview/webview?url='+encodeURIComponent('https://doc.igandan.com/app/integral/integral_welfare.html')+'&title=福利规则'
})
};
const useWelfarePage = () => {
api.useWelfarePage().then(res => {
if (res.code === '200' && res.data) {
//
benefitsList.value = res.data;
res.data.forEach(item => {
item.name = item.name.replace(' ', '');
});
// U
const sortOrder = ['jifen', 'video', 'kejian', 'daicha', 'upan'];
//
benefitsList.value = res.data.sort((a, b) => {
const indexA = sortOrder.indexOf(a.name);
const indexB = sortOrder.indexOf(b.name);
//
if (indexA === -1 && indexB === -1) return 0;
if (indexA === -1) return 1;
if (indexB === -1) return -1;
return indexA - indexB;
});
}
});
};
@ -470,21 +509,27 @@
border:2rpx solid #fff;
&.jifen{
border:2rpx solid #ffad17;
background:#feeae9;
}
&.wenxian{
border:2rpx solid #33c966;
background:#fdeafe;
}
&.video{
border:2rpx solid #ff951d;
background:#fefbea;
}
&.kejian{
border:2rpx solid #f17dff;
background:#fdeafe;
}
&.upan{
border:2rpx solid #40cdc5;
background:#eafffa;
}
&.wanfang{
border:2rpx solid #4aa2fe;
background:#fff;
}
.disabled-text {
color: $text-light !important;

View File

@ -591,8 +591,13 @@
}
.filter-item{
display:flex;
align-items: center;
.filterbox{
margin-top: 5rpx;
margin-top: 0rpx;
}
.newbox{
margin-top: -11rpx;
}
.filter-text{
color:#666;

View File

@ -16,13 +16,13 @@
</view>
<view class="divider-line"></view>
<view class="form-item">
<view class="form-item" v-if="type==2">
<view class="label">邮箱</view>
<input class="input" v-model="email" type="text" placeholder="用于接收电子卡等信息(可选)" />
</view>
<view class="divider-line"></view>
<view class="form-item select-item" @click="openAreaPicker">
<view class="form-item select-item" @click="openAreaPicker" v-if="type==1">
<view class="label">地址</view>
<view class="input placeholder" v-if="!regionText">请选择地址</view>
<view class="input" v-else>{{ regionText }}</view>
@ -30,14 +30,15 @@
</view>
<view class="divider-line"></view>
<view class="form-item">
<view class="form-item" v-if="type==1">
<view class="label">详细地址</view>
<input class="input" v-model="detail" placeholder="请输入街道、门牌等详细地址信息" />
</view>
<view class="divider-line"></view>
</scroll-view>
<view class="footer-bar" @click="submit">
<view class="confirm-btn" >确定</view>
<view class="confirm-btn" >确定兑换</view>
</view>
<!-- 省市区选择器 -->
@ -62,20 +63,80 @@
<view v-else class="picker-empty">地区数据加载中...</view>
</view>
</view>
<unidialog
:title="'确认收货信息'"
:visible="freeVisible"
:content="freeContent"
@close="freeClose"
@confirm="freeConfirm"
>
<template #content>
<view>
<view class="row">
<view class="left">收件人:</view>
<view class="right">{{ receiver }}</view>
</view>
<view class="row">
<view class="left">手机号:</view>
<view class="right">{{ mobile }}</view>
</view>
<view class="row" >
<view class="left">地址:</view>
<view class="right">{{ regionText+detail }}</view>
</view>
<view class="row">
<view class="left">兑换积分:</view>
<view class="right"><text class="price">{{ points }}积分</text>(包邮)</view>
</view>
<view class="row">请确认此次兑换物品不退不换</view>
</view>
</template>
</unidialog>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import areaList from '@/utils/areaList.js'
import api from '@/api/api.js'
import navTo from '@/utils/navTo';
import goods_api from '@/api/goods_api';
import unidialog from '@/components/dialog/dialog.vue';
const freeVisible = ref(false)
const freeContent = ref('')
const goods_order_id = ref('')
const points = ref(0)
const freeClose = () => {
freeVisible.value = false
}
const freeConfirm = () => {
freeVisible.value = false;
goods_api.payGoodsOrder({
goods_order_uuid: goods_order_id.value,
}).then(res => {
if(res.code == 1 || res.code == 200){
uni.showToast({
title: '兑换成功',
icon: 'none',
duration: 2000
});
setTimeout(() => {
uni.navigateBack({
delta: 2
})
}, 2000)
}
})
}
const receiver = ref('')
const mobile = ref('')
const regionText = ref('')
const detail = ref('')
const email = ref('')
const editingId = ref(null)
const goodsUuid = ref('')
const type = ref(1)
const goodsNum = ref(1)
const goBack = () => uni.navigateBack()
// [{code,label,value,children:[...] }...]
@ -142,69 +203,42 @@ const confirmArea = () => {
}
onLoad((opts) => {
if (opts && opts.id) {
//
editingId.value = Number(opts.id)
try {
const list = uni.getStorageSync('goods_addresses') || []
const target = Array.isArray(list) ? list.find(a => a.id === editingId.value) : null
if (target) {
receiver.value = target.receiver || ''
mobile.value = target.mobile || ''
regionText.value = target.region || ''
detail.value = target.detail || ''
email.value = target.email || ''
}
} catch (e) {}
}
console.log(22);
console.log(opts);
goodsUuid.value = opts.goodsUuid
goodsNum.value = opts.goodsNum;
type.value = opts.type;
})
const submit = () => {
if (!receiver.value) return uni.showToast({ title: '请输入收件人', icon: 'none' })
if (!/^1\d{10}$/.test(mobile.value)) return uni.showToast({ title: '请输入正确手机号', icon: 'none' })
if (!regionText.value) return uni.showToast({ title: '请选择地址', icon: 'none' })
if (!detail.value) return uni.showToast({ title: '请输入详细地址', icon: 'none' })
if (email.value && !/^([a-zA-Z0-9_\.-]+)@([a-zA-Z0-9\.-]+)\.([a-zA-Z]{2,})$/.test(email.value)) return uni.showToast({ title: '邮箱格式不正确', icon: 'none' })
const STORAGE_KEY = 'goods_addresses'
let list = []
try {
const cached = uni.getStorageSync(STORAGE_KEY)
list = Array.isArray(cached) ? cached : []
} catch (e) { list = [] }
if (editingId.value) {
//
list = list.map(a => a.id === editingId.value ? {
...a,
receiver: receiver.value,
mobile: mobile.value,
region: regionText.value,
detail: detail.value,
fullAddress: `${regionText.value} ${detail.value}`,
email: email.value
} : a)
} else {
//
const address = {
id: Date.now(),
receiver: receiver.value,
mobile: mobile.value,
region: regionText.value,
detail: detail.value,
fullAddress: `${regionText.value} ${detail.value}`,
email: email.value,
createdAt: Date.now()
}
list.unshift(address)
if(type.value == 1){
if (!regionText.value) return uni.showToast({ title: '请选择地址', icon: 'none' })
if (!detail.value) return uni.showToast({ title: '请输入详细地址', icon: 'none' })
}else{
if (email.value && !/^([a-zA-Z0-9_\.-]+)@([a-zA-Z0-9\.-]+)\.([a-zA-Z]{2,})$/.test(email.value)) return uni.showToast({ title: '邮箱格式不正确', icon: 'none' })
}
uni.setStorageSync(STORAGE_KEY, list)
uni.showToast({ title: '提交成功', icon: 'none' })
setTimeout(() => { uni.navigateBack() }, 500)
goods_api.createGoodsOrder({
goodsUuid: goodsUuid.value,
goodsNum: goodsNum.value,
user_name: receiver.value,
mobile: mobile.value,
email:email.value,
address: regionText.value+detail.value
}).then(res => {
if(res.code == 1 || res.code == 200){
points.value = res.data.pionts*res.data.goods_num;
freeVisible.value = true
goods_order_id.value = res.data.goods_order_id
}
})
}
</script>
<style scoped>
<style scoped lang="scss">
.address-page { min-height: 100vh; background: #fff; }
.content { position: absolute; top: calc(var(--status-bar-height) + 44px); bottom: 120rpx; left: 0; right: 0; background: #fff; }
.form-item { display: flex; align-items: center; padding: 24rpx; }
@ -227,5 +261,25 @@ const submit = () => {
.picker-view { height: 480rpx; }
.picker-item { height: 80rpx; line-height: 80rpx; text-align: center; color: #333; }
.picker-empty { padding: 40rpx; text-align: center; color: #999; }
.row{
display: flex;
align-items: center;
font-size: 28rpx;
padding: 12rpx 0;
max-width: 800rpx;
margin-left: -100rpx;
.left{
text-align: left;
max-width: 125rpx;
width:auto!important;
}
.price{
color: #FF4D4F;
}
}
.left{
width: 160rpx;
}
</style>

View File

@ -5,7 +5,7 @@
<scroll-view scroll-y class="content">
<!-- 收货地址 -->
<view class="addr-card" @click="changeAddress">
<!-- <view class="addr-card" @click="changeAddress">
<view class="addr-header">
<text class="addr-title">收货信息</text>
<text class="addr-change">{{ selectedAddress ? '更换' : '添加' }}</text>
@ -15,7 +15,7 @@
<text class="addr-row small">{{ selectedAddress.fullAddress || (selectedAddress.region + ' ' + selectedAddress.detail) }}</text>
</view>
<view v-else class="addr-empty">请添加收货地址</view>
</view>
</view> -->
<view class="goods-title">{{ title }}</view>
<view class="price">{{ price }}积分</view>
@ -37,16 +37,38 @@
</view>
</scroll-view>
<view class="footer-bar">
<view class="confirm-btn" @click="goAddress">我要兑换</view>
<view class="footer-bar" @click="goAddress">
<view class="confirm-btn" >我要兑换</view>
</view>
</view>
<unidialog
:title="'确认收货信息'"
:visible="freeVisible"
:content="freeContent"
@close="freeClose"
@confirm="freeConfirm"
>
</unidialog>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import goods_api from '@/api/goods_api'
import unidialog from '@/components/dialog/dialog.vue';
const freeVisible = ref(false)
import navTo from '@/utils/navTo';
const freeContent = ref('您的积分不足,是否购买积分?')
const freeClose = () => {
freeVisible.value = false
}
const freeConfirm = () => {
freeVisible.value = false;
navTo({
url: '/pages_app/buyPoint/buyPoint'
})
}
const title = ref('')
const price = ref(0)
const qty = ref(1)
@ -54,6 +76,7 @@ const needPoints = ref(0)
const totalPoints = ref(0)
const selectedAddress = ref(null)
const id = ref('')
const type = ref(null)
const goBack = () => uni.navigateBack()
@ -63,10 +86,12 @@ const setQty = (n) => {
}
onLoad((opts) => {
console.log(opts);
if (opts) {
title.value = decodeURIComponent(opts.title || '')
price.value = Number(opts.price || 0)
id.value = opts.id || ''
type.value = opts.type
setQty(1)
getTotalPoints()
}
@ -110,24 +135,14 @@ const changeAddress = () => {
}
const goAddress = () => {
if (needPoints.value > totalPoints.value) {
uni.showToast({ title: '积分不足', icon: 'none' })
return
if(Number(needPoints.value) > Number(totalPoints.value)){
freeVisible.value = true
}else{
uni.navigateTo({
url: '/pages_goods/exchange/address?goodsUuid='+id.value+'&type='+type.value+'&goodsNum='+qty.value
})
}
if (!selectedAddress.value) {
changeAddress()
return
}
const data = {
goodsUuid: id.value,
address: selectedAddress.value.fullAddress,
user_name: selectedAddress.value.receiver,
mobile: selectedAddress.value.mobile,
goodsNum: qty.value,
email: selectedAddress.value.email
}
console.log(data)
//{"goodsUuid":"e6ca84edc8e64242a379dd0b895ea812",
@ -137,26 +152,26 @@ const goAddress = () => {
// "goodsNum":"1",
// "email":""}
//
uni.showModal({
title: '确认兑换',
content: `兑换“${title.value}”x${qty.value},共需 ${needPoints.value} 积分`,
success: (r) => {
if (r.confirm) {
//
totalPoints.value = Math.max(0, totalPoints.value - needPoints.value)
uni.removeStorageSync(SELECTED_KEY)
goods_api.createGoodsOrder(data).then(res => {
console.log(res)
if (res.code == 200) {
uni.showToast({ title: '兑换成功', icon: 'none' })
uni.navigateBack()
} else {
uni.showToast({ title: res.msg, icon: 'none' })
}
})
}
}
})
// uni.showModal({
// title: '',
// content: `${title.value}x${qty.value} ${needPoints.value} `,
// success: (r) => {
// if (r.confirm) {
// //
// totalPoints.value = Math.max(0, totalPoints.value - needPoints.value)
// uni.removeStorageSync(SELECTED_KEY)
// goods_api.createGoodsOrder(data).then(res => {
// console.log(res)
// if (res.code == 200) {
// uni.showToast({ title: '', icon: 'none' })
// uni.navigateBack()
// } else {
// uni.showToast({ title: res.msg, icon: 'none' })
// }
// })
// }
// }
// })
}
const getTotalPoints = () => {
goods_api.getTotalPoints && goods_api.getTotalPoints().then(res => {

View File

@ -13,7 +13,7 @@
>
<template v-slot:right>
<view class="nav-actions">
<view class="btn" @click="goToSearch">搜索</view>
<view class="btn" @click="goSearch">搜索</view>
</view>
</template>
</uni-nav-bar>
@ -148,11 +148,14 @@
</view>
</view>
<!-- 商品网格上拉加载 -->
<!-- 商品网格上拉加载 + 下拉刷新 -->
<scroll-view
class="product-grid"
scroll-y
refresher-enabled="true"
:refresher-triggered="refresherTriggered"
@scrolltolower="getGoodsList"
@refresherrefresh="onRefresherRefresh"
:lower-threshold="100"
>
<view class="grid-wrap">
@ -160,6 +163,7 @@
class="product-item"
v-for="(product, index) in products"
:key="product.uuid || index"
@click="goToProductDetail(product)"
>
<view class="product-image-container">
@ -219,6 +223,7 @@ const page = ref(1);
const pageSize = ref(10);
const isLoadingMore = ref(false);
const noMore = ref(false);
const refresherTriggered = ref(false);
const onSwiperChange = (e) => {
currentBannerIndex.value = e.detail.current;
};
@ -288,7 +293,17 @@ const goToProductDetail = (product) => {
url: `/pages_goods/productDetail/productDetail?id=${id}`,
});
};
const goSearch = () => {
uni.sendNativeEvent(
"goHomeSearch",
{
msg: "pointMall",
},
(ret) => {
console.log(ret);
}
);
}
const goToMyRedemption = () => {
uni.navigateTo({
url: "/pages_goods/myRedemption/myRedemption",
@ -305,7 +320,7 @@ const goToBannerDetail = (banner) => {
//
uni.navigateTo({
url: `/pages_app/webview/webview?url=${encodeURIComponent(
banner.path
docUrl+banner.path
)}&title=${banner.title}`,
});
};
@ -393,6 +408,31 @@ const getGoodsTagList = () => {
});
};
//
const onRefresherRefresh = async () => {
if (refresherTriggered.value) return;
refresherTriggered.value = true;
try {
//
page.value = 1;
noMore.value = false;
isLoadingMore.value = false;
products.value = [];
//
getGoodsNewsList();
getGoodsTagList();
await getGoodsList();
} catch (error) {
console.error("刷新数据失败:", error);
uni.showToast({
title: "刷新失败,请重试",
icon: "none",
});
} finally {
refresherTriggered.value = false;
}
};
onMounted(() => {
getGoodsNewsList();
//
@ -613,7 +653,7 @@ onMounted(() => {
right: 0;
z-index: 1;
height: calc(
100vh - var(--status-bar-height) - 44px - 88rpx
100vh - var(--status-bar-height) - 44px - 575rpx
); /* 预留顶部导航/筛选及底部栏 */
background-color: #f5f5f5;
}

View File

@ -16,7 +16,7 @@
<scroll-view scroll-y class="detail-scroll">
<!-- 商品主图轮播 -->
<view class="swiper-box">
<swiper class="detail-swiper" :indicator-dots="true" :autoplay="false" :interval="3000" :duration="400" indicator-color="#ccc" indicator-active-color="#8B2316">
<swiper class="detail-swiper" :indicator-dots="true" :autoplay="true" :interval="5000" :duration="400" indicator-color="#ccc" indicator-active-color="#8B2316">
<swiper-item v-for="(img, idx) in images" :key="idx">
<image class="swiper-image" :src="img" mode="aspectFit"></image>
</swiper-item>
@ -25,7 +25,7 @@
<!-- 标题与价格销量 -->
<view class="summary">
<view class="title">{{ product.title }}</view>
<view class="title">[包邮]{{ product.title }}</view>
<view class="price-row">
<text class="price">{{ product.price }}积分</text>
<text class="exchanged">已兑换{{ product.times }}</text>
@ -51,8 +51,8 @@
</scroll-view>
<!-- 底部兑换按钮 -->
<view class="bottom-bar">
<view class="redeem-btn" @click="goExchange">在线兑换</view>
<view class="bottom-bar" @click="goExchange">
<view class="redeem-btn" >在线兑换</view>
</view>
</view>
</template>
@ -76,6 +76,7 @@ const fetchDetail = async (id) => {
if ((res.code === 200 || res.code === '200') && res.data) {
product.value = {
id,
type: res.data.type,
title: res.data.name || '',
price: res.data.bonuspoints || 0,
times: res.data.times || 0,
@ -103,7 +104,7 @@ onLoad((opts) => {
const goExchange = () => {
uni.navigateTo({
url: `/pages_goods/exchange/index?id=${product.value.id}&title=${encodeURIComponent(product.value.title)}&price=${product.value.price}`
url: `/pages_goods/exchange/index?id=${product.value.id}&title=${encodeURIComponent(product.value.title)}&price=${product.value.price}&type=${product.value.type}`
})
}
</script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

BIN
static/signin_false.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
static/signin_true.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -101,5 +101,6 @@

View File

@ -120,9 +120,9 @@ export const request = (url, data = {}, method = 'post', loading = false, conten
if(process.env.UNI_PLATFORM == "mp-weixin"){
uni.redirectTo({url:'/pages_app/login/login'})
}
// else{
// uni.navigateTo({url:'/pages_app/login/login'})
// }
else{
uni.navigateTo({url:'/pages_app/login/login'})
}
uni.sendNativeEvent('getNewToken', {
msg: 'getNewToken'
},ret => {