hookehuyr

refactor(cycle-selection): 使用van-popup组件重构周期选择弹窗

移除手动计算弹窗尺寸的逻辑,改用vant组件内置的弹窗功能
添加自定义单选按钮样式,优化用户体验
<template>
<div class="cycle-selection-page">
<van-config-provider :theme-vars="themeVars">
<div class="cycle-popup">
<van-config-provider :theme-vars="themeVars">
<van-popup
v-model:show="showPopup"
position="center"
:style="{ width: '85vw', maxWidth: '500px', borderRadius: '12px' }"
:close-on-click-overlay="false"
>
<div class="cycle-popup-content">
<div class="popup-header">
<h3>选择周期</h3>
</div>
<div class="popup-content">
<p style="padding-top: 0.85rem; text-align: justify;">{{ cycle_note }}</p>
<p class="cycle-note">{{ cycle_note }}</p>
<van-radio-group v-model="selectedCycle">
<div v-for="cycle in cycleList" :key="cycle.id" class="cycle-item">
<van-radio :name="cycle.id">
<template #icon="{ checked }">
<div class="custom-icon" :class="{ checked }">
<van-icon name="success" v-if="checked" />
</div>
</template>
<div class="cycle-info">
<div class="cycle-title">{{ cycle.title }}</div>
<div class="cycle-time">
......@@ -25,17 +35,23 @@
</van-radio-group>
</div>
<div class="popup-footer">
<van-button type="primary" class="confirm-btn" @click="confirmCycleSelection" :disabled="!selectedCycle">
<van-button
type="primary"
block
round
@click="confirmCycleSelection"
:disabled="!selectedCycle"
>
确认选择
</van-button>
</div>
</div>
</van-config-provider>
</div>
</van-popup>
</van-config-provider>
</template>
<script setup>
import { ref, onMounted, nextTick, onUnmounted } from 'vue';
import { ref, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { getCycleListAPI } from '@/api/cycle';
import { styleColor } from '@/constant.js';
......@@ -57,74 +73,9 @@ const themeVars = {
const cycleList = ref([]);
const selectedCycle = ref('');
const cycle_note = ref('');
const showPopup = ref(false);
/**
* 动态设置弹框尺寸
*/
const setPopupSize = () => {
nextTick(() => {
const popupElement = document.querySelector('.cycle-popup');
if (popupElement) {
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
// 设置宽度为屏幕的85%
const popupWidth = screenWidth * 0.85;
popupElement.style.width = `${popupWidth}px`;
// 根据屏幕尺寸动态计算最大宽度
let maxWidth;
if (screenWidth <= 480) {
// 小屏设备
maxWidth = screenWidth * 0.9;
} else if (screenWidth <= 768) {
// 中等屏幕设备
maxWidth = 420;
} else {
// 大屏设备
maxWidth = 500;
}
popupElement.style.maxWidth = `${maxWidth}px`;
// 设置高度为屏幕的70%
const popupHeight = screenHeight * 0.7;
popupElement.style.height = `${popupHeight}px`;
// 计算内容区域高度
calculatePopupContentHeight();
}
});
};
/**
* 动态计算弹窗内容区域高度
*/
const calculatePopupContentHeight = () => {
nextTick(() => {
const popupElement = document.querySelector('.cycle-popup');
const headerElement = document.querySelector('.popup-header');
const footerElement = document.querySelector('.popup-footer');
const contentElement = document.querySelector('.popup-content');
if (popupElement && headerElement && footerElement && contentElement) {
const popupHeight = popupElement.offsetHeight;
const headerHeight = headerElement.offsetHeight;
const footerHeight = footerElement.offsetHeight;
const padding = 40; // 上下padding的总和
const contentHeight = popupHeight - headerHeight - footerHeight - padding;
contentElement.style.height = `${contentHeight}px`;
}
});
};
/**
* 窗口尺寸变化处理函数
*/
const handleResize = () => {
setPopupSize();
};
/**
* 获取周期列表
......@@ -142,8 +93,8 @@ const getCycleList = async (form_code) => {
// 设置周期列表
cycleList.value = data.cycle_list;
cycle_note.value = data.cycle_note;
// 设置弹框尺寸
setPopupSize();
// 显示弹框
showPopup.value = true;
} else {
// 如果不需要周期选择,检查未完成表单后跳转到目标页面
const targetRoute = sessionStorage.getItem('cycle_target_route');
......@@ -245,40 +196,15 @@ onMounted(() => {
console.error('缺少表单代码参数');
$router.replace('/');
}
// 监听窗口尺寸变化
window.addEventListener('resize', handleResize);
// 监听屏幕方向变化
window.addEventListener('orientationchange', handleResize);
});
onUnmounted(() => {
// 清理事件监听器
window.removeEventListener('resize', handleResize);
window.removeEventListener('orientationchange', handleResize);
});
</script>
<style lang="less">
.cycle-selection-page {
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
.cycle-popup-content {
display: flex;
align-items: center;
justify-content: center;
.cycle-popup {
width: 85vw;
height: 70vh;
background: white;
border-radius: 12px;
display: flex;
flex-direction: column;
overflow: hidden;
position: relative;
margin: 0 auto;
}
flex-direction: column;
max-height: 70vh;
.popup-header {
padding: 20px;
text-align: center;
......@@ -300,6 +226,14 @@ onUnmounted(() => {
min-height: 0;
}
.cycle-note {
padding-top: 0.85rem;
text-align: justify;
margin-bottom: 1rem;
color: #666;
line-height: 1.5;
}
.cycle-item {
padding: 15px 0;
border-bottom: 1px solid #f5f5f5;
......@@ -340,13 +274,21 @@ onUnmounted(() => {
flex-shrink: 0;
}
.confirm-btn {
width: 100%;
height: 44px;
border-radius: 8px;
font-size: 16px;
font-weight: 500;
.custom-icon {
width: 20px;
height: 20px;
border: 2px solid #ddd;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
&.checked {
border-color: var(--van-radio-checked-icon-color);
background-color: var(--van-radio-checked-icon-color);
color: white;
}
}
}
</style>
......