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

[Feat 0000]数据中心 内业管理登录页开发 数据中心bug修复

bobo04052021@163.com 5 месяцев назад
Родитель
Сommit
8294588ccf

+ 1 - 1
.env

@@ -1,5 +1,5 @@
 # port
-VITE_PORT = 3100
+VITE_PORT = 8062
 
 #  网站标题
 VITE_GLOB_APP_TITLE = 智能通风管控系统

BIN
src/assets/images/vent/loginDataCenter/dataCenterBg.png


BIN
src/assets/images/vent/loginDataCenter/loginForm.png


+ 3 - 0
src/assets/images/vent/loginDataCenter/password.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="19.702" height="25.838" viewBox="0 0 19.702 25.838">
+  <path id="路径_57147" data-name="路径 57147" d="M191.747,92.91h-17.7a1,1,0,0,1-1-1v-12.7a1,1,0,0,1,1-1h.7V76c-.015-.238-.03-.49-.03-.743a8.187,8.187,0,1,1,16.373,0V78.2h.669a1,1,0,0,1,1,1V91.885A1,1,0,0,1,191.747,92.91ZM182.4,86.343v2.3h1v-2.3a2.169,2.169,0,1,0-2.674-2.11A2.208,2.208,0,0,0,182.4,86.343Zm6.508-11.01v-.059a6.01,6.01,0,1,0-12.02,0v2.942h12.035Z" transform="translate(-173.056 -67.072)" fill="#fff"/>
+</svg>

+ 3 - 0
src/assets/images/vent/loginDataCenter/user.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="25.542" height="27.884" viewBox="0 0 25.542 27.884">
+  <path id="路径_57143" data-name="路径 57143" d="M112.367,79.9c-5.431,0-9.487,3.519-9.487,8.63v.551c0,2.671,4.346,2.671,9.849,2.671h5.844c5.285,0,9.849,0,9.849-2.671v-.551c0-5.111-4.056-8.63-9.487-8.63Zm2.992-1.345a7.357,7.357,0,1,0-7.8-7.345,7.592,7.592,0,0,0,7.8,7.345Z" transform="translate(-102.88 -63.87)" fill="#fff"/>
+</svg>

BIN
src/assets/images/vent/loginNeiye/1-1.png


BIN
src/assets/images/vent/loginNeiye/1-2.png


BIN
src/assets/images/vent/loginNeiye/bg.png


BIN
src/assets/images/vent/loginNeiye/btn1.png


BIN
src/assets/images/vent/loginNeiye/btn2.png


+ 6 - 0
src/assets/images/vent/loginNeiye/pass.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="13.08" height="14.807" viewBox="0 0 13.08 14.807">
+  <g id="组_15950" data-name="组 15950" transform="translate(-63.5 0.5)">
+    <path id="路径_57144" data-name="路径 57144" d="M74.813,5.177h-.458V4.314a4.253,4.253,0,0,0-.341-1.676,4.352,4.352,0,0,0-2.3-2.3,4.287,4.287,0,0,0-3.352,0,4.352,4.352,0,0,0-2.3,2.3,4.253,4.253,0,0,0-.341,1.676v.863h-.458A1.269,1.269,0,0,0,64,6.445v6.094a1.269,1.269,0,0,0,1.267,1.267h9.546a1.269,1.269,0,0,0,1.267-1.267V6.445A1.269,1.269,0,0,0,74.813,5.177Zm-8.278-.863a3.505,3.505,0,0,1,7.011,0v.863H66.535Zm8.737,8.224a.46.46,0,0,1-.458.458H65.267a.46.46,0,0,1-.458-.458V6.445a.46.46,0,0,1,.458-.458h9.546a.46.46,0,0,1,.458.458Z" fill="#fff" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1"/>
+    <path id="路径_57145" data-name="路径 57145" d="M482.4,608a.406.406,0,0,0-.4.4v1.78a.4.4,0,1,0,.809,0V608.4A.406.406,0,0,0,482.4,608Z" transform="translate(-412.364 -599.803)" fill="#fff" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1"/>
+  </g>
+</svg>

+ 4 - 0
src/assets/images/vent/loginNeiye/user.svg

