cnhis-design-vue 2.1.18 → 2.1.19

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 (126) hide show
  1. package/CHANGELOG.md +2219 -2219
  2. package/es/affix/index.js +8 -8
  3. package/es/age/index.js +10 -10
  4. package/es/alert/index.js +8 -8
  5. package/es/anchor/index.js +8 -8
  6. package/es/auto-complete/index.js +8 -8
  7. package/es/avatar/index.js +8 -8
  8. package/es/back-top/index.js +8 -8
  9. package/es/badge/index.js +8 -8
  10. package/es/base/index.js +8 -8
  11. package/es/big-table/index.js +207 -206
  12. package/es/big-table/style.css +1 -1
  13. package/es/breadcrumb/index.js +8 -8
  14. package/es/button/index.js +31 -31
  15. package/es/calendar/index.js +8 -8
  16. package/es/captcha/index.js +3 -3
  17. package/es/card/index.js +8 -8
  18. package/es/carousel/index.js +8 -8
  19. package/es/cascader/index.js +8 -8
  20. package/es/checkbox/index.js +9 -9
  21. package/es/col/index.js +8 -8
  22. package/es/collapse/index.js +8 -8
  23. package/es/color-picker/index.js +1 -1
  24. package/es/comment/index.js +8 -8
  25. package/es/config-provider/index.js +8 -8
  26. package/es/date-picker/index.js +8 -8
  27. package/es/descriptions/index.js +8 -8
  28. package/es/divider/index.js +8 -8
  29. package/es/drag-layout/index.js +3 -3
  30. package/es/drawer/index.js +8 -8
  31. package/es/dropdown/index.js +8 -8
  32. package/es/editor/index.js +1 -1
  33. package/es/empty/index.js +8 -8
  34. package/es/fabric-chart/index.js +427 -314
  35. package/es/fabric-chart/style.css +1 -1
  36. package/es/form/index.js +8 -8
  37. package/es/form-model/index.js +8 -8
  38. package/es/form-table/index.js +62 -62
  39. package/es/index/index.js +1078 -963
  40. package/es/index/style.css +1 -1
  41. package/es/input/index.js +9 -9
  42. package/es/input-number/index.js +8 -8
  43. package/es/layout/index.js +8 -8
  44. package/es/list/index.js +8 -8
  45. package/es/locale-provider/index.js +8 -8
  46. package/es/map/index.js +9 -9
  47. package/es/mentions/index.js +8 -8
  48. package/es/menu/index.js +8 -8
  49. package/es/message/index.js +8 -8
  50. package/es/multi-chat/index.js +92 -92
  51. package/es/multi-chat-client/index.js +86 -86
  52. package/es/multi-chat-history/index.js +4 -4
  53. package/es/multi-chat-record/index.js +14 -14
  54. package/es/multi-chat-setting/index.js +27 -27
  55. package/es/multi-chat-sip/index.js +1 -1
  56. package/es/notification/index.js +8 -8
  57. package/es/page-header/index.js +8 -8
  58. package/es/pagination/index.js +8 -8
  59. package/es/popconfirm/index.js +8 -8
  60. package/es/popover/index.js +8 -8
  61. package/es/progress/index.js +8 -8
  62. package/es/radio/index.js +9 -9
  63. package/es/rate/index.js +8 -8
  64. package/es/result/index.js +8 -8
  65. package/es/row/index.js +8 -8
  66. package/es/scale-view/index.js +33 -33
  67. package/es/select/index.js +11 -11
  68. package/es/select-label/index.js +11 -11
  69. package/es/select-person/index.js +20 -20
  70. package/es/skeleton/index.js +8 -8
  71. package/es/slider/index.js +8 -8
  72. package/es/space/index.js +8 -8
  73. package/es/spin/index.js +8 -8
  74. package/es/statistic/index.js +8 -8
  75. package/es/steps/index.js +8 -8
  76. package/es/switch/index.js +8 -8
  77. package/es/table-filter/index.js +142 -141
  78. package/es/table-filter/style.css +1 -1
  79. package/es/tabs/index.js +8 -8
  80. package/es/tag/index.js +9 -9
  81. package/es/time-picker/index.js +8 -8
  82. package/es/timeline/index.js +8 -8
  83. package/es/tooltip/index.js +8 -8
  84. package/es/transfer/index.js +8 -8
  85. package/es/tree/index.js +8 -8
  86. package/es/tree-select/index.js +8 -8
  87. package/es/upload/index.js +8 -8
  88. package/es/verification-code/index.js +2 -2
  89. package/lib/cui.common.js +1073 -958
  90. package/lib/cui.umd.js +1073 -958
  91. package/lib/cui.umd.min.js +77 -77
  92. package/package.json +106 -106
  93. package/packages/big-table/src/BigTable.vue +3039 -3038
  94. package/packages/big-table/src/assets/style/table-base.less +370 -370
  95. package/packages/big-table/src/components/AutoLayoutButton.vue +270 -270
  96. package/packages/big-table/src/utils/batchEditing.js +610 -610
  97. package/packages/big-table/src/utils/bigTableProps.js +95 -95
  98. package/packages/button/src/ButtonPrint/components/IdentityVerification.vue +181 -181
  99. package/packages/button/src/ButtonPrint/index.vue +728 -728
  100. package/packages/fabric-chart/src/components/TimeScaleValue.vue +113 -117
  101. package/packages/fabric-chart/src/const/defaultVaule.js +59 -59
  102. package/packages/fabric-chart/src/fabric-chart/FabricPolylines.vue +1035 -960
  103. package/packages/fabric-chart/src/fabric-chart/FabricScaleValue.vue +135 -135
  104. package/packages/fabric-chart/src/fabric-chart/FabricTextGroup.vue +558 -558
  105. package/packages/fabric-chart/src/fabric-chart2/FabricTop.vue +172 -172
  106. package/packages/fabric-chart/src/mixins/draw.js +70 -62
  107. package/packages/fabric-chart/src/mixins/eventCommon.js +9 -10
  108. package/packages/multi-chat/chat/chatFooter.vue +1598 -1598
  109. package/packages/multi-chat/chat/chatMain.vue +1442 -1442
  110. package/packages/multi-chat/chat/quickReply.vue +439 -439
  111. package/packages/multi-chat/chat/scrollList.vue +1232 -1232
  112. package/packages/multi-chat/setting/baseInfo/index.vue +1316 -1316
  113. package/packages/multi-chat/store/actions.js +448 -448
  114. package/packages/multi-chat/store/state.js +112 -112
  115. package/packages/scale-view/formitem/r-choice.vue +714 -714
  116. package/packages/scale-view/scaleView.vue +2010 -2010
  117. package/packages/select-person/select-person.vue +1658 -1658
  118. package/packages/table-filter/src/base-search-com/BaseSearch.vue +2462 -2462
  119. package/packages/table-filter/src/components/c-tree-select/tree-select.vue +336 -336
  120. package/packages/table-filter/src/components/multi-select/multi-select.vue +219 -219
  121. package/packages/table-filter/src/components/out-quick-search/out-quick-search.vue +340 -340
  122. package/packages/table-filter/src/components/search-condition/SearchCondition.vue +3 -2
  123. package/packages/table-filter/src/const/dataOptions.js +43 -43
  124. package/packages/table-filter/src/mixins/mixins.js +695 -695
  125. package/packages/table-filter/src/quick-search/QuickSearch.vue +2083 -2083
  126. package/src/directive/preventReClick.js +12 -12
