开发基于客户端渲染的BIM设置

dev_xd
lj7788@126.com 2025-08-15 16:02:05 +08:00
parent 5c2e43e8ec
commit 130f9b53dd
7 changed files with 254 additions and 63 deletions

View File

@ -11,7 +11,7 @@
<script>
window.yanzhuAppTitle = "数字建安施工";
</script>
<link rel="icon" href="/cdn/bsimages/faviconnew.ico?v=4" />
<link rel="icon" href="/cdn/bsimages/faviconnewfaviconnew.ico?v=4" />
<title>数字建安施工</title>
<script
type="text/javascript"

View File

@ -6,6 +6,12 @@
<el-form-item label="漫游名称" prop="name">
<el-input v-model="form.name" style="width: 100%" />
</el-form-item>
<el-form-item label="移动速度" prop="moveRate" v-if="isClient && false">
<el-radio-group v-model="form.moveRate" size="small">
<el-radio-button v-for="(it, idx) in speed" :label="it.label" :value="it.value"
:key="idx" />
</el-radio-group>
</el-form-item>
<el-form-item label="漫游时长" prop="time">
<el-input-number v-model="form.time" :step="1" :min="1" style="width: 100%" />
<template #append></template>
@ -16,7 +22,7 @@
<div>
<el-table :data="form.viewPortPoints" border style="width: 100%">
<el-table-column prop="name" label="视点">
<template #default="scope">{{'视点' + (++scope.$index) }}</template>
<template #default="scope">{{ '视点' + (++scope.$index) }}</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
@ -34,11 +40,14 @@
<el-tab-pane label="漫游历史" name="tab2">
<el-table :data="roamList" style="width: 100%">
<el-table-column prop="name" label="名称" />
<el-table-column label="操作" width="200px">
<el-table-column label="操作" width="220px" class-name="opt-td">
<template #default="scope">
<el-button v-if="scope.row.play === 0" type="primary" link @click="playIR(scope.row)"></el-button>
<el-button v-else-if="scope.row.play === 1" type="primary" auto-insert-spacelink @click="playIRPause(scope.row)"></el-button>
<el-button v-else-if="scope.row.play === 2" type="primary" link @click="playContinue(scope.row)"></el-button>
<el-button v-if="scope.row.play === 0" type="primary" link
@click="playIR(scope.row)">播放</el-button>
<el-button v-else-if="scope.row.play === 1" type="primary" auto-insert-spacelink
@click="playIRPause(scope.row)">暂停</el-button>
<el-button v-else-if="scope.row.play === 2" type="primary" link
@click="playContinue(scope.row)">继续</el-button>
<el-button link @click="playCancel(scope.row)" type="primary">取消</el-button>
<el-button link @click="delCamera(scope.row, scope.$index)" type="danger">删除</el-button>
<el-button link @click="renamed(scope.row)" type="success">改名</el-button>
@ -46,15 +55,9 @@
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
v-model:current-page="pagination.current"
v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 30, 50]"
:total="pagination.total"
layout="total, prev, pager, next"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 30, 50]" :total="pagination.total" layout="total, prev, pager, next"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
</div>
</el-tab-pane>
</el-tabs>
@ -95,7 +98,8 @@ export default {
roamList: [],
playState: false,
form: {
name: '', //
moveRate: 0,//
name: '', //
time: 10, //(3°)
viewPortPoints: [],
},
@ -135,9 +139,16 @@ export default {
isMobile: false,
currentPrjId: null,
currentComId: null,
isClient: false,
speed: [{ "label": "慢", "value": 0.1 }, { "label": "中", "value": 0.2 }, { "label": "快", "value": 0.3 }, { "label": "特快", "value": 0.4 }]
}
},
mounted() {
this.isClient = this.me.bimCfg?.clientApi == true
if (this.isClient) {
this.form.moveRate = this.speed[0].value
}
this.isMobile = _isMobile() ? true : false
const userStore = useUserStore()
this.currentPrjId = userStore.currentPrjId
@ -192,14 +203,20 @@ export default {
this.pagination.total = res.data.pageInfo.totalCount
let datas = res.data.rows
if (datas.length > 0) datas.forEach((x) => (x.play = 0))
that.roamList = datas
that.roamList = datas.filter(x => x.roamingMode == (that.isClient ? "Client" : 0))
that.updated()
})
},
updated() {},
updated() { },
//
GetViewPort() {
const that = this
if (this.isClient) {
let data = api.Camera.getViewPort();
that.form.viewPortPoints.push(data)
ElMessage.info('已添加')
return;
}
api.Camera.getViewPort((data) => {
that.form.viewPortPoints.push(data)
ElMessage.info('已添加')
@ -220,12 +237,21 @@ export default {
ElMessage.warning('请输入漫游名称!')
return
}
if (that.form.time == '' || that.form.time == null) {
ElMessage.warning('请输入漫游时长!')
return
}
that.playState = true
that.isRoaming = true
if (this.isClient) {
api.Camera.startViewPortRoam(this.form.viewPortPoints, 0, this.form.time * 1000, res => {
that.playState = false
ElMessage.success('漫游完成!')
that.SaveRoam()
});
return;
}
api.Camera.startViewPortRoam(that.form.viewPortPoints, that.form.time, (res) => {
that.playState = false
ElMessage.success('漫游完成!')
@ -259,16 +285,15 @@ export default {
this.saveTime = +new Date()
const params = {
roamingType: 2,
speed: 0,
speed: this.form.moveRate,
sort: 0,
time: this.form.time,
name: this.form.name,
roamingMode: 0,
roamingMode: this.isClient ? "Client" : 0,
moveRate: 0,
turnRate: 0,
projectId: this.currentPrjId,
modelId: api.m_model.keys().toArray().join(','),
roamingMode: 0,
comId: this.currentComId,
points: JSON.stringify(this.form.viewPortPoints),
pointCount: this.form.viewPortPoints.length,
@ -297,6 +322,10 @@ export default {
this.roamList.find((x) => x.play === 1).play = 0
}
data.play = 1
if (this.isClient) {
this.playClient(data);
return;
}
api.Camera.startViewPortRoam(JSON.parse(data.points), data.time, (res) => {
this.isRoamingHistory = false
data.play = 0
@ -316,14 +345,28 @@ export default {
//
playContinue(data) {
data.play = 1
if (this.isClient) {
this.playClient(data)
return;
}
api.Camera.pauseViewPortRoam(true)
// this.$forceUpdate()
},
playClient(data) {
api.Camera.startViewPortRoam(JSON.parse(data.points), 0, data.time * 1000, (res) => {
this.isRoamingHistory = false
data.play = 0
ElMessage.info('漫游结束!')
this.resetScane()
})
},
//
playCancel(data) {
if (data.play !== 0) {
data.play = 0
this.isRoamingHistory = false
if (this.isClient) {
api.Camera.IRPlayCancle()
}
api.Camera.stopViewPortRoam()
this.resetScane()
}
@ -373,18 +416,28 @@ export default {
<style lang="scss">
.custom-viewpoint {
width: 340px;
width: 360px;
padding: 0px 10px 10px;
.el-tabs__content {
padding: 0px;
.opt-td {
.cell {
padding: 0px;
}
}
}
.pagination-container {
margin-top: 0px;
height: 32px;
display: flex;
justify-content: flex-end;
.el-pagination {
font-size: 12px;
.el-pagination__total,
.el-pagination__sizes {
margin-right: 16px;

View File

@ -240,9 +240,8 @@ export default {
api.Model.location(modelId);
if (this.$parent.viewPoint) {
if (this.me.bimCfg.clientApi) {
if (this.$parent.viewPoint["world"]) {
}
let pt=this.$parent.viewPoint;
api.Camera.SetCamera(pt.position, pt.heading, pt.pitch)
} else {
if (this.$parent.viewPoint["world"]) {
api.Camera.setViewPort(this.$parent.viewPoint);

View File

@ -23,12 +23,17 @@
<el-button type="primary" @click="updatePosition"></el-button>
</div>
<template v-if="isClient">
<div class="button-group angle-group">
<div class="nav-title">角度调整</div>
<template v-if="clientEditMode">
<el-button type="primary" @click="doSaveEditData"></el-button>
</template>
<el-button v-else type="primary" @click="updateRotate"></el-button>
</div>
</template>
<template v-else>
<div class="nav-title">旋转</div>
<el-form-item label="绕X轴">
@ -102,6 +107,12 @@ export default {
}
},
methods: {
doCancelEdit(){
if(this.isClient){
this.clientEditMode = false;
api.Edit.setEditMode("")
}
},
doSaveEditData() {
this.clientEditMode = false;
api.Edit.setEditMode("")
@ -124,6 +135,7 @@ export default {
}
},
onCancel() {
this.doCancelEdit();
this.resetPosition();
this.me.showMove = false;
this.me.activeMenu = -1;
@ -167,6 +179,7 @@ export default {
},
resetPosition() {
this.doCancelEdit();
let modelInfo = this.me.models.find(model => model.modelId == this.modelId);
if (modelInfo) {
let cfg = modelInfo.bimCfg;
@ -235,6 +248,9 @@ export default {
.button-group {
margin-bottom: 10px;
text-align: right;
&.angle-group{
text-align: left;
}
}
.footer-btn {

View File

@ -6,6 +6,30 @@
<el-form-item label="漫游名称" prop="name">
<el-input v-model="form.name" style="width: 100%"></el-input>
</el-form-item>
<template v-if="isClient">
<el-form-item label="移动速度" prop="moveRate">
<el-radio-group v-model="form.moveRate" size="small">
<el-radio-button v-for="(it, idx) in speed" :label="it.label" :value="it.value"
:key="idx" />
</el-radio-group>
</el-form-item>
<el-form-item label="旋转速度" prop="turnRate">
<el-radio-group v-model="form.turnRate" size="small">
<el-radio-button v-for="(it, idx) in rotate" :label="it.label" :value="it.value"
:key="idx" />
</el-radio-group>
</el-form-item>
<el-form-item label="穿过障碍物" prop="canCrossWall">
<el-switch v-model="form.canCrossWall" :active-value="true" :inactive-value="false"
active-text="是" inactive-text="否" />
</el-form-item>
<el-form-item label="重力感应" prop="lookFactor">
<el-switch v-model="form.canGravity" :active-value="true" :inactive-value="false"
active-text="是" inactive-text="否" />
</el-form-item>
</template>
<template v-else>
<el-form-item label="漫游类型" prop="roamType">
<el-select v-model="form.roamType" placeholder="请选择">
<el-option label="第一人称漫游" value="First"></el-option>
@ -14,13 +38,14 @@
</el-select>
</el-form-item>
<el-form-item label="移动速度" prop="moveRate">
<el-input-number v-model="form.moveRate" :precision="2" :step="0.01" :min="0" placeholder="0.00"
style="width: 100%"></el-input-number>
<el-input-number v-model="form.moveRate" :precision="2" :step="0.01" :min="0"
placeholder="0.00" style="width: 100%"></el-input-number>
</el-form-item>
<el-form-item label="旋转速度" prop="lookFactor">
<el-input-number v-model="form.turnRate" :precision="2" :step="0.01" :min="0" placeholder="0.00"
style="width: 100%"></el-input-number>
<el-form-item label="旋转速度" prop="turnRate">
<el-input-number v-model="form.turnRate" :precision="2" :step="0.01" :min="0"
placeholder="0.00" style="width: 100%"></el-input-number>
</el-form-item>
</template>
<el-form-item>
<el-button @click="startImmersionRoaming" ghost>开始漫游</el-button>
<el-button @click="endImmersionRoaming(99)" ghost>结束漫游</el-button>
@ -196,6 +221,8 @@ export default {
moveRate: 0.5,
turnRate: 1,
roamType: 'Third',
canCrossWall: false,
canGravity: true,
},
rulesRenamed: {
name: [
@ -232,11 +259,30 @@ export default {
pageSize: 10,
total: 0,
},
rotate: [{ "label": "慢", "value": 1 }, { "label": "中", "value": 2 }, { "label": "快", "value": 3 }, { "label": "特快", "value": 4 }],
speed: [{ "label": "慢", "value": 0.1 }, { "label": "中", "value": 0.2 }, { "label": "快", "value": 0.3 }, { "label": "特快", "value": 0.4 }]
}
},
mounted() {
window.xapp = this
this.isClient = this.me.bimCfg?.clientApi == true
if (this.isClient) {
this.data = [{
option: "↑ ← → ↓",
title: "移动"
},];
this.data1 = [{
option: "鼠标按左键前进后退",
title: "视角前进后退"
}, {
option: "鼠标按左键左右移动",
title: "视角左右环视"
},];
this.form.moveRate = this.speed[0].value
this.form.turnRate = this.rotate[0].value
this.form.canGravity = true
this.form.canCrossWall = false
}
if (!this.isClient) {
api.Plugin.addMiniMap()
let options = {
@ -291,9 +337,12 @@ export default {
api.Camera.EndImmersionRoaming();
api.Camera.PickIrBirthplace(A => {
api.Camera.SetIRConfig({
roamingMode: this.form.roamType,
bRecordLocus: true,
roamName: this.form.name,
canCrossWall: this.form.canCrossWall,
canGravity: this.form.canGravity,
moveRate: this.form.moveRate,
turnRate: this.form.turnRate,
lookFactor: this.form.turnRate,
footerHeight: 1,
onIRStart: () => {
ElMessage.warning('请使用鼠标左键进行操作!')
@ -313,6 +362,9 @@ export default {
if (this.stop === 0) {
return
}
if (this.isClient) {
result = this.$tryToJson(result.records, []);
}
let data = {
vo: {
roamingType: 1,
@ -323,7 +375,7 @@ export default {
comId: this.currentComId,
name: this.form.name,
modelId: api.m_model.keys().toArray().join(','),
roamingMode: this.form.roamType,
roamingMode: this.isClient ? "Client1" : this.form.roamType,
moveRate: this.form.moveRate,
turnRate: this.form.turnRate,
points: JSON.stringify(result),
@ -333,6 +385,7 @@ export default {
roamingAdd(data).then((res) => {
if (res.code == 0) {
ElMessage.success('保存成功!')
this.form.name = "";
} else {
ElMessage.error('保存失败!')
}
@ -406,6 +459,17 @@ export default {
let record = typeof data.points === 'string' ? JSON.parse(data.points) : data.points
this.isStop = 0
if (this.isClient) {
this.isRoaming = true
api.Camera.PlayIRCamera({
records: data.points,
complete: () => {
data.play = 0
}
})
return;
}
api.Camera.setImmersiveRoamConfig({
roamingMode: data.roamingMode,
moveRate: data.moveRate,
@ -428,11 +492,19 @@ export default {
},
playIRPause(data) {
data.play = 2
if (this.isClient) {
api.Camera.PlayIRPause();
}else{
api.Camera.pauseImmersiveRoam(false)
}
},
playContinue(data) {
data.play = 1
if (this.isClient) {
api.Camera.PlayIRContinue();
} else {
api.Camera.pauseImmersiveRoam(true)
}
if (this.historys.findIndex((x) => x.play === 1) > -1) {
this.historys.find((x) => x.play === 1).play = 0
}
@ -445,7 +517,11 @@ export default {
this.historys.find((x) => x.play === 1).play = 0
}
}
if (this.isClient) {
api.Camera.IRPlayCancle()
} else {
api.Camera.cancelPlayImmersiveRoam()
}
this.isRoamingHistory = false
this.me && this.me.resetScene()
},
@ -556,5 +632,9 @@ export default {
}
}
}
.el-switch__label.is-active {
color: #fff;
}
}
</style>

View File

@ -1,6 +1,7 @@
<template>
<div class="bim-setting-viewpoint">
<el-button class="btn-create" type="primary" @click="CreateViewpoint" @keyup.prevent @keydown.enter.prevent>创建视点</el-button>
<el-button class="btn-create" type="primary" @click="CreateViewpoint" @keyup.prevent
@keydown.enter.prevent>创建视点</el-button>
<div style="margin-top: 10px">
<el-card class="viewpoint-list scroll-box" v-if="viewpointList.length > 0">
@ -14,7 +15,7 @@
</div>
<div class="viewpoint-actions">
<el-tooltip content="默认视点">
<el-icon @click="DefaultViewpoint(item, index)" :color="item.isOvert?'#409eff':'#ccc'">
<el-icon @click="DefaultViewpoint(item, index)" :color="item.isOvert ? '#409eff' : '#ccc'">
<SuccessFilled v-if="item.isOvert" />
<CircleCheck v-if="!item.isOvert" />
</el-icon>
@ -35,12 +36,17 @@
<el-empty description="暂无视点数据" v-else />
</div>
<div class="pagination-container">
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.pageSize" :page-sizes="[10, 20, 30, 50]" :total="pagination.total" layout="total, prev, pager, next" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
<el-pagination v-model:current-page="pagination.current" v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 30, 50]" :total="pagination.total" layout="total, prev, pager, next"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
</div>
<el-dialog title="保存视点" :width="400" v-model="visible" :before-close="handleCancel" class="dialog-bim-setting-viewpoint" :destroy-on-close="true" :close-on-click-modal="false" :modal="false" :class="{ 'mobile-Model': isMobile }">
<el-dialog title="保存视点" :width="400" v-model="visible" :before-close="handleCancel"
class="dialog-bim-setting-viewpoint" :destroy-on-close="true" :close-on-click-modal="false" :modal="false"
:class="{ 'mobile-Model': isMobile }">
<el-form :model="form" :rules="formRules" ref="form" label-width="80px">
<el-form-item label="视点名称" prop="title">
<el-input v-model="form.title" placeholder="请输入视点名称" :rules="[{ required: true, message: '请输入视点名称' }]" @keydown.stop @keyup.stop @keypress.stop/>
<el-input v-model="form.title" placeholder="请输入视点名称" :rules="[{ required: true, message: '请输入视点名称' }]"
@keydown.stop @keyup.stop @keypress.stop />
</el-form-item>
<el-form-item label="缩略图">
<el-image style="width: 100%" :src="previewImage" :preview-src-list="[previewImage]" />
@ -51,11 +57,12 @@
</el-form>
<template #footer>
<el-button @click="handleCancel"></el-button>
<el-button type="primary" @click="SaveViewpoint"></el-button>
<el-button type="primary" :loading="loading" @click="SaveViewpoint"></el-button>
</template>
</el-dialog>
<el-dialog title="视点重命名" class="body-noscroll" v-model="visibleRenamed" width="400px" :before-close="() => (visibleRenamed = false)">
<el-dialog title="视点重命名" class="body-noscroll" v-model="visibleRenamed" width="400px"
:before-close="() => (visibleRenamed = false)">
<el-form ref="formRenamedRef" :rules="rulesRenamed" :model="formRenamed" label-width="80px">
<el-form-item label="漫游名称" prop="name">
<el-input v-model="formRenamed.name" maxlength="20" placeholder="请输入名称"></el-input>
@ -67,7 +74,7 @@
<template #footer>
<span class="dialog-footer">
<el-button @click="visibleRenamed = false">取消</el-button>
<el-button type="primary" @click="handSaveRenamed"></el-button>
<el-button type="primary" :loading="loading" @click="handSaveRenamed"></el-button>
</span>
</template>
</el-dialog>
@ -77,7 +84,7 @@
<script>
import { _isMobile } from "@/utils/public";
import { Delete, Picture, Edit } from "@element-plus/icons-vue";
import { viewpointGet, viewpointAdd, viewpointUpdateByName, viewpointDeleteById, updateDefaultViewPoint ,clearDefaultViewPoint} from "@/api/bim/bim.js";
import { viewpointGet, viewpointAdd, viewpointUpdateByName, viewpointDeleteById, updateDefaultViewPoint, clearDefaultViewPoint } from "@/api/bim/bim.js";
import { ElMessage, ElMessageBox } from "element-plus";
import useUserStore from "@/store/modules/user";
export default {
@ -90,6 +97,8 @@ export default {
},
data() {
return {
loading:false,
isClient: false,
viewpointList: [],
visible: false,
confirmLoading: false,
@ -133,6 +142,7 @@ export default {
},
mounted() {
this.isMobile = _isMobile() ? true : false;
this.isClient = this.me.bimCfg?.clientApi == true
const userStore = useUserStore();
this.currentPrjId = userStore.currentPrjId;
this.currentComId = userStore.currentComId;
@ -165,6 +175,16 @@ export default {
},
CreateViewpoint() {
const that = this;
if (this.isClient) {
let el = document.querySelector("#bimSettingContainer canvas");
if (el) {
let res = el.toDataURL()
that.imgBlobName = res;
that.previewImage = res;
that.visible = true;
}
return;
}
api.Public.saveScreenShot((res) => {
that.imgBlobName = res;
that.previewImage = res;
@ -189,7 +209,12 @@ export default {
ZoomViewpoint(item) {
const that = this;
if (item.viewPosition != null) {
api.Camera.setViewPort(JSON.parse(item.viewPosition));
let pt=JSON.parse(item.viewPosition)
if(this.isClient){
api.Camera.SetCamera(pt.position, pt.heading, pt.pitch)
}else{
api.Camera.setViewPort(pt);
}
}
},
editViewPoint(item, index) {
@ -264,8 +289,19 @@ export default {
});
});
},
getViewPort(cb){
if(this.isClient){
let point=api.Camera.GetCamera();
cb(point)
}else{
api.Camera.getViewPort((p)=>{
cb(p)
});
}
},
SaveViewpoint() {
const that = this;
this.loading=true;
that.$refs.form.validate((valid) => {
if (!valid) {
return false;
@ -276,7 +312,7 @@ export default {
ElMessage.info("上传图片失败!");
return false;
}
api.Camera.getViewPort((p) => {
this.getViewPort((p) => {
let obj = {
name: this.form.title,
remark: that.form.remark,
@ -293,6 +329,7 @@ export default {
parentId: 0,
};
viewpointAdd({ vo: obj }).then((result) => {
this.loading=false;
if (result.code == 0) {
ElMessage.success("已保存!");
that.form = {
@ -326,15 +363,18 @@ export default {
.bim-setting-viewpoint {
width: 340px;
padding: 0px 10px 10px;
.btn-create {
position: absolute;
top: 10px;
right: 40px;
}
.pagination-container {
margin-top: 10px;
margin-bottom: 20px;
}
.viewpoint-list {
margin-bottom: 10px;
max-height: 500px;
@ -367,6 +407,7 @@ export default {
.viewpoint-actions {
display: flex;
align-content: center;
.el-icon {
margin-left: 10px;
cursor: pointer;
@ -380,6 +421,7 @@ export default {
}
}
}
.dialog-bim-setting-viewpoint {
.el-dialog__body {
overflow: hidden !important;

View File

@ -187,6 +187,7 @@ export default {
if (this.$refs.personRoaming) {
this.$refs.personRoaming.isRoaming = false;
}
api.Camera.stopImmersiveRoam();
api.Model.location(api.m_model.keys().toArray()[0]);
if (!this.bimCfg.clientApi) {