fl-web-component 1.2.12 → 1.2.13

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 (52) hide show
  1. package/README.md +2 -0
  2. package/dist/fl-web-component.common.1.js.map +1 -1
  3. package/dist/fl-web-component.common.2.js.map +1 -1
  4. package/dist/fl-web-component.common.3.js.map +1 -1
  5. package/dist/fl-web-component.common.js +129 -86
  6. package/dist/fl-web-component.common.js.map +1 -1
  7. package/dist/fl-web-component.css +1 -1
  8. package/package.json +1 -1
  9. package/packages/components/com-graphics/index.vue +31 -6
  10. package/src/utils/flgltf-parser.js +68 -50
  11. package/src/utils/instance-parser.js +39 -30
  12. package/packages/components/button/index.vue +0 -26
  13. package/packages/components/model/api/index.js +0 -421
  14. package/packages/components/model/api/mock/detecttree.js +0 -58
  15. package/packages/components/model/api/mock/getmodel-line.js +0 -15834
  16. package/packages/components/model/api/mock/init.js +0 -1
  17. package/packages/components/model/api/mock/pbstree.js +0 -826
  18. package/packages/components/model/api/mock/topology.json +0 -3238
  19. package/packages/components/model/components/TextOverTooltip/index.vue +0 -84
  20. package/packages/components/model/components/annotation-toolbar.vue +0 -410
  21. package/packages/components/model/components/check-proofing-model.vue +0 -39
  22. package/packages/components/model/components/clipping-type.vue +0 -59
  23. package/packages/components/model/components/com-dialogWrapper/Readme.md +0 -53
  24. package/packages/components/model/components/com-dialogWrapper/index.vue +0 -114
  25. package/packages/components/model/components/detect-panel.vue +0 -339
  26. package/packages/components/model/components/detect-tree.vue +0 -445
  27. package/packages/components/model/components/firstPer-panel.vue +0 -109
  28. package/packages/components/model/components/header-button.vue +0 -470
  29. package/packages/components/model/components/imageViewer/index.vue +0 -126
  30. package/packages/components/model/components/import-model.vue +0 -127
  31. package/packages/components/model/components/location-panel.vue +0 -91
  32. package/packages/components/model/components/measure-type.vue +0 -59
  33. package/packages/components/model/components/pbs-tree.vue +0 -497
  34. package/packages/components/model/components/proof-config.vue +0 -72
  35. package/packages/components/model/components/proof-for-pc.vue +0 -126
  36. package/packages/components/model/components/proof-history.vue +0 -300
  37. package/packages/components/model/components/proof-panel-detail.vue +0 -568
  38. package/packages/components/model/components/proof-panel.vue +0 -846
  39. package/packages/components/model/components/proof-project-user.vue +0 -445
  40. package/packages/components/model/components/proof-publish.vue +0 -130
  41. package/packages/components/model/components/proof-role.vue +0 -504
  42. package/packages/components/model/components/props-panel.vue +0 -258
  43. package/packages/components/model/index.vue +0 -3425
  44. package/packages/components/model/readme.md +0 -31
  45. package/packages/components/model/utils/annotation-tool.js +0 -333
  46. package/packages/components/model/utils/cursor.js +0 -23
  47. package/packages/components/model/utils/detect-v1.js +0 -329
  48. package/packages/components/model/utils/index.js +0 -48
  49. package/packages/components/model/utils/threejs/measure-angle.js +0 -258
  50. package/packages/components/model/utils/threejs/measure-area.js +0 -281
  51. package/packages/components/model/utils/threejs/measure-distance.js +0 -209
  52. package/packages/components/model/utils/threejs/measure-volume.js +0 -97