@@ -0,0 +1,4 @@
+<svg id="组_15951" data-name="组 15951" xmlns="http://www.w3.org/2000/svg" width="15.126" height="15.246" viewBox="0 0 15.126 15.246">
+  <path id="路径_57131" data-name="路径 57131" d="M270.129,11.018a3.111,3.111,0,1,1-3.111,3.111,3.121,3.121,0,0,1,3.111-3.111m0-.778a3.889,3.889,0,1,0,3.889,3.889A3.851,3.851,0,0,0,270.129,10.24Z" transform="translate(-262.385 -10.24)" fill="#fff"/>
+  <path id="路径_57132" data-name="路径 57132" d="M20.079,471.04v.778a17.075,17.075,0,0,1,2.567.233,2.475,2.475,0,0,1,.7.233c.156.078.233.078.389.156,2.489,1.167,3.345,3.189,3.034,4.667-.156.622-.544,1.4-1.322,1.478H14.634c-.7,0-1.089-.7-1.245-1.322-.311-1.478.467-3.578,3.111-4.823a10.47,10.47,0,0,1,3.578-.545v-.856m0,0a11.912,11.912,0,0,0-3.889.622c-5.134,2.411-4.2,7.623-1.556,7.623h10.89c2.722-.233,3.345-5.367-1.556-7.623-.078,0-.7-.233-1.167-.311A12.5,12.5,0,0,0,20.079,471.04Z" transform="translate(-12.49 -464.039)" fill="#fff"/>
+</svg>

+ 5 - 1
src/router/routes/index.ts

