From 689dd676fc0efb31236d989334122590b7198d61 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期一, 16 三月 2026 09:30:11 +0800
Subject: [PATCH] 1

---
 Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue |  346 ++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 217 insertions(+), 129 deletions(-)

diff --git a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue
index 9a6cbf9..7c9c152 100644
--- a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue
+++ b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web/src/views/HomeView.vue
@@ -1,113 +1,108 @@
 <template>
   <div>
-    <div class="d-flex justify-content-between align-items-center mb-4">
-      <div>
-        <h2 class="mb-0">
-          <i class="bi bi-cpu-fill me-2"></i>S7 PLC 浠跨湡鍣ㄥ疄渚�
+    <div class="page-header">
+      <div class="header-left">
+        <h2>
+          <el-icon :size="24"><Cpu /></el-icon>
+          S7 PLC 浠跨湡鍣ㄥ疄渚�
         </h2>
-        <p class="text-muted mb-0 mt-1">绠$悊鍜岀洃鎺� S7 PLC 浠跨湡鍣ㄥ疄渚�</p>
+        <p class="text-muted">绠$悊鍜岀洃鎺� S7 PLC 浠跨湡鍣ㄥ疄渚�</p>
       </div>
-      <div class="d-flex align-items-center gap-3">
-        <div class="text-muted small">
-          杩愯涓�: {{ runningCount }} | 宸插仠姝�: {{ stoppedCount }}
-          <span v-if="errorCount > 0" class="text-danger">| 閿欒: {{ errorCount }}</span>
+      <div class="header-right">
+        <div class="stats">
+          <span>杩愯涓�: {{ runningCount }} | 宸插仠姝�: {{ stoppedCount }}</span>
+          <span v-if="errorCount > 0" class="error-text">| 閿欒: {{ errorCount }}</span>
         </div>
-        <router-link to="/create" class="btn btn-primary">
-          <i class="bi bi-plus-lg me-1"></i>鍒涘缓瀹炰緥
-        </router-link>
+        <el-button type="primary" @click="$router.push('/create')">
+          <el-icon><Plus /></el-icon>
+          鍒涘缓瀹炰緥
+        </el-button>
       </div>
     </div>
 
     <!-- Loading state -->
-    <div v-if="loading && instances.length === 0" class="text-center py-5">
-      <div class="spinner-border text-primary" role="status">
-        <span class="visually-hidden">鍔犺浇涓�...</span>
-      </div>
-      <p class="mt-3 text-muted">姝e湪鍔犺浇瀹炰緥鍒楄〃...</p>
+    <div v-if="loading && instances.length === 0" class="loading-container">
+      <el-icon class="loading-icon" :size="40"><Loading /></el-icon>
+      <p>姝e湪鍔犺浇瀹炰緥鍒楄〃...</p>
     </div>
 
     <!-- Empty state -->
-    <div v-else-if="instances.length === 0" class="empty-state">
-      <i class="bi bi-inbox"></i>
-      <h3>鏆傛棤瀹炰緥</h3>
-      <p>鐐瑰嚮涓婃柟"鍒涘缓瀹炰緥"鎸夐挳鏉ュ垱寤烘偍鐨勭涓�涓豢鐪熷櫒瀹炰緥</p>
-    </div>
+    <el-empty v-else-if="instances.length === 0" description="鏆傛棤瀹炰緥">
+      <el-button type="primary" @click="$router.push('/create')">鍒涘缓绗竴涓疄渚�</el-button>
+    </el-empty>
 
     <!-- Instances grid -->
