Просмотр исходного кода

refactor(locales, lss): enhance localization and improve input handling

- Added new localization entries for English and Chinese, including terms related to LSS and device management.
- Updated input placeholders and labels in the LSS view to utilize localized strings for better user experience.
- Streamlined the search form and table structures for improved clarity and consistency across the application.
yb 1 неделя назад
Родитель
Сommit
7668051942
3 измененных файлов с 111 добавлено и 97 удалено
  1. 28 7
      src/locales/en.json
  2. 26 5
      src/locales/zh-cn.json
  3. 57 85
      src/views/lss/index.vue

+ 28 - 7
src/locales/en.json

@@ -2,8 +2,12 @@
   "Cloudflare Stream": "Cloudflare Stream",
   "Cloudflare Stream 配置": "Cloudflare Stream Configuration",
   "IP": "IP",
+  "IP / 设备ID / 名称": "IP / Device ID / Name",
   "IP地址": "IP Address",
   "LSS": "LSS",
+  "LSS ID": "LSS ID",
+  "LSS 节点详情": "LSS Node Details",
+  "LSS详情": "LSS Details",
   "Logo URL": "Logo URL",
   "PTZ": "PTZ",
   "RTSP URL模板": "RTSP URL Template",
@@ -12,6 +16,7 @@
   "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放": "RTSP streams need to be converted to HLS/WebRTC via server before playing in browser",
   "RTSP地址": "RTSP URL",
   "RTSP端口": "RTSP Port",
+  "Status": "Status",
   "Stream 测试": "Stream Test",
   "Video ID": "Video ID",
   "ably": "ably",
@@ -23,7 +28,6 @@
   "button.selectedSsers": "Selected Users",
   "button.whether": "Whether",
   "errorCode.0": "Success",
-  "hold": "hold",
   "iframe 模式": "iframe Mode",
   "input.SelectAll": "Select All",
   "login.confirmPassword": "Confirm Password",
@@ -40,7 +44,10 @@
   "两次输入的密码不一致": "The passwords entered twice do not match",
   "个厂家": "Factory",
   "个厂家吗?": "Factory?",
+  "个设备": "Device",
   "事件日志": "Event Log",
+  "五分钟内有返回": "Returned within 5 minutes",
+  "五分钟内没有返回": "Not returned within 5 minutes",
   "仅切换": "Switch Only",
   "仅在前端直接调用 API 时需要(不推荐)": "Only needed when directly calling the API in the frontend (not recommended)",
   "仪表盘": "Dashboard",
@@ -54,8 +61,9 @@
   "停止推流失败": "Stop stream failed",
   "全屏": "Fullscreen",
   "全部": "All",
-  "关键词": "Keyword",
+  "共": "Total",
   "关闭": "Close",
+  "关闭时间": "Closed At",
   "创建时间": "Created At",
   "初始化失败": "Initialization failed",
   "初始化成功": "Initialization successful",
@@ -65,25 +73,29 @@
   "删除成功": "Deleted successfully",
   "刷新数据": "Refresh",
   "协议支持": "Protocol Support",
+  "厂商": "Vendor",
   "厂家代码": "Factory Code",
   "厂家名称": "Factory Name",
   "原密码": "Old Password",
+  "参数配置": "Parameter Configuration",
   "取消": "Cancel",
   "取消选择": "Clear Selection",
   "可用通道数量": "Available Channels",
-  "台机器": "machines",
-  "台机器吗?": "machines?",
+  "台机器": "Machines",
+  "台机器吗?": "Machines?",
   "名称": "Name",
   "吗?": "?",
   "否": "No",
   "启动失败": "Start failed",
   "启动推流失败": "Start stream failed",
+  "启动时间": "Start Time",
   "启用": "Enabled",
   "启用状态": "Status",
   "命令模板": "Command Template",
   "品牌": "Brand",
   "在线": "Online",
   "地址": "Address",
