feat(plan): 集成录入计划书方案B并扩展弹窗组件
新增方案B内容组件,包含币种、计划、性别、年龄等字段,并还原设计稿布局与交互。 修改首页,将热卖产品的"计划书"按钮点击事件改为弹出录入界面,实现多方案演示。 扩展组件类型声明,注册新增组件以供使用。
Showing
6 changed files
with
536 additions
and
2 deletions
| ... | @@ -13,6 +13,8 @@ declare module 'vue' { | ... | @@ -13,6 +13,8 @@ declare module 'vue' { |
| 13 | NavHeader: typeof import('./src/components/NavHeader.vue')['default'] | 13 | NavHeader: typeof import('./src/components/NavHeader.vue')['default'] |
| 14 | NutAvatar: typeof import('@nutui/nutui-taro')['Avatar'] | 14 | NutAvatar: typeof import('@nutui/nutui-taro')['Avatar'] |
| 15 | NutButton: typeof import('@nutui/nutui-taro')['Button'] | 15 | NutButton: typeof import('@nutui/nutui-taro')['Button'] |
| 16 | + NutInput: typeof import('@nutui/nutui-taro')['Input'] | ||
| 17 | + NutPicker: typeof import('@nutui/nutui-taro')['Picker'] | ||
| 16 | NutPopup: typeof import('@nutui/nutui-taro')['Popup'] | 18 | NutPopup: typeof import('@nutui/nutui-taro')['Popup'] |
| 17 | NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] | 19 | NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] |
| 18 | NutTabPane: typeof import('@nutui/nutui-taro')['TabPane'] | 20 | NutTabPane: typeof import('@nutui/nutui-taro')['TabPane'] |
| ... | @@ -22,11 +24,14 @@ declare module 'vue' { | ... | @@ -22,11 +24,14 @@ declare module 'vue' { |
| 22 | OfficeViewer: typeof import('./src/components/OfficeViewer.vue')['default'] | 24 | OfficeViewer: typeof import('./src/components/OfficeViewer.vue')['default'] |
| 23 | PdfPreview: typeof import('./src/components/PdfPreview.vue')['default'] | 25 | PdfPreview: typeof import('./src/components/PdfPreview.vue')['default'] |
| 24 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] | 26 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] |
| 27 | + PlanPopup: typeof import('./src/components/PlanPopup/index.vue')['default'] | ||
| 25 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] | 28 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] |
| 26 | QrCode: typeof import('./src/components/qrCode.vue')['default'] | 29 | QrCode: typeof import('./src/components/qrCode.vue')['default'] |
| 27 | QrCodeSearch: typeof import('./src/components/qrCodeSearch.vue')['default'] | 30 | QrCodeSearch: typeof import('./src/components/qrCodeSearch.vue')['default'] |
| 28 | RouterLink: typeof import('vue-router')['RouterLink'] | 31 | RouterLink: typeof import('vue-router')['RouterLink'] |
| 29 | RouterView: typeof import('vue-router')['RouterView'] | 32 | RouterView: typeof import('vue-router')['RouterView'] |
| 33 | + SchemeA: typeof import('./src/components/PlanSchemes/SchemeA.vue')['default'] | ||
| 34 | + SchemeB: typeof import('./src/components/PlanSchemes/SchemeB.vue')['default'] | ||
| 30 | SectionCard: typeof import('./src/components/SectionCard.vue')['default'] | 35 | SectionCard: typeof import('./src/components/SectionCard.vue')['default'] |
| 31 | SectionItem: typeof import('./src/components/SectionItem.vue')['default'] | 36 | SectionItem: typeof import('./src/components/SectionItem.vue')['default'] |
| 32 | TabBar: typeof import('./src/components/TabBar.vue')['default'] | 37 | TabBar: typeof import('./src/components/TabBar.vue')['default'] | ... | ... |
| 1 | +## [2026-01-31] - 集成录入计划书方案B | ||
| 2 | + | ||
| 3 | +### 新增 | ||
| 4 | +- 新增录入计划书方案B内容组件 (`src/components/PlanSchemes/SchemeB.vue`) | ||
| 5 | + - 还原设计稿 (`docs/design/manulife-V1/录入计划书/方案B`) 布局与交互 | ||
| 6 | + - 包含币种、计划、性别、年龄、保险期间、交费期间、保费等字段 | ||
| 7 | + | ||
| 8 | +### 变更 | ||
| 9 | +- 修改首页 (`src/pages/index/index.vue`) | ||
| 10 | + - 引入 `PlanPopup`, `SchemeA`, `SchemeB` 组件 | ||
| 11 | + - 将热卖产品的"计划书"按钮点击事件改为弹出录入界面 | ||
| 12 | + - 第一个产品对应方案A,第二个产品对应方案B,实现多方案演示 | ||
| 13 | + | ||
| 14 | +--- | ||
| 15 | + | ||
| 16 | +**详细信息**: | ||
| 17 | +- **新增文件**: `src/components/PlanSchemes/SchemeB.vue` | ||
| 18 | +- **修改文件**: `src/pages/index/index.vue` | ||
| 19 | +- **技术栈**: Vue 3, Tailwind CSS, NutUI | ||
| 20 | + | ||
| 21 | +## [2026-01-31] - 新增录入计划书功能 | ||
| 22 | + | ||
| 23 | +### 新增 | ||
| 24 | +- 新增录入计划书弹窗容器组件 (`src/components/PlanPopup`) | ||
| 25 | + - 使用 `nut-popup` 实现底部弹出的 90% 高度弹窗 | ||
| 26 | + - 支持 `slot` 插入不同内容,具备良好的扩展性 | ||
| 27 | +- 新增录入计划书方案A内容组件 (`src/components/PlanSchemes/SchemeA.vue`) | ||
| 28 | + - 还原设计稿 (`docs/design/manulife-V1/录入计划书/方案A`) 布局与交互 | ||
| 29 | + - 使用 Tailwind CSS 和 NutUI 组件 (`nut-input`, `nut-picker`, `nut-button` 等) 实现 | ||
| 30 | + - 包含完整的表单逻辑:姓名、性别、年龄、行业、年收入、家庭结构、保险需求、期望收益率 | ||
| 31 | + - 使用图标和交互式选择器提升用户体验 | ||
| 32 | + | ||
| 33 | +--- | ||
| 34 | + | ||
| 35 | +**详细信息**: | ||
| 36 | +- **新增文件**: `src/components/PlanPopup/index.vue`, `src/components/PlanSchemes/SchemeA.vue` | ||
| 37 | +- **技术栈**: Vue 3, Tailwind CSS, NutUI | ||
| 38 | +- **测试状态**: 已通过 | ||
| 39 | +- **备注**: | ||
| 40 | + - 为后续新增其他方案预留了目录结构 (`src/components/PlanSchemes/`) | ||
| 41 | + | ||
| 1 | ## [2026-01-31] - 重构文件操作逻辑,消除代码重复 | 42 | ## [2026-01-31] - 重构文件操作逻辑,消除代码重复 |
| 2 | 43 | ||
| 3 | ### 重构 | 44 | ### 重构 | ... | ... |
src/components/PlanPopup/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2026-01-31 12:49:11 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2026-01-31 12:50:32 | ||
| 5 | + * @FilePath: /manulife-weapp/src/components/PlanPopup/index.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <nut-popup :visible="visible" position="bottom" round :style="{ height: '90%' }" | ||
| 10 | + @update:visible="emit('update:visible', $event)" :close-on-click-overlay="true"> | ||
| 11 | + <div class="h-full flex flex-col bg-white overflow-hidden rounded-t-2xl"> | ||
| 12 | + <slot></slot> | ||
| 13 | + </div> | ||
| 14 | + </nut-popup> | ||
| 15 | +</template> | ||
| 16 | + | ||
| 17 | +<script setup> | ||
| 18 | +/** | ||
| 19 | + * @description 录入计划书弹窗容器组件 | ||
| 20 | + * @param {boolean} visible - 控制弹窗显示隐藏 | ||
| 21 | + * @emits update:visible - 更新 visible 状态 | ||
| 22 | + */ | ||
| 23 | +import { defineProps, defineEmits } from 'vue'; | ||
| 24 | + | ||
| 25 | +const props = defineProps({ | ||
| 26 | + visible: { | ||
| 27 | + type: Boolean, | ||
| 28 | + default: false, | ||
| 29 | + }, | ||
| 30 | +}); | ||
| 31 | + | ||
| 32 | +const emit = defineEmits(['update:visible']); | ||
| 33 | +</script> | ||
| 34 | + | ||
| 35 | +<style lang="less" scoped> | ||
| 36 | +:deep(.nut-popup) { | ||
| 37 | + border-top-left-radius: 16px; | ||
| 38 | + border-top-right-radius: 16px; | ||
| 39 | +} | ||
| 40 | +</style> |
src/components/PlanSchemes/SchemeA.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="flex flex-col h-full bg-white"> | ||
| 3 | + <!-- Header --> | ||
| 4 | + <div class="flex justify-between items-center px-6 py-6 border-b border-gray-100"> | ||
| 5 | + <span class="text-lg font-normal text-gray-800">申请计划书</span> | ||
| 6 | + <img | ||
| 7 | + class="w-6 h-6" | ||
| 8 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng9edea6fd27cf6cb2ff57c90a0834dcda1f86b6072ce07f5e7e07069c2d3b3e9e" | ||
| 9 | + @click="close" | ||
| 10 | + /> | ||
| 11 | + </div> | ||
| 12 | + | ||
| 13 | + <!-- Scrollable Content --> | ||
| 14 | + <div class="flex-1 overflow-y-auto px-6 py-4"> | ||
| 15 | + <!-- 客户姓名 --> | ||
| 16 | + <div class="text-sm text-gray-700 mb-2">客户姓名</div> | ||
| 17 | + <nut-input | ||
| 18 | + v-model="form.name" | ||
| 19 | + placeholder="请输入客户姓名" | ||
| 20 | + class="!border !border-gray-200 !rounded-lg !px-3 !py-2 mb-4" | ||
| 21 | + :border="false" | ||
| 22 | + /> | ||
| 23 | + | ||
| 24 | + <!-- 性别 --> | ||
| 25 | + <div class="text-sm text-gray-700 mb-2">性别</div> | ||
| 26 | + <div class="flex items-center mb-4"> | ||
| 27 | + <div | ||
| 28 | + class="flex items-center mr-8 cursor-pointer" | ||
| 29 | + @click="form.gender = 'male'" | ||
| 30 | + > | ||
| 31 | + <img | ||
| 32 | + class="w-5 h-5 mr-2" | ||
| 33 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPngaa89ac8577908dfb2901e1067741dcdc9a5b58739da04a5243e45c296275f5ef" | ||
| 34 | + /> | ||
| 35 | + <span :class="form.gender === 'male' ? 'text-blue-600 font-bold' : 'text-gray-800'">男</span> | ||
| 36 | + </div> | ||
| 37 | + <div | ||
| 38 | + class="flex items-center cursor-pointer" | ||
| 39 | + @click="form.gender = 'female'" | ||
| 40 | + > | ||
| 41 | + <img | ||
| 42 | + class="w-5 h-5 mr-2" | ||
| 43 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng86258dc38e0dde555b09ba68a94fb042ce0172628791dc178dd1a7c0c89a824f" | ||
| 44 | + /> | ||
| 45 | + <span :class="form.gender === 'female' ? 'text-blue-600 font-bold' : 'text-gray-800'">女</span> | ||
| 46 | + </div> | ||
| 47 | + </div> | ||
| 48 | + | ||
| 49 | + <!-- 年龄 --> | ||
| 50 | + <div class="text-sm text-gray-700 mb-2">年龄</div> | ||
| 51 | + <nut-input | ||
| 52 | + v-model="form.age" | ||
| 53 | + type="digit" | ||
| 54 | + placeholder="请输入年龄" | ||
| 55 | + class="!border !border-gray-200 !rounded-lg !px-3 !py-2 mb-4" | ||
| 56 | + :border="false" | ||
| 57 | + /> | ||
| 58 | + | ||
| 59 | + <!-- 行业 --> | ||
| 60 | + <div class="text-sm text-gray-700 mb-2">行业</div> | ||
| 61 | + <div | ||
| 62 | + class="flex justify-between items-center p-3 border border-gray-200 rounded-lg mb-4 bg-white" | ||
| 63 | + @click="showIndustryPicker = true" | ||
| 64 | + > | ||
| 65 | + <span :class="form.industry ? 'text-gray-900' : 'text-gray-400'" class="text-sm"> | ||
| 66 | + {{ form.industry || '请选择职业' }} | ||
| 67 | + </span> | ||
| 68 | + <img | ||
| 69 | + class="w-3.5 h-3.5" | ||
| 70 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPngcf768ccd4a7e2a9d761be1bbd425d7c09e15f44c66570d21e5e9121448ccada5" | ||
| 71 | + /> | ||
| 72 | + </div> | ||
| 73 | + | ||
| 74 | + <!-- 年收入区间 --> | ||
| 75 | + <div class="text-sm text-gray-700 mb-2">年收入区间</div> | ||
| 76 | + <div class="relative mb-4"> | ||
| 77 | + <nut-input | ||
| 78 | + v-model="form.income" | ||
| 79 | + type="digit" | ||
| 80 | + placeholder="请输入年收入" | ||
| 81 | + class="!border !border-gray-200 !rounded-lg !px-3 !py-2 !pr-10" | ||
| 82 | + :border="false" | ||
| 83 | + /> | ||
| 84 | + <span class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 text-sm">万元</span> | ||
| 85 | + </div> | ||
| 86 | + | ||
| 87 | + <!-- 家庭结构 --> | ||
| 88 | + <div class="text-sm text-gray-700 mb-2">家庭结构</div> | ||
| 89 | + <div class="flex flex-wrap gap-4 mb-4"> | ||
| 90 | + <div | ||
| 91 | + v-for="item in familyOptions" | ||
| 92 | + :key="item.value" | ||
| 93 | + class="flex items-center cursor-pointer min-w-[60px]" | ||
| 94 | + @click="toggleSelection('family', item.value)" | ||
| 95 | + > | ||
| 96 | + <img :src="item.icon" class="w-5 h-5 mr-2" /> | ||
| 97 | + <span :class="form.family.includes(item.value) ? 'text-blue-600 font-bold' : 'text-gray-800'" class="text-sm"> | ||
| 98 | + {{ item.label }} | ||
| 99 | + </span> | ||
| 100 | + </div> | ||
| 101 | + </div> | ||
| 102 | + | ||
| 103 | + <!-- 保险需求 --> | ||
| 104 | + <div class="text-sm text-gray-700 mb-2">保险需求</div> | ||
| 105 | + <div class="flex flex-wrap gap-4 mb-4"> | ||
| 106 | + <div | ||
| 107 | + v-for="item in insuranceOptions" | ||
| 108 | + :key="item.value" | ||
| 109 | + class="flex items-center cursor-pointer min-w-[85px]" | ||
| 110 | + @click="toggleSelection('insurance', item.value)" | ||
| 111 | + > | ||
| 112 | + <img :src="item.icon" class="w-5 h-5 mr-2" /> | ||
| 113 | + <span :class="form.insurance.includes(item.value) ? 'text-blue-600 font-bold' : 'text-gray-800'" class="text-sm"> | ||
| 114 | + {{ item.label }} | ||
| 115 | + </span> | ||
| 116 | + </div> | ||
| 117 | + </div> | ||
| 118 | + | ||
| 119 | + <!-- 期望收益率 --> | ||
| 120 | + <div class="text-sm text-gray-700 mb-2">期望收益率</div> | ||
| 121 | + <div class="relative mb-8"> | ||
| 122 | + <nut-input | ||
| 123 | + v-model="form.returnRate" | ||
| 124 | + type="digit" | ||
| 125 | + placeholder="请输入期望收益率" | ||
| 126 | + class="!border !border-gray-200 !rounded-lg !px-3 !py-2 !pr-10" | ||
| 127 | + :border="false" | ||
| 128 | + /> | ||
| 129 | + <span class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 text-sm">%</span> | ||
| 130 | + </div> | ||
| 131 | + </div> | ||
| 132 | + | ||
| 133 | + <!-- Footer Buttons --> | ||
| 134 | + <div class="p-6 pt-2 pb-8 flex justify-between gap-4 border-t border-gray-100 bg-white"> | ||
| 135 | + <div | ||
| 136 | + class="flex-1 py-3 text-center border border-blue-600 text-blue-600 rounded-lg text-base" | ||
| 137 | + @click="close" | ||
| 138 | + > | ||
| 139 | + 取消 | ||
| 140 | + </div> | ||
| 141 | + <div | ||
| 142 | + class="flex-1 py-3 text-center bg-blue-600 text-white rounded-lg text-base" | ||
| 143 | + @click="submit" | ||
| 144 | + > | ||
| 145 | + 提交申请 | ||
| 146 | + </div> | ||
| 147 | + </div> | ||
| 148 | + | ||
| 149 | + <!-- Industry Picker --> | ||
| 150 | + <nut-popup position="bottom" v-model:visible="showIndustryPicker"> | ||
| 151 | + <nut-picker | ||
| 152 | + :columns="industryColumns" | ||
| 153 | + title="选择行业" | ||
| 154 | + @confirm="confirmIndustry" | ||
| 155 | + @cancel="showIndustryPicker = false" | ||
| 156 | + /> | ||
| 157 | + </nut-popup> | ||
| 158 | + </div> | ||
| 159 | +</template> | ||
| 160 | + | ||
| 161 | +<script setup> | ||
| 162 | +/** | ||
| 163 | + * @description 录入计划书 - 方案A 内容组件 | ||
| 164 | + * @emits close - 关闭弹窗事件 | ||
| 165 | + * @emits submit - 提交事件,携带表单数据 | ||
| 166 | + */ | ||
| 167 | +import { ref, reactive } from 'vue'; | ||
| 168 | + | ||
| 169 | +const emit = defineEmits(['close', 'submit']); | ||
| 170 | + | ||
| 171 | +const form = reactive({ | ||
| 172 | + name: '', | ||
| 173 | + gender: '', // 'male' | 'female' | ||
| 174 | + age: '', | ||
| 175 | + industry: '', | ||
| 176 | + income: '', | ||
| 177 | + family: [], | ||
| 178 | + insurance: [], | ||
| 179 | + returnRate: '', | ||
| 180 | +}); | ||
| 181 | + | ||
| 182 | +const showIndustryPicker = ref(false); | ||
| 183 | + | ||
| 184 | +const industryColumns = [ | ||
| 185 | + { text: 'IT/互联网', value: 'it' }, | ||
| 186 | + { text: '金融', value: 'finance' }, | ||
| 187 | + { text: '教育', value: 'education' }, | ||
| 188 | + { text: '医疗', value: 'medical' }, | ||
| 189 | + { text: '其他', value: 'other' }, | ||
| 190 | +]; | ||
| 191 | + | ||
| 192 | +const familyOptions = [ | ||
| 193 | + { label: '配偶', value: 'spouse', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng78cf3ef069859580d9e4f17fc5095d6fbf460f1437ac3deaa43ab0a5a71a775e' }, | ||
| 194 | + { label: '子女', value: 'children', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng845af3ba96be197313380a56d1607660c93f44687cb6e966dbf28c9d51142dd9' }, | ||
| 195 | + { label: '父母', value: 'parents', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng845af3ba96be197313380a56d1607660c93f44687cb6e966dbf28c9d51142dd9' }, // Using same icon as placeholder from design if needed, or check if unique one exists. Design uses same for parents/others in reference code snippet (lines 70, 78) but distinct in variable name logic? Actually design uses specific URLs. I copied from reference. | ||
| 196 | + { label: '其他', value: 'others', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng845af3ba96be197313380a56d1607660c93f44687cb6e966dbf28c9d51142dd9' }, | ||
| 197 | +]; | ||
| 198 | + | ||
| 199 | +// Reference code lines 70, 78 use the same URL as 62 (children). I'll use them as is. | ||
| 200 | + | ||
| 201 | +const insuranceOptions = [ | ||
| 202 | + { label: '人身保障', value: 'life', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng78cf3ef069859580d9e4f17fc5095d6fbf460f1437ac3deaa43ab0a5a71a775e' }, | ||
| 203 | + { label: '财富传承', value: 'wealth', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng845af3ba96be197313380a56d1607660c93f44687cb6e966dbf28c9d51142dd9' }, | ||
| 204 | + { label: '子女教育', value: 'education', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng845af3ba96be197313380a56d1607660c93f44687cb6e966dbf28c9d51142dd9' }, | ||
| 205 | + { label: '养老规划', value: 'pension', icon: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng845af3ba96be197313380a56d1607660c93f44687cb6e966dbf28c9d51142dd9' }, | ||
| 206 | +]; | ||
| 207 | + | ||
| 208 | +const toggleSelection = (field, value) => { | ||
| 209 | + const index = form[field].indexOf(value); | ||
| 210 | + if (index === -1) { | ||
| 211 | + form[field].push(value); | ||
| 212 | + } else { | ||
| 213 | + form[field].splice(index, 1); | ||
| 214 | + } | ||
| 215 | +}; | ||
| 216 | + | ||
| 217 | +const confirmIndustry = ({ selectedValue, selectedOptions }) => { | ||
| 218 | + form.industry = selectedOptions[0].text; | ||
| 219 | + showIndustryPicker.value = false; | ||
| 220 | +}; | ||
| 221 | + | ||
| 222 | +const close = () => { | ||
| 223 | + emit('close'); | ||
| 224 | +}; | ||
| 225 | + | ||
| 226 | +const submit = () => { | ||
| 227 | + // Validate form if needed | ||
| 228 | + console.log('Submit form:', form); | ||
| 229 | + emit('submit', form); | ||
| 230 | +}; | ||
| 231 | +</script> | ||
| 232 | + | ||
| 233 | +<style lang="less" scoped> | ||
| 234 | +/* Override NutUI input styles to match design */ | ||
| 235 | +:deep(.nut-input) { | ||
| 236 | + padding: 0; | ||
| 237 | + background: transparent; | ||
| 238 | +} | ||
| 239 | +</style> |
src/components/PlanSchemes/SchemeB.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="flex flex-col h-full bg-gray-50"> | ||
| 3 | + <!-- Header --> | ||
| 4 | + <div class="flex justify-between items-center px-5 py-5 bg-white rounded-t-xl"> | ||
| 5 | + <span class="text-lg font-normal text-gray-900">保险计划书申请</span> | ||
| 6 | + <img | ||
| 7 | + class="w-5 h-5" | ||
| 8 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng43284a8c3fc98c60509d6d415fed8113414c4c0b072fa0f3b41fc26e76a03b15" | ||
| 9 | + @click="close" | ||
| 10 | + /> | ||
| 11 | + </div> | ||
| 12 | + | ||
| 13 | + <!-- Scrollable Content --> | ||
| 14 | + <div class="flex-1 overflow-y-auto p-4"> | ||
| 15 | + <div class="bg-white rounded-xl p-5 shadow-sm"> | ||
| 16 | + <!-- 币种 --> | ||
| 17 | + <div class="flex justify-between items-start mb-5"> | ||
| 18 | + <span class="text-sm text-gray-600 mt-1.5">币种</span> | ||
| 19 | + <div class="bg-blue-50 rounded-md px-3 py-1.5"> | ||
| 20 | + <span class="text-sm text-blue-600">美元保单</span> | ||
| 21 | + </div> | ||
| 22 | + </div> | ||
| 23 | + | ||
| 24 | + <!-- 计划 --> | ||
| 25 | + <div class="flex justify-between items-start mb-5"> | ||
| 26 | + <span class="text-sm text-gray-600 mt-1.5">计划</span> | ||
| 27 | + <div class="bg-blue-50 rounded-md px-3 py-1.5"> | ||
| 28 | + <span class="text-sm text-blue-600">基础情景</span> | ||
| 29 | + </div> | ||
| 30 | + </div> | ||
| 31 | + | ||
| 32 | + <!-- 附加计划 & 性别 --> | ||
| 33 | + <div class="flex justify-between items-center mb-5"> | ||
| 34 | + <span class="text-base text-gray-900">附加计划</span> | ||
| 35 | + <div class="flex items-center"> | ||
| 36 | + <span class="text-sm text-gray-600 mr-4">性别</span> | ||
| 37 | + <div class="flex items-center"> | ||
| 38 | + <div | ||
| 39 | + class="flex items-center mr-4 cursor-pointer" | ||
| 40 | + @click="form.gender = 'female'" | ||
| 41 | + > | ||
| 42 | + <img | ||
| 43 | + class="w-4.5 h-4.5 mr-1" | ||
| 44 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng1015590381802ed3f770814c3e05e4b73e6534f72e97a9a0721c459ed1dbac6a" | ||
| 45 | + /> | ||
| 46 | + <span :class="form.gender === 'female' ? 'text-blue-600 font-bold' : 'text-gray-800'" class="text-sm">女</span> | ||
| 47 | + </div> | ||
| 48 | + <div | ||
| 49 | + class="flex items-center cursor-pointer" | ||
| 50 | + @click="form.gender = 'male'" | ||
| 51 | + > | ||
| 52 | + <img | ||
| 53 | + class="w-4.5 h-4.5 mr-1" | ||
| 54 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPngb0bb17420dba3691281e919f69d1e06a69d343e53ee68ad570ec2fe340cdb09c" | ||
| 55 | + /> | ||
| 56 | + <span :class="form.gender === 'male' ? 'text-blue-600 font-bold' : 'text-gray-500'" class="text-sm">男</span> | ||
| 57 | + </div> | ||
| 58 | + </div> | ||
| 59 | + </div> | ||
| 60 | + </div> | ||
| 61 | + | ||
| 62 | + <!-- 年龄 --> | ||
| 63 | + <div class="flex justify-between items-center mb-5"> | ||
| 64 | + <span class="text-sm text-gray-600">年龄</span> | ||
| 65 | + <div class="flex items-center"> | ||
| 66 | + <nut-input | ||
| 67 | + v-model="form.age" | ||
| 68 | + type="digit" | ||
| 69 | + placeholder="请输入" | ||
| 70 | + class="!p-0 !bg-transparent !w-16 !text-right !text-gray-900 !text-sm" | ||
| 71 | + :border="false" | ||
| 72 | + input-align="right" | ||
| 73 | + /> | ||
| 74 | + <span class="text-sm text-gray-900 mx-1">周岁</span> | ||
| 75 | + <img | ||
| 76 | + class="w-4 h-4" | ||
| 77 | + src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPng4f1ca24a37fc014649249f2a5db80cdec300bf86076429fb76cc42dff9b59f3d" | ||
| 78 | + /> | ||
| 79 | + </div> | ||
| 80 | + </div> | ||
| 81 | + | ||
| 82 | + <!-- 保险期间 --> | ||
| 83 | + <div class="flex justify-between items-start mb-5"> | ||
| 84 | + <span class="text-sm text-gray-600 mt-1.5">保险期间</span> | ||
| 85 | + <div class="bg-blue-50 rounded-md px-3 py-1.5"> | ||
| 86 | + <span class="text-sm text-blue-600">终身</span> | ||
| 87 | + </div> | ||
| 88 | + </div> | ||
| 89 | + | ||
| 90 | + <!-- 交费期间 --> | ||
| 91 | + <div class="text-sm text-gray-600 mb-3">交费期间</div> | ||
| 92 | + <div class="flex flex-wrap gap-3 mb-5"> | ||
| 93 | + <div | ||
| 94 | + v-for="period in paymentPeriods" | ||
| 95 | + :key="period" | ||
| 96 | + class="px-4 py-2 rounded-lg text-sm cursor-pointer transition-colors border" | ||
| 97 | + :class="form.paymentPeriod === period ? 'bg-blue-600 text-white border-blue-600' : 'bg-gray-50 text-gray-600 border-gray-200'" | ||
| 98 | + @click="form.paymentPeriod = period" | ||
| 99 | + > | ||
| 100 | + {{ period }} | ||
| 101 | + </div> | ||
| 102 | + </div> | ||
| 103 | + | ||
| 104 | + <!-- 年交保费 --> | ||
| 105 | + <div class="text-sm text-gray-600 mb-2">年交保费</div> | ||
| 106 | + <div class="bg-gray-50 rounded-lg border border-gray-200 p-3 flex justify-between items-center"> | ||
| 107 | + <nut-input | ||
| 108 | + v-model="form.premium" | ||
| 109 | + type="digit" | ||
| 110 | + placeholder="请输入保费" | ||
| 111 | + class="!p-0 !bg-transparent flex-1 !text-base !text-gray-900" | ||
| 112 | + :border="false" | ||
| 113 | + /> | ||
| 114 | + <span class="text-sm text-gray-500 ml-2">美元</span> | ||
| 115 | + </div> | ||
| 116 | + </div> | ||
| 117 | + </div> | ||
| 118 | + | ||
| 119 | + <!-- Footer Buttons --> | ||
| 120 | + <div class="p-4 pt-2 pb-8 flex justify-between gap-4 bg-gray-50"> | ||
| 121 | + <div | ||
| 122 | + class="flex-1 py-3 text-center border border-blue-600 text-blue-600 rounded-lg text-base bg-white" | ||
| 123 | + @click="close" | ||
| 124 | + > | ||
| 125 | + 取消 | ||
| 126 | + </div> | ||
| 127 | + <div | ||
| 128 | + class="flex-1 py-3 text-center bg-blue-600 text-white rounded-lg text-base" | ||
| 129 | + @click="submit" | ||
| 130 | + > | ||
| 131 | + 提交申请 | ||
| 132 | + </div> | ||
| 133 | + </div> | ||
| 134 | + </div> | ||
| 135 | +</template> | ||
| 136 | + | ||
| 137 | +<script setup> | ||
| 138 | +/** | ||
| 139 | + * @description 录入计划书 - 方案B 内容组件 | ||
| 140 | + * @emits close - 关闭弹窗事件 | ||
| 141 | + * @emits submit - 提交事件,携带表单数据 | ||
| 142 | + */ | ||
| 143 | +import { reactive, defineEmits } from 'vue'; | ||
| 144 | + | ||
| 145 | +const emit = defineEmits(['close', 'submit']); | ||
| 146 | + | ||
| 147 | +const form = reactive({ | ||
| 148 | + currency: '美元保单', | ||
| 149 | + plan: '基础情景', | ||
| 150 | + gender: 'female', | ||
| 151 | + age: '30', | ||
| 152 | + insurancePeriod: '终身', | ||
| 153 | + paymentPeriod: '10年交', | ||
| 154 | + premium: '100000', | ||
| 155 | +}); | ||
| 156 | + | ||
| 157 | +const paymentPeriods = ['10年交', '3年交', '5年交', '躸交', '2年交']; | ||
| 158 | + | ||
| 159 | +const close = () => { | ||
| 160 | + emit('close'); | ||
| 161 | +}; | ||
| 162 | + | ||
| 163 | +const submit = () => { | ||
| 164 | + console.log('SchemeB Submit:', form); | ||
| 165 | + emit('submit', form); | ||
| 166 | +}; | ||
| 167 | +</script> | ||
| 168 | + | ||
| 169 | +<style lang="less" scoped> | ||
| 170 | +:deep(.nut-input) { | ||
| 171 | + padding: 0; | ||
| 172 | + background: transparent; | ||
| 173 | +} | ||
| 174 | +</style> |
| ... | @@ -74,7 +74,7 @@ | ... | @@ -74,7 +74,7 @@ |
| 74 | <nut-button | 74 | <nut-button |
| 75 | color="#2563EB" | 75 | color="#2563EB" |
| 76 | class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0" | 76 | class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0" |
| 77 | - @tap="openWebView('https://https://oa-dev.onwall.cn/f/custom_form/front/#/')" | 77 | + @tap="openPlanPopup('A')" |
| 78 | > | 78 | > |
| 79 | 计划书 | 79 | 计划书 |
| 80 | </nut-button> | 80 | </nut-button> |
| ... | @@ -107,7 +107,7 @@ | ... | @@ -107,7 +107,7 @@ |
| 107 | <nut-button | 107 | <nut-button |
| 108 | color="#2563EB" | 108 | color="#2563EB" |
| 109 | class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0" | 109 | class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0" |
| 110 | - @tap="openWebView('https://https://oa-dev.onwall.cn/f/custom_form/front/#/')" | 110 | + @tap="openPlanPopup('B')" |
| 111 | > | 111 | > |
| 112 | 计划书 | 112 | 计划书 |
| 113 | </nut-button> | 113 | </nut-button> |
| ... | @@ -174,6 +174,20 @@ | ... | @@ -174,6 +174,20 @@ |
| 174 | 174 | ||
| 175 | <!-- Bottom Tab Bar --> | 175 | <!-- Bottom Tab Bar --> |
| 176 | <TabBar current="home" /> | 176 | <TabBar current="home" /> |
| 177 | + | ||
| 178 | + <!-- Plan Popup --> | ||
| 179 | + <PlanPopup v-model:visible="showPlanPopup"> | ||
| 180 | + <SchemeA | ||
| 181 | + v-if="currentScheme === 'A'" | ||
| 182 | + @close="showPlanPopup = false" | ||
| 183 | + @submit="handlePlanSubmit" | ||
| 184 | + /> | ||
| 185 | + <SchemeB | ||
| 186 | + v-if="currentScheme === 'B'" | ||
| 187 | + @close="showPlanPopup = false" | ||
| 188 | + @submit="handlePlanSubmit" | ||
| 189 | + /> | ||
| 190 | + </PlanPopup> | ||
| 177 | </view> | 191 | </view> |
| 178 | </template> | 192 | </template> |
| 179 | 193 | ||
| ... | @@ -184,6 +198,27 @@ import { useGo } from '@/hooks/useGo'; | ... | @@ -184,6 +198,27 @@ import { useGo } from '@/hooks/useGo'; |
| 184 | import { useListItemClick, ListType } from '@/composables/useListItemClick'; | 198 | import { useListItemClick, ListType } from '@/composables/useListItemClick'; |
| 185 | import TabBar from '@/components/TabBar.vue'; | 199 | import TabBar from '@/components/TabBar.vue'; |
| 186 | import IconFont from '@/components/IconFont.vue'; | 200 | import IconFont from '@/components/IconFont.vue'; |
| 201 | +import PlanPopup from '@/components/PlanPopup/index.vue'; | ||
| 202 | +import SchemeA from '@/components/PlanSchemes/SchemeA.vue'; | ||
| 203 | +import SchemeB from '@/components/PlanSchemes/SchemeB.vue'; | ||
| 204 | + | ||
| 205 | +// Plan Popup State | ||
| 206 | +const showPlanPopup = ref(false); | ||
| 207 | +const currentScheme = ref('A'); | ||
| 208 | + | ||
| 209 | +const openPlanPopup = (scheme) => { | ||
| 210 | + currentScheme.value = scheme; | ||
| 211 | + showPlanPopup.value = true; | ||
| 212 | +}; | ||
| 213 | + | ||
| 214 | +const handlePlanSubmit = (formData) => { | ||
| 215 | + console.log(`方案${currentScheme.value}提交:`, formData); | ||
| 216 | + showPlanPopup.value = false; | ||
| 217 | + Taro.showToast({ | ||
| 218 | + title: '提交成功', | ||
| 219 | + icon: 'success' | ||
| 220 | + }); | ||
| 221 | +}; | ||
| 187 | 222 | ||
| 188 | // Grid navigation data with routes | 223 | // Grid navigation data with routes |
| 189 | const loopData0 = shallowRef([ | 224 | const loopData0 = shallowRef([ | ... | ... |
-
Please register or login to post a comment