liujintao 2 недель назад
Родитель
Сommit
c5482a733b

+ 2 - 3
.env

@@ -1,3 +1,2 @@
-## 项目标题
-VITE_APP_TITLE='Camera Management
-'
+# 项目标题
+VITE_APP_TITLE='Camera Management'

+ 0 - 1
.env.development

@@ -5,7 +5,6 @@ VITE_PUBLIC_PATH='/'
 ## 路由模式 hash 或 html5
 VITE_ROUTER_HISTORY='html5'
 
-
 VITE_HOST_IP = '192.168.32.103'
 
 VITE_VIDEO_PORT = '8000'

+ 10 - 0
package-lock.json

@@ -14,6 +14,7 @@
         "js-cookie": "^3.0.5",
         "nprogress": "^0.2.0",
         "pinia": "^2.1.7",
+        "qrcode.vue": "^3.6.0",
         "vue": "^3.3.11",
         "vue-router": "^4.2.5"
       },
@@ -2302,6 +2303,15 @@
       "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
       "license": "MIT"
     },
+    "node_modules/qrcode.vue": {
+      "version": "3.6.0",
+      "resolved": "https://mirrors.huaweicloud.com/repository/npm/qrcode.vue/-/qrcode.vue-3.6.0.tgz",
+      "integrity": "sha512-vQcl2fyHYHMjDO1GguCldJxepq2izQjBkDEEu9NENgfVKP6mv/e2SU62WbqYHGwTgWXLhxZ1NCD1dAZKHQq1fg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "vue": "^3.0.0"
+      }
+    },
     "node_modules/quansync": {
       "version": "0.2.11",
       "resolved": "https://mirrors.huaweicloud.com/repository/npm/quansync/-/quansync-0.2.11.tgz",

+ 2 - 1
package.json

@@ -16,13 +16,14 @@
     "js-cookie": "^3.0.5",
     "nprogress": "^0.2.0",
     "pinia": "^2.1.7",
+    "qrcode.vue": "^3.6.0",
     "vue": "^3.3.11",
     "vue-router": "^4.2.5"
   },
   "devDependencies": {
-    "@vitejs/plugin-vue": "^4.5.2",
     "@types/js-cookie": "^3.0.6",
     "@types/nprogress": "^0.2.3",
+    "@vitejs/plugin-vue": "^4.5.2",
     "@vue/tsconfig": "^0.5.0",
     "sass": "^1.97.0",
     "typescript": "~5.3.0",

+ 9 - 0
src/api/setting.ts

@@ -111,3 +111,12 @@ export function getCameraDeviceInfo() {
 //   })
 // }
 
+
+export function cameraResetPassword(data: any) {
+  return request({
+    url: `/API/V1.0/Device/ResetPassword`,
+    method: 'put',
+    data
+  })
+}
+

+ 1 - 1
src/assets/base.css

@@ -8,7 +8,7 @@
   /** NavigationBar 组件 */
   --v3-navigationbar-height: 50px;
   /** Sidebar 组件(左侧模式全部生效、顶部模式全部不生效、混合模式非颜色部分生效) */
-  --v3-sidebar-width: 150px;
+  --v3-sidebar-width: 168px;
   --v3-sidebar-hide-width: 58px;
   --v3-sidebar-menu-item-height: 60px;
   --v3-sidebar-menu-tip-line-bg-color: var(--el-color-primary);

+ 1 - 4
src/constants/cache-key.ts

@@ -3,10 +3,7 @@ const SYSTEM_NAME = "v3-admin-vite"
 /** 缓存数据时用到的 Key */
 class CacheKey {
   static readonly TOKEN = `${SYSTEM_NAME}-token-key`
-  static readonly PROJECT = `${SYSTEM_NAME}-project`
-  static readonly SUPPORT_MUL = `${SYSTEM_NAME}-supportMul`
-  static readonly START_STATUS = `${SYSTEM_NAME}-start-status`
-  static readonly PROJECT_BALL = `${SYSTEM_NAME}-project-ball`
+  static readonly USERNAME = `${SYSTEM_NAME}-username-key`
   static readonly CONFIG_LAYOUT = `${SYSTEM_NAME}-config-layout-key`
   static readonly SIDEBAR_STATUS = `${SYSTEM_NAME}-sidebar-status-key`
   static readonly ACTIVE_THEME_NAME = `${SYSTEM_NAME}-active-theme-name-key`

+ 27 - 1
src/layouts/components/NavigationBar/index.vue

@@ -3,11 +3,15 @@ import { useRouter } from 'vue-router'
 import { useUserStore } from '@/stores/modules/user'
 import { useAppStore } from '@/stores/modules/app'
 import Hamburger from '../Hamburger/index.vue'
+import { getUsername } from '@/utils/cache/cookies'
 
 const router = useRouter()
 const appStore = useAppStore()
 const userStore = useUserStore()
 
+const username = ref('')
+username.value = getUsername()
+
 /** 切换侧边栏 */
 const toggleSidebar = () => {
   appStore.toggleSidebar(false)
@@ -28,7 +32,11 @@ const logout = () => {
       @toggle-click="toggleSidebar"
     />
     <div class="logout-btn">
-      <el-button @click="logout">退出登录</el-button>
+      <div class="user-info">
+        <el-icon><User /></el-icon>
+        <span class="username">{{ username }}</span>
+      </div>
+      <el-button @click="logout">Logout</el-button>
     </div>
   </div>
 </template>
@@ -50,9 +58,27 @@ const logout = () => {
   .logout-btn {
     display: flex;
     align-items: center;
+    gap: 20px;
     justify-content: right;
     margin-inline-start: auto;
     margin-right: 10px;
   }
 }
+.user-info {
+  display: inline-flex;
+  align-items: center;
+  padding: 0 16px;
+  gap: 8px;
+  font-size: 14px;
+  color: var(--el-text-color-regular);
+
+  .username {
+    font-weight: 500;
+  }
+
+  .el-icon {
+    font-size: 16px;
+    color: var(--el-text-color-secondary);
+  }
+}
 </style>

+ 5 - 3
src/layouts/components/SideBar/index.vue

@@ -62,13 +62,15 @@ $transition-time: 0.35s;
       background-color: #002140;
       color: #fff;
       font-weight: 700;
-      line-height: 22px;
+      line-height: 45px;
       font-size: 15px;
       display: flex;
       align-items: center;
-      flex-direction: column;
+      justify-content: center;
+      //flex-direction: column;
       text-align: center;
-      white-space: pre-line;
+
+      //white-space: pre-line;
     }
     .sidebar-none {
       color: #fff;

+ 1 - 1
src/layouts/index.vue

@@ -35,7 +35,7 @@ const layoutClasses = computed(() => {
 
 // 在组件挂载时添加事件监听
 onMounted(() => {
-  //每次组件挂载时就调同步事件接口
+  // 每次组件挂载时就调同步事件接口
   // const timeParaData: TimeParaData = {
   //   time: format(new Date(), 'yyyy-MM-dd-HH-mm-ss')
   // }

+ 4 - 4
src/router/index.ts

@@ -18,7 +18,7 @@ export const constantRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/preview/index.vue'),
         name: 'Preview',
         meta: {
-          title: '预览',
+          title: 'Preview',
           isShow: true,
           icon: 'View'
         }
@@ -31,7 +31,7 @@ export const constantRoutes: RouteRecordRaw[] = [
     component: Layouts,
     redirect: '/setting',
     meta: {
-      title: '设置',
+      title: 'Settings',
       isShow: true,
       icon: 'Setting'
     },
@@ -41,7 +41,7 @@ export const constantRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/setting/systemSetting/index.vue'),
         name: 'SystemSetting',
         meta: {
-          title: '相机设置'
+          title: 'Camera Settings'
         }
       },
       {
@@ -49,7 +49,7 @@ export const constantRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/setting/netSetting/index.vue'),
         name: 'NetSetting',
         meta: {
-          title: '网络设置'
+          title: 'Network Settings'
         }
       }
     ]

+ 3 - 3
src/stores/modules/user.ts

@@ -1,10 +1,9 @@
 import { ref } from 'vue'
 import store from '@/stores'
 import { defineStore } from 'pinia'
-import { getToken, removeToken } from '@/utils/cache/cookies'
+import { getToken, removeToken, removeUsername, setUsername } from '@/utils/cache/cookies'
 import { loginApi } from '@/api/login'
 import { type LoginRequestData } from '@/api/types/login'
-import { removeProjectFromLocal } from '@/utils/cache/cookies'
 
 export const useUserStore = defineStore('user', () => {
   const token = ref<string>(getToken() || '')
@@ -17,13 +16,14 @@ export const useUserStore = defineStore('user', () => {
     const { data } = await loginApi({ name, password })
     username.value = name
     token.value = unToken
+    setUsername(username.value)
     return data
   }
 
   /** 登出 */
   const logout = () => {
     removeToken()
-    removeProjectFromLocal()
+    removeUsername(username.value)
     token.value = ''
   }
   /** 重置 Token */

+ 6 - 15
src/utils/cache/cookies.ts

@@ -13,21 +13,12 @@ export const removeToken = () => {
   Cookies.remove(CacheKey.TOKEN)
 }
 
-export const getProjectFromLocal = () => {
-  return Cookies.get(CacheKey.PROJECT)
+export const setUsername = (username: string) => {
+  Cookies.set(CacheKey.USERNAME, username)
 }
-export const setProjectFromLocal = (val: string) => {
-  Cookies.set(CacheKey.PROJECT, val)
+export const getUsername = () => {
+  return Cookies.get(CacheKey.USERNAME)
 }
-
-export const removeProjectFromLocal = () => {
-  Cookies.remove(CacheKey.PROJECT)
-}
-
-export const setSupportMul = (val: string) => {
-  Cookies.set(CacheKey.SUPPORT_MUL, val)
-}
-//获得是否开始测试状态
-export const getStartStatus = () => {
-  return Cookies.get(CacheKey.START_STATUS)
+export const removeUsername = () => {
+  Cookies.remove(CacheKey.USERNAME)
 }

+ 327 - 24
src/views/login/index.vue

@@ -3,7 +3,7 @@
     <div class="login-card">
       <div class="content">
         <div class="title">
-          <h2>欢迎使用摄像机管理系统</h2>
+          <h3>Welcome to Camera Management System</h3>
         </div>
         <el-form
           ref="loginFormRef"
@@ -14,7 +14,7 @@
           <el-form-item prop="username">
             <el-input
               v-model.trim="loginFormData.name"
-              placeholder="账号"
+              placeholder="Account"
               :prefix-icon="User"
               size="large"
               tabindex="1"
@@ -24,7 +24,7 @@
           <el-form-item prop="password" class="password-form-item">
             <el-input
               v-model.trim="loginFormData.password"
-              placeholder="密码"
+              placeholder="Password"
               :prefix-icon="Lock"
               show-password
               size="large"
@@ -32,7 +32,7 @@
               type="password"
             />
             <div class="forget-password">
-              <el-link type="primary" @click="dialogVisible = true">忘记密码</el-link>
+              <el-link type="primary" @click="dialogVisible = true">Forgot Password</el-link>
             </div>
           </el-form-item>
           <el-button
@@ -42,10 +42,10 @@
             class="login-btn"
             @click.prevent="handleLogin"
           >
-            登 录
+            Login
           </el-button>
           <div class="login-tip">
-            <span>初始密码请参阅说明书</span>
+            <span>For initial password, please refer to the manual or contact the administrator.</span>
           </div>
         </el-form>
       </div>
@@ -53,14 +53,43 @@
     <!-- 忘记密码对话框 -->
     <el-dialog
       v-model="dialogVisible"
-      title="忘记密码"
-      width="500"
+      title="Note"
+      width="800px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      @close="handleDialogClose"
     >
-      <span>请联系客服或管理员获取超级密码后在登录!</span>
+      <div class="forgot-password-dialog">
+        <div class="device-password-title">Device Password</div>
+        <div class="qrcode-container">
+          <qrcode-vue
+            :value="devicePassword"
+            :size="160"
+            :errorCorrectionLevel="level"
+          />
+          <span class="password-text">{{devicePassword}}</span>
+        </div>
+        <div class="reset-methods">
+          <div class="methods-title">How to Reset Password:</div>
+          <div class="method-item">
+            <strong>Method 1:</strong> Open PC software spd.exe, enter the obtained device password into the UID input box, click make, and generate a 12-digit super password.
+          </div>
+          <div class="method-item">
+            <strong>Method 2:</strong> Open mobile APP SPD, click "Enable QR code scanning", scan the QR code above to generate a 12-digit super password, or click the "Manual input" button, enter the device password, click confirm, and generate a super password.
+          </div>
+        </div>
+        <div class="password-input-container">
+          <el-input
+            v-model="superPassword"
+            placeholder="Enter Super Password"
+            size="default"
+          />
+        </div>
+      </div>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="dialogVisible = false">
-            确认
+          <el-button  style="width: 250px" type="primary" @click="handleResetPassword">
+            Reset to Default Password
           </el-button>
         </div>
       </template>
@@ -77,21 +106,27 @@ import { User, Lock } from '@element-plus/icons-vue'
 import { type LoginRequestData } from '@/api/types/login'
 import { setToken } from '@/utils/cache/cookies'
 import { setRouter } from '@/router'
+import type { TimeParaData } from '@/api/types/setting'
+import { format } from 'date-fns'
+import { getCameraDeviceInfo, PutTimePara } from '@/api/setting'
+import QrcodeVue from 'qrcode.vue'
+import { cameraResetPassword } from '@/api/setting'
+
 
 const router = useRouter()
-/** 登录表单元素的引用 */
 const loginFormRef = ref<FormInstance | null>(null)
-/** 登录按钮 Loading */
 const loading = ref(false)
-/** 忘记密码对话框是否可见 */
 const dialogVisible = ref(false)
-/** 登录表单数据 */
 const loginFormData: LoginRequestData = reactive({
   name: '',
   password: '',
   code: ''
 })
-/** 登录表单校验规则 */
+
+const devicePassword = ref('DEVICE_123456')
+const superPassword = ref('')
+const level = ref('H')
+
 const loginFormRules: FormRules = {
   name: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
   password: [
@@ -100,7 +135,33 @@ const loginFormRules: FormRules = {
   ]
 }
 
-/** 登录逻辑 */
+const handleDialogClose = () => {
+  dialogVisible.value = false
+}
+
+
+async function getDeviceInfo(){
+  const res = await getCameraDeviceInfo()
+  devicePassword.value = res.data.MacAddr.replace(/:/g, '')
+}
+
+onMounted(() => {
+  getDeviceInfo()
+})
+
+function handleResetPassword() {
+  cameraResetPassword({
+    ResetPassword: superPassword.value
+  }).then((res: string) => {
+    if (res.data === 'ok\n') {
+      ElMessage.success('Reset Password Successful')
+      handleDialogClose()
+    } else {
+      ElMessage.error('Reset Password Failed!')
+    }
+  })
+}
+
 const handleLogin = () => {
   loginFormRef.value?.validate((valid: boolean, fields) => {
     if (valid) {
@@ -109,18 +170,22 @@ const handleLogin = () => {
         .login(loginFormData)
         .then((res: string) => {
           if (res == 'ok\n') {
-            ElMessage.success('登录成功')
+            ElMessage.success('Login Successful')
             const token = useUserStore().token
             setToken(token)
             setRouter()
             router.push({ path: '/' })
+            const timeParaData: TimeParaData = {
+              time: format(new Date(), 'yyyy-MM-dd-HH-mm-ss')
+            }
+            PutTimePara(timeParaData)
           } else {
-            ElMessage.error('用户名或密码错误')
+            ElMessage.error('Incorrect username or password')
           }
         })
         .catch(() => {
           loginFormData.password = ''
-          ElMessage.error('登录失败')
+          ElMessage.error('Login Failed')
         })
         .finally(() => {
           loading.value = false
@@ -137,8 +202,9 @@ const handleLogin = () => {
   display: flex;
   justify-content: center;
   align-items: center;
-  height: 100%;
-  width: 100%;
+  height: 100vh;
+  width: 100vw;
+  background-color: #f5f7fa;
 
   .title {
     text-align: center;
@@ -189,7 +255,7 @@ const handleLogin = () => {
           justify-content: flex-end;
 
           :deep(.el-link) {
-            font-size: 13px;
+            font-size: 11px;
 
             &:hover {
               text-decoration: underline;
@@ -203,6 +269,7 @@ const handleLogin = () => {
         margin-top: 32px;
         font-weight: 500;
         letter-spacing: 1px;
+        transition: all 0.3s ease;
 
         &:hover {
           transform: translateY(-2px);
@@ -212,11 +279,247 @@ const handleLogin = () => {
 
       .login-tip {
         text-align: center;
-        font-size: 13px;
+        font-size: 11px;
         margin-top: 16px;
         color: #999;
       }
     }
   }
 }
+
+/* 忘记密码对话框样式 */
+.forgot-password-dialog {
+  padding: 0;
+  box-sizing: border-box;
+
+  .device-password-title {
+    font-size: 14px;
+    color: #666;
+    margin-bottom: 16px;
+    text-align: center;
+    font-weight: 500;
+  }
+
+  .qrcode-container {
+    display: flex;
+    flex-direction: column;  /* 改为纵向排列 */
+    align-items: center;     /* 居中对齐 */
+    justify-content: center;
+    margin-bottom: 28px;
+    padding: 0 20px;
+    gap: 10px;
+
+    .password-text {
+      font-size: 14px;
+      color: #333;
+      font-weight: 500;
+      word-break: break-all;  // 防止长密码换行问题
+      text-align: center;
+      max-width: 160px;  // 与二维码同宽
+    }
+  }
+
+  .reset-methods {
+    margin-bottom: 28px;
+    padding: 0 20px;
+    text-align: left;
+
+    .methods-title {
+      font-size: 13px;
+      margin-bottom: 12px;
+      font-weight: 500;
+      color: #333;
+      text-align: left;
+    }
+
+    .method-item {
+      font-size: 12px;
+      line-height: 1.8;
+      margin-bottom: 10px;
+      color: #666;
+      text-indent: 0;
+
+      strong {
+        color: #333;
+        font-weight: 600;
+      }
+    }
+  }
+
+  .password-input-container {
+    margin-bottom: 20px;
+    display: flex;
+    justify-content: center;
+    padding: 0 20px;
+
+    :deep(.el-input) {
+      width: 100%;
+      max-width: 340px;
+
+      :deep(.el-input__wrapper) {
+        box-shadow: none;
+        border: 1px solid #e5e7eb;
+        border-radius: 6px;
+        padding: 0 12px;
+        height: 40px;
+        background-color: #fafbfc;
+        transition: all 0.3s ease;
+
+        &:hover {
+          border-color: #d9d9d9;
+          background-color: #fff;
+        }
+
+        :deep(.el-input__inner) {
+          border: none;
+          padding: 0;
+          height: 40px;
+          font-size: 13px;
+          background-color: transparent;
+          color: #333;
+
+          &::placeholder {
+            color: #b3b3b3;
+          }
+        }
+      }
+
+      :deep(.el-input__inner:focus) {
+        color: #333;
+      }
+    }
+  }
+}
+
+/* 对话框整体样式优化 */
+:deep(.el-dialog) {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.12);
+
+  .el-dialog__wrapper {
+    backdrop-filter: blur(2px);
+  }
+}
+
+/* 对话框标题样式 */
+:deep(.el-dialog__header) {
+  padding: 16px 15px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  margin: 0;
+  border-bottom: none;
+  margin-left: -20px;
+  margin-right: -20px;
+  margin-top: -20px;
+  width: calc(100% + 40px);
+  position: relative;
+  left: -20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  overflow: visible;
+
+  .el-dialog__title {
+    color: white;
+    font-size: 18px;
+    font-weight: 600;
+    flex: 1;
+    margin: 0 30px;
+    min-width: 0;
+  }
+
+  .el-dialog__headerbtn {
+    position: static;
+    top: auto;
+    right: auto;
+    transform: none;
+    flex-shrink: 0;
+    margin-left: 10px;  // ← 就是这一行
+
+    //margin-left: 10px;
+
+    .el-dialog__close {
+      color: white;
+      font-size: 25px;
+      transition: all 0.3s ease;
+      cursor: pointer;
+      width: 32px;
+      height: 32px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+
+      &:hover {
+        opacity: 0.8;
+        transform: rotate(90deg);
+      }
+    }
+  }
+}
+
+/* 对话框关闭按钮 - 关键修复 */
+:deep(.el-dialog__close) {
+  color: white;
+  font-size: 25px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  position: relative;
+  width: auto;
+  height: auto;
+  padding: 0px;
+  border: none;
+  background: none;
+  outline: none;
+
+  &:hover {
+    opacity: 0.8;
+    transform: rotate(90deg);
+  }
+
+  &:focus {
+    outline: none;
+  }
+}
+
+:deep(.el-dialog__body) {
+  padding: 24px 0 0;
+  background-color: #fff;
+}
+
+/* 对话框页脚样式 */
+:deep(.el-dialog__footer) {
+  padding: 20px;
+  background-color: #fff;
+  text-align: center;
+  border-top: 1px solid #f0f0f0;
+}
+
+/* 重置密码按钮样式 */
+:deep(.dialog-footer) {
+  display: flex;
+  justify-content: center;
+  padding: 0;
+
+  .el-button {
+    width: 140px;
+    height: 40px;
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    border: none;
+    color: white;
+    font-size: 14px;
+    font-weight: 500;
+    border-radius: 6px;
+    transition: all 0.3s ease;
+    cursor: pointer;
+
+    &:hover {
+      transform: translateY(-2px);
+      box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3);
+    }
+
+    &:active {
+      transform: translateY(0);
+    }
+  }
+}
 </style>

+ 17 - 19
src/views/setting/netSetting/index.vue

@@ -1,17 +1,16 @@
-
 <template>
   <div class="setting-container">
     <div class="setting-card">
       <div class="card-header">
-        <h2 class="title">网络设置</h2>
-        <p class="subtitle">配置设备的网络连接参数</p>
+        <h2 class="title">Network Settings</h2>
+        <p class="subtitle">Configure device network connection parameters</p>
       </div>
       <div class="content">
         <el-form
           ref="settingFormRef"
           :hide-required-asterisk="true"
           label-position="left"
-          label-width="100px"
+          label-width="125px"
           :model="settingFormData"
           :rules="settingFormRules"
           @keyup.enter="handleSave"
@@ -19,7 +18,7 @@
           <!-- 自动获取DHCP -->
           <div class="dhcp-section">
             <div class="dhcp-header">
-              <span class="dhcp-label">自动获取 (DHCP)</span>
+              <span class="dhcp-label">Automatic (DHCP)</span>
               <el-switch
                 v-model="settingFormData.enableDHCP"
                 :active-value="1"
@@ -29,16 +28,16 @@
                 @change="switchChange($event)"
               />
             </div>
-            <p class="dhcp-tip">启用自动配置时,以下字段将被禁用</p>
+            <p class="dhcp-tip">The following fields will be disabled when automatic configuration is enabled.</p>
           </div>
 
           <!-- IP版本 -->
-          <el-form-item label="IP版本" prop="IP_version" class="form-item-custom">
+          <el-form-item label="IP Version" prop="IP_version" class="form-item-custom">
             <el-input v-model="IP_version"   disabled></el-input>
           </el-form-item>
 
           <!-- IP地址 -->
-          <el-form-item label="IP地址" prop="IP" class="form-item-custom">
+          <el-form-item label="IP Address" prop="IP" class="form-item-custom">
             <IPInputBox
               :disabled="settingFormData.enableDHCP"
               :ip-val="settingFormData.ipAddress"
@@ -47,7 +46,7 @@
           </el-form-item>
 
           <!-- 子网掩码 -->
-          <el-form-item label="子网掩码" prop="mask" class="form-item-custom">
+          <el-form-item label="Subnet Mask" prop="mask" class="form-item-custom">
             <IPInputBox
               :disabled="settingFormData.enableDHCP"
               :ip-val="settingFormData.subNetAddress"
@@ -56,16 +55,15 @@
           </el-form-item>
 
           <!-- 默认网关 -->
-          <el-form-item label="默认网关" prop="gateway" class="form-item-custom">
+          <el-form-item label="Default Gateway" prop="gateway" class="form-item-custom">
             <IPInputBox
               :disabled="settingFormData.enableDHCP"
               :ip-val="settingFormData.gateWayAddress"
               @update:ip-val="(updateVal) => (settingFormData.gateWayAddress = updateVal)"
             />
           </el-form-item>
-
           <!-- 物理地址 -->
-          <el-form-item label="物理地址" class="form-item-custom">
+          <el-form-item label="Physical Address" class="form-item-custom">
             <el-input
               v-model="settingFormData.deviceMac"
               disabled
@@ -83,8 +81,8 @@
               @click="handleSave()"
               class="save-button"
             >
-              <span v-if="!loading">保 存</span>
-              <span v-else>保存中...</span>
+              <span v-if="!loading">Save</span>
+              <span v-else>Saving...</span>
             </el-button>
           </div>
         </el-form>
@@ -189,10 +187,10 @@ fetchData()
 const handleSave = () => {
     settingFormRef.value?.validate((valid: boolean, fields) => {
       if (valid) {
-        ElMessageBox.confirm('更改网络配置,设备将会重启', {
-          confirmButtonText: '确认',
-          cancelButtonText: '取消',
-          type: 'warning'
+        ElMessageBox.confirm('Changing the network configuration will restart the device', {
+          confirmButtonText: 'Confirm',
+          cancelButtonText: 'Cancel',
+          type: 'warning',
         }).then(() => {
           loading.value = true
           putUserSettingApi(param.NIC, settingFormData)
@@ -221,7 +219,7 @@ const handleSave = () => {
 
 .setting-card {
   width: 100%;
-  max-width: 500px;
+  max-width: 510px;
   //background: white;
   border-radius: 12px;
   box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);

+ 10 - 10
src/views/setting/systemSetting/components/alarm/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="alarm-container">
     <div class="alarm-header">
-      <span class="alarm-title">手动报警控制</span>
+      <span class="alarm-title">Manual Alarm Control</span>
     </div>
     <div class="alarm-buttons">
       <el-button
@@ -11,7 +11,7 @@
         class="btn-alarm"
         :loading="loading"
       >
-        开启手动报警
+        Enable Manual Alarm
       </el-button>
       <el-button
         type="info"
@@ -20,12 +20,12 @@
         class="btn-close"
         :loading="loading"
       >
-        关闭手动报警
+        Disable Manual Alarm
       </el-button>
     </div>
     <div class="alarm-tip">
       <span class="tip-icon">ℹ️</span>
-      <span>报警开启后将持续1分钟</span>
+      <span>Alarm will remain active for 1 minute after activation.</span>
     </div>
   </div>
 </template>
@@ -45,12 +45,12 @@ async function handleCloseAlarm() {
       AlarmSettings: 0
     })
     if (res.data === 'ok\n') {
-      ElMessage.success('关闭手动报警成功!')
+      ElMessage.success('Manual Alarm Deactivated Successfully')
     } else {
-      ElMessage.warning('关闭手动报警异常!')
+      ElMessage.warning('Manual Alarm Deactivation Error')
     }
   } catch (error) {
-    ElMessage.error('关闭手动报警失败!')
+    ElMessage.error('Manual Alarm Deactivation Error')
   } finally {
     loading.value = false
   }
@@ -64,12 +64,12 @@ async function handleAlarm() {
       AlarmSettings: 1
     })
     if (res.data === 'ok\n') {
-      ElMessage.success('开启手动报警成功,持续时间为1分钟!')
+      ElMessage.success('Manual alarm activated successfully. It will remain active for 1 minute.')
     } else {
-      ElMessage.warning('手动报警开启异常!')
+      ElMessage.warning('Manual Alarm Activation Error')
     }
   } catch (error) {
-    ElMessage.error('手动报警开启失败!')
+    ElMessage.error('Failed to Activate Manual Alarm.')
   } finally {
     loading.value = false
   }

+ 5 - 5
src/views/setting/systemSetting/components/cameraInfo/index.vue

@@ -5,10 +5,10 @@
         ref="formRef"
         v-loading="loading"
         label-position="left"
-        label-width="80px"
+        label-width="130px"
         :model="formData"
       >
-        <el-form-item label="项目名字" prop="DeviceName">
+        <el-form-item label="Device Name" prop="DeviceName">
           <el-input
             v-model="formData.DeviceName"
             class="el-input"
@@ -16,21 +16,21 @@
             type="text"
           />
         </el-form-item>
-        <el-form-item label="软件版本" prop="SoftwareVer">
+        <el-form-item label="Software Version" prop="SoftwareVer">
           <el-input
             v-model="formData.SoftwareVer"
             :disabled="true"
             type="text"
           />
         </el-form-item>
-        <el-form-item label="硬件版本" prop="HardwareVer">
+        <el-form-item label="Hardware Version" prop="HardwareVer">
           <el-input
             v-model="formData.HardwareVer"
             :disabled="true"
             type="text"
           />
         </el-form-item>
-        <el-form-item label="MAC地址" prop="MacAddr">
+        <el-form-item label="MAC Address" prop="MacAddr">
           <el-input
             v-model="formData.MacAddr"
             :disabled="true"

+ 10 - 9
src/views/setting/systemSetting/components/nightVision/index.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="night-mode">
     <div class="night-mode-content">
-      <span class="night-mode-label">夜视模式</span>
-      <el-select v-model="NightMode"  style="width: 160px">
+      <span class="night-mode-label">Night Vision Mode</span>
+      <el-select v-model="NightMode"  style="width: 220px">
         <el-option
           v-for="item in NightModeOptions"
           :key="item.value"
@@ -16,7 +16,7 @@
       @click="handleNightMode"
       style="width: 60px"
     >
-      保存
+      Save
     </el-button>
   </div>
 </template>
@@ -30,15 +30,15 @@ const NightMode = ref(0)
 const NightModeOptions = [
   {
     value: 0,
-    label: '全彩夜视',
+    label: 'Full Color Night Vision',
   },
   {
     value: 1,
-    label: '黑白夜视',
+    label: 'Black & White Night Vision',
   },
   {
     value: 2,
-    label: '智能夜视',
+    label: 'Smart Night Vision',
   }
 ]
 
@@ -58,9 +58,9 @@ async function handleNightMode() {
     NightMode: NightMode.value
   })
   if(res.data === 'ok\n'){
-    ElMessage.success('操作成功')
+    ElMessage.success('Operation Successful')
   }else{
-    ElMessage.warning('操作失败')
+    ElMessage.warning('Operation Failed')
   }
 }
 </script>
@@ -80,10 +80,11 @@ async function handleNightMode() {
   }
 
   &-label {
-    font-size: 16px;
+    font-size: 15px;
     font-weight: 500;
     color: #303133;
     min-width: 80px;
+    margin-right: 20px;
   }
 
 }

+ 20 - 23
src/views/setting/systemSetting/components/time/index.vue

@@ -2,17 +2,16 @@
   <div class="time-container">
     <div class="time-card">
       <div class="card-header">
-        <h3 class="card-title">时间设置</h3>
+        <h3 class="card-title">Time Settings</h3>
       </div>
 
       <div class="card-content">
         <div class="form-group">
-          <label class="form-label">显示模式</label>
+          <label class="form-label">Display Mode</label>
           <el-select
             v-model="timeMode"
             class="mode-select"
             @change="changeTimeMode"
-            placeholder="请选择时间格式"
           >
             <el-option
               v-for="item in timeModeOptions"
@@ -24,7 +23,7 @@
         </div>
 
         <div class="form-group">
-          <label class="form-label">本机时间</label>
+          <label class="form-label">System Time</label>
           <div class="time-info">
             <span>{{ currentTime }}</span>
           </div>
@@ -36,7 +35,7 @@
             @click="syncTime"
             class="sync-button"
           >
-            <span>同步至相机</span>
+            <span>Sync to Camera</span>
           </el-button>
         </div>
       </div>
@@ -51,34 +50,32 @@ import { format } from 'date-fns'
 import { ElMessage } from 'element-plus'
 import type { TimeParaData } from '@/api/types/setting'
 
-const timeMode = ref(0)
+const timeMode = ref(1)
 const currentTime = ref('')
 let intervalId: number | null = null
 
-
 const timeModeOptions = [
   {
-    value: 1,
-    label: '24小时制'
+    value: 0,
+    label: '12-Hour Format'
   },
   {
-    value: 0,
-    label: '12小时制'
+    value: 1,
+    label: '24-Hour Format'
   }
 ]
 
-// 更新时间函数
 function updateTime() {
-  const now = new Date()
+  const now = new Date();
   currentTime.value = timeMode.value === 1
-    ? format(now, 'HH:mm:ss')
-    : format(now, 'hh:mm:ss a')
+    ? format(now, 'yyyy-MM-dd HH:mm:ss') // 修改这里以包括年月日
+    : format(now, 'yyyy-MM-dd hh:mm:ss a'); // 和这里
 }
 
 async function getTimeMode() {
   try {
     const res = await GetTimePara()
-    timeMode.value = res.data?.timeMode || 1
+    timeMode.value = res.data?.timeMode
     updateTime() // 初始更新
   } catch (error) {
     console.error('获取时间模式失败', error)
@@ -99,19 +96,19 @@ onBeforeUnmount(() => {
 })
 
 async function changeTimeMode() {
-  updateTime() // 立即更新显示格式
+  updateTime()
   const timeParaData: TimeParaData = {
     timeMode: timeMode.value
   }
   try {
     const res = await PutTimePara(timeParaData)
     if (res.data === 'ok\n') {
-      ElMessage.success('修改成功')
+      ElMessage.success('Update Successful')
     } else {
-      ElMessage.error('修改失败')
+      ElMessage.error('Update Failed')
     }
   } catch (error) {
-    ElMessage.error('修改失败')
+    ElMessage.error('Update Failed')
   }
 }
 
@@ -122,12 +119,12 @@ function syncTime() {
   }
   PutTimePara(timeParaData).then(res => {
     if (res.data === 'ok\n') {
-      ElMessage.success('同步成功')
+      ElMessage.success('Operation Successful')
     } else {
-      ElMessage.error('同步失败')
+      ElMessage.error('Operation Failed')
     }
   }).catch(() => {
-    ElMessage.error('同步失败')
+    ElMessage.error('Operation Failed')
   })
 }
 </script>

+ 15 - 15
src/views/setting/systemSetting/components/user/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div v-loading="loading" class="user-password-form">
-    <h3>相机密码设置</h3>
+    <h3>Camera Password Settings</h3>
     <el-form
       ref="formRef"
       :model="userManagementFormData"
@@ -10,7 +10,7 @@
       <el-form-item prop="oldPassword">
         <el-input
           v-model.trim="userManagementFormData.oldPassword"
-          placeholder="旧密码"
+          placeholder="Old Password"
           size="large"
           tabindex="1"
           type="password"
@@ -21,7 +21,7 @@
       <el-form-item prop="newPassword">
         <el-input
           v-model.trim="userManagementFormData.newPassword"
-          placeholder="新密码"
+          placeholder="New Password"
           size="large"
           tabindex="2"
           type="password"
@@ -31,15 +31,15 @@
       <el-form-item prop="newPasswordSc">
         <el-input
           v-model.trim="userManagementFormData.newPasswordSc"
-          placeholder="确认新密码"
+          placeholder="Confirm New Password"
           size="large"
           tabindex="3"
           type="password"
           show-password
         />
       </el-form-item>
-      <el-button size="large" type="primary" @click.prevent="handleConfirm">
-        保存
+      <el-button type="primary" @click.prevent="handleConfirm">
+        Save
       </el-button>
     </el-form>
   </div>
@@ -70,18 +70,18 @@ const userManagementFormData = reactive({
 /** 表单校验规则 */
 const userManagementFormRules: FormRules = {
   oldPassword: [
-    { required: true, message: '请输入旧密码', trigger: 'blur' },
-    { min: 1, max: 16, message: '密码长度必须在1到16个字符之间', trigger: 'blur' }
+    { required: true, message: 'Please enter your old password', trigger: 'blur' },
+    { min: 1, max: 16, message: 'Password length must be between 1 and 16 characters', trigger: 'blur' }
   ],
   newPassword: [
-    { required: true, message: '请输入新密码', trigger: 'blur' },
-    { min: 1, max: 16, message: '密码长度必须在1到16个字符之间', trigger: 'blur' }
+    { required: true, message: 'Please enter your new password.', trigger: 'blur' },
+    { min: 1, max: 16, message: 'Password length must be between 1 and 16 characters', trigger: 'blur' }
   ],
   newPasswordSc: [
     {
       validator: (rule, value, callback) => {
         if (value !== userManagementFormData.newPassword) {
-          callback(new Error('两次密码不一致'))
+          callback(new Error('Passwords do not match'))
         } else {
           callback()
         }
@@ -102,20 +102,20 @@ const handleConfirm = () => {
       putPasswordApi(userManagementFormData)
         .then((res) => {
           if (res.data == 'ok\n') {
-            ElMessage.success('修改成功')
+            ElMessage.success('Success')
             useUserStore().logout() // 退出登录
             router.push('/login')
           } else {
-            ElMessage.error('修改失败')
+            ElMessage.error('Failed')
           }
           loading.close()
         })
         .catch((error) => {
           loading.close()
-          ElMessage.success('修改失败' + error)
+          ElMessage.success('Failed' + error)
         })
     } else {
-      ElMessage.error('请检查输入项')
+      ElMessage.error('Please check your input')
     }
   })
 }

+ 7 - 7
src/views/setting/systemSetting/components/volume/index.vue

@@ -7,12 +7,12 @@
           <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
           <path d="M15.54 3.54a9 9 0 0 1 0 12.72M19.07 4.93a15 15 0 0 1 0 14.14"></path>
         </svg>
-        <h2>喇叭音量</h2>
+        <h2>Speaker Volume</h2>
       </div>
 
       <!-- 音量显示 -->
       <div class="volume-display">
-        <span class="label">当前音量</span>
+        <span class="label">Current Volume</span>
         <span class="value">{{ speakerVolume }}%</span>
       </div>
 
@@ -41,11 +41,11 @@
         @click="saveVolume"
         class="save-btn"
       >
-        {{ loading ? '保存中...' : '保存设置' }}
+        Save
       </el-button>
 
       <!-- 提示信息 -->
-      <p class="help-text">调整音量后点击保存按钮生效</p>
+<!--      <p class="help-text">调整音量后点击保存按钮生效</p>-->
     </div>
   </div>
 </template>
@@ -86,14 +86,14 @@ const saveVolume = async () => {
   try {
     const res = await cameraVolume({ speakerVolume: speakerVolume.value })
     if(res.data == 'ok\n') {
-      ElMessage.success(`音量已保存`)
+      ElMessage.success(`Volume Saved`)
     } else {
-      ElMessage.error('音量设置失败')
+      ElMessage.error('Failed to Save Volume Settings')
     }
   } catch (error) {
     feedback.value = {
       type: 'error',
-      message: '保存失败,请重试'
+      message: 'Operation failed. Please try again'
     }
     console.error('保存音量失败:', error)
   } finally {

+ 24 - 24
src/views/setting/systemSetting/index.vue

@@ -1,10 +1,10 @@
 <template>
   <div class="system-setting-container">
     <el-tabs v-model="activeName" class="demo-tabs">
-      <el-tab-pane label="基本信息" name="first">
+      <el-tab-pane label="Basic Information" name="first">
         <CameraInfo />
       </el-tab-pane>
-      <el-tab-pane label="系统维护" name="second">
+      <el-tab-pane label="System Maintenance" name="second">
         <el-form
           ref="formRef"
           :model="FormData"
@@ -15,33 +15,33 @@
               v-model="FormData.reset"
               class="vertical-radio-group"
             >
-              <el-radio :value="1">恢复出厂设置</el-radio>
-              <el-radio :value="2">手动重启相机</el-radio>
+              <el-radio :value="1">Restore Factory Settings</el-radio>
+              <el-radio :value="2">Manual Camera Restart</el-radio>
             </el-radio-group>
           </el-form-item>
           <el-button  type="primary" @click.prevent="handle" :loading="loading">
-            执行
+            Execute
           </el-button>
         </el-form>
 
       </el-tab-pane>
-      <el-tab-pane label="时间设置" name="third">
+      <el-tab-pane label="Time Settings" name="third">
         <TimeSetting />
       </el-tab-pane>
 
-      <el-tab-pane label="音量设置" name="fourth">
+      <el-tab-pane label="Volume Settings" name="fourth">
         <VolumeSetting />
       </el-tab-pane>
 
-      <el-tab-pane label="报警设置" name="fifth">
+      <el-tab-pane label="Alarm Settings" name="fifth">
         <AlarmSetting />
       </el-tab-pane>
 
-      <el-tab-pane label="夜视模式" name="sixth">
+      <el-tab-pane label="Night Vision Mode" name="sixth">
         <NightVision />
       </el-tab-pane>
 
-      <el-tab-pane label="密码管理" name="seventh">
+      <el-tab-pane label="Password Management" name="seventh">
         <UserPassword />
       </el-tab-pane>
     </el-tabs>
@@ -71,11 +71,11 @@ const FormData = reactive({ reset: 0 })
 const handleReset = async () => {
   try {
     await ElMessageBox.confirm(
-      '该操作将会修改相机配置并重启相机,是否继续?',
-      '警告',
+      'This operation will modify the camera configuration and restart it. Continue?',
+      'Warning',
       {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
+        confirmButtonText: 'OK',
+        cancelButtonText: 'Cancel',
         type: 'warning',
         confirmButtonClass: 'el-button--danger'
       }
@@ -87,9 +87,9 @@ const handleReset = async () => {
         cameraReset(FormData)
           .then((res) => {
             if (res.data === 'ok\n') {
-              ElMessage.success('操作成功,请稍等片刻...')
+              ElMessage.success('Operation successful. Please wait a moment...')
             } else {
-              ElMessage.error('操作失败')
+              ElMessage.error('Operation failed')
             }
             loading.close()
           })
@@ -104,7 +104,7 @@ const handleReset = async () => {
   } catch (error) {
     console.log(error)
     if (error !== 'cancel') {
-      ElMessage.error('操作失败')
+      ElMessage.error('Operation failed')
     }
   }
 }
@@ -113,25 +113,25 @@ const handleReset = async () => {
 const handleRestart = async () => {
   try {
     await ElMessageBox.confirm(
-      '该操作将会重启相机,是否继续?',
-      '提示',
+      'This operation will restart the camera. Continue?',
+      'Note',
       {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
+        confirmButtonText: 'OK',
+        cancelButtonText: 'Cancel',
         type: 'warning',
         confirmButtonClass: 'el-button--danger'
       }
     )
     const resp = await cameraReset({ reboot: 1 })
     if (resp.data === 'ok\n') {
-      ElMessage.success('相机重启成功,请稍等片刻...')
+      ElMessage.success('Camera restarted successfully. Please wait a moment...')
     } else {
-      ElMessage.error('相机重启失败')
+      ElMessage.error('Operation failed')
     }
   } catch (error) {
     console.log(error)
     if (error !== 'cancel') {
-      ElMessage.error('相机重启失败')
+      ElMessage.error('Operation failed')
     }
   }
 }

+ 2 - 14
vite.config.ts

@@ -8,7 +8,7 @@ import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
 
 export default (configEnv: ConfigEnv): UserConfigExport => {
   const viteEnv = loadEnv(configEnv.mode, process.cwd()) as ImportMetaEnv
-  const { VITE_PUBLIC_PATH } = viteEnv
+  const { VITE_PUBLIC_PATH, VITE_HOST_IP } = viteEnv
   const isDevelopment = configEnv.mode === 'development'
   return {
     base: VITE_PUBLIC_PATH,
@@ -26,20 +26,8 @@ export default (configEnv: ConfigEnv): UserConfigExport => {
       /** 接口代理 */
       proxy: isDevelopment
         ? {
-            '/sports/': {
-              target: 'http://192.168.32.103/',
-              ws: true,
-              /** 是否允许跨域 */
-              changeOrigin: true
-            },
             '/API/V1.0': {
-              target: 'http://192.168.32.103:7000',
-              ws: true,
-              /** 是否允许跨域 */
-              changeOrigin: true
-            },
-            '/XWAPI/V1.0': {
-              target: 'http://192.168.32.103:7000',
+              target: `http://${VITE_HOST_IP}:7000`,
               ws: true,
               /** 是否允许跨域 */
               changeOrigin: true