+  "型号": "Model",
   "复制": "Copy",
   "如何获取 Customer Subdomain": "How to get Customer Subdomain",
   "密码": "Password",
@@ -96,9 +108,10 @@
   "序号": "No.",
   "开启": "Start",
   "开始日期": "Start Date",
-  "当前任务": "Current Task",
   "当前状态": "Current Status",
+  "待机": "Standby",
   "心跳": "heartbeat",
+  "心跳状态": "Heartbeat Status",
   "忘记密码?": "Forgot password?",
   "快捷操作": "Quick Actions",
   "快速测试": "Quick Test",
@@ -109,18 +122,20 @@
   "批量删除": "Batch Delete",
   "批量删除失败": "Batch delete failed",
   "技术支持": "Support",
+  "持续返回中,并且频繁": "Continuously returning and frequently",
   "排序": "Sort",
   "排序号": "Sort No.",
+  "推币机列表": "Coin Machine List",
   "推流中": "Streaming",
   "推流任务已停止": "Stream task stopped",
   "推流任务已启动": "Stream task started",
   "推流控制": "Push Stream Control",
   "推流方式": "Push Stream Method",
-  "推流状态": "Push Stream Status",
   "推荐通过后端代理调用,避免暴露 Token": "Recommended to call through the backend proxy to avoid exposing the Token",
   "描述": "Description",
   "提示": "Notice",
   "摄像头ID": "Camera ID",
+  "摄像头列表": "Camera List",
   "摄像头在线率": "Camera Online Rate",
   "摄像头总数": "Total Cameras",
   "摄像头数": "Cameras",
@@ -147,6 +162,8 @@
   "新建标签": "New Tab",
   "是": "Yes",
   "暂停": "Pause",
+  "暂无关联设备": "No associated devices",
+  "暂无推币机数据": "No coin machine data",
   "暂无日志": "No logs",
   "暂无视频流": "No video stream",
   "暂无预置位": "No preset",
@@ -171,6 +188,7 @@
   "测试视频": "Test Video",
   "测试连接": "Test Connection",
   "添加": "Add",
+  "添加时间": "Add Time",
   "清空": "Clear",
   "版本": "Version",
   "状态": "Status",
@@ -196,7 +214,6 @@
   "确定要删除该 Live Stream 吗?": "Are you sure you want to delete the Live Stream?",
   "确定要删除选中的": "Are you sure you want to delete the selected",
   "确认密码": "Confirm Password",
-  "禁用": "Disable",
   "离线": "Offline",
   "稳定性": "Uptime",
   "空闲": "Idle",
@@ -217,16 +234,19 @@
   "至": "to",
   "获取机器列表失败": "Failed to get machine list",
   "获取统计数据失败": "Failed to get statistics",
+  "表现形式为": "Formatted as",
   "观看统计": "Watching Statistics",
   "视频地址": "Video URL",
   "视频播放测试": "Video Playback Test",
   "记住我": "Remember me",
   "设备ID": "Device ID",
   "设备列表": "Device List",
+  "设备控制": "Device Control",
   "请先配置摄像头": "Please configure the camera first",
   "请再次输入新密码": "Please enter the new password again",
   "请联系管理员重置密码": "Please contact the administrator to reset your password",
   "请输入IP地址": "Please enter IP address",
+  "请输入ably信息": "Please enter ably information",
   "请输入厂家代码": "Please enter factory code",
   "请输入厂家名称": "Please enter factory name",
   "请输入原密码": "Please enter the old password",
@@ -242,6 +262,7 @@
   "请选择视频源并点击播放": "Please select video source and click play",
   "跳转失败": "Jump failed",
   "转换服务地址": "Proxy Service URL",
+  "运行参数": "Run Parameters",
   "退出登录": "Logout",
   "选择测试源": "Select Test Source",
   "通道": "Channel",

+ 26 - 5
src/locales/zh-cn.json

@@ -2,8 +2,12 @@
   "Cloudflare Stream": "Cloudflare Stream",
   "Cloudflare Stream 配置": "Cloudflare Stream 配置",
   "IP": "IP",
