bxs-tools-ui 3.3.3 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/es/add-and-take/index.js +1 -7969
  2. package/es/adjust-baoe/index.js +197 -8192
  3. package/es/index.css +1 -1
  4. package/es/index.js +8788 -43737
  5. package/es/insure-calculate/index.css +1 -1
  6. package/es/insure-calculate/index.js +1046 -36665
  7. package/es/person-info/index.css +1 -1
  8. package/es/person-info/index.js +83 -8042
  9. package/es/product-info/index.css +1 -1
  10. package/es/product-info/index.js +3006 -10612
  11. package/es/share-sheet/index.js +69 -8040
  12. package/es/utils/index.js +1250 -9334
  13. package/lib/add-and-take/index.js +4 -7973
  14. package/lib/adjust-baoe/index.js +196 -8192
  15. package/lib/index.css +1 -1
  16. package/lib/index.js +8717 -43671
  17. package/lib/insure-calculate/index.css +1 -1
  18. package/lib/insure-calculate/index.js +1034 -36662
  19. package/lib/person-info/index.css +1 -1
  20. package/lib/person-info/index.js +86 -8046
  21. package/lib/product-info/index.css +1 -1
  22. package/lib/product-info/index.js +2807 -10414
  23. package/lib/share-sheet/index.js +72 -8044
  24. package/lib/utils/index.js +1252 -9337
  25. package/package.json +5 -3
  26. package/packages/adjust-baoe/index.vue +2 -9
  27. package/packages/bxs-utils/planbook/common.ts +5 -0
  28. package/packages/bxs-utils/planbook/insurance.ts +19 -0
  29. package/packages/bxs-utils/planbook/person.ts +3 -2
  30. package/packages/bxs-utils/planbook/product.ts +57 -164
  31. package/packages/bxs-utils/readme.md +3 -1
  32. package/packages/index.ts +1 -1
  33. package/packages/insure-calculate/demo/index.vue +1 -1
  34. package/packages/insure-calculate/index.vue +18 -17
  35. package/packages/planbook-input/components/product-table.vue +3 -13
  36. package/packages/planbook-input/helper.js +4 -26
  37. package/packages/product-info/components/product-insurance-form.md +46 -0
  38. package/packages/product-info/components/product-insurance-form.vue +360 -0
  39. package/packages/product-info/demo/index.vue +2 -1
  40. package/packages/product-info/handler.js +307 -0
  41. package/packages/product-info/handler.md +26 -0
  42. package/packages/product-info/index.less +33 -0
  43. package/packages/product-info/index.vue +306 -532
  44. package/packages/product-info/readme.md +7 -1
  45. package/packages/share-sheet/constant.js +1 -2
  46. package/src/api/trade.js +31 -0
  47. package/src/components/common/common-group-title.less +54 -0
  48. package/src/components/common/common-group-title.md +34 -0
  49. package/src/components/common/common-group-title.vue +72 -0
  50. package/src/components/common/common-title.less +4 -0
  51. package/src/components/common/common-title.vue +8 -2
  52. package/src/components/profession-list/README.md +114 -0
  53. package/src/components/profession-list/constant.js +4 -0
  54. package/src/components/profession-list/handler.js +155 -0
  55. package/src/components/profession-list/index.less +182 -0
  56. package/src/components/profession-list/index.vue +443 -0
@@ -14,279 +14,129 @@
14
14
  </div>
15
15
  </section>
16
16
 
17
- <template v-for="ins in filterInsuranceList">
18
- <van-form
19
- :ref="`insuranceForm${ins.key}`"
20
- :key="ins.key"
21
- :class="['bxt-product-info-form', `bxt-product-insurance-id-${ins.key}`, isNextInsuranceFollow(ins) ? 'bxt-product-info-form-follow' : '']"
22
- :show-error="false"
23
- @submit.native.prevent="closeKeyBoard()"
24
- >
25
- <template v-for="ele in ins.eleOrderList">
26
- <van-field v-if="['cmCommonTitle'].includes(ele.componentName)" :key="ele.key" :name="ele.key" :rules="getElementRules(ele)">
27
- <template #input>
28
- <CommonTitle
29
- v-model="ele.value"
30
- :key="`${productData.key}_${ins.key}_${ele.key}`"
31
- :name="ele.key"
32
- :code="ins.code"
33
- :huomian-tag="getInsuranceTitleHmTag(ins)"
34
- :status-tag="getInsuranceSaleStatusTag(ins)"
35
- :huomian-tips="!!$listeners.openCrmPerson && getHuomianTips(ins, ele)"
36
- :label="ele.labelName"
37
- :style="{
38
- fontSize: '17px',
39
- fontWeight: 'bold'
40
- }"
41
- :disabled="getElementDisabled(ele)"
42
- :data-stat-id="`product_insurance_${ele.key}`"
43
- @change="onChange({ insData: ins, eleData: ele })"
44
- @openCrmPerson="$emit('openCrmPerson')"
45
- />
46
- </template>
47
- </van-field>
17
+ <template v-for="block in displayBlocks">
18
+ <!-- 普通险(在前) -->
19
+ <ProductInsuranceForm
20
+ v-if="block.type === 'normal'"
21
+ :ref="`insuranceForm${block.ins.key}`"
22
+ :key="block.ins.key"
23
+ v-bind="insFormBind(block.ins)"
24
+ @change="onChange"
25
+ @openCrmPerson="$emit('openCrmPerson')"
26
+ />
48
27
 
