three-trees-ui 1.0.99 → 1.1.1

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.
@@ -16,23 +16,33 @@
16
16
  @click="showDialog"
17
17
  >
18
18
  <div
19
- v-if="inputWriteable"
20
- class="el-input el-input--suffix"
21
- :class="{ 'custom-selector-mobile': isMobile }"
19
+ ref="tagSpans"
20
+ style="width: calc(100% - 25px);"
21
+ :class="{
22
+ 'el-select__tags_readonly': !inputWriteable,
23
+ 'el-select__tags': inputWriteable,
24
+ }"
22
25
  >
23
- <div v-if="isMobile" class="custom-selector-mobile-box">
24
- <div
26
+ <span class="tag-wrap">
27
+ <span
25
28
  v-for="(item, index) in demensions"
26
29
  :key="index"
27
- class="common-selector-tag"
30
+ class="el-tag el-tag--info el-tag--small"
31
+ @click.stop
28
32
  >
29
- <span>{{ item.name }}</span>
30
- <i class="el-icon-error" @click.stop="handleRemove(item)"></i>
31
- </div>
32
- </div>
33
+ <span class="el-select__tags-text">{{ item.name }}</span>
34
+ <i
35
+ v-if="inputWriteable"
36
+ class="el-tag__close el-icon-close"
37
+ @click="handleRemove(item)"
38
+ ></i>
39
+ </span>
40
+ </span>
41
+ </div>
42
+ <div v-if="inputWriteable" class="el-input el-input--suffix">
33
43
  <input
34
44
  ref="inputEl"
35
- v-model="calcInputValue"
45
+ v-model="value"
36
46
  v-validate="inputValidate"
37
47
  type="text"
38
48
  readonly="readonly"
@@ -40,6 +50,10 @@
40
50
  autocomplete="off"
41
51
  class="el-input__inner"
42
52
  :placeholder="placeholder"
53
+ :style="{
54
+ height: inputSuffixHeight + 'px',
55
+ lineHeight: inputSuffixHeight + 'px',
56
+ }"
43
57
  />
44
58
  <span class="el-input__suffix">
45
59
  <span class="el-input__suffix-inner">
@@ -48,13 +62,9 @@
48
62
  </span>
49
63
  </span>
50
64
  </div>
51
- <div v-else class="el-select__tags_readonly">
52
- <span>{{ calcInputValue }}</span>
53
- </div>
54
65
  </div>
55
66
  <ht-field-tail :field-name="inputName" :input-value="value" />
56
67
  <el-dialog
57
- v-if="dialogVisible"
58
68
  title="选择维度"
59
69
  :visible.sync="dialogVisible"
60
70
  class="dialog-selector__wrapper"
@@ -206,10 +216,6 @@
206
216
  mode: {
207
217
  type: String,
208
218
  },
209
- formInputsDisplay: {
210
- type: String,
211
- default: 'inline',
212
- },
213
219
  },
214
220
  data() {
215
221
  return {
@@ -221,17 +227,6 @@
221
227
  }
222
228
  },
223
229
  computed: {
224
- calcInputValue: function() {
225
- let name = ''
226
- if (this.demensions) {
227
- name = this.demensions
228
- .map((k) => {
229
- return k.name
230
- })
231
- .join(',')
232
- }
233
- return name
234
- },
235
230
  primaryField: function() {
236
231
  return this.config && this.config.hasOwnProperty('id')
237
232
  ? 'id'
@@ -290,8 +285,14 @@
290
285
  // 通过valueChange事件发布值变更消息
291
286
  this.$emit('valueChange', ary.join(','), newVal)
292
287
  setTimeout(() => {
288
+ if (newVal.length > 0) {
289
+ this.calacInputSuffixHeight()
290
+ } else {
291
+ this.inputSuffixHeight = 30
292
+ }
293
293
  if (this.$refs.inputEl) {
294
- this.$validator.validate(this.inputName)
294
+ this.$refs.inputEl.focus()
295
+ this.$refs.inputEl.blur()
295
296
  }
296
297
  }, 10)
297
298
  },
@@ -370,13 +371,14 @@
370
371
  this.demensions = tmpAry
371
372
  }