+  "IP / 设备ID / 名称": "IP / 设备ID / 名称",
   "IP地址": "IP地址",
   "LSS": "LSS",
+  "LSS ID": "LSS ID",
+  "LSS 节点详情": "LSS 节点详情",
+  "LSS详情": "LSS详情",
   "Logo URL": "Logo URL",
   "PTZ": "PTZ",
   "RTSP URL模板": "RTSP URL模板",
@@ -12,6 +16,7 @@
   "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放": "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放",
   "RTSP地址": "RTSP地址",
   "RTSP端口": "RTSP端口",
+  "Status": "Status",
   "Stream 测试": "Stream 测试",
   "Video ID": "Video ID",
   "ably": "ably",
@@ -23,7 +28,6 @@
   "button.selectedSsers": "button.selectedSsers",
   "button.whether": "button.whether",
   "errorCode.0": "errorCode.0",
-  "hold": "hold",
   "iframe 模式": "iframe 模式",
   "input.SelectAll": "input.SelectAll",
   "login.confirmPassword": "login.confirmPassword",
@@ -40,7 +44,10 @@
   "两次输入的密码不一致": "两次输入的密码不一致",
   "个厂家": "个厂家",
   "个厂家吗?": "个厂家吗?",
+  "个设备": "个设备",
   "事件日志": "事件日志",
+  "五分钟内有返回": "五分钟内有返回",
+  "五分钟内没有返回": "五分钟内没有返回",
   "仅切换": "仅切换",
   "仅在前端直接调用 API 时需要(不推荐)": "仅在前端直接调用 API 时需要(不推荐)",
   "仪表盘": "仪表盘",
@@ -54,8 +61,9 @@
   "停止推流失败": "停止推流失败",
   "全屏": "全屏",
   "全部": "全部",
-  "关键词": "关键词",
+  "共": "共",
   "关闭": "关闭",
+  "关闭时间": "关闭时间",
   "创建时间": "创建时间",
   "初始化失败": "初始化失败",
   "初始化成功": "初始化成功",
@@ -65,9 +73,11 @@
   "删除成功": "删除成功",
   "刷新数据": "刷新数据",
   "协议支持": "协议支持",
+  "厂商": "厂商",
   "厂家代码": "厂家代码",
   "厂家名称": "厂家名称",
   "原密码": "原密码",
+  "参数配置": "参数配置",
   "取消": "取消",
   "取消选择": "取消选择",
   "可用通道数量": "可用通道数量",
@@ -78,12 +88,14 @@
   "否": "否",
   "启动失败": "启动失败",
   "启动推流失败": "启动推流失败",
+  "启动时间": "启动时间",
   "启用": "启用",
   "启用状态": "启用状态",
   "命令模板": "命令模板",
   "品牌": "品牌",
   "在线": "在线",
   "地址": "地址",
+  "型号": "型号",
   "复制": "复制",
   "如何获取 Customer Subdomain": "如何获取 Customer Subdomain",
   "密码": "密码",
@@ -96,9 +108,10 @@
   "序号": "序号",
   "开启": "开启",
   "开始日期": "开始日期",
-  "当前任务": "当前任务",
   "当前状态": "当前状态",
+  "待机": "待机",
   "心跳": "心跳",
+  "心跳状态": "心跳状态",
   "忘记密码?": "忘记密码?",
   "快捷操作": "快捷操作",
   "快速测试": "快速测试",
@@ -109,18 +122,20 @@
   "批量删除": "批量删除",
   "批量删除失败": "批量删除失败",
   "技术支持": "技术支持",
+  "持续返回中,并且频繁": "持续返回中,并且频繁",
   "排序": "排序",
   "排序号": "排序号",
+  "推币机列表": "推币机列表",
   "推流中": "推流中",
   "推流任务已停止": "推流任务已停止",
   "推流任务已启动": "推流任务已启动",
   "推流控制": "推流控制",
   "推流方式": "推流方式",