@@ -1 +1 @@
1
- @charset "UTF-8";#fl-model[data-v-9d23b864],#konva-container[data-v-4458f11e]{width:100%;height:100%;cursor:pointer}#konva-container[data-v-4458f11e]{z-index:3;overflow:hidden}span[data-v-f547d5c6]{font-weight:bolder}.text[data-v-f547d5c6]{margin-top:20px}.line[data-v-f547d5c6]{border-bottom:1px solid #dcdfe6;margin:20px 0}.center[data-v-f547d5c6]{display:flex;flex-direction:column;align-items:center}.center .cen span[data-v-f547d5c6],.center .top span[data-v-f547d5c6]{color:"#53a8ff";display:inline-block;width:30px;height:30px;text-align:center;line-height:30px;border:1px solid;padding:5px;margin-bottom:10px;background-color:#e9f3ff}.center .cen span[data-v-f547d5c6]{margin:10px}.button[data-v-f547d5c6]{display:flex;justify-content:end;margin-top:20px}@font-face{font-family:iconfont;src:url(//at.alicdn.com/t/font_3226805_qqvo3ag3r8.woff2?t=1646635700216) format("woff2"),url(//at.alicdn.com/t/font_3226805_qqvo3ag3r8.woff?t=1646635700216) format("woff"),url(//at.alicdn.com/t/font_3226805_qqvo3ag3r8.ttf?t=1646635700216) format("truetype")}.iconfont[data-v-f547d5c6]{font-family:iconfont!important;font-size:50px;font-style:normal;color:"#53a8ff";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-shubiao[data-v-f547d5c6]:before{content:""}#svg-tigger[data-v-0ec35ee4]{cursor:pointer;height:100%;width:100%}
1
+ @charset "UTF-8";#fl-model[data-v-dee00b62],#konva-container[data-v-4458f11e]{width:100%;height:100%;cursor:pointer}#konva-container[data-v-4458f11e]{z-index:3;overflow:hidden}span[data-v-f547d5c6]{font-weight:bolder}.text[data-v-f547d5c6]{margin-top:20px}.line[data-v-f547d5c6]{border-bottom:1px solid #dcdfe6;margin:20px 0}.center[data-v-f547d5c6]{display:flex;flex-direction:column;align-items:center}.center .cen span[data-v-f547d5c6],.center .top span[data-v-f547d5c6]{color:"#53a8ff";display:inline-block;width:30px;height:30px;text-align:center;line-height:30px;border:1px solid;padding:5px;margin-bottom:10px;background-color:#e9f3ff}.center .cen span[data-v-f547d5c6]{margin:10px}.button[data-v-f547d5c6]{display:flex;justify-content:end;margin-top:20px}@font-face{font-family:iconfont;src:url(//at.alicdn.com/t/font_3226805_qqvo3ag3r8.woff2?t=1646635700216) format("woff2"),url(//at.alicdn.com/t/font_3226805_qqvo3ag3r8.woff?t=1646635700216) format("woff"),url(//at.alicdn.com/t/font_3226805_qqvo3ag3r8.ttf?t=1646635700216) format("truetype")}.iconfont[data-v-f547d5c6]{font-family:iconfont!important;font-size:50px;font-style:normal;color:"#53a8ff";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-shubiao[data-v-f547d5c6]:before{content:""}#svg-tigger[data-v-0ec35ee4]{cursor:pointer;height:100%;width:100%}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fl-web-component",
3
- "version": "1.2.12",
3
+ "version": "1.2.13",
4
4
  "scripts": {
5
5
  "tip1": "仅调试本组件不涉及业务组件,请执行dev",
6
6
  "dev": "vue-cli-service serve",
@@ -122,6 +122,7 @@
122
122
  this.initControl();
123
123
  this.initLight();
124
124
  this.initLabelRender();
125
+ this.exportParmas();
125
126
  // 判断是设备是手机还是电脑
126
127
  let isMobileDevice = this.isMobileDevice();
127
128
  if (isMobileDevice) {
@@ -153,6 +154,8 @@
153
154
  antialias: true,
154
155
  alpha: true,
155
156
  logarithmicDepthBuffer: true,
157
+ powerPreference: 'high-performance',
158
+ preserveDrawingBuffer: true, //保留图形缓冲区 TODO 临时截图使用
156
159
  });
157
160
  renderer.setPixelRatio(window.devicePixelRatio * 2);
158
161
  renderer.setSize(window.innerWidth, window.innerHeight);
@@ -162,10 +165,14 @@
162
165
  renderer.outputEncoding = this.THREE.sRGBEncoding;
163
166
  instructions.appendChild(renderer.domElement);
164
167
  renderer.setClearAlpha(0);