49
- <template v-if="isInsuranceChecked(ins) && !ele.isHide">
50
- <van-field
51
- v-if="['cmCommonInput'].includes(ele.componentName)"
52
- v-model.number="ele.value"
53
- :ref="ins.key + ele.key + 'item'"
54
- :key="ins.key + ele.key"
55
- :id="`id_${ins.key}_${ele.key}`"
56
- :type="ele.inputType || 'tel'"
57
- :class="{
58
- 'van-field-unit': activeInputKey === ins.key + ele.key && numberUnitStr
59
- }"
60
- :prop="ele.key"
61
- :label="ele.labelName"
62
- :placeholder="ele.placeholder"
63
- :disabled="getElementDisabled(ele)"
64
- :readonly="getElementDisabled(ele)"
65
- :maxlength="ele.maxlength || 9"
66
- :rules="getElementRules(ele)"
67
- autocomplete="off"
68
- input-align="right"
69
- error-message-align="right"
70
- clearable
71
- :inputmode="ele.inputType || 'text'"
72
- @focus="
73
- activeInputKey = ins.key + ele.key
74
- numberUnitStr = getAmountUnit(ele)
75
- "
76
- @blur="activeInputKey = ''"
77
- @input="numberUnitStr = getAmountUnit(ele)"
78
- @change="onChange({ insData: ins, eleData: ele })"
79
- @clear="onChange({ insData: ins, eleData: ele })"
80
- >
81
- <template v-if="!ele.isDisabled" #right-icon>
82
- <i class="icon iconfont icon-edit" style="font-size: 20px;" @click="onClickIcon(`id_${ins.key}_${ele.key}`)" />
83
- </template>
84
- </van-field>
85
- <div v-if="activeInputKey === ins.key + ele.key && numberUnitStr" :key="ins.key + ele.key + 'unit'" class="bxt-ins-unit-tips">
86
- <em />
87
- <span>
88
- {{ numberUnitStr }}
89
- </span>
90
- </div>
91
- <div v-if="getRecommendValues(ins, ele)" :key="ins.key + ele.key + 'recommend'" class="bxt-ins-recommend-values">
92
- <span v-for="v in getRecommendValues(ins, ele)" :key="v" @click="onClickRecommendValue(v, ins, ele)">
93
- {{ v }}
94
- </span>
95
- </div>
96
-
97
- <CommonRadio
98
- v-if="['cmCommonRadioBtn'].includes(ele.componentName)"
99
- v-model="ele.value"
100
- class="bxt-ins-form-radio-btn"
101
- :key="ins.key + ele.key"
102
- :name="ele.key"
103
- :label="ele.labelName"
104
- :disabled="getElementDisabled(ele)"
105
- :readonly="getElementDisabled(ele)"
106
- :rules="getElementRules(ele)"
107
- :options="ele.opts.filter(o => !o.isHide && !o.isDisabled && !o.isInvalid)"
108
- input-align="right"
109
- border
110
- :data-stat-id="`product_insurance_${ele.key}`"
111
- @input="onChange({ insData: ins, eleData: ele })"
112
- />
113
-
114
- <van-field
115
- v-if="['cmCommonRadio'].includes(ele.componentName)"
116
- class="bxt-ins-form-radio"
117
- :key="ins.key + ele.key"
118
- :name="ele.key"
119
- :label="ele.labelName"
120
- :rules="getElementRules(ele)"
121
- >
122
- <template #input>
123
- <van-radio-group v-model="ele.value" :disabled="getElementDisabled(ele)" @change="onChange({ insData: ins, eleData: ele })">
124
- <van-radio
125
- v-for="opt in ele.opts"
126
- :id="`${productData.key}_${ins.key}_${ele.key}_${opt.val}`"
127
- :key="opt.val"
128
- :name="typeof ele.value === 'number' && !isNaN(Number(opt.val)) ? opt.val * 1 : opt.val"
129
- :disabled="opt.val != ele.value && opt.isDisabled"
130
- :label-disabled="opt.val != ele.value && opt.isDisabled"
131
- >
132
- <template #icon="props">
133
- <van-icon v-if="props.checked" class-prefix="iconfont icon" name="multiple_choice" size="20px" />
134
- <van-icon v-else class-prefix="iconfont icon" name="choose_none_line" size="20px" />
135
- </template>
136
- <div class="bxt-ins-form-radio-content">
137
- <span v-if="opt.code" class="bxt-ins-form-radio--code">{{ opt.code }}</span>
138
- <span
139
- class="bxt-ins-form-radio--tx"
140
- :class="[genInsuranceHmTag(opt) || getInsuranceSaleStatusTagByKey(opt.val) ? 'bxt-ins-form-radio--width' : '']"
141
- >
142
- {{ opt.desc }}
143
- </span>
144
- <span v-if="getInsuranceSaleStatusTagByKey(opt.val)" class="bxt-ins-form-radio--sale-tag">
145
- {{ getInsuranceSaleStatusTagByKey(opt.val) }}
146
- </span>
147
- <span v-if="genInsuranceHmTag(opt)" class="bxt-ins-form-radio--tag">
148
- {{ genInsuranceHmTag(opt) }}
149
- </span>
150
- </div>
151
- </van-radio>
152
- </van-radio-group>
153
- </template>
154
- </van-field>
155
-
156
- <CommonSelect
157
- v-if="['cmCommonSelect'].includes(ele.componentName)"
158
- v-model="ele.value"
159
- :key="ele.componentName + ins.key + ele.key"
160
- :name="ele.key"
161
- :label="ele.labelName"
162
- :placeholder="ele.placeholder"
163
- :disabled="getElementDisabled(ele)"
164
- :readonly="getElementDisabled(ele)"
165
- :rules="getElementRules(ele)"
166
- :options="ele.opts.filter(o => !o.isHide && !o.isDisabled && !o.isInvalid)"
167
- :right-icon="getElementDisabled(ele) ? '' : 'arrow'"
168
- input-align="right"
169
- border
170
- :data-stat-id="`product_insurance_${ele.key}`"
171
- @change="onChange({ insData: ins, eleData: ele })"
172
- />
173
-
174
- <div :key="`${ins.key}${ele.key}_note`" v-if="ele.note" class="bxt-form-item-label-note">
175
- {{ ele.note }}
176
- </div>
177
- </template>
28
+ <!-- 组合险组头 + 子险 -->
29
+ <div v-else :key="`group-${block.groupKey}`" class="bxt-product-group">
30
+ <div class="bxt-product-info-form bxt-product-group-header">
31
+ <CommonGroupTitle
32
+ :value="isGroupActive(block.groupKey)"
33
+ :key="`${productData.key}_group_${block.groupKey}`"
34
+ :label="block.groupName"
35
+ :disabled="isGroupSwitchDisabled(block.groupKey)"
36
+ :data-stat-id="`product_insurance_group_${block.groupKey}`"
37
+ @change="onGroupActiveChange(block.groupKey, $event)"
38
+ />
39
+ </div>
40
+ <template v-if="isGroupActive(block.groupKey)">
41
+ <ProductInsuranceForm
42
+ v-for="ins in block.insList"
43
+ :ref="`insuranceForm${ins.key}`"
44
+ :key="ins.key"
45
+ v-bind="insFormBind(ins, 'groupSub')"
46
+ @change="onChange"
47
+ @title-change="onInsuranceTitleChange"
48
+ @openCrmPerson="$emit('openCrmPerson')"
49
+ />
178
50
  </template>
