fl-web-component 0.1.0 → 0.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.
Files changed (33) hide show
  1. package/README.md +35 -24
  2. package/dist/fl-web-component.common.js +67035 -54
  3. package/dist/fl-web-component.common.js.map +1 -1
  4. package/dist/fl-web-component.css +1 -1
  5. package/dist/fl-web-component.umd.js +67035 -54
  6. package/dist/fl-web-component.umd.js.map +1 -1
  7. package/dist/fl-web-component.umd.min.js +13 -1
  8. package/dist/fl-web-component.umd.min.js.map +1 -1
  9. package/package.json +59 -47
  10. package/packages/components/button/index.vue +6 -3
  11. package/packages/components/com-card/card-page.vue +100 -0
  12. package/packages/components/com-card/index.vue +54 -0
  13. package/packages/components/com-dialogWrapper/Readme.md +53 -0
  14. package/packages/components/com-dialogWrapper/index.vue +101 -0
  15. package/packages/components/com-formDialog/Readme.md +409 -0
  16. package/packages/components/com-formDialog/index.vue +470 -0
  17. package/packages/components/com-graphics/index.vue +240 -0
  18. package/packages/components/com-page/index.vue +101 -0
  19. package/packages/components/com-selectTree/Readme.md +17 -0
  20. package/packages/components/com-selectTree/index.vue +238 -0
  21. package/packages/components/com-table/column-default.vue +76 -0
  22. package/packages/components/com-table/column-dynamic.vue +40 -0
  23. package/packages/components/com-table/column-menu.vue +71 -0
  24. package/packages/components/com-table/column-slot.vue +53 -0
  25. package/packages/components/com-table/column.vue +49 -0
  26. package/packages/components/com-table/config.js +21 -0
  27. package/packages/components/com-table/index.vue +281 -0
  28. package/packages/components/com-table/table-page.vue +106 -0
  29. package/packages/components/com-tabs/index.vue +50 -0
  30. package/packages/components/com-treeDynamic/Readme.md +271 -0
  31. package/packages/components/com-treeDynamic/index.vue +207 -0
  32. package/patches/camera-controls+2.9.0.patch +63 -0
  33. package/{packages/index.js → src/main.js} +5 -5