@@ -38,7 +38,11 @@ export const LoginRoute: AppRouteRecordRaw = {
   path: '/login',
   name: 'Login',
   //新版后台登录,如果想要使用旧版登录放开即可
-  component: () => import('/@/views/sys/login/Login.vue'),
+  // component: () => import('/@/views/sys/login/Login.vue'),
+  //数据中心登录
+  // component: () => import('/@/views/sys/login/LoginDataCenter.vue'),
+  // 内页登录
+  component: () => import('/@/views/sys/login/LoginNeiye.vue'),
   // component: () => import('/@/views/system/loginmini/MiniLogin.vue'),
   meta: {
     title: t('routes.basic.login'),

+ 131 - 0
src/views/sys/login/LoginDataCenter.vue

@@ -0,0 +1,131 @@
+<template>
+  <div class="login-container">
+    <!-- 标题 -->
+    <h1 class="title">数据管理中心</h1>
+
+    <!-- 登录框(切图外框) -->
+    <div class="login-frame">
+      <div class="flex center">
+        <LoginForm />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import LoginForm from './LoginFormDataCenter.vue';
+// 响应式数据
+const username = ref('');
+const password = ref('');
+
+// 登录方法
+const handleLogin = () => {
+  if (!username.value) {
+    alert('请输入用户名');
+    return;
+  }
+  if (!password.value) {
+    alert('请输入密码');
+    return;
+  }
+  // 这里可对接接口,示例仅打印
+  console.log('登录信息:', { username: username.value, password: password.value });
+};
+
+// 忘记密码
+const handleForgotPwd = () => {
+  alert('跳转到忘记密码页面');
+};
+</script>
+
+<style scoped>
+.login-container {
+  width: 100%;
+  height: 100%;
+  background: url('@/assets/images/vent/loginDataCenter/dataCenterBg.png') no-repeat center;
+  background-size: 100% 100%;
+  overflow: hidden;
+  position: relative;
+}
+
+/* 标题样式 */
+.title {
+  position: absolute;
+  top: 24vh;
+  left: 20%;
+  transform: translateX(-50%);
+  color: #e2e8f0;
+  font-size: 24px;
+  font-weight: 800;
+  font-style: italic;
+  letter-spacing: 5px;
+  margin: 0;
+}
+
+/* 登录框外框(切图) */
+.login-frame {
+  position: absolute;
+  top: 55%;
+  left: 20%;
+  transform: translate(-50%, -50%);
+  width: 38%;
+  height: 40%;
+  background: url('@/assets/images/vent/loginDataCenter/loginForm.png') no-repeat center;
+  background-size: 100% 100%;
+}
+
+/* 登录表单 */
+.login-form {
+  width: 80%;
+  display: flex;
+  flex-direction: column;
+}
+
+.input-item {
+  width: 100%;
+}
+
+.input-item:focus {
+  border-color: #3b82f6;
+  box-shadow: 0 0 8px rgba(59, 130, 246, 0.5);
+}
+
+.input-item::placeholder {
+  color: #94a3b8;
+}
+
+.forgot-pwd {
+  text-align: right;
+}
+
+.forgot-pwd a {
+  color: #94a3b8;
+  font-size: 0.8rem;
+  text-decoration: none;
+  transition: color 0.3s;
+}
+
+.forgot-pwd a:hover {
+  color: #3b82f6;
+}
+
+.login-btn {
+  width: 100%;
+  padding: 0.8rem;
+  background: #3b82f6;
+  border: none;
+  border-radius: 4px;
+  color: #fff;
+  font-size: 1rem;
+  font-weight: bold;
+  cursor: pointer;
+  transition: all 0.3s;
+  box-shadow: 0 0 10px rgba(59, 130, 246, 0.4);
+}
+
+.login-btn:hover {
+  background: #2563eb;
+  box-shadow: 0 0 15px rgba(59, 130, 246, 0.6);
+}
+</style>

+ 208 - 0
src/views/sys/login/LoginFormDataCenter.vue

@@ -0,0 +1,208 @@
+<template>
+  <div class="login-box">
+    <Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow" @keypress.enter="handleLogin" autocomplete="off">
+      <FormItem name="account" class="enter-x">
+        <div class="input-box">
+          <div class="img-user" />
+          <Input size="large" v-model:value="formData.account" :placeholder="t('sys.login.userName')" class="fix-auto-fill" />
+        </div>
+      </FormItem>
+      <FormItem name="password" class="enter-x">
+        <div class="input-box">
+          <div class="img-pass" />
+          <InputPassword size="large" visibilityToggle v-model:value="formData.password" :placeholder="t('sys.login.password')" />
+        </div>
+      </FormItem>
+    </Form>
+    <div class="btn-box">
+      <div class="btn" @click="handleLogin"> {{ t('sys.login.loginButton') }}</div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { reactive, ref, toRaw, unref, computed, onMounted } from 'vue';
+
+import { Checkbox, Form, Input, Row, Col, Button } from 'ant-design-vue';
+import { createFromIconfontCN } from '@ant-design/icons-vue';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+import { useUserStore } from '/@/store/modules/user';
+import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
+import { useDesign } from '/@/hooks/web/useDesign';
+import { getCodeInfo } from '/@/api/sys/user';
+//import { onKeyStroke } from '@vueuse/core';
+
+const ACol = Col;
+const ARow = Row;
+const FormItem = Form.Item;
+const InputPassword = Input.Password;
+const IconFont = createFromIconfontCN({
+  scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js',
+});
+const { t } = useI18n();
+const { notification, createErrorModal } = useMessage();
+const { prefixCls } = useDesign('login');
+const userStore = useUserStore();
+
+const { setLoginState, getLoginState } = useLoginState();
+const { getFormRules } = useFormRules();
+
+const formRef = ref();
+const thirdModalRef = ref();
+const loading = ref(false);
+const rememberMe = ref(false);
+
+const formData = reactive({
+  account: '',
+  password: '',
+  inputCode: '',
+});
+const randCodeData = reactive({
+  randCodeImage: '',
+  requestCodeSuccess: false,
+  checkKey: null,
+});
+
+const { validForm } = useFormValid(formRef);
+
+//onKeyStroke('Enter', handleLogin);
+
+const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN);
+
+async function handleLogin() {
+  const data = await validForm();
+  if (!data) return;
+  try {
+    loading.value = true;
+    const { userInfo } = await userStore.login(
+      toRaw({
+        password: data.password,
+        username: data.account,
+        captcha: data.inputCode,
+        checkKey: randCodeData.checkKey,
+        mode: 'none', //不要默认的错误提示
+      })
+    );
+    if (userInfo) {
+      notification.success({
+        message: t('sys.login.loginSuccessTitle'),
+        description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
+        duration: 3,
+      });
+    }
+  } catch (error) {
+    // notification.error({
+    //   message: t('sys.api.errorTip'),
+    //   description: error.message || t('sys.api.networkExceptionMsg'),
+    //   duration: 3,
+    // });
+    loading.value = false;
+
+    //update-begin-author:taoyan date:2022-5-3 for: issues/41 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变
+    handleChangeCheckCode();
+    //update-end-author:taoyan date:2022-5-3 for: issues/41 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变
+  }
+}
+function handleChangeCheckCode() {
+  formData.inputCode = '';
+  //TODO 兼容mock和接口,暂时这样处理
+  randCodeData.checkKey = 1629428467008; //new Date().getTime();
+  getCodeInfo(randCodeData.checkKey).then((res) => {
+    randCodeData.randCodeImage = res;
+    randCodeData.requestCodeSuccess = true;
+  });
+}
+
+/**
+ * 第三方登录
+ * @param type
+ */
+function onThirdLogin(type) {
+  thirdModalRef.value.onThirdLogin(type);
+}
+//初始化验证码
+onMounted(() => {
+  handleChangeCheckCode();
+});
+</script>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+@ventSpace: zxm;
+
+.login-box {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  gap: 20px;
+  padding: 20px;
+  margin-top: 8%;
+  margin-left: 28%;
+  .input-box {
+    display: flex;
+    flex-direction: row;
+    width: 100%;
+    background: #165691;
+    border: 1px solid #1d7fbd;
+    border-radius: 4px;
+    font-size: 0.9rem;
+    transition: all 0.3s;
+    input {
+      background: #165691 !important;
+      border: none;
+      color: #fff;
+    }
+    .img-user {
+      width: 24px;
+      height: 24px;
+      margin: 0 12px;
+      background: url('@/assets/images/vent/loginDataCenter/user.svg') no-repeat center;
+      background-size: contain;
+      align-self: center;
+    }
+    .img-pass {
+      width: 24px;
+      height: 24px;
+      margin: 0 12px;
+      background: url('@/assets/images/vent/loginDataCenter/password.svg') no-repeat center;
+      background-size: contain;
+      align-self: center;
+    }
+    :deep(.zxm-input .zxm-input-lg) {
+      background: #165691 !important;
+      border: none;
+      color: #fff;
+    }
+    :deep(.zxm-input-affix-wrapper > input.zxm-input) {
+      background: #165691 !important;
+      border: none;
+      color: #fff;
+    }
+    :deep(.zxm-form-item-has-error :not(.zxm-input-disabled):not(.zxm-input-borderless).zxm-input) {
+      background: #165691 !important;
+    }
+    :deep(.zxm-input-affix-wrapper) {
+      background: #165691 !important;
+      border: none;
+    }
+  }
+  .btn-box {
+    width: 276px;
+    height: 40px;
+    top: 40px;
+    left: 30%;
+    cursor: pointer;
+    background: #2390fd;
+    border-radius: 4px;
+    .btn {
+      color: #fff;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-size: 14px;
+      height: 40px;
+    }
+  }
+}
+</style>

+ 214 - 0
src/views/sys/login/LoginFormNeiye.vue

@@ -0,0 +1,214 @@
+<template>
+  <div class="login-box">
+    <Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow" @keypress.enter="handleLogin" autocomplete="off">
+      <FormItem name="account" class="enter-x">
+        <div class="input-box">
+          <div class="img-user" />
+          <Input size="large" v-model:value="formData.account" :placeholder="t('sys.login.userName')" class="fix-auto-fill" />
+        </div>
+      </FormItem>
+      <FormItem name="password" class="enter-x">
+        <div class="input-box">
+          <div class="img-pass" />
+          <InputPassword size="large" visibilityToggle v-model:value="formData.password" :placeholder="t('sys.login.password')" />
+        </div>
+      </FormItem>
+    </Form>
+    <div class="btn-box">
+      <div class="btn" @click="handleLogin"> {{ t('sys.login.loginButton') }}</div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { reactive, ref, toRaw, unref, computed, onMounted } from 'vue';
+
+import { Checkbox, Form, Input, Row, Col, Button } from 'ant-design-vue';
+import { createFromIconfontCN } from '@ant-design/icons-vue';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+import { useUserStore } from '/@/store/modules/user';
+import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
+import { useDesign } from '/@/hooks/web/useDesign';
+import { getCodeInfo } from '/@/api/sys/user';
+//import { onKeyStroke } from '@vueuse/core';
+
+const ACol = Col;
+const ARow = Row;
+const FormItem = Form.Item;
+const InputPassword = Input.Password;
+const IconFont = createFromIconfontCN({
+  scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js',
+});
+const { t } = useI18n();
+const { notification, createErrorModal } = useMessage();
+const { prefixCls } = useDesign('login');
+const userStore = useUserStore();
+
+const { setLoginState, getLoginState } = useLoginState();
+const { getFormRules } = useFormRules();
+
+const formRef = ref();
+const thirdModalRef = ref();
+const loading = ref(false);
+const rememberMe = ref(false);
+
+const formData = reactive({
+  account: '',
+  password: '',
+  inputCode: '',
+});
+const randCodeData = reactive({
+  randCodeImage: '',
+  requestCodeSuccess: false,
+  checkKey: null,
+});
+
+const { validForm } = useFormValid(formRef);
+
+//onKeyStroke('Enter', handleLogin);
+
+const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN);
+
+async function handleLogin() {
+  const data = await validForm();
+  if (!data) return;
+  try {
+    loading.value = true;
+    const { userInfo } = await userStore.login(
+      toRaw({
+        password: data.password,
+        username: data.account,
+        captcha: data.inputCode,
+        checkKey: randCodeData.checkKey,
+        mode: 'none', //不要默认的错误提示
+      })
+    );
+    if (userInfo) {
+      notification.success({
+        message: t('sys.login.loginSuccessTitle'),
+        description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
+        duration: 3,
+      });
+    }
+  } catch (error) {
+    // notification.error({
+    //   message: t('sys.api.errorTip'),
+    //   description: error.message || t('sys.api.networkExceptionMsg'),
+    //   duration: 3,
+    // });
+    loading.value = false;
+
+    //update-begin-author:taoyan date:2022-5-3 for: issues/41 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变
+    handleChangeCheckCode();
+    //update-end-author:taoyan date:2022-5-3 for: issues/41 登录页面,当输入验证码错误时,验证码图片要刷新一下,而不是保持旧的验证码图片不变
+  }
+}
+function handleChangeCheckCode() {
+  formData.inputCode = '';
+  //TODO 兼容mock和接口,暂时这样处理
+  randCodeData.checkKey = 1629428467008; //new Date().getTime();
+  getCodeInfo(randCodeData.checkKey).then((res) => {
+    randCodeData.randCodeImage = res;
+    randCodeData.requestCodeSuccess = true;
+  });
+}
+
+/**
+ * 第三方登录
+ * @param type
+ */
+function onThirdLogin(type) {
+  thirdModalRef.value.onThirdLogin(type);
+}
+//初始化验证码
+onMounted(() => {
+  handleChangeCheckCode();
+});
+</script>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+@ventSpace: zxm;
+
+.login-box {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  gap: 20px;
+  padding: 20px;
+  margin-top: 17%;
+  margin-left: 25%;
+  .input-box {
+    display: flex;
+    flex-direction: row;
+    width: 300px;
+    background-image: url('@/assets/images/vent/loginNeiye/1-1.png');
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    height: 40px;
+    border-radius: 4px;
+    font-size: 0.9rem;
+    transition: all 0.3s;
+    color: #fff;
+    input {
+      background: transparent !important;
+      border: none;
+      color: #fff;
+    }
+    .img-user {
+      width: 24px;
+      height: 24px;
+      margin: 0 12px;
+      margin-left: 30px;
+      background: url('@/assets/images/vent/loginNeiye/user.svg') no-repeat center;
+      background-size: contain;
+      align-self: center;
+    }
+    .img-pass {
+      width: 24px;
+      height: 24px;
+      margin: 0 12px;
+      margin-left: 30px;
+      background: url('@/assets/images/vent/loginNeiye/pass.svg') no-repeat center;
+      background-size: contain;
+      align-self: center;
+    }
+    :deep(.zxm-input .zxm-input-lg) {
+      background: transparent !important;
+      border: none;
+      color: #fff;
+    }
+    :deep(.zxm-input-affix-wrapper > input.zxm-input) {
+      background: transparent !important;
+      border: none;
+      color: #fff;
+    }
+    :deep(.zxm-form-item-has-error :not(.zxm-input-disabled):not(.zxm-input-borderless).zxm-input) {
+      background: transparent !important;
+    }
+    :deep(.zxm-input-affix-wrapper) {
+      background: transparent !important;
+      border: none;
+    }
+  }
+  .btn-box {
+    width: 100%;
+    height: 40px;
+    top: 40px;
+    left: 30%;
+    cursor: pointer;
+    background: url('@/assets/images/vent/loginNeiye/btn1.png') no-repeat center;
+    background-size: 100% 100%;
+    border-radius: 4px;
+    .btn {
+      color: #fff;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-size: 16px;
+      height: 40px;
+    }
+  }
+}
+</style>

