From dfc8bf85757190202fe9ff89738538f4e0f4f530 Mon Sep 17 00:00:00 2001 From: Flow <958079825@qq.com> Date: Tue, 24 Jun 2025 10:44:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=96=E6=B6=88=E4=BC=9A=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/person/index.ts | 7 +- src/views/vip/components/RechargeDialog.vue | 148 +++++++++++++++----- src/views/vip/index.vue | 4 +- 3 files changed, 121 insertions(+), 38 deletions(-) diff --git a/src/api/person/index.ts b/src/api/person/index.ts index c9132c6a6..c1d2be39f 100644 --- a/src/api/person/index.ts +++ b/src/api/person/index.ts @@ -108,5 +108,10 @@ export const PersonApi = { // 开通会员 becomeVip: async (data: any) => { return await request.put({ url: `/system/person/become-vip`, data }) - } + }, + + //取消会员 + cancelVip: async (userid: number) => { + return await request.put({ url: `/system/person/cancel-vip?userid=` + userid }) + }, } diff --git a/src/views/vip/components/RechargeDialog.vue b/src/views/vip/components/RechargeDialog.vue index c92693498..b88fbf540 100644 --- a/src/views/vip/components/RechargeDialog.vue +++ b/src/views/vip/components/RechargeDialog.vue @@ -52,8 +52,40 @@ value-format="YYYY-MM-DD" :disabled-date="disabledDate" class="expire-picker" - @change="calculateDuration" /> + +
+
快捷选择:
+
+ + 一个月 + + + 三个月 + + + 一年 + +
+
@@ -61,10 +93,10 @@
- 开通时长 + 剩余时长
{{ calculatedDuration }}
-
从当前到期时间开始计算
+
当前会员剩余时长
@@ -138,6 +170,8 @@ watch(() => props.visible, (val) => { if (val) { // 弹窗打开时,设置默认时间为当前到期时间后一年 setDefaultExpireDate() + // 计算当前剩余时长 + calculateDuration() } }) @@ -172,51 +206,55 @@ const setDefaultExpireDate = () => { calculateDuration() } +// 设置快捷日期 +const setQuickDate = (months) => { + let baseDate + if (props.member.vipendtime) { + // 如果有到期时间,以到期时间为基准 + baseDate = new Date(props.member.vipendtime) + } else { + // 如果没有到期时间,以当前时间为基准 + baseDate = new Date() + } + + // 设置为指定月数后 + const targetDate = new Date(baseDate) + targetDate.setMonth(targetDate.getMonth() + months) + + // 格式化日期 + const year = targetDate.getFullYear() + const month = String(targetDate.getMonth() + 1).padStart(2, '0') + const day = String(targetDate.getDate()).padStart(2, '0') + + newExpireDate.value = `${year}-${month}-${day}` +} + // 计算开通时长 const calculateDuration = () => { - if (!newExpireDate.value) { - calculatedDuration.value = '' + if (!props.member.vipendtime) { + calculatedDuration.value = '未开通会员' return } - let startDate - if (props.member.vipendtime) { - // 如果有当前到期时间,以当前到期时间为起始时间 - startDate = new Date(props.member.vipendtime) - } else { - // 如果没有到期时间,以当前时间为起始时间 - startDate = new Date() - } + // 以当前时间为起始时间 + const startDate = new Date() - // 将选择的日期转换为当天的23:59:59 - const endDate = new Date(newExpireDate.value + ' 23:59:59') + // 会员的当前到期时间 + const endDate = new Date(props.member.vipendtime) // 计算时间差(毫秒) const timeDiff = endDate.getTime() - startDate.getTime() if (timeDiff <= 0) { - calculatedDuration.value = '无效时长' + calculatedDuration.value = '已过期' return } - // 转换为天、小时、分钟 - const days = Math.floor(timeDiff / (1000 * 60 * 60 * 24)) - const hours = Math.floor((timeDiff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)) - const minutes = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60)) + // 只计算天数 + const days = Math.ceil(timeDiff / (1000 * 60 * 60 * 24)) - // 格式化显示 - let durationText = '' - if (days > 0) { - durationText += `${days}天` - } - if (hours > 0) { - durationText += `${hours}小时` - } - if (minutes > 0) { - durationText += `${minutes}分钟` - } - - calculatedDuration.value = durationText || '0分钟' + // 只显示天数 + calculatedDuration.value = `${days}天` } // 禁用过去的日期 @@ -381,6 +419,9 @@ const handleSubmit = async () => { border: 1px solid #e2e8f0; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); transition: all 0.3s ease; + display: flex; + flex-direction: column; + height: 100%; } .time-card:hover { @@ -416,10 +457,14 @@ const handleSubmit = async () => { font-weight: 600; color: #1e293b; font-family: 'Courier New', monospace; - margin-bottom: 8px; - padding: 8px 12px; + margin-bottom: 12px; + padding: 12px; background: #f1f5f9; border-radius: 6px; + flex: 1; + display: flex; + align-items: center; + min-height: 40px; } .time-status { @@ -428,6 +473,7 @@ const handleSubmit = async () => { border-radius: 12px; text-align: center; font-weight: 500; + margin-top: 8px; } .time-status:not(.expired) { @@ -453,6 +499,38 @@ const handleSubmit = async () => { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } +/* 快捷选项样式 */ +.quick-options { + margin-top: 12px; + padding-top: 12px; + border-top: 1px solid #e2e8f0; +} + +.quick-title { + font-size: 12px; + color: #64748b; + margin-bottom: 8px; + font-weight: 500; +} + +.quick-buttons { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +.quick-btn { + font-size: 12px; + padding: 4px 8px; + border-radius: 6px; + transition: all 0.2s ease; +} + +.quick-btn:hover { + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(59, 130, 246, 0.2); +} + /* 开通时长卡片 */ .duration-card { background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); diff --git a/src/views/vip/index.vue b/src/views/vip/index.vue index 73c17f458..716f55797 100644 --- a/src/views/vip/index.vue +++ b/src/views/vip/index.vue @@ -264,8 +264,8 @@ const handleCancel = (member) => { // 密码验证成功 const handlePasswordVerifySuccess = async (password) => { try { - // TODO: 这里需要调用后端API验证密码并取消会员 - // 暂时显示成功消息 + // 调用后端API验证密码并取消会员 + await PersonApi.cancelVip(currentMember.value.id) ElMessage.success('已取消会员资格') // 关闭密码验证弹窗 passwordVerifyVisible.value = false