feat: update simulation mode rate and camera views

This commit is contained in:
Cui Hongwei
2026-07-13 16:56:58 +08:00
parent 74f640a05f
commit fe9f445073

View File

@@ -37,6 +37,30 @@
</div>
</div>
</div>
<div v-if="simulationRateDialogVisible" class="simulation-rate-mask" @click.self="cancelSimulationRateDialog">
<div class="simulation-rate-dialog">
<div class="simulation-rate-dialog__head">
<strong>选择仿真播放倍率</strong>
<span>默认 5 </span>
</div>
<div class="simulation-rate-options">
<button
v-for="rate in autoPlayRates"
:key="rate"
type="button"
class="simulation-rate-option"
:class="{ 'simulation-rate-option--active': pendingAutoPlayRate === rate }"
@click="selectSimulationRate(rate)"
>
{{ rate }}x
</button>
</div>
<div class="simulation-rate-dialog__actions">
<button type="button" class="simulation-rate-action simulation-rate-action--ghost" @click="cancelSimulationRateDialog">取消</button>
<button type="button" class="simulation-rate-action simulation-rate-action--primary" @click="confirmSimulationRate">开始仿真</button>
</div>
</div>
</div>
<div class="leftLine"></div>
<div class="rightLine"></div>
@@ -275,7 +299,12 @@ export default {
currentMode: 'DT',
srcDt: 'http://localhost:10056/',
srcSm: 'http://localhost:10059/',
smIframeBase: 'http://localhost:10059/',
autoPlayCraftCode: '',
autoPlayRates: [0.5, 1, 2, 4, 5, 10],
selectedAutoPlayRate: 5,
pendingAutoPlayRate: 5,
simulationRateDialogVisible: false,
modeSwitchTimer: null,
cameraSyncTimer: null,
iframeReadyTimer: null,
@@ -283,38 +312,38 @@ export default {
clockTimer: null,
resizeHandler: null,
alarmPieChart: null,
activeView: 'longRail',
activeView: 'overview',
viewButtons: [
{ label: '全揽视角', value: 'overview' },
{ label: '加工中心单元视角', value: 'longRail' },
{ label: '车床加工单元视角', value: 'shortRail' },
{ label: '插齿机单元视角', value: 'joint' },
{ label: '磨床加工单元视角', value: 'grinder' },
{ label: '全揽视角', value: 'overview' }
{ label: '磨床加工单元视角', value: 'grinder' }
],
cameraViews: {
longRail: {
target: { x: -5.725619423653396, y: 1.559219531820475, z: -5.23360272959924 },
position: { x: -18.7530206850084, y: 1.6376732214652037, z: 15.344064598520557 },
target: { x: -7.242748313927699, y: 1.365235845234568, z: -6.193333867630938 },
position: { x: -20.270149575282687, y: 1.4436895348793037, z: 14.38433346048873 },
zoom0: 1
},
shortRail: {
target: { x: -5.814177085428968, y: 16.255194514605996, z: -5.3456965650308055 },
position: { x: -17.571406723801864, y: 16.32599896951042, z: 13.22564819859711 },
target: { x: -7.001588883043185, y: 16.262345352657395, z: -6.097455776264499 },
position: { x: -18.758818521416032, y: 16.33314980756182, z: 12.473888987363225 },
zoom0: 1
},
joint: {
target: { x: 2.7622940494890424, y: 15.83905572715569, z: 0.08552052688719117 },
position: { x: -4.6476929900921515, y: 15.883680193065107, z: 11.790099601955712 },
target: { x: 1.9482734060133915, y: 15.747678960743341, z: -0.429474906955281 },
position: { x: -5.461713633567803, y: 15.792303426652754, z: 11.275104168113232 },
zoom0: 1
},
grinder: {
target: { x: -10.128808700176803, y: -15.480679803858136, z: 1.9651555238025413 },
position: { x: -21.43448244172167, y: -15.531783203240701, z: 12.347383997813267 },
target: { x: -10.691421929972085, y: -15.525894683054275, z: 1.3522782143982923 },
position: { x: -21.99709567151696, y: -15.576998082436841, z: 11.73450668840891 },
zoom0: 1
},
overview: {
target: { x: -2.4540886878602937, y: -1.7690793306726371, z: -0.104103172990748 },
position: { x: -44.67609815729721, y: -1.5148097061598855, z: 38.669527626788486 },
target: { x: -4.793874852627955, y: 6.052339186049304, z: -6.403726952169199 },
position: { x: -26.23140973687205, y: 33.78061698752333, z: 24.44556028867285 },
zoom0: 1
}
},
@@ -570,8 +599,11 @@ export default {
const config = window.dt_Config || {}
this.iframeAddress = config.iframeAddress ? config.iframeAddress : ''
this.autoPlayCraftCode = config.autoPlayCraftCode || 'E8077755-9B85-46A1-9B8A-85083C00DF26'
this.smIframeBase = config.smIframe || this.srcSm
this.selectedAutoPlayRate = this.normalizeAutoPlayRate(config.autoPlayRate || this.getAutoPlayRateFromUrl(this.smIframeBase) || 5)
this.pendingAutoPlayRate = this.selectedAutoPlayRate
this.srcDt = this.buildIframeUrl(config.dtIframe || this.srcDt, this.autoPlayCraftCode)
this.srcSm = this.buildIframeUrl(config.smIframe || this.srcSm, this.autoPlayCraftCode)
this.srcSm = this.buildIframeUrl(this.smIframeBase, this.autoPlayCraftCode, this.selectedAutoPlayRate)
this.titleText = config.titleText
this.updateTime()
this.setScale()
@@ -637,17 +669,44 @@ export default {
this.syncActiveCamera()
}
},
buildIframeUrl(baseUrl, craftCode) {
buildIframeUrl(baseUrl, craftCode, autoPlayRate) {
if (!baseUrl) {
return ''
}
let nextUrl = baseUrl
if (nextUrl.includes('dmtmode=SM')) {
nextUrl = this.withAutoPlayRateParam(nextUrl, this.normalizeAutoPlayRate(autoPlayRate))
}
if (craftCode && nextUrl.includes('autoPlayCraftCode=') && !nextUrl.includes(craftCode)) {
const separator = nextUrl.endsWith('=') || nextUrl.endsWith('/') ? '' : '/'
nextUrl = `${nextUrl}${separator}${craftCode}`
}
return this.withTransparentParam(nextUrl)
},
getAutoPlayRateFromUrl(url) {
const match = String(url || '').match(/[?&]autoPlayRate=([^&#]*)/)
return match ? decodeURIComponent(match[1]) : ''
},
normalizeAutoPlayRate(rate) {
const numericRate = Number(rate)
return this.autoPlayRates.includes(numericRate) ? numericRate : 5
},
withAutoPlayRateParam(url, rate) {
const value = encodeURIComponent(String(rate))
if (url.includes('autoPlayRate=')) {
return url.replace(/([?&]autoPlayRate=)[^&#]*/, `$1${value}`)
}
if (url.includes('autoPlayCraftCode=')) {
return url.replace(/([?&])autoPlayCraftCode=/, `$1autoPlayRate=${value}&autoPlayCraftCode=`)
}
const hashIndex = url.indexOf('#')
if (hashIndex > -1) {
const separator = url.slice(hashIndex).includes('?') ? '&' : '?'
return `${url}${separator}autoPlayRate=${value}`
}
const separator = url.includes('?') ? '&' : '?'
return `${url}${separator}autoPlayRate=${value}`
},
withTransparentParam(url) {
if (!url || url.includes('transparent=true')) {
return url
@@ -725,6 +784,22 @@ export default {
this.switchMode('DT')
},
changeSmMode() {
this.openSimulationRateDialog()
},
openSimulationRateDialog() {
this.pendingAutoPlayRate = this.selectedAutoPlayRate
this.simulationRateDialogVisible = true
},
selectSimulationRate(rate) {
this.pendingAutoPlayRate = this.normalizeAutoPlayRate(rate)
},
cancelSimulationRateDialog() {
this.simulationRateDialogVisible = false
},
confirmSimulationRate() {
this.selectedAutoPlayRate = this.normalizeAutoPlayRate(this.pendingAutoPlayRate)
this.srcSm = this.buildIframeUrl(this.smIframeBase, this.autoPlayCraftCode, this.selectedAutoPlayRate)
this.simulationRateDialogVisible = false
this.switchMode('SM')
},
initAlarmPieChart() {
@@ -1034,6 +1109,114 @@ body,
outline: none;
}
.simulation-rate-mask {
position: absolute;
inset: 0;
z-index: 80;
display: flex;
align-items: center;
justify-content: center;
background: rgba(1, 9, 20, 0.58);
pointer-events: auto;
}
.simulation-rate-dialog {
width: 430px;
padding: 20px 22px 18px;
border: 1px solid rgba(114, 232, 255, 0.48);
background:
linear-gradient(180deg, rgba(19, 55, 82, 0.96), rgba(4, 16, 31, 0.96)),
rgba(5, 20, 44, 0.96);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.12),
inset 0 0 24px rgba(44, 143, 255, 0.18),
0 18px 42px rgba(0, 0, 0, 0.48),
0 0 28px rgba(114, 232, 255, 0.18);
}
.simulation-rate-dialog__head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
margin-bottom: 18px;
}
.simulation-rate-dialog__head strong {
color: #ffffff;
font-size: 20px;
letter-spacing: 0;
text-shadow: 0 0 12px rgba(114, 232, 255, 0.3);
}
.simulation-rate-dialog__head span {
color: #91dfff;
font-size: 13px;
}
.simulation-rate-options {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
}
.simulation-rate-option,
.simulation-rate-action {
height: 36px;
border: 1px solid rgba(111, 224, 255, 0.34);
color: #d8f6ff;
background:
linear-gradient(180deg, rgba(24, 52, 82, 0.82), rgba(5, 17, 30, 0.9)),
rgba(6, 25, 53, 0.72);
font-family: inherit;
font-size: 14px;
font-weight: 700;
cursor: pointer;
}
.simulation-rate-option--active {
color: #ffffff;
border-color: rgba(128, 255, 230, 0.95);
background:
linear-gradient(180deg, rgba(36, 216, 139, 0.42), rgba(14, 92, 61, 0.7)),
rgba(14, 92, 61, 0.52);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.18),
0 0 18px rgba(36, 216, 139, 0.24);
}
.simulation-rate-dialog__actions {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 18px;
}
.simulation-rate-action {
min-width: 96px;
padding: 0 18px;
}
.simulation-rate-action--ghost {
color: #b9d8ec;
border-color: rgba(160, 180, 194, 0.24);
background: rgba(36, 48, 60, 0.48);
}
.simulation-rate-action--primary {
color: #ffffff;
border-color: rgba(114, 232, 255, 0.72);
background:
linear-gradient(90deg, rgba(12, 62, 78, 0.96), rgba(26, 122, 132, 0.88), rgba(12, 62, 78, 0.96)),
rgba(4, 20, 35, 0.86);
box-shadow: 0 0 18px rgba(75, 245, 209, 0.24);
}
.simulation-rate-option:focus,
.simulation-rate-action:focus {
outline: none;
}
.brand-logo {
display: block;
width: 300px;