-    <div v-else class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4">
-      <div v-for="instance in instances" :key="instance.instanceId" class="col">
-        <div :class="['card', 'instance-card', 'h-100', getStatusClass(instance.status)]">
-          <div class="card-header d-flex justify-content-between align-items-center">
-            <h5 class="card-title mb-0">{{ instance.instanceId }}</h5>
-            <span :class="['badge', getStatusClass(instance.status)]">
-              {{ getStatusText(instance.status) }}
-            </span>
-          </div>
-          <div class="card-body">
-            <div class="instance-info mb-3">
-              <div class="row mb-2">
-                <div class="col-6">
-                  <small class="instance-info-label">鍚嶇О</small>
-                  <div class="instance-info-value">{{ instance.name || '-' }}</div>
-                </div>
-                <div class="col-6">
-                  <small class="instance-info-label">PLC鍨嬪彿</small>
-                  <div class="instance-info-value">{{ getPlcTypeText(instance.plcType) }}</div>
-                </div>
-              </div>
-              <div class="row mb-2">
-                <div class="col-6">
-                  <small class="instance-info-label">绔彛</small>
-                  <div class="instance-info-value">{{ instance.port || '-' }}</div>
-                </div>
-                <div class="col-6">
-                  <small class="instance-info-label">瀹㈡埛绔�</small>
-                  <div class="instance-info-value">
-                    <i class="bi bi-people-fill me-1"></i>{{ instance.clientCount || 0 }}
-                  </div>
-                </div>
-              </div>
-              <div v-if="instance.startTime" class="row">
-                <div class="col-12">
-                  <small class="instance-info-label">鍚姩鏃堕棿</small>
-                  <div class="instance-info-value small">{{ formatDate(instance.startTime) }}</div>
-                </div>
-              </div>
-              <div v-if="instance.errorMessage" class="alert alert-danger alert-sm mt-2 mb-0 py-2 small">
-                <i class="bi bi-exclamation-triangle-fill me-1"></i>{{ instance.errorMessage }}
-              </div>
+    <el-row v-else :gutter="20">
+      <el-col v-for="instance in instances" :key="instance.instanceId" :xs="24" :sm="12" :xl="8">
+        <el-card class="instance-card" :class="getStatusClass(instance.status)" shadow="hover">
+          <template #header>
+            <div class="card-header">
+              <span class="instance-id">{{ instance.instanceId }}</span>
+              <el-tag :type="getStatusTagType(instance.status)">
+                {{ getStatusText(instance.status) }}
+              </el-tag>
             </div>
