| | |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | <view class="value">{{ taskTypeText }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | |
| | | <view class="label">总费用:</view> |
| | | <view class="value total">¥{{ totalAmount }}</view> |
| | | </view> |
| | | |
| | | <view class="amount-item paid-amount" v-if="paidAmount > 0"> |
| | | <view class="label">已支付:</view> |
| | | <view class="value" style="color: #34C759;">¥{{ paidAmount }}</view> |
| | | </view> |
| | | |
| | | <view class="amount-item remaining-amount" v-if="paidAmount > 0"> |
| | | <view class="label">剩余未付:</view> |
| | | <view class="value" style="color: #ff9900; font-weight: bold;">¥{{ remainingAmount }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 已支付记录列表 --> |
| | | <view class="payment-history-section" v-if="paidPaymentList.length > 0"> |
| | | <view class="section-title">支付记录</view> |
| | | <view |
| | | class="payment-item" |
| | | v-for="payment in paidPaymentList" |
| | | :key="payment.id" |
| | | > |
| | | <view class="payment-info"> |
| | | <view class="payment-method"> |
| | | <text class="method-tag" :class="['method-' + payment.paymentMethod.toLowerCase()]"> |
| | | {{ getPaymentMethodText(payment.paymentMethod) }} |
| | | </text> |
| | | </view> |
| | | <view class="payment-time"> |
| | | {{ formatPaymentTime(payment.payTime) }} |
| | | </view> |
| | | </view> |
| | | <view class="payment-amount"> |
| | | ¥{{ payment.settlementAmount }} |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="settlement-form"> |
| | |
| | | class="form-textarea" |
| | | placeholder="请输入备注信息" |
| | | v-model="remark" |
| | | /> |
| | | ></textarea> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 支付二维码区域 --> |
| | | <view v-if="showQRCode" class="qr-code-section"> |
| | | <view class="section-title">请扫码支付</view> |
| | | <view class="qr-code-container"> |
| | | <image class="qr-code" :src="qrCodeImage" mode="widthFix"></image> |
| | | <view class="qr-tip">请使用{{ selectedPaymentMethod }}扫码支付</view> |
| | | </view> |
| | | <view class="payment-status"> |
| | | <view v-if="paymentStatus === 'pending'" class="status-pending">等待支付...</view> |
| | | <view v-if="paymentStatus === 'success'" class="status-success"> |
| | | <uni-icons type="checkmarkempty" size="24" color="#4cd964"></uni-icons> |
| | | 支付成功 |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | </scroll-view> |
| | | |
| | | <view class="action-section"> |
| | |
| | | 保存结算 |
| | | </button> |
| | | </view> |
| | | |
| | | <!-- 支付二维码弹窗 --> |
| | | <uni-popup ref="qrCodePopup" type="center" :mask-click="false"> |
| | | <view class="qr-popup-content"> |
| | | <view class="qr-popup-header"> |
| | | <text class="qr-popup-title">{{ selectedPaymentMethod }}支付</text> |
| | | </view> |
| | | |
| | | <view class="qr-popup-body"> |
| | | <view class="qr-code-box" v-if="qrCodeImage"> |
| | | <image class="qr-image" :src="qrCodeImage" mode="widthFix"></image> |
| | | </view> |
| | | |
| | | <view class="qr-loading" v-else> |
| | | <uni-icons type="spinner-cycle" size="40" color="#007AFF"></uni-icons> |
| | | <text class="loading-text">正在生成二维码...</text> |
| | | </view> |
| | | |
| | | <view class="qr-tip-text">请使用{{ selectedPaymentMethod }}扫码支付</view> |
| | | <view class="qr-amount">¥{{ settlementAmount }}</view> |
| | | |
| | | <view class="payment-status-box"> |
| | | <view v-if="paymentStatus === 'pending'" class="status-waiting"> |
| | | <uni-icons type="spinner-cycle" size="20" color="#ff9900"></uni-icons> |
| | | <text>等待支付中...</text> |
| | | </view> |
| | | <view v-if="paymentStatus === 'success'" class="status-paid"> |
| | | <uni-icons type="checkmarkempty" size="24" color="#4cd964"></uni-icons> |
| | | <text>支付成功</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="qr-popup-footer"> |
| | | <button |
| | | class="cancel-pay-btn" |
| | | @click="cancelPayment" |
| | | v-if="paymentStatus !== 'success'" |
| | | > |
| | | 取消支付 |
| | | </button> |
| | | <button |
| | | class="confirm-pay-btn" |
| | | @click="confirmPaymentSuccess" |
| | | v-if="paymentStatus === 'success'" |
| | | > |
| | | 确定 |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </uni-popup> |
| | | |
| | | <!-- 附加费用弹窗 --> |
| | | <uni-popup ref="additionalFeesPopup" type="bottom"> |
| | |
| | | </view> |
| | | |
| | | <!-- 已添加的费用列表 --> |
| | | <view class="added-fees-list" v-if="selectedAdditionalFees.length > 0"> |
| | | <view class="added-fees-list" v-if="additionalFeeList.length > 0"> |
| | | <view class="section-title">已添加费用</view> |
| | | <view |
| | | class="fee-item" |
| | | v-for="(fee, index) in selectedAdditionalFees" |
| | | :key="index" |
| | | v-for="fee in additionalFeeList" |
| | | :key="fee.id" |
| | | > |
| | | <view class="fee-info"> |
| | | <view class="fee-name">{{ fee.name }}</view> |
| | | <view class="fee-price">¥{{ fee.price }} × {{ fee.quantity }}</view> |
| | | <view class="fee-name">{{ fee.feeName }}</view> |
| | | <view class="fee-price">¥{{ fee.unitAmount }} × {{ fee.quantity }}</view> |
| | | </view> |
| | | <view class="fee-total">¥{{ (fee.price * fee.quantity).toFixed(2) }}</view> |
| | | <view class="fee-actions"> |
| | | <view class="fee-total">¥{{ fee.totalAmount }}</view> |
| | | <view class="delete-btn" @click="removeFee(fee.id)" v-if="!paySuccess"> |
| | | <uni-icons type="trash" size="20" color="#e54d42"></uni-icons> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { getPaymentInfo, addAdditionalFee, removeAdditionalFee, createPayment, getPaymentStatus } from '@/api/payment' |
| | | import { getTask } from '@/api/task' |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | task: { |
| | | id: 1, |
| | | taskNo: 'RW20230515001', |
| | | type: 'emergency', |
| | | vehicle: '粤A12345', |
| | | startLocation: '广州市天河区XX路123号', |
| | | endLocation: '广州市白云区YY路456号' |
| | | }, |
| | | baseAmount: 1000, // 基础费用 |
| | | additionalAmount: 0, // 附加费用 |
| | | taskId: null, |
| | | task: {}, |
| | | baseAmount: 0, // 基础费用(成交价) |
| | | additionalAmount: 0, // 附加费用汇总 |
| | | settlementAmount: '', // 结算金额 |
| | | remark: '', // 备注 |
| | | paymentMethods: ['现金', '支付宝', '微信', '挂帐'], |
| | | paymentMethods: [], // 从字典加载支付方式 |
| | | paymentMethodDict: [], // 字典原始数据 |
| | | selectedPaymentMethod: '', |
| | | showQRCode: false, |
| | | paymentStatus: 'pending', // pending, success |
| | | qrCodeImage: '/static/images/qrcode.png', // 二维码图片路径 |
| | | additionalFeeTypes: [ |
| | | { name: '担架费', price: 200 }, |
| | | { name: '等待费', price: 100 }, |
| | | { name: '善后费', price: 150 }, |
| | | { name: '夜间服务费', price: 300 }, |
| | | { name: '长途费', price: 500 } |
| | | ], |
| | | selectedAdditionalFees: [], // 已选择的附加费用 |
| | | qrCodeImage: '', // 二维码图片路径 |
| | | paymentId: null, |
| | | pollTimer: null, // 轮询定时器 |
| | | additionalFeeTypes: [], // 从字典加载 |
| | | additionalFeeList: [], // 已添加的附加费用列表 |
| | | selectedFeeTypeName: '', // 选中的费用类型名称 |
| | | newFeePrice: '' // 新增费用价格 |
| | | selectedFeeTypeValue: '', // 选中的费用类型值 |
| | | newFeePrice: '', // 新增费用价格 |
| | | loading: false, |
| | | paySuccess: false, // 支付成功标记 |
| | | paidAmount: 0, // 已支付金额 |
| | | paidPaymentList: [] // 已支付记录列表 |
| | | } |
| | | }, |
| | | computed: { |
| | | totalAmount() { |
| | | return this.baseAmount + this.additionalAmount; |
| | | }, |
| | | // 剩余未支付金额 |
| | | remainingAmount() { |
| | | return this.totalAmount - this.paidAmount; |
| | | }, |
| | | // 任务类型显示 |
| | | taskTypeText() { |
| | | const typeMap = { |
| | | 'EMERGENCY_TRANSFER': '急救转运', |
| | | 'SCHEDULED_TRANSFER': '计划转运', |
| | | 'EMERGENCY_RESCUE': '急救抢救', |
| | | 'ORDINARY_TASK': '普通任务' |
| | | } |
| | | return typeMap[this.task.type] || this.task.type |
| | | }, |
| | | canSave() { |
| | | // 现金和挂帐可以直接保存,其他支付方式需要支付成功后才能保存 |
| | | // 已全额支付后不能再次保存 |
| | | if (this.remainingAmount <= 0) { |
| | | return false |
| | | } |
| | | |
| | | if (!this.settlementAmount || !this.selectedPaymentMethod) { |
| | | return false; |
| | | return false |
| | | } |
| | | |
| | | if (this.selectedPaymentMethod === '现金' || this.selectedPaymentMethod === '挂帐') { |
| | | return true; |
| | | const amount = parseFloat(this.settlementAmount) |
| | | |
| | | // 校验结算金额必须大于0且不超过剩余金额 |
| | | if (amount <= 0 || amount > this.remainingAmount) { |
| | | return false |
| | | } |
| | | |
| | | // 支付宝、微信等需要支付成功 |
| | | return this.paymentStatus === 'success'; |
| | | const dictValue = this.getPaymentMethodValue(this.selectedPaymentMethod) |
| | | |
| | | // 1-现金, 6-挂账, 7-易医通挂账 可以直接保存 |
| | | if (dictValue === '1' || dictValue === '6' || dictValue === '7') { |
| | | return true |
| | | } |
| | | |
| | | // 3-微信支付, 4-支付宝 需要支付成功后才能保存 |
| | | if (dictValue === '3' || dictValue === '4') { |
| | | return this.paymentStatus === 'success' |
| | | } |
| | | |
| | | // 2-银行转账, 5-POS收款 直接保存 |
| | | return true |
| | | }, |
| | | // 获取费用类型名称数组 |
| | | additionalFeeTypeNames() { |
| | | return this.additionalFeeTypes.map(fee => fee.name); |
| | | return this.additionalFeeTypes.map(fee => fee.dictLabel); |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | // 实际项目中这里会通过API获取任务详情 |
| | | // const taskId = options.id; |
| | | // this.getTaskDetail(taskId); |
| | | if (options.taskId) { |
| | | this.taskId = options.taskId |
| | | this.loadPaymentMethods() // 加载支付方式字典 |
| | | this.loadPaymentInfo() |
| | | this.loadFeeTypes() |
| | | } else { |
| | | this.$modal.showToast('任务ID不能为空') |
| | | setTimeout(() => { |
| | | uni.navigateBack() |
| | | }, 1500) |
| | | } |
| | | }, |
| | | onUnload() { |
| | | // 清除轮询定时器 |
| | | if (this.pollTimer) { |
| | | clearInterval(this.pollTimer) |
| | | } |
| | | }, |
| | | methods: { |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | 'maintenance': '维修保养', |
| | | 'refuel': '加油', |
| | | 'inspection': '巡检', |
| | | 'emergency': '转运任务', |
| | | 'welfare': '福祉车' |
| | | } |
| | | return typeMap[type] || '未知类型' |
| | | // 加载支付方式字典 |
| | | loadPaymentMethods() { |
| | | this.$dict.getDicts('task_payment_method').then(res => { |
| | | // 过滤掉退款(8)和积分(9),只显示1-7 |
| | | this.paymentMethodDict = (res.data || []).filter(item => { |
| | | const value = parseInt(item.dictValue) |
| | | return value >= 1 && value <= 7 |
| | | }) |
| | | // 提取显示名称数组用于picker |
| | | this.paymentMethods = this.paymentMethodDict.map(item => item.dictLabel) |
| | | }).catch(err => { |
| | | console.error('加载支付方式字典失败', err) |
| | | this.$modal.showToast('加载支付方式失败') |
| | | }) |
| | | }, |
| | | |
| | | // 根据选中的名称获取字典值 |
| | | getPaymentMethodValue(label) { |
| | | const method = this.paymentMethodDict.find(item => item.dictLabel === label) |
| | | return method ? method.dictValue : '' |
| | | }, |
| | | |
| | | // 加载支付信息 |
| | | loadPaymentInfo() { |
| | | this.loading = true |
| | | getPaymentInfo(this.taskId).then(res => { |
| | | const data = res.data |
| | | |
| | | // 任务基本信息 |
| | | this.task = { |
| | | taskNo: data.taskCode || '', |
| | | type: data.taskType || '', |
| | | vehicle: data.vehicleInfo || '未分配', |
| | | startLocation: data.departureAddress || '未设置', |
| | | endLocation: data.destinationAddress || '未设置' |
| | | } |
| | | |
| | | // 费用信息 |
| | | this.baseAmount = data.transferPrice || 0 |
| | | this.additionalAmount = data.additionalAmount || 0 |
| | | this.additionalFeeList = data.additionalFees || [] |
| | | this.paidAmount = data.paidAmount || 0 |
| | | this.paidPaymentList = data.paidPayments || [] // 加载已支付记录列表 |
| | | |
| | | // 默认结算金额为剩余未支付金额 |
| | | const remaining = (data.totalAmount || 0) - this.paidAmount |
| | | this.settlementAmount = remaining > 0 ? remaining.toString() : '' |
| | | |
| | | // 如果已全额支付,提示已结算 |
| | | if (remaining <= 0) { |
| | | this.paySuccess = true |
| | | this.$modal.showToast('该任务已结算') |
| | | } |
| | | |
| | | this.loading = false |
| | | }).catch(err => { |
| | | console.error('加载支付信息失败', err) |
| | | this.loading = false |
| | | this.$modal.showToast('加载支付信息失败') |
| | | }) |
| | | }, |
| | | |
| | | // 加载费用类型字典 |
| | | loadFeeTypes() { |
| | | this.$dict.getDicts('task_additional_fee_type').then(res => { |
| | | this.additionalFeeTypes = res.data || [] |
| | | }) |
| | | }, |
| | | |
| | | onPaymentMethodChange(e) { |
| | | this.selectedPaymentMethod = this.paymentMethods[e.detail.value]; |
| | | this.selectedPaymentMethod = this.paymentMethods[e.detail.value] |
| | | const dictValue = this.getPaymentMethodValue(this.selectedPaymentMethod) |
| | | |
| | | // 如果选择支付宝或微信,显示二维码 |
| | | if (this.selectedPaymentMethod === '支付宝' || this.selectedPaymentMethod === '微信') { |
| | | this.showQRCode = true; |
| | | this.paymentStatus = 'pending'; |
| | | // 模拟支付状态检查 |
| | | this.checkPaymentStatus(); |
| | | // 3-微信支付, 4-支付宝 |
| | | if (dictValue === '3' || dictValue === '4') { |
| | | this.openQRCodePopup(dictValue) |
| | | } else { |
| | | this.showQRCode = false; |
| | | this.paymentStatus = 'pending'; |
| | | // 其他支付方式不显示二维码 |
| | | this.showQRCode = false |
| | | this.paymentStatus = 'pending' |
| | | } |
| | | }, |
| | | |
| | | // 打开支付二维码弹窗 |
| | | openQRCodePopup(dictValue) { |
| | | // 重置状态 |
| | | this.qrCodeImage = '' |
| | | this.paymentStatus = 'pending' |
| | | this.showQRCode = true |
| | | |
| | | // 打开弹窗 |
| | | this.$refs.qrCodePopup.open() |
| | | |
| | | // 生成二维码 |
| | | this.generateQRCode(dictValue) |
| | | }, |
| | | |
| | | // 取消支付 |
| | | cancelPayment() { |
| | | // 清除轮询 |
| | | if (this.pollTimer) { |
| | | clearInterval(this.pollTimer); |
| | | this.pollTimer = null; |
| | | } |
| | | |
| | | // 关闭弹窗 |
| | | this.$refs.qrCodePopup.close(); |
| | | |
| | | // 重置状态 |
| | | this.selectedPaymentMethod = ''; |
| | | this.showQRCode = false; |
| | | this.qrCodeImage = ''; |
| | | this.paymentStatus = 'pending'; |
| | | }, |
| | | |
| | | // 确认支付成功 |
| | | confirmPaymentSuccess() { |
| | | // 关闭弹窗 |
| | | this.$refs.qrCodePopup.close(); |
| | | |
| | | // 重新加载支付信息,刷新显示 |
| | | this.loadPaymentInfo(); |
| | | |
| | | // 重置状态,准备下一笔支付 |
| | | this.selectedPaymentMethod = ''; |
| | | this.showQRCode = false; |
| | | this.qrCodeImage = ''; |
| | | this.paymentStatus = 'pending'; |
| | | this.remark = ''; |
| | | // settlementAmount 会在 loadPaymentInfo 中自动设置为剩余金额 |
| | | }, |
| | | |
| | | // 生成支付二维码 |
| | | generateQRCode(paymentMethod) { |
| | | // 校验结算金额 |
| | | if (!this.settlementAmount) { |
| | | this.$modal.showToast('请先输入结算金额'); |
| | | this.$refs.qrCodePopup.close(); |
| | | this.selectedPaymentMethod = ''; |
| | | return; |
| | | } |
| | | |
| | | const amount = parseFloat(this.settlementAmount); |
| | | if (amount <= 0) { |
| | | this.$modal.showToast('结算金额必须大于0'); |
| | | this.$refs.qrCodePopup.close(); |
| | | this.selectedPaymentMethod = ''; |
| | | return; |
| | | } |
| | | |
| | | if (amount > this.remainingAmount) { |
| | | this.$modal.showToast(`结算金额不能超过剩余金额¥${this.remainingAmount}`); |
| | | this.$refs.qrCodePopup.close(); |
| | | this.selectedPaymentMethod = ''; |
| | | return; |
| | | } |
| | | |
| | | const data = { |
| | | taskId: this.taskId, |
| | | paymentMethod: paymentMethod, |
| | | settlementAmount: amount, |
| | | remark: this.remark |
| | | }; |
| | | |
| | | createPayment(data).then(res => { |
| | | const result = res.data; |
| | | this.paymentId = result.paymentId; |
| | | this.qrCodeImage = result.codeUrl; |
| | | this.paymentStatus = 'pending'; |
| | | |
| | | // 开始轮询支付状态 |
| | | this.checkPaymentStatus(); |
| | | }).catch(err => { |
| | | console.error('生成支付二维码失败', err); |
| | | this.$modal.showToast('生成支付二维码失败'); |
| | | this.$refs.qrCodePopup.close(); |
| | | this.selectedPaymentMethod = ''; |
| | | }); |
| | | }, |
| | | |
| | | // 费用类型选择 |
| | | onFeeTypeChange(e) { |
| | | this.selectedFeeTypeName = this.additionalFeeTypeNames[e.detail.value]; |
| | | const index = e.detail.value |
| | | this.selectedFeeTypeName = this.additionalFeeTypes[index].dictLabel |
| | | this.selectedFeeTypeValue = this.additionalFeeTypes[index].dictValue |
| | | }, |
| | | |
| | | // 轮询检查支付状态 |
| | | checkPaymentStatus() { |
| | | // 模拟支付状态检查,实际项目中应该通过API轮询检查支付状态 |
| | | setTimeout(() => { |
| | | // 模拟支付成功 |
| | | this.paymentStatus = 'success'; |
| | | }, 5000); |
| | | if (this.pollTimer) { |
| | | clearInterval(this.pollTimer); |
| | | } |
| | | |
| | | this.pollTimer = setInterval(() => { |
| | | getPaymentStatus(this.taskId, this.paymentId).then(res => { |
| | | const data = res.data; |
| | | if (data.payStatus === 'PAID') { |
| | | // 支付成功 |
| | | this.paymentStatus = 'success'; |
| | | clearInterval(this.pollTimer); |
| | | this.pollTimer = null; |
| | | |
| | | // 在弹窗中显示支付成功状态 |
| | | // 用户需要点击"确定"按钮来关闭弹窗并刷新页面 |
| | | } |
| | | }).catch(err => { |
| | | console.error('查询支付状态失败', err); |
| | | }); |
| | | }, 2000); // 每2秒轮询一次 |
| | | }, |
| | | |
| | | showAdditionalFees() { |
| | |
| | | return; |
| | | } |
| | | |
| | | // 查找选中的费用类型信息 |
| | | const selectedFeeType = this.additionalFeeTypes.find(fee => fee.name === this.selectedFeeTypeName); |
| | | |
| | | // 检查是否已存在同名费用 |
| | | const existingFee = this.selectedAdditionalFees.find(fee => fee.name === this.selectedFeeTypeName); |
| | | if (existingFee) { |
| | | existingFee.quantity += 1; |
| | | } else { |
| | | this.selectedAdditionalFees.push({ |
| | | name: this.selectedFeeTypeName, |
| | | price: parseFloat(this.newFeePrice), |
| | | quantity: 1 |
| | | }); |
| | | // 调用接口添加附加费用 |
| | | const data = { |
| | | taskId: this.taskId, |
| | | feeType: this.selectedFeeTypeValue, |
| | | feeName: this.selectedFeeTypeName, |
| | | unitAmount: parseFloat(this.newFeePrice), |
| | | quantity: 1, |
| | | remark: '' |
| | | } |
| | | |
| | | // 清空输入框 |
| | | this.selectedFeeTypeName = ''; |
| | | this.newFeePrice = ''; |
| | | |
| | | this.calculateAdditionalAmount(); |
| | | this.$modal.showToast('费用添加成功'); |
| | | addAdditionalFee(data).then(res => { |
| | | this.$modal.showToast('费用添加成功') |
| | | |
| | | // 清空输入框 |
| | | this.selectedFeeTypeName = '' |
| | | this.selectedFeeTypeValue = '' |
| | | this.newFeePrice = '' |
| | | |
| | | // 重新加载支付信息 |
| | | this.loadPaymentInfo() |
| | | }).catch(err => { |
| | | console.error('添加费用失败', err) |
| | | this.$modal.showToast('添加费用失败') |
| | | }) |
| | | }, |
| | | |
| | | calculateAdditionalAmount() { |
| | | this.additionalAmount = this.selectedAdditionalFees.reduce((total, fee) => { |
| | | return total + (fee.price * fee.quantity); |
| | | }, 0); |
| | | // 删除附加费用 |
| | | removeFee(feeId) { |
| | | this.$modal.confirm('确定要删除该费用吗?').then(() => { |
| | | removeAdditionalFee({ taskId: this.taskId, feeId }).then(res => { |
| | | this.$modal.showToast('删除成功') |
| | | // 重新加载支付信息 |
| | | this.loadPaymentInfo() |
| | | }).catch(err => { |
| | | console.error('删除费用失败', err) |
| | | this.$modal.showToast('删除费用失败') |
| | | }) |
| | | }).catch(() => {}) |
| | | }, |
| | | |
| | | confirmAdditionalFees() { |
| | | this.calculateAdditionalAmount(); |
| | | this.closeAdditionalFeesPopup(); |
| | | }, |
| | | |
| | | // 获取支付方式文本 |
| | | getPaymentMethodText(dictValue) { |
| | | const method = this.paymentMethodDict.find(item => item.dictValue === dictValue) |
| | | return method ? method.dictLabel : dictValue |
| | | }, |
| | | |
| | | // 格式化支付时间 |
| | | formatPaymentTime(time) { |
| | | if (!time) return '未知' |
| | | const date = new Date(time) |
| | | const year = date.getFullYear() |
| | | const month = String(date.getMonth() + 1).padStart(2, '0') |
| | | const day = String(date.getDate()).padStart(2, '0') |
| | | const hour = String(date.getHours()).padStart(2, '0') |
| | | const minute = String(date.getMinutes()).padStart(2, '0') |
| | | return `${year}-${month}-${day} ${hour}:${minute}` |
| | | }, |
| | | |
| | | saveSettlement() { |
| | | if (!this.settlementAmount) { |
| | | this.$modal.showToast('请输入结算金额'); |
| | | return; |
| | | this.$modal.showToast('请输入结算金额') |
| | | return |
| | | } |
| | | |
| | | if (!this.selectedPaymentMethod) { |
| | | this.$modal.showToast('请选择支付方式'); |
| | | return; |
| | | this.$modal.showToast('请选择支付方式') |
| | | return |
| | | } |
| | | |
| | | // 检查结算金额是否合理 |
| | | if (parseFloat(this.settlementAmount) > this.totalAmount) { |
| | | this.$modal.showToast('结算金额不能大于总费用'); |
| | | return; |
| | | const amount = parseFloat(this.settlementAmount) |
| | | |
| | | // 校验结算金额必须大于0 |
| | | if (amount <= 0) { |
| | | this.$modal.showToast('结算金额必须大于0') |
| | | return |
| | | } |
| | | |
| | | this.$modal.confirm('确定要保存结算信息吗?').then(() => { |
| | | // 这里应该调用API保存结算信息 |
| | | console.log('结算信息:', { |
| | | taskId: this.task.id, |
| | | baseAmount: this.baseAmount, |
| | | additionalAmount: this.additionalAmount, |
| | | totalAmount: this.totalAmount, |
| | | settlementAmount: this.settlementAmount, |
| | | paymentMethod: this.selectedPaymentMethod, |
| | | remark: this.remark, |
| | | additionalFees: this.selectedAdditionalFees |
| | | }); |
| | | |
| | | this.$modal.showToast('结算信息保存成功'); |
| | | // 返回任务列表 |
| | | this.$tab.navigateBack(); |
| | | }).catch(() => { |
| | | // 取消操作 |
| | | }); |
| | | // 校验结算金额不能超过剩余金额 |
| | | if (amount > this.remainingAmount) { |
| | | this.$modal.showToast(`结算金额不能超过剩余金额¥${this.remainingAmount}`) |
| | | return |
| | | } |
| | | |
| | | const dictValue = this.getPaymentMethodValue(this.selectedPaymentMethod) |
| | | |
| | | // 3-微信支付, 4-支付宝 已经在选择时生成了二维码,等待支付完成 |
| | | if (dictValue === '3' || dictValue === '4') { |
| | | if (this.paymentStatus !== 'success') { |
| | | this.$modal.showToast('请先完成扫码支付') |
| | | return |
| | | } |
| | | } |
| | | |
| | | // 1-现金, 2-银行转账, 5-POS收款, 6-挂账, 7-易医通挂账 需要创建支付记录 |
| | | if (dictValue === '1' || dictValue === '2' || dictValue === '5' || dictValue === '6' || dictValue === '7') { |
| | | this.$modal.confirm('确定要保存结算信息吗?').then(() => { |
| | | const data = { |
| | | taskId: this.taskId, |
| | | paymentMethod: dictValue, |
| | | settlementAmount: amount, |
| | | remark: this.remark |
| | | } |
| | | |
| | | this.loading = true |
| | | createPayment(data).then(res => { |
| | | this.loading = false |
| | | const result = res.data |
| | | this.paymentId = result.paymentId |
| | | this.paymentStatus = 'success' |
| | | |
| | | // 重新加载支付信息以获取最新的已支付金额 |
| | | this.loadPaymentInfo() |
| | | |
| | | // 检查是否全额支付(使用最新数据判断) |
| | | setTimeout(() => { |
| | | if (this.remainingAmount <= 0) { |
| | | this.paySuccess = true |
| | | this.$modal.showToast('支付成功,已全额结算') |
| | | setTimeout(() => { |
| | | uni.navigateBack() |
| | | }, 1500) |
| | | } else { |
| | | this.$modal.showToast(`支付成功,剩余¥${this.remainingAmount.toFixed(2)}`) |
| | | // 重置表单,准备下一笔支付 |
| | | this.selectedPaymentMethod = '' |
| | | this.remark = '' |
| | | } |
| | | }, 300) // 等待数据加载完成 |
| | | }).catch(err => { |
| | | this.loading = false |
| | | console.error('创建支付失败', err) |
| | | this.$modal.showToast('创建支付失败') |
| | | }) |
| | | }).catch(() => { |
| | | // 取消操作 |
| | | }) |
| | | } else { |
| | | // 扫码支付(微信/支付宝)的情况不应该走到这里 |
| | | // 因为扫码支付在 confirmPaymentSuccess 中处理 |
| | | this.$modal.showToast('请先完成扫码支付') |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | .payment-history-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 20rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .payment-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx 0; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .payment-info { |
| | | flex: 1; |
| | | |
| | | .payment-method { |
| | | margin-bottom: 10rpx; |
| | | |
| | | .method-tag { |
| | | display: inline-block; |
| | | padding: 4rpx 12rpx; |
| | | border-radius: 6rpx; |
| | | font-size: 24rpx; |
| | | color: white; |
| | | |
| | | &.method-cash { |
| | | background-color: #34C759; |
| | | } |
| | | |
| | | &.method-on_account { |
| | | background-color: #ff9500; |
| | | } |
| | | |
| | | &.method-wechat { |
| | | background-color: #09BB07; |
| | | } |
| | | |
| | | &.method-alipay { |
| | | background-color: #1677FF; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .payment-time { |
| | | font-size: 24rpx; |
| | | color: #999; |
| | | } |
| | | } |
| | | |
| | | .payment-amount { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #34C759; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .settlement-form { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | |
| | | } |
| | | } |
| | | |
| | | // 支付二维码弹窗样式 |
| | | .qr-popup-content { |
| | | width: 600rpx; |
| | | background-color: white; |
| | | border-radius: 20rpx; |
| | | overflow: hidden; |
| | | |
| | | .qr-popup-header { |
| | | padding: 40rpx 30rpx 30rpx; |
| | | text-align: center; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .qr-popup-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | } |
| | | |
| | | .qr-popup-body { |
| | | padding: 40rpx 30rpx; |
| | | text-align: center; |
| | | |
| | | .qr-code-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | margin-bottom: 30rpx; |
| | | |
| | | .qr-image { |
| | | width: 400rpx; |
| | | height: 400rpx; |
| | | border: 2rpx solid #f0f0f0; |
| | | border-radius: 10rpx; |
| | | padding: 20rpx; |
| | | box-sizing: border-box; |
| | | } |
| | | } |
| | | |
| | | .qr-loading { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 400rpx; |
| | | margin-bottom: 30rpx; |
| | | |
| | | .loading-text { |
| | | margin-top: 20rpx; |
| | | font-size: 28rpx; |
| | | color: #999; |
| | | } |
| | | } |
| | | |
| | | .qr-tip-text { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .qr-amount { |
| | | font-size: 48rpx; |
| | | font-weight: bold; |
| | | color: #e54d42; |
| | | margin-bottom: 30rpx; |
| | | } |
| | | |
| | | .payment-status-box { |
| | | padding: 20rpx; |
| | | border-radius: 10rpx; |
| | | |
| | | .status-waiting { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10rpx; |
| | | font-size: 28rpx; |
| | | color: #ff9900; |
| | | |
| | | text { |
| | | margin-left: 10rpx; |
| | | } |
| | | } |
| | | |
| | | .status-paid { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10rpx; |
| | | font-size: 32rpx; |
| | | color: #4cd964; |
| | | font-weight: bold; |
| | | |
| | | text { |
| | | margin-left: 10rpx; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .qr-popup-footer { |
| | | padding: 20rpx 30rpx 30rpx; |
| | | |
| | | .cancel-pay-btn, |
| | | .confirm-pay-btn { |
| | | width: 100%; |
| | | height: 80rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | border: none; |
| | | } |
| | | |
| | | .cancel-pay-btn { |
| | | background-color: #f5f5f5; |
| | | color: #666; |
| | | } |
| | | |
| | | .confirm-pay-btn { |
| | | background-color: #4cd964; |
| | | color: white; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .popup-content { |
| | | background-color: white; |
| | | border-top-left-radius: 20rpx; |
| | |
| | | } |
| | | |
| | | .fee-info { |
| | | flex: 1; |
| | | .fee-name { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | |
| | | } |
| | | } |
| | | |
| | | .fee-actions { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .fee-total { |
| | | font-size: 28rpx; |
| | | font-weight: bold; |
| | | color: #e54d42; |
| | | } |
| | | |
| | | .delete-btn { |
| | | padding: 10rpx; |
| | | } |
| | | } |
| | | } |
| | | |