+ 132 - 0
src/views/sys/login/LoginNeiye.vue

@@ -0,0 +1,132 @@
+<template>
+  <div class="login-container">
+    <!-- 标题 -->
+    <h1 class="title">内页管理系统</h1>
+
+    <!-- 登录框(切图外框) -->
+    <div class="login-frame">
+      <div class="flex center">
+        <LoginForm />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import LoginForm from './LoginFormNeiye.vue';
+// 响应式数据
+const username = ref('');
+const password = ref('');
+
+// 登录方法
+const handleLogin = () => {
+  if (!username.value) {
+    alert('请输入用户名');
+    return;
+  }
+  if (!password.value) {
+    alert('请输入密码');
+    return;
+  }
+  // 这里可对接接口,示例仅打印
+  console.log('登录信息:', { username: username.value, password: password.value });
+};
+
+// 忘记密码
+const handleForgotPwd = () => {
+  alert('跳转到忘记密码页面');
+};
+</script>
+
+<style scoped>
+.login-container {
+  width: 100%;
+  height: 100%;
+  background: url('@/assets/images/vent/loginNeiye/bg.png') no-repeat center;
+  background-size: 100% 100%;
+  overflow: hidden;
+  position: relative;
+}
+
+/* 标题样式 */
+.title {
+  position: absolute;
+  top: 13.5vh;
+  left: 50%;
+  transform: translateX(-50%);
+  color: #e2e8f0;
+  font-size: 24px;
+  font-weight: 800;
+  font-style: italic;
+  letter-spacing: 5px;
+  margin: 0;
+  z-index: 1;
+}
+
+/* 登录框外框(切图) */
+.login-frame {
+  position: absolute;
+  top: 43%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 38%;
+  height: 50%;
+  background: url('@/assets/images/vent/loginNeiye/1-2.png') no-repeat center;
+  background-size: 100% 100%;
+}
+
+/* 登录表单 */
+.login-form {
+  width: 80%;
+  display: flex;
+  flex-direction: column;
+}
+
+.input-item {
+  width: 100%;
+}
+
+.input-item:focus {
+  border-color: #3b82f6;
+  box-shadow: 0 0 8px rgba(59, 130, 246, 0.5);
+}
+
+.input-item::placeholder {
+  color: #94a3b8;
+}
+
+.forgot-pwd {
+  text-align: right;
+}
+
+.forgot-pwd a {
+  color: #94a3b8;
+  font-size: 0.8rem;
+  text-decoration: none;
+  transition: color 0.3s;
+}
+
+.forgot-pwd a:hover {
+  color: #3b82f6;
+}
+
+.login-btn {
+  width: 100%;
+  padding: 0.8rem;
+  background: #3b82f6;
+  border: none;
+  border-radius: 4px;
+  color: #fff;
+  font-size: 1rem;
+  font-weight: bold;
+  cursor: pointer;
+  transition: all 0.3s;
+  box-shadow: 0 0 10px rgba(59, 130, 246, 0.4);
+}
+
+.login-btn:hover {
+  background: #2563eb;
+  box-shadow: 0 0 15px rgba(59, 130, 246, 0.6);
+}
+</style>

