bxs-tools-ui 3.3.2 → 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 (63) hide show
  1. package/es/add-and-take/index.js +1 -7969
  2. package/es/adjust-baoe/index.js +196 -8195
  3. package/es/index.css +1 -1
  4. package/es/index.js +8788 -43744
  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 +3005 -10614
  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 +195 -8195
  15. package/lib/index.css +1 -1
  16. package/lib/index.js +8717 -43678
  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 -10417
  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/add-and-take/demo/index.vue +3 -6
  27. package/packages/adjust-baoe/index.vue +21 -34
  28. package/packages/adjust-baoe/readme.md +0 -1
  29. package/packages/bxs-utils/planbook/common.ts +5 -0
  30. package/packages/bxs-utils/planbook/insurance.ts +19 -0
  31. package/packages/bxs-utils/planbook/person.ts +3 -2
  32. package/packages/bxs-utils/planbook/product.ts +57 -164
  33. package/packages/bxs-utils/readme.md +3 -1
  34. package/packages/index.ts +1 -1
  35. package/packages/insure-calculate/demo/index.vue +1 -1
  36. package/packages/insure-calculate/index.vue +18 -17
  37. package/packages/person-info/demo/index.vue +2 -4
  38. package/packages/planbook-input/components/product-table.vue +3 -14
  39. package/packages/planbook-input/helper.js +16 -53
  40. package/packages/planbook-input/index.vue +20 -28
  41. package/packages/planbook-input/readme.md +3 -3
  42. package/packages/product-info/components/product-insurance-form.md +46 -0
  43. package/packages/product-info/components/product-insurance-form.vue +360 -0
  44. package/packages/product-info/demo/index.vue +4 -5
  45. package/packages/product-info/handler.js +307 -0
  46. package/packages/product-info/handler.md +26 -0
  47. package/packages/product-info/index.less +33 -0
  48. package/packages/product-info/index.vue +306 -534
  49. package/packages/product-info/readme.md +7 -2
  50. package/packages/share-sheet/constant.js +1 -2
  51. package/src/api/adjust-baoe.js +2 -2
  52. package/src/api/planbook.js +4 -20
  53. package/src/api/trade.js +31 -0
  54. package/src/components/common/common-group-title.less +54 -0
  55. package/src/components/common/common-group-title.md +34 -0
  56. package/src/components/common/common-group-title.vue +72 -0
  57. package/src/components/common/common-title.less +4 -0
  58. package/src/components/common/common-title.vue +8 -2
  59. package/src/components/profession-list/README.md +114 -0
  60. package/src/components/profession-list/constant.js +4 -0
  61. package/src/components/profession-list/handler.js +155 -0
  62. package/src/components/profession-list/index.less +182 -0
  63. 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,358 +145,280 @@ 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
330
301
  const planbookId = _get(params, 'planbookId')
331
- const publicPbUuid = _get(params, 'publicPbUuid')
332
302
  const productVerifyData = _get(verifyData, `[${productKey}]`)
333
303
  const eventTarget = {
334
304
  insuranceKey: _get(insData, 'key') || null,
335
305
  insuranceCode: _get(insData, 'code') || null,
336
306
  elementKey: _get(eleData, 'key') || null
337
307
  }
