|
|
@@ -0,0 +1,427 @@
|
|
|
+<template>
|
|
|
+ <div class="sdk-detail-container">
|
|
|
+ <!-- SDK详情 -->
|
|
|
+ <div class="panel">
|
|
|
+ <div class="panel-header">SDK详情</div>
|
|
|
+ <div class="panel-body">
|
|
|
+ <el-form :model="sdkForm" class="sdk-form" label-width="auto" label-position="left" @submit.prevent>
|
|
|
+ <div class="grid-row">
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">实例唯一标识:</span>
|
|
|
+ <span class="value">{{ sdkData.id }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">实例名称:</span>
|
|
|
+ <span class="value">{{ sdkData.name }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">实例类型:</span>
|
|
|
+ <span class="value">{{ sdkData.type }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">实例状态:</span>
|
|
|
+ <span class="value">{{ sdkData.status }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">无心跳通讯:</span>
|
|
|
+ <span class="value">{{ sdkData.noHeartbeat }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">无数据超时时间:</span>
|
|
|
+ <span class="value">{{ sdkData.noDataTimeout }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item form-item">
|
|
|
+ <el-form-item label="是否启用LTS:">
|
|
|
+ <el-switch v-model="sdkForm.enableLTS" @change="handleSdkFormChange" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item form-item">
|
|
|
+ <el-form-item label="断线自动重连:">
|
|
|
+ <el-switch v-model="sdkForm.autoReconnect" @change="handleSdkFormChange" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">当前在线设备:</span>
|
|
|
+ <span class="value">{{ sdkData.onlineDevices }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">传流量汇总:</span>
|
|
|
+ <span class="value">{{ sdkData.trafficSum }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">日下载流量汇总:</span>
|
|
|
+ <span class="value">{{ sdkData.downloadTrafficSum }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">中发连接历史峰值:</span>
|
|
|
+ <span class="value">{{ sdkData.concurrentHistoryPeak }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">上传速率历史峰值:</span>
|
|
|
+ <span class="value">{{ sdkData.uploadSpeedPeak }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">下载速率历史峰值:</span>
|
|
|
+ <span class="value">{{ sdkData.downloadSpeedPeak }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">创建时间:</span>
|
|
|
+ <span class="value">{{ sdkData.createTime }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">到期时间:</span>
|
|
|
+ <span class="value">{{ sdkData.expireTime }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item form-item">
|
|
|
+ <el-form-item label="限制单连接流量每秒NKbps:">
|
|
|
+ <el-input v-model="sdkForm.limitConnTraffic" @blur="handleSdkFormChange" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item form-item">
|
|
|
+ <el-form-item label="限制单连接每秒发送包数:">
|
|
|
+ <el-input v-model="sdkForm.limitConnPackets" @blur="handleSdkFormChange" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">套餐:</span>
|
|
|
+ <span class="value">{{ sdkData.package }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item form-item">
|
|
|
+ <el-form-item label="回环IP:">
|
|
|
+ <el-input v-model="sdkForm.loopbackIp" @blur="handleSdkFormChange" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 套餐详情 -->
|
|
|
+ <div class="panel">
|
|
|
+ <div class="panel-header">套餐详情</div>
|
|
|
+ <div class="panel-body">
|
|
|
+ <div class="grid-row package-grid">
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">应用服务器数:</span>
|
|
|
+ <span class="value">{{ packageData.appServers }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">转发规则数:</span>
|
|
|
+ <span class="value">{{ packageData.forwardRules }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">设备数:</span>
|
|
|
+ <span class="value">{{ packageData.devices }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">并发数:</span>
|
|
|
+ <span class="value">{{ packageData.concurrent }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">带宽(M):</span>
|
|
|
+ <span class="value">{{ packageData.bandwidth }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">防护IP数:</span>
|
|
|
+ <span class="value">{{ packageData.protectIps }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">防护机房:</span>
|
|
|
+ <span class="value">{{ packageData.protectRooms }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="grid-item">
|
|
|
+ <span class="label">切换时间(毫秒):</span>
|
|
|
+ <span class="value">{{ packageData.switchTime }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 主节点规则 -->
|
|
|
+ <div class="panel">
|
|
|
+ <div class="panel-header">主节点规则</div>
|
|
|
+ <div class="panel-body">
|
|
|
+ <el-form :model="mainNodeForm" label-position="top">
|
|
|
+ <div v-for="(item, index) in mainNodeForm.rules" :key="item.id || index" class="rule-row">
|
|
|
+ <el-form-item label="分组节点" class="node-select">
|
|
|
+ <el-select v-model="item.groupNode" placeholder="请选择分组节点">
|
|
|
+ <el-option label="香港" value="香港" />
|
|
|
+ <el-option label="新加坡" value="新加坡" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="IP个数" class="node-select">
|
|
|
+ <el-select v-model="item.ipCount" placeholder="请选择IP个数">
|
|
|
+ <el-option label="1" :value="1" />
|
|
|
+ <el-option label="2" :value="2" />
|
|
|
+ <el-option label="3" :value="3" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <div class="rule-action">
|
|
|
+ <el-button type="danger" @click="removeMainNodeRule(index)">
|
|
|
+ <el-icon>
|
|
|
+ <Close />
|
|
|
+ </el-icon>
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="panel-actions">
|
|
|
+ <el-button type="primary" class="purple-btn" @click="addMainNodeRule">追加</el-button>
|
|
|
+ <el-button type="info" class="gray-btn" @click="saveMainNodeRules">保存更改</el-button>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 备用节点规则 -->
|
|
|
+ <div class="panel">
|
|
|
+ <div class="panel-header">备用节点规则</div>
|
|
|
+ <div class="panel-body">
|
|
|
+ <el-form :model="backupNodeForm" label-position="top">
|
|
|
+ <div v-for="(item, index) in backupNodeForm.rules" :key="item.id || index" class="rule-row">
|
|
|
+ <el-form-item label="分组节点" class="node-select">
|
|
|
+ <el-select v-model="item.groupNode" placeholder="请选择分组节点">
|
|
|
+ <el-option label="香港" value="香港" />
|
|
|
+ <el-option label="新加坡" value="新加坡" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="IP个数" class="node-select">
|
|
|
+ <el-select v-model="item.ipCount" placeholder="请选择IP个数">
|
|
|
+ <el-option label="1" :value="1" />
|
|
|
+ <el-option label="2" :value="2" />
|
|
|
+ <el-option label="3" :value="3" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <div class="rule-action">
|
|
|
+ <el-button type="danger" @click="removeBackupNodeRule(index)">
|
|
|
+ <el-icon>
|
|
|
+ <Close />
|
|
|
+ </el-icon>
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="panel-actions">
|
|
|
+ <el-button type="primary" class="purple-btn" @click="addBackupNodeRule">追加</el-button>
|
|
|
+ <el-button type="info" class="gray-btn" @click="saveBackupNodeRules">保存更改</el-button>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { reactive } from 'vue'
|
|
|
+import { Close } from '@element-plus/icons-vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+
|
|
|
+// Mock Data for SDK Details
|
|
|
+const sdkData = reactive({
|
|
|
+ id: '7d8d1415-b3744597-8827-e1663bed6c',
|
|
|
+ name: 'socke服务',
|
|
|
+ type: 'socket',
|
|
|
+ status: '正常',
|
|
|
+ noHeartbeat: 0,
|
|
|
+ noDataTimeout: 0,
|
|
|
+ onlineDevices: 0,
|
|
|
+ trafficSum: 0,
|
|
|
+ downloadTrafficSum: '0B',
|
|
|
+ concurrentHistoryPeak: 18,
|
|
|
+ uploadSpeedPeak: '5.36Mbps/秒',
|
|
|
+ downloadSpeedPeak: '6.75Kbps/秒',
|
|
|
+ createTime: '2026-02-03 17:05:23',
|
|
|
+ expireTime: '2025-10-08 15:17:36',
|
|
|
+ package: '定制版'
|
|
|
+})
|
|
|
+
|
|
|
+// Form Data for SDK Details (editable fields)
|
|
|
+const sdkForm = reactive({
|
|
|
+ enableLTS: false,
|
|
|
+ autoReconnect: false,
|
|
|
+ limitConnTraffic: '',
|
|
|
+ limitConnPackets: '',
|
|
|
+ loopbackIp: ''
|
|
|
+})
|
|
|
+
|
|
|
+const handleSdkFormChange = () => {
|
|
|
+ // Trigger API request here
|
|
|
+ console.log('SDK Form changed, triggering save request:', sdkForm)
|
|
|
+ ElMessage.success('SDK详情已自动保存')
|
|
|
+}
|
|
|
+
|
|
|
+// Mock Data for Package Details
|
|
|
+const packageData = reactive({
|
|
|
+ appServers: 1,
|
|
|
+ forwardRules: 1,
|
|
|
+ devices: 1,
|
|
|
+ concurrent: 1,
|
|
|
+ bandwidth: 1,
|
|
|
+ protectIps: 1,
|
|
|
+ protectRooms: '1个',
|
|
|
+ switchTime: ''
|
|
|
+})
|
|
|
+
|
|
|
+// Main Node Rules
|
|
|
+const mainNodeForm = reactive({
|
|
|
+ rules: [
|
|
|
+ { id: Date.now(), groupNode: '香港', ipCount: 2 }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+const addMainNodeRule = () => {
|
|
|
+ mainNodeForm.rules.push({ id: Date.now(), groupNode: '', ipCount: null as any })
|
|
|
+}
|
|
|
+
|
|
|
+const removeMainNodeRule = (index: number) => {
|
|
|
+ mainNodeForm.rules.splice(index, 1)
|
|
|
+}
|
|
|
+
|
|
|
+const saveMainNodeRules = () => {
|
|
|
+ console.log('Save main node rules:', mainNodeForm.rules)
|
|
|
+ ElMessage.success('主节点规则保存成功')
|
|
|
+}
|
|
|
+
|
|
|
+// Backup Node Rules
|
|
|
+const backupNodeForm = reactive({
|
|
|
+ rules: [
|
|
|
+ { id: Date.now() + 1, groupNode: '香港', ipCount: 2 }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+const addBackupNodeRule = () => {
|
|
|
+ backupNodeForm.rules.push({ id: Date.now(), groupNode: '', ipCount: null as any })
|
|
|
+}
|
|
|
+
|
|
|
+const removeBackupNodeRule = (index: number) => {
|
|
|
+ backupNodeForm.rules.splice(index, 1)
|
|
|
+}
|
|
|
+
|
|
|
+const saveBackupNodeRules = () => {
|
|
|
+ console.log('Save backup node rules:', backupNodeForm.rules)
|
|
|
+ ElMessage.success('备用节点规则保存成功')
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.sdk-detail-container {
|
|
|
+ color: var(--admin-text-primary);
|
|
|
+ padding-top: 20px;
|
|
|
+ background-color: var(--admin-bg);
|
|
|
+}
|
|
|
+
|
|
|
+.panel {
|
|
|
+ background-color: var(--admin-card-bg);
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ overflow: hidden;
|
|
|
+ border: 1px solid var(--admin-border-color);
|
|
|
+}
|
|
|
+
|
|
|
+.panel-header {
|
|
|
+ background-color: var(--admin-header-form-bg);
|
|
|
+ color: #fff;
|
|
|
+ padding: 12px 20px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-body {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.grid-row {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, 1fr);
|
|
|
+ gap: 24px 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.grid-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ min-height: 32px;
|
|
|
+
|
|
|
+ .label {
|
|
|
+ color: var(--admin-text-secondary);
|
|
|
+ margin-right: 8px;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .value {
|
|
|
+ color: var(--admin-text-primary);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.form-item {
|
|
|
+ .el-form-item {
|
|
|
+ margin-bottom: 0;
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ :deep(.el-form-item__label) {
|
|
|
+ color: var(--admin-text-secondary);
|
|
|
+ padding-right: 8px;
|
|
|
+ line-height: 32px;
|
|
|
+ height: 32px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-form-item__content) {
|
|
|
+ line-height: 32px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input {
|
|
|
+ width: 140px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.rule-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+ gap: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ .node-select {
|
|
|
+ margin-bottom: 0;
|
|
|
+ flex: 1;
|
|
|
+ max-width: 48%;
|
|
|
+
|
|
|
+ :deep(.el-form-item__label) {
|
|
|
+ color: var(--admin-text-secondary);
|
|
|
+ padding-bottom: 8px;
|
|
|
+ line-height: normal;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .rule-action {
|
|
|
+ padding-bottom: 0px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.panel-actions {
|
|
|
+ margin-top: 20px;
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.purple-btn {
|
|
|
+ background: var(--btn-primary-gradient);
|
|
|
+ border: none;
|
|
|
+ color: white;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: var(--btn-primary-gradient-hover);
|
|
|
+ box-shadow: 0 4px 12px var(--btn-primary-shadow);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.gray-btn {
|
|
|
+ background-color: var(--admin-table-header-bg);
|
|
|
+ border-color: var(--admin-border-color);
|
|
|
+ color: var(--admin-text-primary);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: var(--admin-border-color);
|
|
|
+ border-color: var(--admin-text-secondary);
|
|
|
+ color: var(--admin-text-primary);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|