hookehuyr

style(plan): 优化缴费年期组件为单选按钮形式

- 创建 PaymentPeriodRadio 组件替代弹窗选择器
- 未选中状态:灰色边框和文字
- 选中状态:蓝色边框、浅蓝背景、蓝色文字
- 移除单选按钮图标,只显示文字
- 两列网格布局,点击即选

影响文件:
- src/components/plan/PlanFields/PaymentPeriodRadio.vue (新建)
- src/components/plan/PlanTemplates/CriticalIllnessTemplate.vue
- src/components/plan/PlanTemplates/LifeInsuranceTemplate.vue
- src/components/plan/PlanTemplates/SavingsTemplate.vue

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
...@@ -33,6 +33,7 @@ declare module 'vue' { ...@@ -33,6 +33,7 @@ declare module 'vue' {
33 NutTabPane: typeof import('@nutui/nutui-taro')['TabPane'] 33 NutTabPane: typeof import('@nutui/nutui-taro')['TabPane']
34 NutTabs: typeof import('@nutui/nutui-taro')['Tabs'] 34 NutTabs: typeof import('@nutui/nutui-taro')['Tabs']
35 OfficeViewer: typeof import('./src/components/documents/OfficeViewer.vue')['default'] 35 OfficeViewer: typeof import('./src/components/documents/OfficeViewer.vue')['default']
36 + PaymentPeriodRadio: typeof import('./src/components/plan/PlanFields/PaymentPeriodRadio.vue')['default']
36 PdfPreview: typeof import('./src/components/documents/PdfPreview.vue')['default'] 37 PdfPreview: typeof import('./src/components/documents/PdfPreview.vue')['default']
37 PlanFormContainer: typeof import('./src/components/plan/PlanFormContainer.vue')['default'] 38 PlanFormContainer: typeof import('./src/components/plan/PlanFormContainer.vue')['default']
38 PlanPopupNew: typeof import('./src/components/plan/PlanPopupNew.vue')['default'] 39 PlanPopupNew: typeof import('./src/components/plan/PlanPopupNew.vue')['default']
......
1 +<template>
2 + <div>
3 + <!-- 标签 -->
4 + <div v-if="label" class="text-sm text-gray-600 mb-3 flex items-center">
5 + <span v-if="required" class="text-red-500 mr-1">*</span>
6 + <span>{{ label }}</span>
7 + </div>
8 +
9 + <!-- 单选按钮组 -->
10 + <div class="grid grid-cols-2 gap-3">
11 + <view
12 + v-for="option in options"
13 + :key="option"
14 + class="
15 + relative
16 + border-2
17 + rounded-lg
18 + p-4
19 + cursor-pointer
20 + transition-all
21 + flex
22 + items-center
23 + justify-center
24 + text-center
25 + "
26 + :class="
27 + modelValue === option
28 + ? 'border-primary bg-primary-light'
29 + : 'border-gray-300 bg-white'
30 + "
31 + @tap="selectOption(option)"
32 + >
33 + <text
34 + class="text-sm"
35 + :class="modelValue === option ? 'text-primary font-medium' : 'text-gray-500'"
36 + >
37 + {{ option }}
38 + </text>
39 + </view>
40 + </div>
41 + </div>
42 +</template>
43 +
44 +<script setup>
45 +/**
46 + * 缴费年期单选组件
47 + *
48 + * @description 使用单选按钮组形式选择缴费年期,替代弹窗选择器
49 + * @component PaymentPeriodRadio
50 + * @example
51 + * <PaymentPeriodRadio
52 + * v-model="paymentPeriod"
53 + * label="缴费年期"
54 + * :options="['整付(0-75 岁)', '5 年(0-70 岁)']"
55 + * :required="true"
56 + * />
57 + */
58 +
59 +/**
60 + * 组件属性
61 + */
62 +const props = defineProps({
63 + /**
64 + * 标签文本
65 + * @type {string}
66 + */
67 + label: {
68 + type: String,
69 + default: ''
70 + },
71 +
72 + /**
73 + * 是否必填
74 + * @type {boolean}
75 + */
76 + required: {
77 + type: Boolean,
78 + default: false
79 + },
80 +
81 + /**
82 + * 选项数组
83 + * @type {Array<string>}
84 + * @example ['整付(0-75 岁)', '5 年(0-70 岁)', '10 年(0-70 岁)']
85 + */
86 + options: {
87 + type: Array,
88 + required: true
89 + },
90 +
91 + /**
92 + * 绑定的值
93 + * @type {string}
94 + */
95 + modelValue: {
96 + type: String,
97 + default: ''
98 + }
99 +})
100 +
101 +/**
102 + * 组件事件
103 + */
104 +const emit = defineEmits({
105 + /**
106 + * 更新值事件
107 + * @event update:modelValue
108 + * @param {string} value - 选中的选项
109 + */
110 + 'update:modelValue': (value) => typeof value === 'string'
111 +})
112 +
113 +/**
114 + * 选择选项
115 + * @param {string} option - 选中的选项
116 + */
117 +const selectOption = (option) => {
118 + emit('update:modelValue', option)
119 +}
120 +</script>
121 +
122 +<style lang="less">
123 +// 主色样式 - 蓝色
124 +.border-primary {
125 + border-color: #1677ff;
126 +}
127 +
128 +.bg-primary {
129 + background-color: rgba(22, 119, 255, 0.1);
130 +}
131 +
132 +.text-primary {
133 + color: #1677ff;
134 +}
135 +
136 +.bg-primary-light {
137 + background-color: rgba(22, 119, 255, 0.05);
138 +}
139 +
140 +.border-primary\/50 {
141 + border-color: rgba(22, 119, 255, 0.5);
142 +}
143 +
144 +// 选中状态的边框加粗
145 +.border-primary {
146 + border-width: 2px;
147 +}
148 +</style>
...@@ -46,11 +46,10 @@ ...@@ -46,11 +46,10 @@
46 class="mb-5" 46 class="mb-5"
47 /> 47 />
48 48
49 - <!-- 缴费年期 --> 49 + <!-- 缴费年期 - 单选形式 -->
50 - <PlanFieldSelect 50 + <PaymentPeriodRadio
51 v-model="form.payment_period" 51 v-model="form.payment_period"
52 label="缴费年期" 52 label="缴费年期"
53 - placeholder="请选择缴费年期"
54 :options="config.payment_periods" 53 :options="config.payment_periods"
55 :required="true" 54 :required="true"
56 class="mb-5" 55 class="mb-5"
...@@ -83,7 +82,7 @@ import PlanFieldName from '../PlanFields/NameInput.vue' ...@@ -83,7 +82,7 @@ import PlanFieldName from '../PlanFields/NameInput.vue'
83 import PlanFieldAmount from '../PlanFields/AmountKeyboard.vue' 82 import PlanFieldAmount from '../PlanFields/AmountKeyboard.vue'
84 import PlanFieldDatePicker from '../PlanFields/DatePickerGlobal.vue' 83 import PlanFieldDatePicker from '../PlanFields/DatePickerGlobal.vue'
85 import PlanFieldRadio from '../PlanFields/RadioGroup.vue' 84 import PlanFieldRadio from '../PlanFields/RadioGroup.vue'
86 -import PlanFieldSelect from '../PlanFields/SelectPickerGlobal.vue' 85 +import PaymentPeriodRadio from '../PlanFields/PaymentPeriodRadio.vue'
87 86
88 /** 87 /**
89 * 组件属性 88 * 组件属性
......
...@@ -46,11 +46,10 @@ ...@@ -46,11 +46,10 @@
46 class="mb-5" 46 class="mb-5"
47 /> 47 />
48 48
49 - <!-- 缴费年期 --> 49 + <!-- 缴费年期 - 单选形式 -->
50 - <PlanFieldSelect 50 + <PaymentPeriodRadio
51 v-model="form.payment_period" 51 v-model="form.payment_period"
52 label="缴费年期" 52 label="缴费年期"
53 - placeholder="请选择缴费年期"
54 :options="config.payment_periods" 53 :options="config.payment_periods"
55 :required="true" 54 :required="true"
56 class="mb-5" 55 class="mb-5"
...@@ -83,7 +82,7 @@ import PlanFieldName from '../PlanFields/NameInput.vue' ...@@ -83,7 +82,7 @@ import PlanFieldName from '../PlanFields/NameInput.vue'
83 import PlanFieldAmount from '../PlanFields/AmountKeyboard.vue' 82 import PlanFieldAmount from '../PlanFields/AmountKeyboard.vue'
84 import PlanFieldDatePicker from '../PlanFields/DatePickerGlobal.vue' 83 import PlanFieldDatePicker from '../PlanFields/DatePickerGlobal.vue'
85 import PlanFieldRadio from '../PlanFields/RadioGroup.vue' 84 import PlanFieldRadio from '../PlanFields/RadioGroup.vue'
86 -import PlanFieldSelect from '../PlanFields/SelectPickerGlobal.vue' 85 +import PaymentPeriodRadio from '../PlanFields/PaymentPeriodRadio.vue'
87 86
88 /** 87 /**
89 * 组件属性 88 * 组件属性
......
...@@ -46,11 +46,10 @@ ...@@ -46,11 +46,10 @@
46 class="mb-5" 46 class="mb-5"
47 /> 47 />
48 48
49 - <!-- 缴费年期 --> 49 + <!-- 缴费年期 - 单选形式 -->
50 - <PlanFieldSelect 50 + <PaymentPeriodRadio
51 v-model="form.payment_period" 51 v-model="form.payment_period"
52 label="缴费年期" 52 label="缴费年期"
53 - placeholder="请选择缴费年期"
54 :options="config.payment_periods" 53 :options="config.payment_periods"
55 :required="true" 54 :required="true"
56 class="mb-5" 55 class="mb-5"
...@@ -209,6 +208,7 @@ import PlanFieldAmount from '../PlanFields/AmountKeyboard.vue' ...@@ -209,6 +208,7 @@ import PlanFieldAmount from '../PlanFields/AmountKeyboard.vue'
209 import PlanFieldDatePicker from '../PlanFields/DatePickerGlobal.vue' 208 import PlanFieldDatePicker from '../PlanFields/DatePickerGlobal.vue'
210 import PlanFieldRadio from '../PlanFields/RadioGroup.vue' 209 import PlanFieldRadio from '../PlanFields/RadioGroup.vue'
211 import PlanFieldSelect from '../PlanFields/SelectPickerGlobal.vue' 210 import PlanFieldSelect from '../PlanFields/SelectPickerGlobal.vue'
211 +import PaymentPeriodRadio from '../PlanFields/PaymentPeriodRadio.vue'
212 212
213 /** 213 /**
214 * 组件属性 214 * 组件属性
......