Browse Source

布局优化

WangMengRu 4 days ago
parent
commit
97fc888734

+ 119 - 55
src/assets/i18n/en.js

@@ -125,77 +125,138 @@ export default {
     cacheRate: 'Cache Rate',
     lastMonthTraffic: 'Last Month Traffic',
     trafficAnalysis: 'Traffic Analysis',
-    day: 'Daily',
-    month: 'Monthly',
-    year: 'Yearly',
-    trafficTrend: 'Traffic Trend',
-    requestCount: 'Request Count',
-    peakBandwidth: 'Peak Bandwidth',
-    peakQPS: 'Peak QPS',
     traffic: 'Traffic',
     requests: 'Requests',
     bandwidth: 'Bandwidth',
     qps: 'QPS',
     last24h: 'Last 24h',
     last7d: 'Last 7d',
-    last30d: 'Last 30d'
+    last30d: 'Last 30d',
+    dataIndicator: 'Data Indicator',
+    realTimeDataIn24Hours: 'Real Time Data In 24 Hours',
+    trendIn7Days: 'Trend In 7 Days',
+    trendIn30Days: 'Trend In 30 Days',
+    realTime: 'Real Time',
+    weekly: 'Weekly',
+    monthly: 'Monthly',
+    year: 'Yearly',
+    peakBandwidth: 'Peak Bandwidth',
+    trafficTrend: 'Traffic Trend',
+    requestCount: 'Request Count',
+    peakQPS: 'Peak QPS',
+    cancel: 'Cancel',
+    confirm: 'Confirm',
+
   },