179
- </van-form>
51
+ </div>
180
52
  </template>
181
53
  </div>
182
54
  </template>
183
55
  <script lang="ts">
184
56
  import Vue from 'vue'
185
57
  import { Component, Prop } from 'vue-property-decorator'
58
+ import { Toast } from 'vant'
186
59
  import { get as _get } from 'lodash'
187
- import { getPlanbookRecommendData } from '../../src/api/planbook.js'
188
- import { productDataHandler, multipleInsuredHandler, verifyProductRules, initElementValidateRules, convertEleOrderListToObj } from 'packages/bxs-utils/index'
189
- import { createdProductDataToCalc } from 'packages/planbook-input/helper.js'
190
-
191
- import CommonTitle from '../../src/components/common/common-title.vue'
192
- import CommonRadio from '../../src/components/common/common-radio.vue'
193
- import CommonSelect from '../../src/components/common/common-select.vue'
194
- import CommonAgeBirthday from '../../src/components/common/common-age-birthday.vue'
195
-
60
+ import { productDataHandler, multipleInsuredHandler, verifyProductRules } from 'packages/bxs-utils/index'
61
+ import CommonGroupTitle from '../../src/components/common/common-group-title.vue'
62
+ import ProductInsuranceForm from './components/product-insurance-form.vue'
63
+ import {
64
+ getTitleEle,
65
+ getCheckedIds,
66
+ isTitleChecked,
67
+ isTitleEnabled,
68
+ isCheckboxGroup,
69
+ applySelectedIds,
70
+ setAllTitles,
71
+ snapshotGroupTitleEnabledMap,
72
+ getGroupSubsBecameUnselectable,
73
+ buildGroupUiState,
74
+ buildDisplayBlocks,
75
+ fetchRecommendValues,
76
+ createInsuranceInputResultEle as writeInsuranceInputResultEle
77
+ } from './handler.js'
196
78
  import './index.less'
197
79
 
80
+ type GroupUiItem = {
81
+ active: boolean
82
+ locked: boolean
83
+ selectedIds: Array<string | number>
84
+ groupName?: string
85
+ }
86
+
198
87
  @Component({
199
88
  name: 'BxtProductInfo',
200
- components: {
201
- CommonTitle,
202
- CommonRadio,
203
- CommonSelect,
204
- CommonAgeBirthday
205
- }
89
+ components: { CommonGroupTitle, ProductInsuranceForm }
206
90
  })
