imeik-bizui 2.2.6 → 2.2.8

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.
@@ -0,0 +1,164 @@
1
+ <template>
2
+ <div>
3
+ <p v-if="isView" style="line-height: 18px;">{{ getValueName() }}</p>
4
+ <el-cascader
5
+ v-else
6
+ v-model="myValue"
7
+ style="width: 100%"
8
+ v-bind="$attrs"
9
+ :props="cascaderProps"
10
+ :options="options"
11
+ :placeholder="$attrs.placeholder || '请选择'"
12
+ :clearable="$attrs.clearable === false ? false : true"
13
+ :filterable="$attrs.filterable === false ? false : true"
14
+ :show-all-levels="false"
15
+ :collapse-tags="false"
16
+ @change="handleChange"
17
+ ></el-cascader>
18
+ </div>
19
+ </template>
20
+
21
+ <script>
22
+ import { getTagDicType } from '@/api/meeting/index.js'
23
+
24
+ export default {
25
+ name: 'DictionaryCascader',
26
+ props: {
27
+ value: {
28
+ type: [String, Number, Array],
29
+ default: undefined
30
+ },
31
+ sign: {
32
+ required: true,
33
+ type: String,
34
+ default: ''
35
+ },
36
+ multiple: {
37
+ type: Boolean,
38
+ default: false
39
+ },
40
+ showAllLevels: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ emitPath: {
45
+ type: Boolean,
46
+ default: true
47
+ },
48
+ propValue: {
49
+ type: String,
50
+ default: 'objectCode'
51
+ },
52
+ totalItem: {
53
+ type: Object,
54
+ default() {
55
+ return null
56
+ }
57
+ },
58
+ extra: {
59
+ type: Object,
60
+ default: () => ({})
61
+ },
62
+ isView: {
63
+ type: Boolean,
64
+ default: false
65
+ }
66
+ },
67
+ data() {
68
+ return {
69
+ myValue: undefined,
70
+ options: []
71
+ }
72
+ },
73
+ computed: {
74
+ cascaderProps() {
75
+ return {
76
+ multiple: this.multiple,
77
+ label: 'dicName',
78
+ value: 'dicValue',
79
+ children: 'subRegin',
80
+ emitPath: false
81
+ }
82
+ }
83
+ },
84
+ watch: {
85
+ value: {
86
+ immediate: true,
87
+ handler() {
88
+ this.setMyValue()
89
+ }
90
+ }
91
+ },
92
+ created() {
93
+ this.getOptions()
94
+ },
95
+ methods: {
96
+ setMyValue() {
97
+ try {
98
+ this.myValue = JSON.parse(JSON.stringify(this.value))
99
+ } catch (error) {
100
+ this.myValue = undefined
101
+ }
102
+ },
103
+ // 按照某个字段排序
104
+ sortOptions(arr, field) {
105
+ const result = arr.sort((a, b) => {
106
+ if (a.options && a.options.length) {
107
+ a.options = this.sortOptions(a.options, field)
108
+ }
109
+ return parseInt(a[field]) - parseInt(b[field])
110
+ })
111
+ return result
112
+ },
113
+ getOptions() {
114
+ getTagDicType({
115
+ dicTypeCode: 'cs-zsbw'
116
+ }).then((res) => {
117
+ if (res.code === 200) {
118
+ this.options = res.data
119
+ }
120
+ })
121
+ },
122
+
123
+ // 删除为空数组的options
124
+ loopRemoveEmptyOptions(arr) {
125
+ return arr.map((i) => {
126
+ if (!i.options || !i.options.length) {
127
+ delete i.options
128
+ } else {
129
+ this.loopRemoveEmptyOptions(i.options)
130
+ }
131
+
132
+ return i
133
+ })
134
+ },
135
+
136
+ handleChange() {
137
+ this.$emit('input', this.myValue)
138
+ this.$emit('change', this.myValue)
139
+ },
140
+ getValueName() {
141
+ const value = this.myValue
142
+ if (!value) {
143
+ return ''
144
+ }
145
+ const options = this.options
146
+ const result = []
147
+ const loop = (arr) => {
148
+ arr.forEach((i) => {
149
+ if (value.includes(i.dicValue)) {
150
+ result.push(i.dicName)
151
+ } else if (i.subRegin && i.subRegin.length) {
152
+ loop(i.subRegin)
153
+ }
154
+ })
155
+ }
156
+ loop(options)
157
+ return result.join(',')
158
+ }
159
+ }
160
+ }
161
+ </script>
162
+
163
+ <style scoped >
164
+ </style>
@@ -0,0 +1,523 @@
1
+ <!-- 术前术后对比照组件 -->
2
+ <template>
3
+ <div>
4
+ <p class="title">
5
+ 术前术后对比照
6
+ <span class="tip-title"><i class="el-icon-warning-outline mr-1"></i>当涉及不同的医生、产品、部位的照片,请注意拆分多组上传!</span>
7
+ </p>
8
+ <el-form ref="dynamicValidateForm" :model="dynamicValidateForm" label-position="top">
9
+ <div v-for="(domain, index) in dynamicValidateForm.domains" :key="domain.key || index" class="domain-item">
10
+ <img
11
+ v-if="!isView && !isDisabled"
12
+ src="https://imeikud.oss-cn-beijing.aliyuncs.com/pcUploads/1760511384463/%E5%88%A0%E9%99%A4%402x%20(2).png"
13
+ class="delete-icon"
14
+ @click="removeDomain(index)"
15
+ />
16
+ <el-row v-if="!isOldData" :gutter="24">
17
+ <el-col :span="6">
18
+ <el-form-item
19
+ :label="`注射医生`"
20
+ :prop="`domains[${index}].doctorNumber`"
21
+ :rules="{
22
+ required: isRequired,
23
+ message: '请选择注射医生',
24
+ trigger: 'change'
25
+ }"
26
+ >
27
+ <ImSelect
28
+ v-if="!isView"
29
+ v-model="domain.doctorNumber"
30
+ :attrs="{
31
+ style: 'width:100%',
32
+ options: doctorList,
33
+ placeholder: '请选择',
34
+ disabled: isDisabled,
35
+ filterable: true,
36
+ isView: isView
37
+ }"
38
+ :listeners="{ change: (data) => handleDoctorChange(data, domain) }"
39
+ ></ImSelect>
40
+ <div style="height: 18px; line-height: 18px" v-else>{{ domain.doctorName || '-' }}</div>
41
+ </el-form-item>
42
+ </el-col>
43
+ <el-col :span="6">
44
+ <el-form-item
45
+ :label="`注射产品`"
46
+ :prop="`domains[${index}].injectionProducts`"
47
+ :rules="{
48
+ type: 'array',
49
+ required: isRequired,
50
+ message: '请选择注射产品',
51
+ trigger: 'change'
52
+ }"
53
+ >
54
+ <ImSelect
55
+ v-model="domain.injectionProducts"
56
+ :attrs="{
57
+ style: 'width:100%',
58
+ options: productList,
59
+ placeholder: '请选择',
60
+ isView: isView,
61
+ filterable: true,
62
+ disabled: isDisabled,
63
+ multiple: true
64
+ }"
65
+ ></ImSelect>
66
+ </el-form-item>
67
+ </el-col>
68
+
69
+ <el-col :span="6">
70
+ <el-form-item
71
+ :label="`注射部位`"
72
+ :prop="'domains.' + index + '.injectionParts'"
73
+ :rules="{
74
+ type: 'array',
75
+ required: isRequired,
76
+ message: '请选择注射部位',
77
+ trigger: 'change'
78
+ }"
79
+ >
80
+ <DictionaryCascader
81
+ v-model="domain.injectionParts"
82
+ sign="coursePartition"
83
+ prop-value="sign"
84
+ popper-class="full-height"
85
+ :extra="courseExtra"
86
+ :multiple="true"
87
+ :collapse-tags="true"
88
+ :show-all-levels="true"
89
+ :isView="isView"
90
+ :disabled="isDisabled"
91
+ ></DictionaryCascader>
92
+ <div v-if="isView && domain.injectionParts.length === 0">-</div>
93
+ </el-form-item>
94
+ </el-col>
95
+ <el-col :span="6">
96
+ <el-form-item
97
+ :label="`注射时间`"
98
+ :prop="'domains.' + index + '.injectionTime'"
99
+ :rules="{
100
+ required: isRequired,
101
+ message: '请输入注射时间',
102
+ trigger: 'change'
103
+ }"
104
+ >
105
+ <ImDatePicker
106
+ v-if="!isView"
107
+ v-model="domain.injectionTime"
108
+ :attrs="{
109
+ style: 'width:100%',
110
+ placeholder: '请选择注射时间',
111
+ valueFormat: 'yyyy-MM-dd',
112
+ isView: isView,
113
+ disabled: isDisabled
114
+ }"
115
+ ></ImDatePicker>
116
+ <div v-else-if="domain.injectionTime" style="height: 18px; line-height: 18px">{{ domain.injectionTime.slice(0, 10) }}</div>
117
+ <div v-else style="height: 18px; line-height: 18px">-</div>
118
+ </el-form-item>
119
+ </el-col>
120
+
121
+ <el-col :span="24">
122
+ <el-form-item
123
+ :label="`是否可对外使用`"
124
+ :prop="'domains.' + index + '.canExternalUse'"
125
+ :rules="{
126
+ required: isRequired,
127
+ message: '请选择是否可对外使用',
128
+ trigger: 'change'
129
+ }"
130
+ >
131
+ <el-radio-group v-if="!isView" v-model="domain.canExternalUse" :disabled="isDisabled">
132
+ <el-radio :label="1">是</el-radio>
133
+ <el-radio :label="0">否</el-radio>
134
+ </el-radio-group>
135
+ <div style="height: 18px; line-height: 18px" v-else>
136
+ <span v-if="domain.canExternalUse === 1">是</span>
137
+ <span v-else-if="domain.canExternalUse === 0">否</span>
138
+ <span v-else>-</span>
139
+ </div>
140
+ </el-form-item>
141
+ </el-col>
142
+ </el-row>
143
+
144
+ <el-row :gutter="24">
145
+ <el-col :span="12">
146
+ <el-form-item
147
+ :label="`图片`"
148
+ :prop="'domains.' + index + '.originalAttachArray'"
149
+ :rules="{
150
+ required: isRequired,
151
+ message: '请上传图片',
152
+ trigger: 'change'
153
+ }"
154
+ >
155
+ <ImFieldFileUpload
156
+ v-model="domain.originalAttachArray"
157
+ :attrs="{
158
+ safe: true,
159
+ isView: isView,
160
+ disabled: isDisabled,
161
+ fileType: 'image',
162
+ fileSize: 500 * 1024,
163
+ accept: '.jpg,.jpeg,.png,.zip',
164
+ tipText: '上传格式支持:png、jpg、jpeg、zip压缩包,可以上传多个,大小限制500M以内。'
165
+ }"
166
+ ></ImFieldFileUpload>
167
+ </el-form-item>
168
+ </el-col>
169
+ </el-row>
170
+ </div>
171
+ </el-form>
172
+ <div v-if="!isView && !isDisabled" class="text-center">
173
+ <el-button class="add-button" icon="el-icon-plus" @click="addDomain()">添加</el-button>
174
+ </div>
175
+ </div>
176
+ </template>
177
+
178
+ <script>
179
+ import DictionaryCascader from './components/DictionaryCascaderNew.vue'
180
+ import { getProductArchivesList, listInjectionDoctor, listInjectionProduct } from '@/api/meeting/index.js'
181
+
182
+ export default {
183
+ name: 'BeforeAndAfterSurgeryItem',
184
+ components: { DictionaryCascader },
185
+ props: {
186
+ list: {
187
+ type: Array,
188
+ default: () => []
189
+ },
190
+ value: {
191
+ type: Array,
192
+ default: () => []
193
+ },
194
+ attrs: {
195
+ type: Object,
196
+ default: () => ({})
197
+ }
198
+ },
199
+ data() {
200
+ return {
201
+ appendProduct: [],
202
+ courseExtra: {
203
+ orderFlag: 1
204
+ },
205
+ canBeUdExternally: [
206
+ {
207
+ value: '1',
208
+ label: '是'
209
+ },
210
+ {
211
+ value: '0',
212
+ label: '否'
213
+ }
214
+ ],
215
+
216
+ dynamicValidateForm: {
217
+ domains: []
218
+ },
219
+ // 用于避免死循环的标志
220
+ isUpdatingFromParent: false,
221
+ doctorList: [],
222
+ productList: [],
223
+ isOldData: false
224
+ }
225
+ },
226
+ computed: {
227
+ isView() {
228
+ return this.attrs.isView
229
+ },
230
+ isDisabled() {
231
+ return this.attrs.disabled
232
+ },
233
+ isRequired() {
234
+ return this.attrs.isRequired
235
+ },
236
+ domainsItme() {
237
+ return {
238
+ doctorNumber: '', // 注射医生
239
+ doctorName: '',
240
+ doctorMobile: '',
241
+ injectionProducts: '', // 注射产品
242
+ injectionParts: '', // 注射部位
243
+ injectionTime: this.attrs.holdingTim ? this.attrs.holdingTim : '', // 注射时间
244
+ canExternalUse: '', // 是否可对外使用
245
+ originalAttachArray: [], // 图片
246
+ key: Date.now(),
247
+ productNameList: []
248
+ }
249
+ }
250
+ },
251
+ watch: {
252
+ attrs: {
253
+ handler(newVal) {
254
+ this.initData()
255
+ },
256
+ deep: true
257
+ },
258
+ dynamicValidateForm: {
259
+ handler(newVal) {
260
+ console.log('dynamicValidateForm监听', this.dynamicValidateForm.domains)
261
+ },
262
+ deep: true
263
+ },
264
+ list: {
265
+ handler(newVal) {
266
+ // 设置标志,避免触发向父组件发送更新
267
+ this.isUpdatingFromParent = true
268
+ if (newVal && newVal.length > 0) {
269
+ newVal.forEach((item) => {
270
+ if (Object.keys(item)?.length === 1) {
271
+ this.isOldData = true
272
+ }
273
+ if (!item.injectionProducts) {
274
+ item.injectionProducts = []
275
+ }
276
+ if (!item.injectionParts) {
277
+ item.injectionParts = []
278
+ }
279
+ })
280
+ this.dynamicValidateForm.domains = newVal.map((item) => ({
281
+ ...item,
282
+ key: item.key || Date.now() + Math.random()
283
+ }))
284
+ }
285
+ if ((!newVal || newVal.length === 0) && this.isView) {
286
+ this.isOldData = true
287
+ }
288
+ // 在下一个tick重置标志
289
+ this.$nextTick(() => {
290
+ this.isUpdatingFromParent = false
291
+ })
292
+ },
293
+ immediate: true,
294
+ deep: true
295
+ },
296
+ value: {
297
+ handler(newVal) {
298
+ if (!newVal || newVal.length === 0) return
299
+ // 设置标志,避免触发向父组件发送更新
300
+ this.isUpdatingFromParent = true
301
+ if (newVal && newVal.length > 0) {
302
+ newVal.forEach((item) => {
303
+ if (!item.injectionProducts) {
304
+ item.injectionProducts = []
305
+ }
306
+ if (!item.injectionParts) {
307
+ item.injectionParts = []
308
+ }
309
+ })
310
+ this.dynamicValidateForm.domains = newVal.map((item) => ({
311
+ ...item,
312
+ key: item.key || Date.now() + Math.random()
313
+ }))
314
+ }
315
+ // 在下一个tick重置标志
316
+ this.$nextTick(() => {
317
+ this.isUpdatingFromParent = false
318
+ })
319
+ },
320
+ immediate: true,
321
+ deep: true
322
+ }
323
+ },
324
+ mounted() {
325
+ this.initData()
326
+ },
327
+ created() {
328
+ if (!this.dynamicValidateForm.domains.length) {
329
+ this.dynamicValidateForm.domains.push(this.domainsItme)
330
+ }
331
+ },
332
+ methods: {
333
+ getFormListData() {
334
+ this.$refs.dynamicValidateForm.validate((valid) => {
335
+ if (valid) {
336
+ const data = this.dynamicValidateForm.domains
337
+ this.dynamicValidateForm.domains.forEach((item) => {
338
+ item.productNameList = this.getProductName(item.injectionProducts)
339
+ })
340
+ this.$emit('input', data)
341
+ // this.$emit('change', data)
342
+ } else {
343
+ this.$message.error('请完善表单信息!')
344
+ this.$emit('input', null)
345
+ // this.$emit('change', null)
346
+ }
347
+ })
348
+ },
349
+ getProductName(data) {
350
+ const list = []
351
+ this.productList.forEach((item) => {
352
+ if (data.includes(item.value)) {
353
+ list.push(item.label)
354
+ }
355
+ })
356
+ return list
357
+ },
358
+ initData() {
359
+ if (this.attrs.doctorListData && this.attrs.doctorListData.length) {
360
+ this.doctorList = this.attrs.doctorListData.map((item) => ({
361
+ ...item,
362
+ value: item.lecturerCode
363
+ }))
364
+ if (!this.isRequired) {
365
+ this.doctorList = []
366
+ }
367
+ }
368
+ if (!this.isView) {
369
+ this.getAppendDoctorList()
370
+ this.getAppendProductList()
371
+ } else {
372
+ this.getProductList()
373
+ }
374
+ },
375
+ getAppendProductList() {
376
+ if (this.attrs.objectCode) {
377
+ listInjectionProduct(this.attrs.objectCode).then((res) => {
378
+ if (res.code === 200) {
379
+ this.appendProduct = res.data || []
380
+ this.getProductList()
381
+ }
382
+ })
383
+ }
384
+ },
385
+ getAppendDoctorList() {
386
+ if (this.attrs.objectCode) {
387
+ listInjectionDoctor(this.attrs.objectCode).then((res) => {
388
+ if (res.code === 200) {
389
+ const code = []
390
+ const codeListKeys = this.doctorList.map((item) => item.value)
391
+ res.data.forEach((item) => {
392
+ if (codeListKeys.includes(item.lecturerCode)) {
393
+ return
394
+ } else {
395
+ code.push({
396
+ ...item,
397
+ value: item.lecturerCode,
398
+ label: item.lecturerName + ' ' + item.phone
399
+ })
400
+ }
401
+ })
402
+ this.doctorList = [...this.doctorList, ...code]
403
+ }
404
+ })
405
+ }
406
+ },
407
+ getProductList() {
408
+ if (!this.attrs?.productListParams?.belongCompanyCode) {
409
+ return
410
+ }
411
+ if (this.appendProduct && this.appendProduct.length) {
412
+ this.$set(this.attrs, 'productCodeList', [...this.attrs.productCodeList, ...this.appendProduct])
413
+ }
414
+ getProductArchivesList(this.attrs.productListParams).then((res) => {
415
+ if (res.code === 200) {
416
+ res.data?.forEach((element) => {
417
+ element.label = element.productName
418
+ element.value = element.productCode
419
+ })
420
+ this.productList = res.data
421
+ }
422
+ })
423
+ },
424
+ removeDomain(index) {
425
+ if (this.dynamicValidateForm.domains.length > 1) {
426
+ // 设置标志,避免触发向父组件发送更新
427
+ this.isUpdatingFromParent = true
428
+ this.dynamicValidateForm.domains.splice(index, 1)
429
+ // 在下一个tick重置标志
430
+ this.$nextTick(() => {
431
+ this.isUpdatingFromParent = false
432
+ })
433
+ } else {
434
+ this.$message.warning('至少保留一行!')
435
+ }
436
+ },
437
+ addDomain() {
438
+ const newDomain = {
439
+ doctorNumber: '', // 注射医生
440
+ doctorName: '',
441
+ doctorMobile: '',
442
+ injectionProducts: '', // 注射产品
443
+ injectionParts: '', // 注射部位
444
+ injectionTime: this.attrs.holdingTim, // 注射时间
445
+ canExternalUse: '', // 是否可对外使用
446
+ originalAttachArray: [], // 图片
447
+ key: Date.now(),
448
+ productNameList: []
449
+ }
450
+
451
+ // 设置标志,避免触发向父组件发送更新
452
+ this.isUpdatingFromParent = true
453
+ this.dynamicValidateForm.domains.push(newDomain)
454
+ this.$emit('input', this.dynamicValidateForm.domains)
455
+ // this.$emit('change', this.dynamicValidateForm.domains)
456
+
457
+ // 在下一个tick重置标志
458
+ this.$nextTick(() => {
459
+ this.isUpdatingFromParent = false
460
+ })
461
+ },
462
+ handleDoctorChange(data, item) {
463
+ const doctorInfo = this.doctorList.find((item) => item.value === data)
464
+ this.$set(item, 'doctorName', doctorInfo.lecturerName)
465
+ this.$set(item, 'doctorMobile', doctorInfo.phone)
466
+ }
467
+ }
468
+ }
469
+ </script>
470
+
471
+ <style scoped>
472
+ .domain-item {
473
+ border: 1px solid #ebeef5;
474
+ border-radius: 4px;
475
+ padding: 15px;
476
+ margin-bottom: 20px;
477
+ background-color: #f7f7f9;
478
+ position: relative;
479
+ }
480
+
481
+ .el-button[type='danger'] {
482
+ margin-top: 30px;
483
+ }
484
+
485
+ .el-form-item {
486
+ margin-bottom: 18px;
487
+ }
488
+
489
+ ::v-deep .el-col {
490
+ padding-bottom: 10px;
491
+ }
492
+ .add-button {
493
+ width: 100%;
494
+ border: 1px dashed rgb(220, 223, 230);
495
+ }
496
+ .delete-icon {
497
+ position: absolute;
498
+ height: 24px;
499
+ width: 24px;
500
+ right: 0;
501
+ top: 0px;
502
+ cursor: pointer;
503
+ }
504
+ .title {
505
+ font-weight: 600;
506
+ font-size: 16px;
507
+ color: #000000;
508
+ line-height: 24px;
509
+ margin-bottom: 20px;
510
+ display: flex;
511
+ align-items: center;
512
+ }
513
+ .tip-title {
514
+ font-weight: 400;
515
+ font-size: 12px;
516
+ color: #909399;
517
+ line-height: 24px;
518
+ margin-left: 10px;
519
+ }
520
+ ::v-deep .el-form-item__label {
521
+ padding: 0 !important;
522
+ }
523
+ </style>