+ 1 - 1
src/views/vent/dataCenter/deviceCenter/index.vue

@@ -350,7 +350,7 @@ async function refreshData(deviceId: string) {
   // 这里实现具体的请求逻辑
   const device = deviceList.value.find((d) => d.id === deviceId);
   const result = await getDevMonitorListById({ devId: deviceId.toString() });
-  monitorList.value = Object.values(result.readData);
+  monitorList.value[deviceId] = Object.values(result.readData);
 }
 
 onMounted(() => {

+ 2 - 6
src/views/vent/dataCenter/stationCenter/index.vue

@@ -106,7 +106,7 @@ const cardList = ref<any[]>(); //分站列表
 const deviceList = ref<any[]>([]);
 const openNum = ref(0);
 const clsoeNum = ref(0);
-const monitorList = ref<any[]>([]); // 监测数据列表
+const monitorList = ref<Record<string, any[]>>({}); // 监测数据列表
 const expandedRowKeys = ref([]);
 const selectedIndex = ref(0);
 // // 分页参数
@@ -295,10 +295,6 @@ async function loadMonitoringData(deviceId: string) {
     clearInterval(timer);
     timer = null;
   }
-
-  // 立即请求一次数据
-  // 这里可以加上初始加载,避免等待1秒的间隔
-  // 定时器会在1秒后开始,所以先手动加载一次
   refreshData(deviceId);
 
   // 设置新的定时器
@@ -310,7 +306,7 @@ async function refreshData(deviceId: string) {
   // 这里实现具体的请求逻辑
   const device = deviceList.value.find((d) => d.id === deviceId);
   const result = await getDevMonitorListById({ devId: deviceId.toString() });
-  monitorList.value = Object.values(result.readData);
+  monitorList.value[deviceId] = Object.values(result.readData);
 }
 onMounted(async () => {
   await getSubStationList();