Skip to content

标签管理组件

功能介绍

通过远程调用接口获取标签信息,实现标签交互的协同共享。

注:该功能使用了 elementUI 库,使用前需安装该库,具体方法见 elementUI 安装

不妨通过代码示例在 Vue 中尝试一下:

组件代码示例

默认路径为 components/labelManageSet/index.vue

vue
<template>
  <div>
    <!-- 标签管理 -->
    <el-card class="box-card">
      <div class="title">标签管理</div>
      <hr />
      <div class="button mainButton" @click="createLabel()">创建标签</div>

      <el-table
        v-loading="loading"
        :data="testData"
        :empty-text="emptyText"
        style="width: 100%; min-width: 270px"
        max-height="300px"
        highlight-current-row
        @row-dblclick="onClickRow"
      >
        <el-table-column
          label="显隐"
          width="50"
          header-align="center"
          align="center"
        >
          <template slot-scope="scope">
            <el-switch
              v-model="scope.row.isShow"
              :active-value="1"
              :nactive-value="0"
              active-color="#13ce66"
              inactive-color="#ff4949"
              @change="handleChange(scope.$index, scope.row)"
            >
            </el-switch>
          </template>
        </el-table-column>

        <el-table-column
          label="标签名称"
          width="120"
          header-align="center"
          align="center"
        >
          <template slot-scope="scope">
            <div slot="reference" class="name-wrapper">
              <el-tag size="medium">{{ scope.row.text }}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="操作" header-align="center" align="center">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="danger"
              @click="handleDelete(scope.$index, scope.row)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>

<script type="text/javascript">
import * as Cesium from 'cesium'
import axios from 'axios'
import { GET_LABEL_LIST, INSERT_LABEL, UPDATE_LABEL_ISSHOW, DELETE_LABEL } from '@/apis/label/label'