-  "推流状态": "推流状态",
   "推荐通过后端代理调用,避免暴露 Token": "推荐通过后端代理调用,避免暴露 Token",
   "描述": "描述",
   "提示": "提示",
   "摄像头ID": "摄像头ID",
+  "摄像头列表": "摄像头列表",
   "摄像头在线率": "摄像头在线率",
   "摄像头总数": "摄像头总数",
   "摄像头数": "摄像头数",
@@ -147,6 +162,8 @@
   "新建标签": "新建标签",
   "是": "是",
   "暂停": "暂停",
+  "暂无关联设备": "暂无关联设备",
+  "暂无推币机数据": "暂无推币机数据",
   "暂无日志": "暂无日志",
   "暂无视频流": "暂无视频流",
   "暂无预置位": "暂无预置位",
@@ -171,6 +188,7 @@
   "测试视频": "测试视频",
   "测试连接": "测试连接",
   "添加": "添加",
+  "添加时间": "添加时间",
   "清空": "清空",
   "版本": "版本",
   "状态": "状态",
@@ -196,7 +214,6 @@
   "确定要删除该 Live Stream 吗?": "确定要删除该 Live Stream 吗?",
   "确定要删除选中的": "确定要删除选中的",
   "确认密码": "确认密码",
-  "禁用": "禁用",
   "离线": "离线",
   "稳定性": "稳定性",
   "空闲": "空闲",
@@ -217,16 +234,19 @@
   "至": "至",
   "获取机器列表失败": "获取机器列表失败",
   "获取统计数据失败": "获取统计数据失败",
+  "表现形式为": "表现形式为",
   "观看统计": "观看统计",
   "视频地址": "视频地址",
   "视频播放测试": "视频播放测试",
   "记住我": "记住我",
   "设备ID": "设备ID",
   "设备列表": "设备列表",
+  "设备控制": "设备控制",
   "请先配置摄像头": "请先配置摄像头",
   "请再次输入新密码": "请再次输入新密码",
   "请联系管理员重置密码": "请联系管理员重置密码",
   "请输入IP地址": "请输入IP地址",
+  "请输入ably信息": "请输入ably信息",
   "请输入厂家代码": "请输入厂家代码",
   "请输入厂家名称": "请输入厂家名称",
   "请输入原密码": "请输入原密码",
@@ -242,6 +262,7 @@
   "请选择视频源并点击播放": "请选择视频源并点击播放",
   "跳转失败": "跳转失败",
   "转换服务地址": "转换服务地址",
+  "运行参数": "运行参数",
   "退出登录": "退出登录",
   "选择测试源": "选择测试源",
   "通道": "通道",

+ 57 - 85
src/views/lss/index.vue

@@ -6,7 +6,7 @@
         <el-form-item>
           <el-input
             v-model.trim="searchForm.lssId"
-            placeholder="LSS ID"
+            :placeholder="t('LSS ID')"
             clearable
             data-id="search-keyword"
             @keyup.enter="handleSearch"
@@ -15,7 +15,7 @@
         <el-form-item>
           <el-input
             v-model.trim="searchForm.lssName"
-            placeholder="名称"
+            :placeholder="t('名称')"
             clearable
             data-id="search-keyword"
             @keyup.enter="handleSearch"
@@ -23,10 +23,10 @@
         </el-form-item>
         <el-form-item>
           <el-select v-model="searchForm.status" :placeholder="t('心跳')" clearable data-id="search-enabled">
-            <el-option label="全部" value="" />
-            <el-option label="active" :value="1" />
-            <el-option label="hold" :value="2" />
-            <el-option label="dead" :value="3" />
+            <el-option :label="t('全部')" value="" />
+            <el-option :label="t('活跃')" value="active" />
+            <el-option :label="t('待机')" value="hold" />
+            <el-option :label="t('离线')" value="dead" />
           </el-select>
         </el-form-item>
         <el-form-item>