165
- renderer.autoClear = false;
166
- renderer.autoClearColor = false;
167
- renderer.autoClearDepth = false;
168
- renderer.autoClearStencil = false;
168
+
169
+ // 与校审截图功能冲突,暂时先注释掉
170
+ // -----------
171
+ // renderer.autoClear = false;
172
+ // renderer.autoClearColor = false;
173
+ // renderer.autoClearDepth = false;
174
+ // renderer.autoClearStencil = false;
175
+ // -----------
169
176
  },
170
177
  initScene() {
171
178
  modelGroup = new this.THREE.Group();
@@ -285,8 +292,13 @@
285
292
  box: volume,
286
293
  };
287
294
  },
288
- mouseDown() {
295
+ mouseDown(event) {
289
296
  firstTime = new Date().getTime();
297
+ let params = {
298
+ event,
299
+ firstTime,
300
+ };
301
+ this.$emit('leftMouseDown', params);
290
302
  },
291
303
  mouseClick(event) {
292
304
  // 在测量模式下,不进行事件暴露
@@ -1051,7 +1063,10 @@
1051
1063
  });
1052
1064
  },
1053
1065
  // 开启第一视角
1054
- startFirstPer() {
1066
+ startFirstPer({moveSpeed = 200, jumpSpeed = 200}) {
1067
+ removeSpeed = moveSpeed;
1068
+ upSpeed = jumpSpeed;
1069
+
1055
1070
  clock = new this.THREE.Clock();
1056
1071
  downRaycaster = new this.THREE.Raycaster(
1057
1072
  new this.THREE.Vector3(),
@@ -1486,6 +1501,16 @@
1486
1501
  outlineComposer && outlineComposer.render();
1487
1502
  }
1488
1503
  },
1504
+ // 暴露个别参数让业务自己做特殊业务。
1505
+ // 后续若多个业务有相同使用场景,再抽象至公共组件中。
1506
+ exportParmas(){
1507
+ return {
1508
+ renderer,
1509
+ camera,
1510
+ cameraControls,
1511
+ scene,
1512
+ }
1513
+ }
1489
1514
  },
1490
1515
  };
1491
1516
  </script>
@@ -1,31 +1,12 @@
1
1
  import * as THREE from 'three';
2
2
 
3
- function parseData(input) {
4
- // 辅助函数:递归处理实例
5
- function processInstance(instance, parentInstanceId, instanceMap) {
6
- const newInstance = {
7
- category: instance.category || instance.name,
8
- drawObject: instance.drawObject || instance.mesh,
9
- fatherId: parentInstanceId || '',
10
- instanceId: instance.instanceId || instance._batchId,
11
- matrix: instance.matrix,
12
- children: [],
13
- };
14
-
15
- // 处理子实例
16
- if (instance.children && instance.children.length > 0) {
17
- instance.children.forEach(childId => {
18
- const childInstance = instanceMap.get(childId);
19
- if (childInstance) {
20
- const processedChild = processInstance(childInstance, instance.instanceId, instanceMap);
21
- newInstance.children.push(processedChild);
22
- }
23
- });
24
- }
25
-
26
- return newInstance;
27
- }
3
+ const NODE_TYPES = {
4
+ pbsGrp: 1,
5
+ major: 2,
6
+ model: 3,
7
+ };
28
8
 
9
+ function parseData(input) {
29
10
  function flattenAndComputeWorldMatrices(
30
11
  nodes,
31
12
  result = [],
@@ -33,7 +14,7 @@ function parseData(input) {
33
14
  fatherId = ''
34
15
  ) {
35
16
  for (const node of nodes) {
36
- const { category, instanceId, matrix, children, drawObject } = node;
17
+ const { category, instanceId, matrix, children, drawObject, groupId, nodeType } = node;
37
18
 
38
19
  // 构造本地矩阵
39
20
  let localMatrix;
@@ -59,40 +40,19 @@ function parseData(input) {
59
40
  val: Array.from(worldMatrix.toArray()),
60
41
  },
61
42
  fatherId,
43
+ groupId,
44
+ nodeType,
62
45
  });
63
46
 
64
47
  // 递归处理子节点,传递当前世界矩阵
65
48
  if (children) {
66
- // flattenAndComputeWorldMatrices(children, result, worldMatrix, instanceId);
67
49
  flattenAndComputeWorldMatrices(children, result, instanceId);
68
- // flattenAndComputeWorldMatrices(children, result);
69
50
  }
70
51
  }
71
52
 
72
53
  return result;
73
54
  }
74
55
 
75
- // 创建实例映射
76
- const instanceMap = new Map();
77
- input.node.forEach(instance => {
78
- instanceMap.set(instance.id, instance);
79
- });
80
-
81
- // 处理根实例
82
- const rootInstances = [];
83
- instanceMap.forEach(instance => {
84
- let isRoot = true;
85
- instanceMap.forEach(otherInstance => {
86
- if (otherInstance.children && otherInstance.children.includes(instance.id)) {
87
- isRoot = false;
88
- }
89
- });
90
- if (isRoot) {
91
- const processed = processInstance(instance, null, instanceMap);
92
- rootInstances.push(processed);
93
- }
94
- });
95
-
96
56
  // const formateArray = (str) => str?.split(",").map(Number)
97
57
  // 处理drawObjs
98
58
  const drawObjMap = new Map();
@@ -139,6 +99,7 @@ function parseData(input) {
139
99
  });