export default {
  components: {

  },
  data () {
    return {
      modelId: 1,
      loading: false,
      emptyText: "暂无数据",
      testData: [],
      tempData: []
    }
  },

  methods: {

    /**
     * 生成标签
     */
    initLabel () {

      // 暂时关闭定时器
      clearInterval(window.onlineInterval);
      window.onlineInterval = undefined;

      //  获取label
      // TODO: 这里暂时扩大到500,500后的数据如何管理后面处理
      axios.get(GET_LABEL_LIST, {
        params: { modelId: this.modelId, size: 500 }
      })
        .then((res) => {

          // 找出在testData中但不在云端中的数据,进行隐藏
          let badData = this.tempData.filter(item => !res.data.data.records.includes(item))
          badData.forEach((ele) => {
            if (uniCore.tip.getTipById(ele.id) !== null) {
              uniCore.tip.hideTipById(ele.id, true)
              uniCore.tip.hidePointById(ele.id, true)
            }

          })
          this.tempData = res.data.data.records;


          this.testData = res.data.data.records;
          if (this.testData.length === 0) this.emptyText = "暂无数据";
          this.loading = false;
          // 添加标签
          this.testData.forEach(ele => {
            uniCore.tip.getTipById(ele.id).then((res) => {
              if (res === null) {
                if (ele.isShow) {
                  let axis = {};
                  axis.x = parseFloat(ele.xAxis)
                  axis.y = parseFloat(ele.yAxis)
                  axis.z = parseFloat(ele.zAxis)
                  uniCore.tip.createPoint(ele.id, axis)
                  uniCore.tip.initTip(ele.id, axis, ele.text, [0, 1.3, 55000, 0.5], [0, 1.0, 550000, 0.0], ele.color, 1)
                }
              } else {
                uniCore.tip.hideTipById(ele.id, !ele.isShow)
                uniCore.tip.hidePointById(ele.id, !ele.isShow)
              }
            })
          })
        }).then(() => {
          // 重启定时器
          this.$parent.createOnlineInterval();
        })
        .catch(error => {
          console.log(error);
          this.emptyText = "网络错误";
          this.$notify.error({
            title: '错误',
            message: '网络错误,无法更新数据',
          });
          this.loading = false;
        })


      // // TODO: 缓存当前数据,接后端后可考虑删除或修改此处逻辑
      // localStorage.setItem('labelData', JSON.stringify(this.testData));


    },

    onClickRow (val) {
      let axis = uniCore.position.cartesian3_2axis(val.axis);
      uniCore.position.buildingPosition(uniCore.viewer, [axis[0], axis[1], 760], -20, -90, 1)
    },

    handleChange (index, row) {

      // 这里需要将修改提交到后端再进行更新标签状态,以保证多端协同
      this.loading = true;
      row.isShow = !row.isShow ? 0 : 1;
      //  获取label
      axios.post(UPDATE_LABEL_ISSHOW, {
        id: row.id, isShow: row.isShow
      })
        .then((res) => {
          // console.log(res);

          // 更新标签状态
          this.initLabel();
          this.loading = true;
        })
        .catch(error => {
          console.log(error);
          this.emptyText = "网络错误";
          this.$notify.error({
            title: '错误',
            message: '网络错误,无法更新数据',
          });
          this.loading = false;
        })


    },

    handleDelete (index, row) {
      this.loading = true;
      //  删除label
      axios.post(DELETE_LABEL, {
        "id": row.id
      })
        .then((res) => {
          // console.log(res);
          // 隐藏被删除的标签,下一次不再加载该标签
          uniCore.tip.hideTipById(row.id, true)
          uniCore.tip.hidePointById(row.id, true)
          // // 实时删除功能
          this.testData = this.testData.filter(e => e.id !== row.id)
          this.loading = false;

        })
        .catch(error => {
          console.log(error);
          this.$notify.error({
            title: '错误',
            message: '网络错误,无法更新数据',
          });
          this.loading = false;
        })




    },

    /**
     * 创建标签
     */
    createLabel () {
      // 提示用户点击位置创建标签
      this.$notify({
        title: '提示',
        message: '请点击要创建标签的位置',
        type: 'info',
        duration: 500
      });

      viewer.scene.globe.depthTestAgainstTerrain = true; // 必须开启深度检测,否则标签可能不在理想位置

      let uniCore = window.uniCore;

      this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
      this.handler.setInputAction((event) => {
        const earthPosition = viewer.scene.pickPosition(event.position);
        if (Cesium.defined(earthPosition)) {

          // 创建输入框
          let ret = prompt("请输入标签内容");
          if (ret !== null && ret !== "") {
            // 销毁当前方法左键点击事件
            if (this.handler) {
              this.handler.destroy();
              this.handler = undefined;
            }

            let labelObj = {};
            labelObj.modelId = this.modelId;
            labelObj.text = ret;
            labelObj.xAxis = earthPosition.x;
            labelObj.yAxis = earthPosition.y;
            labelObj.zAxis = earthPosition.z;
            labelObj.color = "#1a1a1a";
            labelObj.isShow = 1;


            this.loading = true;
            //  新增label
            axios.post(INSERT_LABEL, labelObj)
              .then((res) => {
                // console.log(res);

                // 更新标签状态
                this.initLabel();
                this.loading = true;
              })
              .catch(error => {
                console.log(error);
                this.$notify.error({
                  title: '错误',
                  message: '网络错误,无法更新数据',
                });
                this.loading = false;
              })



            //             // TODO: 缓存当前数据,接后端后可考虑删除或修改此处逻辑
            // localStorage.setItem('labelData', JSON.stringify(this.testData));

            function guid () {
              return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                var r = Math.random() * 16 | 0,
                  v = c == 'x' ? r : (r & 0x3 | 0x8);
                return v.toString(16);
              });
            }

          }



        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }



  },

  mounted () {
    // // TODO:获取缓存数据,接后端后可考虑删除
    // if (localStorage.getItem('labelData') !== null) {
    //   this.testData = JSON.parse(localStorage.getItem('labelData'));
    // }
  }

}
</script>
<style scoped>
#unicoreContainer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: black;
}
</style>

