调整订单

This commit is contained in:
Flow 2025-09-03 11:14:36 +08:00
parent 89be19e256
commit 12e2a7c99b
4 changed files with 417 additions and 25 deletions

View File

@ -4,6 +4,8 @@ import request from '@/config/axios'
export interface OrderVO {
id: number // 主键ID
orgid: number // 组织机构ID
deviceid: string // 设备ID
devicename: string // 设备名称
userid: number // 用户ID
comboid: number // 套餐ID
orderno: string // 订单编号

View File

@ -101,8 +101,9 @@
{{ (queryParams.pageNo - 1) * queryParams.pageSize + $index + 1 }}
</template>
</el-table-column>
<el-table-column label="订单编号" align="center" prop="orderno" width="200"/>
<el-table-column label="用户ID" align="center" prop="userid" />
<el-table-column label="订单编号" align="center" prop="orderno" width="300"/>
<el-table-column label="设备ID" align="center" prop="deviceid" />
<el-table-column label="设备名称" align="center" prop="devicename" />
<el-table-column label="套餐ID" align="center" prop="comboid" />
<el-table-column label="原价(元)" align="center" prop="originalprice" />
<el-table-column label="实付金额(元)" align="center" prop="actualprice" />
@ -115,20 +116,6 @@
:formatter="dateFormatter"
width="180px"
/>
<el-table-column
label="会员开始时间"
align="center"
prop="vipstarttime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column
label="会员结束时间"
align="center"
prop="vipendtime"
:formatter="dateFormatter"
width="180px"
/>
<!-- <el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button

View File

@ -80,6 +80,47 @@
</div>
</div>
<!-- 支付方式选择区域 -->
<div class="payment-method-settings">
<div class="section-title">
<Icon icon="ep:wallet" class="title-icon" />
<span>选择支付方式</span>
</div>
<div class="payment-options">
<el-radio-group v-model="paytype" class="payment-radio-group">
<el-radio :value="1" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:chat-dot-round" class="payment-icon wechat" />
<span>微信支付</span>
</div>
</el-radio>
<el-radio :value="2" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:wallet" class="payment-icon alipay" />
<span>支付宝</span>
</div>
</el-radio>
<el-radio :value="3" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:credit-card" class="payment-icon bank" />
<span>银行卡</span>
</div>
</el-radio>
<el-radio :value="4" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:money" class="payment-icon cash" />
<span>现金</span>
</div>
</el-radio>
<el-radio :value="5" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:more" class="payment-icon other" />
<span>其他</span>
</div>
</el-radio>
</el-radio-group>
</div>
</div>
</div>
@ -101,9 +142,9 @@
<script setup>
import { ref, defineEmits, defineProps, watch, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { PersonApi } from '@/api/person'
import { DeviceApi } from '@/api/device'
import { ComboApi } from '@/api/combo'
import { OrderApi } from '@/api/order'
const props = defineProps({
visible: {
@ -126,6 +167,7 @@ const dialogVisible = ref(props.visible)
const selectedDuration = ref('')
const customExpireDate = ref('')
const loading = ref(false)
const paytype = ref(1) //
//
const enabledCombos = ref([])
const comboPageIndex = ref(0)
@ -258,6 +300,7 @@ const handleClose = () => {
customExpireDate.value = ''
loading.value = false
selectedComboId.value = null
paytype.value = 1 //
}
const handleSubmit = async () => {
@ -278,38 +321,69 @@ const handleSubmit = async () => {
// 使使使
let vipendtimeMs = 0
let selectedCombo = null
let orderPrice = '0'
const now = new Date()
if (selectedComboId.value) {
const combo = enabledCombos.value.find(c => c.id === selectedComboId.value)
if (!combo) {
selectedCombo = enabledCombos.value.find(c => c.id === selectedComboId.value)
if (!selectedCombo) {
ElMessage.warning('未找到所选套餐')
loading.value = false
return
}
const end = endOfDay(addDays(now, Number(combo.period) || 0))
const end = endOfDay(addDays(now, Number(selectedCombo.period) || 0))
vipendtimeMs = end.getTime()
orderPrice = selectedCombo.price || '0'
} else if (customExpireDate.value) {
const end = endOfDay(new Date(customExpireDate.value))
vipendtimeMs = end.getTime()
//
orderPrice = '0'
} else if (selectedDuration.value) {
const endDate = calculateEndDate()
const end = endOfDay(endDate)
vipendtimeMs = end.getTime()
//
orderPrice = '0'
} else {
ElMessage.warning('请先选择套餐或设置会员时长')
loading.value = false
return
}
//
const orderNo = `VIP${Date.now()}${Math.random().toString(36).substr(2, 4).toUpperCase()}`
//
const orderData = {
orgid: props.member.orgid,
deviceid: props.member.devicecode,
devicename: props.member.devicename || props.member.devicecode,
comboid: selectedCombo ? selectedCombo.id : 0,
orderno: orderNo,
originalprice: orderPrice,
actualprice: orderPrice,
status: 1, //
paytype: paytype.value,
paytime: now.getTime(),
vipstarttime: now.getTime(),
vipendtime: vipendtimeMs,
createtime: now.getTime(),
updatetime: now.getTime()
}
const payload = {
devicecode: props.member.devicecode,
orgid: props.member.orgid,
vipstarttime: now.getTime(),
vipendtime: vipendtimeMs,
isvip: 1
isvip: 1,
paytype: paytype.value
}
await DeviceApi.updateDeviceVip(payload)
await OrderApi.createOrder(orderData)
ElMessage.success('会员开通成功')
@ -691,6 +765,109 @@ const handleSubmit = async () => {
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}
/* 支付方式选择区域 */
.payment-method-settings {
background: #f8fafc;
border-radius: 12px;
padding: 16px;
border: 1px solid #e2e8f0;
margin-top: 16px;
}
.payment-options {
background: white;
border-radius: 10px;
padding: 16px;
border: 1px solid #e2e8f0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.payment-radio-group {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12px;
width: 100%;
}
.payment-radio {
margin: 0;
height: auto;
}
.payment-radio :deep(.el-radio__input) {
display: none;
}
.payment-radio :deep(.el-radio__label) {
padding: 0;
width: 100%;
}
.payment-option {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 12px 8px;
border: 2px solid #e2e8f0;
border-radius: 10px;
background: #fafafa;
cursor: pointer;
transition: all 0.3s ease;
text-align: center;
min-height: 80px;
justify-content: center;
}
.payment-option:hover {
border-color: #3b82f6;
background: #f0f9ff;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
}
.payment-radio.is-checked .payment-option {
border-color: #3b82f6;
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.2);
}
.payment-icon {
font-size: 24px;
margin-bottom: 4px;
}
.payment-icon.wechat {
color: #07c160;
}
.payment-icon.alipay {
color: #1677ff;
}
.payment-icon.bank {
color: #722ed1;
}
.payment-icon.cash {
color: #fa8c16;
}
.payment-icon.other {
color: #8c8c8c;
}
.payment-option span {
font-size: 12px;
font-weight: 500;
color: #374151;
}
.payment-radio.is-checked .payment-option span {
color: #1d4ed8;
font-weight: 600;
}
/* 响应式设计 */
@media (max-width: 768px) {
.duration-grid {
@ -709,5 +886,29 @@ const handleSubmit = async () => {
.vip-status {
align-self: center;
}
.payment-radio-group {
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.payment-option {
min-height: 70px;
padding: 8px 4px;
}
.payment-icon {
font-size: 20px;
}
.payment-option span {
font-size: 11px;
}
}
@media (max-width: 480px) {
.payment-radio-group {
grid-template-columns: repeat(2, 1fr);
}
}
</style>

View File

@ -80,6 +80,47 @@
</div>
</div>
<!-- 支付方式选择区域 -->
<div class="payment-method-settings">
<div class="section-title">
<Icon icon="ep:wallet" class="title-icon" />
<span>选择支付方式</span>
</div>
<div class="payment-options">
<el-radio-group v-model="paytype" class="payment-radio-group">
<el-radio :value="1" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:chat-dot-round" class="payment-icon wechat" />
<span>微信支付</span>
</div>
</el-radio>
<el-radio :value="2" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:wallet" class="payment-icon alipay" />
<span>支付宝</span>
</div>
</el-radio>
<el-radio :value="3" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:credit-card" class="payment-icon bank" />
<span>银行卡</span>
</div>
</el-radio>
<el-radio :value="4" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:money" class="payment-icon cash" />
<span>现金</span>
</div>
</el-radio>
<el-radio :value="5" class="payment-radio">
<div class="payment-option">
<Icon icon="ep:more" class="payment-icon other" />
<span>其他</span>
</div>
</el-radio>
</el-radio-group>
</div>
</div>
</div>
@ -104,6 +145,7 @@ import { ElMessage } from 'element-plus'
import { PersonApi } from '@/api/person'
import { DeviceApi } from '@/api/device'
import { ComboApi } from '@/api/combo'
import { OrderApi } from '@/api/order'
const props = defineProps({
visible: {
@ -130,6 +172,7 @@ const dialogVisible = ref(props.visible)
const selectedDuration = ref('')
const customExpireDate = ref('')
const loading = ref(false)
const paytype = ref(1) //
//
const enabledCombos = ref([])
const comboPageIndex = ref(0)
@ -259,6 +302,7 @@ const handleClose = () => {
customExpireDate.value = ''
loading.value = false
selectedComboId.value = null
paytype.value = 1 //
}
const handleSubmit = async () => {
@ -288,15 +332,19 @@ const handleSubmit = async () => {
//
let vipendtimeMs = 0
let selectedCombo = null
let orderPrice = '0'
if (selectedComboId.value) {
const combo = enabledCombos.value.find(c => c.id === selectedComboId.value)
if (!combo) {
selectedCombo = enabledCombos.value.find(c => c.id === selectedComboId.value)
if (!selectedCombo) {
ElMessage.warning('未找到所选套餐')
loading.value = false
return
}
const end = endOfDay(addDays(baseDate, Number(combo.period) || 0))
const end = endOfDay(addDays(baseDate, Number(selectedCombo.period) || 0))
vipendtimeMs = end.getTime()
orderPrice = selectedCombo.price || '0'
} else if (customExpireDate.value) {
const chosen = endOfDay(new Date(customExpireDate.value))
if (chosen.getTime() <= baseDate.getTime()) {
@ -305,25 +353,52 @@ const handleSubmit = async () => {
return
}
vipendtimeMs = chosen.getTime()
//
orderPrice = '0'
} else if (selectedDuration.value) {
const endDate = calculateEndDateFrom(baseDate)
const end = endOfDay(endDate)
vipendtimeMs = end.getTime()
//
orderPrice = '0'
} else {
ElMessage.warning('请先选择套餐或设置会员时长')
loading.value = false
return
}
//
const orderNo = `RENEW${Date.now()}${Math.random().toString(36).substr(2, 4).toUpperCase()}`
//
const orderData = {
orgid: props.member.orgid,
deviceid: props.member.deviceid,
devicename: props.member.devicename,
comboid: selectedCombo ? selectedCombo.id : 0,
orderno: orderNo,
originalprice: orderPrice,
actualprice: orderPrice,
status: 1, //
paytype: paytype.value,
paytime: now.getTime(),
vipstarttime: currentVipStartMs,
vipendtime: vipendtimeMs,
createtime: now.getTime(),
updatetime: now.getTime()
}
const payload = {
devicecode: props.member.devicecode,
orgid: props.member.orgid,
vipstarttime: currentVipStartMs,
vipendtime: vipendtimeMs,
isvip: 1
isvip: 1,
paytype: paytype.value
}
await DeviceApi.updateDeviceVip(payload)
await OrderApi.createOrder(orderData)
ElMessage.success('会员开通成功')
@ -705,6 +780,109 @@ const handleSubmit = async () => {
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}
/* 支付方式选择区域 */
.payment-method-settings {
background: #f8fafc;
border-radius: 12px;
padding: 16px;
border: 1px solid #e2e8f0;
margin-top: 16px;
}
.payment-options {
background: white;
border-radius: 10px;
padding: 16px;
border: 1px solid #e2e8f0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.payment-radio-group {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12px;
width: 100%;
}
.payment-radio {
margin: 0;
height: auto;
}
.payment-radio :deep(.el-radio__input) {
display: none;
}
.payment-radio :deep(.el-radio__label) {
padding: 0;
width: 100%;
}
.payment-option {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 12px 8px;
border: 2px solid #e2e8f0;
border-radius: 10px;
background: #fafafa;
cursor: pointer;
transition: all 0.3s ease;
text-align: center;
min-height: 80px;
justify-content: center;
}
.payment-option:hover {
border-color: #3b82f6;
background: #f0f9ff;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
}
.payment-radio.is-checked .payment-option {
border-color: #3b82f6;
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.2);
}
.payment-icon {
font-size: 24px;
margin-bottom: 4px;
}
.payment-icon.wechat {
color: #07c160;
}
.payment-icon.alipay {
color: #1677ff;
}
.payment-icon.bank {
color: #722ed1;
}
.payment-icon.cash {
color: #fa8c16;
}
.payment-icon.other {
color: #8c8c8c;
}
.payment-option span {
font-size: 12px;
font-weight: 500;
color: #374151;
}
.payment-radio.is-checked .payment-option span {
color: #1d4ed8;
font-weight: 600;
}
/* 响应式设计 */
@media (max-width: 768px) {
.duration-grid {
@ -723,5 +901,29 @@ const handleSubmit = async () => {
.vip-status {
align-self: center;
}
.payment-radio-group {
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.payment-option {
min-height: 70px;
padding: 8px 4px;
}
.payment-icon {
font-size: 20px;
}
.payment-option span {
font-size: 11px;
}
}
@media (max-width: 480px) {
.payment-radio-group {
grid-template-columns: repeat(2, 1fr);
}
}
</style>