140
100
 
141
101
  const formatInstances = [];
102
+ const rootInstances = parseNode(input.node);
142
103
  flattenAndComputeWorldMatrices(rootInstances, formatInstances);
143
104
 
144
105
  const map = {
@@ -149,4 +110,61 @@ function parseData(input) {
149
110
  return map;
150
111
  }
151
112
 
152
- export { parseData };
113
+ // 递归处理节点实例
114
+ function parseNode(node) {
115
+ function processInstance(instance, parentInstanceId, instanceMap, groupId) {
116
+ const newInstance = {
117
+ category: instance.category || instance.name,
118
+ drawObject: instance.drawObject || instance.mesh,
119
+ fatherId: parentInstanceId || '',
120
+ instanceId: instance.instanceId || instance._batchId,
121
+ matrix: instance.matrix,
122
+ children: [],
123
+ nodeType: instance.nodeType,
124
+ groupId: instance.nodeType === NODE_TYPES.pbsGrp ? instance._batchId : groupId,
125
+ };
126
+
127
+ // 处理子实例
128
+ if (instance.children && instance.children.length > 0) {
129
+ instance.children.forEach(childId => {
130
+ const childInstance = instanceMap.get(childId);
131
+ if (childInstance) {
132
+ const processedChild = processInstance(
133
+ childInstance,
134
+ instance._batchId,
135
+ instanceMap,
136
+ newInstance.groupId
137
+ );
138
+ newInstance.children.push(processedChild);
139
+ }
140
+ });
141
+ }
142
+
143
+ return newInstance;
144
+ }
145
+
146
+ // 创建实例映射
147
+ const instanceMap = new Map();
148
+ node.forEach(instance => {
149
+ instanceMap.set(instance.id, instance);
150
+ });
151
+
152
+ // 处理根实例
153
+ const rootInstances = [];
154
+ instanceMap.forEach(instance => {
155
+ let isRoot = true;
156
+ instanceMap.forEach(otherInstance => {
157
+ if (otherInstance.children && otherInstance.children.includes(instance.id)) {
158
+ isRoot = false;
159
+ }
160
+ });
161
+ if (isRoot) {
162
+ const processed = processInstance(instance, instance._batchId, instanceMap);
163
+ rootInstances.push(processed);
164
+ }
165
+ });
166
+
167
+ return rootInstances;
168
+ }
169
+
170
+ export { parseData, parseNode };
@@ -21,7 +21,7 @@ const GEOM_TYPES = {
21
21
 
22
22
  // 文本对齐枚举
23
23
  const TextAlign = {
24
- TextLeftBottom: 0, // 左下角
24
+ TextLeftBottom: 0, // 左下角
25
25
  TextLeftMiddle: 1,
26
26
  TextLeftTop: 2,
27
27
  TextCenterBottom: 3,
@@ -29,13 +29,13 @@ const TextAlign = {
29
29
  TextCenterTop: 5,
30
30
  TextRightBottom: 6,
31
31
  TextRightMiddle: 7,
32
- TextRightTop: 8, // 右上角
32
+ TextRightTop: 8, // 右上角
33
33
  TextLeft: 9,
34
34
  TextCenter: 10,
35
35
  TextRight: 11,
36
36
  TextAligned: 12,
37
37
  TextMiddle: 13,
38
- TextFit: 14
38
+ TextFit: 14,
39
39
  };
40
40
 
41
41
  let drawObjMapInstance = {};
@@ -85,6 +85,7 @@ function handleInstancedMeshModel(
85
85
  // grouphName !== '' ? instances[i].drawObject + grouphName: instances[i].drawObject;
86
86
  group.name = instances[i].drawObject;
87
87
  group.userData.isInstancedMeshGroup = true;
88
+ group.userData.category = instances[i].category;
88
89
  group.userData.instanceId = instances[i].drawObject;
89
90
  const instanceCount = drawObj.MapInstance.length;
90
91
  drawObj.MapMesh?.forEach(mesh => {
@@ -118,13 +119,13 @@ function handleInstancedMeshModel(
118
119
  // m4.setPosition(new THREE.Vector3(9999999, 9999999, 9999999)); // TODO 临时隐藏方案
119
120
  meshMatrix.elements = item.matrix.val;
120
121
  geomMatrix.elements = mesh.matrix.val;
121
-
122
+
122
123
  // 处理文本居中对齐
123
124
  const { points, alignType } = mesh;
124
- if(isTextType(mesh.type)){
125
+ if (isTextType(mesh.type)) {
125
126
  const positionMatrix = new THREE.Matrix4();
126
-
127
- const alignMatrix = createAlignedText(alignType, model.geometry)
127
+
128
+ const alignMatrix = createAlignedText(alignType, model.geometry);
128
129
 
129
130
  positionMatrix.identity().makeTranslation(points[0], points[1], points[2]);
130
131
  geomMatrix.multiply(alignMatrix).multiply(positionMatrix);
@@ -239,14 +240,15 @@ function drawModel(geom, instanceName, instanceCount, nColor, nOpacity) {
239
240
  * @param {number} type - 几何类型枚举值,参考GEOM_TYPES中的定义
240
241
  * @returns {boolean} 是否为文本类型(2D/3D 单行或多行文本)
241
242
  */
242
- function isTextType(type){
243
- return type == GEOM_TYPES.geom_2d_text ||
243
+ function isTextType(type) {
244
+ return (
245
+ type == GEOM_TYPES.geom_2d_text ||
244
246
  type == GEOM_TYPES.geom_2d_mtext ||
245
247
  type == GEOM_TYPES.geom_3d_text ||
246
248
  type == GEOM_TYPES.geom_3d_mtext
249
+ );
247
250
  }
248
251
 
249
-
250
252
  /**
251
253
  * 绘制曲线
252
254
  *
@@ -314,7 +316,14 @@ function drawCurves(geom, instanceName, instanceCount) {
314
316
  */
315
317
  function draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity) {
316
318
  // 解构几何数据中的自定义几何体和材质
317
- const { geometry: customGeometry, material: customMaterial, triangles, points, normals, prop } = geom;
319
+ const {
320
+ geometry: customGeometry,
321
+ material: customMaterial,
322
+ triangles,
323
+ points,
324
+ normals,
325
+ prop,
326
+ } = geom;
318
327
  // 使用自定义几何体或创建新的缓冲几何体
319
328
  const geometry = customGeometry || new THREE.BufferGeometry();
320
329
 
@@ -359,9 +368,10 @@ function draw3Dmodel(geom, instanceName, instanceCount, nColor, nOpacity) {
359
368
  transparent: true, // 着色器中需要设置透明度
360
369
  };
361
370
 
362
- customMaterial && Object.assign(customMaterial, materialOptions)
371
+ customMaterial && Object.assign(customMaterial, materialOptions);
363
372
 
364
- material = customMaterial ||
373
+ material =
374
+ customMaterial ||
365
375
  new THREE.MeshStandardMaterial({
366
376
  ...materialOptions,
367
377
  roughness: 0.6,
@@ -522,7 +532,7 @@ function drawText(geom, instanceName, instanceCount) {
522
532
  }
523
533
 
524
534
  /**
525
- *
535
+ *
526
536
  * @param {number} align 对齐方式
527
537
  * @param {object} geometry 几何体
528
538
  * @returns
@@ -531,13 +541,13 @@ function createAlignedText(align = TextAlign.TextLeftBottom, geometry) {
531
541
  // 计算几何体包围盒用于对齐计算
532
542
  geometry.computeBoundingBox();
533
543
  const bbox = geometry.boundingBox;
534
-
544
+
535
545
  // 初始化水平和垂直偏移量
536
546
  let offsetX = 0;
537
547
  let offsetY = 0;
538
-
548
+
539
549
  // 水平对齐处理(X轴方向)
540
- switch(align) {
550
+ switch (align) {
541
551
  // 左对齐系列(文本左边界对齐原点)
542
552
  case TextAlign.TextLeft:
543
553
  case TextAlign.TextLeftBottom:
@@ -545,15 +555,15 @@ function createAlignedText(align = TextAlign.TextLeftBottom, geometry) {
545
555
  case TextAlign.TextLeftTop:
546
556
  offsetX = -bbox.min.x; // 左边界对齐
547
557
  break;
548
-
549
- // 居中对齐系列(文本中心对齐原点)
558
+
559
+ // 居中对齐系列(文本中心对齐原点)
550
560
  case TextAlign.TextCenter:
551
561
  case TextAlign.TextCenterBottom:
552
562
  case TextAlign.TextCenterMiddle:
553
563
  case TextAlign.TextCenterTop:
554
564
  offsetX = -(bbox.min.x + bbox.max.x) / 2; // 水平居中
555
565
  break;
556
-
566
+
557
567
  // 右对齐系列(文本右边界对齐原点)
558
568
  case TextAlign.TextRight:
559
569
  case TextAlign.TextRightBottom:
@@ -562,9 +572,9 @@ function createAlignedText(align = TextAlign.TextLeftBottom, geometry) {
562
572
  offsetX = -bbox.max.x; // 右边界对齐
563
573
  break;
564
574
  }
565
-
575
+
566
576
  // 垂直对齐处理(Y轴方向)
567
- switch(align) {
577
+ switch (align) {
568
578
  // 垂直居中系列
569
579
  case TextAlign.TextMiddle:
570
580
  case TextAlign.TextLeftMiddle:
@@ -572,15 +582,15 @@ function createAlignedText(align = TextAlign.TextLeftBottom, geometry) {
572
582
  case TextAlign.TextRightMiddle:
573
583
  offsetY = -(bbox.min.y + bbox.max.y) / 2; // 垂直居中
574
584
  break;
575
-
576
- // 顶部对齐系列
585
+
586
+ // 顶部对齐系列
577
587
  case TextAlign.TextTop:
578
588
  case TextAlign.TextLeftTop:
579
589
  case TextAlign.TextCenterTop:
580
590
  case TextAlign.TextRightTop:
581
591
  offsetY = -bbox.max.y; // 顶部对齐
582
592
  break;
583
-
593
+
584
594
  // 底部对齐系列
585
595
  case TextAlign.TextBottom:
586
596
  case TextAlign.TextLeftBottom:
@@ -589,13 +599,12 @@ function createAlignedText(align = TextAlign.TextLeftBottom, geometry) {
589
599
  offsetY = -bbox.min.y; // 底部对齐
590
600
  break;
591
601
  }
592
-
602
+
593
603
  // 创建对齐变换矩阵
594
604
  const alignMatrix = new THREE.Matrix4();
595
- alignMatrix.identity().makeTranslation(offsetX, offsetY, 0)
596
-
597
- return alignMatrix;
598
- }
605
+ alignMatrix.identity().makeTranslation(offsetX, offsetY, 0);
599
606
 
607
+ return alignMatrix;
608
+ }
600
609
 
601
610
  export { handleInstancedMeshModel };
@@ -1,26 +0,0 @@
1
- <template>
2
- <div>
3
- <button class="my-button" @click="handleClick">
4
- {{ text }}
5
- </button>
6
- </div>
7
- </template>
8
- <script>
9
- export default {
10
- name: 'MyButton',
11
- props: {
12
- text: { type: String, default: 'Click Me' },
13
- },
14
- methods: {
15
- handleClick() {
16
- this.$emit('click');
17
- },
18
- },
19
- };
20
- </script>
21
- <style lang="scss" scoped>
22
- .my-button {
23
- padding: 8px 16px;
24
- background: #42b983;
25
- }
26
- </style>