372
373
  },
373
- async showDialog() {
374
+ showDialog() {
374
375
  if (!this.inputWriteable) {
375
376
  return
376
377
  }
377
378
  this.dialogVisible = true
378
- await this.$nextTick()
379
- this.$refs.selector.onShow()
379
+ setTimeout(() => {
380
+ this.$refs.selector.onShow()
381
+ })
380
382
  },
381
383
  handleClose(done) {
382
384
  this.$refs.selector.onHide()
@@ -399,12 +401,12 @@
399
401
  },
400
402
  // 更新当前输入框的高度来适配已选数据的高度
401
403
  calacInputSuffixHeight() {
402
- // if (!this.$refs.tagSpans) return
403
- // if (this.$refs.tagSpans.offsetHeight) {
404
- // this.inputSuffixHeight = this.$refs.tagSpans.offsetHeight + 5
405
- // } else {
406
- // this.inputSuffixHeight = 30
407
- // }
404
+ if (!this.$refs.tagSpans) return
405
+ if (this.$refs.tagSpans.offsetHeight) {
406
+ this.inputSuffixHeight = this.$refs.tagSpans.offsetHeight + 5
407
+ } else {
408
+ this.inputSuffixHeight = 30
409
+ }
408
410
  },
409
411
  },
410
412
  }
@@ -425,10 +427,7 @@
425
427
  position: relative;
426
428
  top: 50%;
427
429
  }
428
- .el-input__inner {
429
- height: 32px;
430
- line-height: 32px;
431
- }
430
+
432
431
  .el-input__inner[aria-invalid='true'] {
433
432
  border-color: #f56c6c;
434
433
  }
@@ -96,9 +96,29 @@
96
96
  @remove="removeFile"
97
97
  @sort="handleSort"
98
98
  />
99
+ <!-- 图片预览组件 -->
100
+ <el-image
101
+ v-if="!isMobile"
102
+ v-show="false"
103
+ ref="previewImage"
104
+ :preview-src-list="[imgPreviewUrl]"
105
+ ></el-image>
106
+ <!-- 移动端图片 -->
107
+ <viewer
108
+ v-if="isMobile"
109
+ ref="viewerRef"
110
+ class="images"
111
+ :options="viewerOptions"
112
+ :images="imgList"
113
+ @inited="inited"
114
+ >
115
+ <img v-for="src in imgList" v-show="false" :key="src" :src="src" />
116
+ </viewer>
99
117
  </div>
100
118
  </template>
101
119
  <script>
120
+ import { component as viewer } from 'v-viewer'
121
+ import 'viewerjs/dist/viewer.css'
102
122
  import utils from '@/utils.js'
103
123
  import permission from '@/mixins/permission.js'
104
124
  import inputName from '@/mixins/inputName.js'
@@ -115,13 +135,20 @@
115
135
 