@@ -50,7 +50,7 @@
         height="100%"
         @sort-change="handleSortChange"
       >
-        <el-table-column prop="lssId" label="LSS ID" min-width="120" sortable="custom" show-overflow-tooltip />
+        <el-table-column prop="lssId" :label="t('LSS ID')" min-width="120" sortable="custom" show-overflow-tooltip />
         <el-table-column prop="lssName" :label="t('名称')" min-width="140" sortable="custom" show-overflow-tooltip />
         <el-table-column prop="address" :label="t('地址')" min-width="180" sortable="custom" show-overflow-tooltip />
         <el-table-column prop="ip" :label="t('IP')" min-width="180" sortable="custom" show-overflow-tooltip />
@@ -60,7 +60,7 @@
               row.status === 'active'
                 ? t('活跃')
                 : row.status === 'hold'
-                ? t('hold')
+                ? t('待机')
                 : row.status === 'dead'
                 ? t('离线')
                 : '-'
@@ -81,35 +81,6 @@
             {{ row.ablyClientId }}
           </template>
         </el-table-column>
-        <!-- <el-table-column prop="status" :label="t('状态')" min-width="100" sortable="custom">
-          <template #default="{ row }">
-            <el-tag :type="getStatusTagType(row.status)" size="small">
-              {{ formatStatus(row.status) }}
-            </el-tag>
-          </template>
-        </el-table-column> -->
-        <!-- <el-table-column prop="currentTasks" :label="t('当前任务')" min-width="100" sortable="custom" align="center">
-          <template #default="{ row }">{{ row.currentTasks }} / {{ row.maxTasks }}</template>
-        </el-table-column> -->
-        <!-- <el-table-column prop="enabled" :label="t('启用')" min-width="80" align="center">
-          <template #default="{ row }">
-            <el-switch v-model="row.enabled" :loading="row._switching"
-              @change="(val: boolean) => handleToggleEnabled(row, val)" />
-          </template>
-        </el-table-column> -->
-        <!-- <el-table-column prop="ffmpegVersion" label="FFmpeg" show-overflow-tooltip /> -->
-
-        <!-- <el-table-column label="詳情" align="center">
-          <template #default="{ row }">
-            <el-button type="primary" link :icon="View" @click="handleViewDetail(row)" />
-          </template>
-        </el-table-column>
-
-        <el-table-column label="status" align="center">
-          <template #default="{ row }">
-            {{ row.status === 'ONLINE' ? '在线' : '离线' }}
-          </template>
-        </el-table-column> -->
         <el-table-column :label="t('操作')" align="center" fixed="right">
           <template #default="{ row }">
             <el-button type="primary" link :icon="Edit" @click="handleEdit(row, 'detail')" />
@@ -123,7 +94,7 @@
     </div>
 
     <!-- LSS 详情抽屉 -->
-    <el-drawer v-model="detailDrawerVisible" title="LSS 节点详情" direction="rtl" size="500px" destroy-on-close>
+    <el-drawer v-model="detailDrawerVisible" :title="t('LSS 节点详情')" direction="rtl" size="500px" destroy-on-close>
       <el-descriptions :column="1" border>
         <el-descriptions-item label="LSS ID">{{ currentLss?.lssId }}</el-descriptions-item>
         <el-descriptions-item label="名称">{{ currentLss?.lssName }}</el-descriptions-item>
@@ -161,9 +132,9 @@
       <div class="drawer-content">
         <!-- 顶部 Tabs -->
         <el-tabs v-model="editActiveTab" class="drawer-tabs">
-          <el-tab-pane label="LSS详情" name="detail" />
-          <el-tab-pane label="摄像头列表" name="camera" />
-          <el-tab-pane label="推币机列表" name="pusher" />
+          <el-tab-pane :label="t('LSS详情')" name="detail" />
+          <el-tab-pane :label="t('摄像头列表')" name="camera" />
+          <el-tab-pane :label="t('推币机列表')" name="pusher" />
         </el-tabs>
 
         <div class="drawer-body">