@@ -0,0 +1,470 @@
1
+ <!--
2
+ * @Author: fengyang9326@163.com
3
+ * @Date: 2024-05-13 10:36:07
4
+ * @LastEditors: fengyang9326@163.com
5
+ * @LastEditTime: 2024-05-20 09:18:31
6
+ * @FilePath: /web/framework/src/views/system/temporary/form-dialog.vue
7
+ * @Description: 表单
8
+ -->
9
+ <template>
10
+ <div v-loading="loadingForm" class="inline_false">
11
+ <el-form
12
+ ref="form"
13
+ :model="formInline"
14
+ :label-width="labelWidth"
15
+ class="form_inline_false"
16
+ >
17
+ <!-- 表单循环 -->
18
+ <el-form-item
19
+ v-for="(item, index) in formItemConfigArr"
20
+ :key="item.id + index"
21
+ :label="item.label"
22
+ :prop="item.prop"
23
+ :rules="item.deliveryLevel === 'ESS' ? rulesForm[item.prop] : {}"
24
+ >
25
+ <template id="formItemTemp">
26
+ <!-- 表单左侧 label 与 校验 * 号图标 -->
27
+ <span slot="label" class="label_title" :title="item.label">
28
+ <!-- <i v-if="item.deliveryLevel === 'ESS'" class="red_must">*</i> -->
29
+ <!-- <span class="item_label" :title="item.label">{{ item.label }}</span> -->
30
+ {{ item.label }}
31
+ </span>
32
+
33
+ <!-- 1. 选择器_单选 SelectorSingleSelection -->
34
+ <el-select
35
+ v-if="item.itemType === 'SelectorSingleSelection' || item.itemType === '选择器_单选'"
36
+ v-model="valueSelectorSingle"
37
+ class="form_select"
38
+ :placeholder="`请选择${item.label}`"
39
+ @focus="setMinWidth"
40
+ @change="handleSelectorSingle($event, item.prop, index)"
41
+ >
42
+ <el-option
43
+ v-for="(optionItem, optionIndex) in item.optionArr"
44
+ :key="optionItem.optionValue + optionIndex"
45
+ :label="optionItem.optionLabel"
46
+ :value="optionItem.optionValue"
47
+ :style="{'width': minWidth + 2 + 'px'}"
48
+ />
49
+ </el-select>
50
+
51
+ <!-- 2. 选择器_多选 SelectorMultipleSelection -->
52
+ <el-cascader
53
+ v-if="item.itemType === 'SelectorMultipleSelection' || item.itemType === '选择器_多选'"
54
+ ref="formCascader"
55
+ class="form_cascader"
56
+ :options="item.optionArr"
57
+ :placeholder="`请选择${item.label}`"
58
+ :props="{
59
+ checkStrictly: false,
60
+ multiple: true,
61
+ emitPath: false,
62
+ label: 'optionLabel',
63
+ value: 'optionValue',
64
+ }"
65
+ clearable
66
+ @input="handleSelectorMultiple($event, item.prop)"
67
+ />
68
+
69
+ <!-- 3. 选择器_树结构 SelectorTreeStructure -->
70
+ <SelectTree
71
+ v-if="item.itemType === 'SelectorTreeStructure' || item.itemType === '选择器_树结构'"
72
+ ref="SelectTree"
73
+ :filterable="true"
74
+ :value-key="`deptId`"
75
+ :select-key="`deptId`"
76
+ :value-name="`deptName`"
77
+ :tree-data="item.optionArr"
78
+ :tree-props="{
79
+ id: 'deptId',
80
+ label: 'deptName',
81
+ children: 'children'
82
+ }"
83
+ :tree-node-key="`deptId`"
84
+ :placeholder-title="`请选择${item.label}`"
85
+ @nodeClickTree="nodeClickTree"
86
+ />
87
+
88
+ <!-- 4. 选择器_单时间 SelectorSingleTime -->
89
+ <el-date-picker
90
+ v-if="item.itemType === 'SelectorSingleTime' || item.itemType === '选择器_单时间'"
91
+ v-model="formInline[item.prop]"
92
+ type="datetime"
93
+ class="form_dataTime"
94
+ format="yyyy-MM-dd HH:mm:ss"
95
+ value-format="yyyy-MM-dd HH:mm:ss"
96
+ :placeholder="`请选择${item.label}日期时间`"
97
+ @input="handleInputValue($event, item.prop)"
98
+ />
99
+
100
+ <!-- 5. 选择器_单日期 SelectorSingleDate -->
101
+ <el-date-picker
102
+ v-if="item.itemType === 'SelectorSingleDate' || item.itemType === '选择器_单日期'"
103
+ v-model="formInline[item.prop]"
104
+ type="date"
105
+ class="form_picker"
106
+ :placeholder="`请选择${item.label}日期`"
107
+ format="yyyy-MM-dd"
108
+ value-format="yyyy-MM-dd"
109
+ @input="handleInputValue($event, item.prop)"
110
+ />
111
+
112
+ <!-- 6. 选择器_日期范围 SelectorDateRange -->
113
+ <el-date-picker
114
+ v-if="item.itemType === 'SelectorDateRange' || item.itemType === '选择器_日期范围'"
115
+ v-model="formInline[item.prop]"
116
+ type="daterange"
117
+ class="form_daterange"
118
+ format="yyyy-MM-dd"
119
+ value-format="yyyy-MM-dd"
120
+ start-placeholder="开始日期"
121
+ end-placeholder="结束日期"
122
+ @input="handleSelectorDateRange($event, item.prop)"
123
+ />
124
+
125
+ <!-- 7. 多行文本 MultilineText -->
126
+ <el-input
127
+ v-if="item.itemType === 'MultilineText' || item.itemType === '多行文本'"
128
+ v-model="formInline[item.prop]"
129
+ type="textarea"
130
+ class="form_multiline"
131
+ :autosize="{ minRows: 2, maxRows: 4}"
132
+ placeholder="请输入内容"
133
+ @input="handleInputValue($event, item.prop)"
134
+ />
135
+
136
+ <!-- 8. 单选框 RadioBox -->
137
+ <el-radio-group
138
+ v-if="item.itemType === 'RadioBox' || item.itemType === '单选框'"
139
+ v-model="formInline[item.prop]"
140
+ class="form_radio"
141
+ @input="handleInputValue($event, item.prop)"
142
+ >
143
+ <el-radio
144
+ v-for="(optionItem, optionIndex) in item.optionArr"
145
+ :key="optionItem.optionValue + optionIndex"
146
+ :label="optionItem"
147
+ >{{ optionItem.optionLabel }}</el-radio>
148
+ </el-radio-group>
149
+
150
+ <!-- 9. 多选框 MultipleCheckbox -->
151
+ <el-checkbox-group
152
+ v-if="item.itemType === 'MultipleCheckbox' || item.itemType === '多选框'"
153
+ v-model="formInline[item.prop]"
154
+ class="form_checkbox"
155
+ @input="handleInputValue($event, item.prop)"
156
+ >
157
+ <el-checkbox
158
+ v-for="(optionItem, optionIndex) in item.optionArr"
159
+ :key="optionItem.optionValue + optionIndex"
160
+ :label="optionItem"
161
+ >{{ optionItem.optionLabel }}</el-checkbox>
162
+ </el-checkbox-group>
163
+
164
+ <!-- 10. 输入框 InputString InputInteger InputDecimals -->
165
+ <el-input
166
+ v-if="item.itemType === 'InputString' || item.itemType === '字符型'"
167
+ v-model="formInline[item.prop]"
168
+ class="form_input"
169
+ :placeholder="`请选择${item.label}`"
170
+ @input="handleInputValue($event, item.prop)"
171
+ />
172
+ <el-input
173
+ v-if="item.itemType === 'InputDecimals' || item.itemType === '小数型'"
174
+ v-model="formInline[item.prop]"
175
+ class="form_input"
176
+ :placeholder="`请选择${item.label}`"
177
+ oninput="value=value.replace(/[^\d^\.]+/g, '').replace(/^0+(\d)/, '$1').replace(/^\./, '0.').match(/^\d*(\.?\d{0,3})/g)[0]"
178
+ @input="handleInputValue($event, item.prop)"
179
+ />
180
+ <el-input
181
+ v-if="item.itemType === 'InputInteger' || item.itemType === '整数型'"
182
+ v-model="formInline[item.prop]"
183
+ class="form_input"
184
+ :placeholder="`请选择${item.label}`"
185
+ oninput="value=value.replace(/[^\d]/g,'')"
186
+ @input="handleInputValue($event, item.prop)"
187
+ />
188
+
189
+ <!-- 11. 计数器 CounterFrame -->
190
+ <el-input-number
191
+ v-if="item.itemType === 'CounterFrame' || item.itemType === '计数器'"
192
+ v-model="formInline[item.prop]"
193
+ :min="0"
194
+ :max="10000"
195
+ class="form_number"
196
+ label="描述文字"
197
+ @input="handleInputValue($event, item.prop)"
198
+ />
199
+
200
+ <!-- 12. 文件上传 FileUpload -->
201
+
202
+ <!-- 13. 富文本 RichText -->
203
+
204
+
205
+ <!-- 备用校验方法 -->
206
+ <!-- <div class="input_error" v-if="item.isRulesType"> <span class="input_error_label" :title="item.label">{{item.label}}</span>不能为空 </div> -->
207
+ </template>
208
+ </el-form-item>
209
+ </el-form>
210
+ </div>
211
+ </template>
212
+
213
+ <script>
214
+ export default {
215
+ name: 'FormDialog',
216
+ components: {
217
+ SelectTree: () => import('./components/SelectTree') /* 3. 选择器_树结构 SelectorTreeStructure */
218
+ },
219
+ props: {
220
+ /* el-form-item表单循环项 */
221
+ formItemConfigArr: {
222
+ type: Array,
223
+ default: () => []
224
+ },
225
+ /* 表单label宽度 */
226
+ labelWidth: {
227
+ type: String,
228
+ default: '120px'
229
+ }
230
+ },
231
+ data() {
232
+ return {
233
+ /* 表单加载状态 */
234
+ loadingForm: false,
235
+ /* 表单model绑定对象 */
236
+ formInline: {},
237
+ /* 下拉框最小宽度样式 */
238
+ minWidth: undefined,
239
+ /* 1. 选择器_单选 SelectorSingleSelection 绑定的值 */
240
+ valueSelectorSingle: '',
241
+ /* 表单校验 */
242
+ rulesForm: {}
243
+ }
244
+ },
245
+ computed: {},
246
+ watch: {},
247
+ created() {
248
+ this.initialization()
249
+ },
250
+ mounted() {},
251
+ methods: {
252
+ /* 初始化数据 */
253
+ initialization() {
254
+ for (let i = 1; i < this.formItemConfigArr.length; i++) {
255
+ const item = this.formItemConfigArr[i]
256
+ this.rulesForm[item.prop] = {
257
+ required: true,
258
+ validator: this.validateRules(),
259
+ trigger: 'blur'
260
+ }
261
+ switch (item.itemType) {
262
+ /* 1. 选择器_单选 SelectorSingleSelection */
263
+ case 'SelectorSingleSelection':
264
+ this.formInline[item.prop] = {}
265
+ break
266
+
267
+ /* 2. 选择器_多选 SelectorMultipleSelection */
268
+ case 'SelectorMultipleSelection':
269
+ this.formInline[item.prop] = []
270
+ break
271
+
272
+ /* 3. 选择器_树结构 SelectorTreeStructure */
273
+ case 'SelectorTreeStructure':
274
+ this.formInline[item.prop] = {}
275
+ break
276
+
277
+ /* 8. 单选框 RadioBox */
278
+ case 'RadioBox':
279
+ this.formInline[item.prop] = {}
280
+ break
281
+
282
+ /* 9. 多选框 MultipleCheckbox */
283
+ case 'MultipleCheckbox':
284
+ this.formInline[item.prop] = []
285
+ break
286
+
287
+ /* 11. 计数器 CounterFrame */
288
+ case 'CounterFrame':
289
+ this.formInline[item.prop] = 0
290
+ break
291
+
292
+ /**
293
+ * 4. 选择器_单时间 SelectorSingleTime
294
+ * 5. 选择器_单日期 SelectorSingleDate
295
+ * 6. 选择器_日期范围 SelectorDateRange
296
+ * 7. 多行文本 MultilineText
297
+ * 10. 输入框 InputString InputInteger InputDecimals
298
+ * 12. 文件上传 FileUpload
299
+ * 13. 富文本 RichText
300
+ **/
301
+ default:
302
+ this.formInline[item.prop] = ''
303
+ }
304
+ }
305
+ },
306
+ /* 下拉框样式 无数据的情况下,给请选择提示设置最小宽度*/
307
+ setMinWidth(val) {
308
+ this.minWidth = val.srcElement.clientWidth
309
+ },
310
+ validateRules(value, prop) {
311
+ console.log('validateRules', value, prop)
312
+ if (!value) {
313
+ return `${prop}不能为空`
314
+ } else if (this.isNameType(value)) {
315
+ return `${prop}只包含中文、英文、空格、数字、中划线、下划线`
316
+ }
317
+ },
318
+ /**
319
+ * 只包含英文、数字、空格、中划线、下划线
320
+ * true 符合 false 不符合
321
+ **/
322
+ isCodeType(str, prop) {
323
+ if (str.length === 0) {
324
+ return `${prop}不能为空`
325
+ }
326
+ const reg = /[`~!@#$%^&*()+=<>?:"{}|,.;'·~!@#¥%……&*()——+={}|《》?:“”【】、;‘',。、]/im
327
+ const regOne = /^[^\u4e00-\u9fa5]+$/
328
+ const regTwo = /\\/
329
+ if (!reg.test(str) && regOne.test(str) && !regTwo.test(str)) {
330
+ return `${prop}只包含中文、英文、空格、数字、中划线、下划线`
331
+ }
332
+ return true
333
+ },
334
+ /**
335
+ * 可输入英文、中文、空格、数字、中划线、下划线,特殊字符可以排除
336
+ * true 符合 false 不符合
337
+ **/
338
+ isNameType(str, prop) {
339
+ if (str.length === 0) {
340
+ return `${prop}不能为空`
341
+ }
342
+ const reg = /[`~!@#$%^&*()+=<>?:"{}|,.;'·~!@#¥%……&*()——+={}|《》?:“”【】、;‘',。、]/im
343
+ const regTwo = /\\/
344
+ if (!reg.test(str) && !regTwo.test(str)) {
345
+ return `${prop}只包含英文、数字、空格、中划线、下划线`
346
+ }
347
+ return true
348
+ },
349
+
350
+ /* 1. 选择器_单选 SelectorSingleSelection */
351
+ handleSelectorSingle(e, prop, index) {
352
+ this.formInline[prop] = {}
353
+ const arr = this.formItemConfigArr[index].optionArr
354
+ const objIndex = arr.find(item => {
355
+ if (item.optionValue === e) return item
356
+ })
357
+ this.handleInputValue(objIndex, prop)
358
+ },
359
+ /* 2. 选择器_多选 SelectorMultipleSelection */
360
+ handleSelectorMultiple(e, prop) {
361
+ this.formInline[prop] = []
362
+ const nodesObj = this.$refs['formCascader'][0].getCheckedNodes()
363
+ const selectorMultipleSelectionArr = []
364
+ nodesObj.forEach(item => { selectorMultipleSelectionArr.push(item.data) })
365
+ this.handleInputValue(selectorMultipleSelectionArr, prop)
366
+ },
367
+
368
+ /* 3. 选择器_树结构 SelectorTreeStructure */
369
+ nodeClickTree(data) {
370
+ this.handleInputValue(data, 'SelectorTreeStructure')
371
+ },
372
+
373
+ /* 6. 选择器_日期范围 SelectorDateRange */
374
+ handleSelectorDateRange(e, prop) {
375
+ this.formInline[prop] = []
376
+ this.handleInputValue(e, prop)
377
+ },
378
+
379
+ /* 12. 文件上传 FileUpload */
380
+ /* 13. 富文本 RichText */
381
+
382
+ /**
383
+ * 4. 选择器_单时间 SelectorSingleTime
384
+ * 5. 选择器_单日期 SelectorSingleDate
385
+ * 7. 多行文本 MultilineText
386
+ * 8. 单选框 RadioBox
387
+ * 9. 多选框 MultipleCheckbox
388
+ * 10. 输入框 InputString InputInteger InputDecimals
389
+ * 11. 计数器 CounterFrame
390
+ **/
391
+ handleInputValue(e, prop) {
392
+ this.formInline[prop] = e
393
+ this.$forceUpdate()
394
+ const data = { data: e, prop: prop }
395
+ this.$emit('handleInputValue', data)
396
+ }
397
+ }
398
+ }
399
+ </script>
400
+ <style lang="scss" scoped>
401
+ // 1. 选择器_单选 form_select
402
+ .form_select {
403
+ width: 100%;
404
+ }
405
+
406
+ // 2. 选择器_多选 form_cascader
407
+ .form_cascader {
408
+ width: 100%;
409
+ }
410
+
411
+ // 3. 选择器_树结构 SelectorTreeStructure
412
+
413
+ // 4. 选择器_单时间 form_dataTime
414
+ .form_dataTime {
415
+ width: 100%;
416
+ }
417
+
418
+ // 5. 选择器_单日期 form_picker
419
+ .form_picker {
420
+ width: 100%;
421
+ }
422
+
423
+ // 6. 选择器_日期范围 form_daterange
424
+ .form_daterange {
425
+ width: 100%;
426
+ }
427
+
428
+ // 7. 多行文本 form_multiline
429
+ .form_multiline {
430
+ width: 100%;
431
+ }
432
+
433
+ // 8. 单选框 form_radio
434
+ .form_radio {
435
+ width: 100%;
436
+ }
437
+
438
+ // 9. 多选框 form_checkbox
439
+ .form_checkbox {
440
+ width: 100%;
441
+ }
442
+
443
+ // 10. 输入框 form_input
444
+ .form_input {
445
+ width: 100%;
446
+ }
447
+
448
+ // 11. 计数器 form_number
449
+ .form_number {
450
+ width: 100%;
451
+ }
452
+
453
+ // 12. 文件上传 FileUpload
454
+ // 13. 富文本 RichText
455
+
456
+ /* 表单 label 宽度样式 */
457
+ .label_title {
458
+ display: inline-block;
459
+ max-width: calc(100% - 10px);
460
+ box-sizing: border-box;
461
+ // padding-right: 10px;
462
+ /*让长段文本不换行*/
463
+ white-space: nowrap;
464
+ /*设置文本超出元素宽度部分隐藏*/
465
+ overflow-x: hidden;
466
+ /*设置文本超出部分用省略号显示*/
467
+ text-overflow: ellipsis;
468
+ vertical-align: middle;
469
+ }
470
+ </style>
@@ -0,0 +1,240 @@
1
+ <template>
2
+ <div id="instructions">
3
+ </div>
4
+ </template>
5
+ <script>
6
+ var [ renderer, scene, camera, cameraControls, loader, instructions,
7
+ raycaster, mouse, labelRenderer
8
+ ]= (function* (v) { while (true) yield v })(null)
9
+ var [ lastTime, firstTime, fpsClock, timeStamp ] = (function* (v) { while (true) yield v })(0)
10
+ import CameraControls from 'camera-controls'
11
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
12
+ import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js'
13
+ import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
14
+ import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
15
+ export default {
16
+ name: 'Model',
17
+ props: {
18
+ data: {
19
+ type: Array,
20
+ default() {
21
+ return []
22
+ }
23
+ },
24
+ glbUrl: {
25
+ type: String,
26
+ default() {
27
+ return ''
28
+ }
29
+ },
30
+ },
31
+ data() {
32
+ return {}
33
+ },
34
+ created() {
35
+ CameraControls.install({ THREE: this.THREE })
36
+ fpsClock = new this.THREE.Clock()
37
+ raycaster = new this.THREE.Raycaster()
38
+ mouse = new this.THREE.Vector2()
39
+ },
40
+ mounted() {
41
+ instructions = document.getElementById('instructions')
42
+ this.initRender()
43
+ this.initScene()
44
+ this.initCamera()
45
+ this.initControl()
46
+ this.initLight()
47
+ this.initLabelRender()
48
+ loader = new GLTFLoader()
49
+ loader.load('/example/worker.glb', (gltf) => {
50
+ const personModel = gltf.scene
51
+ scene.add(personModel)
52
+ personModel.scale.set(0.1, 0.1, 0.1)
53
+ })
54
+ renderer.domElement.addEventListener('mouseup', this.mouseClick, false)
55
+ renderer.domElement.addEventListener('mousedown',this.mouseDown, false)
56
+ this.animate()
57
+ },
58
+ methods: {
59
+ initRender() {
60
+ renderer = new this.THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })
61
+ renderer.setPixelRatio(window.devicePixelRatio * 2)
62
+ renderer.setSize(window.innerWidth, window.innerHeight)
63
+ renderer.domElement.id = 'three-model'
64
+ renderer.shadowMap.enabled = true
65
+ // 暂时注释这句 还有worker里面的 这跟渲染出的模型浅或暗有关系
66
+ renderer.outputEncoding = this.THREE.sRGBEncoding
67
+ instructions.appendChild(renderer.domElement)
68
+ renderer.autoClear = false
69
+ renderer.autoClearColor = false
70
+ renderer.autoClearDepth = false
71
+ renderer.autoClearStencil = false
72
+ },
73
+ initScene() {
74
+ scene = new this.THREE.Scene()
75
+ // scene.userData.recordEntity = []
76
+ },
77
+ initCamera() {
78
+ camera = new this.THREE.PerspectiveCamera(
79
+ 45,
80
+ window.innerWidth / window.innerHeight,
81
+ 0.1,
82
+ 1000
83
+ )
84
+ camera.position.set(0, 100, 150)
85
+ },
86
+ initControl() {
87
+ // 初始化控件
88
+ cameraControls = new CameraControls(camera, renderer.domElement)
89
+ cameraControls.dollyToCursor = true
90
+ cameraControls.smoothTime = 0.1
91
+ cameraControls.draggingSmoothTime = 0.05
92
+ cameraControls.truckSpeed = 2.0
93
+ cameraControls.infinityDolly = true
94
+ cameraControls.minDistance = 4
95
+ },
96
+ // 初始化光源
97
+ initLight() {
98
+ const pmremGenerator = new this.THREE.PMREMGenerator(renderer)
99
+ scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture
100
+ },
101
+ // 初始化文字画布
102
+ initLabelRender() {
103
+ labelRenderer = new CSS2DRenderer()
104
+ labelRenderer.setSize(instructions.offsetWidth, instructions.offsetHeight)
105
+ labelRenderer.domElement.style.position = 'absolute'
106
+ labelRenderer.domElement.style.top = '0px'
107
+ labelRenderer.domElement.style.pointerEvents = 'none'
108
+ instructions.appendChild(labelRenderer.domElement)
109
+ },
110
+ mouseDown() {
111
+ firstTime = new Date().getTime()
112
+ },
113
+ mouseClick(event) {
114
+ lastTime = new Date().getTime()
115
+ if (lastTime - firstTime < 300) {
116
+ mouse.x = (event.clientX / instructions.offsetWidth) * 2 - 1
117
+ mouse.y = -(event.clientY / instructions.offsetHeight) * 2 + 1
118
+ raycaster.setFromCamera(mouse, camera)
119
+ const intersects = raycaster.intersectObjects(scene.children, true)
120
+ console.log(intersects)
121
+ if (event.button === 0) {
122
+ this.$emit('leftClick', {
123
+ objects: intersects.length > 0 ? [intersects[0]] : []
124
+ })
125
+ } else if (event.button === 2) {
126
+ this.$emit('rightClick', {
127
+ objects: intersects.length > 0 ? [intersects[0]] : [],
128
+ position: { x: event.clientX, y: event.clientY }
129
+ })
130
+ }
131
+ }
132
+ },
133
+ // 修改模型实体属性
134
+ /**
135
+ * 参数内容{
136
+ * list: [{
137
+ * name: '',实体的名字
138
+ * attr: '', 属性名(color、visible(true / false)、opacity(0-1))
139
+ * value: '', 需要修改的值
140
+ * }] // 需要更改实体属性的数据
141
+ * It can be a CSS-style string. For example:
142
+ * 'rgb(250, 0,0)'
143
+ * 'rgb(100%,0%,0%)'
144
+ * 'hsl(0, 100%, 50%)'
145
+ * '#ff0000'
146
+ * '#f00'
147
+ * 'red'
148
+ * }
149
+ */
150
+ updateProperty(list) {
151
+ for (let index = 0; index < list.length; index++) {
152
+ let ele = list[index]
153
+ let obj = scene.getObjectByName(ele.name)
154
+ if (obj) {
155
+ switch (ele.attr) {
156
+ case 'color': obj.material.color = new this.THREE.Color(ele.value)
157
+ break;
158
+ case 'visible': obj.material.visible = ele.value
159
+ break;
160
+ case 'opacity':
161
+ obj.material.opacity = ele.value
162
+ obj.material.transparent = true
163
+ break;
164
+ }
165
+ obj.material.needsUpdate = true
166
+ }
167
+ }
168
+ },
169
+ // 清除上一次的高亮
170
+ // 需要清除高亮颜色的实体数据
171
+ recoverColor(list) {
172
+ for (let index = 0; index < list.length; index++) {
173
+ let ele = list[index]
174
+ let obj = scene.getObjectByName(ele)
175
+ if (obj) {
176
+ obj.material.color = obj.material.userData.nColor
177
+ obj.material.needsUpdate = true
178
+ }
179
+ }
180
+ },
181
+ // 相机定位
182
+ /*
183
+ 定位参数:x: 相机的x位置, y: 相机的y位置, z: 相机的z位置
184
+ heading, pitch, roll
185
+ 视点定位可直接使用此方法
186
+ */
187
+ cameraLocation(parmas) {
188
+ cameraControls.setLookAt(
189
+ parmas.x,
190
+ parmas.y,
191
+ parmas.z,
192
+ parmas.heading,
193
+ parmas.pitch,
194
+ parmas.roll,
195
+ true
196
+ )
197
+ cameraControls.update(0)
198
+ },
199
+ // 添加广告牌
200
+ /*
201
+ 参数{
202
+ billboard: DOM节点
203
+ name: 2d广告牌的名字,用来做清除用的
204
+ x、y、z为广告牌的位置
205
+ }
206
+ */
207
+ billboard(data) {
208
+ const divLabel = new CSS2DObject(data.billboard)
209
+ divLabel.name = data.labelClass // 这个是用来清除广告牌用的
210
+ divLabel.position.set(data.x, data.y, data.z)
211
+ scene.add(divLabel)
212
+ },
213
+ // 清除广告牌
214
+ clearBillboard(name) {
215
+ if (scene && scene.getObjectByName(name)) {
216
+ let sprit = scene.getObjectByName(name)
217
+ scene.remove(sprit)
218
+ this.clearBillboard()
219
+ }
220
+ },
221
+
222
+ animate() {
223
+ const delta = fpsClock.getDelta()
224
+ timeStamp += delta
225
+ requestAnimationFrame(this.animate)
226
+ cameraControls.enabled && cameraControls.update(timeStamp)
227
+ labelRenderer.render(scene, camera)
228
+ renderer.render( scene, camera )
229
+ },
230
+ },
231
+
232
+ }
233
+ </script>
234
+ <style lang="scss" scoped>
235
+ #instructions{
236
+ width: 100%;
237
+ height: 100%;
238
+ cursor: pointer;
239
+ }
240
+ </style>