842a6ff2 by lttnew

个人订单

1 parent 256a8622
// dev
// const baseUrl_api = 'http://192.168.1.125:8787'
const baseUrl_api = 'http://192.168.1.134: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'
......
......@@ -110,10 +110,13 @@
const searchNoData = ref(false)
const pageType = ref('')
onLoad((option) => {
if(option.pageType ){
if(option.pageType){
pageType.value = option.pageType || ''
}else{
}
if(option.chosen){
chosen = JSON.parse(decodeURIComponent(option.chosen || '[]'))
}
if(option.ec){
ec = option.ec
}
......
......@@ -1029,11 +1029,16 @@ function checkDialogs() {
const memberInfoData = app.globalData.memberInfo || {}
// 密码长期未更新提示: changePassFlag='1' && activeStatus=1 && authenticationStatus=2
// 只提示一次
if (app.globalData.changePassFlag == '1' &&
app.globalData.memberInfo?.activeStatus == '1' &&
app.globalData.authenticationStatus == 2) {
const hasShown = uni.getStorageSync('passwordTipShown')
if (!hasShown) {
uni.setStorageSync('passwordTipShown', true)
passwordTipPopup.value.open()
}
}
// 绑定手机号条件: changePassFlag='1' && activeStatus=1 && authenticationStatus=2 && phonenumber为空 && checkFlag=1
if (app.globalData.changePassFlag === '1' &&
......
......@@ -454,7 +454,7 @@ const goToOrder = () => {
return
}
uni.navigateTo({
url: '/personal/order'
url: '/personal/order?perId=' + userInfo.value.perId
});
};
......
<template>
<view :class="{ 'no-scroll': isPopupOpen }" class="order-page">
<!-- 搜索栏 -->
<view class="search-bar">
<uni-easyinput
v-model="queryParams.wfCode"
:input-border="false"
class="search-input"
placeholder="搜索缴费编号"
placeholderStyle="font-size:30rpx;color:#999"
prefixIcon="search"
@blur="handelSearch"
@clear="handelSearch">
</uni-easyinput>
<view class="add-btn" @click="handelSearch">
<text class="add-text">搜索</text>
</view>
</view>
<!-- 订单列表 -->
<scroll-view
:enhanced="true"
:scroll-enabled="!isPopupOpen"
:show-scrollbar="false"
class="order-list-scroll"
lower-threshold="200"
scroll-y
@scrolltolower="loadMore"
>
<view class="order-list">
<!-- 有数据才循环 -->
......@@ -14,39 +33,58 @@
<view
v-for="(item, index) in list"
:key="index"
class="order-card"
class="order-card-new"
@click="goToDetail(item)"
>
<!-- 订单头部:日期 + 状态 -->
<view class="card-header">
<view class="date">
<!-- <image v-if="item.payTime" :src="config.baseUrl_api + '/fs/static/calendar@2x.png'" mode="widthFix" -->
<!-- style="width:30rpx;height:30rpx;"/> -->
<!-- <text v-if="item.payTime" class="date-text">{{ item.payTime }}</text> -->
<text class="value text-primary">{{ item.wfCode || '——' }}</text>
<view class="data-header">
<text class="member-label">个人会员·</text>
<text class="value">{{ item.orderName || '——' }}</text>
</view>
<view
:class="{
success: item.payStatus == 1,
danger: item.payStatus == 2,
pending: item.payStatus == 0
<text :class="{
'status-wait': item.auditStatus == 0,
'status-pending': item.auditStatus == 1,
'status-success': item.auditStatus == 2,
'status-danger': item.auditStatus == 3
}"
class="status-tag"
>
{{ getStatusText(item.payStatus) }}
class="status-tag ">{{ getAuditStatusText(item.auditStatus) }}
</text>
</view>
</view>
<!-- 订单编号、缴费编号 -->
<view class="info-row">
<text class="label">订单编号:</text>
<text class="value">{{ item.tradeNo || '——' }}</text>
<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>
{{ `${filterTime(item.genTime)}个人会员缴费办理` }}
</view>
<view class="price">
<view>{{ item.price || '0.00' }}</view>
<view class="person">{{ item.content?.yearCount || 0 }}</view>
</view>
<view class="info-row">
<text class="label">支付时间:</text>
<text class="value">{{ item.payTime || '' }}</text>
</view>
<!-- 核心:个人会员仅展示缴费年限 -->
<!-- 核心:展示缴费年限 -->
<view v-if="item.content" class="info-section flex f-j-s">
<view class="single-info">
<view class="label">缴费年限:</view>
......@@ -54,31 +92,46 @@
</view>
<view class="line"></view>
<view class="single-info">
<view class="label">缴费方式</view>
<view class="value">{{ item.ziZhangBu ? '对公转账' : '民生付' }}</view>
<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 class="total-row">
<text class="label">费用合计:</text>
<text class="amount">¥{{ (Number(item.price) || 0).toFixed(2) }}</text>
</view>
<!-- 按钮组:靠右紧凑展示 -->
<!-- 按钮组 -->
<view class="btn-group">
<!-- <button class="btn btn-delete" @click="handleDelete(item)">删除</button>-->
<!-- 已缴费:申请开票/已开票 -->
<template v-if="item.payStatus == 1">
<button :disabled="item.invoiceStatus === 1" class="btn btn-invoice" @click="makeInvoiceFN(item)">
{{ item.invoiceStatus === 1 ? '已开票' : '申请开票' }}
<view>
<text class="more" @click.stop="goToDetail(item)">更多</text>
</view>
<view class="btn-flex">
<button class="btn btn-info" @click.stop="goToDetail(item)">查看明细</button>
<!-- 已缴费:申请开票/已开票(需要审核通过才能开票) -->
<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>
<!-- &lt;!&ndash; 未缴费:去缴费 + 取消订单 &ndash;&gt;-->
<!-- <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>-->
<!-- 已开票:查看发票 -->
<template v-if="item.invoiceStatus == 1">
<button class="btn btn-invoice" @click.stop="viewInvoice(item)">查看发票</button>
</template>
</view>
</view>
</view>
</view>
......@@ -95,6 +148,46 @@
</view>
</scroll-view>
<!-- 发票查看弹窗 -->
<view v-if="showInvoicePopup" class="invoice-popup-mask" @click="closeInvoicePopup">
<view class="invoice-popup-content" @click.stop>
<view class="invoice-popup-header">
<text class="invoice-popup-title">发票信息</text>
<view class="invoice-popup-close" @click.stop="closeInvoicePopup"></view>
</view>
<view class="invoice-popup-body">
<view class="invoice-info-list">
<view class="invoice-info-row">
<view class="invoice-info-label">发票类型</view>
<view :class="{ 'vat-type': invoiceData.invoiceType == 2 }" class="invoice-type-badge">
{{ invoiceData.invoiceType == 1 ? '普通发票' : '增值税专用发票' }}
</view>
</view>
<view class="invoice-info-row">
<text class="invoice-info-label">发票抬头</text>
<text class="invoice-info-value">{{ invoiceData.invoiceBuyerName || '—' }}</text>
</view>
<view v-if="invoiceData.invoiceBuyerTaxno" class="invoice-info-row">
<text class="invoice-info-label">纳税人识别号</text>
<text class="invoice-info-value">{{ invoiceData.invoiceBuyerTaxno }}</text>
</view>
<view class="invoice-info-row">
<text class="invoice-info-label">接收邮箱</text>
<text class="invoice-info-value">{{ invoiceData.invoicePushPhone || '—' }}</text>
</view>
<view class="invoice-info-row">
<text class="invoice-info-label">开票时间</text>
<text class="invoice-info-value">{{ invoiceData.invoiceTime || '—' }}</text>
</view>
<view class="invoice-info-row">
<text class="invoice-info-label">开票金额</text>
<text class="invoice-info-value">{{ invoiceData.price || '—' }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 自定义删除确认弹窗 -->
<view v-if="showDelPopup" class="popup-mask" @touchmove.stop.prevent @click.stop="closeDelPopup">
<view class="custom-modal" @click.stop>
......@@ -123,10 +216,11 @@
<script setup>
import {ref, reactive, onMounted, computed} from 'vue';
import {onReachBottom} from '@dcloudio/uni-app'
import {onReachBottom, onShow, onLoad} from '@dcloudio/uni-app'
import {useUserStore} from "@/store/modules/user";
import * as api from '@/common/api.js'
import config from '@/config.js'
import dayjs from 'dayjs'
const userStore = useUserStore()
// 数据与分页配置
......@@ -136,21 +230,22 @@ const hasMore = ref(true);
const pageNum = ref(1);
const pageSize = ref(10);
const userInfo = computed(() => userStore.user)
// 查询参数(固定为个人会员类型)
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
type: '0', // 0表示个人会员
subType: '1', //0道馆 1个人
// queryType: '1',
// payStatus: '',
perId: ''
type: '0',
// subType: '1',
// perId: ''
});
// 弹窗控制
const showDelPopup = ref(false);
const showCancelPopup = ref(false);
const isPopupOpen = ref(false);
const showInvoicePopup = ref(false);
const invoiceData = ref({});
// 弹窗内容
const delModalContent = ref('');
......@@ -159,27 +254,66 @@ const cancelModalContent = ref('');
// 当前操作的订单
const currentOrder = ref(null);
// 是否需要刷新
const needRefresh = ref(false);
// 审核状态文本映射
const getAuditStatusText = (status) => {
const map = {
0: '待提交',
1: '审核中',
2: '审核通过',
3: '审核拒绝'
};
return map[status] || '';
};
onLoad((options) => {
// queryParams.perId = options.perId || userInfo.value.perId
initData();
})
const filterTime = (row) => {
if (!row) return ''
return dayjs(row).format('YYYY年MM月DD日')
}
// 页面挂载初始化
onMounted(() => {
// 获取用户信息
// if (userInfo.value && userInfo.value.perId) {
// queryParams.perId = userInfo.value.perId;
// initData();
// } else {
// uni.showToast({title: '获取用户信息失败', icon: 'none'});
// }
initData();
});
// 页面显示时刷新数据(从开票页面返回时)
onShow(() => {
if (needRefresh.value) {
needRefresh.value = false;
pageNum.value = 1;
list.value = [];
hasMore.value = true;
initData();
}
});
// 小程序原生触底加载
onReachBottom(() => {
if (!loading.value && hasMore.value && !isPopupOpen.value) {
pageNum.value++;
initData();
loadMore();
}
});
// 上拉加载更多
const loadMore = () => {
if (loading.value || !hasMore.value || isPopupOpen.value) return;
pageNum.value++;
initData();
};
// 搜索
const handelSearch = () => {
pageNum.value = 1;
list.value = [];
hasMore.value = true;
initData();
};
// 状态文本映射
const getStatusText = (status) => {
const map = {
......@@ -196,9 +330,9 @@ const initData = async () => {
queryParams.pageNum = pageNum.value;
try {
const res = await api.orderList(queryParams);
if (!res || !res.rows) {
list.value = [];
if (!res || !res.rows || res.rows.length === 0) {
hasMore.value = false;
loading.value = false;
return;
}
// 安全解析content字段
......@@ -222,11 +356,18 @@ const initData = async () => {
} catch (e) {
console.error('订单加载异常:', e);
uni.showToast({title: '加载失败', icon: 'none'});
hasMore.value = false;
} finally {
loading.value = false;
}
};
// 查看明细/详情
const goToDetail = (item) => {
const form = encodeURIComponent(JSON.stringify(item));
uni.navigateTo({url: `/personalVip/orderDetail?rangeId=${item.sourceId || item.id}&type=${queryParams.type}`});
};
// 删除订单
const handleDelete = (item) => {
currentOrder.value = item;
......@@ -270,7 +411,30 @@ const handlePay = async (item) => {
// 申请开票
const makeInvoiceFN = (item) => {
uni.navigateTo({url: `/pages/invoice/apply?orderId=${item.id}&amount=${item.price}&type=1`});
needRefresh.value = true;
uni.navigateTo({
url: `/pages/invoice/apply?orderId=${item.id}&amount=${item.price}&type=1`
});
};
// 查看发票
const viewInvoice = (item) => {
invoiceData.value = {
invoiceType: item.invoiceType || 1,
invoiceBuyerName: item.invoiceTitle || item.invoiceBuyerName || '—',
invoiceBuyerTaxno: item.invoiceTaxno || item.invoiceBuyerTaxno || '',
invoicePushPhone: item.invoiceEmail || item.invoicePushPhone || '—',
price: item.price || '-',
invoiceTime: item.invoiceTime || '—'
};
showInvoicePopup.value = true;
isPopupOpen.value = true;
};
// 关闭发票弹窗
const closeInvoicePopup = () => {
showInvoicePopup.value = false;
isPopupOpen.value = false;
};
// 取消订单
......@@ -317,6 +481,42 @@ const closeCancelPopup = () => {
}
}
/* 搜索栏 */
.search-bar {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background-color: #ffffff;
margin-bottom: 0;
.search-input {
flex: 1;
margin-right: 20rpx;
:deep(.uni-easyinput__content) {
border-radius: 40rpx;
background-color: #f5f7fa;
height: 76rpx;
padding: 0 24rpx;
}
:deep(.uni-easyinput__content-input) {
font-size: 28rpx;
color: #333;
}
}
.add-btn {
display: flex;
align-items: center;
padding: 10rpx 30rpx;
background-color: #AD181F;
border-radius: 40rpx;
font-size: 28rpx;
color: #ffffff;
}
}
// 滚动列表容器
.order-list-scroll {
flex: 1;
......@@ -327,75 +527,106 @@ const closeCancelPopup = () => {
// 订单列表
.order-list {
padding: 20rpx;
}
.order-card {
.order-card-new {
background: #fff;
margin-bottom: 20rpx;
padding: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
border-radius: 12rpx;
}
}
display: flex;
flex-direction: column;
// 卡片头部
.card-header {
// 卡片头部
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20rpx;
padding-bottom: 10rpx;
.date {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8rpx;
font-size: 26rpx;
.data-header {
display: flex;
}
.member-label {
color: #c30d23;
font-size: 28rpx;
font-weight: bold;
}
.value {
color: #000;
font-size: 28rpx;
font-weight: bold;
.tradeNo {
color: #999;
font-size: 26rpx;
}
}
.date-text {
color: #666;
}
}
.status-tag {
font-size: 22rpx;
padding: 6rpx 16rpx;
border-radius: 20rpx;
font-size: 26rpx;
&.status-wait {
color: #597ef7;
}
&.status-pending {
color: #faad14;
}
&.success {
background: #e6f7ef;
&.status-success {
color: #52c41a;
border: 1rpx solid rgba(82, 196, 26, 0.3);
}
&.danger {
background: #fff1f0;
&.status-danger {
color: #ff4d4f;
border: 1rpx solid rgba(232, 52, 29, 0.3);
}
&.pending {
background: #fff7e6;
color: #faad14;
border: 1rpx solid rgba(250, 173, 20, 0.3);
}
}
}
// 基础信息行
.info-row {
.member-time {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 20rpx;
font-size: 26rpx;
justify-content: space-between;
padding-bottom: 10rpx;
.label {
font-size: 26rpx;
color: #999;
flex-shrink: 0;
width: 140rpx;
.star {
color: #000;
font-size: 28rpx;
}
}
.value {
color: #333;
word-break: break-all;
.price {
font-size: 30rpx;
color: #000;
font-weight: bold;
.person {
font-size: 24rpx;
color: #999;
text-align: right;
}
}
}
}
......@@ -403,21 +634,25 @@ const closeCancelPopup = () => {
background: #f3f6fc;
display: flex;
align-items: center;
padding: 0 40rpx;
justify-content: space-around;
margin: 20rpx 0;
justify-content: space-between;
padding: 0 20rpx;
min-height: 100rpx;
border-radius: 20rpx;
}
.line {
width: 1rpx;
height: 90%;
background: #eee;
height: 60rpx;
background: #e5e5e5;
flex-shrink: 0;
}
.single-info {
flex: 1;
padding: 16rpx 20rpx;
border-radius: 8rpx;
font-size: 26rpx;
text-align: center;
.label {
color: #999;
......@@ -429,63 +664,83 @@ const closeCancelPopup = () => {
font-weight: 500;
text-align: center;
margin-top: 10rpx;
&.text-primary {
color: #597ef7;
}
}
// 费用合计
.total-row {
display: flex;
justify-content: space-between;
align-items: center;
margin: 0 0 16rpx;
padding: 8rpx 0;
font-size: 26rpx;
&.text-success {
color: #52c41a;
}
.label {
color: #333;
&.text-danger {
color: #ff4d4f;
}
.amount {
color: #EB6100;
font-weight: 600;
font-size: 28rpx;
&.text-warning {
color: #faad14;
}
}
}
// 按钮组
.btn-group {
display: flex;
justify-content: flex-end;
justify-content: space-between;
align-items: center;
gap: 16rpx;
width: 100%;
margin-top: 20rpx;
.more {
color: #666;
}
.btn-flex {
display: flex;
justify-content: flex-end;
gap: 16rpx;
}
.btn {
padding: 12rpx 32rpx;
border-radius: 40rpx;
font-size: 24rpx;
line-height: 1.5;
width: 160rpx;
height: 50rpx;
line-height: 50rpx;
padding: 0;
border-radius: 20rpx;
font-size: 28rpx;
white-space: nowrap;
display: inline-block;
margin: 0;
font-weight: bold;
border: none;
width: 80px;
background: transparent;
text-align: center;
margin: 0;
&::after {
border: none;
display: none;
}
&.btn-delete {
background: #fff;
color: #e4393c;
border: 1rpx solid #e4393c;
color: #c30d23;
border: 1rpx solid #c30d23;
}
&.btn-invoice {
background: #fff;
color: #e4393c;
border: 1rpx solid #e4393c;
color: #c30d23;
border: 1rpx solid #c30d23;
}
&.btn-view-invoice {
color: #c30d23;
border: 1rpx solid #c30d23;
}
&.btn-info {
color: #444;
border: 1rpx solid #666;
}
&.btn-cancel {
......@@ -495,9 +750,8 @@ const closeCancelPopup = () => {
}
&.btn-pay {
background: linear-gradient(90deg, #FF755A, #F51722);
color: #fff;
border: none;
color: #c30d23;
border: 1rpx solid #c30d23;
}
&:disabled {
......@@ -515,6 +769,99 @@ const closeCancelPopup = () => {
font-size: 26rpx;
}
// 发票弹窗样式
.invoice-popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
.invoice-popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.2);
}
.invoice-popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
background: linear-gradient(135deg, #AD181F 0%, #E4393C 100%);
.invoice-popup-title {
font-size: 32rpx;
font-weight: 600;
color: #fff;
}
.invoice-popup-close {
width: 44rpx;
height: 44rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
}
}
.invoice-popup-body {
padding: 30rpx;
}
.invoice-type-badge {
display: inline-flex;
align-items: center;
padding: 8rpx 24rpx;
background: linear-gradient(135deg, #FF755A 0%, #F51722 100%);
color: #fff;
border-radius: 30rpx;
font-size: 24rpx;
font-weight: 500;
&.vat-type {
background: linear-gradient(135deg, #6aaaf2 0%, #178cd7 100%);
}
}
.invoice-info-list {
.invoice-info-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 24rpx 0;
border-bottom: 1rpx dashed #eee;
&:last-child {
border-bottom: none;
}
.invoice-info-label {
font-size: 26rpx;
color: #999;
flex-shrink: 0;
}
.invoice-info-value {
font-size: 26rpx;
color: #333;
text-align: right;
word-break: break-all;
max-width: 340rpx;
}
}
}
// 弹窗遮罩层
.popup-mask {
position: fixed;
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!