-  product: {
-    title: 'Product Management',
+  certificate: {
+    title: 'Certificate Management',
+    add: 'Add Certificate',
     search: {
-      name: 'Product Name',
-      namePlaceholder: 'Please input product name',
-      category: 'Category',
-      categoryPlaceholder: 'Please select category',
+      certificate: 'Certificate',
+      certificatePlaceholder: 'Please enter certificate name',
       status: 'Status',
       statusPlaceholder: 'Please select status'
     },
     table: {
-      name: 'Product Name',
-      category: 'Category',
-      price: 'Price',
-      stock: 'Stock',
-      status: 'Status'
-    },
-    category: {
-      electronics: 'Electronics',
-      clothing: 'Clothing',
-      food: 'Food'
-    },
-    status: {
-      0: 'Inactive',
-      1: 'Active'
-    }
-  },
-  order: {
-    title: 'Order Management',
-    search: {
-      orderNo: 'Order No.',
-      orderNoPlaceholder: 'Please input order number',
-      status: 'Order Status',
-      statusPlaceholder: 'Please select order status',
-      dateRange: 'Date Range',
-      startDate: 'Start Date',
-      endDate: 'End Date'
-    },
-    table: {
-      orderNo: 'Order No.',
-      customerName: 'Customer Name',
-      amount: 'Amount',
+      Host: 'Host',
+      expiresOn: 'Expires On',
+      type: 'Type',
       status: 'Status',
-      createTime: 'Create Time'
+      bindDomainsTotal: 'Bound Domains'
     },
     status: {
-      pending: 'Pending',
-      processing: 'Processing',
-      completed: 'Completed',
-      cancelled: 'Cancelled'
+      active: 'Valid',
+      inactive: 'Invalid',
+      error: 'Error',
+      expired: 'Expired',
+      expiring: 'Expiring Soon'
     },
-    operations: {
-      detail: 'View Detail',
-      process: 'Process Order'
+    form: {
+      addCertificate: 'Add Certificate',
+      updateCertificate: 'Update Certificate',
+      host: 'Host',
+      hostPlaceholder: 'Please enter host',
+      certificateType: 'Certificate Type',
+      certificateContent: 'Certificate Content',
+      privateKey: 'Private Key',
+      uploadCertificate: 'Upload Certificate',
+      uploadPrivateKey: 'Upload Private Key'
+    },
+    messages: {
+      uploadSuccess: 'Upload successful',
+      updateSuccess: 'Update successful',
+      deleteSuccess: 'Delete successful',
+      deleteConfirm: 'Are you sure to delete this certificate?'
     }
   },
+  statistics: {
+    dataIndicator: 'Data Indicator',
+    domain: 'Domain',
+    equal: 'Equal',
+    notEqual: 'Not Equal',
+    greaterThan: 'Greater Than',
+    lessThan: 'Less Than',
+    startTime: 'Start Time',
+    endTime: 'End Time',
+    rangeSeparator: 'To',
+    export: 'Export',
+    cacheRate: 'Cache Rate',
+    countryDistribution: 'Country Distribution',
+    statusCodeDistribution: 'Status Code Distribution',
+    hostnameDistribution: 'Hostname Distribution',
+    cacheStatus: 'Cache Status',
+    requests: 'Requests',
+    peakBandwidth: 'Peak Bandwidth',
+    traffic: 'Traffic',
+    qps: 'QPS',
+    optionalValue: 'Optional Value'
+  },
+  refresh: {
+    submitRefreshTask: 'Submit Refresh Task',
+    submitPreheatTask: 'Submit Preheat Task',
+    urlAddress: 'URL Address',
+    pleaseEnterTheURLAddressToBeRefreshed: 'Please enter the URL address to be refreshed, multiple addresses please separate by line breaks',
+    pleaseEnterTheURLAddressToBePreheated: 'Please enter the URL address to be preheated, multiple addresses please separate by line breaks',
+    cancel: 'Cancel',
+    confirm: 'Confirm',
+    refreshType: 'Refresh Type',
+    directory: 'Directory',
+    file: 'File',
+    operation: 'Operation',
+    stop: 'Stop',
+    completeTime: 'Complete Time',
+    progress: 'Progress',
+    taskDescription: 'Task Description',
+    submitTime: 'Submit Time',
+    taskStatus: 'Task Status',
+    taskStatusPending: 'Pending',
+    taskStatusRunning: 'Running',
+    taskStatusCompleted: 'Completed',
+    taskStatusFailed: 'Failed',
+    taskStatusStopped: 'Stopped',
+    taskStatusCanceled: 'Canceled',
+    taskStatusPaused: 'Paused',
+    taskStatusQueued: 'Queued',
+    taskStatusProcessing: 'Processing',
+    taskStatusCompletedWithErrors: 'Completed With Errors',
+    taskStatusCompletedWithWarnings: 'Completed With Warnings',
+    cacheRefresh: 'Cache Refresh',
+    cacheRefreshDescription: 'By refreshing the cache, the cached files on the edge node will be forcibly cleared, and the latest version of these files will be obtained when accessed again.',
+    cacheRefreshTime: 'After submitting the refresh, the node will usually complete the cache refresh in 30 seconds to 10 minutes.',
+    cacheRefreshWarning: 'Note: This operation will delete the cached files from the edge node, please confirm before proceeding to avoid accidental operation.',
+    refreshContent: 'Refresh Content',
+    resubmit: 'Resubmit',
+    filePreheat: 'File Preheating',
+    submitRefresh: 'Submit Refresh',
+    filePreheatDescription: 'By preheating files, the files can be cached on the edge node in advance, and the edge node can deliver content to users more quickly when users access.',
+    filePreheatHelp: 'File preheating also helps to relieve the pressure on the source server, avoiding high load on the source server when a large number of users access new resources.',
+    filePreheatTime: 'The preheating time is related to the number and size of files, which may take several minutes to several hours (reference time: about 3000-5000 files per hour).',
+    status: 'Status',
+    submitPreheat: 'Submit Preheat',
+    preheatDescription: 'Preheat Description',
+    refreshDescription: 'Refresh Description',
+
+  },
   system: {
     title: 'Admin System'
   },
@@ -204,8 +265,11 @@ export default {
     user: 'User',
     domain: 'Domain',
     addDomain: 'Add Domain',
-    product: 'Product',
-    order: 'Order'
+    certificate: 'Certificate',
+    addCertificate: 'Add Certificate',
+    statistics: 'Statistics',
+    refresh: 'Refresh',
+    account: 'Account'
   },
   navbar: {
     language: 'Language',

+ 111 - 67
src/assets/i18n/zh-CN.js

@@ -117,64 +117,23 @@ export default {
     qps: 'QPS',
     last24h: '近24小时',
     last7d: '近7天',
-    last30d: '近30天'
-  },
-  product: {
-    title: '产品管理',
-    search: {
-      name: '产品名称',
-      namePlaceholder: '请输入产品名称',
-      category: '产品分类',
-      categoryPlaceholder: '请选择产品分类',
-      status: '状态',
-      statusPlaceholder: '请选择状态'
-    },
-    table: {
-      name: '产品名称',
-      category: '产品分类',
-      price: '价格',
-      stock: '库存',
-      status: '状态'
-    },
-    category: {
-      electronics: '电子产品',
-      clothing: '服装',
-      food: '食品'
-    },
-    status: {
-      0: '下架',
-      1: '上架'
-    }
-  },
-  order: {
-    title: '订单管理',
-    search: {
-      orderNo: '订单编号',
-      orderNoPlaceholder: '请输入订单编号',
-      status: '订单状态',
-      statusPlaceholder: '请选择订单状态',
-      dateRange: '日期范围',
-      startDate: '开始日期',
-      endDate: '结束日期'
-    },
-    table: {
-      orderNo: '订单编号',
-      customerName: '客户名称',
-      amount: '订单金额',
-      status: '订单状态',
-      createTime: '创建时间'
-    },
-    status: {
-      pending: '待处理',
-      processing: '处理中',
-      completed: '已完成',
-      cancelled: '已取消'
-    },
-    operations: {
-      detail: '查看详情',
-      process: '处理订单'
-    }
+    last30d: '近30天',
+    dataIndicator: '数据指标',
+    realTimeDataIn24Hours: '近24小时实时数据',
+    trendIn7Days: '近7天趋势',
+    trendIn30Days: '近30天趋势',
+    realTime: '实时',
+    weekly: '周度',
+    monthly: '月度',
+    year: '年度',
+    peakBandwidth: '峰值带宽',
+    trafficTrend: '流量趋势',
+    requestCount: '请求数趋势',
+    peakQPS: '峰值QPS',
+    cancel: '取消',
+    confirm: '确定',
   },
+ 
   system: {
     title: '后台管理系统'
   },
@@ -195,28 +154,113 @@ export default {
   },
   certificate: {
     title: '证书管理',
+    add: '添加证书',
     search: {
-      domain: '域名',
-      domainPlaceholder: '请输入域名',
+      certificate: '证书',
+      certificatePlaceholder: '请输入证书名称',
       status: '状态',
       statusPlaceholder: '请选择状态'
     },
     table: {
-      domain: '域名',
-      expireTime: '过期时间',
-      status: '状态'
+      Host: '主机名',
+      expiresOn: '过期时间',
+      type: '证书类型',
+      status: '证书状态',
+      bindDomainsTotal: '绑定域名数'
     },
     status: {
-      valid: '有效',
+      active: '有效',
+      inactive: '无效',
+      error: '异常',
       expired: '已过期',
-      soon: '即将过期'
+      expiring: '即将过期'
     },
-    operations: {
-      renew: '续期'
+    form: {
+      addCertificate: '添加证书',
+      updateCertificate: '更新证书',
+      host: '主机名',
+      hostPlaceholder: '请输入主机名',
+      certificateType: '证书类型',
+      certificateContent: '证书内容',
+      privateKey: '私钥',
+      uploadCertificate: '上传证书',
+      uploadPrivateKey: '上传私钥'
+    },
+    messages: {
+      uploadSuccess: '上传成功',
+      updateSuccess: '更新成功',
+      deleteSuccess: '删除成功',
+      deleteConfirm: '确定要删除此证书吗?'
     }
   },
+  statistics: {
+    dataIndicator: '数据指标',
+    domain: '域名',
+    equal: '等于',
+    notEqual: '不等于',
+    greaterThan: '大于',
+    lessThan: '小于',
+    startTime: '开始时间',
+    endTime: '结束时间',
+    rangeSeparator: '至',
+    export: '导出',
+    cacheRate: '缓存命中率',
+    countryDistribution: '国家分布',
+    statusCodeDistribution: '状态码分布',
+    hostnameDistribution: '主机名分布',
+    cacheStatus: '缓存状态',
+    requests: '请求数',
+    peakBandwidth: '峰值带宽',
+    traffic: '流量',
+    qps: 'QPS',
+    optionalValue: '可选值'
+  },
+  refresh: {
+    submitRefreshTask: '提交刷新任务',
+    submitPreheatTask: '提交预热任务',
+    urlAddress: 'URL地址',
+    pleaseEnterTheURLAddressToBeRefreshed: '请输入需要刷新的URL地址,多个地址请换行分隔',
+    pleaseEnterTheURLAddressToBePreheated: '请输入需要预热的URL地址,多个地址请换行分隔',
+    cancel: '取消',
+    confirm: '确认',
+    refreshType: '刷新类型',
+    directory: '目录',
+    file: '文件',
+    operation: '操作',
+    stop: '停止',
+    completeTime: '完成时间',
+    progress: '进度',
+    taskDescription: '任务描述',
+    submitTime: '提交时间',
+    taskStatus: '任务状态',
+    taskStatusPending: '待执行',
+    taskStatusRunning: '执行中',
+    taskStatusCompleted: '已完成',
+    taskStatusFailed: '失败',
+    taskStatusStopped: '已停止',
+    taskStatusCanceled: '已取消',
+    taskStatusPaused: '已暂停',
+    taskStatusQueued: '已排队',
+    taskStatusProcessing: '处理中',
+    taskStatusCompletedWithErrors: '已完成(部分失败)',
+    taskStatusCompletedWithWarnings: '已完成(部分警告)',
+    cacheRefresh: '缓存刷新',
+    cacheRefreshDescription: '通过刷新缓存,能够强制将边缘节点上已缓存的文件清除掉,再次访问时会从源站服务器中重新获取这些文件的最新版本。',
+    cacheRefreshTime: '提交刷新后,通常节点会在30秒至10分钟不等完成刷新缓存。',
+    cacheRefreshWarning: '注意:该操作会将已缓存文件从边缘节点删除掉,请确认后再进行操作,避免误操作。',
+    refreshContent: '刷新内容',
+    resubmit: '重新提交',
+    filePreheat: '文件预热',
+    submitRefresh: '提交刷新',
+    filePreheatDescription: '通过文件预热,能够提前将文件缓存在边缘节点上,当用户发起访问时,边缘节点能够更快速的将内容交付给用户。',
+    filePreheatHelp: '文件预热还有助于缓解源站压力,避免大量用户访问新资源时,源站负载过高。',
+    filePreheatTime: '预热所需时间与文件数量和大小相关,可能在数分钟到数小时不等(参考时长:每小时可预热约3000-5000个文件)',
+    status: '状态',
+    submitPreheat: '提交预热',
+    preheatDescription: '预热说明',
+    refreshDescription: '刷新说明',
+  },
   account: {
     title: '账号设置',
-    // ... 账号设置相关翻译
   }
 } 

+ 6 - 0
src/router/index.js

@@ -49,6 +49,12 @@ const routes = [
         component: () => import('@/views/certificate.vue'),
         meta: { title: 'menu.certificate', icon: 'Lock' }
       },
+      {
+        path: 'addCertificate',
+        name: 'addCertificate',
+        component: () => import('@/views/addCertificate.vue'),
+        meta: { title: 'menu.certificate', icon: 'Lock' }
+      },
       {
         path: 'account',
         name: 'Account',

+ 210 - 0
src/views/addCertificate.vue

@@ -0,0 +1,210 @@
+<template>
+    <div class="certificate-upload">
+      <!-- 证书输入区域 -->
+      <div class="input-section">
+        <div class="form-item">
+          <div class="label">
+            证书(PEM): <span class="required">*</span>
+          </div>
+          <el-input
+            v-model="certificateContent"
+            type="textarea"
+            :rows="8"
+            :placeholder="'将证书复制粘贴至空入框或点击上传文件'"
+          />
+          <div class="upload-hint">
+            <span>将证书复制粘贴至空入框或点击</span>
+            <el-upload
+              class="inline-upload"
+              :auto-upload="false"
+              accept=".pem"
+              :show-file-list="false"
+              :on-change="handleCertFileChange"
+            >
+              <el-link type="primary">上传文件</el-link>
+            </el-upload>
+          </div>
+        </div>
+  
+        <div class="form-item">
+          <div class="label">
+            私钥(PEM): <span class="required">*</span>
+          </div>
+          <el-input
+            v-model="privateKeyContent"
+            type="textarea"
+            :rows="8"
+            :placeholder="'将私钥复制粘贴至空入框或点击上传文件'"
+          />
+          <div class="upload-hint">
+            <span>将私钥复制粘贴至空入框或点击</span>
+            <el-upload
+              class="inline-upload"
+              :auto-upload="false"
+              accept=".pem"
+              :show-file-list="false"
+              :on-change="handleKeyFileChange"
+            >
+              <el-link type="primary">上传文件</el-link>
+            </el-upload>
+          </div>
+        </div>
+      </div>
+  
+      <!-- 按钮区域 -->
+      <div class="button-group">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleSubmit">确定</el-button>
+      </div>
+    </div>
+  </template>
+  
+  <script setup>
+  import { ref } from 'vue'
+  import { ElMessage } from 'element-plus'
+  import { useRouter } from 'vue-router'
+  
+  const router = useRouter()
+  const certificateContent = ref('')
+  const privateKeyContent = ref('')
+  
+  // 处理证书文件上传
+  const handleCertFileChange = (file) => {
+    if (!validateFile(file)) return
+    readFile(file.raw, (content) => {
+      certificateContent.value = content
+      ElMessage.success('证书文件读取成功')
+    })
+  }
+  
+  // 处理私钥文件上传
+  const handleKeyFileChange = (file) => {
+    if (!validateFile(file)) return
+    readFile(file.raw, (content) => {
+      privateKeyContent.value = content
+      ElMessage.success('私钥文件读取成功')
+    })
+  }
+  
+  // 文件验证
+  const validateFile = (file) => {
+    const isPEM = file.name.endsWith('.pem')
+    if (!isPEM) {
+      ElMessage.error('只能上传 PEM 格式的文件!')
+      return false
+    }
+    return true
+  }
+  
+  // 读取文件内容
+  const readFile = (file, callback) => {
+    const reader = new FileReader()
+    reader.onload = (e) => {
+      callback(e.target.result)
+    }
+    reader.onerror = () => {
+      ElMessage.error('文件读取失败')
+    }
+    reader.readAsText(file)
+  }
+  
+  // 取消
+  const handleCancel = () => {
+    router.back()
+  }
+  
+  // 提交
+  const handleSubmit = async () => {
+    if (!certificateContent.value || !privateKeyContent.value) {
+      ElMessage.warning('请填写完整的证书和私钥信息')
+      return
+    }
+  
+    try {
+      // 这里添加实际的提交逻辑
+      await submitCertificate({
+        certificate: certificateContent.value,
+        privateKey: privateKeyContent.value
+      })
+      ElMessage.success('证书添加成功')
+      router.back()
+    } catch (error) {
+      ElMessage.error(error.message || '证书添加失败')
+    }
+  }
+  
+  // 提交证书到后端的方法
+  const submitCertificate = async (data) => {
+    // 这里替换为实际的API调用
+    const response = await fetch('/api/certificates', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json'
+      },
+      body: JSON.stringify(data)
+    })
+    
+    if (!response.ok) {
+      throw new Error('提交失败')
+    }
+    
+    return await response.json()
+  }
+  
+  defineOptions({
+    name: 'AddCertificate'
+  })
+  </script>
+  
+  <style lang="scss" scoped>
+  .certificate-upload {
+    padding: 20px;
+    
+    .input-section {
+      max-width: 800px;
+      margin: 0 auto;
+  
+      .form-item {
+        margin-bottom: 24px;
+  
+        .label {
+          margin-bottom: 8px;
+          font-weight: 500;
+          
+          .required {
+            color: #f56c6c;
+            margin-left: 4px;
+          }
+        }
+  
+        .upload-hint {
+          margin-top: 8px;
+          color: #606266;
+          font-size: 14px;
+          display: flex;
+          align-items: center;
+          gap: 4px;
+  
+          .inline-upload {
+            display: inline-block;
+          }
+        }
+      }
+    }
+  
+    .button-group {
+      margin-top: 24px;
+      text-align: center;
+      
+      .el-button {
+        min-width: 100px;
+        margin: 0 10px;
+      }
+    }
+  }
+  
+  :deep(.el-textarea__inner) {
+    font-family: monospace;
+    font-size: 14px;
+  }
+  </style>

+ 26 - 19
src/views/certificate.vue

@@ -1,21 +1,21 @@
 <template>
-  <page-container :title="$t('domain.title')">
+  <page-container :title="$t('certificate.title')">
     <!-- 搜索区域 -->
     <template #search class="search-container">
       <el-form :inline="true" :model="searchForm" class="search-form">
-        <el-form-item :label="$t('domain.search.domain')" class="search-item">
-          <el-input v-model="searchForm.domain" :placeholder="$t('domain.search.domainPlaceholder')" />
+        <el-form-item :label="$t('certificate.search.certificate')" class="search-item">
+          <el-input v-model="searchForm.certificate" :placeholder="$t('certificate.search.certificatePlaceholder')" />
         </el-form-item>
 
         <el-form-item class="search-buttons">
           <el-button type="primary" @click="handleSearch">
             {{ $t('common.search') }}
           </el-button>
-          <el-button @click="resetSearch">
+          <!-- <el-button @click="resetSearch">
             {{ $t('common.reset') }}
-          </el-button>
-          <el-button type="success" @click="handleAddDomain" class="add-button">
-            {{ $t('domain.add') }}
+          </el-button> -->
+          <el-button type="success" @click="handleAddCertificate" class="add-button">
+            {{ $t('certificate.add') }}
           </el-button>
         </el-form-item>
       </el-form>
@@ -23,24 +23,30 @@
 
     <!-- 表格区域 -->
     <el-table :data="tableData" border v-loading="loading">
-      <el-table-column prop="domain" :label="$t('domain.table.domain')" />
-      <el-table-column prop="domain" :label="$t('domain.table.originDomain')" />
-      <el-table-column prop="domain" :label="$t('domain.table.ssl')" />
-      <el-table-column prop="type" :label="$t('domain.table.type')" />
-      <el-table-column prop="status" :label="$t('domain.table.status')">
+      <el-table-column prop="Host" :label="$t('certificate.table.Host')" />
+      <el-table-column prop="expiresOn" :label="$t('certificate.table.expiresOn')" />
+      <el-table-column prop="type" :label="$t('certificate.table.type')" />
+      <el-table-column prop="status" :label="$t('certificate.table.status')">
         <template #default="{ row }">
           <el-tag :type="getStatusType(row.status)">
-            {{ $t(`domain.status.${row.status}`) }}
+            {{ $t(`certificate.status.${row.status}`) }}
           </el-tag>
         </template>
       </el-table-column>
+      <el-table-column prop="bindDomainsTotal" :label="$t('certificate.table.bindDomainsTotal')" />
       <el-table-column :label="$t('common.operations')" width="200" fixed="right">
         <template #default="{ row }">
-          <el-button type="primary" link @click="handleEdit(row)">
-            {{ $t('common.edit') }}
+          <el-button type="primary" link @click="updateCertificatePage(row)">
+            {{ $t('common.update') }}
+          </el-button>
+          <el-button type="danger" link @click="viewCertification(row)">
+            {{ $t('common.viewCertification') }}
+          </el-button>
+          <el-button type="primary" link @click="download(row)">
+            {{ $t('common.download') }}
           </el-button>
-          <el-button type="danger" link @click="handleDelete(row)">
-            {{ $t('common.delete') }}
+          <el-button type="danger" link @click="deleteCertification(row)">
+            {{ $t('common.deleteCertification') }}
           </el-button>
         </template>
       </el-table-column>
@@ -109,8 +115,8 @@ const resetSearch = () => {
 }
 
 // 添加域名
-const handleAddDomain = () => {
-  router.push('/addDomain')
+const handleAddCertificate = () => {
+  router.push('/addCertificate')
 }
 
 // 获取数据
@@ -173,6 +179,7 @@ defineOptions({
 .search-item{
   display: flex;
   align-items: center;
+  width: 320px;
 }
 .search-buttons{
   display: flex;

+ 14 - 11
src/views/dashboard.vue

@@ -20,12 +20,12 @@
     <!-- 图表控制区 -->
     <el-card class="chart-control-card">
       <div class="chart-controls">
-        <span class="control-label">数据指标:</span>
+        <span class="control-label">{{ $t('dashboard.dataIndicator')}}:</span>
         <el-select v-model="selectedMetric" class="metric-selector">
-          <el-option label="峰值带宽" value="bandwidth" />
-          <el-option label="流量趋势" value="traffic" />
-          <el-option label="请求数趋势" value="requests" />
-          <el-option label="峰值QPS" value="qps" />
+          <el-option :label="$t('dashboard.peakBandwidth')" value="bandwidth" />
+          <el-option :label="$t('dashboard.trafficTrend')" value="traffic" />
+          <el-option :label="$t('dashboard.requestCount')" value="requests" />
+          <el-option :label="$t('dashboard.peakQPS')" value="qps" />
         </el-select>
       </div>
     </el-card>
@@ -37,9 +37,9 @@
         <div class="chart-header">
           <span class="chart-title">
             <el-icon><Timer /></el-icon>
-            近24小时实时数据
+            {{ $t('dashboard.realTimeDataIn24Hours') }}
           </span>
-          <el-tag size="small" effect="dark" type="success">实时</el-tag>
+          <el-tag size="small" effect="dark" type="success" class="chart-tag">{{ $t('dashboard.realTime') }}</el-tag>
         </div>
       </template>
       <div ref="chart24h" class="chart chart-24h-container"></div>
@@ -51,9 +51,9 @@
         <div class="chart-header">
           <span class="chart-title">
             <el-icon><Calendar /></el-icon>
-            近7天趋势
+            {{ $t('dashboard.trendIn7Days') }}
           </span>
-          <el-tag size="small" effect="dark" type="warning">周度</el-tag>
+          <el-tag size="small" effect="dark" type="warning" class="chart-tag">{{ $t('dashboard.weekly') }}</el-tag>
         </div>
       </template>
       <div ref="chart7d" class="chart chart-7d-container"></div>
@@ -65,9 +65,9 @@
         <div class="chart-header">
           <span class="chart-title">
             <el-icon><TrendCharts /></el-icon>
-            近30天趋势
+            {{ $t('dashboard.trendIn30Days') }}
           </span>
-          <el-tag size="small" effect="dark" type="info">月度</el-tag>
+          <el-tag size="small" effect="dark" type="info" class="chart-tag">{{ $t('dashboard.monthly') }}</el-tag>
         </div>
       </template>
       <div ref="chart30d" class="chart chart-30d-container"></div>
@@ -400,6 +400,9 @@ onUnmounted(() => {
     }
   }
 }
+.chart-tag{
+  margin-left: 10px;
+}
 
 // 创新图表网格布局
 .charts-grid {

+ 36 - 36
src/views/refresh.vue

@@ -4,9 +4,9 @@
     <el-card class="section-card refresh-section">
       <template #header>
         <div class="section-header">
-          <h2>缓存刷新</h2>
+          <h2>{{$t('refresh.cacheRefresh')}}</h2>
           <el-button type="primary" @click="showRefreshDialog">
-            <el-icon><Plus /></el-icon>提交刷新
+            <el-icon><Plus /></el-icon>{{$t('refresh.submitRefresh')}}
           </el-button>
         </div>
       </template>
@@ -14,14 +14,14 @@
       <!-- 刷新说明 -->
       <div class="description-box">
         <el-alert
-          title="刷新说明"
+          :title="$t('refresh.refreshDescription')"
           type="info"
           :closable="false"
           show-icon
         >
-          <p>通过刷新缓存,能够强制将边缘节点上已缓存的文件清除掉,再次访问时会从源站服务器中重新获取这些文件的最新版本。</p>
-          <p class="warning">注意:该操作会将已缓存文件从边缘节点删除掉,请确认后再进行操作,避免误操作。</p>
-          <p>提交刷新后,通常节点会在30秒至10分钟不等完成刷新缓存。</p>
+          <p>{{$t('refresh.cacheRefreshDescription')}}</p>
+          <p class="warning">{{$t('refresh.cacheRefreshWarning')}}</p>
+          <p>{{$t('refresh.cacheRefreshTime')}}</p>
         </el-alert>
       </div>
 
@@ -31,16 +31,16 @@
         v-loading="refreshLoading"
         style="margin-top: 20px;"
       >
-        <el-table-column prop="submitTime" label="提交时间" width="180" />
-        <el-table-column prop="content" label="刷新内容" min-width="300" show-overflow-tooltip />
-        <el-table-column label="操作" width="120" fixed="right">
+        <el-table-column prop="submitTime" :label="$t('refresh.submitTime')" width="180" />
+        <el-table-column prop="content" :label="$t('refresh.refreshContent')" min-width="300" show-overflow-tooltip />
+        <el-table-column :label="$t('refresh.operation')" width="120" fixed="right">
           <template #default="{ row }">
             <el-button 
               link 
               type="primary" 
               @click="resubmitRefresh(row)"
             >
-              重新提交
+              {{$t('refresh.resubmit')}}
             </el-button>
           </template>
         </el-table-column>
@@ -64,9 +64,9 @@
     <el-card class="section-card preheat-section">
       <template #header>
         <div class="section-header">
-          <h2>文件预热</h2>
+          <h2>{{$t('refresh.filePreheat')}}</h2>
           <el-button type="success" @click="showPreheatDialog">
-            <el-icon><Plus /></el-icon>提交预热
+            <el-icon><Plus /></el-icon>{{$t('refresh.submitPreheat')}}
           </el-button>
         </div>
       </template>
@@ -74,14 +74,14 @@
       <!-- 预热说明 -->
       <div class="description-box">
         <el-alert
-          title="预热说明"
+          :title="$t('refresh.preheatDescription')"
           type="info"
           :closable="false"
           show-icon
         >
-          <p>通过文件预热,能够提前将文件缓存在边缘节点上,当用户发起访问时,边缘节点能够更快速的将内容交付给用户。</p>
-          <p>文件预热还有助于缓解源站压力,避免大量用户访问新资源时,源站负载过高。</p>
-          <p>预热所需时间与文件数量和大小相关,可能在数分钟到数小时不等(参考时长:每小时可预热约3000-5000个文件)。</p>
+          <p>{{$t('refresh.filePreheatDescription')}}</p>
+          <p>{{$t('refresh.filePreheatHelp')}}</p>
+          <p>{{$t('refresh.filePreheatTime')}}</p>
         </el-alert>
       </div>
 
@@ -91,17 +91,17 @@
         v-loading="preheatLoading"
         style="margin-top: 20px;"
       >
-        <el-table-column prop="description" label="任务描述" min-width="200" show-overflow-tooltip />
-        <el-table-column prop="submitTime" label="提交时间" width="180" />
-        <el-table-column prop="completeTime" label="完成时间" width="180" />
-        <el-table-column prop="status" label="状态" width="120">
+        <el-table-column prop="description" :label="$t('refresh.taskDescription')" min-width="200" show-overflow-tooltip />
+        <el-table-column prop="submitTime" :label="$t('refresh.submitTime')" width="180" />
+        <el-table-column prop="completeTime" :label="$t('refresh.completeTime')" width="180" />
+        <el-table-column prop="status" :label="$t('refresh.status')" width="120">
           <template #default="{ row }">
             <el-tag :type="getStatusType(row.status)">
               {{ getStatusText(row.status) }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="progress" label="进度" width="180">
+        <el-table-column prop="progress" :label="$t('refresh.progress')" width="180">
           <template #default="{ row }">
             <el-progress 
               :percentage="row.progress" 
@@ -109,14 +109,14 @@
             />
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="120" fixed="right">
+        <el-table-column :label="$t('refresh.operation')" width="120" fixed="right">
           <template #default="{ row }">
             <el-button 
               link 
               type="primary" 
               disabled
             >
-              停止
+              {{$t('refresh.stop')}}
             </el-button>
           </template>
         </el-table-column>
@@ -139,29 +139,29 @@
     <!-- 提交刷新对话框 -->
     <el-dialog
       v-model="refreshDialogVisible"
-      title="提交刷新任务"
+      :title="$t('refresh.submitRefreshTask')"
       width="600px"
     >
       <el-form :model="refreshForm" ref="refreshFormRef" :rules="formRules">
-        <el-form-item label="URL地址" prop="urls">
+        <el-form-item :label="$t('refresh.urlAddress')" prop="urls">
           <el-input
             v-model="refreshForm.urls"
             type="textarea"
             :rows="6"
-            placeholder="请输入需要刷新的URL地址,多个地址请换行分隔"
+            :placeholder="$t('refresh.pleaseEnterTheURLAddressToBeRefreshed')"
           />
         </el-form-item>
-        <el-form-item label="刷新类型">
+        <el-form-item :label="$t('refresh.refreshType')">
           <el-radio-group v-model="refreshForm.type">
-            <el-radio label="file">文件</el-radio>
-            <el-radio label="directory">目录</el-radio>
+            <el-radio label="file">{{$t('refresh.file')}}</el-radio>
+            <el-radio label="directory">{{$t('refresh.directory')}}</el-radio>
           </el-radio-group>
         </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button @click="refreshDialogVisible = false">取消</el-button>
-          <el-button type="primary" @click="submitRefresh">确认</el-button>
+          <el-button @click="refreshDialogVisible = false">{{$t('refresh.cancel')}}</el-button>
+          <el-button type="primary" @click="submitRefresh">{{$t('refresh.confirm')}}</el-button>
         </div>
       </template>
     </el-dialog>
@@ -169,23 +169,23 @@
     <!-- 提交预热对话框 -->
     <el-dialog
       v-model="preheatDialogVisible"
-      title="提交预热任务"
+      :title="$t('refresh.submitPreheatTask')"
       width="600px"
     >
       <el-form :model="preheatForm" ref="preheatFormRef" :rules="formRules">
-        <el-form-item label="URL地址" prop="urls">
+        <el-form-item :label="$t('refresh.urlAddress')" prop="urls">
           <el-input
             v-model="preheatForm.urls"
             type="textarea"
             :rows="6"
-            placeholder="请输入需要预热的URL地址,多个地址请换行分隔"
+            :placeholder="$t('refresh.pleaseEnterTheURLAddressToBePreheated')"
           />
         </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button @click="preheatDialogVisible = false">取消</el-button>
-          <el-button type="primary" @click="submitPreheat">确认</el-button>
+          <el-button @click="preheatDialogVisible = false">{{$t('refresh.cancel')}}</el-button>
+          <el-button type="primary" @click="submitPreheat">{{$t('refresh.confirm')}}</el-button>
         </div>
       </template>
     </el-dialog>

+ 23 - 23
src/views/statistics.vue

@@ -6,12 +6,12 @@
 
         <!-- 筛选条件 -->
         <div class="filter-conditions">
-          <div class="condition-title">筛选条件:</div>
+          <div class="condition-title">{{$t('statistics.dataIndicator')}}</div>
           <div class="condition-items">
             <el-select
               v-model="selectedDomain"
               class="condition-item"
-              placeholder="域名"
+              :placeholder="$t('statistics.domain')"
               clearable
               filterable
             >
@@ -26,24 +26,24 @@
             <el-select
               v-model="compareOperator"
               class="condition-item condition-operator"
-              placeholder="等于"
+              :placeholder="$t('dashboard.equal')"
             >
-              <el-option label="等于" value="=" />
-              <el-option label="不等于" value="!=" />
-              <el-option label="大于" value=">" />
-              <el-option label="小于" value="<" />
+              <el-option :label="$t('statistics.equal')" value="=" />
+              <el-option :label="$t('statistics.notEqual')" value="!=" />
+              <el-option :label="$t('statistics.greaterThan')" value=">" />
+              <el-option :label="$t('statistics.lessThan')" value="<" />
             </el-select>
 
             <el-input
               v-model="filterValue"
               class="condition-item"
-              placeholder="可选值"
+              :placeholder="$t('statistics.optionalValue')"
               clearable
             />
 
             <div class="condition-buttons">
-              <el-button type="primary" @click="applyFilter">确定</el-button>
-              <el-button @click="resetFilter">取消</el-button>
+              <el-button type="primary" @click="applyFilter">{{$t('dashboard.confirm')}}</el-button>
+              <el-button @click="resetFilter">{{$t('dashboard.cancel')}}</el-button>
             </div>
           </div>
         </div>
@@ -54,18 +54,18 @@
         <!-- 指标和时间选择 -->
         <div class="filter-header">
           <el-select v-model="selectedMetric" class="metric-selector" @change="handleMetricChange">
-            <el-option label="流量" value="flow" />
-            <el-option label="请求数" value="requests" />
-            <el-option label="峰值带宽" value="bandwidth" />
+            <el-option :label="$t('statistics.traffic')" value="flow" />
+            <el-option :label="$t('statistics.requests')" value="requests" />
+            <el-option :label="$t('statistics.peakBandwidth')" value="bandwidth" />
           </el-select>
           
           <el-date-picker
           style="width: 440px;"
             v-model="dateRange"
             type="datetimerange"
-            range-separator="至"
-            start-placeholder="开始时间"
-            end-placeholder="结束时间"
+            :range-separator="$t('statistics.rangeSeparator')"
+            :start-placeholder="$t('statistics.startTime')"
+            :end-placeholder="$t('statistics.endTime')"
             :shortcuts="dateShortcuts"
             @change="handleDateChange"
           />
@@ -92,7 +92,7 @@
           <div class="chart-header">
             <span>{{ getMetricTitle(selectedMetric) }}趋势</span>
             <el-button-group>
-              <el-button size="small" @click="exportData">导出</el-button>
+              <el-button size="small" @click="exportData">{{$t('statistics.export')}}</el-button>
               <el-button size="small" @click="refreshData">
                 <el-icon><Refresh /></el-icon>
               </el-button>
@@ -105,7 +105,7 @@
       <el-card class="cache-chart">
         <template #header>
           <div class="chart-header">
-            <span>缓存命中率</span>
+            <span>{{$t('statistics.cacheRate')}}</span>
           </div>
         </template>
         <div class="chart-container" ref="cacheChart"></div>
@@ -117,7 +117,7 @@
       <el-card class="region-chart">
         <template #header>
           <div class="chart-header">
-            <span>国家分布</span>
+            <span>{{$t('statistics.countryDistribution')}}</span>
           </div>
         </template>
         <div class="chart-container" ref="regionChart"></div>
@@ -126,7 +126,7 @@
       <el-card class="status-chart">
         <template #header>
           <div class="chart-header">
-            <span>状态码分布</span>
+            <span>{{$t('statistics.statusCodeDistribution')}}</span>
           </div>
         </template>
         <div class="chart-container" ref="statusChart"></div>
@@ -135,12 +135,12 @@
       <el-card class="hostname-chart">
         <template #header>
           <div class="chart-header">
-            <span>主机名分布</span>
+            <span>{{$t('statistics.hostnameDistribution')}}</span>
           </div>
         </template>
         <div class="table-container">
           <el-table :data="hostnameData" stripe>
-            <el-table-column prop="hostname" label="主机名" />
+            <el-table-column prop="hostname" :label="$t('statistics.hostname')" />
             <el-table-column prop="value" :label="getMetricTitle(selectedMetric)" />
           </el-table>
         </div>
@@ -149,7 +149,7 @@
       <el-card class="cache-status-chart">
         <template #header>
           <div class="chart-header">
-            <span>缓存状态</span>
+            <span>{{$t('statistics.cacheStatus')}}</span>
           </div>
         </template>
         <div class="chart-container" ref="cacheStatusChart"></div>