很多页面
This commit is contained in:
@@ -61,8 +61,9 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onUnmounted,computed } from 'vue';
|
||||
import phoneImg from "@/static/phone.png"
|
||||
import smsImg from "@/static/sms.png"
|
||||
import phoneImg from "@/static/phone.png"
|
||||
import smsImg from "@/static/sms.png"
|
||||
import api from "@/api/api.js"
|
||||
const mobile = ref('');
|
||||
const code = ref('');
|
||||
const sending = ref(false);
|
||||
@@ -94,8 +95,17 @@ const sendCode = () => {
|
||||
return;
|
||||
}
|
||||
if (sending.value) return;
|
||||
api.smsSend({
|
||||
mobile: mobile.value,
|
||||
type: 6
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '验证码已发送', icon: 'success' });
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '验证码发送失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
// TODO: 调用发送验证码接口
|
||||
uni.showToast({ title: '验证码已发送', icon: 'success' });
|
||||
startTimer();
|
||||
};
|
||||
|
||||
@@ -108,8 +118,18 @@ const onConfirm = () => {
|
||||
uni.showToast({ title: '请输入正确的验证码', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
// TODO: 提交更换手机号
|
||||
uni.showToast({ title: '已提交', icon: 'success' });
|
||||
//String oldMobile,newMobile, sms = params.get("sms");
|
||||
api.changeMobile({
|
||||
newMobile: mobile.value,
|
||||
sms: code.value,
|
||||
oldMobile: uni.getStorageSync('userInfo').mobile
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '更换手机号成功', icon: 'success' });
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '更换手机号失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<view class="change-pwd-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="修改登录密码"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-wrapper">
|
||||
<view class="input-row">
|
||||
<input class="text-input" :password="true" v-model="oldPwd" placeholder="请输入原密码" placeholder-style="color:#c7c7c7" />
|
||||
</view>
|
||||
<view class="input-row">
|
||||
<input class="text-input" :password="!showNewPwd" v-model="newPwd" placeholder="新密码(6~16位数字字母组合)" placeholder-style="color:#c7c7c7" />
|
||||
</view>
|
||||
<view class="input-row">
|
||||
<input class="text-input" :password="!showConfirmPwd" v-model="confirmPwd" placeholder="确认新密码" placeholder-style="color:#c7c7c7" />
|
||||
</view>
|
||||
|
||||
<view class="forgot" @click="goForgot">忘记密码?</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部确定按钮 -->
|
||||
<view class="bottom-bar">
|
||||
<button class="confirm-btn" @click="onConfirm">确 定</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import api from "@/api/api.js"
|
||||
|
||||
const oldPwd = ref('');
|
||||
const newPwd = ref('');
|
||||
const confirmPwd = ref('');
|
||||
const showNewPwd = ref(false);
|
||||
const showConfirmPwd = ref(false);
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
const goForgot = () => {
|
||||
// 跳转到忘记密码或短信登录页(如无专页,这里跳到短信登录)
|
||||
uni.navigateTo({ url: '/pages_app/smsLogin/smsLogin' });
|
||||
};
|
||||
|
||||
const isStrong = (pwd) => {
|
||||
return /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,16}$/.test(pwd);
|
||||
};
|
||||
|
||||
const onConfirm = () => {
|
||||
if (!oldPwd.value) {
|
||||
return uni.showToast({ title: '请输入原密码', icon: 'none' });
|
||||
}
|
||||
if (!newPwd.value) {
|
||||
return uni.showToast({ title: '请输入新密码', icon: 'none' });
|
||||
}
|
||||
if (!isStrong(newPwd.value)) {
|
||||
return uni.showToast({ title: '密码需6-16位数字字母组合', icon: 'none' });
|
||||
}
|
||||
if (confirmPwd.value !== newPwd.value) {
|
||||
return uni.showToast({ title: '两次输入的密码不一致', icon: 'none' });
|
||||
}
|
||||
|
||||
api.changePassword({
|
||||
old_password: oldPwd.value,
|
||||
password: newPwd.value
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '修改密码成功', icon: 'success' });
|
||||
// 清除登录状态
|
||||
uni.clearStorageSync();
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages_app/login/login'
|
||||
});
|
||||
}, 2000);
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '修改密码失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.change-pwd-page {
|
||||
background: #ffffff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
padding: 40rpx 30rpx 0;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
margin-bottom: 30rpx;
|
||||
background: #ffffff;
|
||||
border: 2rpx solid #eeeeee;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
|
||||
.text-input {
|
||||
height: 96rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.forgot {
|
||||
text-align: center;
|
||||
color: #8b8b8b;
|
||||
font-size: 28rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 40rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
border-radius: 50rpx;
|
||||
background-color: #ffffff;
|
||||
border: 2rpx solid #8B2316;
|
||||
color: #8B2316;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<view class="bank-card-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="常用银行卡"
|
||||
@clickLeft="goBack()"
|
||||
right-text="添加"
|
||||
@clickRight="addBankCard"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
</uni-nav-bar>
|
||||
|
||||
<!-- 银行卡列表 -->
|
||||
<view class="card-list">
|
||||
<view class="card-item" v-for="(card, index) in bankCards" :key="card.uuid">
|
||||
<view class="card-logo">
|
||||
<view class="logo-bg">
|
||||
<text class="logo-text">{{ getBankLogo(card.open_bank) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<view class="card-number">尾号{{ card.card_number }}储蓄卡</view>
|
||||
<view class="bank-name">{{ card.open_bank }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部导航指示器 -->
|
||||
<view class="bottom-indicator"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import navTo from '@/utils/navTo';
|
||||
import api from '@/api/api';
|
||||
const bankCards = ref([]);
|
||||
|
||||
// 银行卡数据
|
||||
const getBankCardList = () => {
|
||||
api.bankCardList({}).then(res => {
|
||||
if (res.code === 200 && res.data.bankList) {
|
||||
bankCards.value = res.data.bankList;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
const addBankCard = () => {
|
||||
navTo({
|
||||
url: '/pages_app/idcardAuth/idcardAuth'
|
||||
});
|
||||
};
|
||||
|
||||
// 获取银行logo文字
|
||||
const getBankLogo = (bankName) => {
|
||||
const bankLogos = {
|
||||
'工商银行': '工',
|
||||
'中国银行': '中',
|
||||
'建设银行': '建',
|
||||
'农业银行': '农',
|
||||
'交通银行': '交',
|
||||
'招商银行': '招',
|
||||
'民生银行': '民',
|
||||
'兴业银行': '兴',
|
||||
'浦发银行': '浦',
|
||||
'光大银行': '光',
|
||||
'华夏银行': '华',
|
||||
'中信银行': '信',
|
||||
'平安银行': '平',
|
||||
'广发银行': '广',
|
||||
'邮储银行': '邮'
|
||||
};
|
||||
return bankLogos[bankName] || bankName.charAt(0);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getBankCardList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bank-card-page {
|
||||
min-height: 100vh;
|
||||
background: #F5F5F5;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 银行卡列表样式 */
|
||||
.card-list {
|
||||
padding: 30rpx;
|
||||
|
||||
.card-item {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.card-logo {
|
||||
margin-right: 30rpx;
|
||||
|
||||
.logo-bg {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: #E60012;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx solid #E60012;
|
||||
|
||||
.logo-text {
|
||||
color: #ffffff;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-info {
|
||||
flex: 1;
|
||||
|
||||
.card-number {
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
margin-bottom: 8rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bank-name {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 底部指示器 */
|
||||
.bottom-indicator {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 120rpx;
|
||||
height: 6rpx;
|
||||
background: #333333;
|
||||
border-radius: 3rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -3,8 +3,8 @@
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="身份验证"
|
||||
@cviewckLeft="goBack"
|
||||
:title="currentStep === 1 ? '身份验证' : '添加银行卡'"
|
||||
@clickLeft="goBack()"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
@@ -18,18 +18,18 @@
|
||||
<view class="progress-bar">
|
||||
<view class="barbox">
|
||||
<view class="imgbox">
|
||||
<up-image :src="stepImg" width="46rpx" height="46rpx" ></up-image>
|
||||
<view class="desc ">身份信息</view>
|
||||
<up-image :src="currentStep >= 1 ? stepActiveImg : stepImg" width="46rpx" height="46rpx"></up-image>
|
||||
<view class="desc" :class="{ active: currentStep >= 1 }">身份信息</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="line" :class="{ active: currentStep >= 2 }"></view>
|
||||
<view class="imgbox">
|
||||
<up-image :src="stepImg" width="46rpx" height="46rpx" ></up-image>
|
||||
<view class="desc">添加银行卡</view>
|
||||
<up-image :src="currentStep >= 2 ? stepActiveImg : stepImg" width="46rpx" height="46rpx"></up-image>
|
||||
<view class="desc" :class="{ active: currentStep >= 2 }">添加银行卡</view>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="line" :class="{ active: currentStep >= 3 }"></view>
|
||||
<view class="imgbox">
|
||||
<up-image :src="stepImg" width="46rpx" height="46rpx" ></up-image>
|
||||
<view class="desc">完成</view>
|
||||
<up-image :src="currentStep >= 3 ? stepActiveImg : stepImg" width="46rpx" height="46rpx"></up-image>
|
||||
<view class="desc" :class="{ active: currentStep >= 3 }">完成</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -57,23 +57,58 @@
|
||||
|
||||
<!-- 输入表单 -->
|
||||
<view class="form-section">
|
||||
<view class="form-item">
|
||||
<text class="form-label">姓名</text>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入您的姓名"
|
||||
v-model="formData.name"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
<!-- 第一步:身份信息 -->
|
||||
<view v-if="currentStep === 1">
|
||||
<view class="form-item">
|
||||
<text class="form-label">姓名</text>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入您的姓名"
|
||||
v-model="formData.name"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">身份证号</text>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入您的身份证号"
|
||||
v-model="formData.idNumber"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">身份证号</text>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入您的身份证号"
|
||||
v-model="formData.idNumber"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
|
||||
<!-- 第二步:添加银行卡 -->
|
||||
<view v-if="currentStep === 2">
|
||||
<view class="form-item">
|
||||
<text class="form-label">银行卡号</text>
|
||||
<view class="input-container">
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="仅限借记卡"
|
||||
v-model="formData.cardNumber"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
<view class="info-icon">
|
||||
<text class="icon-text">!</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">手机号</text>
|
||||
<view class="input-container">
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="银行预留手机号"
|
||||
v-model="formData.mobile"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
<view class="info-icon">
|
||||
<text class="icon-text">!</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -84,38 +119,215 @@
|
||||
|
||||
<!-- 下一步按钮 -->
|
||||
<view class="bottom-actions">
|
||||
<button class="next-btn" @click="onNextStep">下一步</button>
|
||||
<button class="next-btn" :class="{ loading: isLoading }" @click="onNextStep" :disabled="isLoading">
|
||||
<text v-if="!isLoading">下一步</text>
|
||||
<text v-else>验证中...</text>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 短信验证码弹框 -->
|
||||
<view v-if="showSmsDialog" class="sms-mask">
|
||||
<view class="sms-dialog">
|
||||
<view class="sms-title">短信验证码</view>
|
||||
<view class="sms-subtitle">请输入手机{{ maskedMobile }}收到的验证码</view>
|
||||
<view class="sms-input-row">
|
||||
<input class="sms-input" v-model="smsCode" placeholder="请输入验证码" placeholder-style="color: #cccccc" />
|
||||
<button class="sms-code-btn" :disabled="countdown > 0 || sendingCode" @click="onGetSmsCode">
|
||||
<text v-if="countdown === 0">获取验证码</text>
|
||||
<text v-else>{{ countdown }}s</text>
|
||||
</button>
|
||||
</view>
|
||||
<view class="sms-actions">
|
||||
<button class="sms-cancel" @click="onCancelSms">取消</button>
|
||||
<button class="sms-confirm" @click="onConfirmSms">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import stepImg from "@/static/add_card_no.png"
|
||||
import stepActiveImg from "@/static/add_card_yes.png"
|
||||
import navTo from '@/utils/navTo';
|
||||
import api from '@/api/api';
|
||||
|
||||
const formData = ref({
|
||||
name: '',
|
||||
idNumber: ''
|
||||
idNumber: '',
|
||||
cardNumber: '',
|
||||
mobile: ''
|
||||
});
|
||||
|
||||
const isLoading = ref(false);
|
||||
const currentStep = ref(1); // 当前步骤,1表示身份信息,2表示添加银行卡
|
||||
|
||||
// 短信弹框相关
|
||||
const showSmsDialog = ref(false);
|
||||
const smsCode = ref('');
|
||||
const sendingCode = ref(false);
|
||||
const countdown = ref(0);
|
||||
let countdownTimer = null;
|
||||
|
||||
const maskedMobile = computed(() => {
|
||||
const m = formData.value.mobile || '';
|
||||
if (m && m.length >= 7) {
|
||||
return `${m.slice(0,3)}****${m.slice(-4)}`;
|
||||
}
|
||||
return m || '***********';
|
||||
});
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
const onNextStep = () => {
|
||||
if (!formData.value.name.trim()) {
|
||||
uni.showToast({ title: '请输入姓名', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!formData.value.idNumber.trim()) {
|
||||
uni.showToast({ title: '请输入身份证号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
uni.showToast({ title: '验证通过,跳转下一步', icon: 'success' });
|
||||
// 这里可以跳转到下一步页面
|
||||
// 身份证号格式验证
|
||||
const validateIdNumber = (idNumber) => {
|
||||
const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
||||
return reg.test(idNumber);
|
||||
};
|
||||
|
||||
// 姓名格式验证
|
||||
const validateName = (name) => {
|
||||
const reg = /^[\u4e00-\u9fa5]{2,10}$/;
|
||||
return reg.test(name);
|
||||
};
|
||||
|
||||
// 银行卡号验证
|
||||
const validateCardNumber = (cardNumber) => {
|
||||
const reg = /^\d{16,19}$/;
|
||||
return reg.test(cardNumber);
|
||||
};
|
||||
|
||||
// 手机号验证
|
||||
const validateMobile = (mobile) => {
|
||||
const reg = /^1[3-9]\d{9}$/;
|
||||
return reg.test(mobile);
|
||||
};
|
||||
|
||||
const onNextStep = async () => {
|
||||
if (currentStep.value === 1) {
|
||||
// 第一步:身份信息验证
|
||||
if (!formData.value.name.trim()) {
|
||||
uni.showToast({ title: '请输入姓名', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateName(formData.value.name)) {
|
||||
uni.showToast({ title: '请输入正确的姓名(2-10个汉字)', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!formData.value.idNumber.trim()) {
|
||||
uni.showToast({ title: '请输入身份证号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateIdNumber(formData.value.idNumber)) {
|
||||
uni.showToast({ title: '请输入正确的身份证号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
// 调用身份验证API
|
||||
const res = {code:200}
|
||||
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '身份验证成功', icon: 'success' });
|
||||
currentStep.value = 2;
|
||||
isLoading.value = false;
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '身份验证失败', icon: 'none' });
|
||||
isLoading.value = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('身份验证失败:', error);
|
||||
uni.showToast({ title: '网络错误,请重试', icon: 'none' });
|
||||
isLoading.value = false;
|
||||
}
|
||||
} else if (currentStep.value === 2) {
|
||||
// 第二步:银行卡信息验证
|
||||
if (!formData.value.cardNumber.trim()) {
|
||||
uni.showToast({ title: '请输入银行卡号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateCardNumber(formData.value.cardNumber)) {
|
||||
uni.showToast({ title: '请输入正确的银行卡号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!formData.value.mobile.trim()) {
|
||||
uni.showToast({ title: '请输入手机号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateMobile(formData.value.mobile)) {
|
||||
uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 弹出短信验证码弹框
|
||||
showSmsDialog.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const onGetSmsCode = async () => {
|
||||
if (countdown.value > 0) return;
|
||||
const res = await api.smsSend({
|
||||
mobile: formData.value.mobile,
|
||||
type: 3
|
||||
});
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '短信验证码发送成功', icon: 'success' });
|
||||
// 开始60秒倒计时
|
||||
countdown.value = 60;
|
||||
if (countdownTimer) clearInterval(countdownTimer);
|
||||
countdownTimer = setInterval(() => {
|
||||
if (countdown.value > 0) {
|
||||
countdown.value -= 1;
|
||||
} else {
|
||||
clearInterval(countdownTimer);
|
||||
countdownTimer = null;
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '短信验证码发送失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const onConfirmSms = async () => {
|
||||
if (!smsCode.value) {
|
||||
uni.showToast({ title: '请输入短信验证码', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
const res = await api.identificationBankCardNew({
|
||||
phone_number: formData.value.mobile,
|
||||
sms: smsCode.value,
|
||||
id_number: formData.value.idNumber,
|
||||
card_number: formData.value.cardNumber,
|
||||
id_name: formData.value.name
|
||||
});
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '银行卡添加成功', icon: 'success' });
|
||||
navTo({
|
||||
url: '/pages_app/idcardAuth/bankCardList'
|
||||
});
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '银行卡添加失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
const onCancelSms = () => {
|
||||
showSmsDialog.value = false;
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -235,10 +447,11 @@ const onNextStep = () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.form-section {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
padding: 0;
|
||||
|
||||
|
||||
.form-item {
|
||||
@@ -246,58 +459,207 @@ const onNextStep = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 2rpx solid #eee;
|
||||
padding: 0 30rpx 20rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
width:120rpx;
|
||||
width: 120rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex:1;
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
border-color: #ff0000;
|
||||
border-color: #8B2316;
|
||||
}
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
width: 80%;
|
||||
|
||||
.form-input {
|
||||
flex: 9;
|
||||
height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
/* 去除边框后无需变更边框颜色 */
|
||||
}
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
flex:1;
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background: #f0f0f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon-text {
|
||||
font-size: 20rpx;
|
||||
color: #cccccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
background: #ffffff;
|
||||
background: #fff3cd;
|
||||
border: 2rpx solid #ffeaa7;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 60rpx;
|
||||
font-size: 26rpx;
|
||||
color: #000000;
|
||||
color: #856404;
|
||||
line-height: 1.6;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "⚠️";
|
||||
position: absolute;
|
||||
left: 30rpx;
|
||||
top: 30rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
padding-left: 80rpx;
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
padding: 0 30rox 40rpx;
|
||||
padding: 0 30rpx 40rpx;
|
||||
|
||||
.next-btn {
|
||||
margin:0 30rpx;
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #cccccc;
|
||||
background: #8B2316;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 8rpx;
|
||||
font-size: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
background: #8B2316;
|
||||
background: #6B1A0F;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
background: #cccccc;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: #cccccc;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 短信弹框样式 */
|
||||
.sms-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.sms-dialog {
|
||||
width: 680rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.sms-title {
|
||||
text-align: center;
|
||||
font-size: 34rpx;
|
||||
color: #000000;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.sms-subtitle {
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.sms-input-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin: 10rpx 0 30rpx;
|
||||
}
|
||||
|
||||
.sms-input {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
border: 2rpx solid #eeeeee;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.sms-code-btn {
|
||||
width: 200rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #eeeeee;
|
||||
color: #8B2316;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.sms-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.sms-cancel,
|
||||
.sms-confirm {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
border-radius: 8rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.sms-cancel { background: #f5f5f5; color: #000000; margin-right: 20rpx; }
|
||||
.sms-confirm { background: #8B2316; color: #ffffff; margin-left: 20rpx; }
|
||||
</style>
|
||||
|
||||
+233
-72
@@ -4,6 +4,8 @@
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="消息"
|
||||
right-text="清除"
|
||||
@clickRight="clearMsg"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
@@ -19,25 +21,28 @@
|
||||
<view class="grid-item" @click="goBenefit">
|
||||
<view class="icon-wrap gift">
|
||||
<uni-icons type="gift" size="34" color="#fff"></uni-icons>
|
||||
<view class="badge" v-if="badgeData.Module_Welfare > 0">{{ badgeData.Module_Welfare }}</view>
|
||||
</view>
|
||||
<text class="label">福利</text>
|
||||
</view>
|
||||
<view class="grid-item" @click="goOrder">
|
||||
<view class="icon-wrap order">
|
||||
<uni-icons type="list" size="34" color="#fff"></uni-icons>
|
||||
<view class="badge" v-if="badgeData.Module_Order > 0">{{ badgeData.Module_Order }}</view>
|
||||
</view>
|
||||
<text class="label">订单</text>
|
||||
</view>
|
||||
<view class="grid-item" @click="goFollow">
|
||||
<view class="icon-wrap visit">
|
||||
<uni-icons type="heart" size="34" color="#fff"></uni-icons>
|
||||
<view class="badge" v-if="followBadge > 0">{{ followBadge }}</view>
|
||||
<view class="badge" v-if="badgeData.Module_Relation > 0">{{ badgeData.Module_Relation }}</view>
|
||||
</view>
|
||||
<text class="label">随访</text>
|
||||
</view>
|
||||
<view class="grid-item" @click="goReply">
|
||||
<view class="icon-wrap reply">
|
||||
<uni-icons type="chatbubble" size="34" color="#fff"></uni-icons>
|
||||
<view class="badge" v-if="badgeData.Module_Comment > 0">{{ badgeData.Module_Comment }}</view>
|
||||
</view>
|
||||
<text class="label">回复我的</text>
|
||||
</view>
|
||||
@@ -54,13 +59,35 @@
|
||||
@scrolltolower="onLoadMore"
|
||||
lower-threshold="80"
|
||||
>
|
||||
<view class="group" v-for="(group, gIdx) in msgGroups" :key="gIdx">
|
||||
<view class="group-time">{{ group.time }}</view>
|
||||
<view class="card" v-for="(msg, idx) in group.items" :key="idx">
|
||||
<view class="card-title">系统消息</view>
|
||||
<view class="card-content">{{ msg }}</view>
|
||||
<!-- 回复我的模块 - 聊天列表样式 -->
|
||||
<view v-if="currentModule === 4" class="chat-list">
|
||||
<view class="chat-item" v-for="(msg, idx) in msgList" :key="msg.id">
|
||||
<view class="avatar">
|
||||
<image :src="msg.avatar || '/static/default-avatar.png'" mode="aspectFill" @error="handleImageError"></image>
|
||||
</view>
|
||||
<view class="chat-content">
|
||||
<view class="chat-header">
|
||||
<text class="sender-name">{{ msg.sender_name || msg.title }}</text>
|
||||
<text class="chat-time">{{ msg.create_date }}</text>
|
||||
</view>
|
||||
<view class="message-preview">{{ msg.content }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 其他模块 - 卡片样式 -->
|
||||
<view v-else>
|
||||
<view class="card" v-for="(msg, idx) in msgList" :key="msg.id">
|
||||
<view class="card-title">{{ msg.title }}</view>
|
||||
<view class="card-content">{{ msg.content }}</view>
|
||||
<view class="card-time">{{ msg.create_date }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view v-if="msgList.length === 0" class="empty-state">
|
||||
<text class="empty-text">暂无消息</text>
|
||||
</view>
|
||||
<!-- 加载更多提示 -->
|
||||
<view v-if="loading" class="loading-more">
|
||||
<text class="loading-text">加载中...</text>
|
||||
@@ -74,24 +101,21 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import api from '@/api/api.js';
|
||||
import docUrl from '@/utils/docUrl';
|
||||
|
||||
const followBadge = ref(5);
|
||||
// 角标数据
|
||||
const badgeData = ref({
|
||||
Module_Order: 0, // 订单
|
||||
Module_Comment: 0, // 回复我的
|
||||
Module_Welfare: 0, // 福利
|
||||
Module_Relation: 0 // 随访
|
||||
});
|
||||
|
||||
const msgGroups = ref([
|
||||
{
|
||||
time: '2022-04-22 16:32:54',
|
||||
items: ['恭喜您,您的肝胆积分又增加了,快去查看吧']
|
||||
},
|
||||
{
|
||||
time: '2022-04-20 13:33:23',
|
||||
items: ['恭喜您,您的肝胆积分又增加了,快去查看吧']
|
||||
},
|
||||
{
|
||||
time: '2022-04-15 13:36:23',
|
||||
items: ['恭喜您,您的肝胆积分又增加了,快去查看吧']
|
||||
}
|
||||
]);
|
||||
// 消息列表数据
|
||||
const msgList = ref([]);
|
||||
const currentModule = ref(1); // 当前选中的模块,默认显示模块1的消息
|
||||
|
||||
// 刷新/加载状态
|
||||
const refreshing = ref(false);
|
||||
@@ -100,13 +124,7 @@
|
||||
const page = ref(1);
|
||||
const pageSize = ref(10);
|
||||
|
||||
// 模拟更多数据(请在接入接口后替换)
|
||||
const mockMore = [
|
||||
{ time: '2022-04-10 09:20:11', items: ['系统保养完成,服务更稳定~'] },
|
||||
{ time: '2022-04-05 18:06:42', items: ['积分到账提醒,请注意查收。'] },
|
||||
{ time: '2022-03-30 08:15:00', items: ['本周学术会议日程已发布。'] },
|
||||
{ time: '2022-03-25 10:05:16', items: ['您有新的随访任务待处理。'] }
|
||||
];
|
||||
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack({
|
||||
@@ -118,23 +136,46 @@
|
||||
});
|
||||
};
|
||||
|
||||
const goBenefit = () => uni.showToast({ title: '福利', icon: 'none' });
|
||||
const goOrder = () => uni.showToast({ title: '订单', icon: 'none' });
|
||||
const goFollow = () => uni.showToast({ title: '随访', icon: 'none' });
|
||||
const goReply = () => uni.showToast({ title: '回复我的', icon: 'none' });
|
||||
const goBenefit = () => {
|
||||
currentModule.value = 1;
|
||||
getAppMesageList(1);
|
||||
};
|
||||
const goOrder = () => {
|
||||
currentModule.value = 2;
|
||||
getAppMesageList(2);
|
||||
};
|
||||
const goFollow = () => {
|
||||
currentModule.value = 3;
|
||||
getAppMesageList(3);
|
||||
};
|
||||
const goReply = () => {
|
||||
currentModule.value = 4;
|
||||
getAppMesageList(4);
|
||||
};
|
||||
|
||||
const clearMsg = () => {
|
||||
uni.showModal({
|
||||
title: '提醒',
|
||||
content: '是否要清除所有未读消息?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
api.appMesageRead({}).then(res => {
|
||||
console.log(res);
|
||||
});
|
||||
getUnReadList();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// 下拉刷新
|
||||
const onRefresh = async () => {
|
||||
if (refreshing.value) return;
|
||||
refreshing.value = true;
|
||||
try {
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
msgGroups.value.unshift({
|
||||
time: new Date().toISOString().slice(0, 19).replace('T', ' '),
|
||||
items: ['您有一条新的系统通知,欢迎查看。']
|
||||
});
|
||||
// 重新获取当前模块的消息列表
|
||||
getAppMesageList(currentModule.value);
|
||||
// 重新获取未读消息数量
|
||||
getUnReadList();
|
||||
} finally {
|
||||
refreshing.value = false;
|
||||
}
|
||||
@@ -145,19 +186,73 @@
|
||||
if (loading.value || noMore.value) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
const start = (page.value - 1) * 2;
|
||||
const chunk = mockMore.slice(start, start + 2);
|
||||
if (chunk.length === 0) {
|
||||
noMore.value = true;
|
||||
} else {
|
||||
msgGroups.value.push(...chunk);
|
||||
page.value += 1;
|
||||
}
|
||||
// 这里可以根据需要实现分页加载
|
||||
// 目前接口返回的数据已经包含了分页信息
|
||||
// 如果需要加载更多,可以调用 getAppMesageList 并传入页码参数
|
||||
noMore.value = true; // 暂时设置为没有更多数据
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const getUnReadList = () => {
|
||||
api.unReadList({}).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data) {
|
||||
// 更新角标数据
|
||||
badgeData.value = {
|
||||
Module_Order: parseInt(res.data.Module_Order) || 0,
|
||||
Module_Comment: parseInt(res.data.Module_Comment) || 0,
|
||||
Module_Welfare: parseInt(res.data.Module_Welfare) || 0,
|
||||
Module_Relation: parseInt(res.data.Module_Relation) || 0
|
||||
};
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取未读消息列表失败:', err);
|
||||
});
|
||||
};
|
||||
|
||||
const getAppMesageList = (module) => {
|
||||
api.appMesageList({module: module}).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data && res.data.list) {
|
||||
// 更新消息列表数据
|
||||
msgList.value = res.data.list.map(item => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
content: item.content,
|
||||
create_date: item.create_date,
|
||||
is_read: item.is_read,
|
||||
extra: item.extra,
|
||||
// 从extra字段提取用户信息
|
||||
sender_name: item.extra?.user_name || item.title,
|
||||
avatar: item.extra?.user_photo ?
|
||||
(item.extra.user_photo.startsWith('http') ?
|
||||
item.extra.user_photo :
|
||||
`${getBaseUrl()}${item.extra.user_photo}`) :
|
||||
'/static/default-avatar.png'
|
||||
}));
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取消息列表失败:', err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取基础URL
|
||||
const getBaseUrl = () => {
|
||||
return docUrl;
|
||||
};
|
||||
|
||||
// 图片加载错误处理
|
||||
const handleImageError = (e) => {
|
||||
// 设置默认头像
|
||||
e.target.src = '/static/default-avatar.png';
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getUnReadList();
|
||||
getAppMesageList(1);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -243,41 +338,107 @@
|
||||
box-sizing: border-box;
|
||||
bottom: 0rpx;
|
||||
// 加载状态样式
|
||||
.loading-more, .no-more {
|
||||
.loading-more, .no-more, .empty-state {
|
||||
@include flex-center;
|
||||
padding: 28rpx 0;
|
||||
.loading-text, .no-more-text {
|
||||
.loading-text, .no-more-text, .empty-text {
|
||||
font-size: 26rpx;
|
||||
color: $muted;
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
.group-time {
|
||||
text-align: center;
|
||||
color: $muted;
|
||||
font-size: 24rpx;
|
||||
margin: 26rpx 0 16rpx;
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 26rpx;
|
||||
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
|
||||
margin-top: 26rpx;
|
||||
|
||||
.card-title {
|
||||
font-size: 30rpx;
|
||||
color: $text-primary;
|
||||
font-weight: 600;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 26rpx;
|
||||
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
|
||||
margin-bottom: 26rpx;
|
||||
.card-content {
|
||||
font-size: 28rpx;
|
||||
color: $text-secondary;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 30rpx;
|
||||
color: $text-primary;
|
||||
font-weight: 600;
|
||||
margin-bottom: 14rpx;
|
||||
.card-time {
|
||||
font-size: 24rpx;
|
||||
color: $muted;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
// 聊天列表样式
|
||||
.chat-list {
|
||||
.chat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
background: #fff;
|
||||
margin-top: 24rpx;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
font-size: 28rpx;
|
||||
color: $text-secondary;
|
||||
line-height: 1.6;
|
||||
.avatar {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-right: 24rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.chat-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.sender-name {
|
||||
font-size: 30rpx;
|
||||
color: $text-primary;
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.chat-time {
|
||||
font-size: 24rpx;
|
||||
color: $muted;
|
||||
flex-shrink: 0;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.message-preview {
|
||||
font-size: 28rpx;
|
||||
color: $text-secondary;
|
||||
line-height: 1.4;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
<view class="summary-bar">
|
||||
<view class="summary-item">
|
||||
<up-image :src="downLoadImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="summary-text">: {{ downloadCount }}</text>
|
||||
<text class="summary-text">{{ activeTab === 'download' ? '下载账户' : '分享账户' }}: {{ downloadCount }}</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<up-image :src="moneyImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="summary-text">: {{ totalAmount }}</text>
|
||||
<text class="summary-text">{{ activeTab === 'download' ? '文件数量' : '分享文件' }}: {{ totalAmount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -55,12 +55,21 @@
|
||||
@scrolltolower="onLoadMore"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<!-- 空状态 -->
|
||||
<view v-if="coursewareList.length === 0 && !loading" class="empty-state">
|
||||
<text>{{ activeTab === 'download' ? '暂无下载数据' : '暂无分享数据' }}</text>
|
||||
</view>
|
||||
|
||||
<view class="courseware-item" v-for="(item, index) in coursewareList" :key="index" @click="onItemClick(item)">
|
||||
<view class="item-content">
|
||||
<view class="courseware-name">
|
||||
<text class="label">课件名称:</text>
|
||||
<text class="value">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="courseware-provider" v-if="item.providername">
|
||||
<text class="label">{{ activeTab === 'download' ? '提供者' : '下载者' }}:</text>
|
||||
<text class="value">{{ item.providername }}</text>
|
||||
</view>
|
||||
<view class="courseware-time">
|
||||
<text class="label">时间:</text>
|
||||
<text class="value">{{ item.time }}</text>
|
||||
@@ -78,7 +87,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 没有更多数据提示 -->
|
||||
<view v-if="noMore" class="no-more">
|
||||
<view v-if="noMore && coursewareList.length > 0" class="no-more">
|
||||
<text>没有更多数据了</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
@@ -86,7 +95,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import api from '@/api/api';
|
||||
import downLoadImg from "@/static/course_download.png"
|
||||
import moneyImg from "@/static/course_yuan.png"
|
||||
const activeTab = ref('download');
|
||||
@@ -98,28 +108,11 @@ const pageSize = ref(10);
|
||||
const downloadCount = ref(4);
|
||||
const totalAmount = ref('20.00');
|
||||
|
||||
const coursewareList = ref([
|
||||
{
|
||||
name: '慢性病毒性肝炎患者干扰素治疗不良反应临床处理专家共识',
|
||||
time: '2025-02-21',
|
||||
status: '已支付'
|
||||
},
|
||||
{
|
||||
name: '慢乙肝抗病毒治疗-把握时机正确选择',
|
||||
time: '2024-11-27',
|
||||
status: '已支付'
|
||||
},
|
||||
{
|
||||
name: '肝病相关血小板减少症临床管理中国专家共识(2023)解读',
|
||||
time: '2024-10-06',
|
||||
status: '已支付'
|
||||
},
|
||||
{
|
||||
name: '俞云松:耐药阳性菌感染诊疗思路(CHINET数据云)',
|
||||
time: '2022-10-24',
|
||||
status: '已支付'
|
||||
}
|
||||
]);
|
||||
const coursewareList = ref([]);
|
||||
|
||||
onMounted(() => {
|
||||
onRefresh();
|
||||
});
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
@@ -131,37 +124,173 @@ const switchTab = (tab) => {
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
// 这里可以根据标签加载不同数据
|
||||
onRefresh();
|
||||
};
|
||||
|
||||
const onItemClick = (item) => {
|
||||
uni.showToast({ title: `点击了: ${item.name}`, icon: 'none' });
|
||||
// 这里可以根据需要跳转到详情页或执行下载操作
|
||||
console.log('点击课件:', item);
|
||||
|
||||
if (activeTab.value === 'download') {
|
||||
// 下载标签页的处理逻辑
|
||||
if (item.download_path) {
|
||||
uni.downloadFile({
|
||||
url: item.download_path,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
uni.openDocument({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
console.log('打开文档成功');
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('打开文档失败:', err);
|
||||
uni.showToast({ title: '无法打开此文件', icon: 'none' });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('下载失败:', err);
|
||||
uni.showToast({ title: '下载失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.showToast({ title: `点击了下载课件: ${item.name}`, icon: 'none' });
|
||||
}
|
||||
} else {
|
||||
// 分享标签页的处理逻辑
|
||||
uni.showToast({ title: `点击了分享课件: ${item.name}`, icon: 'none' });
|
||||
// 这里可以添加分享相关的操作,比如查看分享详情、重新分享等
|
||||
}
|
||||
};
|
||||
|
||||
const onRefresh = () => {
|
||||
refreshing.value = true;
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
|
||||
setTimeout(() => {
|
||||
refreshing.value = false;
|
||||
uni.showToast({ title: '刷新完成', icon: 'success' });
|
||||
}, 1000);
|
||||
if (activeTab.value === 'download') {
|
||||
api.getGandanfileMyDownload({ page: page.value }).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data.list;
|
||||
// 更新摘要信息
|
||||
downloadCount.value = res.data.downloadTotalAccount || 0;
|
||||
totalAmount.value = res.data.downloadFileCount || 0;
|
||||
|
||||
// 处理课件列表数据
|
||||
coursewareList.value = data.list.map(item => ({
|
||||
name: item.title || '未知课件',
|
||||
time: item.create_date ? item.create_date.split(' ')[0] : '',
|
||||
status: item.order_status === 'paid' ? '已支付' : '未支付',
|
||||
uuid: item.uuid,
|
||||
order_id: item.order_id,
|
||||
type: item.type,
|
||||
providername: item.providername
|
||||
}));
|
||||
|
||||
// 判断是否还有更多数据
|
||||
noMore.value = data.pageNumber >= data.totalPage;
|
||||
}
|
||||
refreshing.value = false;
|
||||
}).catch(err => {
|
||||
console.error('获取下载列表失败:', err);
|
||||
refreshing.value = false;
|
||||
});
|
||||
} else {
|
||||
api.getGandanfileMyShare({ page: page.value }).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data.list;
|
||||
// 更新摘要信息 - 分享数据使用不同的字段
|
||||
downloadCount.value = res.data.shareTotalAccount || 0;
|
||||
totalAmount.value = res.data.shareloadFileCount || 0;
|
||||
|
||||
// 处理分享列表数据
|
||||
coursewareList.value = data.list.map(item => ({
|
||||
name: item.title || '未知课件',
|
||||
time: item.create_date ? item.create_date.split(' ')[0] : '',
|
||||
status: '已分享', // 分享数据没有支付状态,统一显示为已分享
|
||||
uuid: item.uuid,
|
||||
order_id: item.order_id,
|
||||
type: item.type,
|
||||
providername: item.downloadername, // 分享数据中下载者名称对应提供者
|
||||
downloadername: item.downloadername
|
||||
}));
|
||||
|
||||
// 判断是否还有更多数据
|
||||
noMore.value = data.pageNumber >= data.totalPage;
|
||||
}
|
||||
refreshing.value = false;
|
||||
}).catch(err => {
|
||||
console.error('获取分享列表失败:', err);
|
||||
refreshing.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onLoadMore = () => {
|
||||
if (loading.value || noMore.value) return;
|
||||
|
||||
loading.value = true;
|
||||
page.value++;
|
||||
|
||||
setTimeout(() => {
|
||||
if (page.value < 3) {
|
||||
page.value++;
|
||||
uni.showToast({ title: '加载完成', icon: 'success' });
|
||||
} else {
|
||||
noMore.value = true;
|
||||
}
|
||||
loading.value = false;
|
||||
}, 1000);
|
||||
if (activeTab.value === 'download') {
|
||||
api.getGandanfileMyDownload({ page: page.value }).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data.list;
|
||||
// 追加新数据到列表
|
||||
const newList = data.list.map(item => ({
|
||||
name: item.title || '未知课件',
|
||||
time: item.create_date ? item.create_date.split(' ')[0] : '',
|
||||
status: item.order_status === 'paid' ? '已支付' : '未支付',
|
||||
uuid: item.uuid,
|
||||
order_id: item.order_id,
|
||||
type: item.type,
|
||||
providername: item.providername
|
||||
}));
|
||||
|
||||
coursewareList.value = [...coursewareList.value, ...newList];
|
||||
|
||||
// 判断是否还有更多数据
|
||||
noMore.value = data.pageNumber >= data.totalPage;
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch(err => {
|
||||
console.error('加载更多下载列表失败:', err);
|
||||
page.value--; // 恢复页码
|
||||
loading.value = false;
|
||||
});
|
||||
} else {
|
||||
api.getGandanfileMyShare({ page: page.value }).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data.list;
|
||||
// 追加新数据到列表
|
||||
const newList = data.list.map(item => ({
|
||||
name: item.title || '未知课件',
|
||||
time: item.create_date ? item.create_date.split(' ')[0] : '',
|
||||
status: '已分享', // 分享数据没有支付状态,统一显示为已分享
|
||||
uuid: item.uuid,
|
||||
order_id: item.order_id,
|
||||
type: item.type,
|
||||
providername: item.downloadername, // 分享数据中下载者名称对应提供者
|
||||
downloadername: item.downloadername
|
||||
}));
|
||||
|
||||
coursewareList.value = [...coursewareList.value, ...newList];
|
||||
|
||||
// 判断是否还有更多数据
|
||||
noMore.value = data.pageNumber >= data.totalPage;
|
||||
}
|
||||
loading.value = false;
|
||||
}).catch(err => {
|
||||
console.error('加载更多分享列表失败:', err);
|
||||
page.value--; // 恢复页码
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -240,6 +369,7 @@ const onLoadMore = () => {
|
||||
border-bottom:2rpx solid #eee;
|
||||
.item-content {
|
||||
.courseware-name,
|
||||
.courseware-provider,
|
||||
.courseware-time,
|
||||
.courseware-status {
|
||||
display: flex;
|
||||
@@ -269,10 +399,15 @@ const onLoadMore = () => {
|
||||
}
|
||||
}
|
||||
|
||||
.loading-more, .no-more {
|
||||
.loading-more, .no-more, .empty-state {
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
color: #999999;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 100rpx 30rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -60,11 +60,9 @@
|
||||
<view v-if="noMore && records.length > 0" class="no-more">
|
||||
<text>没有更多数据了</text>
|
||||
</view>
|
||||
|
||||
<!-- 调试按钮 -->
|
||||
<view v-if="records.length > 0" class="debug-actions">
|
||||
<button @click="testLoadMore" size="mini" type="primary">测试加载更多</button>
|
||||
<text class="debug-info">当前页: {{ page }}, 加载中: {{ loading }}, 无更多: {{ noMore }}</text>
|
||||
<view class="debug-actions">
|
||||
<!-- <button @click="testLoadMore" size="mini" type="primary">测试加载更多</button>
|
||||
<text class="debug-info">当前页: {{ page }}, 加载中: {{ loading }}, 无更多: {{ noMore }}</text> -->
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -221,7 +219,9 @@ $text: #333;
|
||||
$muted: #999;
|
||||
$card: #ffffff;
|
||||
|
||||
.flower-page { height: calc(100vh - 140rpx); background: $bg; }
|
||||
.flower-page {
|
||||
background: $bg;
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
display: flex;
|
||||
@@ -297,6 +297,7 @@ $card: #ffffff;
|
||||
}
|
||||
|
||||
.debug-actions {
|
||||
height: 50rpx;
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
|
||||
@@ -472,7 +472,7 @@
|
||||
const formattedList = listData.map(item => ({
|
||||
type: item.score_type_name,
|
||||
time: item.create_date,
|
||||
amount: -item.score // 支出为负数
|
||||
amount: item.score // 支出为负数
|
||||
}));
|
||||
|
||||
// 更新支出记录列表
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="兑换福利卡"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
|
||||
<view class="exchange-page">
|
||||
<!-- 顶部红色横幅 -->
|
||||
<view class="top-banner">
|
||||
<view class="banner-text">
|
||||
<view class="line1">已兑换{{ exchangedCount }}张</view>
|
||||
<view class="line2" @click="goMyWelfare">查看现有权益</view>
|
||||
</view>
|
||||
<view class="help-btn" @click="showHelp">帮助说明</view>
|
||||
</view>
|
||||
|
||||
<!-- 使用统一的自定义居中模态框 -->
|
||||
<view v-if="centerVisible" class="center-modal" @click.self="closeCenter">
|
||||
<view class="center-modal-content">
|
||||
<view class="center-title">{{ centerHelp ? '帮助说明' : '提示' }}</view>
|
||||
<view v-if="centerHelp" class="help-content center-help">
|
||||
<text>1、点击“兑换福利卡”,输入密码即可兑换相应权益</text>
|
||||
<text>2、每张福利卡仅限兑换一次,兑换后权益可在“我的福利-使用福利”中查看</text>
|
||||
<text>3、福利卡长期有效,福利卡不能退换或者折现</text>
|
||||
<text>4、查找文献权益不限文献类型,如指南共识、论文、电子书、课件或者视频</text>
|
||||
</view>
|
||||
<view v-else class="center-body">{{ centerText }}</view>
|
||||
<view class="center-actions">
|
||||
<button class="center-btn" @click="closeCenter">知道了</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 输入提示 -->
|
||||
<view class="tips">请输入16位福利卡密码(不区分大小写)<text class="paste-action" @click="pasteFromClipboard">粘贴</text></view>
|
||||
|
||||
<!-- 四段输入框 -->
|
||||
<view class="code-inputs">
|
||||
<input class="code-box" type="text" v-model="code1" maxlength="4" placeholder="" :focus="f1" @input="handleInput(1, $event)" @paste="handlePaste"/>
|
||||
<input class="code-box" type="text" v-model="code2" maxlength="4" placeholder="" :focus="f2" @input="handleInput(2, $event)"/>
|
||||
<input class="code-box" type="text" v-model="code3" maxlength="4" placeholder="" :focus="f3" @input="handleInput(3, $event)"/>
|
||||
<input class="code-box" type="text" v-model="code4" maxlength="4" placeholder="" :focus="f4" @input="handleInput(4, $event)"/>
|
||||
</view>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<view class="btn-wrapper">
|
||||
<button class="submit-btn" :disabled="!isFull" @click="submit">立即兑换</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, nextTick } from 'vue'
|
||||
import api from '@/api/api';
|
||||
const exchangedCount = ref(5)
|
||||
const code1 = ref('')
|
||||
const code2 = ref('')
|
||||
const code3 = ref('')
|
||||
const code4 = ref('')
|
||||
const f1 = ref(true)
|
||||
const f2 = ref(false)
|
||||
const f3 = ref(false)
|
||||
const f4 = ref(false)
|
||||
const helpVisible = ref(false)
|
||||
const centerVisible = ref(false)
|
||||
const centerText = ref('')
|
||||
const centerHelp = ref(false)
|
||||
const isFull = computed(() => (code1.value+code2.value+code3.value+code4.value).length === 16)
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack({
|
||||
fail() {
|
||||
uni.redirectTo({ url: '/pages/index/index' })
|
||||
}
|
||||
})
|
||||
}
|
||||
const showHelp = () => {
|
||||
centerHelp.value = true
|
||||
centerVisible.value = true
|
||||
}
|
||||
|
||||
// 通用模态框
|
||||
const openCenter = (text) => {
|
||||
centerText.value = text
|
||||
centerHelp.value = false
|
||||
centerVisible.value = true
|
||||
}
|
||||
const closeCenter = () => {
|
||||
centerVisible.value = false
|
||||
centerHelp.value = false
|
||||
}
|
||||
const setFocus = (idx) => {
|
||||
f1.value = idx === 1
|
||||
f2.value = idx === 2
|
||||
f3.value = idx === 3
|
||||
f4.value = idx === 4
|
||||
}
|
||||
const handleInput = (idx, e) => {
|
||||
const raw = (e.detail && e.detail.value) || ''
|
||||
const sanitized = raw.replace(/[^a-zA-Z0-9]/g, '')
|
||||
if (idx === 1) code1.value = sanitized
|
||||
if (idx === 2) code2.value = sanitized
|
||||
if (idx === 3) code3.value = sanitized
|
||||
if (idx === 4) code4.value = sanitized
|
||||
if (sanitized.length === 4 && idx < 4) {
|
||||
nextTick(() => setFocus(idx + 1))
|
||||
}
|
||||
}
|
||||
const submit = () => {
|
||||
if (!isFull.value) return
|
||||
const code = (code1.value+code2.value+code3.value+code4.value).toUpperCase()
|
||||
uni.showToast({ title: '兑换中: '+ code, icon: 'none' })
|
||||
api.exchangeWelfareCard({password: code}).then(res => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
uni.showToast({ title: '兑换成功', icon: 'success' })
|
||||
uni.navigateBack()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const goMyWelfare = () => {
|
||||
uni.navigateTo({ url: '/pages_app/myWelfare/myWelfare' })
|
||||
}
|
||||
|
||||
// 处理粘贴(H5等支持paste事件的平台)
|
||||
const handlePaste = (e) => {
|
||||
const text = (e.clipboardData && e.clipboardData.getData('text')) || ''
|
||||
fillByText(text)
|
||||
// 阻止默认粘贴到单个输入框
|
||||
e && e.preventDefault && e.preventDefault()
|
||||
}
|
||||
|
||||
// 从剪贴板读取(App、小程序)
|
||||
const pasteFromClipboard = () => {
|
||||
uni.getClipboardData({
|
||||
success: (res) => {
|
||||
fillByText(res.data || '')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const fillByText = (raw) => {
|
||||
const v = String(raw || '').replace(/[^a-zA-Z0-9]/g, '').toUpperCase().slice(0, 16)
|
||||
code1.value = v.slice(0, 4)
|
||||
code2.value = v.slice(4, 8)
|
||||
code3.value = v.slice(8, 12)
|
||||
code4.value = v.slice(12, 16)
|
||||
nextTick(() => setFocus(v.length >= 16 ? 4 : Math.floor((v.length)/4) + 1))
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$nav-height: 140rpx;
|
||||
.exchange-page{
|
||||
min-height: 100vh;
|
||||
background: #f5f6f7;
|
||||
}
|
||||
.top-banner{
|
||||
position: relative;
|
||||
height: 280rpx;
|
||||
background: linear-gradient(180deg,#ff6a4a 0%, #e93b2d 100%);
|
||||
border-bottom-left-radius: 40rpx;
|
||||
border-bottom-right-radius: 40rpx;
|
||||
.banner-text{
|
||||
position: absolute;
|
||||
left: 48rpx;
|
||||
top: 120rpx;
|
||||
color: #fff;
|
||||
.line1{font-size: 44rpx;font-weight: 600;}
|
||||
.line2{font-size: 36rpx;margin-top: 12rpx;}
|
||||
}
|
||||
.help-btn{
|
||||
position: absolute;
|
||||
right: 40rpx;
|
||||
top: 90rpx;
|
||||
background: rgba(255,255,255,.95);
|
||||
color: #e04835;
|
||||
border-radius: 999rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
.tips{
|
||||
margin: 48rpx;
|
||||
color: #333;
|
||||
font-size: 32rpx;
|
||||
.paste-action{
|
||||
color: #007aff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
.code-inputs{
|
||||
display: flex;
|
||||
gap: 30rpx;
|
||||
padding: 0 48rpx;
|
||||
.code-box{
|
||||
flex: 1;
|
||||
height: 96rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
.btn-wrapper{
|
||||
padding: 80rpx 48rpx 0;
|
||||
.submit-btn{
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
background: linear-gradient(90deg,#ff4d2e,#e93b2d);
|
||||
border-radius: 60rpx;
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
.submit-btn[disabled]{
|
||||
opacity: .6;
|
||||
}
|
||||
}
|
||||
|
||||
/* 帮助弹层样式 */
|
||||
.center-help{padding: 0 32rpx;display:flex;flex-direction:column;align-items:center;gap: 16rpx;color:#333;font-size:28rpx;line-height:1.6;}
|
||||
|
||||
/* 自定义通用模态框 */
|
||||
.center-modal{position: fixed;left:0;right:0;top:0;bottom:0;background: rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index: 9999;}
|
||||
.center-modal-content{width: 640rpx;background:#fff;border-radius:24rpx;overflow:hidden;}
|
||||
.center-title{font-size: 32rpx;color:#333;text-align:center;padding:28rpx 24rpx 12rpx;font-weight:600;}
|
||||
.center-body{padding:0 32rpx 12rpx;color:#333;font-size:28rpx;line-height:1.7;text-align:center;}
|
||||
.center-actions{padding: 24rpx 24rpx 28rpx;}
|
||||
.center-btn{width:100%;height:88rpx;border-radius:999rpx;background:#e93b2d;color:#fff;font-size:30rpx;}
|
||||
|
||||
</style>
|
||||
@@ -11,100 +11,121 @@
|
||||
></uni-nav-bar>
|
||||
|
||||
<view class="benefits-page">
|
||||
|
||||
<!-- 顶部红色横幅 -->
|
||||
<view class="top-banner">
|
||||
<view class="banner-text">
|
||||
<view class="line1">已兑换{{ cardInfo.length }}张</view>
|
||||
<view class="line2" @click="goMyWelfare">查看现有权益</view>
|
||||
</view>
|
||||
<view class="help-btn" @click="showRules">帮助说明</view>
|
||||
</view>
|
||||
|
||||
<!-- 头部导航栏 -->
|
||||
|
||||
|
||||
<!-- 帮助说明模态框(与兑换页一致的居中弹层) -->
|
||||
<view v-if="centerVisible" class="center-modal" @click.self="closeCenter">
|
||||
<view class="center-modal-content">
|
||||
<view class="center-title">帮助说明</view>
|
||||
<view class="center-help">
|
||||
<text>1、点击“兑换福利卡”,输入密码即可兑换相应权益</text>
|
||||
<text>2、每张福利卡仅限兑换一次,兑换后权益可在“我的福利-使用福利”中查看</text>
|
||||
<text>3、福利卡长期有效,福利卡不能退换或者折现</text>
|
||||
<text>4、查找文献权益不限文献类型,如指南共识、论文、电子书、课件或者视频</text>
|
||||
</view>
|
||||
<view class="center-actions">
|
||||
<button class="center-btn" @click="closeCenter">知道了</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 福利卡片列表 -->
|
||||
<view class="scrollbox">
|
||||
<scroll-view class="benefits-list" scroll-y="true" :show-scrollbar="false">
|
||||
<view
|
||||
class="benefit-card"
|
||||
v-for="(benefit, index) in benefitsList"
|
||||
:key="index"
|
||||
:class="benefit.type"
|
||||
@click="claimBenefit(benefit)"
|
||||
>
|
||||
<view class="card-title">{{ benefit.title }}</view>
|
||||
<!-- <view class="card-bg">
|
||||
|
||||
</view> -->
|
||||
<view class="card-content">
|
||||
|
||||
<view class="card-details">
|
||||
<view class="left-section">
|
||||
<text class="condition">{{ benefit.condition }}</text>
|
||||
<text class="requirement">{{ benefit.requirement }}</text>
|
||||
</view>
|
||||
<view class="right-section">
|
||||
<text class="reward-type">{{ benefit.rewardType }}</text>
|
||||
<text class="reward-value">{{ benefit.rewardValue }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 有卡展示(多张) -->
|
||||
<view v-if="hasCard" >
|
||||
<view class="card-wrapper" v-for="(card, cIdx) in cardInfo" :key="card.id">
|
||||
<view class="card-header">
|
||||
<text>卡号:{{ card.idcard }}</text>
|
||||
<text class="time">兑换时间:{{ card.exchange_date }}</text>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="benefit-line" v-for="(w, idx) in card.welfare_list" :key="idx">
|
||||
<text class="index">{{ idx + 1 }}、</text>
|
||||
<text class="text">{{ w.type_name }}{{ w.num }}{{ w.type_unit }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 加载提示 -->
|
||||
<view class="loadmore-tip" v-if="isLoading || isLastPage">
|
||||
<text>{{ isLoading ? '加载中...' : (isLastPage ? '没有更多了' : '') }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 兑换福利卡 -->
|
||||
<view class="emptybox">
|
||||
<up-image :src="emptyImg" width="176rpx" height="204rpx" ></up-image>
|
||||
|
||||
<!-- 无卡空状态 -->
|
||||
<view v-else class="emptybox">
|
||||
<up-image :src="emptyImg" width="176rpx" height="204rpx"></up-image>
|
||||
<view class="empty_desc">暂无福利卡</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部导航栏 -->
|
||||
<view class="bottom-nav">
|
||||
<view class="nav-item" @click="goPointsDetail">
|
||||
<up-image :src="jifenImg" width="34rpx" height="34rpx" ></up-image>
|
||||
<up-image :src="jifenImg" width="34rpx" height="34rpx"></up-image>
|
||||
<text class="nav-text">兑换福利卡</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import jifenImg from "@/static/duihuan.png"
|
||||
import emptyImg from "@/static/icon_empty.png"
|
||||
// 当前选中的标签页
|
||||
const activeTab = ref(0);
|
||||
import api from '@/api/api';
|
||||
import { onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
|
||||
// 是否有福利卡以及示例卡信息
|
||||
const hasCard = ref(true)
|
||||
const cardInfo = ref([]);
|
||||
// 分页状态
|
||||
const pageNum = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const isLastPage = ref(false)
|
||||
const isLoading = ref(false)
|
||||
|
||||
const getMyWelfareCard = (opts = { isRefresh: false }) => {
|
||||
if (isLoading.value) return
|
||||
isLoading.value = true
|
||||
api.myWelfareCard({page: pageNum.value}).then(res => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
const list = Array.isArray(res.data.list) ? res.data.list : []
|
||||
if (opts.isRefresh) {
|
||||
cardInfo.value = list
|
||||
} else {
|
||||
cardInfo.value = pageNum.value === 1 ? list : cardInfo.value.concat(list)
|
||||
}
|
||||
hasCard.value = list.length > 0 || cardInfo.value.length > 0
|
||||
isLastPage.value = !!res.data.isLastPage
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false
|
||||
uni.stopPullDownRefresh()
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getMyWelfareCard()
|
||||
})
|
||||
|
||||
// 福利列表数据
|
||||
const benefitsList = ref([
|
||||
{
|
||||
type: 'points',
|
||||
title: '肝胆积分 (5个新随访)',
|
||||
condition: '赠送积分',
|
||||
requirement: '200积分',
|
||||
rewardType: '立即领取',
|
||||
rewardValue: ''
|
||||
},
|
||||
{
|
||||
type: 'video',
|
||||
title: '肝胆视频',
|
||||
condition: '再新增随访',
|
||||
requirement: '1个',
|
||||
rewardType: '赠送下载',
|
||||
rewardValue: '2集'
|
||||
},
|
||||
{
|
||||
type: 'courseware',
|
||||
title: '肝胆课件',
|
||||
condition: '再新增随访',
|
||||
requirement: '6个',
|
||||
rewardType: '赠送下载',
|
||||
rewardValue: '1篇'
|
||||
},
|
||||
{
|
||||
type: 'usb',
|
||||
title: '知识U盘',
|
||||
condition: '再新增随访 (年度计算)',
|
||||
requirement: '96个',
|
||||
rewardType: '赠送U盘',
|
||||
rewardValue: '1个'
|
||||
}
|
||||
]);
|
||||
// 下拉刷新
|
||||
onPullDownRefresh(() => {
|
||||
pageNum.value = 1
|
||||
isLastPage.value = false
|
||||
getMyWelfareCard({ isRefresh: true })
|
||||
})
|
||||
|
||||
// 上拉加载更多
|
||||
onReachBottom(() => {
|
||||
if (isLastPage.value || isLoading.value) return
|
||||
pageNum.value += 1
|
||||
getMyWelfareCard()
|
||||
})
|
||||
|
||||
// 方法
|
||||
const goBack = () => {
|
||||
@@ -117,49 +138,21 @@
|
||||
});
|
||||
};
|
||||
|
||||
const centerVisible = ref(false)
|
||||
const showRules = () => {
|
||||
uni.showToast({
|
||||
title: '福利规则',
|
||||
icon: 'none'
|
||||
});
|
||||
centerVisible.value = true
|
||||
};
|
||||
|
||||
const switchTab = (index) => {
|
||||
activeTab.value = index;
|
||||
// 这里可以根据标签页切换加载不同的数据
|
||||
uni.showToast({
|
||||
title: `切换到${['领取福利', '使用福利', '兑福利卡'][index]}`,
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
|
||||
const claimBenefit = (benefit) => {
|
||||
uni.showToast({
|
||||
title: `领取${benefit.title}`,
|
||||
icon: 'none'
|
||||
});
|
||||
const closeCenter = () => {
|
||||
centerVisible.value = false
|
||||
};
|
||||
|
||||
const goPointsDetail = () => {
|
||||
uni.showToast({
|
||||
title: '积分详情',
|
||||
icon: 'none'
|
||||
});
|
||||
uni.navigateTo({ url: '/pages_app/myWelfareCard/exchange' })
|
||||
};
|
||||
|
||||
const goBenefitDetail = () => {
|
||||
uni.showToast({
|
||||
title: '福利详情',
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
|
||||
const addPatient = () => {
|
||||
uni.showToast({
|
||||
title: '添加患者',
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
const goMyWelfare = () => {
|
||||
uni.navigateTo({ url: '/pages_app/myWelfare/myWelfare' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -196,7 +189,6 @@
|
||||
.benefits-page {
|
||||
min-height: 100vh;
|
||||
background-color: $bg-color;
|
||||
padding-top: $nav-height; // 为固定导航栏预留空间
|
||||
.emptybox{
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
@@ -330,7 +322,7 @@
|
||||
}
|
||||
.benefits-list {
|
||||
|
||||
|
||||
|
||||
.benefit-card {
|
||||
background: $white;
|
||||
border-radius: 20rpx;
|
||||
@@ -340,22 +332,6 @@
|
||||
overflow: hidden;
|
||||
border:2rpx solid #fff;
|
||||
|
||||
&.points {
|
||||
|
||||
}
|
||||
|
||||
&.video {
|
||||
|
||||
}
|
||||
|
||||
&.courseware {
|
||||
|
||||
}
|
||||
|
||||
&.usb {
|
||||
|
||||
}
|
||||
|
||||
.card-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -364,7 +340,6 @@
|
||||
z-index:0;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.card-content {
|
||||
@@ -388,7 +363,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding:0 40rpx;
|
||||
height: 220rpx;
|
||||
height: 220rpx;
|
||||
.left-section,
|
||||
.right-section {
|
||||
display: flex;
|
||||
@@ -420,6 +395,60 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 顶部横幅与卡片样式 */
|
||||
.top-banner{
|
||||
position: relative;
|
||||
height: 280rpx;
|
||||
background: linear-gradient(180deg,#ff6a4a 0%, #e93b2d 100%);
|
||||
border-bottom-left-radius: 40rpx;
|
||||
border-bottom-right-radius: 40rpx;
|
||||
@include shadow;
|
||||
.banner-text{
|
||||
position: absolute;
|
||||
left: 48rpx;
|
||||
top: 120rpx;
|
||||
color: #fff;
|
||||
.line1{font-size: 44rpx;font-weight: 600;}
|
||||
.line2{font-size: 36rpx;margin-top: 12rpx;}
|
||||
}
|
||||
.help-btn{
|
||||
position: absolute;
|
||||
right: 40rpx;
|
||||
top: 90rpx;
|
||||
background: rgba(255,255,255,.95);
|
||||
color: #e04835;
|
||||
border-radius: 999rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.card-wrapper{
|
||||
margin: 24rpx 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
@include shadow;
|
||||
overflow: hidden;
|
||||
.card-header{
|
||||
background: linear-gradient(90deg,#ff7e4a,#ff4d2e);
|
||||
color: #fff;
|
||||
padding: 24rpx 28rpx;
|
||||
font-size: 26rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.time{opacity:.95}
|
||||
}
|
||||
.card-body{
|
||||
padding: 34rpx 28rpx 40rpx;
|
||||
.benefit-line{
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
line-height: 56rpx;
|
||||
.index{color:#333}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-nav {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
@@ -449,4 +478,20 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 底部加载提示 */
|
||||
.loadmore-tip{
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
padding: 20rpx 0 120rpx; // 给底部按钮留出空间
|
||||
}
|
||||
|
||||
/* 居中模态框样式(复用兑换页风格) */
|
||||
.center-modal{position: fixed;left:0;right:0;top:0;bottom:0;background: rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index: 9999;}
|
||||
.center-modal-content{width: 640rpx;background:#fff;border-radius:24rpx;overflow:hidden;}
|
||||
.center-title{font-size: 32rpx;color:#333;text-align:center;padding:28rpx 24rpx 12rpx;font-weight:600;}
|
||||
.center-help{padding: 0 32rpx;display:flex;flex-direction:column;align-items:center;gap: 16rpx;color:#333;font-size:28rpx;line-height:1.6;}
|
||||
.center-actions{padding: 24rpx 24rpx 28rpx;}
|
||||
.center-btn{width:100%;height:88rpx;border-radius:999rpx;background:#e93b2d;color:#fff;font-size:30rpx;}
|
||||
</style>
|
||||
@@ -130,7 +130,7 @@
|
||||
// 跳转到修改密码页面
|
||||
const goToChangePassword = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages_app/pwdLogin/pwdLogin'
|
||||
url: '/pages_app/changePassword/index'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user