LockTimeModal.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <template>
  2. <Teleport to="body">
  3. <!-- 遮罩层 -->
  4. <transition name="fade">
  5. <div class="modal-mask" v-if="visible" @click="close"></div>
  6. </transition>
  7. <!-- 底部弹窗面板 -->
  8. <transition name="slide-up">
  9. <div class="modal-panel" v-if="visible">
  10. <!-- 顶部小灰条 -->
  11. <div class="panel-handle"></div>
  12. <!-- 标题 -->
  13. <div class="panel-header">
  14. <h3 class="panel-title">设置自动锁定时间</h3>
  15. </div>
  16. <!-- 选项列表 -->
  17. <div class="option-list">
  18. <div
  19. class="option-item"
  20. v-for="item in options"
  21. :key="item"
  22. @click="selectItem(item)"
  23. >
  24. <span class="option-text">{{ item }}</span>
  25. <!-- 选中状态显示的红色对勾图标 -->
  26. <div class="check-icon" v-if="localSelected === item">
  27. <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
  28. <circle cx="12" cy="12" r="10" fill="#E02F44"/> <!-- 红色圆底 -->
  29. <path d="M7 12L10 15L17 8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
  30. </svg>
  31. </div>
  32. </div>
  33. </div>
  34. <!-- 底部按钮 -->
  35. <div class="footer-action">
  36. <button class="confirm-btn" @click="handleConfirm">确认</button>
  37. </div>
  38. <!-- 底部安全区 -->
  39. <div class="safe-area-bottom"></div>
  40. </div>
  41. </transition>
  42. </Teleport>
  43. </template>
  44. <script setup>
  45. import { ref, watch } from 'vue';
  46. const props = defineProps({
  47. visible: Boolean,
  48. currentValue: String // 接收父组件当前的值
  49. });
  50. const emit = defineEmits(['update:visible', 'confirm']);
  51. // 选项数据
  52. const options = ['立即', '5分钟', '10分钟'];
  53. // 内部维护一个选中状态,用于显示对勾
  54. const localSelected = ref('');
  55. // 每次打开弹窗时,把父组件传来的值赋给内部状态
  56. watch(() => props.visible, (val) => {
  57. if (val) {
  58. localSelected.value = props.currentValue;
  59. }
  60. });
  61. const close = () => {
  62. emit('update:visible', false);
  63. };
  64. // 点击列表项(只更新 UI,不提交)
  65. const selectItem = (item) => {
  66. localSelected.value = item;
  67. };
  68. // 点击确认按钮(提交数据并关闭)
  69. const handleConfirm = () => {
  70. emit('confirm', localSelected.value);
  71. close();
  72. };
  73. </script>
  74. <style scoped>
  75. .modal-mask {
  76. position: fixed; top: 0; left: 0; right: 0; bottom: 0;
  77. background: rgba(0,0,0,0.5); z-index: 998;
  78. }
  79. .modal-panel {
  80. position: fixed; left: 0; right: 0; bottom: 0;
  81. background: #fff;
  82. z-index: 999;
  83. border-radius: 16px 16px 0 0;
  84. padding-bottom: 20px;
  85. }
  86. .panel-handle {
  87. width: 36px; height: 4px; background: #E0E0E0;
  88. border-radius: 2px; margin: 10px auto;
  89. }
  90. .panel-header {
  91. padding: 10px 20px 20px;
  92. }
  93. .panel-title {
  94. font-size: 18px; font-weight: 600; color: #333;
  95. }
  96. .option-list {
  97. padding: 0 20px 20px;
  98. }
  99. .option-item {
  100. display: flex; justify-content: space-between; align-items: center;
  101. height: 50px;
  102. font-size: 16px; color: #333;
  103. /* border-bottom: 1px solid #f5f5f5; 可选分割线 */
  104. cursor: pointer;
  105. }
  106. /* 底部按钮区 */
  107. .footer-action {
  108. padding: 10px 20px;
  109. }
  110. .confirm-btn {
  111. width: 100%; height: 48px;
  112. background: #E02F44; /* 截图中的红色 */
  113. color: #fff; border: none; border-radius: 24px;
  114. font-size: 16px; font-weight: 600;
  115. }
  116. .confirm-btn:active { opacity: 0.9; }
  117. .safe-area-bottom { height: env(safe-area-inset-bottom); }
  118. /* 动画 */
  119. .fade-enter-active, .fade-leave-active { transition: opacity 0.3s; }
  120. .fade-enter-from, .fade-leave-to { opacity: 0; }
  121. .slide-up-enter-active, .slide-up-leave-active { transition: transform 0.3s; }
  122. .slide-up-enter-from, .slide-up-leave-to { transform: translateY(100%); }
  123. </style>