58412f8a by lttnew

会员缴费

1 parent 1d933336
......@@ -313,9 +313,16 @@ export function delInfo(perId) {
})
}
// 查询个人个人会员缴费列表
// export function getPaymentList(query) {
// return request({
// url: '/person/paymentRange/selectPageList',
// method: 'get',
// params: query
// })
// }
export function getPaymentList(query) {
return request({
url: '/person/paymentRange/selectPageList',
url: '/person/paymentRangeNew/list',
method: 'get',
params: query
})
......@@ -725,6 +732,12 @@ export function personalCommit(id) {
params: id
})
}
export function getNewCountByRangeId(rangeId) {
return request({
url: `/person/paymentNew/getNewCountByRangeId/${rangeId}`,
method: 'get',
})
}
export function delPayment(payIds) {
return request({
......@@ -746,14 +759,12 @@ export function delcertified(ids) {
})
}
export function editYear(id, year) {
return request({
url: `/person/payment/editYear/${id}`,
method: 'get',
params: {
year: year
}
})
export function editYear(data) {
return request({
url: `/person/paymentNew/editYear/${data.payId}?payId=${data.payId}&year=${data.year}`,
method: 'post',
params: data
})
}
export function editGroupYear(data) {
......@@ -1256,3 +1267,130 @@ export function checkPersonByPersonId(perId) {
method: 'get'
})
}
// 获取团体会员优惠政策
export function canUseDiscount(params) {
return request({
url: `/system/certifiedNew/canUseDiscount`,
method: 'get',
params
})
}
// 获取团体会员一年缴费价格
export function getMyMemberCertUnitFee(params) {
return request({
url: `/system/certifiedNew/getMyMemberCertUnitFee`,
method: 'get',
params
})
}
export function checkBusinessLicense(data) {
return request({
url: `/member/info/checkBusinessLicense`,
method: 'post',
params: data
})
}
// 生成团体订单renewYear
export function certifiedNew(params) {
return request({
url: `/system/certifiedNew/commit`,
method: 'post',
params
})
}
// 模拟回调
export function callBack2(orderId) {
return request({
url: `/system/certifiedNew/callBack2/${orderId}`
})
}
// 优惠政策回显
export function getZtxDiscountPolicy(params) {
return request({
url: '/system/config/getZtxDiscountPolicy',
method: 'get',
params
})
}
// 考官列表
export function listApi(params) {
return request({
url: `/member/examiner/list`,
method: 'get',
params
})
}
// 考官列表
export function examinerDel(id) {
return request({
url: `/member/examiner/${id}`,
method: 'delete'
})
}
// 添加考官
export function otherAdd(memId, ids) {
return request({
url: `/member/examiner/otherAdd/${memId}/${ids}`,
method: 'post'
})
}
export function commitExamPointApply(params) {
return request({
url: `/member/examPointApply/commit?selfSelect=${params.selfSelect}`,
method: 'post',
params
})
}
export function getMyStatus() {
return request({
url: `/member/examPointApply/getMyStatus`
})
}
// 个人会员缴费支付
export function goPay(id) {
return request({
url: `/person/paymentRangeNew/pay/${id}`,
method: 'post'
})
}
// 缴费单列表学员
export function listAPI(params) {
return request({
url: `/person/paymentNew/list`,
method: 'get',
params
})
}
// 删除学员
export function paymentNewDel(id) {
return request({
url: `/person/paymentNew/${id}`,
method: 'delete'
})
}
// 缴费单列表
export function memberInsertPersons(data) {
return request({
url: `/person/paymentNew/memberInsertPersons/${data.rangeId}/${data.year}/${data.idcCode}`,
method: 'post',
data
})
}
export function createMemberPayRange(data) {
return request({
url: `/person/paymentRangeNew/createMemberPayRange`,
method: 'post',
data
})
}
\ No newline at end of file
......
......@@ -42,7 +42,12 @@ page {
.text-primary{text-decoration: underline;}}
}
}
.flex{
display: flex;
}
.f-j-s{
justify-content: space-between;
}
.vipData{
font-size: 24rpx;padding: 10px 20px;box-sizing: border-box;
display: flex;background: #F7E7E8;
......@@ -205,55 +210,55 @@ page {
margin: 0 0 0 30rpx;padding: 0 40rpx;box-sizing: border-box;
}
text{font-size: 30rpx;padding:30rpx 0 0;box-sizing: border-box;}
}
.colorful {
width: 100rpx;
margin-right: 14rpx;
height: 100rpx;
line-height: 100rpx;
font-size: 44rpx;
color: #fff;
text-align: center;
border-radius: 50%;
}
.w100{width: 100%;}
.item {
display: flex;width: 100%;
background: #FFFFFF;box-sizing: border-box;
align-items: center;
border-radius: 15rpx;
margin: 0 0 26rpx;
padding:20rpx;position: relative;
}
.colorful {
width: 100rpx;
margin-right: 14rpx;
height: 100rpx;
line-height: 100rpx;
font-size: 44rpx;
color: #fff;
text-align: center;
border-radius: 50%;
}
.w100{width: 100%;}
.item {
display: flex;width: 100%;
background: #FFFFFF;box-sizing: border-box;
align-items: center;
border-radius: 15rpx;
margin: 0 0 26rpx;
padding:20rpx;position: relative;
.date{color: #999;font-size: 24rpx;}
.status{font-size: 28rpx;position: absolute;right: 30rpx;}
.name{font-size: 30rpx;margin-bottom: 10rpx;word-wrap: break-all;
text{font-size: 28rpx;color: #666;}
}
.icon {
width: 50rpx;
height: 50rpx;
margin-right: 20rpx;
}
&:nth-child(5n) .colorful {
background: #014A9F;
}
&:nth-child(5n+1) .colorful {
background: #AD181F;
}
&:nth-child(5n+2) .colorful {
background: #D3B267;
}
&:nth-child(5n+3) .colorful {
background: #3195F5;
}
&:nth-child(5n+4) .colorful {
background: #E79222;
}
}
.icon {
width: 50rpx;
height: 50rpx;
margin-right: 20rpx;
}
&:nth-child(5n) .colorful {
background: #014A9F;
}
&:nth-child(5n+1) .colorful {
background: #AD181F;
}
&:nth-child(5n+2) .colorful {
background: #D3B267;
}
&:nth-child(5n+3) .colorful {
background: #3195F5;
}
&:nth-child(5n+4) .colorful {
background: #E79222;
}
}
.photobox{}
.photo{width: 100rpx;margin-right: 14rpx;
......@@ -278,7 +283,7 @@ page {
.text-warning{color: #e6a23c;}
}
}
}
.stepItem{position: relative;
padding: 0 0 30rpx 30rpx;box-sizing: border-box;
......@@ -306,65 +311,65 @@ page {
font-size: 30rpx;}
}
}
.personitem {
background: #fff;
box-sizing: border-box;
margin-bottom: 30rpx;
.content-box {
display: flex;
align-items: center;
padding: 16rpx 30rpx;box-sizing: border-box;
border-radius: 15rpx;
justify-content: space-between;
.photobox {
position: relative;
}
.photo {
width: 100rpx;
object-fit: cover;
margin-right: 14rpx;
height: 100rpx;
border-radius: 50%;
}
.noborder {
border: none;
:deep(.uni-select) {
border: none;
text-align: right;
}
}
}
.flexbox {
align-items: center;
}
.date{font-size: 28rpx;color: #666;margin-top: 10rpx;}
&:nth-child(3n) .colorful {
background: #AD181F;
}
&:nth-child(3n+1) .colorful {
background: #014A9F;
}
&:nth-child(3n+2) .colorful {
background: #D3B267;
}
}
.colorful {
width: 100rpx;
margin-right: 14rpx;
height: 100rpx;
line-height: 100rpx;
font-size: 44rpx;
color: #fff;
text-align: center;
border-radius: 50%;
.personitem {
background: #fff;
box-sizing: border-box;
margin-bottom: 30rpx;
.content-box {
display: flex;
align-items: center;
padding: 16rpx 30rpx;box-sizing: border-box;
border-radius: 15rpx;
justify-content: space-between;
.photobox {
position: relative;
}
.photo {
width: 100rpx;
object-fit: cover;
margin-right: 14rpx;
height: 100rpx;
border-radius: 50%;
}
.noborder {
border: none;
:deep(.uni-select) {
border: none;
text-align: right;
}
}
}
.flexbox {
align-items: center;
}
.date{font-size: 28rpx;color: #666;margin-top: 10rpx;}
&:nth-child(3n) .colorful {
background: #AD181F;
}
&:nth-child(3n+1) .colorful {
background: #014A9F;
}
&:nth-child(3n+2) .colorful {
background: #D3B267;
}
}
.colorful {
width: 100rpx;
margin-right: 14rpx;
height: 100rpx;
line-height: 100rpx;
font-size: 44rpx;
color: #fff;
text-align: center;
border-radius: 50%;
}
.slot-button {
display: flex;
......
......@@ -4,9 +4,10 @@
// staging 会员系统
// const baseUrl_api = "http://22yidpjzjifv.ngrok.xiaomiqiu123.top/stage-api/";
const baseUrl_api = "https://ztx.itechtop.cn:8443/stage-api";
// const baseUrl_api = 'http://192.168.1.132:8787'
// const baseUrl_api = "https://ztx.itechtop.cn:8443/stage-api";
const baseUrl_api = 'http://192.168.1.154:8788'
// const baseUrl_api = 'https://tkcn.19wk.cn:8443/stage-api'
// const baseUrl_api = 'http://tk004.wxjylt.com/stage-api'
// const baseUrl_api = 'https://system.taekwondo.org.cn/stage-api'
export default {
......
<template>
<view class="container">
<!-- 搜索区域:固定在顶部 -->
<view class="search-area">
<view class="search-item">
<text>考官姓名:</text>
<input v-model="queryParams.name" placeholder="请输入考官姓名" class="search-input" />
</view>
<view class="search-item">
<text>考官编号:</text>
<input v-model="queryParams.certCode" placeholder="请输入考官编号" class="search-input" />
</view>
<view class="search-buttons">
<button class="search-btn" @click="handleQuery">查询</button>
<button class="reset-btn" @click="resetQuery">重置</button>
</view>
</view>
<view class="list-item" v-for="(item, index) in infoList" :key="item.perId">
<view class="info">
<view class="name">{{ item.name }} {{ item.perCode }}</view>
<view class="idc">证件号码:{{ item.idcCode }}</view>
<view class="reg">注册地:{{ item.memName }}</view>
</view>
<button
class="choose-btn"
:class="{ disabled: checkChosen(item) }"
@click="handleChoose(item)"
:disabled="checkChosen(item)"
>
{{ checkChosen(item) ? '已选择' : '选择' }}
</button>
</view>
<uni-popup ref="expirePopup" type="center" background-color="rgba(0,0,0,0.5)">
<view class="custom-modal">
<view class="modal-title">提示</view>
<view class="modal-content">该考官资质已过期,是否继续添加?</view>
<view class="modal-btns">
<button class="btn-cancel" @click="closeExpirePopup()">取消</button>
<button class="btn-confirm" @click="confirmAddExpireExaminer()">确定</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { ref, reactive, toRefs } from 'vue'
import { onLoad } from '@dcloudio/uni-app';
import * as api from '@/common/api.js'
import _ from 'lodash'
const props = defineProps({
isValidity: {
type: String,
default: '0'
}
})
const isValidity = ref('0')
const memId = ref('')
const chosen = ref([])
const expirePopup = ref(null)
const currentExpireItem = ref(null)
onLoad((option) => {
isValidity.value = option.isValidity
memId.value = option.memId
chosen.value = JSON.parse(option.chosen)
})
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
name: null,
certCode: null,
type: 1,
shenMemId: ''
}
})
const { queryParams } = toRefs(data)
const infoList = ref([])
const loading = ref(false)
const total = ref(0)
// 获取考官列表
async function getList() {
if (!queryParams.value.name)
return uni.showToast({ title: '请输入考官姓名', icon: 'none' })
if (queryParams.value.type == 1 && !queryParams.value.certCode)
return uni.showToast({ title: '请输入考官编号', icon: 'none' })
loading.value = true
const res = await api.getCoachList(queryParams.value)
infoList.value = res.rows
total.value = res.total
loading.value = false
if (infoList.value.length === 0) {
uni.showToast({ title: '请核实考官编号、有效期及归属地!', icon: 'none' })
}
}
// 检查是否已选择
function checkChosen(row) {
return _.some(chosen.value, (c) => {
return c.perId == row.perId
})
}
// 查询
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
// 重置
function resetQuery() {
queryParams.value.name = null
queryParams.value.certCode = null
infoList.value = []
total.value = 0
}
async function handleChoose(row) {
if (checkChosen(row)) {
return uni.showToast({ title: '已选择该考官', icon: 'none' })
}
// 资质过期逻辑
if (row.canChoose != 1) {
// 暂存当前考官数据
currentExpireItem.value = row
// 打开自定义过期确认弹窗
expirePopup.value.open()
return
}
}
// 关闭过期确认弹窗
function closeExpirePopup() {
expirePopup.value.close()
}
// 确认添加过期考官
async function confirmAddExpireExaminer() {
if (!currentExpireItem.value) return
try {
await api.otherAdd(memId.value, currentExpireItem.value.perId)
uni.showToast({ title: '添加成功', icon: 'success' })
uni.navigateBack({ delta: 1 })
} catch (err) {
uni.showToast({ title: '添加失败', icon: 'none' })
} finally {
expirePopup.value.close()
currentExpireItem.value = null
}
}
</script>
<style scoped>
.container {
display: flex;
flex-direction: column;
background: #f7f7f7;
min-height: 100vh;
padding: 0;
}
.search-area {
background: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
margin: 30rpx;
flex-shrink: 0;
}
.search-item {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.search-input {
flex: 1;
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 20rpx;
font-size: 28rpx;
}
.search-buttons {
display: flex;
justify-content: space-between;
margin-top: 10rpx;
}
.search-btn, .reset-btn {
width: 200rpx;
height: 70rpx;
line-height: 70rpx;
border-radius: 8rpx;
text-align: center;
font-size: 28rpx;
}
.search-btn {
background: #C4121B;
color: #fff;
}
.reset-btn {
background: #f7f7f7;
color: #333;
}
/* 列表区域:滚动 */
.list-area {
flex: 1;
background: #ffffff;
border-radius: 16rpx;
margin: 0 30rpx 30rpx;
padding: 0 30rpx;
}
.list-item {
padding: 30rpx;
margin: 0 30rpx;
border-bottom: 1rpx solid #eee;
background-color: #fff;
}
.info {
flex: 1;
}
.name {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.idc, .reg {
font-size: 26rpx;
color: #666;
margin: 20rpx 0;
}
.choose-btn {
color: #C4121B;
font-size: 26rpx;
border: 1rpx solid #C4121B;
border-radius: 8rpx;
padding: 10rpx 20rpx;
background-color: #fff;
margin: 10rpx auto;
}
.choose-btn.disabled {
color: #ccc;
border-color: #ccc;
}
/* 自定义弹窗样式(和之前保持统一) */
.custom-modal {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 40rpx 30rpx;
box-sizing: border-box;
text-align: center;
}
.modal-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
margin-bottom: 30rpx;
}
.modal-content {
font-size: 30rpx;
color: #666;
line-height: 1.6;
margin-bottom: 30rpx;
}
.modal-btns {
display: flex;
justify-content: space-between;
gap: 20rpx;
}
.btn-cancel {
flex: 1;
height: 80rpx;
line-height: 80rpx;
background: #f5f5f5;
color: #999;
border-radius: 40rpx;
font-size: 32rpx;
border: none;
}
.btn-confirm {
flex: 1;
height: 80rpx;
line-height: 80rpx;
background: #C4121B;
color: #fff;
border-radius: 40rpx;
font-size: 32rpx;
border: none;
}
/* 去除button默认边框 */
.btn-cancel::after, .btn-confirm::after {
border: none;
}
</style>
\ No newline at end of file
<template>
<view class="container">
<!-- 考官选择类型 -->
<view class="radio-section">
<radio-group @change="onSelfSelectChange" class="radio-group">
<label class="radio-item">
<radio value="1" :checked="form.selfSelect == '1'" class="custom-radio" />
<text class="radio-text">自行录入考官(级位考官)</text>
</label>
<label class="radio-item">
<radio value="0" :checked="form.selfSelect == '0'" class="custom-radio" />
<text class="radio-text">省跆协指派考官</text>
</label>
</radio-group>
</view>
<view class="section">
<!-- 自行录入考官区域 -->
<view class="section examiner-section" v-if="showExamine">
<button class="add-btn" @click="handelAddExamine">+ 添加考官</button>
</view>
<view class="examiner-list" v-if="showExamine">
<view class="examiner-item" v-for="(item, index) in list" :key="item.id">
<view class="info">
<text class="name">{{ item.perName }} {{ item.perCode }}</text>
<text class="idc">证件号码:{{ item.perIdcCode }}</text>
<text class="reg">注册地:{{ item.memName }}</text>
</view>
<button class="del-btn" @click="handleDel(item)">删除</button>
</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-area">
<button class="submit-btn" @click="handelSubmit">确定提交</button>
</view>
<!-- 自定义考点申请弹窗(替换原uni.showModal) -->
<uni-popup ref="applyPopup" type="center" background-color="rgba(0,0,0,0.5)">
<view class="custom-modal">
<view class="modal-title">考点申请</view>
<view class="modal-btns">
<button class="btn-cancel" @click="closeApplyPopup()">暂不申请</button>
<button class="btn-confirm" @click="confirmApply()">立即申请</button>
</view>
<view class="modal-tip">友情提示:非考点无法申请级位考试</view>
</view>
</uni-popup>
<!-- 自定义删除确认弹窗 -->
<uni-popup ref="delPopup" type="center" background-color="rgba(0,0,0,0.5)">
<view class="custom-modal">
<view class="modal-title">提示</view>
<view class="modal-content">确定删除该考官吗?</view>
<view class="modal-btns">
<button class="btn-cancel" @click="closeDelPopup()">取消</button>
<button class="btn-confirm" @click="confirmDel()">确定</button>
</view>
</view>
</uni-popup>
<!-- 自定义省跆协指派提示弹窗 -->
<uni-popup ref="assignPopup" type="center" background-color="rgba(0,0,0,0.5)">
<view class="custom-modal">
<view class="modal-title">温馨提示</view>
<view class="modal-content">关于考官指派,请联系河北省跆协,联系电话:XXXX</view>
<view class="modal-btns">
<button class="btn-confirm single-btn" @click="closeAssignPopup()">我知道了</button>
</view>
</view>
</uni-popup>
<!-- 自定义提交成功弹窗 -->
<uni-popup ref="successPopup" type="center" background-color="rgba(0,0,0,0.5)">
<view class="custom-modal">
<view class="modal-title">成功</view>
<view class="modal-content">提交成功,请等待审核</view>
<view class="modal-btns">
<button class="btn-confirm single-btn" @click="confirmSuccess()">确定</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { ref, } from 'vue'
import { onLoad,onShow } from '@dcloudio/uni-app'
import * as api from '@/common/api.js'
const form = ref({
selfSelect: '1' // 1:自行录入 0:省跆协指派
})
const showExamine = ref(true)
const loading = ref(false)
const list = ref([])
const memId = ref(null)
// 弹窗引用
const applyPopup = ref(null)
const delPopup = ref(null)
const assignPopup = ref(null)
const successPopup = ref(null)
let currentDelItem = ref(null)
onLoad((option) => {
memId.value = option.memId
getExaminer()
})
onShow(() => {
if (memId.value) {
getExaminer()
}
})
async function getExaminer() {
loading.value = true
const res = await api.listApi({ memId: memId.value })
list.value = res.rows
loading.value = false
}
// 删除考官:打开自定义弹窗
function handleDel(row) {
currentDelItem.value = row
delPopup.value.open()
}
// 确认删除
async function confirmDel() {
await api.examinerDel(currentDelItem.value.id)
uni.showToast({ title: '删除成功', icon: 'success' })
getExaminer()
closeDelPopup()
}
function closeDelPopup() {
delPopup.value.close()
}
// 切换考官类型:打开自定义提示弹窗
function onSelfSelectChange(e) {
form.value.selfSelect = e.detail.value
showExamine.value = e.detail.value == '1'
if (e.detail.value == '2') {
assignPopup.value.open()
}
}
function closeAssignPopup() {
assignPopup.value.close()
}
function handelAddExamine() {
const chosenStr = JSON.stringify(list.value)
uni.navigateTo({
url: `/myCenter/chooseExaminer?memId=${memId.value}&isValidity=0&chosen=${chosenStr}`
})
}
// 提交申请:打开自定义成功弹窗
async function handelSubmit() {
if (!form.value.selfSelect) {
return uni.showToast({ title: '请选择考官类型', icon: 'none' })
}
if (form.value.selfSelect == '1' && list.value.length == 0) {
return uni.showToast({ title: '请添加考官', icon: 'none' })
}
try {
await api.commitExamPointApply(form.value)
successPopup.value.open()
} catch (err) {
uni.showToast({ title: err.data.msg, icon: 'none' })
}
}
function confirmSuccess() {
successPopup.value.close()
uni.navigateBack()
}
// 考点申请弹窗(如需调用可在合适位置打开)
function openApplyPopup() {
applyPopup.value.open()
}
function closeApplyPopup() {
applyPopup.value.close()
}
function confirmApply() {
applyPopup.value.close()
// 此处添加考点申请逻辑
}
</script>
<style scoped>
/* 全局容器 */
.container {
min-height: 100vh;
}
.section{
padding:15rpx 20rpx;
}
/* 单选框区域 */
.radio-section {
background: #fff;
padding: 20rpx 15rpx;
margin-bottom: 10rpx;
border: none;
border-radius: 0;
}
.radio-group {
display: flex;
align-items: center;
gap: 30rpx;
}
.radio-item {
display: flex;
align-items: center;
margin: 0;
}
::v-deep .custom-radio .wx-radio-input {
width: 30rpx;
height: 30rpx;
border-radius: 50%;
}
::v-deep .custom-radio .wx-radio-input.wx-radio-input-checked {
border-color: #C4121B !important;
background: #C4121B !important;
}
.radio-text {
font-size: 14px;
color: #333;
margin-left: 8rpx;
}
/* 考官区域 */
.examiner-section {
background: #fff;
padding: 15rpx;
margin-bottom: 20rpx;
border: none;
border-radius: 0;
}
.add-btn {
background: #fff;
color: #C4121B;
border: 1rpx solid #C4121B;
border-radius: 10rpx;
padding: 10rpx 0;
width: 100%;
font-size: 14px;
}
.examiner-list {
padding: 0 10rpx;
background-color: #fff;
margin-bottom: 20rpx;
overflow-y: auto;
margin-bottom: 70px;
}
.examiner-item {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 20rpx;
border-bottom: 1rpx solid #eee;
align-items: center;
}
.info {
flex: 1;
}
.name {
font-size: 14px;
font-weight: 500;
color: #333;
display: block;
margin-bottom: 5rpx;
}
.idc, .reg {
font-size: 12px;
color: #666;
display: block;
margin: 10rpx 0;
}
.del-btn {
color: #C4121B;
font-size: 12px;
border: 1rpx solid #C4121B;
border-radius: 50rpx;
padding: 10rpx 25rpx;
line-height: 1.2;
background: #fff;
}
/* 提交按钮 */
.submit-area {
padding: 20rpx 0;
background-color: #fff;
width: 100%;
position: fixed;
bottom: 0;
}
.submit-btn {
width: 80%;
height: 88rpx;
border-radius: 44rpx;
margin: 0 auto;
line-height: 88rpx;
background: #C4121B;
color: #fff;
text-align: center;
font-size: 16px;
border: none;
}
/* 自定义弹窗样式(核心) */
.custom-modal {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 40rpx 30rpx;
box-sizing: border-box;
text-align: center;
}
.modal-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
margin-bottom: 30rpx;
}
.modal-content {
font-size: 30rpx;
color: #666;
line-height: 1.6;
margin-bottom: 30rpx;
}
.modal-tip {
font-size: 28rpx;
color: #FF7A00;
margin-top: 20rpx;
}
.modal-btns {
display: flex;
justify-content: space-between;
gap: 20rpx;
}
.btn-cancel {
flex: 1;
height: 80rpx;
line-height: 80rpx;
background: #f5f5f5;
color: #999;
border-radius: 40rpx;
font-size: 32rpx;
border: none;
}
.btn-confirm {
flex: 1;
height: 80rpx;
line-height: 80rpx;
background: #C4121B;
color: #fff;
border-radius: 40rpx;
font-size: 32rpx;
border: none;
}
.single-btn {
flex: 1;
}
.btn-cancel::after, .btn-confirm::after {
border: none;
}
</style>
\ No newline at end of file
<template>
<view class="container">
<!-- 主内容区域 -->
<view class="content">
<!-- 缴费年限 + 费用卡片 -->
<view class="card">
<!-- 缴费年限 -->
<view class="yearRow">
<view class="label">缴费年限</view>
<view class="control">
<image class="icon" @click="minusYear" src="/static/dd_02.png" mode="widthFix" v-if="form.renewYear > 1" ></image>
<image class="icon" src="/static/dd_02_g.png" mode="widthFix" v-else ></image>
<text class="num">{{ form.renewYear }}</text>
<image class="icon" src="/static/btn_03.png" mode="widthFix" @click="plusYear" v-if="form.renewYear < 5" ></image>
<image class="icon" src="/static/btn_03_g.png" mode="widthFix" v-else ></image>
</view>
</view>
</view>
<view class="card ">
<!-- 费用合计 -->
<view class="row ">
<text class="label">费用合计</text>
<text class="value red">{{ form.renewYear * memberFee }}</text>
</view>
<view class="hintRow" v-if="preferentialPolicy">
<text class="hintText">温馨提示:根据中国跆协{{ preferentialData.name || '优惠' }}政策减免一年费用,每个单位在政策有效期内只享受一次</text>
</view>
</view>
<view class="payRow ">
<radio-group @change="onPayTypeChange">
<label class="radioItem">
<radio value="1" :checked="payType === '1'" class="custom-radio" />
<view class="payInfo">
<image class="icon" src="/static/min.png" mode="widthFix"></image>
<text>民生付</text>
</view>
</label>
</radio-group>
</view>
<view class="totalRow ">
<text class="label">支付费用合计</text>
<text class="value redBig">{{ memberTotalFee }}</text>
</view>
</view>
<view class="bottomBtn">
<view class="deductRow">
<text class="label">减免费用</text>
<text class="value red">-{{ memberFee }}</text>
</view>
<button class="payBtn" @click="handelPay" :loading="isPaying">立即支付 ¥{{ memberTotalFee }}</button>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app';
import * as api from '@/common/api.js'
const form = ref({
renewYear: 1
})
const memberFee = ref(0)
const preferentialPolicy = ref(false)
const preferentialData = ref({ name: '优惠' })
const payType = ref('1')
const isPaying = ref(false)
const memberTotalFee = computed(() => {
if (preferentialPolicy.value) {
return memberFee.value * form.value.renewYear - memberFee.value * 1
} else {
return memberFee.value * form.value.renewYear
}
})
// 年限减
const minusYear = () => {
if (form.value.renewYear > 1) {
form.value.renewYear--
}
}
// 年限加
const plusYear = () => {
if (form.value.renewYear < 6) {
form.value.renewYear++
}
}
// 支付方式切换
const onPayTypeChange = (e) => {
payType.value = e.detail.value
}
// 支付操作
const handelPay = async () => {
// if (memberTotalFee.value <= 0) return
isPaying.value = true
const { data } = await api.certifiedNew({ renewYear: form.value.renewYear })
isPaying.value = false
if (data.payFlag == 0) {
uni.navigateTo({
url: `/myCenter/sucPay`
})
} else {
if (data.orderId) {
await callBack2(data.orderId)
uni.navigateTo({
url: `/myCenter/goPay`
})
}
}
}
onLoad((option) => {
// 接收年限
form.value.renewYear = Number(option.renewYear || 1)
// 初始化获取费用和优惠
init()
})
// 初始化接口
async function init() {
try {
await getMyMemberCertUnitFeeApi()
await canUseDiscountApi()
await getZtxDiscountPolicyApi()
} catch (err) {
console.error('初始化失败:', err)
}
}
// 获取会员单价
async function getMyMemberCertUnitFeeApi() {
const res = await api.getMyMemberCertUnitFee()
memberFee.value = Number(res.data || 1500)
}
// 是否可用优惠
async function canUseDiscountApi() {
const res = await api.canUseDiscount()
preferentialPolicy.value = res.data || true
}
// 获取优惠政策详情
async function getZtxDiscountPolicyApi() {
const res = await api.getZtxDiscountPolicy()
preferentialData.value = res.data || { name: '优惠' }
}
</script>
<style scoped>
/* 整体容器 */
.container {
min-height: 100vh;
background-color: #f7f7f7;
}
/* 内容区域 */
.content {
padding: 20rpx 20rpx 120rpx;
}
/* 卡片 */
.card {
background: #fff;
border-radius: 8rpx;
padding: 25rpx 20rpx;
margin-bottom: 20rpx;
}
/* 缴费年限行 */
.yearRow {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
}
.yearRow .label {
font-size: 28rpx;
color: #333;
}
.yearRow .control {
display: flex;
align-items: center;
}
.control image {
width: 50rpx;
height: 50rpx;
}
/* 加减按钮样式 */
.num-btn {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
border: 1rpx solid #C4121B;
}
.num-btn.disabled {
border-color: #ccc;
}
.num-btn.disabled .btn-icon {
color: #ccc;
}
.btn-icon {
font-size: 24rpx;
color: #C4121B;
font-weight: bold;
}
.yearRow .num {
font-size: 28rpx;
color: #333;
min-width: 80rpx;
text-align: center;
margin: 0 10rpx;
}
/* 通用行 */
.row {
display: flex;
justify-content: space-between;
align-items: center;
}
.row .label {
font-size: 28rpx;
color: #333;
}
.row .value {
font-size: 30rpx;
color: #C4121B;
font-weight: 500;
}
/* 优惠提示 */
.hintRow {
display: flex;
align-items: flex-start;
font-size: 24rpx;
line-height: 1.4;
}
.hint-icon {
width: 24rpx;
height: 24rpx;
border-radius: 50%;
background-color: #C4121B;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10rpx;
flex-shrink: 0;
margin-top: 2rpx;
}
.icon{
width:30px;
}
.icon-check {
color: #fff;
font-size: 16rpx;
}
.hintRow .hintText {
color: #FF8124;
flex: 1;
margin-top: 10rpx;
}
/* 减免费用 */
.deductRow {
background: #fff;
padding: 20rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
border-radius: 8rpx;
}
.deductRow .label {
font-size: 28rpx;
color: #333;
}
.deductRow .value {
font-size: 30rpx;
color: #C4121B;
}
/* 支付方式行 */
.payRow {
background: #fff;
border-radius: 8rpx;
padding: 20rpx 20rpx;
margin-bottom: 20rpx;
}
.radioItem {
display: flex;
align-items: center;
}
/* 自定义红色单选框 */
::v-deep .custom-radio .wx-radio-input {
width: 30rpx;
height: 30rpx;
border-radius: 50%;
border: 2rpx solid #ccc;
}
::v-deep .custom-radio .wx-radio-input.wx-radio-input-checked {
border-color: #C4121B !important;
background: #C4121B !important;
}
.payInfo {
display: flex;
align-items: center;
margin-left: 15rpx;
}
.payInfo .icon {
width: 40rpx;
height: 40rpx;
margin-right: 10rpx;
}
.payInfo text {
font-size: 28rpx;
color: #333;
}
/* 总费用行(突出显示) */
.totalRow {
background: #fff;
border-radius: 8rpx;
padding: 20rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10rpx;
}
.totalRow .label {
font-size: 28rpx;
color: #333;
}
.redBig {
font-size: 32rpx;
color: #C4121B;
font-weight: bold;
}
/* 底部按钮 */
.bottomBtn {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 20rpx;
background: #fff;
border-top: 1rpx solid #eee;
}
.payBtn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background-color: #C4121B;
color: #fff;
border-radius: 8rpx;
font-size: 32rpx;
text-align: center;
border: none;
}
.payBtn[disabled] {
background-color: #ccc;
color: #999;
}
/* 通用红色文字 */
.red {
color: #C4121B;
}
</style>
\ No newline at end of file
<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="/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>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app';
import * as api from '@/common/api.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)
// 订单ID存在则调用回调接口
if (res.data?.orderId) {
await api.callBack2(res.data.orderId)
}
// 跳转到支付成功页
uni.navigateTo({
url: `/pages/payOk/payOk?rangeId=${rangeId.value}`
})
} catch (err) {
console.error('支付失败:', err)
uni.showToast({ title: err.data.msg, 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>
\ No newline at end of file
<template>
<view class="success-container">
<!-- 成功图标(渐变圆形+动效) -->
<view class="success-icon">
<view class="icon-circle">
<text class="check-icon"></text>
</view>
</view>
<!-- 支付成功标题(动画) -->
<view class="success-title">支付成功</view>
<view class="success-subtitle">支付成功,请等待审核</view>
<!-- 订单信息卡片(带阴影) -->
<view class="info-card">
<view class="info-item">
<text class="label">付款账户</text>
<text class="value">(5437)</text>
</view>
<view class="info-item">
<text class="label">交易流水号</text>
<text class="value">2205051351076117833</text>
</view>
<view class="info-item">
<text class="label">商户名称</text>
<text class="value">中国跆拳道协会</text>
</view>
<view class="info-item">
<text class="label">订单金额</text>
<text class="value amount">1500.00元</text>
</view>
<view class="info-item">
<text class="label">会员编号</text>
<text class="value">CTA00004</text>
</view>
<view class="info-item">
<text class="label">会员有效期</text>
<text class="value">2028年1月25日</text>
</view>
</view>
<!-- 确定按钮(渐变+动效) -->
<view class="confirm-btn-area">
<button class="confirm-btn" @click="handleConfirm">确定</button>
</view>
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app'
// 确定按钮点击事件
const handleConfirm = () => {
uni.navigateBack({ delta: 1 })
// 也可跳转首页:uni.redirectTo({ url: '/pages/index/index' })
}
onLoad((option) => {
// 可接收订单参数动态渲染,示例:
// if (option.amount) { /* 赋值给金额变量 */ }
})
</script>
<style scoped>
/* 全局容器 */
.success-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 100rpx 40rpx 60rpx;
min-height: 100vh;
background-color: #f8f9fa;
box-sizing: border-box;
}
/* 成功图标容器 */
.success-icon {
margin-bottom: 40rpx;
animation: fadeIn 0.6s ease-out;
}
/* 渐变圆形背景 */
.icon-circle {
width: 180rpx;
height: 180rpx;
border-radius: 50%;
/* 青绿色渐变 */
background: linear-gradient(135deg, #06c1ae, #04a896);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 30rpx rgba(6, 193, 174, 0.3);
/* 轻微上浮动效 */
animation: scaleIn 0.8s ease-out;
}
/* 对勾图标 */
.check-icon {
font-size: 90rpx;
color: #ffffff;
font-weight: bold;
}
/* 支付成功标题 */
.success-title {
font-size: 48rpx;
font-weight: 700;
color: #333333;
margin-bottom: 12rpx;
animation: slideUp 0.6s ease-out;
}
/* 副标题 */
.success-subtitle {
font-size: 28rpx;
color: #666666;
margin-bottom: 60rpx;
animation: slideUp 0.8s ease-out;
}
/* 订单信息卡片 */
.info-card {
width: 100%;
background: #ffffff;
border-radius: 20rpx;
padding: 40rpx 30rpx;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.05);
margin-bottom: 80rpx;
animation: fadeIn 1s ease-out;
}
/* 单个信息项 */
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
/* 最后一项去掉下划线 */
.info-item:last-child {
border-bottom: none;
}
/* 标签样式 */
.label {
font-size: 32rpx;
color: #666666;
}
/* 值样式 */
.value {
font-size: 32rpx;
color: #333333;
text-align: right;
}
/* 金额特殊样式 */
.amount {
color: #cd1e27;
font-weight: 600;
}
/* 确定按钮区域 */
.confirm-btn-area {
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
}
/* 确定按钮(渐变+动效) */
.confirm-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
/* 按钮渐变背景 */
background: #fff;
color: #C4121B;
font-size: 36rpx;
font-weight: 600;
border-radius: 45rpx;
border: 1px solid #C4121B;
animation: slideUp 1s ease-out;
/* 禁止默认样式 */
position: relative;
overflow: hidden;
}
/* 按钮点击反馈 */
.confirm-btn::after {
border: none;
}
.confirm-btn:active {
transform: scale(0.98);
box-shadow: 0 4rpx 10rpx rgba(6, 193, 174, 0.2);
}
/* 动画定义 */
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes scaleIn {
0% { transform: scale(0); }
70% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes slideUp {
0% { opacity: 0; transform: translateY(30rpx); }
100% { opacity: 1; transform: translateY(0); }
}
</style>
\ No newline at end of file
......@@ -557,13 +557,48 @@
}
</script>
<style lang="scss" scoped>
<style lang="scss">
/* 字段名左对齐 */
.uni-forms-item .uni-forms-item__label {
text-align: left !important;
justify-content: flex-start !important;
padding-left: 0 !important;
width: auto !important;
}
/* 内容右对齐 */
.uni-forms-item .uni-forms-item__content {
display: flex !important;
align-items: center !important;
justify-content: flex-end !important;
text-align: right !important;
}
/* 输入框内容右对齐 */
.uni-forms-item .uni-easyinput .uni-easyinput__content-input,
.uni-forms-item .uni-easyinput input,
.uni-forms-item input,
.uni-forms-item .uni-data-select .uni-select__input-box,
.uni-forms-item .uni-data-picker .uni-data-picker__input-box {
text-align: right !important;
}
/* 文本内容右对齐 */
.uni-forms-item .uni-forms-item__content text,
.uni-forms-item .uni-forms-item__content > text {
text-align: right !important;
width: 100%;
display: block;
}
/* 覆盖原有样式 */
:deep(.uni-forms-item__content) {
display: flex;
align-items: center;
justify-content: flex-end;
justify-content: flex-end !important;
}
</style>
<style lang="scss" scoped>
:deep(.segmented-control) {
height: 100rpx;
}
......@@ -636,4 +671,4 @@
:deep(.item-text-overflow) {
text-align: left;
}
</style>
</style>
\ No newline at end of file
......
......@@ -5,37 +5,33 @@
<view class="info">
<view><text>{{list.length}}</text></view>
</view>
<!-- 成员 -->
<view class="userlist">
<view class="item" v-for="(n,index) in list" :key="index">
<view>
<view class="name">{{n.personName}}<text>({{n.memberInfoName}})</text></view>
<view class="date">原有效期至 {{n.originValidityDate?.slice(0,10)||'--'}}</view>
<view class="name">{{n.perName}}<text v-if="n.memberInfoName">({{n.memberInfoName || ''}})</text></view>
<view class="date">原有效期至 {{n.originValidityDate ? n.originValidityDate.slice(0,10) : '--'}}</view>
</view>
<view class="nian">
{{n.payYear}}
</view>
</view>
</view>
</view>
<view class="h3-padding" v-if="feelList.length>0">审核流程</view>
<view class="wBox" v-if="feelList.length>0">
<view class="stepItem" v-for="(n,index) in feelList" :key="index">
<view class="time">{{n.auditTime||'待审批'}}</view>
<view class="time">{{n.auditTime || '待审批'}}</view>
<view class="content">
<view class="status">
<view class="status">
<text v-if="n.auditResult==0" class="text-primary"> 审核中</text>
<text v-if="n.auditResult==1" class="text-success">审核通过</text>
<text v-if="n.auditResult==2" class="text-danger"> 审核拒绝</text>
<text v-if="n.auditResult==3" class="text-warning"> 已撤回</text>
</view>
<view class="name">{{index+1}}</view>
<view class="deptName">{{n.auditDeptName||n.auditBy}}</view>
<view>
备注:{{n.auditMsg||'/' }}
</view>
<view class="deptName">{{n.auditDeptName || n.auditBy}}</view>
<view>备注:{{n.auditMsg || '/' }}</view>
</view>
</view>
</view>
......@@ -44,47 +40,48 @@
<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import {
onMounted,
ref
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
// 查询参数(和PC保持一致)
const queryParams = ref({
// pageNum: 1,
// pageSize: 10
rangeId: '',
pageNum: 1,
pageSize: 999
})
const wfCode = ref('')
const form = ref([])
const form = ref({})
const list = ref([])
const feelList = ref([])
const total = ref(0)
onLoad((option) => {
if ('form' in option) {
if (option.form) {
form.value = JSON.parse(decodeURIComponent(option.form))
queryParams.value.rangeId = form.value.rangId || form.value.rangeId
getList()
getAuditLogs()
}
getFillList(form.value.rangId)
getPersons()
})
function getPersons() {
queryParams.value.rangeId = form.value.rangId
api.addSelectPageList(queryParams.value).then(res => {
list.value = res.pageData.rows
for (var l of list.value) {
if (l.photo && l.photo.indexOf('http') == -1) {
l.photo = config.baseUrl_api + l.photo
}
}
})
async function getList() {
try {
const res = await api.listAPI(queryParams.value)
list.value = res.rows || []
} catch (e) {
list.value = []
console.error('获取成员失败', e)
}
}
function getFillList(id) {
api.fillAuditLog(id).then(res => {
feelList.value = res.data
})
function getAuditLogs() {
if (form.value.auditLogs) {
try {
feelList.value = JSON.parse(form.value.auditLogs)
} catch (e) {
feelList.value = []
}
}
}
</script>
......@@ -107,12 +104,16 @@
.item {
border-bottom: 1px dashed #e5e5e5;
position: relative;
padding: 20rpx 0;
.date {
margin-top: 10rpx;
font-size: 24rpx;
color: #999;
}
.name {
font-size: 30rpx;
text {
margin-left: 1em;
color: #4C5359;
......@@ -123,6 +124,7 @@
.nian {
position: absolute;
right: 0;
top: 30rpx;
font-size: 30rpx;
color: #AD181F;
}
......@@ -137,10 +139,56 @@
view {
color: #7D8592;
margin-right: 20rpx;
text {
color: #AD181F;
}
}
}
.h3-padding {
padding: 20rpx 30rpx 0;
font-size: 30rpx;
font-weight: 500;
}
.stepItem {
border-left: 2rpx solid #E60012;
padding-left: 20rpx;
position: relative;
margin-bottom: 30rpx;
&:before {
content: '';
width: 12rpx;
height: 12rpx;
background: #E60012;
border-radius: 50%;
position: absolute;
left: -7rpx;
top: 0;
}
.time {
font-size: 24rpx;
color: #999;
}
.content {
margin-top: 10rpx;
font-size: 28rpx;
.status {
margin-bottom: 8rpx;
}
.name {
font-weight: 500;
}
.deptName {
margin: 6rpx 0;
color: #666;
}
}
}
</style>
\ No newline at end of file
......
......@@ -2,52 +2,52 @@
<view class="hasfixedbottom">
<view class="searchbar">
<uni-easyinput placeholderStyle="font-size:30rpx" :input-border="false" prefixIcon="search"
v-model="queryParams.personName" placeholder="搜索姓名或证件号码" @blur="getList" @clear="getList">
v-model="queryParams.perName" placeholder="搜索姓名或证件号码" @blur="getList" @clear="getList">
</uni-easyinput>
<view class="invertedbtn-red" @click="goVipList">+ 添加会员</view>
</view>
<view style="padding:0 20rpx">
<view class="vipData mtb30">
<view> 人数合计:<text>{{ formData.personCount? formData.personCount:0 }}</text></view>
<view> 新会员合计:<text>{{ formData.newPersonCount? formData.newPersonCount:0 }}</text></view>
<view> 续费会员合计:<text>{{ formData.oldPersonCount? formData.oldPersonCount:0 }}</text></view>
</view>
<view class="vipData mtb30">
<view> 人数合计:<text>{{ countData.all? countData.all:0 }}</text></view>
<view> 新会员合计:<text>{{ countData.new? countData.new:0 }}</text></view>
<view> 续费会员合计:<text>{{ countData.old? countData.old:0 }}</text></view>
</view>
<uni-swipe-action>
<uni-swipe-action-item class="personitem" v-for="(n,index) in list" :key="index">
<view class="content-box">
<view class="flexbox">
<!-- <view class="colorful">{{n.personName?.slice(0,1)}}</view> -->
<view>{{n.personName}}
<view class="date">
证件号:{{n.personIdcCode}}
<uni-swipe-action>
<uni-swipe-action-item class="personitem" v-for="(n,index) in list" :key="index">
<view class="content-box">
<view class="flexbox">
<view>{{n.perName}}
<view class="date">
证件号:{{n.perIdcCode}}
</view>
</view>
</view>
</view>
<view class="flexbox" @click="changeYear(n)">
<view class="text-danger">({{yearlist[n.payYear-1].text}})</view>
<uni-icons type="forward" size="18" color="#999"></uni-icons>
</view>
</view>
<template v-slot:right>
<view class="slot-button">
<view @click="handleDelete(n)">
<uni-icons type="trash-filled" color="#fff" size="20"></uni-icons>
<text class="slot-button-text">删除</text>
<view class="flexbox" @click="changeYear(n)">
<view class="text-danger">({{yearlist[n.payYear-1].text}})</view>
<uni-icons type="forward" size="18" color="#999"></uni-icons>
</view>
</view>
</template>
</uni-swipe-action-item>
</uni-swipe-action>
</view>
<template v-slot:right>
<view class="slot-button">
<view @click="handleDelete(n)">
<uni-icons type="trash-filled" color="#fff" size="20"></uni-icons>
<text class="slot-button-text">删除</text>
</view>
</view>
</template>
</uni-swipe-action-item>
</uni-swipe-action>
</view>
<view class="nodata" v-if="list.length==0">
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>请添加会员</text>
</view>
<view class="fixedBottom">
<button class="btn-red" :disabled="list?.length <= 0" @click="commitFN">保存并提交</button>
<button class="btn-red" :disabled="list?.length <= 0" @click="commitFN">保存并缴费</button>
</view>
<uni-popup ref="pickView" type="bottom">
......@@ -62,21 +62,17 @@
</template>
<script setup>
import {
ref
} from 'vue'
import {
onShow,
onLoad
} from '@dcloudio/uni-app'
import { ref } from 'vue'
import { onShow, onLoad } from '@dcloudio/uni-app'
import * as api from '@/common/api.js'
import config from '@/config.js'
const app = getApp()
const queryParams = ref({
rangeId: -1
rangeId: '',
pageNum: 1,
pageSize: 10,
})
const formData = ref({})
const list = ref({})
const countData = ref({})
const list = ref([])
const total = ref(0)
const nowYear = ref(1)
const nowItem = ref({})
......@@ -98,11 +94,13 @@
text: '五年',
value: 5
}])
onLoad((option) => {
if (option.rangeId) {
queryParams.value.rangeId = option.rangeId
}
})
onShow(() => {
if (app.globalData.isLogin) {
init()
......@@ -114,71 +112,89 @@
})
function init() {
console.log('init',queryParams.value.rangeId )
getList()
getCount()
}
function getList() {
api.addSelectPageList(queryParams.value).then(res => {
list.value = res.pageData.rows
total.value = res.pageData.total
formData.value = res
})
// 获取列表 + 统计(修复版)
async function getList() {
try {
const res = await api.listAPI(queryParams.value)
list.value = res.rows || []
total.value = res.total || 0
} catch (e) {
list.value = []
total.value = 0
}
// 只有 rangeId 合法时才获取统计(修复关键)
// if (queryParams.value.rangeId && queryParams.value.rangeId > 0) {
// await getCount()
// } else {
// // 清空统计
// countData.value = { all: 0, new: 0, old: 0 }
// }
}
// 获取统计
async function getCount() {
try {
const res = await api.getNewCountByRangeId(queryParams.value.rangeId)
countData.value = res.data || { all: 0, new: 0, old: 0 }
} catch (e) {
countData.value = { all: 0, new: 0, old: 0 }
}
}
function goVipList() {
let path = `/personalVip/vipList?rangeId=${queryParams.value.rangeId}`
uni.redirectTo({
url: path
});
uni.navigateTo({ url: path });
}
function changeYear(e) {
nowItem.value = e
nowYear.value = e.payYear
pickView.value.open()
}
function bindyear(n) {
// 修改年限
async function bindyear(n) {
nowYear.value = n.value
pickView.value.close()
nowItem.value.payYear = n.value
api.editYear(nowItem.value.payId, nowItem.value.payYear).then(res => {
for (var nn of list.value) {
if (nn.perId == nowItem.value.perId) {
nn.payYear = nowItem.value.payYear
}
}
await api.editYear({
payId: nowItem.value.payId,
year: nowItem.value.payYear
})
// 刷新列表和统计
await getList()
uni.showToast({ title: '操作成功' })
}
function handleDelete(row) {
// 删除(修复关键逻辑)
async function handleDelete(row) {
uni.showModal({
title: '提示',
content: `确定删除${row.personName}吗`,
success: function(res) {
content: `确定删除${row.perName}吗`,
success: async function(res) {
if (res.confirm) {
api.delPayment([row.payId]).then(res => {
uni.showToast({
title: '删除成功'
})
if (list.value.length == 1) {
queryParams.value.rangeId = -1
}
getList()
})
await api.paymentNewDel(row.payId)
uni.showToast({ title: '删除成功' })
getList()
}
}
})
}
function commitFN(){
if (queryParams.value.rangeId == -1) return
api.commitRenew(queryParams.value.rangeId).then(res=>{
uni.showToast({
title: '提交成功'
})
uni.navigateBack()
})
}
// 保存缴费
async function commitFN(){
if (!queryParams.value.rangeId) return
uni.navigateTo({
url: `/myCenter/payOrder?rangeId=${queryParams.value.rangeId}`
})
}
</script>
......@@ -186,10 +202,7 @@
.pickViewBox {
background-color: #fff;
text-align: center;
view {
line-height: 3;
}
view { line-height: 3; }
}
.searchbar {
......@@ -201,7 +214,7 @@
.invertedbtn-red {
margin-left: 15rpx;
font-size: 30rpx;
padding: 16rpx 20rpx;
padding: 10rpx 20rpx;
box-sizing: border-box;
border-radius: 50rpx;
background-color: #fff;
......@@ -238,47 +251,53 @@
margin-bottom: 30rpx;
.content-box {
display: flex;background-color: #fff;
display: flex;
background-color: #fff;
align-items: center;
padding: 16rpx;
border-radius: 15rpx;
justify-content: space-between;
.noborder {
border: none;
:deep(.uni-select) {
border: none;
text-align: right;
}
}
margin-bottom: 20rpx;
}
.flexbox {
align-items: center;
}
}
&:nth-child(3n) .colorful {
background: #014A9F;
}
.vipData {
padding: 10rpx 20rpx;
font-size: 28rpx;
color: #666;
view { margin-bottom: 10rpx; }
text { color: #AD181F; font-weight: bold; }
}
&:nth-child(3n+1) .colorful {
background: #AD181F;
}
.nodata {
text-align: center;
padding: 100rpx 0;
image { width: 200rpx; height: 200rpx; margin-bottom: 20rpx; }
text { font-size: 28rpx; color: #999; }
}
&:nth-child(3n+2) .colorful {
background: #D3B267;
}
.fixedBottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx;
background: #fff;
border-top: 1rpx solid #eee;
}
.colorful {
width: 100rpx;
margin-right: 14rpx;
height: 100rpx;
line-height: 100rpx;
font-size: 44rpx;
.btn-red {
width: 100%;
height: 80rpx;
line-height: 80rpx;
background: #E60012;
color: #fff;
text-align: center;
border-radius: 50%;
border-radius: 40rpx;
font-size: 32rpx;
border: none;
}
</style>
\ No newline at end of file
......
......@@ -7,18 +7,17 @@
</view>
<view class="indexboxre">
<view class="tt">会员列表<text class="text-danger">(列表只显示不在缴费中的个人会员)</text></view>
<!-- <uni-indexed-list :options="list" :showSelect="true" @click="bindClick"></uni-indexed-list> -->
<view class="userlist">
<view class="item" v-for="(n,index) in list" :key="index">
<view @click="checkThis(n)">
<image class="icon" v-if="n.checked" :src="config.baseUrl_api+'/fs/static/member/dx_dwn.png'" />
<image class="icon" v-else :src="config.baseUrl_api+'/fs/static/member/dx.png'" />
<view class="item" v-for="(n,index) in list" :key="index">
<view @click="checkThis(n)">
<image class="icon" v-if="n.checked" :src="config.baseUrl_api+'/fs/static/member/dx_dwn.png'" />
<image class="icon" v-else :src="config.baseUrl_api+'/fs/static/member/dx.png'" />
</view>
<view class="photobox">
<image class="photo" v-if="n.photo" :src="n.photo" mode='aspectFill'></image>
<view class="colorful" v-else>{{n.name.slice(0,1)}}</view>
</view>
<view @click="handleInfo(n)">
<view @click="handleInfo(n)">
<view class="name">{{n.name}}</view>
<view class="date" v-if="n.validityDate">到期时间:{{n.validityDate?.slice(0,10)}}</view>
<view class="date" v-else>注册时间:{{n.createTime?.slice(0,10)}}</view>
......@@ -40,25 +39,21 @@
过期
</text>
</view>
</view>
<view class="nodata" v-if="list.length==0">
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>暂无数据</text>
</view>
<view class="nodata" v-if="list.length==0">
<image mode="aspectFit" src="/static/nodata.png"></image>
<text>暂无数据</text>
</view>
</view>
</view>
<view class="fixedBottom" v-if="list.length>0">
<button class="btn-red" @click="handleImport">导入</button>
</view>
</view>
</template>
<script setup>
import * as api from '@/common/api.js'
import config from '@/config.js'
import {
ref,
......@@ -67,34 +62,46 @@
import {
onLoad
} from '@dcloudio/uni-app'
import * as api from '@/common/api.js'
const {
proxy
} = getCurrentInstance()
const app = getApp();
const queryParams = ref({
showMyPersonFlag: 1,
checkPaymentCommit: 1,
fromChoose: 1
showMyPersonFlag: 1,
checkPaymentCommit: 1,
fromChoose: 1,
pageNum: 1,
pageSize: 10,
paymentRangeId: -1,
name: '',
isBlack: 0,
// certStage: '',
validityDateRange: null
})
const list = ref([])
const total = ref(0)
const userType = ref('')
onLoad((option) => {
userType.value = app.globalData.userType
userType.value = app.globalData.userType
queryParams.value.paymentRangeId = option.rangeId
getList()
})
function getList() {
api.selectPageList(queryParams.value).then(res => {
list.value = res.rows
for(var l of list.value){
if(l.photo&&l.photo.indexOf('http')==-1){
l.photo = config.baseUrl_api + l.photo
}
async function getList() {
const res = await api.selectPageList(queryParams.value)
list.value = res.rows
// 处理图片路径
for(var l of list.value){
if(l.photo&&l.photo.indexOf('http')==-1){
l.photo = config.baseUrl_api + l.photo
}
total.value = res.total
})
// 初始化选中状态
l.checked = false
}
total.value = res.total
}
function handleInfo(n) {
......@@ -106,46 +113,59 @@
function goAddRenew() {
uni.navigateBack()
}
function checkThis(n){
if(n.checked){
n.checked = false
}else{
n.checked = true
}
}
function handleImport(){
var arr=[]
for(var n of list.value){
if(n.checked){
arr.push(n.perId)
}
}
if(arr.length==0){
uni.showToast({
title:"请选择会员",
icon:"none"
})
return
}
api.addPersonPaymentGroup({ rangeId: queryParams.value.paymentRangeId, personIdArray: arr.join(',') }).then(res=>{
let path = `/personalVip/renew?rangeId=${res.data.rangeId}`
uni.redirectTo({
url: path
});
})
function checkThis(n){
n.checked = !n.checked
}
async function handleImport(){
const arr = []
const idcCodeList = []
for(var n of list.value){
if(n.checked){
arr.push(n.perId)
idcCodeList.push(n.idcCode)
}
}
if(arr.length==0){
uni.showToast({
title:"请选择会员",
icon:"none"
})
return
}
try {
const res = await api.memberInsertPersons({
rangeId: queryParams.value.paymentRangeId,
year: 1,
idcCode: idcCodeList
})
uni.navigateBack()
uni.showToast({
title: '导入成功',
icon: 'success'
})
} catch (e) {
uni.showToast({
title: '导入失败',
icon: 'none'
})
console.error('批量添加失败:', e)
}
}
</script>
<style scoped lang="scss">
.indexboxre {
padding: 0 30rpx;
.tt {
font-size: 30rpx;
margin: 0 0 30rpx;
color: #4C5359;
color: #4C5359;
text{font-size: 26rpx;margin-left: 10px;}
}
......@@ -169,4 +189,92 @@
font-size: 26rpx;
}
}
.userlist {
.item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1px solid #f5f5f5;
.icon {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
}
.photobox {
margin-right: 20rpx;
.photo {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
.colorful {
width: 80rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
color: #fff;
border-radius: 50%;
font-size: 36rpx;
}
}
.name {
font-size: 32rpx;
font-weight: 500;
}
.date {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.status {
margin-left: auto;
font-size: 28rpx;
}
}
}
.nodata {
text-align: center;
padding: 100rpx 0;
image {
width: 200rpx;
height: 200rpx;
margin-bottom: 20rpx;
}
text {
font-size: 28rpx;
color: #999;
}
}
.fixedBottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx;
background: #fff;
border-top: 1px solid #eee;
.btn-red {
width: 100%;
height: 80rpx;
line-height: 80rpx;
background: #E60012;
color: #fff;
border-radius: 40rpx;
font-size: 32rpx;
border: none;
}
}
</style>
\ No newline at end of file
......
{
"appid": "wx5d51e8ed31bbdbb7",
"appid": "wx523ee37fff4fea9d",
"compileType": "miniprogram",
"libVersion": "3.0.0",
"packOptions": {
......@@ -19,11 +19,23 @@
"disablePlugins": [],
"outputPath": ""
},
"condition": false
"condition": false,
"compileWorklet": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"packNpmManually": false,
"minifyWXSS": true,
"minifyWXML": true,
"localPlugins": false,
"disableUseStrict": false,
"useCompilerPlugins": false,
"swc": false,
"disableSWC": true
},
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
},
"simulatorPluginLibVersion": {}
}
\ No newline at end of file
......
......@@ -2,6 +2,23 @@
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "Venue",
"setting": {
"compileHotReLoad": true
}
"compileHotReLoad": true,
"urlCheck": true,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,
"preloadBackgroundData": false,
"autoAudits": false,
"useApiHook": true,
"useApiHostProcess": true,
"showShadowRootInWxmlPanel": true,
"useStaticServer": false,
"useLanDebug": false,
"showES6CompileOption": false,
"checkInvalidKey": true,
"ignoreDevUnusedFiles": true,
"bigPackageSizeSupport": false
},
"libVersion": "3.15.0",
"condition": {}
}
\ No newline at end of file
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!