207
91
  export default class BxtProductInfo extends Vue {
208
- activeInputKey = ''
209
- numberUnitStr = ''
210
92
  recommendValues = {}
211
93
  recommendValuesCache = {}
212
94
  isShowCustomValueTips = true
95
+ /** 组合险 UI 状态,不进产品数据;Map 保序 */
96
+ groupUiState: Map<string, GroupUiItem> = new Map()
213
97
 
214
- @Prop({
215
- default: () => ({})
216
- })
217
- user: any
218
-
219
- @Prop({
220
- default: () => ({})
221
- })
222
- inputData: any
223
-
224
- @Prop({
225
- default: () => ({})
226
- })
227
- verifyData: any
228
-
229
- @Prop({
230
- default: null
231
- })
232
- groupKey!: number | string
233
-
234
- @Prop({
235
- default: null
236
- })
237
- productKey!: number | string
238
-
239
- @Prop({
240
- default: true
241
- })
242
- showRecommendValue!: boolean
243
-
244
- @Prop({
245
- default: () => ({})
246
- })
247
- params: any
98
+ @Prop({ default: () => ({}) }) user: any
99
+ @Prop({ default: () => ({}) }) inputData: any
100
+ @Prop({ default: () => ({}) }) verifyData: any
101
+ @Prop({ default: null }) groupKey!: number | string
102
+ @Prop({ default: null }) productKey!: number | string
103
+ @Prop({ default: true }) showRecommendValue!: boolean
104
+ @Prop({ default: () => ({}) }) params: any
248
105
 
249
106
  get personData() {
250
- return this.inputData && this.inputData.personData
107
+ return _get(this.inputData, 'personData')
251
108
  }
252
109
  get groupData() {
253
- return this.inputData && this.inputData.productGroupList && this.inputData.productGroupList.find(g => g.key === this.groupKey)
110
+ return (_get(this.inputData, 'productGroupList') || []).find(g => g.key === this.groupKey)
254
111
  }
255
112
  get productData() {
256
- return this.groupData && this.groupData.prodOrderList && this.groupData.prodOrderList.find(p => p.key === this.productKey)
113
+ return (_get(this.groupData, 'prodOrderList') || []).find(p => p.key === this.productKey)
257
114
  }
258
115
  get productForm() {
259
- let productForm: any = {}
260
- this.productData &&
261
- this.productData.mulInsOrderList.map(ins => {
262
- productForm[ins.key] = {}
263
- ins.eleOrderList.map(ele => {
264
- productForm[ins.key][ele.key] = ele.value
265
- })
116
+ const form: any = {}
117
+ const mulInsOrderList = _get(this.productData, 'mulInsOrderList') || []
118
+ mulInsOrderList.forEach(ins => {
119
+ form[ins.key] = {}
120
+ const eleOrderList = _get(ins, 'eleOrderList') || []
121
+ eleOrderList.forEach(ele => {
122
+ form[ins.key][ele.key] = ele.value
266
123
  })
267
- return productForm
124
+ })
125
+ return form
268
126
  }
269
- get filterInsuranceList() {
270
- const list = this.productData && this.productData.mulInsOrderList.filter(ins => !ins.groupKey)
271
- // 下拉框根据条件改单选(按钮)。From hyw
272
- if (list) {
273
- list.forEach(ins => {
274
- if (!ins.eleOrderList) {
275
- return
276
- }
277
- ins.eleOrderList.forEach(ele => {
278
- if (ele.componentName !== 'cmCommonSelect' || !ele.opts) {
279
- return
280
- }
281
- if (ele.opts.length === 1) {
282
- return
283
- }
284
- if (ele.opts.length < 6 && !ele.opts.some(o => o.desc && String(o.desc).length >= 10)) {
285
- ele.componentName = 'cmCommonRadioBtn'
286
- }
287
- })
288
- })
289
- }
127
+ get displayBlocks() {
128
+ return buildDisplayBlocks(_get(this.productData, 'mulInsOrderList'), this.groupUiState, ins => this.normalizeSelectToRadio(ins))
129
+ }
130
+ /** 参与校验的险种:普通险全部;组合险仅组展开且 title 选中的子险 */
131
+ get visibleInsuranceList() {
132
+ const list: any[] = []
133
+ this.displayBlocks.forEach(block => {
134
+ if (block.type === 'normal') {
135
+ list.push(block.ins)
136
+ } else if (this.isGroupActive(block.groupKey)) {
137
+ list.push(...block.insList.filter(isTitleChecked))
138
+ }
139
+ })
290
140
  return list
291
141
  }
292
142
 
@@ -295,35 +145,156 @@ export default class BxtProductInfo extends Vue {
295
145
  }
296
146
  async init() {
297
147
  const { productData } = this
148
+ this.syncGroupUiState(true)
298
149
  this.requiestRecommendValues()
299
150
  const errorMsg = await this.changeProduct(productData, {})
300
151
  this.$emit('change', productData, { errorMsg }, this)
301
152
  }
153
+
154
+ /** ProductInsuranceForm 公共 props */
155
+ insFormBind(ins, insMode = 'normal') {
156
+ return {
157
+ ins,
158
+ insMode,
159
+ productKey: _get(this.productData, 'key'),
160
+ mulInsOrderList: _get(this.productData, 'mulInsOrderList'),
161
+ personData: this.personData,
162
+ recommendValues: this.recommendValues,
163
+ insuranceSaleStatus: _get(this.params, 'insuranceSaleStatus'),
164
+ showHuomianTips: !!this.$listeners.openCrmPerson,
165
+ isFollow: this.isNextInsuranceFollow(ins),
166
+ lockTitleClick: insMode === 'groupSub' && this.isGroupSiblingLocked(ins)
167
+ }
168
+ }
169
+ normalizeSelectToRadio(ins) {
170
+ const eleOrderList = _get(ins, 'eleOrderList') || []
171
+ eleOrderList.forEach(ele => {
172
+ if (ele.componentName !== 'cmCommonSelect' || !ele.opts || ele.opts.length === 1) {
173
+ return
174
+ }
175
+ if (ele.opts.length < 6 && !ele.opts.some(o => o.desc && String(o.desc).length >= 10)) {
176
+ ele.componentName = 'cmCommonRadioBtn'
177
+ }
178
+ })
179
+ }
180
+ getGroupInsurances(groupKey) {
181
+ return (_get(this.productData, 'mulInsOrderList') || []).filter(ins => String(ins.groupKey) === String(groupKey))
182
+ }
183
+ isGroupActive(groupKey) {
184
+ return !!_get(this.groupUiState.get(String(groupKey)), 'active')
185
+ }
186
+ isGroupLocked(groupKey) {
187
+ return !!_get(this.groupUiState.get(String(groupKey)), 'locked')
188
+ }
189
+ /** locked 组内:非锁定子险 title 不可点 */
190
+ isGroupSiblingLocked(ins) {
191
+ const gk = String(ins.groupKey)
192
+ const state = this.groupUiState.get(gk)
193
+ if (!state || !state.locked) {
194
+ return false
195
+ }
196
+ return String(ins.key) !== String(_get(state, 'selectedIds[0]'))
197
+ }
198
+ isGroupSwitchDisabled(groupKey) {
199
+ if (this.isGroupLocked(groupKey)) {
200
+ return true
201
+ }
202
+ const siblings = this.getGroupInsurances(groupKey)
203
+ if (!siblings.length) {
204
+ return true
205
+ }
206
+ const enabled = siblings.filter(isTitleEnabled)
207
+ return enabled.length === 0
208
+ }
209
+ touchGroupUiState() {
210
+ this.groupUiState = new Map(this.groupUiState)
211
+ }
212
+ syncGroupUiState(isInit = false) {
213
+ this.groupUiState = buildGroupUiState(_get(this.productData, 'mulInsOrderList') || [], this.groupUiState, { isInit })
214
+ }
215
+
216
+ /** 组合险开关 */
217
+ onGroupActiveChange(groupKey, active) {
218
+ const gk = String(groupKey)
219
+ const siblings = this.getGroupInsurances(gk)
220
+ const prev = this.groupUiState.get(gk) || {
221
+ active: false,
222
+ locked: false,
223
+ selectedIds: [],
224
+ groupName: _get(siblings, '[0].groupName')
225
+ }
226
+ if (prev.locked) {
227
+ return
228
+ }
229
+
230
+ if (!active) {
231
+ const selectedIds = getCheckedIds(siblings)
232
+ setAllTitles(siblings, false)
233
+ this.groupUiState.set(gk, {
234
+ ...prev,
235
+ active: false,
236
+ selectedIds: selectedIds.length ? selectedIds : prev.selectedIds || []
237
+ })
238
+ } else {
239
+ let restoreIds = (prev.selectedIds || []).slice()
240
+ if (!isCheckboxGroup(siblings) && restoreIds.length > 1) {
241
+ restoreIds = restoreIds.slice(0, 1)
242
+ }
243
+ const appliedIds = applySelectedIds(siblings, restoreIds)
244
+ this.groupUiState.set(gk, {
245
+ ...prev,
246
+ active: true,
247
+ selectedIds: appliedIds
248
+ })
249
+ }
250
+ this.touchGroupUiState()
251
+ this.onChange({
252
+ insData: siblings[0],
253
+ eleData: getTitleEle(siblings[0]) || { key: 'title' }
254
+ })
255
+ }
256
+
257
+ /** 组合子险 title:互斥 / 多选后同步 selectedIds */
258
+ onInsuranceTitleChange(payload) {
259
+ const { insData, eleData } = payload || {}
260
+ const gk = String(insData.groupKey)
261
+ const siblings = this.getGroupInsurances(gk)
262
+ const prev = this.groupUiState.get(gk) || { active: true, locked: false, selectedIds: [], groupName: insData.groupName }
263
+ if (prev.locked) {
264
+ return
265
+ }
266
+
267
+ if (insData.isCheckbox) {
268
+ this.groupUiState.set(gk, { ...prev, active: true, selectedIds: getCheckedIds(siblings) })
269
+ } else if (eleData.value) {
270
+ siblings.forEach(s => {
271
+ if (s.key !== insData.key) {
272
+ const t = getTitleEle(s)
273
+ if (t) {
274
+ t.value = false
275
+ }
276
+ }
277
+ })
278
+ this.groupUiState.set(gk, { ...prev, active: true, selectedIds: [insData.key] })
279
+ } else {
280
+ this.groupUiState.set(gk, { ...prev, active: true, selectedIds: [] })
281
+ }
282
+ this.touchGroupUiState()
283
+ this.onChange({ insData, eleData })
284
+ }
285
+
302
286
  onChange(options: any = {}) {
303
287
  options.type = 'change'
304
288
  const { type, insData, eleData } = options
305
- if (!['title'].includes(eleData.key)) {
289
+ if (_get(eleData, 'key') !== 'title') {
306
290
  this.requiestRecommendValues()
307
291
  }
308
292
  this.$nextTick(async () => {
309
293
  const errorMsg = await this.changeProduct(this.productData, options)
310
- this.$emit(
311
- 'change',
312
- this.productData,
313
- {
314
- type,
315
- insData,
316
- eleData,
317
- errorMsg
318
- },
319
- this
320
- )
294
+ this.$emit('change', this.productData, { type, insData, eleData, errorMsg }, this)
321
295
  })
322
296
  }
323
- onClickIcon(id) {
324
- const inputDom: any = document.querySelector(`#${id}`)
325
- inputDom.focus()
326
- }
297
+
327
298
  async changeProduct(productData, options) {
328
299
  const { $listeners, user, inputData, verifyData, personData, groupKey, productKey, params } = this
329
300
  const { type, insData, eleData } = options
@@ -334,317 +305,120 @@ export default class BxtProductInfo extends Vue {
334
305
  insuranceCode: _get(insData, 'code') || null,
335
306
  elementKey: _get(eleData, 'key') || null
336
307
  }
337
- if (productData.multipleInsured) {
308
+ if (_get(productData, 'multipleInsured')) {
338
309
  multipleInsuredHandler(productData, personData)
339
310
  }
311
+ const prevGroupTitleEnabled = snapshotGroupTitleEnabledMap(_get(productData, 'mulInsOrderList'))
340
312
  await productDataHandler(productData, productVerifyData, personData, {
341
313
  user,
342
314
  planbookId,
343
315
  executeSource: 'userAction',
344
316
  eventTarget
345
317
  })
318
+ this.syncGroupUiState(false)
346
319
  if (type === 'change') {
347
- this.createInsuranceInputResultEle(insData, eleData)
348
- } else {
349
- this.createInsuranceInputResultEle()
320
+ this.toastGroupSubsBecameUnselectable(productData, prevGroupTitleEnabled)
350
321
  }
322
+ this.createInsuranceInputResultEle(type === 'change' ? insData : null, type === 'change' ? eleData : null)
351
323
 
352
- let errorMsg: any = verifyProductRules({
353
- personData,
354
- productData,
355
- insData,
356
- eleData
357
- })
324
+ let errorMsg: any = verifyProductRules({ personData, productData, insData, eleData })
358
325
  if (!errorMsg) {
359
326
  await this.validate()
360
327
  .then(async () => {
361
328
  const hasRevalidateFlag = (_get(productData, 'mulInsOrderList') || []).some(ins => ins.revalidateFlag)
362
- if (hasRevalidateFlag && $listeners.reCalculate) {
363
- await new Promise<any>((resolve, reject) => {
364
- this.$emit(
365
- 'reCalculate',
366
- inputData,
367
- {
368
- user,
369
- planbookId,
370
- groupKey,
371
- productKey,
372
- executeSource: 'userAction',
373
- isIgnoreError: true,
374
- eventTarget
375
- },
376
- resolve,
377
- reject
378
- )
379
- }).catch(err => {
380
- errorMsg = _get(err, '[0].message') || _get(err, 'message')
381
- })
382
- await productDataHandler(productData, productVerifyData, personData, {
383
- user,
384
- planbookId,
385
- executeSource: 'userAction',
386
- eventTarget
387
- })
329
+ if (!(hasRevalidateFlag && $listeners.reCalculate)) {
330
+ return
388
331
  }
332
+ await new Promise<any>((resolve, reject) => {
333
+ this.$emit(
334
+ 'reCalculate',
335
+ inputData,
336
+ { user, planbookId, groupKey, productKey, executeSource: 'userAction', isIgnoreError: true, eventTarget },
337
+ resolve,
338
+ reject
339
+ )
340
+ }).catch(err => {
341
+ errorMsg = _get(err, '[0].message') || _get(err, 'message')
342
+ })
343
+ const prevAfterCalc = snapshotGroupTitleEnabledMap(_get(productData, 'mulInsOrderList'))
344
+ await productDataHandler(productData, productVerifyData, personData, {
345
+ user,
346
+ planbookId,
347
+ executeSource: 'userAction',
348
+ eventTarget
349
+ })
350
+ this.syncGroupUiState(false)
351
+ this.toastGroupSubsBecameUnselectable(productData, prevAfterCalc)
389
352
  })
390
353
  .catch(() => {})
391
354
  }
392
355
  return errorMsg
393
356
  }
394
- isInsuranceChecked(ins) {
395
- let titleEle = ins.eleOrderList.find(e => e.key === 'title')
396
- return ins.key === 'common' || (!!titleEle && titleEle.value)
397
- }
398
- isNextInsuranceFollow(ins) {
399
- let index = this.productData.mulInsOrderList.findIndex(i => i.key === ins.key)
400
- return (
401
- this.productData.mulInsOrderList[index + 1] &&
402
- !this.productData.mulInsOrderList[index + 1].groupKey &&
403
- this.productData.mulInsOrderList[index + 1].isFollowing
404
- )
405
- }
406
- getElementRules(ele) {
407
- let _rules = ele.rules || []
408
- if (ele.isIgnoreValidate) {
409
- _rules = []
410
- }
411
- return _rules
412
- }
413
- getElementDisabled(ele) {
414
- const opts = (ele.opts || []).filter(o => !o.isHide && !o.isDisabled && !o.isInvalid)
415
- return ele.isDisabled || (opts.length === 1 && _get(opts, '[0].val') === ele.value)
416
- }
417
- genInsuranceHmTag(opt) {
418
- const refInsurance = this.productData.mulInsOrderList.find(ins => ins.key === opt.val)
419
- if (!refInsurance) {
420
- return ''
421
- }
422
- if (!refInsurance.huomian || refInsurance.isGroup) {
423
- return ''
424
- }
425
- if (refInsurance.huomian === 'beiHuomian') {
426
- return '被保人'
427
- }
428
- return '投保人'
429
- }
430
- getInsuranceTitleHmTag(insurance) {
431
- if (!insurance.huomian || insurance.isGroup) {
432
- return ''
433
- }
434
- if (insurance.huomian === 'beiHuomian') {
435
- return '被保人'
436
- } else {
437
- return '投保人'
438
- }
439
- }
440
- /** params.insuranceSaleStatus: { [insuranceKey]: number },值为 2 表示停售(与 cmCommonTitle、cmCommonRadio 选项 val 一致) */
441
- getInsuranceSaleStatusTagByKey(key: string | number) {
442
- const map = _get(this, 'params.insuranceSaleStatus')
443
- if (!map || typeof map !== 'object' || key === undefined || key === null) {
444
- return ''
445
- }
446
- const status = map[key] ?? map[String(key)]
447
- if (status === undefined || status === null) {
448
- return ''
357
+
358
+ toastGroupSubsBecameUnselectable(productData, prevEnabledMap) {
359
+ const names = getGroupSubsBecameUnselectable(_get(productData, 'mulInsOrderList'), prevEnabledMap)
360
+ if (names.length) {
361
+ Toast(`承保规则变化,${names.join('、')}不可选`)
449
362
  }
450
- return Number(status) === 2 ? '停' : ''
451
- }
452
- getInsuranceSaleStatusTag(insurance) {
453
- return this.getInsuranceSaleStatusTagByKey(insurance.key)
454
363
  }
455
- getHuomianTips(insurance, element) {
456
- const personOrderList = this.inputData.personData.personOrderList
457
- const applicationInfo = personOrderList.find(p => p.key === 'applicantInfo')
458
- const applicationTitle = applicationInfo && applicationInfo.eleOrderList.find(e => e.key === 'title')
459
- const applicationSame = applicationInfo && applicationInfo.eleOrderList.find(e => e.key === 'applicantAndInsuredSame')
460
- if (!(['touHuomian', 'shuangHuomian'].includes(insurance.huomian) && element.isDisabled)) {
461
- return ''
462
- }
463
- if (!(applicationTitle && applicationTitle.value)) {
464
- return '<em>设置</em>投保人信息后选择'
465
- }
466
- if (applicationSame && applicationSame.value && !insurance.allowSamePerson) {
467
- return '投被保人为同一人,<em>修改</em>投保人信息后选择'
364
+
365
+ isNextInsuranceFollow(ins) {
366
+ const list = _get(this.productData, 'mulInsOrderList') || []
367
+ const index = list.findIndex(i => i.key === ins.key)
368
+ const next = list[index + 1]
369
+ if (!next) {
370
+ return false
468
371
  }
469
- return '当前投保人不能加该险种,<em>修改</em>投保人信息后选择'
470
- }
471
- getAmountUnit(ele) {
472
- let digits = isNaN(ele.value * 1) ? 0 : Math.floor(Math.log10(ele.value) + 1)
473
- switch (digits) {
474
- case 5:
475
- return '万'
476
- case 6:
477
- return '十万'
478
- case 7:
479
- return '百万'
480
- case 8:
481
- return '千万'
482
- case 9:
483
- return '亿'
484
- default:
485
- return ''
372
+ if (ins.groupKey && next.groupKey && String(ins.groupKey) === String(next.groupKey)) {
373
+ return !!next.isFollowing && this.isGroupActive(String(ins.groupKey))
486
374
  }
375
+ return !ins.groupKey && !next.groupKey && !!next.isFollowing
487
376
  }
377
+
488
378
  async validate() {
489
- const { $refs, filterInsuranceList } = this
490
- const insKeys: any = filterInsuranceList.map(ins => ins.key)
379
+ const insKeys = this.visibleInsuranceList.map(ins => ins.key)
491
380
  return new Promise((resolve, reject) => {
492
381
  setTimeout(() => {
493
- const promises = []
494
- for (const k of insKeys) {
495
- const _ref = _get($refs, `insuranceForm${k}[0]`)
496
- if (_ref) {
497
- promises.push(_ref?.validate())
498
- }
499
- }
382
+ const promises = insKeys
383
+ .map(k => _get(this.$refs, `insuranceForm${k}[0]`))
384
+ .filter(ref => ref && ref.validate)
385
+ .map(ref => ref.validate())
500
386
  Promise.all(promises)
501
387
  .then(() => resolve([]))
502
- .catch(error => reject(error))
388
+ .catch(reject)
503
389
  }, 200)
504
390
  })
505
391
  }
506
- closeKeyBoard() {
507
- const activeElement: any = document.activeElement
508
- if (!activeElement) {
509
- return false
510
- }
511
- activeElement.blur()
512
- return false
513
- }
514
- getRecommendValues(ins, ele) {
515
- if (!['baoe', 'baof'].includes(ele.key) || ele.isDisabled) {
516
- return null
517
- }
518
- const insurance = convertEleOrderListToObj(ins)
519
- return this.recommendValues && this.recommendValues[insurance.isGroup ? insurance.insuranceId : insurance.key]
520
- }
521
- async requiestRecommendValues() {
522
- const self = this
523
- const { showRecommendValue, recommendValuesCache, inputData, groupData, productData } = self
524
- if (!showRecommendValue) {
525
- return
526
- }
527
- const requestDataToCalc: any = await createdProductDataToCalc(inputData, {
528
- groupKey: groupData.key,
529
- productKey: productData.key
530
- }).catch(() => {})
531
- const reqParams: any = []
532
- const inputDataToCalc = requestDataToCalc && JSON.parse(requestDataToCalc.jd)
533
- const mulInsOrderList = _get(inputDataToCalc, 'productGroupList[0].prodOrderList[0].mulInsOrderList') || []
534
- mulInsOrderList.forEach(ins => {
535
- reqParams.push({
536
- insuranceId: ins.key,
537
- period: ins.pPeriod,
538
- calMethod: ins.calMethod || ins.feeType || ins.feeBaseType
539
- })
540
- })
541
-
542
- if (recommendValuesCache[JSON.stringify(reqParams)]) {
543
- self.recommendValues = recommendValuesCache[JSON.stringify(reqParams)]
544
- return
545
- }
546
392
 
547
- return getPlanbookRecommendData(reqParams)
548
- .then((data: any) => {
549
- const recommendValues = data.reduce((obj, ele) => {
550
- return Object.assign(obj, {
551
- [ele.insuranceId]: ele.valueList
552
- })
553
- }, {})
554
-
555
- // 推荐金额,根据最小值和最大值进行过滤。From hyw
556
- const mulInsOrderList = _get(productData, 'mulInsOrderList') || []
557
- mulInsOrderList
558
- .filter(ins => ins.eleOrderList && ins.eleOrderList.length)
559
- .filter(ins => recommendValues[ins.key])
560
- .map(ins => {
561
- const calMethod = ins.calMethod || ins.feeType || ins.feeBaseType
562
- const key = calMethod === 'baof2baoe' ? 'baof' : 'baoe'
563
- const ele = ins.eleOrderList.find(ele => ele.key === key)
564
- if (ele) {
565
- if (ele.min && !isNaN(Number(ele.min))) {
566
- recommendValues[ins.key] = (recommendValues[ins.key] || []).filter(v => v >= ele.min)
567
- }
568
- if (ele.max && !isNaN(Number(ele.max))) {
569
- recommendValues[ins.key] = (recommendValues[ins.key] || []).filter(v => v <= ele.max)
570
- }
571
- }
572
- })
573
- self.recommendValues = recommendValues
574
- recommendValuesCache[JSON.stringify(reqParams)] = recommendValues
575
- })
576
- .catch(info => {
577
- self.$toast(info)
393
+ async requiestRecommendValues() {
394
+ if (this.showRecommendValue) {
395
+ try {
396
+ const result = await fetchRecommendValues({
397
+ inputData: this.inputData,
398
+ groupKey: _get(this.groupData, 'key'),
399
+ productKey: _get(this.productData, 'key'),
400
+ productData: this.productData,
401
+ cache: this.recommendValuesCache
402
+ })
403
+ if (result) {
404
+ this.recommendValues = result.recommendValues
405
+ }
406
+ } catch (info) {
407
+ const message = typeof info === 'string' ? info : _get(info, 'message') || _get(info, 'info')
408
+ if (message) {
409
+ Toast(message)
410
+ }
578
411
  console.log(info)
579
- })
580
- }
581
- onClickRecommendValue(value, ins, ele) {
582
- const self = this
583
- ele.value = value
584
- self.onChange({
585
- insData: ins,
586
- eleData: ele
587
- })
588
-
589
- self.$nextTick(() => {
590
- const ref = self.$refs[ins.key + ele.key + 'item']
591
- const ref0 = ref && ref[0]
592
- if (ref0) {
593
- ref0.validate()
594
412
  }
595
- })
596
- }
597
- createInsuranceInputResultEle(insData?: any, eleData?: any) {
598
- const { params, productData } = this
599
- if (!params.allowCustomResult) {
600
- return
601
413
  }
414
+ }
602
415
 
603
- productData.mulInsOrderList
604
- .filter(e => e.key !== 'common' || e.eleOrderList)
605
- .forEach(ins => {
606
- // 需要特别注意组合险的情况
607
- if (ins.groupKey) {
608
- return
609
- }
610
- if (ins.key === 'common') {
611
- return
612
- }
613
- if (insData && eleData && !insData.isGroup && insData.key === ins.key && eleData.key !== 'calMethod') {
614
- return
615
- }
616
-
617
- const calMethod = ins.eleOrderList.find(e => e.key === 'calMethod')
618
- const baof = ins.eleOrderList.find(e => e.key === 'baof') || ins.eleOrderList.find(e => e.key === 'payModePremium')
619
- let inputResult = ins.eleOrderList.find(e => e.key === 'inputResult')
620
- const labelName = calMethod ? (calMethod.value === 'baof2baoe' ? '保额' : '保费') : baof ? '保额' : '保费'
621
- let value = ins.inputResult === undefined ? null : ins.inputResult
622
- if (inputResult) {
623
- value = inputResult.value
624
- }
625
- if (insData && eleData && insData.key === ins.key && eleData.key === 'inputResult') {
626
- value = eleData.value
627
- }
628
- inputResult = {
629
- componentName: 'cmCommonInput',
630
- placeholder: `按照保单填写${labelName}`,
631
- isHide: !productData.inputResultSwitch,
632
- key: 'inputResult',
633
- labelName: `自定义${labelName}`,
634
- inputType: 'text',
635
- required: false,
636
- regExp: '/^\\d{1,}(\\.\\d{1,2})?$/',
637
- regExpMessage: '请输入1-2位小数的值',
638
- value
639
- }
640
- inputResult.rules = initElementValidateRules(inputResult)
641
- delete ins.inputResult
642
- ins.eleOrderList = ins.eleOrderList.filter(e => e.key !== 'inputResult')
643
-
644
- if (productData.inputResultSwitch) {
645
- ins.eleOrderList.push(inputResult)
646
- }
647
- })
416
+ createInsuranceInputResultEle(insData?: any, eleData?: any) {
417
+ writeInsuranceInputResultEle(this.productData, {
418
+ allowCustomResult: _get(this.params, 'allowCustomResult'),
419
+ insData,
420
+ eleData
421
+ })
648
422
  }
649
423
  }
650
424
  </script>