338
- if (productData.multipleInsured) {
308
+ if (_get(productData, 'multipleInsured')) {
339
309
  multipleInsuredHandler(productData, personData)
340
310
  }
311
+ const prevGroupTitleEnabled = snapshotGroupTitleEnabledMap(_get(productData, 'mulInsOrderList'))
341
312
  await productDataHandler(productData, productVerifyData, personData, {
342
313
  user,
343
314
  planbookId,
344
315
  executeSource: 'userAction',
345
316
  eventTarget
346
317
  })
318
+ this.syncGroupUiState(false)
347
319
  if (type === 'change') {
348
- this.createInsuranceInputResultEle(insData, eleData)
349
- } else {
350
- this.createInsuranceInputResultEle()
320
+ this.toastGroupSubsBecameUnselectable(productData, prevGroupTitleEnabled)
351
321
  }
322
+ this.createInsuranceInputResultEle(type === 'change' ? insData : null, type === 'change' ? eleData : null)
352
323
 
353
- let errorMsg: any = verifyProductRules({
354
- personData,
355
- productData,
356
- insData,
357
- eleData
358
- })
324
+ let errorMsg: any = verifyProductRules({ personData, productData, insData, eleData })
359
325
  if (!errorMsg) {
360
326
  await this.validate()
361
327
  .then(async () => {
362
328
  const hasRevalidateFlag = (_get(productData, 'mulInsOrderList') || []).some(ins => ins.revalidateFlag)
363
- if (hasRevalidateFlag && $listeners.reCalculate) {
364
- await new Promise<any>((resolve, reject) => {
365
- this.$emit(
366
- 'reCalculate',
367
- inputData,
368
- {
369
- user,
370
- planbookId,
371
- publicPbUuid,
372
- groupKey,
373
- productKey,
374
- executeSource: 'userAction',
375
- isIgnoreError: true,
376
- eventTarget
377
- },
378
- resolve,
379
- reject
380
- )
381
- }).catch(err => {
382
- errorMsg = _get(err, '[0].message') || _get(err, 'message')
383
- })
384
- await productDataHandler(productData, productVerifyData, personData, {
385
- user,
386
- planbookId,
387
- executeSource: 'userAction',
388
- eventTarget
389
- })
329
+ if (!(hasRevalidateFlag && $listeners.reCalculate)) {
330
+ return
390
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)
391
352
  })
392
353
  .catch(() => {})
393
354
  }
394
355
  return errorMsg
395
356
  }
396
- isInsuranceChecked(ins) {
397
- let titleEle = ins.eleOrderList.find(e => e.key === 'title')
398
- return ins.key === 'common' || (!!titleEle && titleEle.value)
399
- }
400
- isNextInsuranceFollow(ins) {
401
- let index = this.productData.mulInsOrderList.findIndex(i => i.key === ins.key)
402
- return (
403
- this.productData.mulInsOrderList[index + 1] &&
404
- !this.productData.mulInsOrderList[index + 1].groupKey &&
405
- this.productData.mulInsOrderList[index + 1].isFollowing
406
- )
407
- }
408
- getElementRules(ele) {
409
- let _rules = ele.rules || []
410
- if (ele.isIgnoreValidate) {
411
- _rules = []
412
- }
413
- return _rules
414
- }
415
- getElementDisabled(ele) {
416
- const opts = (ele.opts || []).filter(o => !o.isHide && !o.isDisabled && !o.isInvalid)
417
- return ele.isDisabled || (opts.length === 1 && _get(opts, '[0].val') === ele.value)
418
- }
419
- genInsuranceHmTag(opt) {
420
- const refInsurance = this.productData.mulInsOrderList.find(ins => ins.key === opt.val)
421
- if (!refInsurance) {
422
- return ''
423
- }
424
- if (!refInsurance.huomian || refInsurance.isGroup) {
425
- return ''
426
- }
427
- if (refInsurance.huomian === 'beiHuomian') {
428
- return '被保人'
429
- }
430
- return '投保人'
431
- }
432
- getInsuranceTitleHmTag(insurance) {
433
- if (!insurance.huomian || insurance.isGroup) {
434
- return ''
435
- }
436
- if (insurance.huomian === 'beiHuomian') {
437
- return '被保人'
438
- } else {
439
- return '投保人'
440
- }
441
- }
442
- /** params.insuranceSaleStatus: { [insuranceKey]: number },值为 2 表示停售(与 cmCommonTitle、cmCommonRadio 选项 val 一致) */
443
- getInsuranceSaleStatusTagByKey(key: string | number) {
444
- const map = _get(this, 'params.insuranceSaleStatus')
445
- if (!map || typeof map !== 'object' || key === undefined || key === null) {
446
- return ''
447
- }
448
- const status = map[key] ?? map[String(key)]
449
- if (status === undefined || status === null) {
450
- return ''
357
+
358
+ toastGroupSubsBecameUnselectable(productData, prevEnabledMap) {
359
+ const names = getGroupSubsBecameUnselectable(_get(productData, 'mulInsOrderList'), prevEnabledMap)
360
+ if (names.length) {
361
+ Toast(`承保规则变化,${names.join('、')}不可选`)
451
362
  }
452
- return Number(status) === 2 ? '停' : ''
453
- }
454
- getInsuranceSaleStatusTag(insurance) {
455
- return this.getInsuranceSaleStatusTagByKey(insurance.key)
456
363
  }
457
- getHuomianTips(insurance, element) {
458
- const personOrderList = this.inputData.personData.personOrderList
459
- const applicationInfo = personOrderList.find(p => p.key === 'applicantInfo')
460
- const applicationTitle = applicationInfo && applicationInfo.eleOrderList.find(e => e.key === 'title')
461
- const applicationSame = applicationInfo && applicationInfo.eleOrderList.find(e => e.key === 'applicantAndInsuredSame')
462
- if (!(['touHuomian', 'shuangHuomian'].includes(insurance.huomian) && element.isDisabled)) {
463
- return ''
464
- }
465
- if (!(applicationTitle && applicationTitle.value)) {
466
- return '<em>设置</em>投保人信息后选择'
467
- }
468
- if (applicationSame && applicationSame.value && !insurance.allowSamePerson) {
469
- 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
470
371
  }
471
- return '当前投保人不能加该险种,<em>修改</em>投保人信息后选择'
472
- }
473
- getAmountUnit(ele) {
474
- let digits = isNaN(ele.value * 1) ? 0 : Math.floor(Math.log10(ele.value) + 1)
475
- switch (digits) {
476
- case 5:
477
- return '万'
478
- case 6:
479
- return '十万'
480
- case 7:
481
- return '百万'
482
- case 8:
483
- return '千万'
484
- case 9:
485
- return '亿'
486
- default:
487
- return ''
372
+ if (ins.groupKey && next.groupKey && String(ins.groupKey) === String(next.groupKey)) {
373
+ return !!next.isFollowing && this.isGroupActive(String(ins.groupKey))
488
374
  }
375
+ return !ins.groupKey && !next.groupKey && !!next.isFollowing
489
376
  }
377
+
490
378
  async validate() {
491
- const { $refs, filterInsuranceList } = this
492
- const insKeys: any = filterInsuranceList.map(ins => ins.key)
379
+ const insKeys = this.visibleInsuranceList.map(ins => ins.key)
493
380
  return new Promise((resolve, reject) => {
494
381
  setTimeout(() => {
495
- const promises = []
496
- for (const k of insKeys) {
497
- const _ref = _get($refs, `insuranceForm${k}[0]`)
498
- if (_ref) {
499
- promises.push(_ref?.validate())
500
- }
501
- }
382
+ const promises = insKeys
383
+ .map(k => _get(this.$refs, `insuranceForm${k}[0]`))
384
+ .filter(ref => ref && ref.validate)
385
+ .map(ref => ref.validate())
502
386
  Promise.all(promises)
503
387
  .then(() => resolve([]))
504
- .catch(error => reject(error))
388
+ .catch(reject)
505
389
  }, 200)
506
390
  })
507
391
  }
508
- closeKeyBoard() {
509
- const activeElement: any = document.activeElement
510
- if (!activeElement) {
511
- return false
512
- }
513
- activeElement.blur()
514
- return false
515
- }
516
- getRecommendValues(ins, ele) {
517
- if (!['baoe', 'baof'].includes(ele.key) || ele.isDisabled) {
518
- return null
519
- }
520
- const insurance = convertEleOrderListToObj(ins)
521
- return this.recommendValues && this.recommendValues[insurance.isGroup ? insurance.insuranceId : insurance.key]
522
- }
523
- async requiestRecommendValues() {
524
- const self = this
525
- const { showRecommendValue, recommendValuesCache, inputData, groupData, productData } = self
526
- if (!showRecommendValue) {
527
- return
528
- }
529
- const requestDataToCalc: any = await createdProductDataToCalc(inputData, {
530
- groupKey: groupData.key,
531
- productKey: productData.key
532
- }).catch(() => {})
533
- const reqParams: any = []
534
- const inputDataToCalc = requestDataToCalc && JSON.parse(requestDataToCalc.jd)
535
- const mulInsOrderList = _get(inputDataToCalc, 'productGroupList[0].prodOrderList[0].mulInsOrderList') || []
536
- mulInsOrderList.forEach(ins => {
537
- reqParams.push({
538
- insuranceId: ins.key,
539
- period: ins.pPeriod,
540
- calMethod: ins.calMethod || ins.feeType || ins.feeBaseType
541
- })
542
- })
543
-
544
- if (recommendValuesCache[JSON.stringify(reqParams)]) {
545
- self.recommendValues = recommendValuesCache[JSON.stringify(reqParams)]
546
- return
547
- }
548
392
 
549
- return getPlanbookRecommendData(reqParams)
550
- .then((data: any) => {
551
- const recommendValues = data.reduce((obj, ele) => {
552
- return Object.assign(obj, {
553
- [ele.insuranceId]: ele.valueList
554
- })
555
- }, {})
556
-
557
- // 推荐金额,根据最小值和最大值进行过滤。From hyw
558
- const mulInsOrderList = _get(productData, 'mulInsOrderList') || []
559
- mulInsOrderList
560
- .filter(ins => ins.eleOrderList && ins.eleOrderList.length)
561
- .filter(ins => recommendValues[ins.key])
562
- .map(ins => {
563
- const calMethod = ins.calMethod || ins.feeType || ins.feeBaseType
564
- const key = calMethod === 'baof2baoe' ? 'baof' : 'baoe'
565
- const ele = ins.eleOrderList.find(ele => ele.key === key)
566
- if (ele) {
567
- if (ele.min && !isNaN(Number(ele.min))) {
568
- recommendValues[ins.key] = (recommendValues[ins.key] || []).filter(v => v >= ele.min)
569
- }
570
- if (ele.max && !isNaN(Number(ele.max))) {
571
- recommendValues[ins.key] = (recommendValues[ins.key] || []).filter(v => v <= ele.max)
572
- }
573
- }
574
- })
575
- self.recommendValues = recommendValues
576
- recommendValuesCache[JSON.stringify(reqParams)] = recommendValues
577
- })
578
- .catch(info => {
579
- 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
+ }
580
411
  console.log(info)
581
- })
582
- }
583
- onClickRecommendValue(value, ins, ele) {
584
- const self = this
585
- ele.value = value
586
- self.onChange({
587
- insData: ins,
588
- eleData: ele
589
- })
590
-
591
- self.$nextTick(() => {
592
- const ref = self.$refs[ins.key + ele.key + 'item']
593
- const ref0 = ref && ref[0]
594
- if (ref0) {
595
- ref0.validate()
596
412
  }
597
- })
598
- }
599
- createInsuranceInputResultEle(insData?: any, eleData?: any) {
600
- const { params, productData } = this
601
- if (!params.allowCustomResult) {
602
- return
603
413
  }
414
+ }
604
415
 
605
- productData.mulInsOrderList
606
- .filter(e => e.key !== 'common' || e.eleOrderList)
607
- .forEach(ins => {
608
- // 需要特别注意组合险的情况
609
- if (ins.groupKey) {
610
- return
611
- }
612
- if (ins.key === 'common') {
613
- return
614
- }
615
- if (insData && eleData && !insData.isGroup && insData.key === ins.key && eleData.key !== 'calMethod') {
616
- return
617
- }
618
-
619
- const calMethod = ins.eleOrderList.find(e => e.key === 'calMethod')
620
- const baof = ins.eleOrderList.find(e => e.key === 'baof') || ins.eleOrderList.find(e => e.key === 'payModePremium')
621
- let inputResult = ins.eleOrderList.find(e => e.key === 'inputResult')
622
- const labelName = calMethod ? (calMethod.value === 'baof2baoe' ? '保额' : '保费') : baof ? '保额' : '保费'
623
- let value = ins.inputResult === undefined ? null : ins.inputResult
624
- if (inputResult) {
625
- value = inputResult.value
626
- }
627
- if (insData && eleData && insData.key === ins.key && eleData.key === 'inputResult') {
628
- value = eleData.value
629
- }
630
- inputResult = {
631
- componentName: 'cmCommonInput',
632
- placeholder: `按照保单填写${labelName}`,
633
- isHide: !productData.inputResultSwitch,
634
- key: 'inputResult',
635
- labelName: `自定义${labelName}`,
636
- inputType: 'text',
637
- required: false,
638
- regExp: '/^\\d{1,}(\\.\\d{1,2})?$/',
639
- regExpMessage: '请输入1-2位小数的值',
640
- value
641
- }
642
- inputResult.rules = initElementValidateRules(inputResult)
643
- delete ins.inputResult
644
- ins.eleOrderList = ins.eleOrderList.filter(e => e.key !== 'inputResult')
645
-
646
- if (productData.inputResultSwitch) {
647
- ins.eleOrderList.push(inputResult)
648
- }
649
- })
416
+ createInsuranceInputResultEle(insData?: any, eleData?: any) {
417
+ writeInsuranceInputResultEle(this.productData, {
418
+ allowCustomResult: _get(this.params, 'allowCustomResult'),
419
+ insData,
420
+ eleData
421
+ })
650
422
  }
651
423
  }
652
424
  </script>