@@ -190,12 +161,12 @@
                 <el-tooltip placement="right" effect="light">
                   <template #content>
                     <div class="heartbeat-tooltip">
-                      <div class="tooltip-title">心跳状态:</div>
-                      <div>active - 持续返回中,并且频繁</div>
-                      <div>hold - 五分钟内有返回</div>
-                      <div>dead - 五分钟内没有返回</div>
-                      <div class="tooltip-format">表现形式为:</div>
-                      <div class="tooltip-example">Status [yy-mm-dd 00:00:00]</div>
+                      <div class="tooltip-title">{{ t('心跳状态') }}:</div>
+                      <div>{{ t('活跃') }} - {{ t('持续返回中,并且频繁') }}</div>
+                      <div>{{ t('待机') }} - {{ t('五分钟内有返回') }}</div>
+                      <div>{{ t('离线') }} - {{ t('五分钟内没有返回') }}</div>
+                      <div class="tooltip-format">{{ t('表现形式为') }}:</div>
+                      <div class="tooltip-example">{{ t('Status') }} [yy-mm-dd 00:00:00]</div>
                     </div>
                   </template>
                   <el-icon class="heartbeat-info-icon">
@@ -210,7 +181,7 @@
                     type="textarea"
                     :rows="8"
                     v-model="lssEditForm.ably"
-                    placeholder="请输入ably信息"
+                    :placeholder="t('请输入ably信息')"
                     maxlength="1000"
                     show-word-limit
                   />
@@ -226,31 +197,30 @@
                 <el-form-item>
                   <el-input
                     v-model.trim="cameraSearchForm.keyword"
-                    placeholder="IP / 设备ID / 名称"
+                    :placeholder="t('IP / 设备ID / 名称')"
                     clearable
                     style="width: 200px"
                     @keyup.enter="handleCameraSearch"
                   />
                 </el-form-item>
                 <el-form-item>
-                  <el-select v-model="cameraSearchForm.status" placeholder="状态" clearable style="width: 120px">
-                    <el-option label="全部" value="" />
-                    <el-option label="在线" value="ONLINE" />
-                    <el-option label="离线" value="OFFLINE" />
+                  <el-select v-model="cameraSearchForm.status" :placeholder="t('状态')" clearable style="width: 120px">
+                    <el-option :label="t('全部')" value="" />
+                    <el-option :label="t('在线')" value="ONLINE" />
+                    <el-option :label="t('离线')" value="OFFLINE" />
                   </el-select>
                 </el-form-item>
                 <el-form-item>
-                  <el-button type="primary" :icon="Search" @click="handleCameraSearch">查询</el-button>
-                  <el-button :icon="RefreshRight" @click="handleCameraReset">重置</el-button>
+                  <el-button type="primary" :icon="Search" @click="handleCameraSearch">{{ t('查询') }}</el-button>
+                  <el-button :icon="RefreshRight" @click="handleCameraReset">{{ t('重置') }}</el-button>
                 </el-form-item>
               </el-form>
               <el-button type="primary" :icon="Plus" @click="handleAddCamera">{{ t('新增') }}</el-button>
             </div>
-            <el-empty v-if="!cameraLoading && cameraList.length === 0" description="暂无关联设备" />
+            <el-empty v-if="!cameraLoading && cameraList.length === 0" :description="t('暂无关联设备')" />
             <el-table v-else :data="cameraList" stripe size="small" border>
-              <!-- <el-table-column prop="ip" label="本地IP" min-width="110" /> -->
-              <el-table-column prop="cameraId" label="设备ID" min-width="100" show-overflow-tooltip />
-              <el-table-column prop="cameraName" label="名称" min-width="100" show-overflow-tooltip />
+              <el-table-column prop="cameraId" :label="t('设备ID')" min-width="100" show-overflow-tooltip />
+              <el-table-column prop="cameraName" :label="t('名称')" min-width="100" show-overflow-tooltip />
               <el-table-column :label="t('状态(心跳)')" min-width="140">
                 <template #default="{ row }">
                   <span :class="['status-text', row.status === 'active' ? 'status-active' : 'status-dead']">
