e0c6e843 by lttnew

开票

1 parent 8cf99911
......@@ -2264,4 +2264,16 @@ export function refundOrder(id) {
url: `/common/order/refundOrder/${id}`,
method: 'post'
})
}
/**
* 红冲
* @param params
* @returns {id}
*/
export function invoiceFastRed(id) {
return request({
url: `/common/order/invoiceFastRed/${id}`,
method: 'post'
})
}
\ No newline at end of file
......
// dev
// const baseUrl_api = 'http://192.168.1.222:8787'
const baseUrl_api = 'http://192.168.1.222:8787'
// const baseUrl_api = 'http://47.98.186.233:8787'
const baseUrl_api = 'https://tk001.wxjylt.com/stage-api/'
// const baseUrl_api = 'https://tk001.wxjylt.com/stage-api/'
const loginImage_api = 'https://tk001.wxjylt.com/stage-api'
const payUrl = 'https://wxpay.cmbc.com.cn/mobilePlatform/appserver/lcbpPay.do'
......
......@@ -51,39 +51,20 @@
<view class="card-header">
<view class="date">
<view class="data-header">
<text class="member-label">{{ tabs.find(t => t.type === currentTab)?.label }}·</text>
<text class="value ">{{ item.orderName || '——' }}</text>
<text class="member-label">{{ getOrderLabel(item) }} ·</text>
<text class="value ml10">{{ item.wfCode || '——' }} ·</text>
<text class="pay-type ml10">{{ String(item.payType) === '3' ? '对公转账' : '民生付' }}</text>
</view>
<text :class="{
'status-wait': item.auditStatus == 0,
'status-pending': item.auditStatus == 1,
'status-success': item.auditStatus == 2,
'status-danger': item.auditStatus == 3
'status-wait': item.payStatus == 3,
'status-pending': item.payStatus == 0,
'status-success': item.payStatus == 1,
'status-danger': item.payStatus == 2 || item.payStatus == 4
}"
class="status-tag ">{{ getAuditStatusText(item.auditStatus) }}
class="status-tag ">{{ getStatusText(item.payStatus) }}
</text>
</view>
</view>
<view class="card-header">
<view class="date">
<view class="data-header">
<text class="value">
<text class="tradeNo">订单编号:</text>
{{ item.tradeNo || '——' }}
</text>
</view>
</view>
</view>
<view class="card-header">
<view class="date">
<view class="data-header">
<text class="value">
<text class="tradeNo">缴费编号:</text>
{{ item.wfCode || '——' }}
</text>
</view>
</view>
</view>
<view class="member-time">
<view class="label">
<text class="star"></text>
......@@ -91,78 +72,25 @@
</view>
<view class="price">
<view>{{ item.price || '0.00' }}</view>
<view v-if="item.type==0" class="person">{{ item.content?.allPersonCount || 0 }}</view>
<view v-if="item.type==1" class="person">{{ item.content?.yearCount || 0 }}</view>
<view v-if="item.type==2||item.type==3||item.type==4" class="person">{{
item.content?.personCount || 0
}}
</view>
<view class="person">{{ getOrderCountText(item) }}</view>
</view>
</view>
<!-- 核心:前2tab仅展示缴费年限,后2tab仅展示人数合计 -->
<view v-if="item.content" class="info-section flex f-j-s">
<!-- 个人/单位会员(仅缴费年限) -->
<view v-if="currentTab === '0' || currentTab === '1'" class="single-info">
<view class="label">缴费年限:</view>
<view class="value">{{ item.content.yearCount || 0 }}</view>
</view>
<!-- 级位/段位考试(仅人数合计) -->
<view v-if="currentTab === '2' || currentTab === '3' || currentTab === '4'" class="single-info">
<view class="label">人数合计</view>
<view class="value">{{ item.content.personCount || 0 }}</view>
</view>
<view class="line"></view>
<view class="single-info">
<view class="label">订单状态</view>
<view :class="item.effect == 1 ? 'text-success' : 'text-warning'" class="value">
{{ item.effect == 1 ? '已生效' : '未生效' }}
</view>
</view>
<view class="line"></view>
<view class="single-info">
<view class="label">缴费状态</view>
<view
:class="{
'text-primary': item.payStatus == 0,
'text-success': item.payStatus == 1,
'text-danger': item.payStatus == 2
}"
class="value"
>
{{ item.payStatus == 0 ? '待缴费' : item.payStatus == 1 ? '缴费成功' : '订单取消' }}
</view>
</view>
</view>
<!-- 按钮组:靠右紧凑展示 -->
<view class="btn-group">
<view>
<text class="more" @click.stop="goToDetail(item)">更多</text>
</view>
<view class="btn-flex">
<!-- 已缴费:申请开票/已开票(需要审核通过才能开票) -->
<template>
<button class="btn btn-info" @click.stop="goToDetail(item)">查看明细</button>
<template v-if="isZtxRole">
<button :class="{ disabled: isRefundDisabled(item) }" :disabled="isRefundDisabled(item)" class="btn btn-pay" @click.stop="handleRefund(item)">退款</button>
</template>
<template v-else>
<button :class="{ disabled: isPayDisabled(item) }" :disabled="isPayDisabled(item)" class="btn btn-pay" @click.stop="handlePay(item)">支付</button>
<button v-if="canShowCancel(item)" :class="{ disabled: isCancelDisabled(item) }" :disabled="isCancelDisabled(item)" class="btn btn-cancel" @click.stop="handleCancel(item)">取消订单</button>
<template v-if="canShowInvoiceApply(item)">
<button :class="{ disabled: isInvoiceDisabled(item) }" :disabled="isInvoiceDisabled(item)" class="btn btn-view-invoice" @click.stop="makeInvoiceFN(item)">申请开票</button>
</template>
<!-- 已缴费:申请开票/已开票(需要审核通过才能开票) -->
<template v-if="item.payStatus == 1 && item.invoiceStatus != 1&& item.auditStatus == 2 &&item.price>0">
<button :disabled="item.invoiceStatus === 1" class="btn btn-view-invoice"
@click.stop="makeInvoiceFN(item)">
开票
</button>
</template>
<!-- 已开票:查看发票 -->
<template v-if="item.invoiceStatus == 1">
<template v-if="hasInvoice(item)">
<button class="btn btn-invoice" @click.stop="viewInvoice(item)">查看发票</button>
</template>
<!-- 未缴费:去缴费 + 取消订单 -->
<!-- <template v-if="item.payStatus == 0">
<button class="btn btn-cancel" @click="handleCancel(item)">取消订单</button>
<button class="btn btn-pay" @click="handlePay(item)">去缴费</button>
</template> -->
</view>
<button v-if="canShowReIssue(item)" :class="{ disabled: isReIssueDisabled(item) }" :disabled="isReIssueDisabled(item)" class="btn btn-view-invoice" @click.stop="handleReIssue(item)">重新开票</button>
</template>
</view>
</view>
</view>
......@@ -271,41 +199,11 @@ import dayjs from 'dayjs'
const deptType = ref(0);
// 标签栏配置(根据deptType动态生成)
const tabs = computed(() => {
const dt = Number(deptType.value)
console.log('tabs computed, deptType:', deptType.value, 'dt:', dt, 'dt===6:', dt === 6, 'dt==6:', dt == 6);
if (dt === 6) {
console.log('返回3个tab: 个人会员、单位会员、级位考试');
return [
{name: '个人会员', type: '0', label: "会员"},
{name: '单位会员', type: '1', label: "单位"},
{name: '级位考试', type: '2', label: "级位"}
];
} else if (dt === 2) {
console.log('返回3个tab: 单位会员、段位考试、越段考试');
return [
// {name: '单位会员', type: '1'},
{name: '段位考试', type: '3', label: "段位"},
{name: '越段考试', type: '4', label: "越段"}
];
} else if (dt === 1) {
console.log('返回默认5个tab, dt值为:', dt);
return [
{name: '个人会员', type: '0', label: "会员"},
{name: '单位会员', type: '1', label: "单位"},
{name: '级位考试', type: '2', label: "级位"},
{name: '段位考试', type: '3', label: "段位"},
{name: '越段考试', type: '4', label: "越段"}
];
} else {
return [
{name: '单位会员', type: '1', label: "单位"},
];
}
});
const currentTab = ref('0');
const tabs = [
{name: '段位考试', type: '3', label: "段位"},
{name: '越段考试', type: '4', label: "越段"}
];
const currentTab = ref('3');
// 数据与分页配置
const list = ref([]);
......@@ -318,7 +216,7 @@ const pageSize = ref(10);
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
type: '0',
type: '3',
queryType: '1',
// payStatus: ''
});
......@@ -338,13 +236,14 @@ const cancelModalContent = ref('');
// 当前操作的订单
const currentOrder = ref(null);
const isZtxRole = computed(() => Number(deptType.value) === 1)
// 页面挂载初始化
onLoad((option) => {
// 获取app实例和deptType
const app = getApp();
deptType.value = Number(app.globalData?.deptType || 0);
const firstType = tabs.value[0]?.type ?? '0';
const firstType = tabs[0]?.type ?? '3';
// currentTab.value = option.type || firstType;
// queryParams.type = option.type || firstType;
currentTab.value = firstType;
......@@ -390,7 +289,8 @@ const getStatusText = (status) => {
const map = {
0: '待缴费',
1: '缴费成功',
2: '订单取消'
2: '已取消',
4: '已退款'
};
return map[status] || '';
};
......@@ -401,7 +301,10 @@ const getAuditStatusText = (status) => {
0: '待提交',
1: '审核中',
2: '审核通过',
3: '审核拒绝'
3: '审核拒绝',
4: '已退回',
8: '已取消',
9: '待支付'
};
return map[status] || '';
};
......@@ -416,9 +319,57 @@ const filterType = (row) => {
if (row == 1) return '单位会员缴费办理'
if (row == 2) return '级位考试办理'
if (row == 3) return '段位考试办理'
if (row == 4) return '越考试办理'
if (row == 4) return '越考试办理'
}
const getOrderLabel = (item) => {
const map = {
3: '段位',
4: '越段'
}
return map[item?.type] || tabs.find(t => t.type === currentTab.value)?.label || '订单'
}
const getOrderCountText = (item) => {
return `共${item?.content?.personCount || 0}人`
}
const hasInvoice = (item) => String(item?.invoiceStatus) === '1'
const isPayDisabled = (item) => String(item?.auditStatus) !== '9'
const canShowCancel = (item) => String(item?.auditStatus) === '9'
const isCancelDisabled = (item) => String(item?.auditStatus) !== '9'
const canShowInvoiceApply = (item) => !hasInvoice(item)
const isInvoiceDisabled = (item) => {
return String(item?.payStatus) !== '1' ||
hasInvoice(item) ||
String(item?.auditStatus) !== '2' ||
Number(item?.price || 0) <= 0
}
const isWithinCalendarMonth = (dateValue) => {
if (!dateValue) return false
const date = dayjs(dateValue)
if (!date.isValid()) return false
return date.isSame(dayjs(), 'month')
}
const canShowReIssue = (item) => !isZtxRole.value && String(item?.auditStatus) !== '9'
const isReIssueDisabled = (item) => {
return !hasInvoice(item) ||
!isWithinCalendarMonth(item?.invoiceTime) ||
String(item?.payStatus) === '4' ||
String(item?.redFlag) === '1' ||
String(item?.payType) === '3'
}
const isRefundDisabled = (item) => String(item?.payStatus) !== '1' || hasInvoice(item)
// 数据请求核心方法
const initData = async () => {
......@@ -493,22 +444,15 @@ const confirmDel = async () => {
const goToDetail = (item) => {
console.log("goToDetail:", item);
console.log("currentTab.value", currentTab.value);
const form = encodeURIComponent(JSON.stringify(item))
switch (currentTab.value) {
case '1':
uni.navigateTo({url: `/group/groupOrderDetail?form=${form}`});
break;
case '2':
case '3':
case '4':
uni.navigateTo({url: `/pages/rank/applyDetail?examId=${item.sourceId || item.id}&type=${queryParams.type}`});
break;
case '0':
default:
uni.navigateTo({url: `/personalVip/orderDetail?rangeId=${item.sourceId || item.id}&type=${queryParams.type}`});
uni.navigateTo({url: `/pages/rank/applyDetail?examId=${item.sourceId || item.id}&type=${queryParams.type}`});
break;
}
// uni.navigateTo({url: `/pages/rank/applyDetail?examId=${item.sourceId || item.id}&type=${queryParams.type}`});
}
// 关闭删除弹窗
......@@ -520,17 +464,15 @@ const closeDelPopup = () => {
// 去缴费
const handlePay = async (item) => {
if (item.payStatus !== 0) return;
try {
await api.goPay({id: item.id});
uni.navigateTo({url: `/pages/pay/pay?orderId=${item.id}`});
} catch (e) {
uni.showToast({title: '发起支付失败', icon: 'none'});
}
if (isPayDisabled(item)) return;
uni.navigateTo({
url: `/level/paymentDetail?examId=${item.sourceId || item.id}&orderId=${item.id}`
});
};
// 申请开票
const makeInvoiceFN = (item) => {
if (isInvoiceDisabled(item)) return
// 开票条件:缴费成功 && 未开票 && 审核通过
// if (item.payStatus !== 1 || item.invoiceStatus === 1 || item.auditStatus !== 2) {
// return;
......@@ -549,6 +491,26 @@ const makeInvoiceFN = (item) => {
uni.navigateTo({ url });
};
const handleReIssue = async (item) => {
if (isReIssueDisabled(item)) return
const { confirm } = await uni.showModal({
title: '提示',
content: '开票后30天内仅可重开一次,是否确认重新开票?原发票将作废且无法恢复。'
})
if (!confirm) return
try {
uni.showLoading({ title: '处理中...' })
await api.invoiceFastRed(item.id)
uni.hideLoading()
await initData()
makeInvoiceFN({ ...item, invoiceStatus: '0' })
} catch (e) {
uni.hideLoading()
uni.showToast({ title: '重新开票失败', icon: 'none' })
}
}
// 查看发票
const viewInvoice = (item) => {
// 个人/单位会员(type 0或1)直接跳转webview页面展示发票
......@@ -590,8 +552,9 @@ const closeInvoiceWebview = () => {
// 取消订单
const handleCancel = (item) => {
if (isCancelDisabled(item)) return
currentOrder.value = item;
cancelModalContent.value = `是否确认取消订单编号为"${item.tradeNo}"的订单?`;
cancelModalContent.value = `是否确认取消缴费编号为"${item.wfCode}"的订单?`;
showCancelPopup.value = true;
isPopupOpen.value = true;
};
......@@ -600,7 +563,7 @@ const handleCancel = (item) => {
const confirmCancel = async () => {
if (!currentOrder.value) return;
try {
await api.cancelPay(currentOrder.value.id);
await api.cancelOrder(currentOrder.value.id);
uni.showToast({title: '取消成功', icon: 'success'});
pageNum.value = 1;
list.value = [];
......@@ -617,14 +580,38 @@ const closeCancelPopup = () => {
isPopupOpen.value = false;
currentOrder.value = null;
};
const handleRefund = async (item) => {
if (isRefundDisabled(item)) return
const { confirm } = await uni.showModal({
title: '提示',
content: `缴费编号为"${item.wfCode}"的订单是否确认退款?`
})
if (!confirm) return
try {
uni.showLoading({ title: '处理中...' })
await api.refundOrder(item.id)
uni.showToast({ title: '操作成功', icon: 'success' })
pageNum.value = 1
list.value = []
hasMore.value = true
await initData()
} catch (e) {
uni.showToast({ title: '退款失败', icon: 'none' })
} finally {
uni.hideLoading()
}
}
</script>
<style lang="scss" scoped>
.order-page {
background: #f5f7fa;
background: #ededf0;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
&.no-scroll {
overflow: hidden;
......@@ -677,18 +664,18 @@ const closeCancelPopup = () => {
// 标签栏样式
.tab-bar {
display: flex;
//background: #fff;
//border-bottom: 1rpx solid #eee;
flex-shrink: 0;
padding: 22rpx 70rpx 4rpx;
background: #ededf0;
.tab-item {
flex: 1;
text-align: center;
padding: 24rpx 0;
padding: 0 0 14rpx;
font-size: 30rpx;
color: #666;
position: relative;
font-weight: bold;
text-align: center;
&.active {
color: #c30d23;
......@@ -700,9 +687,8 @@ const closeCancelPopup = () => {
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 6rpx;
//background: linear-gradient(90deg, #FF755A, #F51722);
width: 72rpx;
height: 4rpx;
background: #c30d23;
border-radius: 2rpx;
}
......@@ -713,13 +699,17 @@ const closeCancelPopup = () => {
// 滚动列表容器
.order-list-scroll {
flex: 1;
height: auto;
overflow: auto;
height: 0;
min-height: 0;
overflow: hidden;
background: #ededf0;
}
// 订单列表
.order-list {
padding: 20rpx;
min-height: 100%;
box-sizing: border-box;
padding: 0 24rpx calc(180rpx + env(safe-area-inset-bottom));
.order-card {
background: #fff;
......@@ -919,30 +909,20 @@ const closeCancelPopup = () => {
// 按钮组
.btn-group {
display: flex;
justify-content: space-between;
justify-content: flex-end;
align-items: center;
gap: 16rpx;
width: 100%;
margin-top: 20rpx;
.more {
color: #666;
}
.btn-flex {
display: flex;
justify-content: flex-end;
gap: 16rpx;
}
margin-top: 16rpx;
flex-wrap: wrap;
.btn {
// 固定宽度,所有按钮一样大
width: 160rpx;
height: 50rpx;
line-height: 50rpx;
width: 140rpx;
height: 48rpx;
line-height: 48rpx;
padding: 0;
border-radius: 20rpx;
font-size: 28rpx;
border-radius: 10rpx;
font-size: 24rpx;
white-space: nowrap;
font-weight: bold;
border: none;
......@@ -977,7 +957,8 @@ const closeCancelPopup = () => {
&.btn-info {
color: #444;
border: 1rpx solid #666;
border: 1rpx solid #d7d7d7;
background: #fff;
}
&.btn-cancel {
......@@ -992,9 +973,13 @@ const closeCancelPopup = () => {
//border: none;
border: 1rpx solid #c30d23;
}
&:disabled {
opacity: 0.6;
&.disabled,
&[disabled] {
background: #f5f5f5 !important;
color: #b8b8b8 !important;
border: 1rpx solid #e1e1e1 !important;
opacity: 1;
pointer-events: none;
}
}
......@@ -1206,10 +1191,10 @@ const closeCancelPopup = () => {
.order-card-new {
background: #fff;
margin-bottom: 20rpx;
padding: 20rpx;
margin-bottom: 22rpx;
padding: 22rpx 18rpx 18rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
border-radius: 12rpx;
border-radius: 18rpx;
display: flex;
flex-direction: column;
......@@ -1233,6 +1218,8 @@ const closeCancelPopup = () => {
.data-header {
display: flex;
align-items: center;
min-width: 0;
}
.member-label {
......@@ -1243,13 +1230,19 @@ const closeCancelPopup = () => {
.value {
color: #000;
font-size: 28rpx;
font-size: 27rpx;
font-weight: bold;
.tradeNo {
color: #999;
font-size: 26rpx;
}
max-width: 460rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.pay-type {
color: #999;
font-size: 26rpx;
font-weight: normal;
flex-shrink: 0;
}
.date-text {
......@@ -1264,7 +1257,8 @@ const closeCancelPopup = () => {
}
.status-tag {
font-size: 26rpx;
font-size: 24rpx;
color: #999;
//padding: 6rpx 16rpx;
//border-radius: 20rpx;
......@@ -1317,22 +1311,27 @@ const closeCancelPopup = () => {
width: 100%;
display: flex;
justify-content: space-between;
padding-bottom: 10rpx;
padding-bottom: 4rpx;
.label {
max-width: 480rpx;
color: #555;
font-size: 26rpx;
color: #999;
font-weight: 700;
line-height: 1.4;
.star {
color: #000;
font-size: 28rpx;
color: #777;
font-size: 26rpx;
}
}
.price {
font-size: 30rpx;
color: #000;
font-weight: bold;
min-width: 130rpx;
color: #333;
font-size: 26rpx;
font-weight: 500;
text-align: right;
.person {
font-size: 24rpx;
......
......@@ -41,21 +41,27 @@
</view>
</view>
<view class="status-filter">
<view
v-for="(tab, index) in statusTabs"
:key="index"
:class="{ active: currentStatus === tab.type }"
class="status-filter-item"
@click="switchStatus(tab.type)"
>
{{ tab.name }}
<scroll-view
:show-scrollbar="false"
class="status-filter"
scroll-x
>
<view class="status-filter-inner">
<view
v-for="(tab, index) in statusTabs"
:key="index"
:class="{ active: currentStatus === tab.type }"
class="status-filter-item"
@click="switchStatus(tab.type)"
>
{{ tab.name }}
</view>
</view>
<!-- <view class="filter-entry">
<text class="filter-icon"></text>
<text>筛选</text>
</view> -->
</view>
</scroll-view>
<!-- 订单列表 -->
<scroll-view
......@@ -86,7 +92,7 @@
'status-wait': item.payStatus == 3,
'status-pending': item.payStatus == 0,
'status-success': item.payStatus == 1,
'status-danger': item.payStatus == 2
'status-danger': item.payStatus == 2 || item.payStatus == 4
}"
class="status-tag ">{{ getStatusText(item.payStatus) }}
</text>
......@@ -99,23 +105,23 @@
</view>
<view class="price">
<view>{{ item.price || '0.00' }}</view>
<view v-if="item.type==0" class="person">{{ item.content?.allPersonCount || 0 }}</view>
<view v-if="item.type==1" class="person">{{ item.content?.yearCount || 0 }}</view>
<view v-if="item.type==2||item.type==3||item.type==4" class="person">{{
item.content?.personCount || 0
}}
</view>
<view class="person">{{ getOrderCountText(item) }}</view>
</view>
</view>
<view class="btn-group">
<button :class="{ disabled: isPayDisabled(item) }" :disabled="isPayDisabled(item)" class="btn btn-pay" @click.stop="handlePay(item)">支付</button>
<button :class="{ disabled: isCancelDisabled(item) }" :disabled="isCancelDisabled(item)" class="btn btn-cancel" @click.stop="handleCancel(item)">取消订单</button>
<template v-if="!hasInvoice(item)">
<button :class="{ disabled: isInvoiceDisabled(item) }" :disabled="isInvoiceDisabled(item)" class="btn btn-view-invoice" @click.stop="makeInvoiceFN(item)">申请开票</button>
<template v-if="isZtxRole">
<button :class="{ disabled: isRefundDisabled(item) }" :disabled="isRefundDisabled(item)" class="btn btn-danger" @click.stop="handleRefund(item)">退款</button>
</template>
<template v-else>
<button class="btn btn-invoice" @click.stop="viewInvoice(item)">查看发票</button>
<button :class="{ disabled: isPayDisabled(item) }" :disabled="isPayDisabled(item)" class="btn btn-pay" @click.stop="handlePay(item)">支付</button>
<button v-if="canShowCancel(item)" :class="{ disabled: isCancelDisabled(item) }" :disabled="isCancelDisabled(item)" class="btn btn-cancel" @click.stop="handleCancel(item)">取消订单</button>
<template v-if="canShowInvoiceApply(item)">
<button :class="{ disabled: isInvoiceDisabled(item) }" :disabled="isInvoiceDisabled(item)" class="btn btn-view-invoice" @click.stop="makeInvoiceFN(item)">申请开票</button>
</template>
<template v-if="hasInvoice(item)">
<button class="btn btn-invoice" @click.stop="viewInvoice(item)">查看发票</button>
</template>
<button v-if="canShowReIssue(item)" :class="{ disabled: isReIssueDisabled(item) }" :disabled="isReIssueDisabled(item)" class="btn btn-danger" @click.stop="handleReIssue(item)">重新开票</button>
</template>
</view>
</view>
......@@ -229,47 +235,19 @@ import DaoGuanTabBar from '@/components/dao-guan-tab-bar.vue'
const deptType = ref(0);
// 标签栏配置(根据deptType动态生成)
const tabs = computed(() => {
const dt = Number(deptType.value)
console.log('tabs computed, deptType:', deptType.value, 'dt:', dt, 'dt===6:', dt === 6, 'dt==6:', dt == 6);
if (dt === 6) {
console.log('返回3个tab: 个人会员、单位会员、级位考试');
return [
{name: '个人会员', type: '0', label: "会员"},
{name: '单位会员', type: '1', label: "单位"},
{name: '级位考试', type: '2', label: "级位"}
];
} else if (dt === 2) {
console.log('返回3个tab: 单位会员、段位考试、越段考试');
return [
// {name: '单位会员', type: '1'},
{name: '段位考试', type: '3', label: "段位"},
{name: '越段考试', type: '4', label: "越段"}
];
} else if (dt === 1) {
console.log('返回默认5个tab, dt值为:', dt);
return [
{name: '个人会员', type: '0', label: "会员"},
{name: '单位会员', type: '1', label: "单位"},
{name: '级位考试', type: '2', label: "级位"},
{name: '段位考试', type: '3', label: "段位"},
{name: '越段考试', type: '4', label: "越段"}
];
} else {
return [
{name: '单位会员', type: '1', label: "单位"},
];
}
});
const tabs = [
{name: '个人会员', type: '0', label: "会员"},
{name: '单位会员', type: '1', label: "单位"},
{name: '级位考试', type: '2', label: "级位"}
];
const currentTab = ref('0');
const currentStatus = ref('');
const statusTabs = [
{ name: '全部', type: '' },
{ name: '待缴费', type: '0' },
{ name: '缴费成功', type: '1' },
{ name: '订单取消', type: '2' }
{ name: '已取消', type: '2' },
{ name: '已退款', type: '4' }
]
// 数据与分页配置
......@@ -303,13 +281,14 @@ const cancelModalContent = ref('');
// 当前操作的订单
const currentOrder = ref(null);
const isZtxRole = computed(() => Number(deptType.value) === 1)
// 页面挂载初始化
onLoad((option) => {
// 获取app实例和deptType
const app = getApp();
deptType.value = Number(app.globalData?.deptType || 0);
const firstType = tabs.value[0]?.type ?? '0';
const firstType = tabs[0]?.type ?? '0';
// currentTab.value = option.type || firstType;
// queryParams.type = option.type || firstType;
currentTab.value = firstType;
......@@ -364,18 +343,8 @@ const getStatusText = (status) => {
const map = {
0: '待缴费',
1: '缴费成功',
2: '订单取消'
};
return map[status] || '';
};
// 审核状态文本映射
const getAuditStatusText = (status) => {
const map = {
0: '待提交',
1: '审核中',
2: '审核通过',
3: '审核拒绝'
2: '已取消',
4: '已退款'
};
return map[status] || '';
};
......@@ -388,7 +357,7 @@ const getOrderLabel = (item) => {
3: '段位',
4: '越段'
}
return map[item.type] || tabs.value.find(t => t.type === currentTab.value)?.label || '订单'
return map[item.type] || tabs.find(t => t.type === currentTab.value)?.label || '订单'
}
const filterTime = (row) => {
......@@ -401,7 +370,14 @@ const filterType = (row) => {
if (row == 1) return '单位会员缴费办理'
if (row == 2) return '级位考试办理'
if (row == 3) return '段位考试办理'
if (row == 4) return '越位考试办理'
if (row == 4) return '越段考试办理'
}
const getOrderCountText = (item) => {
if (isPersonalOrder(item)) return `共${item?.content?.allPersonCount || 0}人`
if (isGroupOrder(item)) return `共${item?.content?.yearCount || 0}年`
if (isLevelOrder(item)) return `共${item?.content?.personCount || 0}人`
return ''
}
const getRowType = (item) => String(item?.type ?? currentTab.value)
......@@ -412,6 +388,11 @@ const isGroupOrder = (item) => getRowType(item) === '1'
const isLevelOrder = (item) => ['2', '3', '4'].includes(getRowType(item))
const canShowCancel = (item) => {
if (isGroupOrder(item)) return String(item?.auditStatus) === '0'
return String(item?.auditStatus) === '9'
}
const isPayDisabled = (item) => {
if (isPersonalOrder(item)) return String(item?.auditStatus) !== '9'
if (isLevelOrder(item)) return String(item?.auditStatus) !== '9'
......@@ -422,19 +403,43 @@ const isPayDisabled = (item) => {
const isCancelDisabled = (item) => {
if (isPersonalOrder(item)) return String(item?.auditStatus) !== '9'
if (isLevelOrder(item)) return String(item?.auditStatus) !== '9'
if (String(item?.payStatus) !== '0') return true
return false
return String(item?.payStatus) !== '0'
}
const hasInvoice = (item) => String(item?.invoiceStatus) === '1'
const canShowInvoiceApply = (item) => !hasInvoice(item)
const isInvoiceDisabled = (item) => {
if (hasInvoice(item)) return true
if (isPersonalOrder(item)) return String(item?.auditStatus) !== '2'
if (isPersonalOrder(item)) return String(item?.auditStatus) !== '2' || String(item?.payStatus) === '4'
if (isLevelOrder(item)) return String(item?.payStatus) !== '1' || String(item?.auditStatus) !== '2' || Number(item?.price || 0) <= 0
return String(item?.payStatus) !== '1' || String(item?.auditStatus) !== '2' || Number(item?.price || 0) <= 0
}
const isWithinCalendarMonth = (dateValue) => {
if (!dateValue) return false
const date = dayjs(dateValue)
if (!date.isValid()) return false
return date.isSame(dayjs(), 'month')
}
const canShowReIssue = (item) => {
if (isZtxRole.value) return false
if (isGroupOrder(item)) return String(item?.auditStatus) !== '0'
return String(item?.auditStatus) !== '9'
}
const isReIssueDisabled = (item) => {
return String(item?.invoiceStatus) !== '1' ||
!isWithinCalendarMonth(item?.invoiceTime) ||
String(item?.payStatus) === '4' ||
String(item?.redFlag) === '1' ||
String(item?.payType) === '3'
}
const isRefundDisabled = (item) => String(item?.payStatus) !== '1' || String(item?.invoiceStatus) === '1'
const encodeQueryValue = (value) => encodeURIComponent(value || '')
const getPayName = (item) => {
......@@ -576,6 +581,7 @@ const handlePay = async (item) => {
// 申请开票
const makeInvoiceFN = (item) => {
if (isInvoiceDisabled(item)) return
// 开票条件:缴费成功 && 未开票 && 审核通过
// if (item.payStatus !== 1 || item.invoiceStatus === 1 || item.auditStatus !== 2) {
// return;
......@@ -597,6 +603,26 @@ const makeInvoiceFN = (item) => {
uni.navigateTo({ url });
};
const handleReIssue = async (item) => {
if (isReIssueDisabled(item)) return
const { confirm } = await uni.showModal({
title: '提示',
content: '开票后30天内仅可重开一次,是否确认重新开票?原发票将作废且无法恢复。'
})
if (!confirm) return
try {
uni.showLoading({ title: '处理中...' })
await api.invoiceFastRed(item.id)
uni.hideLoading()
await initData()
makeInvoiceFN({ ...item, invoiceStatus: '0' })
} catch (e) {
uni.hideLoading()
uni.showToast({ title: '重新开票失败', icon: 'none' })
}
}
// 查看发票
const viewInvoice = (item) => {
// 个人/单位会员(type 0或1)直接跳转webview页面展示发票
......@@ -638,6 +664,7 @@ const closeInvoiceWebview = () => {
// 取消订单
const handleCancel = (item) => {
if (isCancelDisabled(item)) return
currentOrder.value = item;
cancelModalContent.value = `是否确认取消缴费编号为"${item.wfCode}"的订单?`;
showCancelPopup.value = true;
......@@ -666,6 +693,29 @@ const closeCancelPopup = () => {
currentOrder.value = null;
};
const handleRefund = async (item) => {
if (isRefundDisabled(item)) return
const { confirm } = await uni.showModal({
title: '提示',
content: `缴费编号为"${item.wfCode}"的订单是否确认退款?`
})
if (!confirm) return
try {
uni.showLoading({ title: '处理中...' })
await api.refundOrder(item.id)
uni.showToast({ title: '操作成功', icon: 'success' })
pageNum.value = 1
list.value = []
hasMore.value = true
await initData()
} catch (e) {
uni.showToast({ title: '退款失败', icon: 'none' })
} finally {
uni.hideLoading()
}
}
// 底部导航切换
const onTabSwitch = (index, url) => {
// tab switch handled by component
......@@ -813,14 +863,25 @@ const onTabSwitch = (index, url) => {
}
.status-filter {
display: flex;
align-items: center;
flex-shrink: 0;
padding: 10rpx 26rpx 18rpx;
background: #ededf0;
white-space: nowrap;
width: 100%;
box-sizing: border-box;
}
.status-filter-inner {
display: inline-flex;
align-items: center;
white-space: nowrap;
}
.status-filter-item {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
height: 48rpx;
line-height: 48rpx;
margin-right: 18rpx;
......@@ -829,6 +890,7 @@ const onTabSwitch = (index, url) => {
background: #fff;
color: #777;
font-size: 26rpx;
white-space: nowrap;
}
.status-filter-item.active {
......@@ -1129,6 +1191,12 @@ const onTabSwitch = (index, url) => {
border: 1rpx solid #c30d23;
}
&.btn-danger {
background: #fff;
color: #c30d23;
border: 1rpx solid #c30d23;
}
&.disabled,
&[disabled] {
background: #f5f5f5 !important;
......@@ -1393,6 +1461,8 @@ const onTabSwitch = (index, url) => {
.data-header {
display: flex;
align-items: center;
min-width: 0;
}
.member-label {
......@@ -1415,6 +1485,7 @@ const onTabSwitch = (index, url) => {
color: #999;
font-size: 26rpx;
font-weight: normal;
flex-shrink: 0;
}
.date-text {
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!