116
136
  export default {
117
137
  name: 'HtFile',
118
- components: { HtFieldTail, FileUpload, FileTable, FileList, FileCard },
138
+ components: {
139
+ HtFieldTail,
140
+ FileUpload,
141
+ FileTable,
142
+ FileList,
143
+ FileCard,
144
+ viewer,
145
+ },
119
146
  mixins: [Locale, permission, inputName, form, mobileMode],
120
147
  props: {
121
148
  type: {
122
149
  type: String,
123
150
  default: 'table',
124
- validator: function (value) {
151
+ validator: function(value) {
125
152
  return ['table', 'list', 'card'].indexOf(value) !== -1
126
153
  },
127
154
  },
@@ -223,6 +250,27 @@
223
250
  },
224
251
  data() {
225
252
  return {
253
+ $viewer: null, // viewer组件实例对象
254
+ viewerOptions: {
255
+ backdrop: true, // 是否启用播放模态背景[布尔值/字符串:默认true](不启用时,点击空白处不会退出播放,仅点击右上角关闭按钮才会退出播放)
256
+ inline: false, // 启用inline模式[布尔值:默认false]
257
+ button: true, // 显示右上角关闭按钮[布尔值:默认true]
258
+ navbar: false, // 显示缩略图导航[布尔值/数字:默认true]
259
+ title: false, // 显示当前图片的标题(显示alt属性或从URL解析出的图片名称)[布尔值/数字/方法/数组:默认true]
260
+ toolbar: false, // 显示工具栏、自定义工具栏[布尔值/数字/对象:默认true]
261
+ tooltip: true, // 显示缩放百分比[布尔值:默认true]
262
+ movable: true, // 图片是否可移动[布尔值:默认true]
263
+ zoomable: true, // 图片是否可缩放[布尔值:默认true]
264
+ rotatable: true, // 图片是否可旋转[布尔值:默认true]
265
+ scalable: true, // 图片是否可翻转[布尔值:默认true]
266
+ transition: true, // 使用CSS3过渡[布尔值:默认true]
267
+ fullscreen: true, // 播放时是否全屏[布尔值/全屏配置:默认true]
268
+ keyboard: true, // 是否支持键盘[布尔值:默认true]
269
+ url: 'src', // 播放时图片地址 URL 来源。[字符串/方法:默认src](如果是字符串,则应该是每个图像元素的属性之一。 如果是方法,则应该返回一个有效的图像URL)
270
+ },
271
+ index: null,
272
+ imgList: [],
273
+ imgPreviewUrl: '',
226
274
  writeable: true,
227
275
  temp: null,
228
276
  refreshFileUploadDebounce: _.debounce(this.refreshFileUpload, 200),
@@ -230,7 +278,7 @@
230
278
  }
231
279
  },
232
280
  computed: {
233
- typeVal: function () {
281
+ typeVal: function() {
234
282
  return this.isSimple || this.simplicity ? 'list' : this.type
235
283
  },
236
284
  inputsContainerWidth() {
@@ -238,7 +286,7 @@
238
286
  ? { width: 'auto' }
239
287
  : {}
240
288
  },
241
- actionUrlVal: function () {
289
+ actionUrlVal: function() {
242
290
  return this.actionUrl
243
291
  ? this.actionUrl
244
292
  : this.$requestConfig.uploadUrl
@@ -262,14 +310,14 @@
262
310
  }
263
311
  return baseUrl
264
312
  },
265
- headerVal: function () {
313
+ headerVal: function() {
266
314
  return this.header
267
315
  ? this.header
268
316
  : this.$requestConfig.header
269
317
  ? this.$requestConfig.header()
270
318
  : null
271
319
  },
272
- acceptType: function () {
320
+ acceptType: function() {
273
321
  if (this.accept) {
274
322
  const ary = []
275
323
  this.accept.split(',').forEach((m) => {
@@ -283,10 +331,10 @@
283
331
  }
284
332
  return null
285
333
  },
286
- previewableVal: function () {
334
+ previewableVal: function() {
287
335
  return (this.inputWriteable && this.previewable) || this.allowPreview
288
336
  },
289
- downloadableVal: function () {
337
+ downloadableVal: function() {
290
338
  return (this.inputWriteable && this.downloadable) || this.allowDownload
291
339
  },
292
340
  },
@@ -311,7 +359,14 @@
311
359
  this.inputVal = JSON.parse(this.value)
312
360
  }
313
361
  },
362
+ mounted() {},
314
363
  methods: {
364
+ /**
365
+ * 组件初始化完成,获取组件实例对象
366
+ */
367
+ inited(viewer) {
368
+ this.$viewer = viewer
369
+ },
315
370
  // 上传前做校验
316
371
  beforeUploadMethod(file) {
317
372
  if (
@@ -466,6 +521,49 @@
466
521
  })
467
522
  }
468
523
  },
524
+ customPreviewImg(fileId) {
525
+ this.$requestConfig
526
+ .request({
527
+ url: `${window.context.portal}/system/file/v1/preview?fileId=${fileId}`,
528
+ method: 'get',
529
+ responseType: 'blob',
530
+ })
531
+ .then((response) => {
532
+ if (response.size > 0) {
533
+ var blob = response
534
+ var reader = new FileReader()
535
+ let that = this
536
+ reader.readAsDataURL(blob)
537
+ reader.onload = function(e) {
538
+ that.imgPreviewUrl = e.target.result
539
+ if (that.isMobile) {
540
+ that.imgList = [that.imgPreviewUrl]
541
+ // 2、通过ref获取到对应节点,再通过$viewer属性获取对应的元素信息对象,继而调用方法显示
542
+ that.$refs.viewerRef.$viewer.show()
543
+ return
544
+ }
545
+ that.$refs.previewImage.clickHandler()
546
+ }
547
+ }
548
+ })
549
+ },
550
+ isImgFile(fileName) {
551
+ let fileType = fileName.split('.')[fileName.split('.').length - 1]
552
+ return [
553
+ 'gif',
554
+ 'jpg',
555
+ 'jpeg',
556
+ 'png',
557
+ 'webp',
558
+ 'svg',
559
+ 'GIF',
560
+ 'JPG',
561
+ 'JPEG',
562
+ 'PNG',
563
+ 'WEBP',
564
+ 'SVG',
565
+ ].includes(fileType)
566
+ },
469
567
  preview(file) {
470
568
  if (file.status !== 'success') {
471
569
  this.$message.warning(this.t('ht.file.forbiddenPreview'))
@@ -475,11 +573,21 @@
475
573
  // 当前组件未添加preview事件监听 并且 设置了全局预览方法
476
574
  if (!this._events.preview && this.$preview) {
477
575
  if (this.isMobile) {
478
- this.$preview(file)
576
+ if (this.isImgFile(file.response.fileName)) {
577
+ this.customPreviewImg(file.response.fileId)
578
+ } else {
579
+ this.$preview(file)
580
+ }
479
581
  } else {
480
- let token = this.$requestConfig.getToken().replace('Bearer ', '')
481
- let url = `${window.context.front}/previewFile/${file.response.fileId}/${file.response.fileName}?token=${token}`
482
- window.open(url, '_blank')
582
+ if (this.isImgFile(file.response.fileName)) {
583
+ this.customPreviewImg(file.response.fileId)
584
+ } else {
585
+ let token = this.$requestConfig
586
+ .getToken()
587
+ .replace('Bearer ', '')
588
+ let url = `${window.context.front}/previewFile/${file.response.fileId}/${file.response.fileName}?token=${token}`
589
+ window.open(url, '_blank')
590
+ }
483
591
  }
484
592
  } else {
485
593
  this.$emit('preview', file, this.inputVal)
@@ -16,23 +16,33 @@
16
16
  @click="showDialog"
17
17
  >
18
18
  <div
19
- v-if="inputWriteable"
20
- class="el-input el-input--suffix"
21
- :class="{ 'custom-selector-mobile': isMobile }"
19
+ ref="tagSpans"
20
+ style="width: calc(100% - 25px);"
21
+ :class="{
22
+ 'el-select__tags_readonly': !inputWriteable,
23
+ 'el-select__tags': inputWriteable,
24
+ }"
22
25
  >
23
- <div v-if="isMobile" class="custom-selector-mobile-box">
24
- <div
26
+ <span class="tag-wrap">
27
+ <span
25
28
  v-for="(item, index) in selectors"
26
29
  :key="index"
27
- class="common-selector-tag"
30
+ class="el-tag el-tag--info el-tag--small"
31
+ @click.stop
28
32
  >
29
- <span>{{ item.name }}</span>
30
- <i class="el-icon-error" @click.stop="handleRemove(item)"></i>
31
- </div>
32
- </div>
33
+ <span class="el-select__tags-text">{{ item.name }}</span>
34
+ <i
35
+ v-if="inputWriteable"
36
+ class="el-tag__close el-icon-close"
37
+ @click="handleRemove(item)"
38
+ ></i>
39
+ </span>
40
+ </span>
41
+ </div>
42
+ <div v-if="inputWriteable" class="el-input el-input--suffix">
33
43
  <input
34
44
  ref="inputEl"
35
- v-model="calcInputValue"
45
+ v-model="value"
36
46
  v-validate="inputValidate"
37
47
  type="text"
38
48
  readonly="readonly"
@@ -40,6 +50,10 @@
40
50
  autocomplete="off"
41
51
  class="el-input__inner"
42
52
  :placeholder="placeholder"
53
+ :style="{
54
+ height: inputSuffixHeight + 'px',
55
+ lineHeight: inputSuffixHeight + 'px',
56
+ }"
43
57
  />
44
58
  <span class="el-input__suffix">
45
59
  <span class="el-input__suffix-inner">
@@ -48,54 +62,49 @@
48
62
  </span>
49
63
  </span>
50
64
  </div>
51
- <div v-else class="el-select__tags_readonly">
52
- <span>{{ calcInputValue }}</span>
53
- </div>
54
65
  </div>
55
66
  <ht-field-tail :field-name="inputName" :input-value="value" />
56
- <template v-if="isDialogShow">
57
- <job-selector-mobile-dialog
58
- v-if="isMobile"
59
- ref="jobSelectorMobileDialog"
60
- v-model="selectors"
61
- :search-placeholder="searchPlaceholder"
62
- :single="single"
63
- :data="data"
64
- :pagination="pagination"
65
- :select-label="selectLabel"
66
- :quick-search-props="quickSearchProps"
67
- :append-to-body="appendToBody"
68
- :title="title"
69
- :primary-field="primaryField"
70
- @search="(word) => $emit('search', word)"
71
- @reset="() => $emit('reset')"
72
- @row-click="(row) => $emit('row-click', row)"
73
- @select-data="(data) => $emit('select-data', data)"
74
- @page-change="(page) => $emit('page-change', page)"
75
- />
76
- <job-selector-dialog
77
- v-else
78
- ref="jobSelectorDialog"
79
- v-model="selectors"
80
- :search-placeholder="searchPlaceholder"
81
- :single="single"
82
- :data="data"
83
- :table-columns="tableColumns"
84
- :pagination="pagination"
85
- :select-label="selectLabel"
86
- :quick-search-props="quickSearchProps"
87
- :append-to-body="appendToBody"
88
- :title="title"
89
- :primary-field="primaryField"
90
- :mode="mode"
91
- @search="(word) => $emit('search', word)"
92
- @reset="() => $emit('reset')"
93
- @row-click="(row) => $emit('row-click', row)"
94
- @select-data="(data) => $emit('select-data', data)"
95
- @page-change="(page) => $emit('page-change', page)"
96
- @size-change="(size) => $emit('size-change', size)"
97
- />
98
- </template>
67
+ <job-selector-mobile-dialog
68
+ v-if="isMobile"
69
+ ref="jobSelectorMobileDialog"
70
+ v-model="selectors"
71
+ :search-placeholder="searchPlaceholder"
72
+ :single="single"
73
+ :data="data"
74
+ :pagination="pagination"
75
+ :select-label="selectLabel"
76
+ :quick-search-props="quickSearchProps"
77
+ :append-to-body="appendToBody"
78
+ :title="title"
79
+ :primary-field="primaryField"
80
+ @search="(word) => $emit('search', word)"
81
+ @reset="() => $emit('reset')"
82
+ @row-click="(row) => $emit('row-click', row)"
83
+ @select-data="(data) => $emit('select-data', data)"
84
+ @page-change="(page) => $emit('page-change', page)"
85
+ />
86
+ <job-selector-dialog
87
+ v-else
88
+ ref="jobSelectorDialog"
89
+ v-model="selectors"
90
+ :search-placeholder="searchPlaceholder"
91
+ :single="single"
92
+ :data="data"
93
+ :table-columns="tableColumns"
94
+ :pagination="pagination"
95
+ :select-label="selectLabel"
96
+ :quick-search-props="quickSearchProps"
97
+ :append-to-body="appendToBody"
98
+ :title="title"
99
+ :primary-field="primaryField"
100
+ :mode="mode"
101
+ @search="(word) => $emit('search', word)"
102
+ @reset="() => $emit('reset')"
103
+ @row-click="(row) => $emit('row-click', row)"
104
+ @select-data="(data) => $emit('select-data', data)"
105
+ @page-change="(page) => $emit('page-change', page)"
106
+ @size-change="(size) => $emit('size-change', size)"
107
+ />
99
108
  </div>
100
109
  </template>
101
110
  <script>
@@ -172,23 +181,11 @@
172
181
  },
173
182
  data() {
174
183
  return {
175
- isDialogShow: false,
176
184
  inputSuffixHeight: 30,
177
185
  selectors: [],
178
186
  }
179
187
  },
180
188
  computed: {
181
- calcInputValue: function() {
182
- let name = ''
183
- if (this.selectors) {
184
- name = this.selectors
185
- .map((k) => {
186
- return k.name
187
- })
188
- .join(',')
189
- }
190
- return name
191
- },
192
189
  primaryField: function() {
193
190
  return this.config && this.config.hasOwnProperty('id')
194
191
  ? 'id'
@@ -238,8 +235,14 @@
238
235
  // 通过valueChange事件发布值变更消息
239
236
  this.$emit('valueChange', ary.join(','), newVal)
240
237
  setTimeout(() => {
238
+ if (newVal.length > 0) {
239
+ this.calacInputSuffixHeight()
240
+ } else {
241
+ this.inputSuffixHeight = 30
242
+ }
241
243
  if (this.$refs.inputEl) {
242
- this.$validator.validate(this.inputName)
244
+ this.$refs.inputEl.focus()
245
+ this.$refs.inputEl.blur()
243
246
  }
244
247
  }, 10)
245
248
  },
@@ -293,14 +296,10 @@
293
296
  this.selectors = tmpAry
294
297
  }
295
298
  },
296
- async showDialog() {
299
+ showDialog() {
297
300
  if (!this.inputWriteable) {
298
301
  return
299
302
  }
300
- if (this.isDialogShow === false) {
301
- this.isDialogShow = true
302
- await this.$nextTick()
303
- }
304
303
  if (this.isMobile) {
305
304
  this.$refs.jobSelectorMobileDialog.showDialog()
306
305
  } else {
@@ -316,12 +315,12 @@
316
315
  },
317
316
  // 更新当前输入框的高度来适配已选数据的高度
318
317
  calacInputSuffixHeight() {
319
- // if (!this.$refs.tagSpans) return
320
- // if (this.$refs.tagSpans.offsetHeight) {
321
- // this.inputSuffixHeight = this.$refs.tagSpans.offsetHeight + 5
322
- // } else {
323
- // this.inputSuffixHeight = 30
324
- // }
318
+ if (!this.$refs.tagSpans) return
319
+ if (this.$refs.tagSpans.offsetHeight) {
320
+ this.inputSuffixHeight = this.$refs.tagSpans.offsetHeight + 5
321
+ } else {
322
+ this.inputSuffixHeight = 30
323
+ }
325
324
  },
326
325
  },
327
326
  }
@@ -336,10 +335,7 @@
336
335
  position: relative;
337
336
  top: 50%;
338
337
  }
339
- .el-input__inner {
340
- height: 32px;
341
- line-height: 32px;
342
- }
338
+
343
339
  .el-input__inner[aria-invalid='true'] {
344
340
  border-color: #f56c6c;
345
341
  }