@@ -258,14 +228,14 @@
                   </span>
                 </template>
               </el-table-column>
-              <el-table-column label="参数配置" min-width="80" align="center">
+              <el-table-column :label="t('参数配置')" min-width="80" align="center">
                 <template #default="{ row }">
-                  <el-button type="primary" link @click="handleViewConfig(row)">查看</el-button>
+                  <el-button type="primary" link @click="handleViewConfig(row)">{{ t('查看') }}</el-button>
                 </template>
               </el-table-column>
-              <el-table-column label="运行参数" min-width="80" align="center">
+              <el-table-column :label="t('运行参数')" min-width="80" align="center">
                 <template #default="{ row }">
-                  <el-button type="primary" link @click="handleViewRunParams(row)">查看</el-button>
+                  <el-button type="primary" link @click="handleViewRunParams(row)">{{ t('查看') }}</el-button>
                 </template>
               </el-table-column>
               <el-table-column prop="brand" :label="t('厂商')" min-width="90">
@@ -273,13 +243,13 @@
                   {{ formatBrand(row.vendorName) }}
                 </template>
               </el-table-column>
-              <el-table-column prop="model" label="型号" min-width="130" show-overflow-tooltip />
-              <el-table-column label="添加时间" min-width="140">
+              <el-table-column prop="model" :label="t('型号')" min-width="130" show-overflow-tooltip />
+              <el-table-column :label="t('添加时间')" min-width="140">
                 <template #default="{ row }">
                   {{ formatTime(row.createdAt) }}
                 </template>
               </el-table-column>
-              <el-table-column label="设备控制" min-width="100" align="center" fixed="right">
+              <el-table-column :label="t('设备控制')" min-width="100" align="center" fixed="right">
                 <template #default="{ row }">
                   <el-button type="primary" link :icon="Edit" @click="handleEditCamera(row)" />
                   <el-button type="danger" link :icon="Delete" @click="handleDeleteCamera(row)" />
@@ -289,12 +259,14 @@
                 </template>
               </el-table-column>
             </el-table>
-            <div v-if="cameraList.length > 0" class="camera-count">共 {{ cameraList.length }} 个设备</div>
+            <div v-if="cameraList.length > 0" class="camera-count">
+              {{ t('共') }} {{ cameraList.length }} {{ t('个设备') }}
+            </div>
           </div>
 
           <!-- 推币机列表 Tab -->
           <div v-show="editActiveTab === 'pusher'" class="tab-content">
-            <el-empty description="暂无推币机数据" />
+            <el-empty :description="t('暂无推币机数据')" />
           </div>
         </div>
 
@@ -308,45 +280,45 @@
     <!-- 设备列表抽屉 -->
     <el-drawer
       v-model="cameraDrawerVisible"
-      :title="`设备列表 - ${currentLss?.lssName || ''}`"
+      :title="`${t('设备列表')} - ${currentLss?.lssName || ''}`"
       direction="rtl"
       size="80%"
       destroy-on-close
       class="device-drawer"
     >
       <el-tabs v-model="deviceActiveTab" class="device-tabs">
-        <el-tab-pane label="摄像头列表" name="camera">
+        <el-tab-pane :label="t('摄像头列表')" name="camera">
           <div v-loading="cameraLoading" class="tab-content-wrapper">
             <div class="camera-toolbar">
               <el-form :model="cameraSearchForm" inline>
                 <el-form-item>
                   <el-input
                     v-model.trim="cameraSearchForm.keyword"
-                    placeholder="IP / 设备ID / 名称"
+                    :placeholder="t('IP / 设备ID / 名称')"
                     clearable
                     style="width: 200px"
                     @keyup.enter="handleCameraSearch"
                   />
                 </el-form-item>
                 <el-form-item>
