index.vue 3.45 KB
<!--
 * @Date: 2026-01-31 12:49:11
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2026-02-06 21:40:34
 * @FilePath: /manulife-weapp/src/components/PlanPopup/index.vue
 * @Description: 文件描述
-->
<template>
  <nut-popup
    :visible="visible"
    position="bottom"
    round
    :style="{ height: '90%' }"
    :close-on-click-overlay="true"
    :safe-area-inset-bottom="true"
    @update:visible="handleVisibleChange"
  >
    <div class="h-full flex flex-col bg-gray-50 overflow-hidden rounded-t-2xl">
      <!-- Header -->
      <div class="flex justify-between items-center px-5 py-4 bg-white border-b border-gray-100 flex-shrink-0">
        <span class="text-lg font-bold text-gray-900">{{ title }}</span>
        <div class="p-2 -mr-2" @click="handleClose">
          <IconFont name="close" size="16" color="#9CA3AF" />
        </div>
      </div>

      <!-- Scrollable Content -->
      <div class="flex-1 overflow-y-auto p-4">
        <div class="bg-white rounded-xl p-5 shadow-sm">
          <slot></slot>
        </div>
      </div>

      <!-- Footer Buttons -->
      <div
        v-show="childPopupCount === 0"
        class="p-4 bg-white border-t border-gray-100 flex gap-3 flex-shrink-0 pb-safe"
      >
        <nut-button
          plain
          type="primary"
          class="flex-1 !h-[88rpx] !rounded-[16rpx] !text-[30rpx] !border-blue-600"
          @click="handleClose"
        >
          取消
        </nut-button>
        <nut-button
          type="primary"
          color="#2563EB"
          class="flex-1 !h-[88rpx] !rounded-[16rpx] !text-[30rpx]"
          @click="handleSubmit"
        >
          生成计划书
        </nut-button>
      </div>

    </div>
  </nut-popup>
</template>

<script setup>
/**
 * @description 录入计划书弹窗容器组件
 * @param {boolean} visible - 控制弹窗显示隐藏
 * @param {string} title - 弹窗标题
 * @emits update:visible - 更新 visible 状态
 * @emits close - 关闭弹窗
 * @emits submit - 提交表单
 */
import { defineProps, defineEmits, ref, watch, provide } from 'vue';
import IconFont from '@/components/IconFont.vue';

const props = defineProps({
  visible: {
    type: Boolean,
    default: false,
  },
  title: {
    type: String,
    default: '计划书',
  },
});

const emit = defineEmits(['update:visible', 'close', 'submit']);

/**
 * 子弹窗计数器
 * @description 用于跟踪有多少个子弹窗打开,> 0 时隐藏底部按钮
 */
const childPopupCount = ref(0);


/**
 * 处理子弹窗打开事件
 */
const handleChildOpen = () => {
  childPopupCount.value++;
};

/**
 * 处理子弹窗关闭事件
 */
const handleChildClose = () => {
  if (childPopupCount.value > 0) {
    childPopupCount.value--;
  }
};

// Provide 子弹窗控制函数给所有后代组件
provide('popupControl', {
  open: handleChildOpen,
  close: handleChildClose
})

// 处理 visible 变化事件
const handleVisibleChange = (value) => {
  emit('update:visible', value);
  if (!value) {
    // 重置子弹窗计数器
    childPopupCount.value = 0;
    emit('close');
  }
}

const handleClose = () => {
  emit('update:visible', false);
  emit('close');
}

const handleSubmit = () => {
  emit('submit');
}
</script>

<style lang="less">
:deep(.nut-popup) {
  border-top-left-radius: 16px;
  border-top-right-radius: 16px;
  background-color: #F9FAFB;
}

/* 适配底部安全区 */
.pb-safe {
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}
</style>