@@ -1,2010 +1,2010 @@
1
- <template>
2
- <div class="r-scale">
3
- <slot v-if="spinning">
4
- <a-spin :indicator="indicator" tip="加载中..." />
5
- </slot>
6
- <slot v-if="!spinning && !hasFrontAddress">
7
- <!-- <div v-if="noData">暂无数据</div> -->
8
- <NoData v-if="noData" :noDataImg="noDataImg" :noDataTip="noDataTip"></NoData>
9
- <template v-else>
10
- <evaluatePage
11
- v-if="showEvaluateEntry"
12
- :formArray="formArray"
13
- :evaluateResultConfig="config.evaluateResultConfig"
14
- :evaluateResultSetting="config.evaluateResultSetting"
15
- :isFinished="isFinished"
16
- :maxScore="maxScore"
17
- @writeGuage="writeGuage"
18
- ></evaluatePage>
19
- <template v-else>
20
- <evaluateCountdown
21
- v-if="showEvaluateCoundownPage"
22
- ref="evaluateCountdown"
23
- :formArray="formArray"
24
- :evaluateResultConfig="config.evaluateResultConfig"
25
- :evaluateResultSetting="config.evaluateResultSetting"
26
- :form="form"
27
- :isFinished="isFinished"
28
- :currentTime="currentTime"
29
- :showEvaluateCountdown="showEvaluateCountdown"
30
- @closeEvaluateCountdown="closeEvaluateCountdown"
31
- ></evaluateCountdown>
32
- <div
33
- class="scale-container"
34
- :class="{ 'scale-container-nopadding': handlePageClass }"
35
- :style="scaleStyle"
36
- >
37
- <div class="totalScore-warp" v-if="hasScore">
38
- <div>
39
- 测评总分:
40
- <span>{{ maxScore }}分</span>
41
- </div>
42
- <div>
43
- 测评分数:
44
- <span :style="{ color: getEvaResColor }">{{ config.totalScore }}分</span>
45
- </div>
46
- <template v-if="hasEvaluateSetting">
47
- <div>
48
- 测评结果:
49
- <span
50
- class="score-result"
51
- :style="{ color: getEvaResColor }"
52
- >{{ config.evaluateResult }}</span>
53
- </div>
54
- <div>
55
- 结果说明:
56
- <span>{{ config.evaluateResultExplain }}</span>
57
- </div>
58
- </template>
59
- </div>
60
- <a-form-model
61
- ref="ruleForm"
62
- :model="form"
63
- :rules="rules"
64
- :layout="form.layout"
65
- :colon="false"
66
- class="main"
67
- >
68
- <template v-for="(item, index) in formArray">
69
- <!-- 标题 -->
70
- <template v-if="item.type == 'TITLE'">
71
- <a-form-model-item
72
- v-if="isShowItem(item)"
73
- :colon="false"
74
- :key="item.id || item.seq"
75
- >
76
- <h1 class="lb-title">{{ item.title }}</h1>
77
- <div class="lb-title">{{ item.describe }}</div>
78
- </a-form-model-item>
79
- </template>
80
- <!-- 分线栏 -->
81
- <template v-else-if="item.type == 'LINEBAR'">
82
- <a-form-model-item
83
- v-if="isShowItem(item)"
84
- :colon="false"
85
- :key="item.id || item.seq"
86
- >
87
- <div class="linebar-div" v-if="item.title">
88
- <span>{{ item.title }}</span>
89
- <a-divider />
90
- </div>
91
- <template v-else>
92
- <a-divider />
93
- </template>
94
- </a-form-model-item>
95
- </template>
96
- <!-- 提示语 -->
97
- <template v-else-if="item.type == 'PROMPT'">
98
- <a-form-model-item
99
- v-if="isShowItem(item)"
100
- class="my-prompt"
101
- :colon="false"
102
- :key="item.id || item.seq"
103
- >
104
- <MyPrompt :key="item.id || item.seq" :options="item.setting" />
105
- </a-form-model-item>
106
- </template>
107
- <template v-else-if="item.type == 'IMGCARD'">
108
- <a-form-model-item
109
- v-if="isShowItem(item)"
110
- :colon="false"
111
- :key="item.id || item.seq"
112
- >
113
- <a v-if="item.setting.imgLink" :href="item.setting.imgLink" target="_blank">
114
- <img class="img-card" :src="item.setting.imgUrl" />
115
- </a>
116
- <img class="img-card" v-else :src="item.setting.imgUrl" />
117
- </a-form-model-item>
118
- </template>
119
- <!-- 富文本 -->
120
- <template v-else-if="item.type == 'RICH_TEXT'">
121
- <div
122
- :key="item.id || item.seq"
123
- class="rich-text-content"
124
- v-html="item.setting.defaultValue"
125
- ></div>
126
- </template>
127
- <template v-else>
128
- <a-form-model-item
129
- v-if="isShowItem(item)"
130
- :key="item.id || item.seq"
131
- :prop="formKey(item)"
132
- >
133
- <span slot="label">
134
- <span
135
- :class="{ 'scale-label-required': isFormBoldOpen(item) }"
136
- v-html="handleShowQuestionNumber(item)"
137
- ></span>
138
- <span class="required-text" v-if="isFormBoldOpen(item)">(必填)</span>
139
- <span
140
- class="evalute-label"
141
- v-if="showEvaluateLabel(item)"
142
- >{{ showEvaluateLabel(item) }}</span>
143
- <template v-if="showEvatip(item)">
144
- <span class="evalute-tip" @click="showEvaTipModal(item)">
145
- <svg-icon icon-class="a-xitongtubiaotishi" />查看提示
146
- </span>
147
- </template>
148
- </span>
149
- <!-- 输入框 -->
150
- <MyInput
151
- v-bind="$attrs"
152
- v-if="isInput(item.type)"
153
- v-model="form[formKey(item)]"
154
- :type="item.valueType"
155
- :row="item.setting.inputRow || 1"
156
- :defaultPlaceHolder="item.setting.defaultPlaceHolder"
157
- :isLock="componentDisable"
158
- />
159
-
160
- <!-- 单选/下拉/多选/级联 -->
161
- <MyChoice
162
- v-bind="$attrs"
163
- v-else-if="isChoice(item.type)"
164
- v-model="form[formKey(item)]"
165
- :item="item"
166
- :isLock="componentDisable"
167
- :curIndex="index"
168
- :openType="openType"
169
- @change="handleChoice($event, item)"
170
- @radioChange="radioChange"
171
- @checkboxChange="checkboxChange"
172
- />
173
- <!-- 日期/时间 -->
174
- <MyTime
175
- v-bind="$attrs"
176
- v-else-if="isTime(item.type)"
177
- :value="getTimeValue(item)"
178
- :type="item.type"
179
- :startToStop="item.setting.startToStop"
180
- :dateType="item.setting.dateType"
181
- :isLock="componentDisable"
182
- @change="changeTime($event, item)"
183
- />
184
- <!-- 上传附件 or 图片 -->
185
- <MyUpload
186
- v-bind="$attrs"
187
- v-else-if="isUpload(item.type)"
188
- :upType="item.type"
189
- :useFileList="item.dbValue"
190
- :limitPic="item.setting.limitPic"
191
- :isLock="componentDisable"
192
- @change="changeUpload($event, item)"
193
- />
194
- <!-- 地图 -->
195
- <div
196
- v-else-if="item.type === 'LOCATION'"
197
- @click="!isLock && (mapVisible = !mapVisible)"
198
- :class="{ 'map-container': !isLock }"
199
- >
200
- <a-input
201
- placeholder="请选择"
202
- :value="handleGetAddress(form[formKey(item)])"
203
- disabled
204
- >
205
- <a-icon slot="prefix" type="info-circle" />
206
- </a-input>
207
- <MapComp
208
- v-bind="$attrs"
209
- :visible.sync="mapVisible"
210
- :locationProp="form[formKey(item)]"
211
- :isLock="componentDisable"
212
- @selectLocation="handleSelectLocation($event, item)"
213
- />
214
- </div>
215
- <!-- 地址 -->
216
- <MyAddress
217
- v-bind="$attrs"
218
- v-else-if="item.type === 'ADDRESS'"
219
- :setting="item.setting"
220
- :defaultValue="defaultAddress"
221
- :isLock="componentDisable"
222
- @change="changeAddress($event, item)"
223
- />
224
- <!-- 标签 -->
225
- <label-form
226
- v-bind="$attrs"
227
- v-else-if="item.type === 'LABEL'"
228
- :item="item"
229
- :selectedList="labelSelectedList"
230
- :isLock="componentDisable"
231
- :sourceType="source"
232
- @onChange="labelChange($event, item)"
233
- />
234
- <!-- 视频 -->
235
- <vod-Chunk-upload
236
- v-bind="$attrs"
237
- v-else-if="item.type === 'VEDIO'"
238
- :source="'guage'"
239
- :formData="item"
240
- :limitNum="item.setting.limitPic"
241
- :defFileList="form[formKey(item)]"
242
- :isLock="componentDisable"
243
- @vodFileList="vodFileList($event, item)"
244
- />
245
- <!-- 答案解析 -->
246
- <answerParse v-if="showAnswerParse(item)" :item="item"></answerParse>
247
- </a-form-model-item>
248
- </template>
249
- </template>
250
- </a-form-model>
251
- </div>
252
- <template v-if="type === 'customList'">
253
- <div class="footer" v-if="!noBtn">
254
- <a-button @click="cancel" v-if="false" style="margin-right: 8px;">取消</a-button>
255
- <a-button @click="onSubmit" type="primary" :disabled="banSubmit">保存</a-button>
256
- </div>
257
- </template>
258
- <template v-else>
259
- <div class="footer" v-if="showSaveBtn">
260
- <a-button @click="cancel" style="margin-right: 8px;">取消</a-button>
261
- <a-button type="primary" v-if="!isLock" @click="onSubmit" :disabled="banSubmit">保存</a-button>
262
- </div>
263
- </template>
264
- </template>
265
- </template>
266
- </slot>
267
- </div>
268
- </template>
269
- <script>
270
- import { Icon, Checkbox, Tree, Tooltip, Input, Spin, FormModel, Divider, Button } from 'ant-design-vue';
271
- import create from '@/core/create';
272
- import { MyChoice, MyInput, MyAddress, MyUpload, MyTime, MyPrompt } from './formitem';
273
- import MapComp from '../map/src/popup-map';
274
- import labelForm from '~/select-label/select-label';
275
- import vodChunkUpload from '~/upload/chunk-upload/vod-chunk-upload.vue';
276
- // import { EventBus } from "@/common/utils/eventBus.js";
277
- import { judgeTypes } from './mixin/judgeTypes';
278
- import NoDataJs from './mixin/NoData';
279
- // import { mapGetters } from "vuex";
280
- import moment from 'moment';
281
- import utils from '@/utils/utils-map';
282
- import evaluatePage from './evaluatePage.vue';
283
- import evaluateCountdown from './evaluateCountdown.vue';
284
- import answerParse from './answerParse.vue';
285
- import vexutils from '@/utils/vexutils';
286
- import NoData from './NoData.vue';
287
- export default create({
288
- name: 'scale-view',
289
- mixins: [judgeTypes, NoDataJs],
290
- props: {
291
- ids: {
292
- type: Object,
293
- default: () => {
294
- return { guage_id: '', db_id: undefined };
295
- }
296
- },
297
- params: { default: () => ({}), type: Object },
298
- guageData: { type: Object, default: () => ({}) },
299
- noBtn: { type: Boolean, default: false },
300
- hideBtn: { type: Boolean, default: false },
301
- source: { type: String, default: '' },
302
- isLock: { type: Boolean, default: false },
303
- type: {
304
- type: String,
305
- default: ''
306
- },
307
- styleSetting: {
308
- type: Object,
309
- default: () => ({})
310
- },
311
-
312
- fontSizeObj: {
313
- type: Object,
314
- default: () => ({
315
- large: 1.25,
316
- medium: 1.1,
317
- small: 1,
318
- extrasmall: 0.9
319
- })
320
- },
321
- openType: { type: String, default: '' },
322
- scaleApiConfig: {
323
- type: Object,
324
- default: () => ({})
325
- }
326
- },
327
- components: {
328
- MyChoice,
329
- MyInput,
330
- MapComp,
331
- MyAddress,
332
- MyUpload,
333
- MyTime,
334
- MyPrompt,
335
- labelForm,
336
- vodChunkUpload,
337
- [Icon.name]: Icon,
338
- [Spin.name]: Spin,
339
- [Tree.name]: Tree,
340
- [Input.name]: Input,
341
- [Input.Search.name]: Input.Search,
342
- [Checkbox.name]: Checkbox,
343
- [Divider.name]: Divider,
344
- [Button.name]: Button,
345
- [FormModel.name]: FormModel,
346
- [FormModel.Item.name]: FormModel.Item,
347
- [Tooltip.name]: Tooltip,
348
- evaluatePage,
349
- evaluateCountdown,
350
- answerParse,
351
- NoData
352
- },
353
- computed: {
354
- queryformBoldOpen() {
355
- return this.$route.query?.formBoldOpen == 1;
356
- },
357
- showEvatip() {
358
- return function (item) {
359
- if (!this.isEvaluation(item.type)) return false;
360
- return this.$route.query?.evatip == 1 || this.params?.evatip == 1;
361
- };
362
- },
363
- isFormBoldOpen() {
364
- return function (item) {
365
- let res = item.required;
366
- // 量表未登录时 判断 url中是否有 formBoldOpen
367
- if (!this.styleSetting || !Object.keys(this.styleSetting).length || !('formBoldOpen' in this.styleSetting)) {
368
- return res && this.queryformBoldOpen;
369
- }
370
- return res && this.styleSetting.formBoldOpen;
371
- };
372
- },
373
- scaleStyle() {
374
- let fontSize = this.fontSize;
375
- if (!fontSize || fontSize === 'S') return null;
376
- const keyValue = {
377
- L: 'large',
378
- M: 'medium',
379
- XS: 'extrasmall'
380
- };
381
- fontSize = keyValue[fontSize];
382
- const scale = (fontSize && this.fontSizeObj[fontSize]) || 1;
383
- const size = 10000;
384
- const value = Math.floor((100 / scale) * size) / size;
385
- return {
386
- width: `${value}%`,
387
- height: `${value}%`,
388
- transform: `scale(${scale})`
389
- };
390
- },
391
- handlePageClass() {
392
- if (this.type == 'customList' && !this.noBtn) return false;
393
- if (!this.noBtn && !this.hideBtn) return false;
394
- return true;
395
- },
396
- isShowItem() {
397
- return item => this.showEvent(item);
398
- },
399
- handleShowQuestionNumber() {
400
- return function (item) {
401
- let { type } = item || {};
402
- let tempTile = this.config?.autoQuestionNumber === false ? item.showTitle : `${item.softcode}、${item.showTitle}`;
403
- if (!this.isEvaluation(type)) return tempTile;
404
-
405
- let score = this.handleEvaluationScore(item);
406
- return `${tempTile}&nbsp;<span style="color:#2d7aff;">${score}</span>`;
407
- // if (this.noBtn) {
408
- // let score = this.handleEvaluationScore(item);
409
- // return `${tempTile}&nbsp;<span style="color:#2d7aff;">${score}</span>`;
410
- // }
411
- // if (!this.isLock) {
412
- // let score = this.handleEvaluationScore(item);
413
- // return `${tempTile}&nbsp;<span style="color:#2d7aff;">${score}</span>`;
414
- // }
415
- // if (item.questionScore !== undefined) {
416
- // return `${tempTile}&nbsp;<span style="color:#2d7aff;">(${item.questionScore}分)</span>`;
417
- // }
418
- // return tempTile;
419
- };
420
- },
421
- hasScore() {
422
- let { config } = this;
423
- if (!config || !Object.keys(config).length) return false;
424
- if ('totalScore' in config) return true;
425
- return false;
426
- },
427
- // 预览按钮打开的量表页面
428
- isPreviewScale() {
429
- let guage_id = this.ids?.guage_id;
430
- return guage_id && this.noBtn;
431
- },
432
- hasEvaluateSetting() {
433
- let { config } = this;
434
- if (!config || !Object.keys(config).length) return false;
435
- if ('evaluateResult' in config && config.evaluateResult) return true;
436
- return false;
437
- },
438
- getTimeValue() {
439
- return function (item) {
440
- let value = this.form[this.formKey(item)];
441
- return value;
442
- };
443
- },
444
- // 是否展示考试入口
445
- showEvaluateEntry() {
446
- // 非预览
447
- // 有evaluateResultSetting || url中含有固定参数
448
- // 倒计时未结束
449
- // 未填写过
450
- return !this.isPreviewScale && this.showEvaluatePage && this.showEvaluateSettingWrap && !this.isFinished && !this.noBtn && !this.hideBtn;
451
- },
452
- // 是否展示倒计时
453
- showEvaluateCoundownPage() {
454
- return !this.isPreviewScale && !this.showEvaluateEntry && this.showEvaluateCountdownWrap && !this.isFinished && !this.noBtn && !this.hideBtn;
455
- },
456
- // 是否设置 evaluateResultSetting
457
- hasEvaluateResultSetting() {
458
- let { evaluateResultSetting = {} } = this.config;
459
- // 读取优先级为测评设置值(变量) > URL参数 > 测评设置值(固定值)
460
- // 是否设置 evaluateResultSetting
461
- let valueArr =
462
- Object.values(evaluateResultSetting).filter(item => {
463
- if (item) return true;
464
- }) || [];
465
- return valueArr.length;
466
- },
467
- hasparamsEvaluate() {
468
- return this.paramsEvaluate && Object.keys(this.paramsEvaluate).length;
469
- },
470
- // url中是否有默认值
471
- hasDefault() {
472
- let hash = window.location.hash;
473
- let defaultVariable = ['evaname', 'evadesc', 'evast', 'evadur', 'evaan'];
474
- let hasDefault = defaultVariable.find(item => hash.includes(item));
475
- return this.paramsEvaluate || hasDefault;
476
- },
477
- // 是否有提交按钮
478
- showSaveBtn() {
479
- // 无测评设置 && url中无固定参数
480
- if (!this.hasEvaluateResultSetting && !this.hasDefault) {
481
- return !this.noBtn && !this.hideBtn;
482
- }
483
- return !this.noBtn && !this.hideBtn && !this.isFinished;
484
- },
485
- // 组件是否 Disable
486
- componentDisable() {
487
- // 无测评设置 && url中无固定参数
488
- if (!this.hasEvaluateResultSetting && !this.hasDefault) {
489
- return this.hideBtn || this.isLock;
490
- }
491
- return this.hideBtn || this.isLock || this.isFinished;
492
- },
493
- showEvaluateLabel() {
494
- return function (item) {
495
- let obj = {
496
- EVALUATE_RADIO_BLOCK: '单选题',
497
- EVALUATE_CHECKBOX_BLOCK: '多选题'
498
- };
499
- return obj[item.type];
500
- };
501
- },
502
- showAnswerParse() {
503
- return function (item) {
504
- let { evaluateAnswer, checkAnswerMode, evaluateStartTime, evaluateTime } = this.config?.evaluateResultSetting || {};
505
- let arr = ['EVALUATE_RADIO_BLOCK', 'EVALUATE_CHECKBOX_BLOCK', 'EVALUATE_SELECT', 'EVALUATE_INPUT'];
506
- let maxScore = item?.scoreConfigs || 0;
507
- let isShow = evaluateAnswer && this.isFinished && arr.includes(item.type) && maxScore;
508
- if (!evaluateStartTime || !evaluateTime || (checkAnswerMode && checkAnswerMode == 1)) return isShow;
509
- if (!vexutils.isValidDate(new Date(evaluateStartTime))) return isShow;
510
- // 答案解析时间 考试时间结束后
511
- let endTime = moment(evaluateStartTime).add(evaluateTime, 'minutes');
512
- let isRang = endTime.diff(moment(), 'seconds', true);
513
- return isShow && isRang <= 0;
514
- };
515
- },
516
- tipMsg() {
517
- return this.type === 'customList' ? '保存' : '提交';
518
- },
519
- formKey() {
520
- return function (item) {
521
- return item.databaseTitle || item.title;
522
- };
523
- },
524
- getEvaResColor() {
525
- let { evaluateResultConfig = [], totalScore } = this.config || {};
526
- totalScore = +totalScore || 0;
527
- if (!evaluateResultConfig?.length || !totalScore) return '#2474FF';
528
- let matchItem = evaluateResultConfig.find(item => item.startScore <= totalScore && totalScore <= item.endScore);
529
- if (!matchItem) return '#2474FF';
530
- return matchItem.color || '#2474FF';
531
- }
532
- },
533
- watch: {
534
- ids: {
535
- immediate: true,
536
- deep: true,
537
- handler(newVal, oldVal) {
538
- if (oldVal) {
539
- if (newVal.guage_id) {
540
- if (newVal.guage_id != oldVal.guage_id) {
541
- this.init(newVal);
542
- }
543
- }
544
- } else {
545
- if (newVal.guage_id) this.init(newVal);
546
- }
547
- }
548
- },
549
- guageData: {
550
- immediate: true,
551
- deep: true,
552
- handler(value) {
553
- if (value) {
554
- if (Object.keys(value || {}).length) {
555
- // guageForm打开 重新请求重置之前的答案
556
- this.form = {};
557
- this.formArray = [];
558
- const data = JSON.parse(JSON.stringify(value));
559
- this.$nextTick(() => {
560
- this.initForm(data);
561
- });
562
- }
563
- }
564
- }
565
- }
566
- },
567
- data() {
568
- return {
569
- other: '',
570
- form: {},
571
- submitForm: {},
572
- rules: {},
573
- config: {},
574
- formArray: [],
575
- mapVisible: false,
576
- mapLocation: '',
577
- labelSelectedList: [],
578
- defaultFormArray: [],
579
- fontSize: '',
580
- filterArr: ['SUCCESS_TIP', 'CALLBACK_INTERFACE', 'SPREAD_PARAMS', 'REDIRECT', 'FRONT_ADDRESS', 'RETURN_PATH'],
581
- spinning: true,
582
- indicator: <a-icon type="loading" style="font-size: 24px" spin />,
583
- totalScore: undefined,
584
- shareId: '',
585
- currentTime: moment(),
586
- showEvaluatePage: false,
587
- showEvaluateSettingWrap: true,
588
- showEvaluateCountdownWrap: false,
589
- showEvaluateCountdown: false,
590
- banSubmit: false,
591
- isFinished: false,
592
- maxScore: 0,
593
- originConfig: {},
594
- paramsEvaluate: null,
595
- hasFrontAddress: true,
596
- choiceComObj: {},
597
- evatipMap: {} // 维护一个tip map避免重复请求
598
- };
599
- },
600
- mounted() {
601
- this.handleQuery();
602
- if (this.noBtn) {
603
- // EventBus.$on("guageSubmit", this.onSubmit);
604
- }
605
- },
606
- beforeDestroy() {
607
- // EventBus.$off("guageSubmit");
608
- },
609
- methods: {
610
- init(configData) {
611
- this.spinning = true;
612
- try {
613
- this.resetNodata();
614
- this.initForm(configData);
615
- } catch (error) {
616
- this.spinning = false;
617
- this.hasFrontAddress = false;
618
- this.setNoData(true, error?.resultMsg, error?.result);
619
- }
620
- },
621
- handleQuery() {
622
- let { id } = this.$route.query;
623
- id && (this.shareId = id);
624
- },
625
- initForm(data) {
626
- let { list = [], map = {}, isFinished = false } = data;
627
- let curUrl = this.handleFrontAddress(list);
628
- if (curUrl) {
629
- window.location.href = curUrl;
630
- return;
631
- }
632
- map.maxScore && (this.maxScore = map.maxScore);
633
- this.isFinished = isFinished;
634
- if (data.isNotFilled) {
635
- this.spinning = false;
636
- this.hasFrontAddress = false;
637
- this.setNoData(true, '未查询到量表填写记录');
638
- return;
639
- }
640
- if (data.isLackCustomer) {
641
- let _this = this;
642
- // 校验用户环境
643
- this.$info({
644
- title: '已设置填写次数限制',
645
- content: '请在包含用户信息的环境中打开此量表',
646
- onOk() {
647
- _this.$emit('onCloseSetting');
648
- }
649
- });
650
- }
651
- this.config = map;
652
-
653
- if ('evaluateResultConfig' in map && utils.isJSON(map.evaluateResultConfig)) {
654
- this.config.evaluateResultConfig = JSON.parse(map.evaluateResultConfig);
655
- }
656
- if ('evaluateResultSetting' in map && utils.isJSON(map.evaluateResultSetting)) {
657
- this.config.evaluateResultSetting = JSON.parse(map.evaluateResultSetting);
658
- // 随机测评
659
- if (this.config?.randomId && this.config.evaluateResultSetting) {
660
- this.config.evaluateResultSetting.evaluateName = this.config.name;
661
- this.config.evaluateResultSetting.evaluateExplain = this.config.remark;
662
- }
663
- }
664
-
665
- this.originConfig = JSON.parse(JSON.stringify(this.config));
666
-
667
- if (this.params && Object.keys(this.params).length) {
668
- let res = this.handleBtnParamsEvaluate(this.params);
669
- res && Object.keys(res).length && (this.paramsEvaluate = res);
670
- }
671
-
672
- this.handleEvaluateParams(this.config.evaluateResultSetting);
673
- this.handleShowEvaluate();
674
-
675
- this.defaultFormArray = JSON.parse(JSON.stringify(list));
676
- let filterArr = this.filterArr;
677
- list = list.filter(v => !filterArr.includes(v.type));
678
- this.formArray = this.formatArray(list || []);
679
- this.form = this.defaultFormValue(this.formArray);
680
- this.rules = this.formatRules(this.formArray);
681
- this.fontSize = data.fontSize;
682
- this.spinning = false;
683
- this.hasFrontAddress = false;
684
- },
685
- handleFrontAddress(list) {
686
- if (!list || !list.length) return;
687
- let matchItem = list.find(item => item.type === 'FRONT_ADDRESS');
688
- if (!matchItem || !Object.keys(matchItem).length) return;
689
- let setting;
690
- if (matchItem.setting && utils.isJSON(matchItem.setting)) {
691
- setting = JSON.parse(matchItem.setting);
692
- }
693
- if (!setting || !Object.keys(setting).length) return;
694
- let query = this.handleQueryParams();
695
- // redirect=1 代表从前置地址跳转回来了
696
- if (query?.redirect == 1) return;
697
- let { frontAddress } = setting;
698
- if (frontAddress) {
699
- let urlHref = window.location.href;
700
- let preStr = '?';
701
- if (frontAddress.includes('?')) {
702
- preStr = '&';
703
- }
704
- let curUrl = `${frontAddress}${preStr}redirect_url=${encodeURIComponent(urlHref)}`;
705
- return curUrl;
706
- }
707
- },
708
- handleBtnParamsEvaluate(params) {
709
- let defaultVariable = ['evaname', 'evadesc', 'evast', 'evadur', 'evaan'];
710
- let res = {};
711
- for (let key in params) {
712
- let value = params[key];
713
- if (defaultVariable.includes(key) && value) {
714
- res[key] = value;
715
- }
716
- }
717
- return res;
718
- },
719
- /** *
720
- * 解析测评参数
721
- */
722
- handleEvaluateParams(evaluateResultSetting) {
723
- if (!evaluateResultSetting || !Object.keys(evaluateResultSetting).length) return;
724
- // 分享测评量表链接URL支持传入测评名称-evaname 测评说明-evadesc 测评时间-evast 测评时长-evadur 固定参数
725
- let query = this.handleQueryParams();
726
- // 按钮传参
727
- if (this.hasparamsEvaluate) {
728
- query = this.paramsEvaluate;
729
- }
730
- let obj = {
731
- evaluateName: 'evaname',
732
- evaluateExplain: 'evadesc',
733
- evaluateStartTime: 'evast',
734
- evaluateTime: 'evadur',
735
- evaluateAnswer: 'evaan'
736
- };
737
- for (let key in evaluateResultSetting) {
738
- let value = evaluateResultSetting[key];
739
- let isParseKey = value && key != 'evaluateAnswer' && typeof value === 'string' && value.includes('${');
740
- if (isParseKey) {
741
- let parseValue = value.replace(/\$\{([^}]+)\}/g, (_v, $1) => {
742
- let param;
743
- if ($1.startsWith('form.')) {
744
- param = query[$1.split('.')[1]];
745
- }
746
- return param || '';
747
- });
748
- this.$set(evaluateResultSetting, key, parseValue);
749
- } else {
750
- let val = query[obj[key]];
751
- if (key == 'evaluateAnswer') {
752
- val = val === 'true' || val == 1 ? true : false;
753
- }
754
- query[obj[key]] && this.$set(evaluateResultSetting, key, val);
755
- }
756
- }
757
- // 部分evaluateResultSetting 但是却有url
758
- if (this.hasDefault) {
759
- let defaultVariable = ['evaname', 'evadesc', 'evast', 'evadur', 'evaan'];
760
- let defObj = {
761
- evaname: 'evaluateName',
762
- evadesc: 'evaluateExplain',
763
- evast: 'evaluateStartTime',
764
- evadur: 'evaluateTime',
765
- evaan: 'evaluateAnswer'
766
- };
767
- defaultVariable.forEach(item => {
768
- let key = defObj[item];
769
- if (!evaluateResultSetting[key]) {
770
- let val = query[item];
771
- if (item == 'evaan') {
772
- val = val === 'true' || val == 1 ? true : false;
773
- }
774
- query[item] && this.$set(evaluateResultSetting, key, val);
775
- }
776
- });
777
- }
778
- this.setEvaluateStartTime(evaluateResultSetting);
779
- },
780
- handleQueryParams() {
781
- let params = {};
782
- for (let [key, value] of new URLSearchParams(window.location.hash.split('?')[1]).entries()) {
783
- params[key] = decodeURIComponent(value);
784
- }
785
- return params;
786
- },
787
- handleShowEvaluate() {
788
- // 读取优先级为测评设置值(变量) > URL参数 > 测评设置值(固定值)
789
- // 无 evaluateResultSetting
790
- if (!this.hasEvaluateResultSetting) {
791
- // url中是否有默认值
792
- // 无默认值 不显示考试入口页面
793
- if (!this.hasDefault) return false;
794
- // 有默认值 显示考试入口页面
795
- if (!('evaluateResultSetting' in this.config)) {
796
- this.$set(this.config, 'evaluateResultSetting', {});
797
- }
798
- this.setDefaultEvaluate(this.config.evaluateResultSetting);
799
- this.showEvaluatePage = true;
800
- this.showEvaluateCountdownWrap = true;
801
- return;
802
- }
803
-
804
- let { evaluateResultSetting = {} } = this.config;
805
- if (!evaluateResultSetting || !Object.keys(evaluateResultSetting).length) return;
806
- this.showEvaluateCountdownWrap = true;
807
-
808
- // 只要有开始时间都显示测评组件
809
- let { evaluateStartTime } = evaluateResultSetting;
810
- let { evaluateName } = this.originConfig?.evaluateResultSetting || {};
811
- // 未设置开始时间 一直可以填写
812
- if (!evaluateStartTime) {
813
- this.showEvaluatePage = true;
814
- return;
815
- }
816
- if (!vexutils.isValidDate(new Date(evaluateStartTime))) {
817
- if (!evaluateName) return false;
818
- }
819
- this.showEvaluatePage = true;
820
- },
821
- setDefaultEvaluate(evaluateResultSetting) {
822
- let query = this.handleQueryParams();
823
- // 按钮传参
824
- if (this.hasparamsEvaluate) {
825
- query = this.paramsEvaluate;
826
- }
827
- if (query.evaname) {
828
- this.$set(evaluateResultSetting, 'evaluateName', query.evaname);
829
- }
830
- if (query.evadesc) {
831
- this.$set(evaluateResultSetting, 'evaluateExplain', query.evadesc);
832
- }
833
- if (query.evast) {
834
- this.$set(evaluateResultSetting, 'evaluateStartTime', query.evast);
835
- }
836
- if (query.evadur) {
837
- this.$set(evaluateResultSetting, 'evaluateTime', query.evadur);
838
- }
839
- if (query.evaan) {
840
- let evaan = query.evaan === 'true' || query.evaan == 1 ? true : false;
841
- this.$set(evaluateResultSetting, 'evaluateAnswer', evaan);
842
- }
843
-
844
- this.setEvaluateStartTime(evaluateResultSetting);
845
- },
846
- // 时间戳需要是数字
847
- setEvaluateStartTime(evaluateResultSetting) {
848
- let evaluateStartTime = evaluateResultSetting?.evaluateStartTime;
849
- if (!evaluateStartTime) return;
850
- if (!vexutils.isValidDate(new Date(evaluateStartTime)) && vexutils.isValidDate(new Date(Number(evaluateStartTime)))) {
851
- evaluateResultSetting.evaluateStartTime = Number(evaluateStartTime);
852
- }
853
- },
854
- // 量表提交数据
855
- defaultFormValue(formArray) {
856
- const formData = {};
857
- let val;
858
- formArray.forEach(item => {
859
- const key = this.formKey(item);
860
- const { type } = item;
861
- let defValue;
862
- if (item.dbValue) {
863
- defValue = item.dbValue;
864
- } else {
865
- if (item.setting?.defValType == 3) {
866
- let urlKey = item.setting?.outDefaultValue?.urlKey;
867
- if (urlKey) {
868
- let list = urlKey.split(',');
869
- if (list.length > 1) {
870
- let val = list
871
- .map(l => {
872
- let tempV = this.getQueryVariable(l);
873
- if (tempV) return decodeURIComponent(tempV);
874
- return null;
875
- })
876
- .filter(Boolean);
877
- val.length && (defValue = val);
878
- } else {
879
- let val = this.getQueryVariable(list[0]);
880
- if (val) {
881
- val = decodeURIComponent(val);
882
- defValue = item.type == 'CHECKBOX_BLOCK' ? val.split() : val;
883
- }
884
- }
885
- }
886
- }
887
- }
888
- switch (type) {
889
- case 'LOCATION':
890
- formData[key] = defValue || '';
891
- break;
892
- case 'SEARCH_CASCADE':
893
- formData[key] = defValue || [];
894
- break;
895
- case 'ADDRESS':
896
- formData[key] = defValue || '';
897
- this.defaultAddress = defValue || {};
898
- break;
899
- case 'LABEL':
900
- formData[key] = defValue || {};
901
- if (vexutils.isObject(defValue)) {
902
- this.labelSelectedList = defValue?.labels || [];
903
- } else if (Array.isArray(defValue)) {
904
- this.labelSelectedList = defValue;
905
- } else {
906
- this.labelSelectedList = [];
907
- }
908
- break;
909
- case 'TITLE':
910
- formData[key] = item.title;
911
- break;
912
- case 'IMGCARD':
913
- formData[key] = item.setting?.imgUrl || '';
914
- break;
915
- case 'UPFILE':
916
- case 'UPPICTURE':
917
- formData[key] = defValue || [];
918
- break;
919
- // 自定义列表特殊处理
920
- case 'CHECKBOX_BLOCK':
921
- if (defValue && !Array.isArray(defValue) && this.type === 'customList') {
922
- formData[key] = defValue.split(',').filter(ii => !!ii);
923
- } else {
924
- val = defValue || item.setting.defaultValue;
925
- if (vexutils.isJSON(val)) {
926
- val = JSON.parse(val);
927
- }
928
- formData[key] = val;
929
- }
930
- break;
931
- default:
932
- val = defValue || item.setting.defaultValue;
933
- if (vexutils.isJSON(val)) {
934
- val = JSON.parse(val);
935
- }
936
- formData[key] = val;
937
- break;
938
- }
939
- });
940
- return formData;
941
- },
942
- // 解析传参组件
943
- compileSpreadParams(spreadParams) {
944
- return spreadParams.domains.map(v => {
945
- let obj = {};
946
- if (v.valueType == '1') {
947
- obj[v.name] = v.value;
948
- } else if (v.valueType == '2') {
949
- obj[v.name] = this.getQueryVariable(v.value);
950
- }
951
- return obj;
952
- });
953
- },
954
- // 获取url链接参数
955
- getQueryVariable(variable) {
956
- let query = {};
957
- if (this.source == 'layout') {
958
- // 按钮传参
959
- query = this.params;
960
- } else {
961
- query = this.handleQueryParams() || {};
962
- }
963
- if (!query) return false;
964
- return query[variable] || false;
965
- },
966
- // 初始化量表
967
- formatArray(list) {
968
- let i = 1;
969
- const results = list.map(item => {
970
- const key = this.formKey(item);
971
- let title = (key || '').replace(/\n/g, '');
972
- this.$set(item, 'showTitle', item.title);
973
- // 表单校验rule prop如果有 . 会报错, 替换成 ~-~
974
- if (title.includes('.')) {
975
- let newTitle = title.replace(/\./g, '~-~');
976
- this.$set(item, 'title', newTitle);
977
- }
978
- this.$set(item, 'isShow', true);
979
- Object.keys(item).forEach(key => {
980
- if (utils.isJSON(item[key])) {
981
- if (item.type != 'LOCATION') {
982
- item[key] = JSON.parse(item[key]);
983
- }
984
- }
985
- });
986
- const notIndexArr = ['LINEBAR', 'TITLE', 'PROMPT', 'IMGCARD', 'RICH_TEXT'];
987
- if (notIndexArr.indexOf(item.type) < 0 && !item.hide) {
988
- this.$set(item, 'softcode', i++);
989
- }
990
-
991
- // "RADIO_BLOCK", "CHECKBOX_BLOCK" 将取值value改为key
992
- if (this.isChoice(item.type)) {
993
- this.handleFormatOptions(item.options, item.type);
994
- if (item.type != 'SEARCH_CASCADE') {
995
- if (item.dbValue) {
996
- this.nextLogicEvent(item.dbValue, item, results, true);
997
- } else {
998
- if (item.setting.defaultValue) {
999
- this.nextLogicEvent(item.setting.defaultValue, item, results, true);
1000
- }
1001
- }
1002
- }
1003
- }
1004
- return item;
1005
- });
1006
- return results.map(item => {
1007
- // 题目关联
1008
- let relationLogicObj = utils.isString(item.relationLogic) ? JSON.parse(item.relationLogic) : item.relationLogic;
1009
- this.handleRelationLogic(list, relationLogicObj);
1010
-
1011
- // 跳题逻辑
1012
- this.handLenextLogic(item);
1013
-
1014
- // 自定义列表特殊处理
1015
- if (item.type === 'CHECKBOX_BLOCK' && item.dbValue && !Array.isArray(item.dbValue) && this.type === 'customList') {
1016
- item.dbValue = item.dbValue.split(',').filter(ii => !!ii);
1017
- }
1018
- return item;
1019
- });
1020
- },
1021
- /**
1022
- * "RADIO_BLOCK", "CHECKBOX_BLOCK" 将取值value改为key, relationLogic需要重新处理
1023
- */
1024
- handleRelationLogic(list, relationLogicObj) {
1025
- let { condition } = relationLogicObj || {};
1026
- if (!condition || !condition.length) return;
1027
- condition.forEach(c => {
1028
- let matchItem = list.find(f => f.seq == c.subject_seq);
1029
- if (!matchItem) return;
1030
- let isChoice = this.isRadioOrCheckBox(matchItem.options, matchItem.type);
1031
- if (!isChoice) return;
1032
- let value = c.value;
1033
- if (Array.isArray(value)) {
1034
- value = value.map(v => {
1035
- return this.replaceConditionItem(matchItem.options, v);
1036
- });
1037
- c.value = value;
1038
- } else {
1039
- c.value = this.replaceConditionItem(matchItem.options, value);
1040
- }
1041
- });
1042
- },
1043
- /**
1044
- * "RADIO_BLOCK", "CHECKBOX_BLOCK" 将取值value改为key, nextLogic需要重新处理
1045
- */
1046
- handLenextLogic(item) {
1047
- let { nextLogic, options, type } = item || {};
1048
- let isChoice = this.isRadioOrCheckBox(options, type);
1049
- if (!nextLogic || !isChoice) return;
1050
- let { condition } = nextLogic || {};
1051
- if (!condition || !condition.length) return;
1052
- condition.forEach(c => {
1053
- let value = c.value;
1054
- if (Array.isArray(value)) {
1055
- value = value.map(v => {
1056
- return this.replaceConditionItem(options, v);
1057
- });
1058
- c.value = value;
1059
- } else {
1060
- c.value = this.replaceConditionItem(options, value);
1061
- }
1062
- });
1063
- },
1064
- replaceConditionItem(options, value) {
1065
- let matchOption = options.find(v => value === v.value);
1066
- if (!matchOption) return value;
1067
- return matchOption.key;
1068
- },
1069
- isRadioOrCheckBox(options, type) {
1070
- let typeArr = ['RADIO_BLOCK', 'CHECKBOX_BLOCK'];
1071
- if (!typeArr.includes(type)) return;
1072
- if (!options) return;
1073
- if (options && utils.isJSON(options)) {
1074
- options = JSON.parse(options);
1075
- }
1076
- if (!options.length) return;
1077
- return true;
1078
- },
1079
- handleFormatOptions(options, type) {
1080
- let isChoice = this.isRadioOrCheckBox(options, type);
1081
- if (!isChoice) return;
1082
-
1083
- options.forEach((item, i) => {
1084
- if (item.key !== 'other') {
1085
- item.key = i + 1;
1086
- }
1087
- if (item.prefix || item.suffix) {
1088
- item.value = item.prefix || item.suffix;
1089
- }
1090
- });
1091
- },
1092
- // 初始化rules
1093
- formatRules(formArray) {
1094
- const rules = {};
1095
- formArray.forEach(item => {
1096
- let newTitle = this.formKey(item);
1097
- // 表单校验rule prop如果有 . 会报错, 替换成 ~-~
1098
- if (newTitle.includes('.')) {
1099
- newTitle = newTitle.replace(/\./g, '~-~');
1100
- }
1101
- rules[newTitle] = [{ required: item.required, message: '必填', trigger: 'change' }];
1102
- if (item.type == 'MOBILE' && item.validation) {
1103
- rules[newTitle].push({
1104
- pattern: /^1[3456789]\d{9}$/,
1105
- message: '格式错误',
1106
- trigger: 'blur'
1107
- });
1108
- } else if (item.type == 'ID_CARD' && item.validation) {
1109
- rules[newTitle].push({
1110
- pattern: /^\d{6}(((19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{3}([0-9]|x|X))|(\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{3}))$/,
1111
- message: '格式错误',
1112
- trigger: 'blur'
1113
- });
1114
- } else if (item.type == 'ADDRESS' && item.required) {
1115
- if (this.handleAddressType(item)) {
1116
- rules[newTitle].push({
1117
- validator: this.checkAdress,
1118
- trigger: 'change'
1119
- });
1120
- }
1121
- } else if (item.type == 'LABEL' && item.required) {
1122
- rules[newTitle].push({
1123
- validator: this.checkLabel,
1124
- trigger: 'change'
1125
- });
1126
- } else if (item.type == 'DATETIME' && this.type == 'customList') {
1127
- // 自定义列表特殊处理日期时间 最大值
1128
- // dateMaxType 1当前日期时间 2指定日期时间 3其他日期时间字段
1129
- let dateMaxType = this.handleDateMaxType(item);
1130
- if (!dateMaxType) return;
1131
- let obj = {
1132
- 1: 'checkDateMaxCur',
1133
- 2: 'checkDateMaxSet',
1134
- 3: 'checkDateMaxOther'
1135
- };
1136
- let methodName = obj[dateMaxType];
1137
- rules[newTitle].push({
1138
- validator: (rule, value, callback) => this[methodName](rule, value, callback, item),
1139
- trigger: 'change'
1140
- });
1141
- } else if (item.type === 'RADIO_BLOCK') {
1142
- this.choiceComObj[this.formKey(item)] = {};
1143
- rules[newTitle].push({
1144
- validator: (rule, value, callback) => this.checkRadio(rule, value, callback, item),
1145
- trigger: 'change'
1146
- });
1147
- } else if (item.type === 'CHECKBOX_BLOCK') {
1148
- this.choiceComObj[this.formKey(item)] = {};
1149
- rules[newTitle].push({
1150
- validator: (rule, value, callback) => this.checkCheckbox(rule, value, callback, item),
1151
- trigger: 'change'
1152
- });
1153
- }
1154
- });
1155
- return rules;
1156
- },
1157
- handleAddressType(item) {
1158
- let setObj = { addressType: 'province-city-district-address' };
1159
- if (utils.isJSON(item.setting)) {
1160
- setObj = JSON.parse(item.setting);
1161
- } else {
1162
- setObj = item.setting;
1163
- }
1164
- let isAdress = setObj.addressType.includes('address');
1165
- return isAdress;
1166
- },
1167
- checkAdress(rule, value, callback) {
1168
- let { address } = value || {};
1169
- if (!address) {
1170
- return callback(new Error('必填'));
1171
- }
1172
- callback();
1173
- },
1174
- checkLabel(rule, value, callback) {
1175
- if (!value || !Object.keys(value).length) {
1176
- return callback(new Error('必填'));
1177
- }
1178
- let { labelStr, labels = [] } = value;
1179
- if (!labelStr || !labels.length) {
1180
- return callback(new Error('必填'));
1181
- }
1182
- callback();
1183
- },
1184
- handleDateMaxType(item) {
1185
- let setObj = item.setting;
1186
- if (utils.isJSON(setObj)) {
1187
- setObj = JSON.parse(setObj);
1188
- }
1189
- return setObj.dateMaxType;
1190
- },
1191
- // 自定义列表 日期时间 max 当前日期时间
1192
- checkDateMaxCur(rule, value, callback, item) {
1193
- if (!value) return callback();
1194
- let { dateType } = item.setting;
1195
- if (!dateType) return callback();
1196
- let dateMaxValue = this.currentTime;
1197
- if (dateType == 'time') {
1198
- dateMaxValue = this.currentTime.format('HH:mm:ss');
1199
- }
1200
- let isMax = this.handleMax(dateType, value, dateMaxValue);
1201
- if (!isMax) {
1202
- return callback(new Error('最大不能超过当前日期时间'));
1203
- }
1204
- callback();
1205
- },
1206
- // 自定义列表 日期时间 max 指定日期时间
1207
- checkDateMaxSet(rule, value, callback, item) {
1208
- if (!value) return callback();
1209
- let { dateMaxValue, dateType } = item.setting;
1210
- if (!dateMaxValue || !dateType) return callback();
1211
- let isMax = this.handleMax(dateType, value, dateMaxValue);
1212
- if (!isMax) {
1213
- return callback(new Error('最大不能超过指定日期时间'));
1214
- }
1215
- callback();
1216
- },
1217
- // 自定义列表 日期时间 max 其他日期时间字段
1218
- checkDateMaxOther(rule, value, callback, item) {
1219
- if (!value) return callback();
1220
- let { outDateMaxValue, dateType } = item.setting;
1221
- if (!outDateMaxValue || !dateType) return callback();
1222
- let matchDateItem = this.formArray.find(v => v.seq === outDateMaxValue);
1223
- if (!matchDateItem || matchDateItem.hide) return callback();
1224
- let matchValue = this.form[this.formKey(matchDateItem)];
1225
- if (!matchValue) return;
1226
- let isMax = this.handleMax(dateType, value, matchValue);
1227
- if (!isMax) {
1228
- return callback(new Error(`最大不能超过【${matchDateItem.title}】日期时间`));
1229
- }
1230
- callback();
1231
- },
1232
- checkRadio(rule, value, callback, item) {
1233
- if (!value) return callback();
1234
- let { options } = item;
1235
- if (!options.length || value === 'other') return callback();
1236
- const key = this.formKey(item);
1237
- let { optionsPreSuffixObj = {} } = this.choiceComObj[key] || {};
1238
- let matchItem = options.find((o, i) => {
1239
- if (i + 1 === value) {
1240
- return true;
1241
- }
1242
- return false;
1243
- });
1244
- if (!matchItem || matchItem.importability) return callback();
1245
- if (matchItem.prefix || matchItem.suffix) {
1246
- let inputValue = optionsPreSuffixObj[value];
1247
- if (!inputValue) {
1248
- return callback(new Error(`请完善选项`));
1249
- }
1250
- }
1251
- callback();
1252
- },
1253
- checkCheckbox(rule, value, callback, item) {
1254
- if (!value || !value.length) return callback();
1255
- let { options } = item;
1256
- if (!options.length) return callback();
1257
- let i = 0,
1258
- len = value.length,
1259
- v;
1260
- const key = this.formKey(item);
1261
- let { optionsPreSuffixObj = {} } = this.choiceComObj[key] || {};
1262
- for (; i < len; i++) {
1263
- v = value[i];
1264
- if (v === 'other') continue;
1265
- let matchItem = options.find((o, j) => {
1266
- if (j + 1 === v) {
1267
- return true;
1268
- }
1269
- return false;
1270
- });
1271
- if (!matchItem || matchItem.importability) continue;
1272
-
1273
- if (matchItem.prefix || matchItem.suffix) {
1274
- let inputValue = optionsPreSuffixObj[v];
1275
- if (!inputValue) {
1276
- return callback(new Error(`请完善选项`));
1277
- }
1278
- }
1279
- }
1280
- callback();
1281
- },
1282
- handleMax(dateType, value, dateMaxValue) {
1283
- let curValue = '';
1284
- let tempValue = '';
1285
- if (dateType == 'time') {
1286
- let curYMD = this.currentTime.format('YYYY MM DD ');
1287
- curValue = moment(curYMD + dateMaxValue).valueOf();
1288
- tempValue = moment(curYMD + value).valueOf();
1289
- } else if (dateType == 'date') {
1290
- curValue = moment(dateMaxValue).valueOf();
1291
- tempValue = moment(value).valueOf();
1292
- } else {
1293
- curValue = moment(dateMaxValue).valueOf();
1294
- tempValue = moment(value).valueOf();
1295
- }
1296
- if (tempValue > curValue) {
1297
- return false;
1298
- }
1299
- return true;
1300
- },
1301
- handleGetAddress(val) {
1302
- if (utils.isJSON(val)) {
1303
- const valObj = JSON.parse(val);
1304
- return valObj.address || valObj.name;
1305
- }
1306
- return '';
1307
- },
1308
- handleSelectLocation(e, item) {
1309
- const { locationProp, isInit } = e;
1310
- this.mapLocation = locationProp;
1311
- const key = this.formKey(item);
1312
- this.form[key] = locationProp;
1313
- this.mapVisible = isInit || false;
1314
- },
1315
- isInput(type) {
1316
- return type == 'INPUT' || type == 'ID_CARD' || type == 'MOBILE' || type == 'EVALUATE_INPUT';
1317
- },
1318
- isChoice(type) {
1319
- return (
1320
- type == 'SELECT' ||
1321
- type == 'RADIO_BLOCK' ||
1322
- type == 'CHECKBOX_BLOCK' ||
1323
- type == 'SEARCH_CASCADE' ||
1324
- type == 'EVALUATE_RADIO_BLOCK' ||
1325
- type == 'EVALUATE_CHECKBOX_BLOCK' ||
1326
- type == 'EVALUATE_SELECT'
1327
- );
1328
- },
1329
- isTime(type) {
1330
- return type == 'DATE' || type == 'TIME' || type == 'DATETIME';
1331
- },
1332
- isUpload(type) {
1333
- return type == 'UPFILE' || type == 'UPPICTURE';
1334
- },
1335
- writeGuage(showCountdown) {
1336
- this.showEvaluateSettingWrap = false;
1337
- this.showEvaluateCountdown = showCountdown;
1338
- },
1339
- closeEvaluateCountdown() {
1340
- // 倒计时结束自动提交 无需校验
1341
- this.showEvaluateCountdown = false;
1342
- if (this.isPreviewScale) return;
1343
- this.banSubmit = true;
1344
- this.submitMethod();
1345
- this.$warning({
1346
- title: '温馨提示',
1347
- content: '测评时间到了,结束测评!',
1348
- okText: '确定',
1349
- onOk: () => {}
1350
- });
1351
- },
1352
- async showEvaTipModal(item) {
1353
- if (this.evatipMap[item.id]) {
1354
- this.evatipConfirm(this.evatipMap[item.id]);
1355
- return;
1356
- }
1357
- let key = 'getSubjectAnswer';
1358
- const fn = this.scaleApiConfig?.[key] || null;
1359
- if (!fn || typeof fn !== 'function') {
1360
- this.$message.error(`${key} Is not a function`);
1361
- return;
1362
- }
1363
- let obj = await fn(item.id);
1364
- if (!obj) return;
1365
- if (!this.evatipMap[item.id]) {
1366
- this.evatipMap[item.id] = obj;
1367
- this.evatipConfirm(obj);
1368
- }
1369
- },
1370
- closeTip() {
1371
- this.$destroyAll();
1372
- },
1373
- evatipConfirm(str) {
1374
- let _this = this;
1375
- let content = h => (
1376
- <div class="evatip-container">
1377
- <a-icon type="close" class="tip-content-close" on-click={_this.closeTip} />
1378
- <span>答案解析:</span>
1379
- <p>{str}</p>
1380
- </div>
1381
- );
1382
- this.$confirm({
1383
- title: '提示',
1384
- icon: () => null,
1385
- content,
1386
- okText: '确定',
1387
- cancelText: '关闭',
1388
- onOk() {},
1389
- onCancel() {},
1390
- class: 'evatip-modal-wrap'
1391
- });
1392
- },
1393
- // 选择组件
1394
- handleChoice(choiceValue, formItem) {
1395
- let { value = '', list = [] } = choiceValue;
1396
- this.nextLogicEvent(value, formItem, this.formArray);
1397
- this.handleDynamicDataRelation(list, formItem, this.formArray);
1398
- },
1399
- // 下拉框 动态数据源关联字段
1400
- handleDynamicDataRelation(list, formItem, formArray) {
1401
- let { targetSource } = formItem;
1402
- if (!targetSource || !Object.keys(targetSource).length) return;
1403
- if (!targetSource.target_id) return;
1404
- let { relationParam = [] } = targetSource;
1405
- if (!relationParam.length) return;
1406
- relationParam.forEach(item => {
1407
- let matchEle = formArray.find(v => v.seq === item.relationElement);
1408
- const key = this.formKey(matchEle);
1409
- if (matchEle) {
1410
- if (!list.length) {
1411
- this.form[key] = '';
1412
- } else {
1413
- let relationFieldList = list.map(v => v[item.relationField] || '/') || '';
1414
- this.form[key] = relationFieldList.join(',');
1415
- }
1416
- }
1417
- });
1418
- },
1419
- // 设置的logic condition 最大next_subject
1420
- handleLogicMaxNext(condition = []) {
1421
- const arr = condition.map(({ next_subject }) => (next_subject == 'end' ? 9999 : +(next_subject || 9999)));
1422
- const max = Math.max.call(null, ...arr);
1423
- return max;
1424
- },
1425
- // 当前formItem 下一个触发logicCodition item 的seq
1426
- handleLogicList(formItem, formArray) {
1427
- const { seq } = formItem;
1428
- let list = formArray.map(item => {
1429
- if (item.seq > seq && item.isShow && item.__isLogic__) return item;
1430
- return false;
1431
- });
1432
- let nextItemMax = 0;
1433
- let i = 0,
1434
- len = list.length,
1435
- item;
1436
- for (; i < len; i++) {
1437
- item = list[i];
1438
- let curVal = this.form[this.formKey(item)];
1439
- if (!curVal) continue;
1440
- if (Array.isArray(curVal)) {
1441
- if (!curVal.length) continue;
1442
- }
1443
- const { nextLogic, seq, __isLogic__, __lastSeq__ } = item;
1444
- if (!nextLogic.next_logic_is || !nextLogic.condition.length) continue;
1445
- if (__lastSeq__) {
1446
- nextItemMax = __lastSeq__;
1447
- break;
1448
- }
1449
- }
1450
- return nextItemMax;
1451
- },
1452
- // 跳题逻辑
1453
- nextLogicEvent(choiceValue, formItem, formArray = [], isInit) {
1454
- const { nextLogic, seq } = formItem;
1455
- if (!nextLogic) return;
1456
- if (nextLogic.next_logic_is && nextLogic.condition.length) {
1457
- let nextMax = 9999,
1458
- nextItemMax = 0;
1459
- if (!isInit) {
1460
- nextMax = this.handleLogicMaxNext(nextLogic.condition);
1461
- nextItemMax = this.handleLogicList(formItem, formArray);
1462
- }
1463
- nextLogic.condition.some(con => {
1464
- const { value, next_subject } = con;
1465
- const lastSeq = next_subject == 'end' ? 9999 : next_subject;
1466
- if (nextItemMax && nextItemMax > seq && nextItemMax < nextMax) {
1467
- nextMax = nextItemMax;
1468
- }
1469
- if (nextLogic.next_logic == 'condition') {
1470
- let hasValue = false;
1471
- if (Array.isArray(choiceValue)) {
1472
- hasValue = choiceValue.includes(value);
1473
- } else {
1474
- hasValue = choiceValue === value;
1475
- }
1476
-
1477
- // 添加非响应式key __isLogic__ __lastSeq__
1478
- Object.defineProperty(formItem, '__isLogic__', {
1479
- value: hasValue,
1480
- writable: true
1481
- });
1482
- Object.defineProperty(formItem, '__lastSeq__', {
1483
- value: seq + 1,
1484
- writable: true
1485
- });
1486
-
1487
- if (hasValue) {
1488
- formArray.forEach(item => {
1489
- if (item.seq > seq && item.seq < lastSeq) {
1490
- item.isShow = false;
1491
- // 跳过时 清空已填内容
1492
- const key = this.formKey(item);
1493
- this.form[key] && (this.form[key] = '');
1494
- } else if (item.seq >= lastSeq && item.seq < nextMax) {
1495
- this.$set(item, 'isShow', true);
1496
- }
1497
- });
1498
- return true;
1499
- } else {
1500
- formArray.forEach(item => {
1501
- if (item.seq > seq && item.seq < lastSeq) {
1502
- item.isShow = true;
1503
- }
1504
- });
1505
- }
1506
- } else if (nextLogic.next_logic == 'uncondition') {
1507
- let res = utils.isEmpty(choiceValue);
1508
-
1509
- // 添加非响应式key __isLogic__ __lastSeq__
1510
- Object.defineProperty(formItem, '__isLogic__', {
1511
- value: !res,
1512
- writable: true
1513
- });
1514
- Object.defineProperty(formItem, '__lastSeq__', {
1515
- value: seq + 1,
1516
- writable: true
1517
- });
1518
-
1519
- formArray.forEach(item => {
1520
- const key = this.formKey(item);
1521
- if (item.seq > seq && item.seq < lastSeq) {
1522
- item.isShow = res;
1523
- // 跳过时 清空已填内容
1524
- if (!res) {
1525
- this.form[key] && (this.form[key] = '');
1526
- }
1527
- }
1528
- });
1529
- }
1530
- });
1531
- }
1532
- },
1533
- // 关联逻辑
1534
- showEvent(formItem, isSubmitCallback) {
1535
- if (formItem.hide) return false;
1536
- const { form } = this;
1537
- let relationLogicObj = {};
1538
- // 回调接口
1539
- if (isSubmitCallback) {
1540
- let setting = formItem.setting;
1541
- if (formItem.setting && utils.isJSON(formItem.setting)) {
1542
- setting = JSON.parse(formItem.setting);
1543
- }
1544
- relationLogicObj = utils.isString(setting.callbackCondition) ? JSON.parse(setting.callbackCondition) : setting.callbackCondition;
1545
- if (!relationLogicObj || !relationLogicObj.condition || !relationLogicObj.condition.length) return true;
1546
- } else {
1547
- relationLogicObj = utils.isString(formItem.relationLogic) ? JSON.parse(formItem.relationLogic) : formItem.relationLogic;
1548
- }
1549
- if (!relationLogicObj || !Object.keys(relationLogicObj).length) return true;
1550
- const { relation_logic_is, condition, relation_logic } = relationLogicObj;
1551
- if (relation_logic_is) {
1552
- const results = condition.map(c => {
1553
- let key = this.formKey(this.formArray.filter(f => f.seq == c.subject_seq)[0]);
1554
- if (utils.isArray(form[key])) {
1555
- return form[key].some(v => c.value.includes(v));
1556
- } else {
1557
- return c.value.includes(form[key]);
1558
- }
1559
- });
1560
- if (relation_logic == 'OR') {
1561
- formItem.isShow = results.some(el => el);
1562
- } else if (relation_logic == 'AND') {
1563
- formItem.isShow = results.every(el => el);
1564
- } else {
1565
- formItem.isShow = results[0];
1566
- }
1567
- }
1568
- return formItem.isShow;
1569
- },
1570
- // 单选组件回调
1571
- radioChange(val, item, obj) {
1572
- const key = this.formKey(item);
1573
- this.form[key] = val;
1574
- item.type === 'RADIO_BLOCK' && this.$set(this.choiceComObj, key, obj);
1575
- this.nextLogicEvent(val, item, this.formArray);
1576
- },
1577
- // 多选组件回调
1578
- checkboxChange(val, item, obj) {
1579
- const key = this.formKey(item);
1580
- this.form[key] = val;
1581
- item.type === 'CHECKBOX_BLOCK' && this.$set(this.choiceComObj, key, obj);
1582
- this.nextLogicEvent(val, item, this.formArray);
1583
- },
1584
- // 标签组件回调
1585
- labelChange(labelList, item) {
1586
- const key = this.formKey(item);
1587
- this.form[key] = this.handleGetLabelSubmit(labelList);
1588
- },
1589
- // 视频组件回调
1590
- vodFileList(list, item) {
1591
- const key = this.formKey(item);
1592
- this.form[key] = list;
1593
- },
1594
- handleGetLabelSubmit(labelSelectedList) {
1595
- if (!labelSelectedList || !labelSelectedList.length)
1596
- return {
1597
- labelStr: '',
1598
- labels: []
1599
- };
1600
- const selectedList = labelSelectedList || [];
1601
- const labelStrList = [];
1602
- const labels = [];
1603
- // "cacheKey":"label_标签","isSelect":true
1604
- selectedList.forEach(v => {
1605
- labels.push(v);
1606
- labelStrList.push(v.labelName);
1607
- });
1608
- this.labelSelectedList = selectedList;
1609
- return {
1610
- labelStr: labelStrList.join(','),
1611
- labels: labels
1612
- };
1613
- },
1614
- // 地址回调
1615
- changeAddress(allValue, item) {
1616
- const key = this.formKey(item);
1617
- this.form[key] = allValue;
1618
- },
1619
- // 上传回调
1620
- changeUpload(value, item) {
1621
- const key = this.formKey(item);
1622
- this.form[key] = value;
1623
- },
1624
- // 时间回调
1625
- changeTime(value, item) {
1626
- const key = this.formKey(item);
1627
- this.form[key] = value;
1628
- this.submitForm[key] = value;
1629
- },
1630
- // 保存
1631
- onSubmit() {
1632
- // 不包含测评组件,点击提交,弹出二次确认对话框,确认要提交吗?
1633
- let hasEvaluate = this.formArray.find(item => this.isEvaluation(item.type));
1634
- if (!hasEvaluate) {
1635
- this.confirmSubmit('确认要提交吗?');
1636
- return;
1637
- }
1638
-
1639
- // 包含测评组件,不包含考试时长,点击提交,弹出二次确认对话框,确认要结束测评吗?
1640
- // 判断有无测评配置 并且在测评时间内
1641
- let { evaluateResultSetting } = this.config;
1642
- if (!evaluateResultSetting || (!Object.keys(evaluateResultSetting).length && !this.showEvaluateEntry)) {
1643
- this.confirmSubmit('确认要结束测评吗?');
1644
- return;
1645
- }
1646
-
1647
- // 表单内嵌量表, 没有开始答题, 不需要调用保存接口
1648
- if (this.openType == 'formIframe' && this.showEvaluateEntry) {
1649
- this.$emit('submitNoRequest');
1650
- return;
1651
- }
1652
-
1653
- // 无倒计时
1654
- let countdownDom = this.$refs.evaluateCountdown;
1655
- if (!countdownDom?.showEvaluateCountdown) {
1656
- this.confirmSubmit('确认要结束测评吗?');
1657
- return;
1658
- }
1659
-
1660
- // 在倒计时内
1661
- let message = '确认要提前结束测评吗?';
1662
- let setAnswered = this.$refs.evaluateCountdown?.setAnswered;
1663
- let totalLen = this.$refs.evaluateCountdown?.totalLen;
1664
- // 存在未解答题目
1665
- if (setAnswered < totalLen) {
1666
- message = '存在未解答的题目,确定要提前结束吗?';
1667
- }
1668
- this.confirmSubmit(message);
1669
- },
1670
- confirmSubmit(message) {
1671
- let _this = this;
1672
- this.$confirm({
1673
- title: '温馨提示',
1674
- content: message,
1675
- okText: '确定',
1676
- cancelText: '取消',
1677
- onOk: () => {
1678
- _this.onSubmitForm();
1679
- },
1680
- onCancel() {}
1681
- });
1682
- },
1683
- onSubmitForm() {
1684
- this.$refs['ruleForm'].validate((valid, keys) => {
1685
- if (valid) {
1686
- this.submitMethod();
1687
- } else {
1688
- if (Object.keys(keys).length > 0) {
1689
- let key = Object.keys(keys)[0];
1690
- let field = keys[key][0].field,
1691
- message = keys[key][0].message;
1692
- let matchItem = this.formArray.find(v => v.databaseTitle === field);
1693
- if (matchItem) {
1694
- field = matchItem.title;
1695
- }
1696
- this.$message.error(field + message);
1697
- }
1698
- return false;
1699
- }
1700
- });
1701
- },
1702
- submitMethod() {
1703
- const hasSpreadParams = this.defaultFormArray.find(v => v.type === 'SPREAD_PARAMS');
1704
- if (hasSpreadParams) {
1705
- if (utils.isJSON(hasSpreadParams.setting)) {
1706
- hasSpreadParams.setting = JSON.parse(hasSpreadParams.setting);
1707
- }
1708
- let spreadKey = this.formKey(hasSpreadParams);
1709
- this.submitForm[spreadKey] = this.compileSpreadParams(hasSpreadParams.setting.spreadParams);
1710
- }
1711
- // 自定义列表新增时多选特殊处理
1712
- let checkBoxKey = this.defaultFormArray.find(ii => ii.type == 'CHECKBOX_BLOCK');
1713
- if (checkBoxKey && Array.isArray(this.form[checkBoxKey.title]) && this.type === 'customList') {
1714
- this.form[checkBoxKey.title] = this.form[checkBoxKey.title].join(',');
1715
- }
1716
- const scoreJson = this.handleScoreJson();
1717
- let params;
1718
- if (this.type === 'customList') {
1719
- params = {
1720
- definedListId: this.ids.guage_id,
1721
- dbId: this.ids.db_id,
1722
- scoreJson: JSON.stringify(scoreJson)
1723
- };
1724
- } else {
1725
- const { guageId, randomId } = this.config;
1726
- params = Object.assign(this.params, {
1727
- guageId,
1728
- scoreJson: JSON.stringify(scoreJson),
1729
- randomId
1730
- });
1731
- }
1732
- if (this.shareId) {
1733
- params.shareId = this.shareId;
1734
- }
1735
- const tipSetting = this.defaultFormArray.find(item => item.type === 'SUCCESS_TIP');
1736
- if (tipSetting) {
1737
- // 提交保存成功提示设置
1738
- const tip = utils.isJSON(tipSetting.setting) ? JSON.parse(tipSetting.setting) : tipSetting.setting;
1739
- params.tipSetting = JSON.stringify({
1740
- tipMode: tip.tipMode,
1741
- tipType: tip.tipType,
1742
- tipText: tip.tipText,
1743
- tipApi: tip.tipApi
1744
- });
1745
- }
1746
- let hasCallbackItem = this.defaultFormArray.find(v => v.type === 'CALLBACK_INTERFACE');
1747
- let isCallback = false;
1748
- if (hasCallbackItem) {
1749
- isCallback = this.showEvent(hasCallbackItem, true);
1750
- }
1751
- /**
1752
- * NOTE:
1753
- * 提交数据往外推
1754
- */
1755
- this.$emit('onSubmit', params, hasCallbackItem, isCallback);
1756
- },
1757
- handleScoreJson() {
1758
- let tempObj = Object.assign({}, this.form, this.submitForm);
1759
- let res = {};
1760
- if (!Object.keys(tempObj).length) return {};
1761
- for (let key in tempObj) {
1762
- let itemTemp = this.formArray.find(item => this.formKey(item) == key);
1763
- let curValue = tempObj[key];
1764
- if (key && itemTemp) {
1765
- let keyTemp;
1766
- if (itemTemp && itemTemp.databaseTitle) keyTemp = itemTemp.databaseTitle;
1767
- if (this.type == 'customList' && itemTemp && itemTemp.setting && itemTemp.setting.startToStop != 1 && curValue && itemTemp.type == 'DATETIME') {
1768
- if (itemTemp.setting && itemTemp.setting.dateType == 'time' && curValue) curValue = moment().format('YYYY-MM-DD ') + curValue;
1769
- if (itemTemp.setting && itemTemp.setting.dateType == 'date' && curValue) curValue = moment(curValue).format('YYYY-MM-DD ') + moment().format('HH:mm:ss');
1770
- }
1771
-
1772
- // 处理choice选项 将key替换为value
1773
- let isChoice = ['RADIO_BLOCK', 'CHECKBOX_BLOCK'].includes(itemTemp.type);
1774
- if (isChoice) {
1775
- let { options } = itemTemp;
1776
- let obj = this.choiceComObj[key];
1777
- if (itemTemp.type === 'RADIO_BLOCK' && curValue) {
1778
- curValue = this.handleChoiceItem(curValue, options, obj);
1779
- }
1780
- if (itemTemp.type === 'CHECKBOX_BLOCK' && curValue?.length) {
1781
- let resArr = this.handleCheckboxParams(curValue, options, obj);
1782
- curValue = resArr;
1783
- }
1784
- }
1785
-
1786
- if (key.includes('~-~')) {
1787
- let newKey = keyTemp ? keyTemp.replace(/~-~/g, '.') : key.replace(/~-~/g, '.');
1788
- res[newKey] = curValue;
1789
- } else {
1790
- res[keyTemp || key] = !curValue ? null : curValue;
1791
- }
1792
- } else {
1793
- res[key] = curValue;
1794
- }
1795
- }
1796
- console.log('res', res);
1797
- return res;
1798
- },
1799
- handleCheckboxParams(value, options, obj) {
1800
- let res = [];
1801
- let i = 0,
1802
- len = value.length,
1803
- v;
1804
- for (; i < len; i++) {
1805
- v = value[i];
1806
- let matchItem = options.find((o, i) => {
1807
- if (i + 1 === v) {
1808
- return true;
1809
- }
1810
- return false;
1811
- });
1812
- if (matchItem && !matchItem.prefix && !matchItem.suffix) {
1813
- res.push(matchItem.value);
1814
- continue;
1815
- }
1816
- let tempValue = this.handleChoiceItem(v, options, obj);
1817
- res.push(tempValue);
1818
- }
1819
- return res;
1820
- },
1821
- handleChoiceItem(value, options, obj) {
1822
- let { othersText, optionsPreSuffixObj = {} } = obj || {};
1823
- if (value === 'other') {
1824
- return othersText || '其他';
1825
- }
1826
- let matchItem = options.find((o, i) => {
1827
- if (i + 1 === value) {
1828
- return true;
1829
- }
1830
- return false;
1831
- });
1832
- if (!matchItem) return;
1833
- if (!matchItem.prefix && !matchItem.suffix) return matchItem.value;
1834
- let resValue = optionsPreSuffixObj[value] || '';
1835
- if (matchItem.prefix) {
1836
- resValue = matchItem.prefix + resValue;
1837
- } else {
1838
- resValue += matchItem.suffix;
1839
- }
1840
- return resValue;
1841
- },
1842
- resetForm() {
1843
- this.$refs.ruleForm.resetFields();
1844
- },
1845
- cancel() {
1846
- this.$emit('onCloseSetting');
1847
- },
1848
- handleEvaluationScore(ele) {
1849
- let { minScore = 0, maxScore = 0, scoreType } = ele.scoreConfigs || {};
1850
- return `(${maxScore}分)`;
1851
- }
1852
- }
1853
- });
1854
- </script>
1855
- <style lang="less" scoped>
1856
- .r-scale {
1857
- position: relative;
1858
- width: 100%;
1859
- height: 100%;
1860
- overflow: hidden;
1861
- padding-top: 4px;
1862
- padding-bottom: 50px;
1863
- .scale-container {
1864
- width: 100%;
1865
- height: 100%;
1866
- padding-bottom: 10px;
1867
- transform-origin: 0 0;
1868
- overflow-y: auto;
1869
- box-sizing: border-box;
1870
- &.scale-container-nopadding {
1871
- height: 100%;
1872
- }
1873
- &::-webkit-scrollbar {
1874
- width: 10px;
1875
- }
1876
- }
1877
- /deep/ .no-data-tip {
1878
- width: 100%;
1879
- height: 100%;
1880
- }
1881
- .totalScore-warp {
1882
- padding: 16px;
1883
- margin-bottom: 16px;
1884
- font-weight: 400;
1885
- color: #666666;
1886
- background: #f2f2f4;
1887
- font-size: 14px;
1888
- border-radius: 6px;
1889
- div + div {
1890
- margin-top: 4px;
1891
- }
1892
- span {
1893
- font-weight: 500;
1894
- color: #090909;
1895
- }
1896
- .score-result {
1897
- color: #2d7aff;
1898
- }
1899
- }
1900
- /deep/ .ant-spin-spinning {
1901
- height: 100%;
1902
- width: 100%;
1903
- padding-top: 88px;
1904
- }
1905
- /deep/ .ant-select ~ div {
1906
- position: relative !important;
1907
- }
1908
- // /deep/.ant-select-dropdown {
1909
- // top: 0px !important;
1910
- // left: 1px !important;
1911
- // }
1912
- .lb-title {
1913
- text-align: center;
1914
- }
1915
- .map-container {
1916
- cursor: pointer;
1917
- /deep/ .ant-input-disabled {
1918
- color: rgba(0, 0, 0, 0.65);
1919
- background-color: #fff;
1920
- cursor: pointer;
1921
- }
1922
- }
1923
- .linebar-div {
1924
- text-align: center;
1925
- margin-top: 24px;
1926
- /deep/ .ant-divider {
1927
- margin-top: -4px;
1928
- }
1929
- }
1930
- .my-prompt {
1931
- padding: 10px;
1932
- box-shadow: 0 5px 13px rgba(0, 0, 0, 0.14);
1933
- background-color: #fff;
1934
- border-radius: 4px;
1935
- }
1936
- .img-card {
1937
- width: 100%;
1938
- }
1939
- }
1940
- .main {
1941
- // overflow: auto;
1942
- // overflow-x: hidden;
1943
- padding: 0 16px;
1944
- box-sizing: border-box;
1945
- /deep/.ant-form-item-required::before {
1946
- color: #e02828;
1947
- }
1948
- .scale-label-required {
1949
- font-weight: 700;
1950
- }
1951
- .required-text {
1952
- color: #e02828;
1953
- }
1954
- .evalute-label {
1955
- display: inline-block;
1956
- height: 20px;
1957
- line-height: 20px;
1958
- padding: 0 5px;
1959
- margin-left: 4px;
1960
- font-size: 12px;
1961
- color: #2d7aff;
1962
- border-radius: 4px;
1963
- border: 1px solid rgba(45, 122, 255, 0.5);
1964
- background: rgba(45, 122, 255, 0.1);
1965
- }
1966
- .evalute-tip {
1967
- display: inline-block;
1968
- padding: 0 5px;
1969
- margin-left: 8px;
1970
- color: #fe9626;
1971
- border-radius: 2px;
1972
- background: rgba(255, 194, 0, 0.15);
1973
- cursor: pointer;
1974
- .ant-icon {
1975
- margin-right: 2px;
1976
- }
1977
- }
1978
- /deep/ .ant-form-item-label {
1979
- // white-space: break-spaces;
1980
- white-space: unset;
1981
- text-align: left;
1982
- line-height: 20px;
1983
- padding: 6px 0;
1984
- width: 100%;
1985
- .ant-form-item-no-colon {
1986
- width: 100%;
1987
- }
1988
- }
1989
- }
1990
- .footer {
1991
- position: absolute;
1992
- bottom: 0;
1993
- left: 0;
1994
- width: 100%;
1995
- border-top: 1px solid #e8e8e8;
1996
- padding-top: 12px;
1997
- height: 50px;
1998
- box-sizing: border-box;
1999
- background: #fff;
2000
- }
2001
- .rich-text-content {
2002
- word-break: break-all;
2003
- /deep/ p {
2004
- margin-bottom: 0;
2005
- }
2006
- /deep/ img {
2007
- max-width: 100%;
2008
- }
2009
- }
2010
- </style>
1
+ <template>
2
+ <div class="r-scale">
3
+ <slot v-if="spinning">
4
+ <a-spin :indicator="indicator" tip="加载中..." />
5
+ </slot>
6
+ <slot v-if="!spinning && !hasFrontAddress">
7
+ <!-- <div v-if="noData">暂无数据</div> -->
8
+ <NoData v-if="noData" :noDataImg="noDataImg" :noDataTip="noDataTip"></NoData>
9
+ <template v-else>
10
+ <evaluatePage
11
+ v-if="showEvaluateEntry"
12
+ :formArray="formArray"
13
+ :evaluateResultConfig="config.evaluateResultConfig"
14
+ :evaluateResultSetting="config.evaluateResultSetting"
15
+ :isFinished="isFinished"
16
+ :maxScore="maxScore"
17
+ @writeGuage="writeGuage"
18
+ ></evaluatePage>
19
+ <template v-else>
20
+ <evaluateCountdown
21
+ v-if="showEvaluateCoundownPage"
22
+ ref="evaluateCountdown"
23
+ :formArray="formArray"
24
+ :evaluateResultConfig="config.evaluateResultConfig"
25
+ :evaluateResultSetting="config.evaluateResultSetting"
26
+ :form="form"
27
+ :isFinished="isFinished"
28
+ :currentTime="currentTime"
29
+ :showEvaluateCountdown="showEvaluateCountdown"
30
+ @closeEvaluateCountdown="closeEvaluateCountdown"
31
+ ></evaluateCountdown>
32
+ <div
33
+ class="scale-container"
34
+ :class="{ 'scale-container-nopadding': handlePageClass }"
35
+ :style="scaleStyle"
36
+ >
37
+ <div class="totalScore-warp" v-if="hasScore">
38
+ <div>
39
+ 测评总分:
40
+ <span>{{ maxScore }}分</span>
41
+ </div>
42
+ <div>
43
+ 测评分数:
44
+ <span :style="{ color: getEvaResColor }">{{ config.totalScore }}分</span>
45
+ </div>
46
+ <template v-if="hasEvaluateSetting">
47
+ <div>
48
+ 测评结果:
49
+ <span
50
+ class="score-result"
51
+ :style="{ color: getEvaResColor }"
52
+ >{{ config.evaluateResult }}</span>
53
+ </div>
54
+ <div>
55
+ 结果说明:
56
+ <span>{{ config.evaluateResultExplain }}</span>
57
+ </div>
58
+ </template>
59
+ </div>
60
+ <a-form-model
61
+ ref="ruleForm"
62
+ :model="form"
63
+ :rules="rules"
64
+ :layout="form.layout"
65
+ :colon="false"
66
+ class="main"
67
+ >
68
+ <template v-for="(item, index) in formArray">
69
+ <!-- 标题 -->
70
+ <template v-if="item.type == 'TITLE'">
71
+ <a-form-model-item
72
+ v-if="isShowItem(item)"
73
+ :colon="false"
74
+ :key="item.id || item.seq"
75
+ >
76
+ <h1 class="lb-title">{{ item.title }}</h1>
77
+ <div class="lb-title">{{ item.describe }}</div>
78
+ </a-form-model-item>
79
+ </template>
80
+ <!-- 分线栏 -->
81
+ <template v-else-if="item.type == 'LINEBAR'">
82
+ <a-form-model-item
83
+ v-if="isShowItem(item)"
84
+ :colon="false"
85
+ :key="item.id || item.seq"
86
+ >
87
+ <div class="linebar-div" v-if="item.title">
88
+ <span>{{ item.title }}</span>
89
+ <a-divider />
90
+ </div>
91
+ <template v-else>
92
+ <a-divider />
93
+ </template>
94
+ </a-form-model-item>
95
+ </template>
96
+ <!-- 提示语 -->
97
+ <template v-else-if="item.type == 'PROMPT'">
98
+ <a-form-model-item
99
+ v-if="isShowItem(item)"
100
+ class="my-prompt"
101
+ :colon="false"
102
+ :key="item.id || item.seq"
103
+ >
104
+ <MyPrompt :key="item.id || item.seq" :options="item.setting" />
105
+ </a-form-model-item>
106
+ </template>
107
+ <template v-else-if="item.type == 'IMGCARD'">
108
+ <a-form-model-item
109
+ v-if="isShowItem(item)"
110
+ :colon="false"
111
+ :key="item.id || item.seq"
112
+ >
113
+ <a v-if="item.setting.imgLink" :href="item.setting.imgLink" target="_blank">
114
+ <img class="img-card" :src="item.setting.imgUrl" />
115
+ </a>
116
+ <img class="img-card" v-else :src="item.setting.imgUrl" />
117
+ </a-form-model-item>
118
+ </template>
119
+ <!-- 富文本 -->
120
+ <template v-else-if="item.type == 'RICH_TEXT'">
121
+ <div
122
+ :key="item.id || item.seq"
123
+ class="rich-text-content"
124
+ v-html="item.setting.defaultValue"
125
+ ></div>
126
+ </template>
127
+ <template v-else>
128
+ <a-form-model-item
129
+ v-if="isShowItem(item)"
130
+ :key="item.id || item.seq"
131
+ :prop="formKey(item)"
132
+ >
133
+ <span slot="label">
134
+ <span
135
+ :class="{ 'scale-label-required': isFormBoldOpen(item) }"
136
+ v-html="handleShowQuestionNumber(item)"
137
+ ></span>
138
+ <span class="required-text" v-if="isFormBoldOpen(item)">(必填)</span>
139
+ <span
140
+ class="evalute-label"
141
+ v-if="showEvaluateLabel(item)"
142
+ >{{ showEvaluateLabel(item) }}</span>
143
+ <template v-if="showEvatip(item)">
144
+ <span class="evalute-tip" @click="showEvaTipModal(item)">
145
+ <svg-icon icon-class="a-xitongtubiaotishi" />查看提示
146
+ </span>
147
+ </template>
148
+ </span>
149
+ <!-- 输入框 -->
150
+ <MyInput
151
+ v-bind="$attrs"
152
+ v-if="isInput(item.type)"
153
+ v-model="form[formKey(item)]"
154
+ :type="item.valueType"
155
+ :row="item.setting.inputRow || 1"
156
+ :defaultPlaceHolder="item.setting.defaultPlaceHolder"
157
+ :isLock="componentDisable"
158
+ />
159
+
160
+ <!-- 单选/下拉/多选/级联 -->
161
+ <MyChoice
162
+ v-bind="$attrs"
163
+ v-else-if="isChoice(item.type)"
164
+ v-model="form[formKey(item)]"
165
+ :item="item"
166
+ :isLock="componentDisable"
167
+ :curIndex="index"
168
+ :openType="openType"
169
+ @change="handleChoice($event, item)"
170
+ @radioChange="radioChange"
171
+ @checkboxChange="checkboxChange"
172
+ />
173
+ <!-- 日期/时间 -->
174
+ <MyTime
175
+ v-bind="$attrs"
176
+ v-else-if="isTime(item.type)"
177
+ :value="getTimeValue(item)"
178
+ :type="item.type"
179
+ :startToStop="item.setting.startToStop"
180
+ :dateType="item.setting.dateType"
181
+ :isLock="componentDisable"
182
+ @change="changeTime($event, item)"
183
+ />
184
+ <!-- 上传附件 or 图片 -->
185
+ <MyUpload
186
+ v-bind="$attrs"
187
+ v-else-if="isUpload(item.type)"
188
+ :upType="item.type"
189
+ :useFileList="item.dbValue"
190
+ :limitPic="item.setting.limitPic"
191
+ :isLock="componentDisable"
192
+ @change="changeUpload($event, item)"
193
+ />
194
+ <!-- 地图 -->
195
+ <div
196
+ v-else-if="item.type === 'LOCATION'"
197
+ @click="!isLock && (mapVisible = !mapVisible)"
198
+ :class="{ 'map-container': !isLock }"
199
+ >
200
+ <a-input
201
+ placeholder="请选择"
202
+ :value="handleGetAddress(form[formKey(item)])"
203
+ disabled
204
+ >
205
+ <a-icon slot="prefix" type="info-circle" />
206
+ </a-input>
207
+ <MapComp
208
+ v-bind="$attrs"
209
+ :visible.sync="mapVisible"
210
+ :locationProp="form[formKey(item)]"
211
+ :isLock="componentDisable"
212
+ @selectLocation="handleSelectLocation($event, item)"
213
+ />
214
+ </div>
215
+ <!-- 地址 -->
216
+ <MyAddress
217
+ v-bind="$attrs"
218
+ v-else-if="item.type === 'ADDRESS'"
219
+ :setting="item.setting"
220
+ :defaultValue="defaultAddress"
221
+ :isLock="componentDisable"
222
+ @change="changeAddress($event, item)"
223
+ />
224
+ <!-- 标签 -->
225
+ <label-form
226
+ v-bind="$attrs"
227
+ v-else-if="item.type === 'LABEL'"
228
+ :item="item"
229
+ :selectedList="labelSelectedList"
230
+ :isLock="componentDisable"
231
+ :sourceType="source"
232
+ @onChange="labelChange($event, item)"
233
+ />
234
+ <!-- 视频 -->
235
+ <vod-Chunk-upload
236
+ v-bind="$attrs"
237
+ v-else-if="item.type === 'VEDIO'"
238
+ :source="'guage'"
239
+ :formData="item"
240
+ :limitNum="item.setting.limitPic"
241
+ :defFileList="form[formKey(item)]"
242
+ :isLock="componentDisable"
243
+ @vodFileList="vodFileList($event, item)"
244
+ />
245
+ <!-- 答案解析 -->
246
+ <answerParse v-if="showAnswerParse(item)" :item="item"></answerParse>
247
+ </a-form-model-item>
248
+ </template>
249
+ </template>
250
+ </a-form-model>
251
+ </div>
252
+ <template v-if="type === 'customList'">
253
+ <div class="footer" v-if="!noBtn">
254
+ <a-button @click="cancel" v-if="false" style="margin-right: 8px;">取消</a-button>
255
+ <a-button @click="onSubmit" type="primary" :disabled="banSubmit">保存</a-button>
256
+ </div>
257
+ </template>
258
+ <template v-else>
259
+ <div class="footer" v-if="showSaveBtn">
260
+ <a-button @click="cancel" style="margin-right: 8px;">取消</a-button>
261
+ <a-button type="primary" v-if="!isLock" @click="onSubmit" :disabled="banSubmit">保存</a-button>
262
+ </div>
263
+ </template>
264
+ </template>
265
+ </template>
266
+ </slot>
267
+ </div>
268
+ </template>
269
+ <script>
270
+ import { Icon, Checkbox, Tree, Tooltip, Input, Spin, FormModel, Divider, Button } from 'ant-design-vue';
271
+ import create from '@/core/create';
272
+ import { MyChoice, MyInput, MyAddress, MyUpload, MyTime, MyPrompt } from './formitem';
273
+ import MapComp from '../map/src/popup-map';
274
+ import labelForm from '~/select-label/select-label';
275
+ import vodChunkUpload from '~/upload/chunk-upload/vod-chunk-upload.vue';
276
+ // import { EventBus } from "@/common/utils/eventBus.js";
277
+ import { judgeTypes } from './mixin/judgeTypes';
278
+ import NoDataJs from './mixin/NoData';
279
+ // import { mapGetters } from "vuex";
280
+ import moment from 'moment';
281
+ import utils from '@/utils/utils-map';
282
+ import evaluatePage from './evaluatePage.vue';
283
+ import evaluateCountdown from './evaluateCountdown.vue';
284
+ import answerParse from './answerParse.vue';
285
+ import vexutils from '@/utils/vexutils';
286
+ import NoData from './NoData.vue';
287
+ export default create({
288
+ name: 'scale-view',
289
+ mixins: [judgeTypes, NoDataJs],
290
+ props: {
291
+ ids: {
292
+ type: Object,
293
+ default: () => {
294
+ return { guage_id: '', db_id: undefined };
295
+ }
296
+ },
297
+ params: { default: () => ({}), type: Object },
298
+ guageData: { type: Object, default: () => ({}) },
299
+ noBtn: { type: Boolean, default: false },
300
+ hideBtn: { type: Boolean, default: false },
301
+ source: { type: String, default: '' },
302
+ isLock: { type: Boolean, default: false },
303
+ type: {
304
+ type: String,
305
+ default: ''
306
+ },
307
+ styleSetting: {
308
+ type: Object,
309
+ default: () => ({})
310
+ },
311
+
312
+ fontSizeObj: {
313
+ type: Object,
314
+ default: () => ({
315
+ large: 1.25,
316
+ medium: 1.1,
317
+ small: 1,
318
+ extrasmall: 0.9
319
+ })
320
+ },
321
+ openType: { type: String, default: '' },
322
+ scaleApiConfig: {
323
+ type: Object,
324
+ default: () => ({})
325
+ }
326
+ },
327
+ components: {
328
+ MyChoice,
329
+ MyInput,
330
+ MapComp,
331
+ MyAddress,
332
+ MyUpload,
333
+ MyTime,
334
+ MyPrompt,
335
+ labelForm,
336
+ vodChunkUpload,
337
+ [Icon.name]: Icon,
338
+ [Spin.name]: Spin,
339
+ [Tree.name]: Tree,
340
+ [Input.name]: Input,
341
+ [Input.Search.name]: Input.Search,
342
+ [Checkbox.name]: Checkbox,
343
+ [Divider.name]: Divider,
344
+ [Button.name]: Button,
345
+ [FormModel.name]: FormModel,
346
+ [FormModel.Item.name]: FormModel.Item,
347
+ [Tooltip.name]: Tooltip,
348
+ evaluatePage,
349
+ evaluateCountdown,
350
+ answerParse,
351
+ NoData
352
+ },
353
+ computed: {
354
+ queryformBoldOpen() {
355
+ return this.$route.query?.formBoldOpen == 1;
356
+ },
357
+ showEvatip() {
358
+ return function (item) {
359
+ if (!this.isEvaluation(item.type)) return false;
360
+ return this.$route.query?.evatip == 1 || this.params?.evatip == 1;
361
+ };
362
+ },
363
+ isFormBoldOpen() {
364
+ return function (item) {
365
+ let res = item.required;
366
+ // 量表未登录时 判断 url中是否有 formBoldOpen
367
+ if (!this.styleSetting || !Object.keys(this.styleSetting).length || !('formBoldOpen' in this.styleSetting)) {
368
+ return res && this.queryformBoldOpen;
369
+ }
370
+ return res && this.styleSetting.formBoldOpen;
371
+ };
372
+ },
373
+ scaleStyle() {
374
+ let fontSize = this.fontSize;
375
+ if (!fontSize || fontSize === 'S') return null;
376
+ const keyValue = {
377
+ L: 'large',
378
+ M: 'medium',
379
+ XS: 'extrasmall'
380
+ };
381
+ fontSize = keyValue[fontSize];
382
+ const scale = (fontSize && this.fontSizeObj[fontSize]) || 1;
383
+ const size = 10000;
384
+ const value = Math.floor((100 / scale) * size) / size;
385
+ return {
386
+ width: `${value}%`,
387
+ height: `${value}%`,
388
+ transform: `scale(${scale})`
389
+ };
390
+ },
391
+ handlePageClass() {
392
+ if (this.type == 'customList' && !this.noBtn) return false;
393
+ if (!this.noBtn && !this.hideBtn) return false;
394
+ return true;
395
+ },
396
+ isShowItem() {
397
+ return item => this.showEvent(item);
398
+ },
399
+ handleShowQuestionNumber() {
400
+ return function (item) {
401
+ let { type } = item || {};
402
+ let tempTile = this.config?.autoQuestionNumber === false ? item.showTitle : `${item.softcode}、${item.showTitle}`;
403
+ if (!this.isEvaluation(type)) return tempTile;
404
+
405
+ let score = this.handleEvaluationScore(item);
406
+ return `${tempTile}&nbsp;<span style="color:#2d7aff;">${score}</span>`;
407
+ // if (this.noBtn) {
408
+ // let score = this.handleEvaluationScore(item);
409
+ // return `${tempTile}&nbsp;<span style="color:#2d7aff;">${score}</span>`;
410
+ // }
411
+ // if (!this.isLock) {
412
+ // let score = this.handleEvaluationScore(item);
413
+ // return `${tempTile}&nbsp;<span style="color:#2d7aff;">${score}</span>`;
414
+ // }
415
+ // if (item.questionScore !== undefined) {
416
+ // return `${tempTile}&nbsp;<span style="color:#2d7aff;">(${item.questionScore}分)</span>`;
417
+ // }
418
+ // return tempTile;
419
+ };
420
+ },
421
+ hasScore() {
422
+ let { config } = this;
423
+ if (!config || !Object.keys(config).length) return false;
424
+ if ('totalScore' in config) return true;
425
+ return false;
426
+ },
427
+ // 预览按钮打开的量表页面
428
+ isPreviewScale() {
429
+ let guage_id = this.ids?.guage_id;
430
+ return guage_id && this.noBtn;
431
+ },
432
+ hasEvaluateSetting() {
433
+ let { config } = this;
434
+ if (!config || !Object.keys(config).length) return false;
435
+ if ('evaluateResult' in config && config.evaluateResult) return true;
436
+ return false;
437
+ },
438
+ getTimeValue() {
439
+ return function (item) {
440
+ let value = this.form[this.formKey(item)];
441
+ return value;
442
+ };
443
+ },
444
+ // 是否展示考试入口
445
+ showEvaluateEntry() {
446
+ // 非预览
447
+ // 有evaluateResultSetting || url中含有固定参数
448
+ // 倒计时未结束
449
+ // 未填写过
450
+ return !this.isPreviewScale && this.showEvaluatePage && this.showEvaluateSettingWrap && !this.isFinished && !this.noBtn && !this.hideBtn;
451
+ },
452
+ // 是否展示倒计时
453
+ showEvaluateCoundownPage() {
454
+ return !this.isPreviewScale && !this.showEvaluateEntry && this.showEvaluateCountdownWrap && !this.isFinished && !this.noBtn && !this.hideBtn;
455
+ },
456
+ // 是否设置 evaluateResultSetting
457
+ hasEvaluateResultSetting() {
458
+ let { evaluateResultSetting = {} } = this.config;
459
+ // 读取优先级为测评设置值(变量) > URL参数 > 测评设置值(固定值)
460
+ // 是否设置 evaluateResultSetting
461
+ let valueArr =
462
+ Object.values(evaluateResultSetting).filter(item => {
463
+ if (item) return true;
464
+ }) || [];
465
+ return valueArr.length;
466
+ },
467
+ hasparamsEvaluate() {
468
+ return this.paramsEvaluate && Object.keys(this.paramsEvaluate).length;
469
+ },
470
+ // url中是否有默认值
471
+ hasDefault() {
472
+ let hash = window.location.hash;
473
+ let defaultVariable = ['evaname', 'evadesc', 'evast', 'evadur', 'evaan'];
474
+ let hasDefault = defaultVariable.find(item => hash.includes(item));
475
+ return this.paramsEvaluate || hasDefault;
476
+ },
477
+ // 是否有提交按钮
478
+ showSaveBtn() {
479
+ // 无测评设置 && url中无固定参数
480
+ if (!this.hasEvaluateResultSetting && !this.hasDefault) {
481
+ return !this.noBtn && !this.hideBtn;
482
+ }
483
+ return !this.noBtn && !this.hideBtn && !this.isFinished;
484
+ },
485
+ // 组件是否 Disable
486
+ componentDisable() {
487
+ // 无测评设置 && url中无固定参数
488
+ if (!this.hasEvaluateResultSetting && !this.hasDefault) {
489
+ return this.hideBtn || this.isLock;
490
+ }
491
+ return this.hideBtn || this.isLock || this.isFinished;
492
+ },
493
+ showEvaluateLabel() {
494
+ return function (item) {
495
+ let obj = {
496
+ EVALUATE_RADIO_BLOCK: '单选题',
497
+ EVALUATE_CHECKBOX_BLOCK: '多选题'
498
+ };
499
+ return obj[item.type];
500
+ };
501
+ },
502
+ showAnswerParse() {
503
+ return function (item) {
504
+ let { evaluateAnswer, checkAnswerMode, evaluateStartTime, evaluateTime } = this.config?.evaluateResultSetting || {};
505
+ let arr = ['EVALUATE_RADIO_BLOCK', 'EVALUATE_CHECKBOX_BLOCK', 'EVALUATE_SELECT', 'EVALUATE_INPUT'];
506
+ let maxScore = item?.scoreConfigs || 0;
507
+ let isShow = evaluateAnswer && this.isFinished && arr.includes(item.type) && maxScore;
508
+ if (!evaluateStartTime || !evaluateTime || (checkAnswerMode && checkAnswerMode == 1)) return isShow;
509
+ if (!vexutils.isValidDate(new Date(evaluateStartTime))) return isShow;
510
+ // 答案解析时间 考试时间结束后
511
+ let endTime = moment(evaluateStartTime).add(evaluateTime, 'minutes');
512
+ let isRang = endTime.diff(moment(), 'seconds', true);
513
+ return isShow && isRang <= 0;
514
+ };
515
+ },
516
+ tipMsg() {
517
+ return this.type === 'customList' ? '保存' : '提交';
518
+ },
519
+ formKey() {
520
+ return function (item) {
521
+ return item.databaseTitle || item.title;
522
+ };
523
+ },
524
+ getEvaResColor() {
525
+ let { evaluateResultConfig = [], totalScore } = this.config || {};
526
+ totalScore = +totalScore || 0;
527
+ if (!evaluateResultConfig?.length || !totalScore) return '#2474FF';
528
+ let matchItem = evaluateResultConfig.find(item => item.startScore <= totalScore && totalScore <= item.endScore);
529
+ if (!matchItem) return '#2474FF';
530
+ return matchItem.color || '#2474FF';
531
+ }
532
+ },
533
+ watch: {
534
+ ids: {
535
+ immediate: true,
536
+ deep: true,
537
+ handler(newVal, oldVal) {
538
+ if (oldVal) {
539
+ if (newVal.guage_id) {
540
+ if (newVal.guage_id != oldVal.guage_id) {
541
+ this.init(newVal);
542
+ }
543
+ }
544
+ } else {
545
+ if (newVal.guage_id) this.init(newVal);
546
+ }
547
+ }
548
+ },
549
+ guageData: {
550
+ immediate: true,
551
+ deep: true,
552
+ handler(value) {
553
+ if (value) {
554
+ if (Object.keys(value || {}).length) {
555
+ // guageForm打开 重新请求重置之前的答案
556
+ this.form = {};
557
+ this.formArray = [];
558
+ const data = JSON.parse(JSON.stringify(value));
559
+ this.$nextTick(() => {
560
+ this.initForm(data);
561
+ });
562
+ }
563
+ }
564
+ }
565
+ }
566
+ },
567
+ data() {
568
+ return {
569
+ other: '',
570
+ form: {},
571
+ submitForm: {},
572
+ rules: {},
573
+ config: {},
574
+ formArray: [],
575
+ mapVisible: false,
576
+ mapLocation: '',
577
+ labelSelectedList: [],
578
+ defaultFormArray: [],
579
+ fontSize: '',
580
+ filterArr: ['SUCCESS_TIP', 'CALLBACK_INTERFACE', 'SPREAD_PARAMS', 'REDIRECT', 'FRONT_ADDRESS', 'RETURN_PATH'],
581
+ spinning: true,
582
+ indicator: <a-icon type="loading" style="font-size: 24px" spin />,
583
+ totalScore: undefined,
584
+ shareId: '',
585
+ currentTime: moment(),
586
+ showEvaluatePage: false,
587
+ showEvaluateSettingWrap: true,
588
+ showEvaluateCountdownWrap: false,
589
+ showEvaluateCountdown: false,
590
+ banSubmit: false,
591
+ isFinished: false,
592
+ maxScore: 0,
593
+ originConfig: {},
594
+ paramsEvaluate: null,
595
+ hasFrontAddress: true,
596
+ choiceComObj: {},
597
+ evatipMap: {} // 维护一个tip map避免重复请求
598
+ };
599
+ },
600
+ mounted() {
601
+ this.handleQuery();
602
+ if (this.noBtn) {
603
+ // EventBus.$on("guageSubmit", this.onSubmit);
604
+ }
605
+ },
606
+ beforeDestroy() {
607
+ // EventBus.$off("guageSubmit");
608
+ },
609
+ methods: {
610
+ init(configData) {
611
+ this.spinning = true;
612
+ try {
613
+ this.resetNodata();
614
+ this.initForm(configData);
615
+ } catch (error) {
616
+ this.spinning = false;
617
+ this.hasFrontAddress = false;
618
+ this.setNoData(true, error?.resultMsg, error?.result);
619
+ }
620
+ },
621
+ handleQuery() {
622
+ let { id } = this.$route.query;
623
+ id && (this.shareId = id);
624
+ },
625
+ initForm(data) {
626
+ let { list = [], map = {}, isFinished = false } = data;
627
+ let curUrl = this.handleFrontAddress(list);
628
+ if (curUrl) {
629
+ window.location.href = curUrl;
630
+ return;
631
+ }
632
+ map.maxScore && (this.maxScore = map.maxScore);
633
+ this.isFinished = isFinished;
634
+ if (data.isNotFilled) {
635
+ this.spinning = false;
636
+ this.hasFrontAddress = false;
637
+ this.setNoData(true, '未查询到量表填写记录');
638
+ return;
639
+ }
640
+ if (data.isLackCustomer) {
641
+ let _this = this;
642
+ // 校验用户环境
643
+ this.$info({
644
+ title: '已设置填写次数限制',
645
+ content: '请在包含用户信息的环境中打开此量表',
646
+ onOk() {
647
+ _this.$emit('onCloseSetting');
648
+ }
649
+ });
650
+ }
651
+ this.config = map;
652
+
653
+ if ('evaluateResultConfig' in map && utils.isJSON(map.evaluateResultConfig)) {
654
+ this.config.evaluateResultConfig = JSON.parse(map.evaluateResultConfig);
655
+ }
656
+ if ('evaluateResultSetting' in map && utils.isJSON(map.evaluateResultSetting)) {
657
+ this.config.evaluateResultSetting = JSON.parse(map.evaluateResultSetting);
658
+ // 随机测评
659
+ if (this.config?.randomId && this.config.evaluateResultSetting) {
660
+ this.config.evaluateResultSetting.evaluateName = this.config.name;
661
+ this.config.evaluateResultSetting.evaluateExplain = this.config.remark;
662
+ }
663
+ }
664
+
665
+ this.originConfig = JSON.parse(JSON.stringify(this.config));
666
+
667
+ if (this.params && Object.keys(this.params).length) {
668
+ let res = this.handleBtnParamsEvaluate(this.params);
669
+ res && Object.keys(res).length && (this.paramsEvaluate = res);
670
+ }
671
+
672
+ this.handleEvaluateParams(this.config.evaluateResultSetting);
673
+ this.handleShowEvaluate();
674
+
675
+ this.defaultFormArray = JSON.parse(JSON.stringify(list));
676
+ let filterArr = this.filterArr;
677
+ list = list.filter(v => !filterArr.includes(v.type));
678
+ this.formArray = this.formatArray(list || []);
679
+ this.form = this.defaultFormValue(this.formArray);
680
+ this.rules = this.formatRules(this.formArray);
681
+ this.fontSize = data.fontSize;
682
+ this.spinning = false;
683
+ this.hasFrontAddress = false;
684
+ },
685
+ handleFrontAddress(list) {
686
+ if (!list || !list.length) return;
687
+ let matchItem = list.find(item => item.type === 'FRONT_ADDRESS');
688
+ if (!matchItem || !Object.keys(matchItem).length) return;
689
+ let setting;
690
+ if (matchItem.setting && utils.isJSON(matchItem.setting)) {
691
+ setting = JSON.parse(matchItem.setting);
692
+ }
693
+ if (!setting || !Object.keys(setting).length) return;
694
+ let query = this.handleQueryParams();
695
+ // redirect=1 代表从前置地址跳转回来了
696
+ if (query?.redirect == 1) return;
697
+ let { frontAddress } = setting;
698
+ if (frontAddress) {
699
+ let urlHref = window.location.href;
700
+ let preStr = '?';
701
+ if (frontAddress.includes('?')) {
702
+ preStr = '&';
703
+ }
704
+ let curUrl = `${frontAddress}${preStr}redirect_url=${encodeURIComponent(urlHref)}`;
705
+ return curUrl;
706
+ }
707
+ },
708
+ handleBtnParamsEvaluate(params) {
709
+ let defaultVariable = ['evaname', 'evadesc', 'evast', 'evadur', 'evaan'];
710
+ let res = {};
711
+ for (let key in params) {
712
+ let value = params[key];
713
+ if (defaultVariable.includes(key) && value) {
714
+ res[key] = value;
715
+ }
716
+ }
717
+ return res;
718
+ },
719
+ /** *
720
+ * 解析测评参数
721
+ */
722
+ handleEvaluateParams(evaluateResultSetting) {
723
+ if (!evaluateResultSetting || !Object.keys(evaluateResultSetting).length) return;
724
+ // 分享测评量表链接URL支持传入测评名称-evaname 测评说明-evadesc 测评时间-evast 测评时长-evadur 固定参数
725
+ let query = this.handleQueryParams();
726
+ // 按钮传参
727
+ if (this.hasparamsEvaluate) {
728
+ query = this.paramsEvaluate;
729
+ }
730
+ let obj = {
731
+ evaluateName: 'evaname',
732
+ evaluateExplain: 'evadesc',
733
+ evaluateStartTime: 'evast',
734
+ evaluateTime: 'evadur',
735
+ evaluateAnswer: 'evaan'
736
+ };
737
+ for (let key in evaluateResultSetting) {
738
+ let value = evaluateResultSetting[key];
739
+ let isParseKey = value && key != 'evaluateAnswer' && typeof value === 'string' && value.includes('${');
740
+ if (isParseKey) {
741
+ let parseValue = value.replace(/\$\{([^}]+)\}/g, (_v, $1) => {
742
+ let param;
743
+ if ($1.startsWith('form.')) {
744
+ param = query[$1.split('.')[1]];
745
+ }
746
+ return param || '';
747
+ });
748
+ this.$set(evaluateResultSetting, key, parseValue);
749
+ } else {
750
+ let val = query[obj[key]];
751
+ if (key == 'evaluateAnswer') {
752
+ val = val === 'true' || val == 1 ? true : false;
753
+ }
754
+ query[obj[key]] && this.$set(evaluateResultSetting, key, val);
755
+ }
756
+ }
757
+ // 部分evaluateResultSetting 但是却有url
758
+ if (this.hasDefault) {
759
+ let defaultVariable = ['evaname', 'evadesc', 'evast', 'evadur', 'evaan'];
760
+ let defObj = {
761
+ evaname: 'evaluateName',
762
+ evadesc: 'evaluateExplain',
763
+ evast: 'evaluateStartTime',
764
+ evadur: 'evaluateTime',
765
+ evaan: 'evaluateAnswer'
766
+ };
767
+ defaultVariable.forEach(item => {
768
+ let key = defObj[item];
769
+ if (!evaluateResultSetting[key]) {
770
+ let val = query[item];
771
+ if (item == 'evaan') {
772
+ val = val === 'true' || val == 1 ? true : false;
773
+ }
774
+ query[item] && this.$set(evaluateResultSetting, key, val);
775
+ }
776
+ });
777
+ }
778
+ this.setEvaluateStartTime(evaluateResultSetting);
779
+ },
780
+ handleQueryParams() {
781
+ let params = {};
782
+ for (let [key, value] of new URLSearchParams(window.location.hash.split('?')[1]).entries()) {
783
+ params[key] = decodeURIComponent(value);
784
+ }
785
+ return params;
786
+ },
787
+ handleShowEvaluate() {
788
+ // 读取优先级为测评设置值(变量) > URL参数 > 测评设置值(固定值)
789
+ // 无 evaluateResultSetting
790
+ if (!this.hasEvaluateResultSetting) {
791
+ // url中是否有默认值
792
+ // 无默认值 不显示考试入口页面
793
+ if (!this.hasDefault) return false;
794
+ // 有默认值 显示考试入口页面
795
+ if (!('evaluateResultSetting' in this.config)) {
796
+ this.$set(this.config, 'evaluateResultSetting', {});
797
+ }
798
+ this.setDefaultEvaluate(this.config.evaluateResultSetting);
799
+ this.showEvaluatePage = true;
800
+ this.showEvaluateCountdownWrap = true;
801
+ return;
802
+ }
803
+
804
+ let { evaluateResultSetting = {} } = this.config;
805
+ if (!evaluateResultSetting || !Object.keys(evaluateResultSetting).length) return;
806
+ this.showEvaluateCountdownWrap = true;
807
+
808
+ // 只要有开始时间都显示测评组件
809
+ let { evaluateStartTime } = evaluateResultSetting;
810
+ let { evaluateName } = this.originConfig?.evaluateResultSetting || {};
811
+ // 未设置开始时间 一直可以填写
812
+ if (!evaluateStartTime) {
813
+ this.showEvaluatePage = true;
814
+ return;
815
+ }
816
+ if (!vexutils.isValidDate(new Date(evaluateStartTime))) {
817
+ if (!evaluateName) return false;
818
+ }
819
+ this.showEvaluatePage = true;
820
+ },
821
+ setDefaultEvaluate(evaluateResultSetting) {
822
+ let query = this.handleQueryParams();
823
+ // 按钮传参
824
+ if (this.hasparamsEvaluate) {
825
+ query = this.paramsEvaluate;
826
+ }
827
+ if (query.evaname) {
828
+ this.$set(evaluateResultSetting, 'evaluateName', query.evaname);
829
+ }
830
+ if (query.evadesc) {
831
+ this.$set(evaluateResultSetting, 'evaluateExplain', query.evadesc);
832
+ }
833
+ if (query.evast) {
834
+ this.$set(evaluateResultSetting, 'evaluateStartTime', query.evast);
835
+ }
836
+ if (query.evadur) {
837
+ this.$set(evaluateResultSetting, 'evaluateTime', query.evadur);
838
+ }
839
+ if (query.evaan) {
840
+ let evaan = query.evaan === 'true' || query.evaan == 1 ? true : false;
841
+ this.$set(evaluateResultSetting, 'evaluateAnswer', evaan);
842
+ }
843
+
844
+ this.setEvaluateStartTime(evaluateResultSetting);
845
+ },
846
+ // 时间戳需要是数字
847
+ setEvaluateStartTime(evaluateResultSetting) {
848
+ let evaluateStartTime = evaluateResultSetting?.evaluateStartTime;
849
+ if (!evaluateStartTime) return;
850
+ if (!vexutils.isValidDate(new Date(evaluateStartTime)) && vexutils.isValidDate(new Date(Number(evaluateStartTime)))) {
851
+ evaluateResultSetting.evaluateStartTime = Number(evaluateStartTime);
852
+ }
853
+ },
854
+ // 量表提交数据
855
+ defaultFormValue(formArray) {
856
+ const formData = {};
857
+ let val;
858
+ formArray.forEach(item => {
859
+ const key = this.formKey(item);
860
+ const { type } = item;
861
+ let defValue;
862
+ if (item.dbValue) {
863
+ defValue = item.dbValue;
864
+ } else {
865
+ if (item.setting?.defValType == 3) {
866
+ let urlKey = item.setting?.outDefaultValue?.urlKey;
867
+ if (urlKey) {
868
+ let list = urlKey.split(',');
869
+ if (list.length > 1) {
870
+ let val = list
871
+ .map(l => {
872
+ let tempV = this.getQueryVariable(l);
873
+ if (tempV) return decodeURIComponent(tempV);
874
+ return null;
875
+ })
876
+ .filter(Boolean);
877
+ val.length && (defValue = val);
878
+ } else {
879
+ let val = this.getQueryVariable(list[0]);
880
+ if (val) {
881
+ val = decodeURIComponent(val);
882
+ defValue = item.type == 'CHECKBOX_BLOCK' ? val.split() : val;
883
+ }
884
+ }
885
+ }
886
+ }
887
+ }
888
+ switch (type) {
889
+ case 'LOCATION':
890
+ formData[key] = defValue || '';
891
+ break;
892
+ case 'SEARCH_CASCADE':
893
+ formData[key] = defValue || [];
894
+ break;
895
+ case 'ADDRESS':
896
+ formData[key] = defValue || '';
897
+ this.defaultAddress = defValue || {};
898
+ break;
899
+ case 'LABEL':
900
+ formData[key] = defValue || {};
901
+ if (vexutils.isObject(defValue)) {
902
+ this.labelSelectedList = defValue?.labels || [];
903
+ } else if (Array.isArray(defValue)) {
904
+ this.labelSelectedList = defValue;
905
+ } else {
906
+ this.labelSelectedList = [];
907
+ }
908
+ break;
909
+ case 'TITLE':
910
+ formData[key] = item.title;
911
+ break;
912
+ case 'IMGCARD':
913
+ formData[key] = item.setting?.imgUrl || '';
914
+ break;
915
+ case 'UPFILE':
916
+ case 'UPPICTURE':
917
+ formData[key] = defValue || [];
918
+ break;
919
+ // 自定义列表特殊处理
920
+ case 'CHECKBOX_BLOCK':
921
+ if (defValue && !Array.isArray(defValue) && this.type === 'customList') {
922
+ formData[key] = defValue.split(',').filter(ii => !!ii);
923
+ } else {
924
+ val = defValue || item.setting.defaultValue;
925
+ if (vexutils.isJSON(val)) {
926
+ val = JSON.parse(val);
927
+ }
928
+ formData[key] = val;
929
+ }
930
+ break;
931
+ default:
932
+ val = defValue || item.setting.defaultValue;
933
+ if (vexutils.isJSON(val)) {
934
+ val = JSON.parse(val);
935
+ }
936
+ formData[key] = val;
937
+ break;
938
+ }
939
+ });
940
+ return formData;
941
+ },
942
+ // 解析传参组件
943
+ compileSpreadParams(spreadParams) {
944
+ return spreadParams.domains.map(v => {
945
+ let obj = {};
946
+ if (v.valueType == '1') {
947
+ obj[v.name] = v.value;
948
+ } else if (v.valueType == '2') {
949
+ obj[v.name] = this.getQueryVariable(v.value);
950
+ }
951
+ return obj;
952
+ });
953
+ },
954
+ // 获取url链接参数
955
+ getQueryVariable(variable) {
956
+ let query = {};
957
+ if (this.source == 'layout') {
958
+ // 按钮传参
959
+ query = this.params;
960
+ } else {
961
+ query = this.handleQueryParams() || {};
962
+ }
963
+ if (!query) return false;
964
+ return query[variable] || false;
965
+ },
966
+ // 初始化量表
967
+ formatArray(list) {
968
+ let i = 1;
969
+ const results = list.map(item => {
970
+ const key = this.formKey(item);
971
+ let title = (key || '').replace(/\n/g, '');
972
+ this.$set(item, 'showTitle', item.title);
973
+ // 表单校验rule prop如果有 . 会报错, 替换成 ~-~
974
+ if (title.includes('.')) {
975
+ let newTitle = title.replace(/\./g, '~-~');
976
+ this.$set(item, 'title', newTitle);
977
+ }
978
+ this.$set(item, 'isShow', true);
979
+ Object.keys(item).forEach(key => {
980
+ if (utils.isJSON(item[key])) {
981
+ if (item.type != 'LOCATION') {
982
+ item[key] = JSON.parse(item[key]);
983
+ }
984
+ }
985
+ });
986
+ const notIndexArr = ['LINEBAR', 'TITLE', 'PROMPT', 'IMGCARD', 'RICH_TEXT'];
987
+ if (notIndexArr.indexOf(item.type) < 0 && !item.hide) {
988
+ this.$set(item, 'softcode', i++);
989
+ }
990
+
991
+ // "RADIO_BLOCK", "CHECKBOX_BLOCK" 将取值value改为key
992
+ if (this.isChoice(item.type)) {
993
+ this.handleFormatOptions(item.options, item.type);
994
+ if (item.type != 'SEARCH_CASCADE') {
995
+ if (item.dbValue) {
996
+ this.nextLogicEvent(item.dbValue, item, results, true);
997
+ } else {
998
+ if (item.setting.defaultValue) {
999
+ this.nextLogicEvent(item.setting.defaultValue, item, results, true);
1000
+ }
1001
+ }
1002
+ }
1003
+ }
1004
+ return item;
1005
+ });
1006
+ return results.map(item => {
1007
+ // 题目关联
1008
+ let relationLogicObj = utils.isString(item.relationLogic) ? JSON.parse(item.relationLogic) : item.relationLogic;
1009
+ this.handleRelationLogic(list, relationLogicObj);
1010
+
1011
+ // 跳题逻辑
1012
+ this.handLenextLogic(item);
1013
+
1014
+ // 自定义列表特殊处理
1015
+ if (item.type === 'CHECKBOX_BLOCK' && item.dbValue && !Array.isArray(item.dbValue) && this.type === 'customList') {
1016
+ item.dbValue = item.dbValue.split(',').filter(ii => !!ii);
1017
+ }
1018
+ return item;
1019
+ });
1020
+ },
1021
+ /**
1022
+ * "RADIO_BLOCK", "CHECKBOX_BLOCK" 将取值value改为key, relationLogic需要重新处理
1023
+ */
1024
+ handleRelationLogic(list, relationLogicObj) {
1025
+ let { condition } = relationLogicObj || {};
1026
+ if (!condition || !condition.length) return;
1027
+ condition.forEach(c => {
1028
+ let matchItem = list.find(f => f.seq == c.subject_seq);
1029
+ if (!matchItem) return;
1030
+ let isChoice = this.isRadioOrCheckBox(matchItem.options, matchItem.type);
1031
+ if (!isChoice) return;
1032
+ let value = c.value;
1033
+ if (Array.isArray(value)) {
1034
+ value = value.map(v => {
1035
+ return this.replaceConditionItem(matchItem.options, v);
1036
+ });
1037
+ c.value = value;
1038
+ } else {
1039
+ c.value = this.replaceConditionItem(matchItem.options, value);
1040
+ }
1041
+ });
1042
+ },
1043
+ /**
1044
+ * "RADIO_BLOCK", "CHECKBOX_BLOCK" 将取值value改为key, nextLogic需要重新处理
1045
+ */
1046
+ handLenextLogic(item) {
1047
+ let { nextLogic, options, type } = item || {};
1048
+ let isChoice = this.isRadioOrCheckBox(options, type);
1049
+ if (!nextLogic || !isChoice) return;
1050
+ let { condition } = nextLogic || {};
1051
+ if (!condition || !condition.length) return;
1052
+ condition.forEach(c => {
1053
+ let value = c.value;
1054
+ if (Array.isArray(value)) {
1055
+ value = value.map(v => {
1056
+ return this.replaceConditionItem(options, v);
1057
+ });
1058
+ c.value = value;
1059
+ } else {
1060
+ c.value = this.replaceConditionItem(options, value);
1061
+ }
1062
+ });
1063
+ },
1064
+ replaceConditionItem(options, value) {
1065
+ let matchOption = options.find(v => value === v.value);
1066
+ if (!matchOption) return value;
1067
+ return matchOption.key;
1068
+ },
1069
+ isRadioOrCheckBox(options, type) {
1070
+ let typeArr = ['RADIO_BLOCK', 'CHECKBOX_BLOCK'];
1071
+ if (!typeArr.includes(type)) return;
1072
+ if (!options) return;
1073
+ if (options && utils.isJSON(options)) {
1074
+ options = JSON.parse(options);
1075
+ }
1076
+ if (!options.length) return;
1077
+ return true;
1078
+ },
1079
+ handleFormatOptions(options, type) {
1080
+ let isChoice = this.isRadioOrCheckBox(options, type);
1081
+ if (!isChoice) return;
1082
+
1083
+ options.forEach((item, i) => {
1084
+ if (item.key !== 'other') {
1085
+ item.key = i + 1;
1086
+ }
1087
+ if (item.prefix || item.suffix) {
1088
+ item.value = item.prefix || item.suffix;
1089
+ }
1090
+ });
1091
+ },
1092
+ // 初始化rules
1093
+ formatRules(formArray) {
1094
+ const rules = {};
1095
+ formArray.forEach(item => {
1096
+ let newTitle = this.formKey(item);
1097
+ // 表单校验rule prop如果有 . 会报错, 替换成 ~-~
1098
+ if (newTitle.includes('.')) {
1099
+ newTitle = newTitle.replace(/\./g, '~-~');
1100
+ }
1101
+ rules[newTitle] = [{ required: item.required, message: '必填', trigger: 'change' }];
1102
+ if (item.type == 'MOBILE' && item.validation) {
1103
+ rules[newTitle].push({
1104
+ pattern: /^1[3456789]\d{9}$/,
1105
+ message: '格式错误',
1106
+ trigger: 'blur'
1107
+ });
1108
+ } else if (item.type == 'ID_CARD' && item.validation) {
1109
+ rules[newTitle].push({
1110
+ pattern: /^\d{6}(((19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{3}([0-9]|x|X))|(\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])\d{3}))$/,
1111
+ message: '格式错误',
1112
+ trigger: 'blur'
1113
+ });
1114
+ } else if (item.type == 'ADDRESS' && item.required) {
1115
+ if (this.handleAddressType(item)) {
1116
+ rules[newTitle].push({
1117
+ validator: this.checkAdress,
1118
+ trigger: 'change'
1119
+ });
1120
+ }
1121
+ } else if (item.type == 'LABEL' && item.required) {
1122
+ rules[newTitle].push({
1123
+ validator: this.checkLabel,
1124
+ trigger: 'change'
1125
+ });
1126
+ } else if (item.type == 'DATETIME' && this.type == 'customList') {
1127
+ // 自定义列表特殊处理日期时间 最大值
1128
+ // dateMaxType 1当前日期时间 2指定日期时间 3其他日期时间字段
1129
+ let dateMaxType = this.handleDateMaxType(item);
1130
+ if (!dateMaxType) return;
1131
+ let obj = {
1132
+ 1: 'checkDateMaxCur',
1133
+ 2: 'checkDateMaxSet',
1134
+ 3: 'checkDateMaxOther'
1135
+ };
1136
+ let methodName = obj[dateMaxType];
1137
+ rules[newTitle].push({
1138
+ validator: (rule, value, callback) => this[methodName](rule, value, callback, item),
1139
+ trigger: 'change'
1140
+ });
1141
+ } else if (item.type === 'RADIO_BLOCK') {
1142
+ this.choiceComObj[this.formKey(item)] = {};
1143
+ rules[newTitle].push({
1144
+ validator: (rule, value, callback) => this.checkRadio(rule, value, callback, item),
1145
+ trigger: 'change'
1146
+ });
1147
+ } else if (item.type === 'CHECKBOX_BLOCK') {
1148
+ this.choiceComObj[this.formKey(item)] = {};
1149
+ rules[newTitle].push({
1150
+ validator: (rule, value, callback) => this.checkCheckbox(rule, value, callback, item),
1151
+ trigger: 'change'
1152
+ });
1153
+ }
1154
+ });
1155
+ return rules;
1156
+ },
1157
+ handleAddressType(item) {
1158
+ let setObj = { addressType: 'province-city-district-address' };
1159
+ if (utils.isJSON(item.setting)) {
1160
+ setObj = JSON.parse(item.setting);
1161
+ } else {
1162
+ setObj = item.setting;
1163
+ }
1164
+ let isAdress = setObj.addressType.includes('address');
1165
+ return isAdress;
1166
+ },
1167
+ checkAdress(rule, value, callback) {
1168
+ let { address } = value || {};
1169
+ if (!address) {
1170
+ return callback(new Error('必填'));
1171
+ }
1172
+ callback();
1173
+ },
1174
+ checkLabel(rule, value, callback) {
1175
+ if (!value || !Object.keys(value).length) {
1176
+ return callback(new Error('必填'));
1177
+ }
1178
+ let { labelStr, labels = [] } = value;
1179
+ if (!labelStr || !labels.length) {
1180
+ return callback(new Error('必填'));
1181
+ }
1182
+ callback();
1183
+ },
1184
+ handleDateMaxType(item) {
1185
+ let setObj = item.setting;
1186
+ if (utils.isJSON(setObj)) {
1187
+ setObj = JSON.parse(setObj);
1188
+ }
1189
+ return setObj.dateMaxType;
1190
+ },
1191
+ // 自定义列表 日期时间 max 当前日期时间
1192
+ checkDateMaxCur(rule, value, callback, item) {
1193
+ if (!value) return callback();
1194
+ let { dateType } = item.setting;
1195
+ if (!dateType) return callback();
1196
+ let dateMaxValue = this.currentTime;
1197
+ if (dateType == 'time') {
1198
+ dateMaxValue = this.currentTime.format('HH:mm:ss');
1199
+ }
1200
+ let isMax = this.handleMax(dateType, value, dateMaxValue);
1201
+ if (!isMax) {
1202
+ return callback(new Error('最大不能超过当前日期时间'));
1203
+ }
1204
+ callback();
1205
+ },
1206
+ // 自定义列表 日期时间 max 指定日期时间
1207
+ checkDateMaxSet(rule, value, callback, item) {
1208
+ if (!value) return callback();
1209
+ let { dateMaxValue, dateType } = item.setting;
1210
+ if (!dateMaxValue || !dateType) return callback();
1211
+ let isMax = this.handleMax(dateType, value, dateMaxValue);
1212
+ if (!isMax) {
1213
+ return callback(new Error('最大不能超过指定日期时间'));
1214
+ }
1215
+ callback();
1216
+ },
1217
+ // 自定义列表 日期时间 max 其他日期时间字段
1218
+ checkDateMaxOther(rule, value, callback, item) {
1219
+ if (!value) return callback();
1220
+ let { outDateMaxValue, dateType } = item.setting;
1221
+ if (!outDateMaxValue || !dateType) return callback();
1222
+ let matchDateItem = this.formArray.find(v => v.seq === outDateMaxValue);
1223
+ if (!matchDateItem || matchDateItem.hide) return callback();
1224
+ let matchValue = this.form[this.formKey(matchDateItem)];
1225
+ if (!matchValue) return;
1226
+ let isMax = this.handleMax(dateType, value, matchValue);
1227
+ if (!isMax) {
1228
+ return callback(new Error(`最大不能超过【${matchDateItem.title}】日期时间`));
1229
+ }
1230
+ callback();
1231
+ },
1232
+ checkRadio(rule, value, callback, item) {
1233
+ if (!value) return callback();
1234
+ let { options } = item;
1235
+ if (!options.length || value === 'other') return callback();
1236
+ const key = this.formKey(item);
1237
+ let { optionsPreSuffixObj = {} } = this.choiceComObj[key] || {};
1238
+ let matchItem = options.find((o, i) => {
1239
+ if (i + 1 === value) {
1240
+ return true;
1241
+ }
1242
+ return false;
1243
+ });
1244
+ if (!matchItem || matchItem.importability) return callback();
1245
+ if (matchItem.prefix || matchItem.suffix) {
1246
+ let inputValue = optionsPreSuffixObj[value];
1247
+ if (!inputValue) {
1248
+ return callback(new Error(`请完善选项`));
1249
+ }
1250
+ }
1251
+ callback();
1252
+ },
1253
+ checkCheckbox(rule, value, callback, item) {
1254
+ if (!value || !value.length) return callback();
1255
+ let { options } = item;
1256
+ if (!options.length) return callback();
1257
+ let i = 0,
1258
+ len = value.length,
1259
+ v;
1260
+ const key = this.formKey(item);
1261
+ let { optionsPreSuffixObj = {} } = this.choiceComObj[key] || {};
1262
+ for (; i < len; i++) {
1263
+ v = value[i];
1264
+ if (v === 'other') continue;
1265
+ let matchItem = options.find((o, j) => {
1266
+ if (j + 1 === v) {
1267
+ return true;
1268
+ }
1269
+ return false;
1270
+ });
1271
+ if (!matchItem || matchItem.importability) continue;
1272
+
1273
+ if (matchItem.prefix || matchItem.suffix) {
1274
+ let inputValue = optionsPreSuffixObj[v];
1275
+ if (!inputValue) {
1276
+ return callback(new Error(`请完善选项`));
1277
+ }
1278
+ }
1279
+ }
1280
+ callback();
1281
+ },
1282
+ handleMax(dateType, value, dateMaxValue) {
1283
+ let curValue = '';
1284
+ let tempValue = '';
1285
+ if (dateType == 'time') {
1286
+ let curYMD = this.currentTime.format('YYYY MM DD ');
1287
+ curValue = moment(curYMD + dateMaxValue).valueOf();
1288
+ tempValue = moment(curYMD + value).valueOf();
1289
+ } else if (dateType == 'date') {
1290
+ curValue = moment(dateMaxValue).valueOf();
1291
+ tempValue = moment(value).valueOf();
1292
+ } else {
1293
+ curValue = moment(dateMaxValue).valueOf();
1294
+ tempValue = moment(value).valueOf();
1295
+ }
1296
+ if (tempValue > curValue) {
1297
+ return false;
1298
+ }
1299
+ return true;
1300
+ },
1301
+ handleGetAddress(val) {
1302
+ if (utils.isJSON(val)) {
1303
+ const valObj = JSON.parse(val);
1304
+ return valObj.address || valObj.name;
1305
+ }
1306
+ return '';
1307
+ },
1308
+ handleSelectLocation(e, item) {
1309
+ const { locationProp, isInit } = e;
1310
+ this.mapLocation = locationProp;
1311
+ const key = this.formKey(item);
1312
+ this.form[key] = locationProp;
1313
+ this.mapVisible = isInit || false;
1314
+ },
1315
+ isInput(type) {
1316
+ return type == 'INPUT' || type == 'ID_CARD' || type == 'MOBILE' || type == 'EVALUATE_INPUT';
1317
+ },
1318
+ isChoice(type) {
1319
+ return (
1320
+ type == 'SELECT' ||
1321
+ type == 'RADIO_BLOCK' ||
1322
+ type == 'CHECKBOX_BLOCK' ||
1323
+ type == 'SEARCH_CASCADE' ||
1324
+ type == 'EVALUATE_RADIO_BLOCK' ||
1325
+ type == 'EVALUATE_CHECKBOX_BLOCK' ||
1326
+ type == 'EVALUATE_SELECT'
1327
+ );
1328
+ },
1329
+ isTime(type) {
1330
+ return type == 'DATE' || type == 'TIME' || type == 'DATETIME';
1331
+ },
1332
+ isUpload(type) {
1333
+ return type == 'UPFILE' || type == 'UPPICTURE';
1334
+ },
1335
+ writeGuage(showCountdown) {
1336
+ this.showEvaluateSettingWrap = false;
1337
+ this.showEvaluateCountdown = showCountdown;
1338
+ },
1339
+ closeEvaluateCountdown() {
1340
+ // 倒计时结束自动提交 无需校验
1341
+ this.showEvaluateCountdown = false;
1342
+ if (this.isPreviewScale) return;
1343
+ this.banSubmit = true;
1344
+ this.submitMethod();
1345
+ this.$warning({
1346
+ title: '温馨提示',
1347
+ content: '测评时间到了,结束测评!',
1348
+ okText: '确定',
1349
+ onOk: () => {}
1350
+ });
1351
+ },
1352
+ async showEvaTipModal(item) {
1353
+ if (this.evatipMap[item.id]) {
1354
+ this.evatipConfirm(this.evatipMap[item.id]);
1355
+ return;
1356
+ }
1357
+ let key = 'getSubjectAnswer';
1358
+ const fn = this.scaleApiConfig?.[key] || null;
1359
+ if (!fn || typeof fn !== 'function') {
1360
+ this.$message.error(`${key} Is not a function`);
1361
+ return;
1362
+ }
1363
+ let obj = await fn(item.id);
1364
+ if (!obj) return;
1365
+ if (!this.evatipMap[item.id]) {
1366
+ this.evatipMap[item.id] = obj;
1367
+ this.evatipConfirm(obj);
1368
+ }
1369
+ },
1370
+ closeTip() {
1371
+ this.$destroyAll();
1372
+ },
1373
+ evatipConfirm(str) {
1374
+ let _this = this;
1375
+ let content = h => (
1376
+ <div class="evatip-container">
1377
+ <a-icon type="close" class="tip-content-close" on-click={_this.closeTip} />
1378
+ <span>答案解析:</span>
1379
+ <p>{str}</p>
1380
+ </div>
1381
+ );
1382
+ this.$confirm({
1383
+ title: '提示',
1384
+ icon: () => null,
1385
+ content,
1386
+ okText: '确定',
1387
+ cancelText: '关闭',
1388
+ onOk() {},
1389
+ onCancel() {},
1390
+ class: 'evatip-modal-wrap'
1391
+ });
1392
+ },
1393
+ // 选择组件
1394
+ handleChoice(choiceValue, formItem) {
1395
+ let { value = '', list = [] } = choiceValue;
1396
+ this.nextLogicEvent(value, formItem, this.formArray);
1397
+ this.handleDynamicDataRelation(list, formItem, this.formArray);
1398
+ },
1399
+ // 下拉框 动态数据源关联字段
1400
+ handleDynamicDataRelation(list, formItem, formArray) {
1401
+ let { targetSource } = formItem;
1402
+ if (!targetSource || !Object.keys(targetSource).length) return;
1403
+ if (!targetSource.target_id) return;
1404
+ let { relationParam = [] } = targetSource;
1405
+ if (!relationParam.length) return;
1406
+ relationParam.forEach(item => {
1407
+ let matchEle = formArray.find(v => v.seq === item.relationElement);
1408
+ const key = this.formKey(matchEle);
1409
+ if (matchEle) {
1410
+ if (!list.length) {
1411
+ this.form[key] = '';
1412
+ } else {
1413
+ let relationFieldList = list.map(v => v[item.relationField] || '/') || '';
1414
+ this.form[key] = relationFieldList.join(',');
1415
+ }
1416
+ }
1417
+ });
1418
+ },
1419
+ // 设置的logic condition 最大next_subject
1420
+ handleLogicMaxNext(condition = []) {
1421
+ const arr = condition.map(({ next_subject }) => (next_subject == 'end' ? 9999 : +(next_subject || 9999)));
1422
+ const max = Math.max.call(null, ...arr);
1423
+ return max;
1424
+ },
1425
+ // 当前formItem 下一个触发logicCodition item 的seq
1426
+ handleLogicList(formItem, formArray) {
1427
+ const { seq } = formItem;
1428
+ let list = formArray.map(item => {
1429
+ if (item.seq > seq && item.isShow && item.__isLogic__) return item;
1430
+ return false;
1431
+ });
1432
+ let nextItemMax = 0;
1433
+ let i = 0,
1434
+ len = list.length,
1435
+ item;
1436
+ for (; i < len; i++) {
1437
+ item = list[i];
1438
+ let curVal = this.form[this.formKey(item)];
1439
+ if (!curVal) continue;
1440
+ if (Array.isArray(curVal)) {
1441
+ if (!curVal.length) continue;
1442
+ }
1443
+ const { nextLogic, seq, __isLogic__, __lastSeq__ } = item;
1444
+ if (!nextLogic.next_logic_is || !nextLogic.condition.length) continue;
1445
+ if (__lastSeq__) {
1446
+ nextItemMax = __lastSeq__;
1447
+ break;
1448
+ }
1449
+ }
1450
+ return nextItemMax;
1451
+ },
1452
+ // 跳题逻辑
1453
+ nextLogicEvent(choiceValue, formItem, formArray = [], isInit) {
1454
+ const { nextLogic, seq } = formItem;
1455
+ if (!nextLogic) return;
1456
+ if (nextLogic.next_logic_is && nextLogic.condition.length) {
1457
+ let nextMax = 9999,
1458
+ nextItemMax = 0;
1459
+ if (!isInit) {
1460
+ nextMax = this.handleLogicMaxNext(nextLogic.condition);
1461
+ nextItemMax = this.handleLogicList(formItem, formArray);
1462
+ }
1463
+ nextLogic.condition.some(con => {
1464
+ const { value, next_subject } = con;
1465
+ const lastSeq = next_subject == 'end' ? 9999 : next_subject;
1466
+ if (nextItemMax && nextItemMax > seq && nextItemMax < nextMax) {
1467
+ nextMax = nextItemMax;
1468
+ }
1469
+ if (nextLogic.next_logic == 'condition') {
1470
+ let hasValue = false;
1471
+ if (Array.isArray(choiceValue)) {
1472
+ hasValue = choiceValue.includes(value);
1473
+ } else {
1474
+ hasValue = choiceValue === value;
1475
+ }
1476
+
1477
+ // 添加非响应式key __isLogic__ __lastSeq__
1478
+ Object.defineProperty(formItem, '__isLogic__', {
1479
+ value: hasValue,
1480
+ writable: true
1481
+ });
1482
+ Object.defineProperty(formItem, '__lastSeq__', {
1483
+ value: seq + 1,
1484
+ writable: true
1485
+ });
1486
+
1487
+ if (hasValue) {
1488
+ formArray.forEach(item => {
1489
+ if (item.seq > seq && item.seq < lastSeq) {
1490
+ item.isShow = false;
1491
+ // 跳过时 清空已填内容
1492
+ const key = this.formKey(item);
1493
+ this.form[key] && (this.form[key] = '');
1494
+ } else if (item.seq >= lastSeq && item.seq < nextMax) {
1495
+ this.$set(item, 'isShow', true);
1496
+ }
1497
+ });
1498
+ return true;
1499
+ } else {
1500
+ formArray.forEach(item => {
1501
+ if (item.seq > seq && item.seq < lastSeq) {
1502
+ item.isShow = true;
1503
+ }
1504
+ });
1505
+ }
1506
+ } else if (nextLogic.next_logic == 'uncondition') {
1507
+ let res = utils.isEmpty(choiceValue);
1508
+
1509
+ // 添加非响应式key __isLogic__ __lastSeq__
1510
+ Object.defineProperty(formItem, '__isLogic__', {
1511
+ value: !res,
1512
+ writable: true
1513
+ });
1514
+ Object.defineProperty(formItem, '__lastSeq__', {
1515
+ value: seq + 1,
1516
+ writable: true
1517
+ });
1518
+
1519
+ formArray.forEach(item => {
1520
+ const key = this.formKey(item);
1521
+ if (item.seq > seq && item.seq < lastSeq) {
1522
+ item.isShow = res;
1523
+ // 跳过时 清空已填内容
1524
+ if (!res) {
1525
+ this.form[key] && (this.form[key] = '');
1526
+ }
1527
+ }
1528
+ });
1529
+ }
1530
+ });
1531
+ }
1532
+ },
1533
+ // 关联逻辑
1534
+ showEvent(formItem, isSubmitCallback) {
1535
+ if (formItem.hide) return false;
1536
+ const { form } = this;
1537
+ let relationLogicObj = {};
1538
+ // 回调接口
1539
+ if (isSubmitCallback) {
1540
+ let setting = formItem.setting;
1541
+ if (formItem.setting && utils.isJSON(formItem.setting)) {
1542
+ setting = JSON.parse(formItem.setting);
1543
+ }
1544
+ relationLogicObj = utils.isString(setting.callbackCondition) ? JSON.parse(setting.callbackCondition) : setting.callbackCondition;
1545
+ if (!relationLogicObj || !relationLogicObj.condition || !relationLogicObj.condition.length) return true;
1546
+ } else {
1547
+ relationLogicObj = utils.isString(formItem.relationLogic) ? JSON.parse(formItem.relationLogic) : formItem.relationLogic;
1548
+ }
1549
+ if (!relationLogicObj || !Object.keys(relationLogicObj).length) return true;
1550
+ const { relation_logic_is, condition, relation_logic } = relationLogicObj;
1551
+ if (relation_logic_is) {
1552
+ const results = condition.map(c => {
1553
+ let key = this.formKey(this.formArray.filter(f => f.seq == c.subject_seq)[0]);
1554
+ if (utils.isArray(form[key])) {
1555
+ return form[key].some(v => c.value.includes(v));
1556
+ } else {
1557
+ return c.value.includes(form[key]);
1558
+ }
1559
+ });
1560
+ if (relation_logic == 'OR') {
1561
+ formItem.isShow = results.some(el => el);
1562
+ } else if (relation_logic == 'AND') {
1563
+ formItem.isShow = results.every(el => el);
1564
+ } else {
1565
+ formItem.isShow = results[0];
1566
+ }
1567
+ }
1568
+ return formItem.isShow;
1569
+ },
1570
+ // 单选组件回调
1571
+ radioChange(val, item, obj) {
1572
+ const key = this.formKey(item);
1573
+ this.form[key] = val;
1574
+ item.type === 'RADIO_BLOCK' && this.$set(this.choiceComObj, key, obj);
1575
+ this.nextLogicEvent(val, item, this.formArray);
1576
+ },
1577
+ // 多选组件回调
1578
+ checkboxChange(val, item, obj) {
1579
+ const key = this.formKey(item);
1580
+ this.form[key] = val;
1581
+ item.type === 'CHECKBOX_BLOCK' && this.$set(this.choiceComObj, key, obj);
1582
+ this.nextLogicEvent(val, item, this.formArray);
1583
+ },
1584
+ // 标签组件回调
1585
+ labelChange(labelList, item) {
1586
+ const key = this.formKey(item);
1587
+ this.form[key] = this.handleGetLabelSubmit(labelList);
1588
+ },
1589
+ // 视频组件回调
1590
+ vodFileList(list, item) {
1591
+ const key = this.formKey(item);
1592
+ this.form[key] = list;
1593
+ },
1594
+ handleGetLabelSubmit(labelSelectedList) {
1595
+ if (!labelSelectedList || !labelSelectedList.length)
1596
+ return {
1597
+ labelStr: '',
1598
+ labels: []
1599
+ };
1600
+ const selectedList = labelSelectedList || [];
1601
+ const labelStrList = [];
1602
+ const labels = [];
1603
+ // "cacheKey":"label_标签","isSelect":true
1604
+ selectedList.forEach(v => {
1605
+ labels.push(v);
1606
+ labelStrList.push(v.labelName);
1607
+ });
1608
+ this.labelSelectedList = selectedList;
1609
+ return {
1610
+ labelStr: labelStrList.join(','),
1611
+ labels: labels
1612
+ };
1613
+ },
1614
+ // 地址回调
1615
+ changeAddress(allValue, item) {
1616
+ const key = this.formKey(item);
1617
+ this.form[key] = allValue;
1618
+ },
1619
+ // 上传回调
1620
+ changeUpload(value, item) {
1621
+ const key = this.formKey(item);
1622
+ this.form[key] = value;
1623
+ },
1624
+ // 时间回调
1625
+ changeTime(value, item) {
1626
+ const key = this.formKey(item);
1627
+ this.form[key] = value;
1628
+ this.submitForm[key] = value;
1629
+ },
1630
+ // 保存
1631
+ onSubmit() {
1632
+ // 不包含测评组件,点击提交,弹出二次确认对话框,确认要提交吗?
1633
+ let hasEvaluate = this.formArray.find(item => this.isEvaluation(item.type));
1634
+ if (!hasEvaluate) {
1635
+ this.confirmSubmit('确认要提交吗?');
1636
+ return;
1637
+ }
1638
+
1639
+ // 包含测评组件,不包含考试时长,点击提交,弹出二次确认对话框,确认要结束测评吗?
1640
+ // 判断有无测评配置 并且在测评时间内
1641
+ let { evaluateResultSetting } = this.config;
1642
+ if (!evaluateResultSetting || (!Object.keys(evaluateResultSetting).length && !this.showEvaluateEntry)) {
1643
+ this.confirmSubmit('确认要结束测评吗?');
1644
+ return;
1645
+ }
1646
+
1647
+ // 表单内嵌量表, 没有开始答题, 不需要调用保存接口
1648
+ if (this.openType == 'formIframe' && this.showEvaluateEntry) {
1649
+ this.$emit('submitNoRequest');
1650
+ return;
1651
+ }
1652
+
1653
+ // 无倒计时
1654
+ let countdownDom = this.$refs.evaluateCountdown;
1655
+ if (!countdownDom?.showEvaluateCountdown) {
1656
+ this.confirmSubmit('确认要结束测评吗?');
1657
+ return;
1658
+ }
1659
+
1660
+ // 在倒计时内
1661
+ let message = '确认要提前结束测评吗?';
1662
+ let setAnswered = this.$refs.evaluateCountdown?.setAnswered;
1663
+ let totalLen = this.$refs.evaluateCountdown?.totalLen;
1664
+ // 存在未解答题目
1665
+ if (setAnswered < totalLen) {
1666
+ message = '存在未解答的题目,确定要提前结束吗?';
1667
+ }
1668
+ this.confirmSubmit(message);
1669
+ },
1670
+ confirmSubmit(message) {
1671
+ let _this = this;
1672
+ this.$confirm({
1673
+ title: '温馨提示',
1674
+ content: message,
1675
+ okText: '确定',
1676
+ cancelText: '取消',
1677
+ onOk: () => {
1678
+ _this.onSubmitForm();
1679
+ },
1680
+ onCancel() {}
1681
+ });
1682
+ },
1683
+ onSubmitForm() {
1684
+ this.$refs['ruleForm'].validate((valid, keys) => {
1685
+ if (valid) {
1686
+ this.submitMethod();
1687
+ } else {
1688
+ if (Object.keys(keys).length > 0) {
1689
+ let key = Object.keys(keys)[0];
1690
+ let field = keys[key][0].field,
1691
+ message = keys[key][0].message;
1692
+ let matchItem = this.formArray.find(v => v.databaseTitle === field);
1693
+ if (matchItem) {
1694
+ field = matchItem.title;
1695
+ }
1696
+ this.$message.error(field + message);
1697
+ }
1698
+ return false;
1699
+ }
1700
+ });
1701
+ },
1702
+ submitMethod() {
1703
+ const hasSpreadParams = this.defaultFormArray.find(v => v.type === 'SPREAD_PARAMS');
1704
+ if (hasSpreadParams) {
1705
+ if (utils.isJSON(hasSpreadParams.setting)) {
1706
+ hasSpreadParams.setting = JSON.parse(hasSpreadParams.setting);
1707
+ }
1708
+ let spreadKey = this.formKey(hasSpreadParams);
1709
+ this.submitForm[spreadKey] = this.compileSpreadParams(hasSpreadParams.setting.spreadParams);
1710
+ }
1711
+ // 自定义列表新增时多选特殊处理
1712
+ let checkBoxKey = this.defaultFormArray.find(ii => ii.type == 'CHECKBOX_BLOCK');
1713
+ if (checkBoxKey && Array.isArray(this.form[checkBoxKey.title]) && this.type === 'customList') {
1714
+ this.form[checkBoxKey.title] = this.form[checkBoxKey.title].join(',');
1715
+ }
1716
+ const scoreJson = this.handleScoreJson();
1717
+ let params;
1718
+ if (this.type === 'customList') {
1719
+ params = {
1720
+ definedListId: this.ids.guage_id,
1721
+ dbId: this.ids.db_id,
1722
+ scoreJson: JSON.stringify(scoreJson)
1723
+ };
1724
+ } else {
1725
+ const { guageId, randomId } = this.config;
1726
+ params = Object.assign(this.params, {
1727
+ guageId,
1728
+ scoreJson: JSON.stringify(scoreJson),
1729
+ randomId
1730
+ });
1731
+ }
1732
+ if (this.shareId) {
1733
+ params.shareId = this.shareId;
1734
+ }
1735
+ const tipSetting = this.defaultFormArray.find(item => item.type === 'SUCCESS_TIP');
1736
+ if (tipSetting) {
1737
+ // 提交保存成功提示设置
1738
+ const tip = utils.isJSON(tipSetting.setting) ? JSON.parse(tipSetting.setting) : tipSetting.setting;
1739
+ params.tipSetting = JSON.stringify({
1740
+ tipMode: tip.tipMode,
1741
+ tipType: tip.tipType,
1742
+ tipText: tip.tipText,
1743
+ tipApi: tip.tipApi
1744
+ });
1745
+ }
1746
+ let hasCallbackItem = this.defaultFormArray.find(v => v.type === 'CALLBACK_INTERFACE');
1747
+ let isCallback = false;
1748
+ if (hasCallbackItem) {
1749
+ isCallback = this.showEvent(hasCallbackItem, true);
1750
+ }
1751
+ /**
1752
+ * NOTE:
1753
+ * 提交数据往外推
1754
+ */
1755
+ this.$emit('onSubmit', params, hasCallbackItem, isCallback);
1756
+ },
1757
+ handleScoreJson() {
1758
+ let tempObj = Object.assign({}, this.form, this.submitForm);
1759
+ let res = {};
1760
+ if (!Object.keys(tempObj).length) return {};
1761
+ for (let key in tempObj) {
1762
+ let itemTemp = this.formArray.find(item => this.formKey(item) == key);
1763
+ let curValue = tempObj[key];
1764
+ if (key && itemTemp) {
1765
+ let keyTemp;
1766
+ if (itemTemp && itemTemp.databaseTitle) keyTemp = itemTemp.databaseTitle;
1767
+ if (this.type == 'customList' && itemTemp && itemTemp.setting && itemTemp.setting.startToStop != 1 && curValue && itemTemp.type == 'DATETIME') {
1768
+ if (itemTemp.setting && itemTemp.setting.dateType == 'time' && curValue) curValue = moment().format('YYYY-MM-DD ') + curValue;
1769
+ if (itemTemp.setting && itemTemp.setting.dateType == 'date' && curValue) curValue = moment(curValue).format('YYYY-MM-DD ') + moment().format('HH:mm:ss');
1770
+ }
1771
+
1772
+ // 处理choice选项 将key替换为value
1773
+ let isChoice = ['RADIO_BLOCK', 'CHECKBOX_BLOCK'].includes(itemTemp.type);
1774
+ if (isChoice) {
1775
+ let { options } = itemTemp;
1776
+ let obj = this.choiceComObj[key];
1777
+ if (itemTemp.type === 'RADIO_BLOCK' && curValue) {
1778
+ curValue = this.handleChoiceItem(curValue, options, obj);
1779
+ }
1780
+ if (itemTemp.type === 'CHECKBOX_BLOCK' && curValue?.length) {
1781
+ let resArr = this.handleCheckboxParams(curValue, options, obj);
1782
+ curValue = resArr;
1783
+ }
1784
+ }
1785
+
1786
+ if (key.includes('~-~')) {
1787
+ let newKey = keyTemp ? keyTemp.replace(/~-~/g, '.') : key.replace(/~-~/g, '.');
1788
+ res[newKey] = curValue;
1789
+ } else {
1790
+ res[keyTemp || key] = !curValue ? null : curValue;
1791
+ }
1792
+ } else {
1793
+ res[key] = curValue;
1794
+ }
1795
+ }
1796
+ console.log('res', res);
1797
+ return res;
1798
+ },
1799
+ handleCheckboxParams(value, options, obj) {
1800
+ let res = [];
1801
+ let i = 0,
1802
+ len = value.length,
1803
+ v;
1804
+ for (; i < len; i++) {
1805
+ v = value[i];
1806
+ let matchItem = options.find((o, i) => {
1807
+ if (i + 1 === v) {
1808
+ return true;
1809
+ }
1810
+ return false;
1811
+ });
1812
+ if (matchItem && !matchItem.prefix && !matchItem.suffix) {
1813
+ res.push(matchItem.value);
1814
+ continue;
1815
+ }
1816
+ let tempValue = this.handleChoiceItem(v, options, obj);
1817
+ res.push(tempValue);
1818
+ }
1819
+ return res;
1820
+ },
1821
+ handleChoiceItem(value, options, obj) {
1822
+ let { othersText, optionsPreSuffixObj = {} } = obj || {};
1823
+ if (value === 'other') {
1824
+ return othersText || '其他';
1825
+ }
1826
+ let matchItem = options.find((o, i) => {
1827
+ if (i + 1 === value) {
1828
+ return true;
1829
+ }
1830
+ return false;
1831
+ });
1832
+ if (!matchItem) return;
1833
+ if (!matchItem.prefix && !matchItem.suffix) return matchItem.value;
1834
+ let resValue = optionsPreSuffixObj[value] || '';
1835
+ if (matchItem.prefix) {
1836
+ resValue = matchItem.prefix + resValue;
1837
+ } else {
1838
+ resValue += matchItem.suffix;
1839
+ }
1840
+ return resValue;
1841
+ },
1842
+ resetForm() {
1843
+ this.$refs.ruleForm.resetFields();
1844
+ },
1845
+ cancel() {
1846
+ this.$emit('onCloseSetting');
1847
+ },
1848
+ handleEvaluationScore(ele) {
1849
+ let { minScore = 0, maxScore = 0, scoreType } = ele.scoreConfigs || {};
1850
+ return `(${maxScore}分)`;
1851
+ }
1852
+ }
1853
+ });
1854
+ </script>
1855
+ <style lang="less" scoped>
1856
+ .r-scale {
1857
+ position: relative;
1858
+ width: 100%;
1859
+ height: 100%;
1860
+ overflow: hidden;
1861
+ padding-top: 4px;
1862
+ padding-bottom: 50px;
1863
+ .scale-container {
1864
+ width: 100%;
1865
+ height: 100%;
1866
+ padding-bottom: 10px;
1867
+ transform-origin: 0 0;
1868
+ overflow-y: auto;
1869
+ box-sizing: border-box;
1870
+ &.scale-container-nopadding {
1871
+ height: 100%;
1872
+ }
1873
+ &::-webkit-scrollbar {
1874
+ width: 10px;
1875
+ }
1876
+ }
1877
+ /deep/ .no-data-tip {
1878
+ width: 100%;
1879
+ height: 100%;
1880
+ }
1881
+ .totalScore-warp {
1882
+ padding: 16px;
1883
+ margin-bottom: 16px;
1884
+ font-weight: 400;
1885
+ color: #666666;
1886
+ background: #f2f2f4;
1887
+ font-size: 14px;
1888
+ border-radius: 6px;
1889
+ div + div {
1890
+ margin-top: 4px;
1891
+ }
1892
+ span {
1893
+ font-weight: 500;
1894
+ color: #090909;
1895
+ }
1896
+ .score-result {
1897
+ color: #2d7aff;
1898
+ }
1899
+ }
1900
+ /deep/ .ant-spin-spinning {
1901
+ height: 100%;
1902
+ width: 100%;
1903
+ padding-top: 88px;
1904
+ }
1905
+ /deep/ .ant-select ~ div {
1906
+ position: relative !important;
1907
+ }
1908
+ // /deep/.ant-select-dropdown {
1909
+ // top: 0px !important;
1910
+ // left: 1px !important;
1911
+ // }
1912
+ .lb-title {
1913
+ text-align: center;
1914
+ }
1915
+ .map-container {
1916
+ cursor: pointer;
1917
+ /deep/ .ant-input-disabled {
1918
+ color: rgba(0, 0, 0, 0.65);
1919
+ background-color: #fff;
1920
+ cursor: pointer;
1921
+ }
1922
+ }
1923
+ .linebar-div {
1924
+ text-align: center;
1925
+ margin-top: 24px;
1926
+ /deep/ .ant-divider {
1927
+ margin-top: -4px;
1928
+ }
1929
+ }
1930
+ .my-prompt {
1931
+ padding: 10px;
1932
+ box-shadow: 0 5px 13px rgba(0, 0, 0, 0.14);
1933
+ background-color: #fff;
1934
+ border-radius: 4px;
1935
+ }
1936
+ .img-card {
1937
+ width: 100%;
1938
+ }
1939
+ }
1940
+ .main {
1941
+ // overflow: auto;
1942
+ // overflow-x: hidden;
1943
+ padding: 0 16px;
1944
+ box-sizing: border-box;
1945
+ /deep/.ant-form-item-required::before {
1946
+ color: #e02828;
1947
+ }
1948
+ .scale-label-required {
1949
+ font-weight: 700;
1950
+ }
1951
+ .required-text {
1952
+ color: #e02828;
1953
+ }
1954
+ .evalute-label {
1955
+ display: inline-block;
1956
+ height: 20px;
1957
+ line-height: 20px;
1958
+ padding: 0 5px;
1959
+ margin-left: 4px;
1960
+ font-size: 12px;
1961
+ color: #2d7aff;
1962
+ border-radius: 4px;
1963
+ border: 1px solid rgba(45, 122, 255, 0.5);
1964
+ background: rgba(45, 122, 255, 0.1);
1965
+ }
1966
+ .evalute-tip {
1967
+ display: inline-block;
1968
+ padding: 0 5px;
1969
+ margin-left: 8px;
1970
+ color: #fe9626;
1971
+ border-radius: 2px;
1972
+ background: rgba(255, 194, 0, 0.15);
1973
+ cursor: pointer;
1974
+ .ant-icon {
1975
+ margin-right: 2px;
1976
+ }
1977
+ }
1978
+ /deep/ .ant-form-item-label {
1979
+ // white-space: break-spaces;
1980
+ white-space: unset;
1981
+ text-align: left;
1982
+ line-height: 20px;
1983
+ padding: 6px 0;
1984
+ width: 100%;
1985
+ .ant-form-item-no-colon {
1986
+ width: 100%;
1987
+ }
1988
+ }
1989
+ }
1990
+ .footer {
1991
+ position: absolute;
1992
+ bottom: 0;
1993
+ left: 0;
1994
+ width: 100%;
1995
+ border-top: 1px solid #e8e8e8;
1996
+ padding-top: 12px;
1997
+ height: 50px;
1998
+ box-sizing: border-box;
1999
+ background: #fff;
2000
+ }
2001
+ .rich-text-content {
2002
+ word-break: break-all;
2003
+ /deep/ p {
2004
+ margin-bottom: 0;
2005
+ }
2006
+ /deep/ img {
2007
+ max-width: 100%;
2008
+ }
2009
+ }
2010
+ </style>