-                  <el-select v-model="cameraSearchForm.status" placeholder="状态" clearable style="width: 120px">
-                    <el-option label="全部" value="" />
-                    <el-option label="在线" value="ONLINE" />
-                    <el-option label="离线" value="OFFLINE" />
+                  <el-select v-model="cameraSearchForm.status" :placeholder="t('状态')" clearable style="width: 120px">
+                    <el-option :label="t('全部')" value="" />
+                    <el-option :label="t('在线')" value="ONLINE" />
+                    <el-option :label="t('离线')" value="OFFLINE" />
                   </el-select>
                 </el-form-item>
                 <el-form-item>
-                  <el-button type="primary" :icon="Search" @click="handleCameraSearch">查询</el-button>
-                  <el-button :icon="RefreshRight" @click="handleCameraReset">重置</el-button>
+                  <el-button type="primary" :icon="Search" @click="handleCameraSearch">{{ t('查询') }}</el-button>
+                  <el-button :icon="RefreshRight" @click="handleCameraReset">{{ t('重置') }}</el-button>
                 </el-form-item>
               </el-form>
               <el-button type="primary" :icon="Plus" @click="handleAddCamera">{{ t('新增') }}</el-button>
             </div>
-            <el-empty v-if="!cameraLoading && cameraList.length === 0" description="暂无关联设备" />
+            <el-empty v-if="!cameraLoading && cameraList.length === 0" :description="t('暂无关联设备')" />
             <el-table v-else :data="cameraList" stripe size="small" border>
               <!-- <el-table-column prop="ip" label="本地IP" min-width="110" /> -->
-              <el-table-column prop="cameraId" label="设备ID" min-width="100" show-overflow-tooltip />
-              <el-table-column prop="cameraName" label="名称" min-width="100" show-overflow-tooltip />
+              <el-table-column prop="cameraId" :label="t('设备ID')" min-width="100" show-overflow-tooltip />
+              <el-table-column prop="cameraName" :label="t('名称')" min-width="100" show-overflow-tooltip />
               <el-table-column :label="t('状态(心跳)')" min-width="140">
                 <template #default="{ row }">
                   <span :class="['status-text', row.status === 'active' ? 'status-active' : 'status-dead']">
@@ -354,12 +326,12 @@
                   </span>
                 </template>
               </el-table-column>
-              <el-table-column label="参数配置" min-width="80" align="center">
+              <el-table-column :label="t('参数配置')" min-width="80" align="center">
                 <template #default="{ row }">
                   <el-button type="primary" link @click="handleViewConfig(row)">查看</el-button>
                 </template>
               </el-table-column>
-              <el-table-column label="运行参数" min-width="80" align="center">
+              <el-table-column :label="t('运行参数')" min-width="80" align="center">
                 <template #default="{ row }">
                   <el-button type="primary" link @click="handleViewRunParams(row)">查看</el-button>
                 </template>
@@ -369,13 +341,13 @@
                   {{ formatBrand(row.brand) }}
                 </template>
               </el-table-column>
-              <el-table-column prop="model" label="型号" min-width="130" show-overflow-tooltip />
-              <el-table-column label="添加时间" min-width="140">
+              <el-table-column prop="model" :label="t('型号')" min-width="130" show-overflow-tooltip />
+              <el-table-column :label="t('添加时间')" min-width="140">
                 <template #default="{ row }">
                   {{ formatTime(row.createdAt) }}
                 </template>
               </el-table-column>
-              <el-table-column label="设备控制" min-width="100" align="center" fixed="right">
+              <el-table-column :label="t('设备控制')" min-width="100" align="center" fixed="right">
                 <template #default="{ row }">
                   <el-button type="primary" link :icon="Edit" @click="handleEditCamera(row)" />
                   <el-button type="danger" link :icon="Delete" @click="handleDeleteCamera(row)" />