7d6c26f4 by 张猛

道馆个人,级位缴费

1 parent c1b557f6
......@@ -1429,12 +1429,11 @@ export function checkBusinessLicense(data) {
}
// 生成单位订单renewYear
export function certifiedNew(data) {
return request({
url: `/system/certifiedNew/commit`,
method: 'post',
params: data
})
export function certifiedNew(renewYear) {
return request({
url: `/system/certifiedNew/commit?renewYear=${renewYear}`,
method: 'post',
})
}
// 模拟回调
......@@ -1519,9 +1518,9 @@ export function getMyStatus() {
}
// 个人会员缴费支付
export function goPay(id) {
export function goPay(id, payType) {
return request({
url: `/person/paymentRangeNew/pay/${id}`,
url: `/person/paymentRangeNew/pay/${id}/${payType}`,
method: 'post'
})
}
......@@ -1728,11 +1727,11 @@ export function confirmExam(examId) {
}
// 提交级位考试订单
export function commitJiExam(data) {
export function commitJiExam(params) {
return request({
url: `/exam/person/commitJi`,
url: `/exam/info/commitJi/${params.id}/${params.addresId}/${params.payType}`,
method: 'post',
data
params
})
}
......
......@@ -23,7 +23,7 @@ const ERROR_MESSAGES = {
* @async
* @param {string} orderId - 订单ID,用于错误处理和取消订单
* @param {string} encryptedData - 加密数据
* @returns {Promise<void>}
* @returns {Promise<string>}
* @throws {Error} 支付过程中发生的错误
*/
async function minShengPay(orderId, encryptedData) {
......@@ -86,14 +86,13 @@ async function minShengPay(orderId, encryptedData) {
uni.hideLoading()
// 8. 调起微信支付
const [payErr] = await to(invokeWechatPayment(payParams, orderId))
const [payErr, paySuccess] = await to(invokeWechatPayment(payParams, orderId))
if (payErr) {
handlePaymentError(payErr, orderId)
}
// if (paySuccess) {
// return paySuccess
// }
if (paySuccess) {
return 'OK'
}
}
/**
......@@ -213,10 +212,10 @@ function invokeWechatPayment(payParams, orderId) {
signType: payParams.signType,
paySign: payParams.paySign,
success: (res) => {
resolve(res)
uni.showToast({
title: '支付成功',
duration: 2000,
complete: () => resolve(res)
})
},
fail: async (err) => {
......
<template>
<view>
<view class="searchbar">
<uni-easyinput placeholderStyle="font-size:30rpx" :input-border="false" prefixIcon="search"
v-model="queryParams.name" placeholder="搜索考级名称" @blur="getList" @clear="getList">
</uni-easyinput>
<view class="invertedbtn-red" v-if="isExam=='0'" @click="goAdd">+ 添加级位考试</view>
</view>
<view class="appList">
<view class="appItem" v-for="(item,index) in list" :key="item.examId || index">
<view class="status" @click="goDetail(item)">
<text v-if="item.status=='0'" class="text-primary">{{ item.statusStr }}</text>
<text v-if="item.status=='1'" class="text-primary">{{ item.statusStr }}</text>
<text v-if="item.status=='2'" class="text-success">{{ item.statusStr }}</text>
<text v-if="item.status=='3'" class="text-danger">{{ item.statusStr }}</text>
<text v-if="item.status=='4'" class="text-warning">{{ item.statusStr }}</text>
</view>
<view class="date" v-if="item.status!='0'&&item.submitTime">提交时间:{{item.submitTime}}</view>
<view class="mt0" @click="goDetail(item)"><text class="text-primary">{{item.examCode}}</text></view>
<view class="name mt0" @click="goDetail(item)">{{item.name}}</view>
<view class="pp esp">申请单位:{{item.memberName}}</view>
<view class="pp esp">考级日期:{{item.startTime.substring(0,16)}}{{item.endTime.substring(0,16)}}</view>
<view class="flexbox" @click="goDetail(item)">
<view>
申请日期
<view>{{item.applyTime.substring(0, 10)}}</view>
</view>
<view>
考官
<view>{{item.examinerNames}}</view>
</view>
<view>
通过人数
<view>{{item.pass}}</view>
</view>
</view>
<view class="func" v-if="item.status=='0'||item.status=='3'||item.status=='4'">
<button @click="handleDelete(item)">删除</button>
<button @click="editThis(item)">编辑</button>
<button :disabled="!(item.totalNum?item.totalNum:(item.pass+item.noPass))" @click="handleSubmit(item)">提交审核</button>
</view>
</view>
</view>
<view class="nodata" v-if="list.length==0">
<image mode="aspectFit" :src="config.baseUrl_api + '/fs/static/nodata.png'"></image>
<text>暂无数据</text>
</view>
</view>
<view>
<view class="searchbar">
<uni-easyinput v-model="queryParams.name" :input-border="false" placeholder="搜索考级名称"
placeholderStyle="font-size:30rpx" prefixIcon="search" @blur="getList" @clear="getList">
</uni-easyinput>
<view v-if="isExam=='0'" class="invertedbtn-red" @click="goAdd">+ 添加级位考试</view>
</view>
<view class="appList">
<view v-for="(item,index) in list" :key="item.examId || index" class="appItem">
<view class="status" @click="goDetail(item)">
<text v-if="item.status=='0'" class="text-primary">{{ item.statusStr }}</text>
<text v-if="item.status=='1'" class="text-primary">{{ item.statusStr }}</text>
<text v-if="item.status=='2'" class="text-success">{{ item.statusStr }}</text>
<text v-if="item.status=='3'" class="text-danger">{{ item.statusStr }}</text>
<text v-if="item.status=='4'" class="text-warning">{{ item.statusStr }}</text>
</view>
<view v-if="item.status!='0'&&item.submitTime" class="date">提交时间:{{ item.submitTime }}</view>
<view class="mt0" @click="goDetail(item)">
<text class="text-primary">{{ item.examCode }}</text>
</view>
<view class="name mt0" @click="goDetail(item)">{{ item.name }}</view>
<view class="pp esp">申请单位:{{ item.memberName }}</view>
<view class="pp esp">考级日期:{{ item.startTime?.substring(0, 16) }}{{ item.endTime?.substring(0, 16) }}
</view>
<view class="flexbox" @click="goDetail(item)">
<view>
申请日期
<view>{{ item.applyTime?.substring(0, 10) }}</view>
</view>
<view>
考官
<view>{{ item.examinerNames }}</view>
</view>
<view>
通过人数
<view>{{ item.pass }}</view>
</view>
</view>
<view v-if="item.status=='0'||item.status=='3'||item.status=='4'||item.status=='9'" class="func">
<button :disabled="item.status=='1'||item.status=='2'||item.status=='3'"
@click="handleDelete(item)">删除
</button>
<button :disabled="!(item.status=='0')" @click="editThis(item)">编辑</button>
<button :disabled="item.status!='0'&&item.status!='9'||item.totalNum==0||item.pass==0"
@click="handleSubmit(item)">
提交审核
</button>
</view>
</view>
</view>
<view v-if="list.length==0" class="nodata">
<image :src="config.baseUrl_api + '/fs/static/nodata.png'" mode="aspectFit"></image>
<text>暂无数据</text>
</view>
</view>
</template>
<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import {
onMounted,
ref
} from 'vue'
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
const app = getApp();
const queryParams = ref({
// pageNum: 1,
// pageSize: 10
type: '1',
rankStatus: '0'
})
const navs = ref(['未提交', '审核中', '审核通过', '审核拒绝'])
const current = ref()
const list = ref([])
const total = ref(0)
const deptType = ref('')
const userType = ref('')
const isExam = ref('1')
onShow(() => {
if (app.globalData.isLogin) {
init()
} else {
app.firstLoadCallback = () => {
init()
};
}
})
function init() {
uni.showLoading({
title: '加载中',
mask: true
})
deptType.value = app.globalData.deptType
userType.value = app.globalData.userType
isExam.value = app.globalData.isExam
getList()
}
function getList() {
api.getLevelList(queryParams.value).then(res => {
uni.hideLoading()
list.value = res.rows
total.value = res.total
})
}
function goAdd() {
let path = `/level/addApply`
uni.navigateTo({
url: path
});
}
function editThis(item) {
let path = `/level/addApply?examId=${item.examId}`
uni.navigateTo({
url: path
});
}
function handleSubmit(item) {
uni.showModal({
title: '提示',
content: `请确认人员照片是否已更新`,
success: function(res) {
if (res.confirm) {
// 跳转到付款详情页面
uni.navigateTo({
url: `/level/paymentDetail?examId=${item.examId}`
});
}
}
})
}
function handleDelete(row) {
uni.showModal({
title: '提示',
content: `确定删除${row.name}吗`,
success: function(res) {
if (res.confirm) {
uni.showLoading({
title: `删除中`
})
api.delLevel(row.examId).then(res=>{
uni.showToast({
title:'操作成功!',
icon:'none'
})
uni.hideLoading()
getList()
})
}
}
})
}
function upApply(id) {
api.submitVerity(id).then(res => {
uni.hideLoading()
getList()
uni.showToast({
title: `提交成功`
})
})
}
function goDetail(item) {
if (item.status != '0') {
let path = `/level/applyDetail?examId=${item.examId}`
uni.navigateTo({
url: path
});
} else {
// 去编辑
editThis(item)
}
}
import * as api from '@/common/api.js'
import config from '@/config.js'
import {
onMounted,
ref
} from 'vue'
import {
onLoad,
onShow
} from '@dcloudio/uni-app'
const app = getApp();
const queryParams = ref({
// pageNum: 1,
// pageSize: 10
type: '1',
rankStatus: '0'
})
const navs = ref(['未提交', '审核中', '审核通过', '审核拒绝'])
const current = ref()
const list = ref([])
const total = ref(0)
const deptType = ref('')
const userType = ref('')
const isExam = ref('1')
onShow(() => {
if (app.globalData.isLogin) {
init()
} else {
app.firstLoadCallback = () => {
init()
};
}
})
function init() {
uni.showLoading({
title: '加载中',
mask: true
})
deptType.value = app.globalData.deptType
userType.value = app.globalData.userType
isExam.value = app.globalData.isExam
getList()
}
function getList() {
api.getLevelList(queryParams.value).then(res => {
uni.hideLoading()
list.value = res.rows
total.value = res.total
})
}
function goAdd() {
let path = `/level/addApply`
uni.navigateTo({
url: path
});
}
function editThis(item) {
let path = `/level/addApply?examId=${item.examId}`
uni.navigateTo({
url: path
});
}
function handleSubmit(item) {
uni.showModal({
title: '提示',
content: `请确认人员照片是否已更新`,
success: function (res) {
if (res.confirm) {
// 跳转到付款详情页面
uni.navigateTo({
url: `/level/paymentDetail?examId=${item.examId}`
});
}
}
})
}
function handleDelete(row) {
uni.showModal({
title: '提示',
content: `确定删除${row.name}吗`,
success: function (res) {
if (res.confirm) {
uni.showLoading({
title: `删除中`
})
api.delLevel(row.examId).then(res => {
uni.showToast({
title: '操作成功!',
icon: 'none'
})
uni.hideLoading()
getList()
})
}
}
})
}
function upApply(id) {
api.submitVerity(id).then(res => {
uni.hideLoading()
getList()
uni.showToast({
title: `提交成功`
})
})
}
function goDetail(item) {
if (item.status != '0') {
let path = `/level/applyDetail?examId=${item.examId}`
uni.navigateTo({
url: path
});
} else {
// 去编辑
editThis(item)
}
}
</script>
<style scoped lang="scss">
.searchbar {
display: flex;
align-items: center;
padding: 25rpx;
box-sizing: border-box;
:deep(.uni-easyinput .uni-easyinput__content) {
border-radius: 35rpx;
border: none;
height: 70rpx;
}
:deep(.uni-easyinput__content-input) {
font-size: 26rpx;
}
.invertedbtn-red {
border-radius: 50px;
background-color: #fff;
font-size: 30rpx;
padding: 10rpx 20rpx;
}
}
.mt0 {
margin-top: 0 !important;
}
.appList .appItem .name {
width: 80%;
word-break: break-all;
}
<style lang="scss" scoped>
.searchbar {
display: flex;
align-items: center;
padding: 25rpx;
box-sizing: border-box;
:deep(.uni-easyinput .uni-easyinput__content) {
border-radius: 35rpx;
border: none;
height: 70rpx;
}
:deep(.uni-easyinput__content-input) {
font-size: 26rpx;
}
.invertedbtn-red {
border-radius: 50px;
background-color: #fff;
font-size: 30rpx;
padding: 10rpx 20rpx;
}
}
.mt0 {
margin-top: 0 !important;
}
.appList .appItem .name {
width: 80%;
word-break: break-all;
}
</style>
......
<template>
<view class="payment-page">
<!-- 加载状态 -->
<view class="loading-wrap" v-if="loading">
<view v-if="loading" class="loading-wrap">
<text>加载中...</text>
</view>
<view v-else>
<!-- 缴费单位卡片 -->
<view class="info-card">
......@@ -16,15 +16,15 @@
<view class="info-line sub">{{ deptInfo.aname || '--' }}</view>
</view>
</view>
<!-- 邮寄信息卡片 -->
<view class="info-card">
<view class="card-header">
<text class="card-title">邮寄信息</text>
<text class="manage-btn" @click="goAddressManage">管理地址</text>
</view>
<view class="address-content" v-if="selectedAddress.id" @click="goAddressManage">
<view v-if="selectedAddress.id" class="address-content" @click="goAddressManage">
<view class="address-region">
{{ selectedAddress.province }} {{ selectedAddress.city }} {{ selectedAddress.area }}
</view>
......@@ -33,57 +33,57 @@
</view>
<view class="address-contact">
{{ selectedAddress.name }} {{ selectedAddress.phone }}
<view class="default-tag" v-if="selectedAddress.defaultFlag == 1">默认</view>
<view v-if="selectedAddress.defaultFlag == 1" class="default-tag">默认</view>
</view>
</view>
<view class="empty-address" v-else @click="goAddressManage">
<view v-else class="empty-address" @click="goAddressManage">
<text class="empty-tip">请添加收货地址</text>
<text class="arrow"></text>
</view>
</view>
<!-- 考试信息卡片 -->
<view class="info-card">
<view class="card-header">
<text class="card-title">考试信息</text>
</view>
<view class="exam-info">
<view class="info-row">
<text class="label">人数合计</text>
<text class="value">{{ examData.allCount || 0 }}</text>
</view>
<view class="info-row level-row" v-if="levelTags.length > 0">
<view v-if="levelTags.length > 0" class="info-row level-row">
<text class="label">级别分布</text>
<view class="level-tags">
<view class="level-tag" v-for="tag in levelTags" :key="tag.level">
<view v-for="tag in levelTags" :key="tag.level" class="level-tag">
{{ tag.name }}{{ tag.count }}
</view>
</view>
</view>
<view class="info-row total-row">
<text class="label">费用合计</text>
<text class="value price">¥{{ (Number(examData.allFee) || 0).toFixed(2) }}</text>
</view>
</view>
</view>
<!-- 支付方式 -->
<view class="payment-section">
<view class="section-title">支付方式</view>
<view class="payment-methods">
<view class="payment-item selected">
<image class="icon" :src="config.baseUrl_api + '/fs/static/min.png'" mode="widthFix"></image>
<image :src="config.baseUrl_api + '/fs/static/min.png'" class="icon" mode="widthFix"></image>
<text class="payment-name">民生付</text>
<view class="check-icon"></view>
</view>
</view>
</view>
</view>
<!-- 底部提交按钮 -->
<view class="bottom-bar">
<view class="total-info">
......@@ -91,23 +91,24 @@
<text class="total-price">¥{{ (Number(examData.allFee) || 0).toFixed(2) }}</text>
</view>
<view
class="submit-btn"
:class="{ disabled: !selectedAddress.id }"
class="submit-btn"
@click="handleSubmit"
>
提交订单
</view>
</view>
<view class="tip-text" v-if="!selectedAddress.id">请先选择邮寄地址</view>
<view v-if="!selectedAddress.id" class="tip-text">请先选择邮寄地址</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { onLoad ,onShow} from '@dcloudio/uni-app';
import {ref, computed, onMounted} from 'vue';
import {onLoad, onShow} from '@dcloudio/uni-app';
import * as api from '@/common/api.js';
import config from '@/config.js'
import {minShengPay} from '@/common/pay.js';
const examId = ref('');
const loading = ref(true);
......@@ -145,7 +146,7 @@ onLoad((options) => {
// 获取全局用户信息
const app = getApp();
memberInfo.value = app.globalData.memberInfo || {};
});
onMounted(() => {
......@@ -164,10 +165,10 @@ onShow(() => {
}
});
const getName = async () => {
const res = await api.getMyOwnMemberInfo()
const res = await api.getMyOwnMemberInfo()
deptInfo.value = res.data.dept
}
const initData = async () => {
loading.value = true;
......@@ -179,7 +180,7 @@ const initData = async () => {
}
} catch (e) {
console.error('获取考试信息失败', e);
uni.showToast({ title: '加载失败', icon: 'none' });
uni.showToast({title: '加载失败', icon: 'none'});
} finally {
loading.value = false;
}
......@@ -204,63 +205,73 @@ const goAddressManage = () => {
const handleSubmit = async () => {
if (!selectedAddress.value.id) {
return uni.showToast({ title: '请先选择地址', icon: 'none' });
return uni.showToast({title: '请先选择地址', icon: 'none'});
}
uni.showModal({
title: '提示',
content: `确定提交订单吗?`,
success: async (res) => {
if (res.confirm) {
uni.showLoading({ title: '提交中...' });
uni.showLoading({title: '提交中...'});
try {
const commitRes = await api.commitJiExam({
addresId: selectedAddress.value.id,
id: examId.value
id: examId.value,
payType: '2'
});
if (commitRes.data && commitRes.data.orderId) {
// 有支付流程,调用支付
const payRes = await api.payJiExam(commitRes.data.orderId);
uni.hideLoading();
if (payRes.data && payRes.data.payResult && payRes.data.payResult.encryptedData) {
// 调用支付
uni.requestPayment({
provider: 'wxpay',
timeStamp: payRes.data.payResult.timeStamp,
nonceStr: payRes.data.payResult.nonceStr,
package: payRes.data.payResult.package,
signType: payRes.data.payResult.signType,
paySign: payRes.data.payResult.paySign,
success: () => {
uni.showToast({ title: '支付成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
},
fail: () => {
uni.showToast({ title: '支付失败', icon: 'none' });
}
});
} else {
// 无需支付,直接成功
uni.showToast({ title: '提交成功', icon: 'success' });
if (commitRes.data && commitRes.data.payResult.encryptedData) {
const res = await minShengPay(commitRes.data.orderId, commitRes.data.payResult.encryptedData)
if (res == 'OK') {
uni.showToast({title: '支付成功', icon: 'success'});
setTimeout(() => {
uni.navigateBack();
}, 1500);
}, 1500)
}
} else {
uni.hideLoading();
uni.showToast({ title: '提交成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
// if (commitRes.data && commitRes.data.orderId) {
// // 有支付流程,调用支付
// const payRes = await api.payJiExam(commitRes.data.orderId);
// uni.hideLoading();
//
// if (payRes.data && payRes.data.payResult && payRes.data.payResult.encryptedData) {
// // 调用支付
// uni.requestPayment({
// provider: 'wxpay',
// timeStamp: payRes.data.payResult.timeStamp,
// nonceStr: payRes.data.payResult.nonceStr,
// package: payRes.data.payResult.package,
// signType: payRes.data.payResult.signType,
// paySign: payRes.data.payResult.paySign,
// success: () => {
// uni.showToast({title: '支付成功', icon: 'success'});
// setTimeout(() => {
// uni.navigateBack();
// }, 1500);
// },
// fail: () => {
// uni.showToast({title: '支付失败', icon: 'none'});
// }
// });
// } else {
// // 无需支付,直接成功
// uni.showToast({title: '提交成功', icon: 'success'});
// setTimeout(() => {
// uni.navigateBack();
// }, 1500);
// }
// } else {
// uni.hideLoading();
// uni.showToast({title: '提交成功', icon: 'success'});
// setTimeout(() => {
// uni.navigateBack();
// }, 1500);
// }
} catch (e) {
uni.hideLoading();
console.error('提交失败', e);
uni.showToast({ title: '提交失败', icon: 'none' });
uni.showToast({title: '提交失败', icon: 'none'});
}
}
}
......@@ -291,7 +302,7 @@ const handleSubmit = async () => {
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.card-header {
display: flex;
justify-content: space-between;
......@@ -299,14 +310,14 @@ const handleSubmit = async () => {
padding-bottom: 20rpx;
margin-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
.card-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
position: relative;
padding-left: 20rpx;
&::before {
content: '';
position: absolute;
......@@ -319,19 +330,19 @@ const handleSubmit = async () => {
border-radius: 3rpx;
}
}
.manage-btn {
font-size: 28rpx;
color: #1561cb;
}
}
.card-content {
.info-line {
font-size: 30rpx;
color: #333;
margin-bottom: 8rpx;
&.sub {
font-size: 26rpx;
color: #999;
......@@ -344,13 +355,13 @@ const handleSubmit = async () => {
background: #f8f9fa;
padding: 24rpx;
border-radius: 12rpx;
.address-region {
font-size: 28rpx;
color: #666;
margin-bottom: 10rpx;
}
.address-detail {
font-size: 30rpx;
color: #333;
......@@ -358,14 +369,14 @@ const handleSubmit = async () => {
margin-bottom: 16rpx;
line-height: 1.5;
}
.address-contact {
display: flex;
align-items: center;
gap: 16rpx;
font-size: 26rpx;
color: #666;
.default-tag {
background: linear-gradient(135deg, #FF755A, #F51722);
color: #fff;
......@@ -383,12 +394,12 @@ const handleSubmit = async () => {
padding: 30rpx;
background: #f8f9fa;
border-radius: 12rpx;
.empty-tip {
font-size: 28rpx;
color: #999;
}
.arrow {
font-size: 36rpx;
color: #999;
......@@ -399,39 +410,39 @@ const handleSubmit = async () => {
.info-row {
display: flex;
margin-bottom: 24rpx;
&:last-child {
margin-bottom: 0;
}
.label {
width: 140rpx;
font-size: 28rpx;
color: #666;
flex-shrink: 0;
}
.value {
font-size: 28rpx;
color: #333;
font-weight: 500;
&.price {
color: #e4393c;
font-size: 36rpx;
font-weight: 600;
}
}
&.level-row {
align-items: flex-start;
.level-tags {
flex: 1;
display: flex;
flex-wrap: wrap;
gap: 12rpx;
.level-tag {
background: #fff0f0;
color: #e4393c;
......@@ -441,7 +452,7 @@ const handleSubmit = async () => {
}
}
}
&.total-row {
padding-top: 20rpx;
border-top: 1rpx dashed #eee;
......@@ -455,7 +466,7 @@ const handleSubmit = async () => {
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
.section-title {
font-size: 32rpx;
font-weight: 600;
......@@ -463,7 +474,7 @@ const handleSubmit = async () => {
margin-bottom: 20rpx;
position: relative;
padding-left: 20rpx;
&::before {
content: '';
position: absolute;
......@@ -476,41 +487,41 @@ const handleSubmit = async () => {
border-radius: 3rpx;
}
}
.payment-methods {
background: #f8f9fa;
border-radius: 12rpx;
padding: 20rpx;
.payment-item {
display: flex;
align-items: center;
padding: 16rpx;
border-radius: 12rpx;
border: 2rpx solid transparent;
&.selected {
border-color: #e4393c;
background: #fff;
.check-icon {
display: flex;
}
}
.payment-icon {
width: 48rpx;
height: 48rpx;
margin-right: 16rpx;
}
.payment-name {
flex: 1;
font-size: 30rpx;
color: #333;
font-weight: 500;
}
.check-icon {
width: 40rpx;
height: 40rpx;
......@@ -537,25 +548,25 @@ const handleSubmit = async () => {
padding: 20rpx 30rpx;
background: #fff;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
.total-info {
flex: 1;
display: flex;
align-items: baseline;
gap: 8rpx;
.total-label {
font-size: 28rpx;
color: #666;
}
.total-price {
font-size: 40rpx;
color: #e4393c;
font-weight: 600;
}
}
.submit-btn {
width: 240rpx;
height: 88rpx;
......@@ -566,18 +577,20 @@ const handleSubmit = async () => {
font-size: 32rpx;
border-radius: 44rpx;
font-weight: 500;
&.disabled {
opacity: 0.5;
pointer-events: none;
}
}
}
.icon {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
.tip-text {
position: fixed;
bottom: 130rpx;
......
......@@ -7,23 +7,25 @@
<text class="info-label">缴费单位</text>
<text class="info-value">{{ payName || '-' }}</text>
</view>
<view class="info-row" v-if="assoName">
<view v-if="assoName" class="info-row">
<text class="info-label">所属协会</text>
<text class="info-value">{{ assoName || '-' }}</text>
</view>
</view>
<view class="card">
<view class="yearRow">
<view class="label">缴费年限</view>
<view class="control">
<image v-if="form.renewYear > 1" class="icon" mode="widthFix" :src="config.baseUrl_api + '/fs/static/dd_02.png'"
<image v-if="form.renewYear > 1" :src="config.loginImage_api + '/fs/static/dd_02.png'" class="icon"
mode="widthFix"
@click="minusYear"></image>
<image v-else class="icon" mode="widthFix" :src="config.baseUrl_api + '/fs/static/dd_02_g.png'"></image>
<image v-else :src="config.loginImage_api + '/fs/static/dd_02_g.png'" class="icon" mode="widthFix"></image>
<text class="num">{{ form.renewYear }}</text>
<image v-if="form.renewYear < 5" class="icon" mode="widthFix" :src="config.baseUrl_api + '/fs/static/btn_03.png'"
<image v-if="form.renewYear < 5" :src="config.loginImage_api + '/fs/static/btn_03.png'" class="icon"
mode="widthFix"
@click="plusYear"></image>
<image v-else class="icon" mode="widthFix" :src="config.baseUrl_api + '/fs/static/btn_03_g.png'"></image>
<image v-else :src="config.loginImage_api + '/fs/static/btn_03_g.png'" class="icon" mode="widthFix"></image>
</view>
</view>
</view>
......@@ -47,7 +49,7 @@
<label class="radioItem">
<radio :checked="payType === '1'" class="custom-radio" value="1"/>
<view class="payInfo">
<image class="icon" mode="widthFix" :src="config.baseUrl_api + '/fs/static/min.png'"></image>
<image :src="config.baseUrl_api + '/fs/static/min.png'" class="icon" mode="widthFix"></image>
<text>民生付</text>
</view>
</label>
......@@ -84,6 +86,7 @@ import to from 'await-to-js'
import * as api from '@/common/api.js'
import {minShengPay} from '@/common/pay.js'
import config from '@/config.js'
const form = ref({
renewYear: 1
})
......@@ -132,20 +135,16 @@ const handelPay = async () => {
})
return
}
// 显示 loading
uni.showLoading({
title: '支付中...',
mask: true
})
if (isPaying.value) return
isPaying.value = true
// 创建订单 - 参考PC端逻辑
const [orderErr, orderRes] = await to(api.certifiedNew({
renewYear: form.value.renewYear,
type: '1',
url: ''
}))
const [orderErr, orderRes] = await to(api.certifiedNew(form.value.renewYear))
if (orderErr) {
uni.hideLoading()
isPaying.value = false
......@@ -155,7 +154,7 @@ const handelPay = async () => {
})
return
}
const data = orderRes.data
// 无需支付,直接成功
if (data.payFlag == 0) {
......@@ -168,11 +167,14 @@ const handelPay = async () => {
}
if (data.payResult && data.payResult.encryptedData) {
try {
await minShengPay(data.orderId, data.payResult.encryptedData)
// 支付成功,跳转到成功页面
uni.redirectTo({
url: `/myCenter/sucPay?orderId=${data.orderId}`
})
const res = await minShengPay(data.orderId, data.payResult.encryptedData)
if (res == 'OK') {
isPaying.value = false
// 支付成功,跳转到成功页面
uni.redirectTo({
url: `/myCenter/sucPay?orderId=${data.orderId}`
})
}
} catch (e) {
console.error('支付失败', e)
uni.hideLoading()
......@@ -185,12 +187,12 @@ const handelPay = async () => {
}
onLoad((option) => {
console.log(66,option)
console.log(66, option)
// 接收年限
form.value.renewYear = Number(option.renewYear || 1)
// 接收缴费单位和所属协会
payName.value = decodeURIComponent(option.payName || '')
console.log(77,payName.value)
console.log(77, payName.value)
assoName.value = decodeURIComponent(option.assoName || '')
// 初始化获取费用和优惠
init()
......@@ -237,7 +239,7 @@ async function getZtxDiscountPolicyApi() {
}
</script>
<style scoped lang="scss">
<style lang="scss" scoped>
/* 整体容器 */
.container {
min-height: 100vh;
......@@ -265,16 +267,16 @@ async function getZtxDiscountPolicyApi() {
align-items: center;
padding: 16rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.info-label {
font-size: 28rpx;
color: #666;
}
.info-value {
font-size: 28rpx;
color: #333;
......
<template>
<view class="pay-order-container">
<!-- 页面头部 -->
<view class="page-header">
<text class="title">确认并支付</text>
</view>
<!-- 订单核心信息 -->
<view class="order-info">
<view class="info-item">
<text class="label">人数合计:</text>
<text class="value red">{{ formData.all ?? 0 }}</text>
</view>
<view class="info-item">
<text class="label">新会员合计:</text>
<text class="value red">{{ formData.new ?? 0 }}</text>
</view>
<view class="info-item">
<text class="label">续费会员合计:</text>
<text class="value red">{{ formData.old ?? 0 }}</text>
</view>
<view class="info-item total-price">
<text class="label">支付总费用:</text>
<text class="value red">{{ formData.price ?? 0 }}</text>
</view>
</view>
<!-- 支付方式选择(修复v-model报错 + 默认勾选) -->
<view class="pay-type-section">
<text class="section-title">选择支付方式</text>
<!-- uni-app小程序原生radio-group写法 -->
<radio-group :value="payType" @change="handlePayTypeChange">
<label class="radio-item">
<!-- checked属性实现默认勾选 -->
<radio value="0" color="#E60012" :checked="payType === '0'" />
<view class="pay-method">
<image class="icon" :src="config.baseUrl_api + '/fs/static/min.png'" mode="widthFix"></image>
<text class="pay-name">民生付</text>
</view>
</label>
</radio-group>
</view>
<!-- 底部支付按钮 -->
<view class="fixed-bottom">
<button class="pay-btn red-bg" :loading="payLoading" @click="handlePay">立即支付</button>
</view>
</view>
<view class="pay-order-container">
<!-- 页面头部 -->
<view class="page-header">
<text class="title">确认并支付</text>
</view>
<!-- 订单核心信息 -->
<view class="order-info">
<view class="info-item">
<text class="label">人数合计:</text>
<text class="value red">{{ formData.all ?? 0 }}</text>
</view>
<view class="info-item">
<text class="label">新会员合计:</text>
<text class="value red">{{ formData.new ?? 0 }}</text>
</view>
<view class="info-item">
<text class="label">续费会员合计:</text>
<text class="value red">{{ formData.old ?? 0 }}</text>
</view>
<view class="info-item total-price">
<text class="label">支付总费用:</text>
<text class="value red">{{ formData.price ?? 0 }}</text>
</view>
</view>
<!-- 支付方式选择(修复v-model报错 + 默认勾选) -->
<view class="pay-type-section">
<text class="section-title">选择支付方式</text>
<!-- uni-app小程序原生radio-group写法 -->
<radio-group :value="payType" @change="handlePayTypeChange">
<label class="radio-item">
<!-- checked属性实现默认勾选 -->
<radio :checked="payType === '0'" color="#E60012" value="0"/>
<view class="pay-method">
<image :src="config.baseUrl_api + '/fs/static/min.png'" class="icon" mode="widthFix"></image>
<text class="pay-name">民生付</text>
</view>
</label>
</radio-group>
</view>
<!-- 底部支付按钮 -->
<view class="fixed-bottom">
<button :loading="payLoading" class="pay-btn red-bg" @click="handlePay">立即支付</button>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app';
import * as api from '@/common/api.js'
import config from '@/config.js'
// 核心数据
const formData = ref({}) // 订单统计数据
const rangeId = ref('') // 核心业务ID
const payType = ref('0') // 支付方式(默认0=民生付)
const payLoading = ref(false) // 支付按钮加载状态
// 页面加载接收参数
onLoad(async (options) => {
console.log('订单ID:', options.rangeId)
if (options.rangeId) {
rangeId.value = options.rangeId
await getCount()
}
})
async function getCount() {
try {
const res = await api.getNewCountByRangeId(rangeId.value)
formData.value = res.data || {
all: 0,
new: 0,
old: 0
}
} catch (e) {
formData.value = {
all: 0,
new: 0,
old: 0
}
}
}
// 支付方式切换
function handlePayTypeChange(e) {
payType.value = e.detail.value
}
// 立即支付核心逻辑
async function handlePay() {
// 基础校验
if (!rangeId.value || rangeId.value === '-1') {
return uni.showToast({
title: '订单ID异常',
icon: 'none'
})
}
try {
payLoading.value = true
const res = await api.goPay(rangeId.value)
if (res.data?.orderId) {
await api.pcallBack2(res.data.orderId)
uni.redirectTo({
url: `/myCenter/sucPay?rangeId=${rangeId.value}from=payOrder`
})
}
// 跳转到支付成功页
} catch (err) {
const errMsg = err?.data?.msg || err?.message || '支付失败,请稍后重试'
uni.showToast({
title: errMsg,
icon: 'none'
})
} finally {
payLoading.value = false
}
}
import {
ref
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app';
import * as api from '@/common/api.js'
import config from '@/config.js'
import {minShengPay} from "@/common/pay";
// 核心数据
const formData = ref({}) // 订单统计数据
const rangeId = ref('') // 核心业务ID
const payType = ref('0') // 支付方式(默认0=民生付)
const payLoading = ref(false) // 支付按钮加载状态
// 页面加载接收参数
onLoad(async (options) => {
console.log('订单ID:', options.rangeId)
if (options.rangeId) {
rangeId.value = options.rangeId
await getCount()
}
})
async function getCount() {
try {
const res = await api.getNewCountByRangeId(rangeId.value)
formData.value = res.data || {
all: 0,
new: 0,
old: 0
}
} catch (e) {
formData.value = {
all: 0,
new: 0,
old: 0
}
}
}
// 支付方式切换
function handlePayTypeChange(e) {
payType.value = e.detail.value
}
// 立即支付核心逻辑
async function handlePay() {
// 基础校验
if (!rangeId.value || rangeId.value === '-1') {
return uni.showToast({
title: '订单ID异常',
icon: 'none'
})
}
try {
payLoading.value = true
const res = await api.goPay(rangeId.value, '2')
if (res.data.payResult && res.data.payResult.encryptedData) {
const reason = await minShengPay(res.data.orderId, res.data.payResult.encryptedData)
if (reason == 'OK') {
// // 支付成功,跳转到成功页面
// uni.redirectTo({
// url: `/myCenter/sucPay?orderId=${res.data.orderId}`
// })
uni.showToast({title: '支付成功', icon: 'success'});
setTimeout(() => {
uni.navigateBack();
}, 1500)
}
}
// 跳转到支付成功页
} catch (err) {
const errMsg = err?.data?.msg || err?.message || '支付失败,请稍后重试'
uni.showToast({
title: errMsg,
icon: 'none'
})
} finally {
payLoading.value = false
}
}
</script>
<style scoped lang="scss">
.pay-order-container {
padding: 30rpx;
background-color: #fff;
min-height: 100vh;
box-sizing: border-box;
}
.icon {
width: 30px;
}
// 页面头部
.page-header {
text-align: center;
padding: 20rpx 0;
border-bottom: 1px solid #eee;
margin-bottom: 40rpx;
.title {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
}
// 订单信息区域
.order-info {
margin-bottom: 60rpx;
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 25rpx 0;
border-bottom: 1px solid #f5f5f5;
font-size: 32rpx;
.label {
color: #666;
}
.value {
font-weight: 600;
font-size: 34rpx;
}
.red {
color: #E60012;
}
}
.total-price {
border-bottom: none;
margin-top: 10rpx;
.label {
font-size: 34rpx;
color: #333;
}
.value {
font-size: 38rpx;
}
}
}
// 支付方式区域
.pay-type-section {
margin-bottom: 80rpx;
.section-title {
font-size: 32rpx;
color: #333;
margin-bottom: 20rpx;
display: block;
}
.radio-item {
display: flex;
align-items: center;
font-size: 32rpx;
padding: 10rpx 0;
.pay-method {
display: flex;
align-items: center;
margin-left: 10rpx;
.pay-name {
font-size: 32rpx;
margin-left: 20rpx;
color: #333;
}
}
}
}
// 底部支付按钮
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 30rpx 30rpx;
background-color: #fff;
border-top: 1px solid #eee;
.pay-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
font-size: 34rpx;
font-weight: 600;
}
.red-bg {
background-color: #E60012;
color: #fff;
}
}
<style lang="scss" scoped>
.pay-order-container {
padding: 30rpx;
background-color: #fff;
min-height: 100vh;
box-sizing: border-box;
}
.icon {
width: 30px;
}
// 页面头部
.page-header {
text-align: center;
padding: 20rpx 0;
border-bottom: 1px solid #eee;
margin-bottom: 40rpx;
.title {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
}
// 订单信息区域
.order-info {
margin-bottom: 60rpx;
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 25rpx 0;
border-bottom: 1px solid #f5f5f5;
font-size: 32rpx;
.label {
color: #666;
}
.value {
font-weight: 600;
font-size: 34rpx;
}
.red {
color: #E60012;
}
}
.total-price {
border-bottom: none;
margin-top: 10rpx;
.label {
font-size: 34rpx;
color: #333;
}
.value {
font-size: 38rpx;
}
}
}
// 支付方式区域
.pay-type-section {
margin-bottom: 80rpx;
.section-title {
font-size: 32rpx;
color: #333;
margin-bottom: 20rpx;
display: block;
}
.radio-item {
display: flex;
align-items: center;
font-size: 32rpx;
padding: 10rpx 0;
.pay-method {
display: flex;
align-items: center;
margin-left: 10rpx;
.pay-name {
font-size: 32rpx;
margin-left: 20rpx;
color: #333;
}
}
}
}
// 底部支付按钮
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 30rpx 30rpx;
background-color: #fff;
border-top: 1px solid #eee;
.pay-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
font-size: 34rpx;
font-weight: 600;
}
.red-bg {
background-color: #E60012;
color: #fff;
}
}
</style>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!