From c493779a8504fe1eb548c865ff268a7f7436ec01 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期四, 19 三月 2026 11:43:36 +0800
Subject: [PATCH] feat: 集成机械手客户端并重构模拟器前端工作台
---
Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/DetailsView.vue | 251 ++++++++++++++++++++++++++++---------------------
1 files changed, 142 insertions(+), 109 deletions(-)
diff --git a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/DetailsView.vue b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/DetailsView.vue
index c336b5a..83ea82c 100644
--- a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/DetailsView.vue
+++ b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/DetailsView.vue
@@ -1,5 +1,6 @@
锘�<template>
<div
+ class="admin-page"
v-loading.fullscreen.lock="startActionLoading"
element-loading-text="姝e湪鍚姩瀹炰緥锛岃绋嶅��..."
>
@@ -31,44 +32,64 @@
</el-button>
</div>
- <el-row :gutter="20" class="status-cards">
- <el-col :xs="12" :sm="6">
- <el-card shadow="hover" class="status-card">
- <el-statistic title="鐘舵��">
- <template #default>
- <el-tag :type="getStatusTagType(instance.status)" size="large">
- {{ getStatusText(instance.status) }}
- </el-tag>
- </template>
- </el-statistic>
- </el-card>
- </el-col>
- <el-col :xs="12" :sm="6">
- <el-card shadow="hover" class="status-card">
- <el-statistic title="杩炴帴瀹㈡埛绔�" :value="instance.clientCount">
- <template #suffix>
- <el-icon><User /></el-icon>
- </template>
- </el-statistic>
- </el-card>
- </el-col>
- <el-col :xs="12" :sm="6">
- <el-card shadow="hover" class="status-card">
- <el-statistic title="鎬昏姹傛暟" :value="instance.totalRequests" />
- </el-card>
- </el-col>
- <el-col :xs="12" :sm="6">
- <el-card shadow="hover" class="status-card">
- <el-statistic title="绔彛" :value="instance.port" />
- </el-card>
- </el-col>
- </el-row>
+ <section class="section-block">
+ <div class="section-head">
+ <div>
+ <h3 class="section-title">淇℃伅鍖�</h3>
+ <p class="section-desc">瀹炰緥杩愯鐘舵�佷笌杩炴帴姒傝</p>
+ </div>
+ </div>
+ <div class="section-body">
+ <el-row :gutter="12" class="status-cards">
+ <el-col :xs="12" :sm="6">
+ <el-card shadow="hover" class="status-card panel-card">
+ <el-statistic title="鐘舵��">
+ <template #default>
+ <el-tag :type="getStatusTagType(instance.status)" size="large">
+ {{ getStatusText(instance.status) }}
+ </el-tag>
+ </template>
+ </el-statistic>
+ </el-card>
+ </el-col>
+ <el-col :xs="12" :sm="6">
+ <el-card shadow="hover" class="status-card panel-card">
+ <el-statistic title="杩炴帴瀹㈡埛绔�" :value="instance.clientCount">
+ <template #suffix>
+ <el-icon><User /></el-icon>
+ </template>
+ </el-statistic>
+ </el-card>
+ </el-col>
+ <el-col :xs="12" :sm="6">
+ <el-card shadow="hover" class="status-card panel-card">
+ <el-statistic title="鎬昏姹傛暟" :value="instance.totalRequests" />
+ </el-card>
+ </el-col>
+ <el-col :xs="12" :sm="6">
+ <el-card shadow="hover" class="status-card panel-card">
+ <el-statistic title="绔彛" :value="instance.port" />
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+ </section>
- <el-card class="mt-4" shadow="never">
+ <section class="section-block detail-section">
+ <div class="section-head">
+ <div>
+ <h3 class="section-title">鎿嶄綔鍖�</h3>
+ <p class="section-desc">宸︿晶瀹炰緥淇℃伅涓庢搷浣滐紝鍙充晶瀹炴椂 DB 鏁版嵁</p>
+ </div>
+ </div>
+ <div class="section-body">
+ <el-row :gutter="16" class="detail-main">
+ <el-col :xs="24" :lg="8">
+ <el-card class="panel-card" shadow="never">
<template #header>
<span class="card-header-title">鍩烘湰淇℃伅</span>
</template>
- <el-descriptions :column="2" border>
+ <el-descriptions :column="1" border>
<el-descriptions-item label="瀹炰緥ID">{{ instance.instanceId }}</el-descriptions-item>
<el-descriptions-item label="瀹炰緥鍚嶇О">{{ instance.name }}</el-descriptions-item>
<el-descriptions-item label="PLC鍨嬪彿">{{ getPlcTypeText(instance.plcType) }}</el-descriptions-item>
@@ -79,17 +100,18 @@
<el-descriptions-item v-if="instance.lastActivityTime" label="鏈�鍚庢椿鍔ㄦ椂闂�">
{{ formatDate(instance.lastActivityTime) }}
</el-descriptions-item>
- <el-descriptions-item v-if="instance.errorMessage" label="閿欒淇℃伅" :span="2">
+ <el-descriptions-item v-if="instance.errorMessage" label="閿欒淇℃伅">
<el-text type="danger">{{ instance.errorMessage }}</el-text>
</el-descriptions-item>
</el-descriptions>
</el-card>
- <el-card class="mt-4" shadow="never">
+ <el-card class="panel-card left-actions" shadow="never">
<div class="action-buttons">
<el-button
v-if="instance.status === 'Stopped' || instance.status === 'Error'"
type="success"
+
@click="handleStart"
>
<el-icon><VideoPlay /></el-icon>
@@ -98,6 +120,7 @@
<el-button
v-if="instance.status === 'Running'"
type="warning"
+
@click="handleStop"
>
<el-icon><VideoPause /></el-icon>
@@ -114,13 +137,15 @@
</div>
</el-card>
- <el-card class="mt-4" shadow="never">
+ </el-col>
+ <el-col :xs="24" :lg="16">
+ <el-card class="panel-card" shadow="never">
<template #header>
<div class="db-header">
<span class="card-header-title">DB鍧楀疄鏃舵暟鎹�</span>
<div class="db-toolbar">
<el-switch v-model="autoRefreshDb" active-text="鑷姩鍒锋柊" />
- <el-button size="small" @click="loadMemoryData(true)">鎵嬪姩鍒锋柊</el-button>
+ <el-button @click="loadMemoryData(true)">鎵嬪姩鍒锋柊</el-button>
</div>
</div>
</template>
@@ -131,7 +156,7 @@
<template #default>
<div v-if="deviceDbViews.length === 0" class="text-muted">褰撳墠璁惧妯℃澘鏈尮閰嶅埌鍙樉绀虹殑DB鍧�</div>
<div v-else>
- <el-tabs type="border-card" class="db-tabs">
+ <el-tabs type="border-card" class="db-tabs">
<el-tab-pane
v-for="view in deviceDbViews"
:key="view.templateDbNumber"
@@ -149,25 +174,27 @@
:key="`${view.templateDbNumber}-${group.key}`"
>
<template #label>
- <el-tag :type="getFieldGroupTagType(group.key)" size="small">{{ group.key }}</el-tag>
+ <el-tag :type="getFieldGroupTagType(group.key)">{{ group.key }}</el-tag>
</template>
+ <div class="field-table-wrap">
<el-table
:data="group.fields"
border
- size="small"
+ class="field-table"
+ table-layout="auto"
empty-text="褰撳墠鍒嗙粍鏃犲瓧娈垫槧灏�"
>
- <el-table-column prop="fieldKey" label="瀛楁" min-width="140" />
- <el-table-column prop="address" label="鍦板潃" width="130" />
- <el-table-column prop="mappedDb" label="鏄犲皠鍧�" width="120">
+ <el-table-column prop="fieldKey" label="瀛楁" />
+ <el-table-column prop="address" label="鍦板潃" />
+ <el-table-column prop="mappedDb" label="鏄犲皠鍧�">
<template #default="{ row }">
- <el-tag :type="getDbTagType(row.mappedDb)" size="small">{{ row.mappedDb }}</el-tag>
+ <el-tag :type="getDbTagType(row.mappedDb)">{{ row.mappedDb }}</el-tag>
</template>
</el-table-column>
- <el-table-column prop="dataType" label="绫诲瀷" width="90" />
- <el-table-column prop="direction" label="鏂瑰悜" width="130" />
- <el-table-column prop="value" label="褰撳墠鍊�" min-width="220" />
- <el-table-column label="淇敼鍊�" min-width="220">
+ <el-table-column prop="dataType" label="绫诲瀷" />
+ <el-table-column prop="direction" label="鏂瑰悜" />
+ <el-table-column prop="value" label="褰撳墠鍊�" />
+ <el-table-column label="淇敼鍊�">
<template #default="{ row }">
<el-switch
v-if="row.dataType === 'Bool'"
@@ -181,17 +208,18 @@
@change="markFieldDirty(row)"
:disabled="!isFieldWritable(row)"
:controls="false"
- style="width: 100%"
+ class="editable-control"
/>
<el-input
v-else
v-model="fieldEditValues[getFieldEditKey(row)]"
@input="markFieldDirty(row)"
:disabled="!isFieldWritable(row)"
+ class="editable-control"
/>
</template>
</el-table-column>
- <el-table-column label="鎿嶄綔" width="90" fixed="right">
+ <el-table-column label="鎿嶄綔" width="88" fixed="right">
<template #default="{ row }">
<el-button
type="primary"
@@ -205,26 +233,29 @@
</template>
</el-table-column>
</el-table>
+ </div>
</el-tab-pane>
</el-tabs>
+ <template v-else-if="view.fields.length > 0">
+ <div class="field-table-wrap">
<el-table
- v-else-if="view.fields.length > 0"
:data="view.fields"
border
- size="small"
+ class="field-table"
+ table-layout="auto"
empty-text="褰撳墠DB鍧楁棤瀛楁鏄犲皠"
>
- <el-table-column prop="fieldKey" label="瀛楁" min-width="140" />
- <el-table-column prop="address" label="鍦板潃" width="130" />
- <el-table-column prop="mappedDb" label="鏄犲皠鍧�" width="120">
+ <el-table-column prop="fieldKey" label="瀛楁" />
+ <el-table-column prop="address" label="鍦板潃" />
+ <el-table-column prop="mappedDb" label="鏄犲皠鍧�">
<template #default="{ row }">
- <el-tag :type="getDbTagType(row.mappedDb)" size="small">{{ row.mappedDb }}</el-tag>
+ <el-tag :type="getDbTagType(row.mappedDb)">{{ row.mappedDb }}</el-tag>
</template>
</el-table-column>
- <el-table-column prop="dataType" label="绫诲瀷" width="90" />
- <el-table-column prop="direction" label="鏂瑰悜" width="130" />
- <el-table-column prop="value" label="褰撳墠鍊�" min-width="220" />
- <el-table-column label="淇敼鍊�" min-width="220">
+ <el-table-column prop="dataType" label="绫诲瀷" />
+ <el-table-column prop="direction" label="鏂瑰悜" />
+ <el-table-column prop="value" label="褰撳墠鍊�" />
+ <el-table-column label="淇敼鍊�">
<template #default="{ row }">
<el-switch
v-if="row.dataType === 'Bool'"
@@ -238,17 +269,18 @@
@change="markFieldDirty(row)"
:disabled="!isFieldWritable(row)"
:controls="false"
- style="width: 100%"
+ class="editable-control"
/>
<el-input
v-else
v-model="fieldEditValues[getFieldEditKey(row)]"
@input="markFieldDirty(row)"
:disabled="!isFieldWritable(row)"
+ class="editable-control"
/>
</template>
</el-table-column>
- <el-table-column label="鎿嶄綔" width="90" fixed="right">
+ <el-table-column label="鎿嶄綔" width="88" fixed="right">
<template #default="{ row }">
<el-button
type="primary"
@@ -262,6 +294,8 @@
</template>
</el-table-column>
</el-table>
+ </div>
+ </template>
<div v-else class="text-muted">褰撳墠DB鍧楁棤瀛楁鏄犲皠</div>
<div class="card-header-title field-title">鍘熷鏁版嵁</div>
@@ -300,6 +334,10 @@
/>
</div>
</el-card>
+ </el-col>
+ </el-row>
+ </div>
+ </section>
</div>
</div>
</template>
@@ -1065,48 +1103,8 @@
</script>
<style scoped>
-.page-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 20px;
- flex-wrap: wrap;
- gap: 16px;
-}
-
-.header-left h2 {
- display: flex;
- align-items: center;
- gap: 8px;
- margin: 0 0 8px 0;
-}
-
-.text-muted {
- color: #909399;
- margin: 0;
-}
-
-.loading-container {
- text-align: center;
- padding: 60px 0;
- color: #909399;
-}
-
-.loading-icon {
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
.status-cards {
- margin-bottom: 20px;
+ margin-bottom: 8px;
}
.status-card {
@@ -1119,13 +1117,17 @@
}
.mt-4 {
- margin-top: 16px;
+ margin-top: 14px;
}
.action-buttons {
display: flex;
- gap: 12px;
+ gap: 10px;
flex-wrap: wrap;
+}
+
+.left-actions {
+ margin-top: 14px;
}
.db-header {
@@ -1142,7 +1144,7 @@
.db-content {
margin: 0;
- max-height: 180px;
+ max-height: 168px;
overflow: auto;
white-space: pre-wrap;
font-family: Consolas, Monaco, 'Courier New', monospace;
@@ -1168,11 +1170,11 @@
}
.db-tabs {
- margin-top: 8px;
+ margin-top: 10px;
}
.data-view-tabs {
- margin-top: 8px;
+ margin-top: 10px;
}
.db-raw-toolbar {
@@ -1189,4 +1191,35 @@
margin-top: 12px;
margin-bottom: 8px;
}
+
+.field-table-wrap {
+ width: 100%;
+ overflow-x: auto;
+}
+
+:deep(.field-table) {
+ width: max-content;
+ min-width: 100%;
+}
+
+:deep(.editable-control) {
+ width: 100%;
+}
+
+:deep(.status-card .el-card__body) {
+ padding: 14px 16px;
+}
+
+:deep(.action-buttons .el-button) {
+ min-width: 82px;
+}
+
+:deep(.panel-card > .el-card__header) {
+ padding: 14px 18px;
+}
+
+:deep(.panel-card > .el-card__body) {
+ padding: 14px 18px;
+}
</style>
+
--
Gitblit v1.9.3