<style rel="stylesheet/scss" lang="scss" scoped>
::v-deep .el-card__body {
  padding: 20px 0px 0 0px;
}
::v-deep .box-card {
  position: absolute;
  top: 3%;
  left: 3%;
  width: 300px;
  z-index: 1;
  background: rgb(26 26 26 / 83%);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0px 24px 54px 0px rgba(35, 41, 50, 0.5);
  border-radius: 15px;
  padding: 0 24px 24px 24px;
  margin-bottom: 12px;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);

  .title {
    font-size: 18px;
    font-weight: bold;
    text-shadow: 1px 1px #000;
    color: #fefeff;
    display: block;
    margin-bottom: 10px;
  }

  hr {
    margin-left: 24px;
    margin-bottom: 10px;
    border: none;
    border-bottom: 1px solid #ffffff1a;
  }

  .el-table {
    border-radius: 15px;
  }

  .button {
    display: inline-flex;
    margin: 5px 10px;
    color: white;
    background: #4d4d4dd1;
    border-radius: 10px;
    padding: 7px 20px;
    cursor: pointer;
    transition: 0.3s;
  }

  .mainButton {
    background: #105bc5;
    font-weight: 700;
    padding: 7px 40px;
  }

  .subButton {
    background: #979797cc;
  }

  .mainButton:hover {
    background: #009fff;
    box-shadow: 0px 0px 54px 0px #009fffa8;
  }

  .subButton:hover {
    background: #d7d7d7cc;
    box-shadow: 0px 0px 54px 0px #d7d7d7a8;
  }
}
</style>

API代码示例(服务器需自行配置):

js
let baseURL = process.env.VUE_APP_DEV_API || ""

export const GET_LABEL_LIST = baseURL + "/bim/label/list"
export const INSERT_LABEL = baseURL + "/bim/label/add"
export const UPDATE_LABEL_ISSHOW = baseURL + "/bim/label/update"
export const DELETE_LABEL = baseURL + "/bim/label/del"

接口配置可参考 示例项目 Apifox 文档 中有关于 label 的接口响应示例。

调用代码示例

vue
<template>
  <div id="unicoreContainer">
    <!-- 标签管理窗口卡片开始 -->
    <lmSet ref="lmSetId"></lmSet>
    <!-- 标签管理窗口卡片结束 -->
  </div>
</template>

<script>
import { UniCore } from 'unicore-sdk'
import { config } from 'unicore-sdk/unicore.config'
import 'unicore-sdk/Widgets/widgets.css'
import lmSet from '@/components/labelManageSet/index'; //标签管理组件


export default {

  components: {
    lmSet
  },
  // 生命周期 - 挂载完成(可以访问DOM元素)
  mounted () {
    this.init();

    // 可以不断调用 initLabel 方法实现实时轮询最新数据,如
    setInterval(() => {
      this.$refs.lmSetId.initLabel();
    }, 1000)
  },

  // 方法集合
  methods: {

    /**
    * 通用图形引擎初始化
    */
    init () {

      // 初始化UniCore

      // 目前采用Cesium的地形&底图数据,这里配置Cesium的token
      let accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxNjEwMzI4My01MjBmLTQzYzktOGZiMS0wMDRhZjE0N2IyMGIiLCJpZCI6MTc1NzkyLCJpYXQiOjE3MTM3NzQ3OTh9.zU-R4MNvHr8rvn1v28PQfDImyutnpPF2lmEgGeSPckQ";
      // 初始化unicore
      let uniCore = new UniCore(config, accessToken);
      uniCore.init("unicoreContainer");
      window.uniCore = uniCore;
      let viewer = uniCore.viewer;

      // 视角初始化
      uniCore.position.buildingPosition(viewer, [113.12380548015745, 28.250758831850005, 700], -20, -45, 1);

    }
  }

}
</script>
<style scoped>
#unicoreContainer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: black;
}
</style>

调用代码示例中的关键代码

js
setInterval(() => {
  this.$refs.lmSetId.initLabel();
}, 1000)