Ver código fonte

测量线关联场景

bill 3 anos atrás
pai
commit
52670e2dae

+ 9 - 6
src/api/mesasure.ts

@@ -1,19 +1,22 @@
 import axios from './instance'
 import { MESASURE_LIST, INSERT_MESASURE, DELETE_MESASURE, UPDATE_MESASURE } from './constant'
+import { FuseModel } from '@/store'
 
 export enum MeasureType {
-  free = 0,
-  vertical,
-  area
+  free = 'free',
+  vertical = 'vertical',
+  area = 'area'
 }
 
-export interface Measure {
+export type MeasurePosition = {point: SceneLocalPos, modelId: FuseModel['id']}
+
+export interface Measure<T extends MeasureType = MeasureType> {
   id: string,
   fusionId: number,
   desc: string,
   title: string,
-  positions: SceneLocalPos[],
-  type: MeasureType,
+  positions: MeasurePosition[],
+  type: T,
 }
 
 interface ServiceMeasure {

+ 72 - 3
src/components/bill-ui/components/icon/iconfont/demo_index.html

@@ -55,6 +55,24 @@
           <ul class="icon_lists dib-box">
           
             <li class="dib">
+              <span class="icon iconfont">&#xe6e8;</span>
+                <div class="name">a-film</div>
+                <div class="code-name">&amp;#xe6e8;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe642;</span>
+                <div class="name">nav-edit</div>
+                <div class="code-name">&amp;#xe642;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe648;</span>
+                <div class="name">pic</div>
+                <div class="code-name">&amp;#xe648;</div>
+              </li>
+          
+            <li class="dib">
               <span class="icon iconfont">&#xe6e4;</span>
                 <div class="name">list-scene</div>
                 <div class="code-name">&amp;#xe6e4;</div>
@@ -330,9 +348,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1661479592359') format('woff2'),
-       url('iconfont.woff?t=1661479592359') format('woff'),
-       url('iconfont.ttf?t=1661479592359') format('truetype');
+  src: url('iconfont.woff2?t=1661736391827') format('woff2'),
+       url('iconfont.woff?t=1661736391827') format('woff'),
+       url('iconfont.ttf?t=1661736391827') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -359,6 +377,33 @@
         <ul class="icon_lists dib-box">
           
           <li class="dib">
+            <span class="icon iconfont icon-a-film"></span>
+            <div class="name">
+              a-film
+            </div>
+            <div class="code-name">.icon-a-film
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-nav-edit"></span>
+            <div class="name">
+              nav-edit
+            </div>
+            <div class="code-name">.icon-nav-edit
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-pic"></span>
+            <div class="name">
+              pic
+            </div>
+            <div class="code-name">.icon-pic
+            </div>
+          </li>
+          
+          <li class="dib">
             <span class="icon iconfont icon-list-scene"></span>
             <div class="name">
               list-scene
@@ -774,6 +819,30 @@
           
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-a-film"></use>
+                </svg>
+                <div class="name">a-film</div>
+                <div class="code-name">#icon-a-film</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-nav-edit"></use>
+                </svg>
+                <div class="name">nav-edit</div>
+                <div class="code-name">#icon-nav-edit</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-pic"></use>
+                </svg>
+                <div class="name">pic</div>
+                <div class="code-name">#icon-pic</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#icon-list-scene"></use>
                 </svg>
                 <div class="name">list-scene</div>

+ 15 - 3
src/components/bill-ui/components/icon/iconfont/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 3549513 */
-  src: url('iconfont.woff2?t=1661479592359') format('woff2'),
-       url('iconfont.woff?t=1661479592359') format('woff'),
-       url('iconfont.ttf?t=1661479592359') format('truetype');
+  src: url('iconfont.woff2?t=1661736391827') format('woff2'),
+       url('iconfont.woff?t=1661736391827') format('woff'),
+       url('iconfont.ttf?t=1661736391827') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,18 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-a-film:before {
+  content: "\e6e8";
+}
+
+.icon-nav-edit:before {
+  content: "\e642";
+}
+
+.icon-pic:before {
+  content: "\e648";
+}
+
 .icon-list-scene:before {
   content: "\e6e4";
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
src/components/bill-ui/components/icon/iconfont/iconfont.js


+ 21 - 0
src/components/bill-ui/components/icon/iconfont/iconfont.json

@@ -6,6 +6,27 @@
   "description": "",
   "glyphs": [
     {
+      "icon_id": "31503933",
+      "name": "a-film",
+      "font_class": "a-film",
+      "unicode": "e6e8",
+      "unicode_decimal": 59112
+    },
+    {
+      "icon_id": "25631122",
+      "name": "nav-edit",
+      "font_class": "nav-edit",
+      "unicode": "e642",
+      "unicode_decimal": 58946
+    },
+    {
+      "icon_id": "23786363",
+      "name": "pic",
+      "font_class": "pic",
+      "unicode": "e648",
+      "unicode_decimal": 58952
+    },
+    {
       "icon_id": "31485449",
       "name": "list-scene",
       "font_class": "list-scene",

BIN
src/components/bill-ui/components/icon/iconfont/iconfont.ttf


BIN
src/components/bill-ui/components/icon/iconfont/iconfont.woff


BIN
src/components/bill-ui/components/icon/iconfont/iconfont.woff2


+ 110 - 19
src/sdk/association.ts

@@ -1,6 +1,11 @@
 import { sdk } from './sdk'
 import { toRaw, ref, watch, nextTick } from 'vue'
-import { viewModeStack, showLeftPanoStack, custom, getResource } from '@/env'
+import { 
+  viewModeStack, 
+  showLeftPanoStack, 
+  custom, 
+  getResource 
+} from '@/env'
 import { 
   mount, 
   diffArrayChange, 
@@ -19,13 +24,33 @@ import {
   sysBus, 
   getFuseModelShowVariable, 
   SceneType,
-  backupFuseModels
+  backupFuseModels,
+  MeasureType,
+  measures
 } from '@/store'
 
 import TaggingComponent from '@/components/tagging/list.vue'
 
-import type { SDK, SceneModel, SceneGuidePath, ModelAttrRange } from '.'
-import { FuseModel, Tagging } from '@/store'
+import type { FuseModel, Tagging, Measure } from '@/store'
+import type { 
+  SDK, 
+  SceneModel, 
+  SceneGuidePath, 
+  ModelAttrRange, 
+  Measure as SceneMeasure 
+} from '.'
+
+let isUnSet = false
+const unSet = ((fn: () => void) => {
+  nextTick(() => {
+    isUnSet = true
+    fn()
+    nextTick(() => isUnSet = false)
+  })
+})
+
+
+// -----------------模型关联--------------------
 
 export const modelRange: ModelAttrRange  = {
   opacityRange: { min: 0, max: 100, step: 0.1 },
@@ -37,15 +62,6 @@ const sceneModelMap = new WeakMap<FuseModel, SceneModel>()
 export const getSceneModel = (model?: FuseModel | null) => model && sceneModelMap.get(toRaw(model))
 
 const associationModels = (sdk: SDK) => {
-  let isUnSet = false
-  const unSet = ((fn: () => void) => {
-    nextTick(() => {
-      isUnSet = true
-      fn()
-      nextTick(() => isUnSet = false)
-    })
-  })
-
   const getModels = () => fuseModels.value
   shallowWatchArray(getModels, (models, oldModels) => {
     const { added, deleted } = diffArrayChange(models, oldModels)
@@ -123,12 +139,37 @@ const associationModels = (sdk: SDK) => {
       (loaded) => {
         if (loaded) {
           const modelShow = getFuseModelShowVariable(item)
-          watch(() => item.bottom, () => isUnSet || getSceneModel(item)?.changeBottom(item.bottom), {immediate: true})
-          watch(() => item.opacity, () => isUnSet || getSceneModel(item)?.changeOpacity(item.opacity), {immediate: true})
-          watch(() => item.scale, () => isUnSet || getSceneModel(item)?.changeScale(item.scale), {immediate: true})
-          watch(() => item.position, () => isUnSet || getSceneModel(item)?.changePosition(item.position), {immediate: true})
-          watch(() => item.rotation, () => isUnSet || getSceneModel(item)?.changeRotation(item.rotation), {immediate: true})
-          watch(() => modelShow.value, () => isUnSet || getSceneModel(item)?.changeShow(modelShow.value), {immediate: true})
+          watch(
+            () => item.bottom, 
+            () => isUnSet || getSceneModel(item)?.changeBottom(item.bottom), 
+            { immediate: true }
+          )
+          watch(
+            () => item.opacity, 
+            () => isUnSet || getSceneModel(item)?.changeOpacity(item.opacity), 
+            { immediate: true }
+          )
+          watch(
+            () => item.scale, 
+            () => isUnSet || getSceneModel(item)?.changeScale(item.scale), 
+            { immediate: true }
+          )
+          watch(
+            () => item.position, 
+            () => isUnSet || getSceneModel(item)?.changePosition(item.position), 
+            { immediate: true }
+          )
+          watch(
+            () => item.rotation, 
+            () => isUnSet || getSceneModel(item)?.changeRotation(item.rotation), 
+            { immediate: true }
+          )
+          watch(
+            () => modelShow.value, 
+            () => isUnSet || getSceneModel(item)?.changeShow(modelShow.value), 
+            { immediate: true }
+          )
+
           stopLoadedWatch()
         }
       }
@@ -136,6 +177,9 @@ const associationModels = (sdk: SDK) => {
   })
 }
 
+
+// -----------------热点关联--------------------
+
 const associationTaggings = (el: HTMLDivElement) => {
   const getTaggings = () => taggings.value
   const taggingVMs = new WeakMap<Tagging, ReturnType<typeof mount>>()
@@ -153,6 +197,50 @@ const associationTaggings = (el: HTMLDivElement) => {
 }
 
 
+// -----------------测量关联--------------------
+
+const sceneMeasureMap = new WeakMap<Measure , SceneMeasure>()
+export const getSceneMeasure = (measure?: Measure | null) => measure && sceneMeasureMap.get(toRaw(measure))
+
+export const associationMessaure = <T extends MeasureType>(smMeasure: SceneMeasure<T>, measure: Measure<T>) => {
+  smMeasure.bus.on('update', ([points, modelIds]) => {
+    unSet(() => {
+      measure.positions = points.map((point, i) => ({ point, modelId: modelIds[i] }))
+      measure.desc = measure.type === MeasureType.area
+        ? (smMeasure as unknown as SceneMeasure<MeasureType.area>).getArea().toString()
+        : (smMeasure as unknown as SceneMeasure<MeasureType.free>).getDistance().toString()
+    })
+  })
+
+  smMeasure.bus.on('highlight', selected => unSet(() => measure.selected = selected))
+}
+
+const associationMessaures = (sdk: SDK) => {
+  const getMeasures = () => measures.value
+
+  shallowWatchArray(getMeasures, (measures, oldMeasures) => {
+    const { added, deleted } = diffArrayChange(measures, oldMeasures)
+    for (const item of added) {
+      const sceneMeasure = sdk.drawMeasure(item.type, item.positions)
+      associationMessaure(sceneMeasure, item)
+      sceneMeasureMap.set(item, sceneMeasure)
+    }
+    for (const item of deleted) {
+      const sceneMeasure = getSceneMeasure(item)
+      sceneMeasure && sceneMeasure.destroy()
+    }
+  })
+
+  arrayChildEffectScope(getMeasures, measure => {
+    watch(
+      () => measure.selected, 
+      (selected = false) => isUnSet || getSceneMeasure(measure)?.changeSelect(selected))
+  })
+}
+
+
+// -----------------导览关联--------------------
+
 const fullView = async (fn: () => void) => {
   const popViewMode = togetherCallback([
     viewModeStack.push(ref('full')),
@@ -219,7 +307,10 @@ export const playSceneGuide = async (paths: SceneGuidePath[], changeIndexCallbac
 export const pauseSceneGuide = () => isScenePlayIng.value = false
 
 
+// -----------------启动关联--------------------
+
 export const setupAssociation = (mountEl: HTMLDivElement) => {
   associationModels(sdk)
   associationTaggings(mountEl)
+  associationMessaures(sdk)
 }

+ 26 - 3
src/sdk/sdk.ts

@@ -1,7 +1,7 @@
 import cover from './cover'
 import { loadLib } from '@/utils'
 
-import type { FuseModelAttrs, FuseModel, GuidePath } from '@/store'
+import { FuseModelAttrs, FuseModel, GuidePath, MeasureType, Measure as StoreMeasure, MeasurePosition } from '@/store'
 import type { Emitter } from 'mitt'
 
 
@@ -78,6 +78,27 @@ export interface CameraComeToProps {
 
 export type CalcPathProps = [[SceneGuidePath, SceneGuidePath], Partial<Pick<SceneGuidePath, 'time' | 'speed'>>]
 
+
+
+export interface MeasureBase {
+  destroy: () => void
+  show: () => void
+  hide: () => void
+  bus: Emitter<{ update: [MeasurePosition['point'][], MeasurePosition['modelId'][]]; highlight: boolean }>
+  changeSelect: (isHight: boolean) => void
+} 
+
+export type Measure<T extends StoreMeasure['type'] = StoreMeasure['type']> = MeasureBase & (
+  T extends MeasureType.area
+    ? { getArea: () => number }
+    : { getDistance: () => number }
+)
+
+
+export type StartMeasure<T extends StoreMeasure['type']> = Measure<T> & {
+  bus: Emitter<{ submit: [MeasurePosition['point'][], MeasurePosition['modelId'][]]; cancel: void; invalidPoint: string }>
+}
+
 export interface SDK {
   layout: HTMLDivElement,
   sceneBus: Emitter<{ 'cameraChange': void }>
@@ -88,9 +109,11 @@ export interface SDK {
   screenshot: (width: number, height: number) => Promise<string>
   getPose: () => { position: SceneLocalPos, target: SceneLocalPos }
   comeTo: (pos: CameraComeToProps) => void
-  enterSceneGuide: (data: SceneGuidePath[]) => SceneGuide
+  enterSceneGuide: (data: SceneGuidePath[]) => SceneGuide,
+
+  drawMeasure<T extends StoreMeasure['type']>(type: T, positions: StoreMeasure['positions']): Measure<T>,
+  startMeasure<T extends StoreMeasure['type']>(type: T): StartMeasure<T> ,
 }
-  
 
 
 export let sdk: SDK

+ 7 - 4
src/store/measure.ts

@@ -17,7 +17,10 @@ import {
   postDeleteMeasure
 } from '@/api'
 
-import type { Measure, Measures } from '@/api'
+import type { Measure as SMeasure } from '@/api'
+
+export type Measure<T extends MeasureType = MeasureType> = SMeasure<T> & { selected?: boolean }
+export type Measures = Measure[]
 
 export const MeasureTypeMeta = {
   [MeasureType.area]: { icon: 'v-l', desc: '自由', unitDesc: '长度', unit: 'm' },
@@ -30,7 +33,7 @@ export const measures = ref<Measures>([])
 export const createMeasure = (measure: Partial<Measure> = {}): Measure => ({
   id: createTemploraryID(),
   fusionId: fuseModels.value[0].fusionId,
-  title: '',
+  title: `测量${measures.value.length + 1}`,
   positions: [],
   desc: '',
   type: MeasureType.free,
@@ -65,5 +68,5 @@ export const autoSaveMeasures = autoSetModeCallback(measures, {
   save: saveMeasures
 })
 
-export type { Measure, Measures } from '@/api'
-export { MeasureType }
+export type { MeasurePosition } from '@/api'
+export { MeasureType, }

+ 2 - 1
src/utils/index.ts

@@ -77,4 +77,5 @@ export * from './watch'
 export * from './diff'
 export * from './params'
 export * from './file-serve'
-export * from './video-cover'
+export * from './video-cover'
+export * from './meta'

+ 28 - 3
src/utils/meta.ts

@@ -1,7 +1,32 @@
+export enum MetaType {
+  image = 'image',
+  video = 'video',
+  other = 'other'
+}
 
-const images = ['bmp', 'jpg', 'png', 'tif', 'gif', 'pcx', 'tga', 'exif', 'fpx', 'svg', 'psd', 'cdr', 'pcd', 'dxf', 'ufo', 'eps', 'ai', 'raw', 'WMF', 'webp', 'avif', 'apng']
-const video = ['wmv', 'asf', 'asx', 'rm', 'rmvb', 'mp4', '3gp', 'mov', 'm4v', 'avi', 'dat', 'mkv', 'flv', 'vob']
+export const metaTypeExtnames = {
+  [MetaType.image]: ['bmp', 'jpg', 'png', 'tif', 'gif', 'pcx', 'tga', 'exif', 'fpx', 'svg', 'psd', 'cdr', 'pcd', 'dxf', 'ufo', 'eps', 'ai', 'raw', 'WMF', 'webp', 'avif', 'apng'],
+  [MetaType.video]: ['wmv', 'asf', 'asx', 'rm', 'rmvb', 'mp4', '3gp', 'mov', 'm4v', 'avi', 'dat', 'mkv', 'flv', 'vob']
+}
 
-export const getUrlType = (url: string) => {
+export const getExtname = (url: string) => {
+  const index = url.lastIndexOf('.')
+  if (~index) {
+    return url.substring(index + 1)
+  } else {
+    return null
+  }
+}
 
+export const getUrlType = (url: string) => {
+  const extname = getExtname(url)?.toLowerCase()
+  if (extname) {
+    for (const [type, extnames] of Object.entries(metaTypeExtnames)) {
+      if (extnames.includes(extname)) {
+        return type as MetaType
+      }
+    }
+  } else {
+    return MetaType.other
+  }
 }

+ 15 - 0
src/views/folder/index.vue

@@ -13,6 +13,7 @@
           class="fun-ctrl" 
           @click="preview(floder)"
         >
+          <ui-icon :type="typeIcons[floder.metaType]" v-if="floder.metaType" />
           <p>{{ floder.filesTitle }}</p>
         </div>
       </div>
@@ -23,6 +24,7 @@
 <script lang="ts" setup>
 import { LeftPano } from '@/layout'
 import { computed, ref } from 'vue';
+import { getUrlType, MetaType } from '@/utils'
 import { 
   initialFloderTypes, 
   initialFloders,
@@ -41,9 +43,19 @@ const types = computed(() =>
     id: type.filesTypeId,
     title: type.filesTypeName,
     floders: getFloderByType(type)
+      .map(floder => ({
+        ...floder,
+        metaType: getUrlType(floder.filesUrl)
+      })),
   }))
 )
 
+const typeIcons = {
+  [MetaType.image]: 'pic',
+  [MetaType.video]: 'a-film',
+  [MetaType.other]: 'nav-edit'
+}
+
 const preview = (floder: Floder) => window.open(floder.filesUrl)
 
 </script>
@@ -74,8 +86,11 @@ const preview = (floder: Floder) => window.open(floder.filesUrl)
     padding: 20px 10px;
     border-bottom: 1px solid rgba(255,255,255,0.16);
     cursor: pointer;
+    display: flex;
+    align-items: center;
 
     p {
+      margin-left: 10px;
       font-size: 12px;
       color: currentColor;
     }

+ 17 - 14
src/views/measure/edit.vue

@@ -4,10 +4,12 @@
 
 <script lang="ts" setup>
 import { ref, reactive, watch } from 'vue'
-import { enterEdit, enterOld, sysBus } from '@/store'
+import { enterEdit, enterOld, sysBus, giveupLeave, MeasureType } from '@/store'
 import { useViewStack } from '@/hook'
 import { togetherCallback } from '@/utils'
-import { showRightCtrlPanoStack, showRightPanoStack, } from '@/env'
+import { showRightCtrlPanoStack, showRightPanoStack } from '@/env'
+import { sdk, associationMessaure } from '@/sdk'
+import { Message } from 'bill/index'
 
 import type { Measure } from '@/store'
 
@@ -16,22 +18,23 @@ const emit = defineEmits<{
   (e: 'close'): void
   (e: 'submit', measure: Measure): void
 }>()
+
 const measure = reactive(props.measure)
+const modelMeasure = sdk.startMeasure(measure.type)
+associationMessaure(modelMeasure, measure)
+modelMeasure.bus.on('cancel', giveupLeave)
+modelMeasure.bus.on('invalidPoint', Message.error)
+
+enterEdit(() => {
+  emit('close')
+  modelMeasure.destroy()
+})
+watch(measure, () => enterOld(), { deep: true })
+sysBus.on('save', () => emit('submit', measure), { pre: true })
+
 
-enterEdit(() => emit('close'))
 useViewStack(() => togetherCallback([
   showRightCtrlPanoStack.push(ref(false)),
   showRightPanoStack.push(ref(false)),
 ]))
-sysBus.on('save', () => emit('submit', measure), { pre: true })
-watch(measure, () => enterOld(), { deep: true })
-
-setTimeout(() => {
-  measure.positions = [
-    {x: 1, y: 1, z: 1},
-    {x: 1, y: 1, z: 1},
-  ]
-  measure.title = '123123'
-  measure.desc = '20'
-}, 2000)
 </script>

+ 1 - 0
src/views/measure/index.vue

@@ -56,6 +56,7 @@ const editMeasure = ref<Measure | null>(null)
 const enterCreateMeasure = (type: MeasureType) => {
   editMeasure.value = createMeasure({ type })
 }
+
 const options: ActionsItem[] = [
   {
     icon: MeasureTypeMeta[MeasureType.free].icon,

+ 1 - 1
src/views/measure/sign.vue

@@ -24,7 +24,7 @@ withDefaults(
   { edit: true }
 )
 
-const emit = defineEmits<{ 
+defineEmits<{ 
   (e: 'delete'): void 
   (e: 'fly'): void
 }>()

+ 6 - 7
src/views/proportion/index.vue

@@ -18,7 +18,7 @@
 import { Message } from 'bill/index'
 import { useViewStack } from '@/hook'
 import { router } from '@/router'
-import { ref, computed, watchEffect, nextTick } from 'vue'
+import { ref, computed, watch, nextTick } from 'vue'
 import { getSceneModel } from '@/sdk'
 import { autoSaveFuseModels, getFuseModel, leave } from '@/store'
 
@@ -34,12 +34,12 @@ const model = computed(() => {
 const sceneModel = computed(() => model.value && getSceneModel(model.value))
 
 let scaleSet: ScaleSet | null = null
-const length = ref<number>()
+const length = ref<number | null>(null)
 
-watchEffect(() => {
+watch(length, () => {
   const len = length.value
-  if (len) {
-    nextTick(() => scaleSet?.setLength(len))
+  if (len !== null) {
+    scaleSet?.setLength(len)
   }
 })
 
@@ -55,8 +55,7 @@ useViewStack(() => {
     scaleSet.startMeasure()
     
     return () => {
-      console.error('???')
-      model.leaveAlignment()
+      model.leaveScaleSet()
       scaleSet = null
     }
   } else {

+ 20 - 7
vite.config.ts

@@ -31,11 +31,6 @@ export default defineConfig({
         changeOrigin: true,
         rewrite: path => path.replace(/^\/local/, '')
       },
-      '/api/laser': {
-        target: 'https://uat-laser.4dkankan.com/',
-        changeOrigin: true,
-        rewrite: path => path.replace(/^\/api/, '')
-      },
       '/api': {
         target: 'http://192.168.0.47:8808',
         changeOrigin: true,
@@ -50,11 +45,29 @@ export default defineConfig({
         target: 'https://test.4dkankan.com',
         changeOrigin: true,
       },
+
+
       '/swss': {
-        target: 'http://localhost:8080/',
+        target: 'https://uat-laser.4dkankan.com/uat',
         changeOrigin: true,
         rewrite: path => path.replace(/^\/swss/, '')
-      }
+      },
+      '/laser': {
+        target: 'https://uat-laser.4dkankan.com',
+        changeOrigin: true,
+        rewrite: path => path.replace(/^\/swss/, '')
+      },
+
+      // '/swss': {
+      //   target: 'localhost:8080',
+      //   changeOrigin: true,
+      //   rewrite: path => path.replace(/^\/swss/, '')
+      // },
+      // '/api/laser': {
+      //   target: 'https://uat-laser.4dkankan.com/',
+      //   changeOrigin: true,
+      //   rewrite: path => path.replace(/^\/api/, '')
+      // }
     }
   }
 })