+          </template>
+
+          <div class="instance-info">
+            <el-descriptions :column="2" size="small">
+              <el-descriptions-item label="鍚嶇О">{{ instance.name || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="PLC鍨嬪彿">{{ getPlcTypeText(instance.plcType) }}</el-descriptions-item>
+              <el-descriptions-item label="绔彛">{{ instance.port || '-' }}</el-descriptions-item>
+              <el-descriptions-item label="瀹㈡埛绔�">
+                <el-icon><User /></el-icon>
+                {{ instance.clientCount || 0 }}
+              </el-descriptions-item>
+              <el-descriptions-item v-if="instance.startTime" label="鍚姩鏃堕棿" :span="2">
+                {{ formatDate(instance.startTime) }}
+              </el-descriptions-item>
+            </el-descriptions>
+
+            <el-alert
+              v-if="instance.errorMessage"
+              type="error"
+              :closable="false"
+              class="mt-2"
+              show-icon
+            >
+              {{ instance.errorMessage }}
+            </el-alert>
           </div>
-          <div class="card-footer bg-white">
-            <div class="action-buttons d-flex gap-2">
-              <button
+
+          <template #footer>
+            <div class="card-footer">
+              <el-button
                 v-if="instance.status === 'Running'"
-                class="btn btn-warning btn-sm flex-fill"
+                type="warning"
                 @click="handleStop(instance.instanceId)"
               >
-                <i class="bi bi-stop-fill me-1"></i>鍋滄
-              </button>
-              <button
+                <el-icon><VideoPause /></el-icon>
+                鍋滄
+              </el-button>
+              <el-button
                 v-if="instance.status === 'Stopped'"
-                class="btn btn-success btn-sm flex-fill"
+                type="success"
                 @click="handleStart(instance.instanceId)"
               >
-                <i class="bi bi-play-fill me-1"></i>鍚姩
-              </button>
-              <router-link :to="`/details/${instance.instanceId}`" class="btn btn-info btn-sm text-white flex-fill">
-                <i class="bi bi-info-circle-fill me-1"></i>璇︽儏
-              </router-link>
-              <router-link :to="`/edit/${instance.instanceId}`" class="btn btn-primary btn-sm flex-fill">
-                <i class="bi bi-pencil-fill me-1"></i>缂栬緫
-              </router-link>
-              <button class="btn btn-danger btn-sm" @click="handleDelete(instance.instanceId)">
-                <i class="bi bi-trash-fill"></i>
-              </button>
+                <el-icon><VideoPlay /></el-icon>
+                鍚姩
+              </el-button>
+              <el-button type="info" @click="$router.push(`/details/${instance.instanceId}`)">
+                <el-icon><InfoFilled /></el-icon>
+                璇︽儏
+              </el-button>
+              <el-button type="primary" @click="$router.push(`/edit/${instance.instanceId}`)">
+                <el-icon><Edit /></el-icon>
+                缂栬緫
+              </el-button>
+              <el-button type="danger" @click="handleDelete(instance.instanceId)">
+                <el-icon><Delete /></el-icon>
+              </el-button>
             </div>
-          </div>
-        </div>
-      </div>
-    </div>
+          </template>
+        </el-card>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
@@ -115,6 +110,18 @@
 import { onMounted, onUnmounted } from 'vue'
 import { storeToRefs } from 'pinia'
 import { useInstancesStore } from '../stores/instances'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import {
+  Cpu,
+  Plus,
+  Loading,
+  User,
+  VideoPause,
+  VideoPlay,
+  InfoFilled,
+  Edit,
+  Delete
+} from '@element-plus/icons-vue'
 
 const store = useInstancesStore()
 const { instances, loading, runningCount, stoppedCount, errorCount } = storeToRefs(store)
@@ -129,27 +136,45 @@
 })
 
 function handleStart(id: string) {
-  if (confirm(`纭畾瑕佸惎鍔ㄥ疄渚� "${id}" 鍚�?`)) {
-    store.startInstance(id).catch(() => {
-      alert('鍚姩澶辫触锛岃鏌ョ湅鎺у埗鍙�')
+  ElMessageBox.confirm(`纭畾瑕佸惎鍔ㄥ疄渚� "${id}" 鍚�?`, '纭', {
+    confirmButtonText: '纭畾',
+    cancelButtonText: '鍙栨秷',
+    type: 'info'
+  }).then(() => {
+    store.startInstance(id).then(() => {
+      ElMessage.success('鍚姩鍛戒护宸插彂閫�')
+    }).catch(() => {
+      ElMessage.error('鍚姩澶辫触锛岃鏌ョ湅鎺у埗鍙�')
     })
-  }
+  })
 }
 
 function handleStop(id: string) {
-  if (confirm(`纭畾瑕佸仠姝㈠疄渚� "${id}" 鍚�?`)) {
-    store.stopInstance(id).catch(() => {
-      alert('鍋滄澶辫触锛岃鏌ョ湅鎺у埗鍙�')
+  ElMessageBox.confirm(`纭畾瑕佸仠姝㈠疄渚� "${id}" 鍚�?`, '纭', {
+    confirmButtonText: '纭畾',
+    cancelButtonText: '鍙栨秷',
+    type: 'warning'
+  }).then(() => {
+    store.stopInstance(id).then(() => {
+      ElMessage.success('鍋滄鍛戒护宸插彂閫�')
+    }).catch(() => {
+      ElMessage.error('鍋滄澶辫触锛岃鏌ョ湅鎺у埗鍙�')
     })
-  }
+  })
 }
 
 function handleDelete(id: string) {
-  if (confirm(`纭畾瑕佸垹闄ゅ疄渚� "${id}" 鍚�?姝ゆ搷浣滀笉鍙挙閿�!`)) {
-    store.deleteInstance(id).catch(() => {
-      alert('鍒犻櫎澶辫触锛岃鏌ョ湅鎺у埗鍙�')
+  ElMessageBox.confirm(`纭畾瑕佸垹闄ゅ疄渚� "${id}" 鍚�?姝ゆ搷浣滀笉鍙挙閿�!`, '璀﹀憡', {
+    confirmButtonText: '纭畾',
+    cancelButtonText: '鍙栨秷',
+    type: 'error'
+  }).then(() => {
+    store.deleteInstance(id).then(() => {
+      ElMessage.success('瀹炰緥宸插垹闄�')
+    }).catch(() => {
+      ElMessage.error('鍒犻櫎澶辫触锛岃鏌ョ湅鎺у埗鍙�')
     })
-  }
+  })
 }
 
 function getStatusClass(status: string): string {
@@ -161,6 +186,17 @@
     'Error': 'status-error'
   }
   return map[status] || ''
+}
+
+function getStatusTagType(status: string): 'success' | 'info' | 'warning' | 'danger' | 'info' {
+  const map: Record<string, 'success' | 'info' | 'warning' | 'danger'> = {
+    'Stopped': 'info',
+    'Starting': 'info',
+    'Running': 'success',
+    'Stopping': 'warning',
+    'Error': 'danger'
+  }
+  return map[status] || 'info'
 }
 
 function getStatusText(status: string): string {
@@ -200,52 +236,104 @@
 </script>
 
 <style scoped>
-.instance-card {
-  transition: transform 0.2s, box-shadow 0.2s;
+.page-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  margin-bottom: 20px;
+  flex-wrap: wrap;
+  gap: 16px;
 }
 
-.instance-card:hover {
-  transform: translateY(-2px);
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+.header-left h2 {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin: 0 0 8px 0;
 }
 
-.instance-info-label {
-  color: #6c757d;
-  font-size: 0.75rem;
-  text-transform: uppercase;
-  letter-spacing: 0.5px;
+.text-muted {
+  color: #909399;
+  margin: 0;
 }
 
-.instance-info-value {
-  font-weight: 500;
-}
-
-.action-buttons {
+.header-right {
+  display: flex;
+  align-items: center;
+  gap: 16px;
   flex-wrap: wrap;
 }
 
-.status-stopped { border-left: 4px solid #6c757d; }
-.status-starting { border-left: 4px solid #0dcaf0; }
-.status-running { border-left: 4px solid #198754; }
-.status-stopping { border-left: 4px solid #ffc107; }
-.status-error { border-left: 4px solid #dc3545; }
+.stats {
+  color: #606266;
+  font-size: 14px;
+}
 
-.empty-state {
+.error-text {
+  color: #f56c6c;
+}
+
+.loading-container {
   text-align: center;
-  padding: 4rem 2rem;
-  color: #6c757d;
+  padding: 60px 0;
+  color: #909399;
 }
 
-.empty-state i {
-  font-size: 4rem;
-  margin-bottom: 1rem;
+.loading-icon {
+  animation: spin 1s linear infinite;
 }
 
-.empty-state h3 {
-  margin-bottom: 0.5rem;
+@keyframes spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
 }
 
-.alert-sm {
-  font-size: 0.875rem;
+.instance-card {
+  margin-bottom: 20px;
+  transition: all 0.3s;
+}
+
+.instance-card:hover {
+  transform: translateY(-4px);
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.instance-id {
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.instance-info {
+  margin-bottom: 16px;
+}
+
+.card-footer {
+  display: flex;
+  gap: 8px;
+  flex-wrap: wrap;
+}
+
+.card-footer .el-button {
+  flex: 1;
+  min-width: 60px;
+}
+
+.status-stopped { border-left: 4px solid #909399; }
+.status-starting { border-left: 4px solid #409eff; }
+.status-running { border-left: 4px solid #67c23a; }
+.status-stopping { border-left: 4px solid #e6a23c; }
+.status-error { border-left: 4px solid #f56c6c; }
+
+.mt-2 {
+  margin-top: 8px;
 }
 </style>

--
Gitblit v1.9.3