ZZJ
2021-12-10 5f0ba4bd0c69fd1ebcad122a2dcab8840d929188
登录前配置页
3个文件已修改
9个文件已添加
16个文件已删除
2640 ■■■■ 已修改文件
public/images/init/背景图.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/0.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/1.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/10.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/11.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/12.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/13.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/14.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/15.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/2.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/3.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/4.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/5.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/6.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/7.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/8.png 补丁 | 查看 | 原始文档 | blame | 历史
public/images/login/9.png 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/App.vue 757 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/api.ts 111 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/components/IPInput.vue 238 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/components/formAccount.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/components/formInfo.vue 259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/components/formNet.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login/App.vue 564 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login/ParticleNetwork.vue 348 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login/api.ts 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login/main.ts 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/images/init/±³¾°Í¼.png
public/images/login/0.png
Binary files differ
public/images/login/1.png
Binary files differ
public/images/login/10.png
Binary files differ
public/images/login/11.png
Binary files differ
public/images/login/12.png
Binary files differ
public/images/login/13.png
Binary files differ
public/images/login/14.png
Binary files differ
public/images/login/15.png
Binary files differ
public/images/login/2.png
Binary files differ
public/images/login/3.png
Binary files differ
public/images/login/4.png
Binary files differ
public/images/login/5.png
Binary files differ
public/images/login/6.png
Binary files differ
public/images/login/7.png
Binary files differ
public/images/login/8.png
Binary files differ
public/images/login/9.png
Binary files differ
src/pages/index/App.vue
@@ -1,564 +1,271 @@
<template>
  <!-- <div class v-loading="vLoading" :style="`width: ${currentWidth}px;height:${currentHeight}px`">
    <div class="web-site">
      <a href="http://www.smartai.com" target="_blank">www.smartai.com</a>
    </div>
  <div class="init" v-if="!isWhite">
    <div class="content">
      <div class="title">欢迎注册Smart AI äººå·¥æ™ºèƒ½æ“ä½œç³»ç»Ÿ</div>
      <el-steps :active="active" finish-status="success" :align-center="true">
        <el-step title="创建账号"></el-step>
        <el-step title="配置网络"></el-step>
        <el-step title="注册信息"></el-step>
      </el-steps>
    <lang-select class="lang-select"/>
    <licence />
    <div class="right-bg" style>
      <particle-network />
    </div>
    <div class="left-bg">
      <div class="login-logo">
        <img src="/images/login-logo.png" alt width="105px" height="105px" />
      </div>
      <div class="login-com">
        <span>{{ $t('login.company') }}</span>
      </div>
      <div class="login-form">
        <el-form
          :model="user"
          status-icon
          :rules="nullRule"
          :validate-on-rule-change="false"
          ref="ruleForm"
          class="demo-ruleForm"
        >
          <el-form-item prop="loginName">
            <el-input v-model="user.loginName" style="width:280px" :placeholder="$t('placeholder.enterUsername')">
              <i slot="prefix" class="iconfont iconyonghu1"></i>
            </el-input>
          </el-form-item>
          <el-form-item prop="password">
            <el-input
              show-password
              @keyup.enter.native="systemLogin()"
              v-model="user.password"
              autocomplete="off"
              style="width:280px"
              :placeholder="$t('placeholder.enterPassword')"
            >
              <i slot="prefix" class="iconfont iconmima"></i>
            </el-input>
          </el-form-item>
          <el-form-item>
            <el-button ref="submit" type="warning" @click="systemLogin()" style="width:280px">{{ $t('button.login') }}</el-button>
          </el-form-item>
        </el-form>
      </div>
      <p class="gradient-text gradient-text-one">
        â€”—
        <b>SmartAI</b> {{ $t('login.aios') }} â€”—
      </p>
      <p
        class="gradient-text gradient-text-one"
        style="letter-spacing: 1.8px;font-size:15px;"
      >V1.0.0</p>
    </div>
  </div> -->
  <div class="login">
    <div class="title">
      <div class="en">Smart AI</div>
      <div class="ch">人工智能操作系统</div>
    </div>
    <div class="left_footer">
      <img class="logo" src="/images/login/LOGO.png" alt="" />
      <div class="web">www.smartai.com</div>
    </div>
    <div
      class="login-form"
      :style="{ background: backgroundColor }"
      :class="{ empty: !user.loginName && !user.password }"
    >
      <img class="logo" src="/images/login/OS.png" alt="" />
      <el-form
        :model="user"
        status-icon
        :rules="nullRule"
        :validate-on-rule-change="false"
        ref="ruleForm"
        class="demo-ruleForm"
      <el-carousel
        ref="carousel"
        trigger="click"
        height="480px"
        :loop="false"
        :autoplay="false"
        :initial-index="active"
      >
        <el-form-item prop="loginName">
          <el-input
            v-model="user.loginName"
            :placeholder="$t('placeholder.enterUsername')"
          >
            <i slot="prefix" class="iconfont icon">&#xe7e5;</i>
          </el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input
            show-password
            @keyup.enter.native="systemLogin()"
            v-model="user.password"
            autocomplete="off"
            :placeholder="$t('placeholder.enterPassword')"
          >
            <i slot="prefix" class="iconfont icon">&#xe7e4;</i>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button ref="submit" type="warning" @click="systemLogin()">{{
            $t("button.login")
          }}</el-button>
        </el-form-item>
      </el-form>
        <el-carousel-item>
          <formAccount ref="form0"></formAccount>
        </el-carousel-item>
        <el-carousel-item>
          <formNet ref="form1"></formNet>
        </el-carousel-item>
        <el-carousel-item>
          <formInfo ref="form2"></formInfo>
        </el-carousel-item>
      </el-carousel>
      <div class="control">
        <div class="pre" @click="preForm">上一步</div>
        <div class="next" @click="nextForm" v-if="active == 0">下一步</div>
        <div class="next" @click="nextForm" v-if="active == 1">跳过</div>
        <div class="next" @click="nextForm" v-if="active == 2">完成</div>
      </div>
    </div>
  </div>
  <div class="white" v-else></div>
</template>
<script>
import { tologin, getLoginUserData, getServerName } from "./api.ts";
import ParticleNetwork from "./ParticleNetwork";
import Licence from "@/components/licence";
import LangSelect from "@/components/langSelect";
import { getMenuListData } from "@/api/utils";
import formAccount from "@/pages/index/components/formAccount";
import formNet from "@/pages/index/components/formNet";
import formInfo from "@/pages/index/components/formInfo";
import {
  getInitInfo,
  savePassword,
  initNetwork,
  saveRegInfo,
  getRegInfo,
} from "./api";
export default {
  name: "login-pgae",
  metaInfo: {
    title: "登录页",
  created() {
    this.getInitInfo();
  },
  data() {
    return {
      active: 0,
      formData: {},
      isWhite: true,
    };
  },
  components: {
    //  ParticleNetwork,
    // Licence,
    //  LangSelect
  },
  computed: {
    rules() {
      return {
        loginName: [
          {
            required: true,
            message: this.$t("placeholder.enterUsername"),
            trigger: "change",
          },
        ],
        password: [
          {
            required: true,
            message: this.$t("placeholder.enterPassword"),
            trigger: "change",
          },
        ],
      };
    },
  },
  data: () => ({
    serverTitle: "",
    user: {
      loginName: "",
      password: "",
      rememberMe: false,
    },
    nullRule: {},
    loading: "",
    vLoading: false,
    currentHeight: 1057,
    currentWidth: 1920,
    backgroundColor: "",
    backgroundList: [
      "#2A2344",
      "#342344",
      "#000000",
      "#233044",
      "#0B252E",
      "#150051",
      "#110040",
    ],
  }),
  created() {
    this.getServerName();
    this.getScreenHeight();
    this.backgroundColor =
      this.backgroundList[
        Math.floor(Math.random() * this.backgroundList.length)
      ];
  },
  mounted() {
    // è‡ªåŠ¨ç™»å½•æŽ¥å£
    this.loginRobot();
  },
  watch: {},
  beforeDestroy() {
    window.onresize = null;
    formAccount,
    formNet,
    formInfo,
  },
  methods: {
    loginRobot() {
      // è§£æžè·¯ç”±å‚数,并缓存
      let user = this.getQueryVariable("username");
      let passwd = this.getQueryVariable("password");
      if (user.length && passwd.length) {
        sessionStorage.setItem(
          "autoLogin",
          JSON.stringify({ username: user, passwd: passwd })
        );
        this.user.loginName = user;
        this.user.password = passwd;
        this.systemLogin();
    preForm() {
      if (this.active == 0) {
        return;
      }
      this.active--;
      this.$refs["carousel"].prev();
    },
    async nextForm() {
      if (this.active == 2) {
        const data = this.$refs[`form${this.active}`].getFormData();
        await saveRegInfo(data);
        location.assign("/login");
        return;
      }
      // ç™»é™†è¶…时后的重新登陆
      let sessionInfo = sessionStorage.getItem("autoLogin");
      if (sessionInfo) {
        let authority = JSON.parse(sessionInfo);
        this.user.loginName = authority.username;
        this.user.password = authority.passwd;
        this.systemLogin();
      if (this.active == 0) {
        const data = this.$refs[`form${this.active}`].getFormData();
        if (!data) {
          return false;
        }
        const res1 = await savePassword(data);
        console.log(data);
      }
    },
    systemLogin() {
      this.nullRule = this.rules;
      this.$nextTick(() => {
        this.$refs["ruleForm"].validate((valid) => {
          if (valid) {
            this.loading = this.$loading({
              lock: true,
              text: "Loading",
              spinner: "el-icon-loading",
              background: "rgba(0, 0, 0, 0.7)",
            });
            this.testLogin();
          } else {
            this.nullRule = {};
          }
        });
        this.nullRule = {};
      });
    },
    async testLogin() {
      // location.assign("/view/desktop/")
      tologin({ username: this.user.loginName, password: this.user.password })
        .then((json) => {
          const loginedInfo = {
            access_token: json.token_type + " " + json.access_token,
            refresh_token: json.refresh_token,
          };
          sessionStorage.setItem("expires_in", json.expires_in);
          sessionStorage.setItem("loginedInfo", JSON.stringify(loginedInfo));
          this.loading.close();
          this.getLoginUserData();
        })
        .catch((err) => {
          this.loading.close();
          this.$notify({
            title: "提示",
            type: "error",
            message: err.msg,
          });
          this.$refs.pwd.focus();
        });
    },
    async getLoginUserData() {
      let res = await getLoginUserData();
      if (res.success) {
        sessionStorage.setItem("userInfo", JSON.stringify(res.data));
        this.$notify.success("登录成功!");
        // èŽ·å–æƒé™
        await this.getMenuList();
        location.assign("/view/desktop/");
        return res.data;
      } else {
        this.$notify.error("登录失败!");
      }
    },
    getScreenHeight() {
      this.currentHeight = document.documentElement.clientHeight;
      this.currentWidth = document.documentElement.clientWidth;
      window.onresize = () => {
        this.currentHeight = document.documentElement.clientHeight;
        this.currentWidth = document.documentElement.clientWidth;
        this.$forceUpdate();
      };
    },
    async getServerName() {
      let res = await getServerName();
      if (res && res.success) {
        this.serverTitle = res.data.serverName;
        window.document.title = res.data.serverName
          ? res.data.serverName
          : "SmartAI";
        sessionStorage.setItem("title", res.data.serverName);
      if (this.active == 1) {
        const data = this.$refs[`form${this.active}`].getFormData();
        await initNetwork(data);
        console.log(data);
      }
      this.active++;
      this.$refs["carousel"].next();
    },
    async getMenuList() {
      let results = await getMenuListData({});
      if (results && results.success) {
        /* å­˜å‚¨æƒé™ */
        let buttonAuthoritys = results.data;
        if (results && results.length && this.$route.query.is_login) {
          this.$router.replace(results[0].url);
        }
        sessionStorage.setItem(
          "buttonAuthoritys",
          "," + buttonAuthoritys + ","
        );
        sessionStorage.setItem("menuInfo", JSON.stringify(results));
      } else {
        this.$toast({
          type: "error",
          message: "菜单获取失败",
        });
    async getInitInfo() {
      const res = await getInitInfo();
      if (res.data.initPwd && !res.data.initRegInfo) {
        const res1 = await getRegInfo();
        this.active = 1;
        this.$refs["carousel"].setActiveItem(1);
      }
    },
    getQueryVariable(variable) {
      var query = window.location.search.substring(1);
      var vars = query.split("&");
      for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split("=");
        if (pair[0] == variable) {
          return pair[1];
        }
      if (res.data.initPwd && res.data.initRegInfo) {
        location.assign("/login");
        return;
      }
      return false;
      this.isWhite = false;
    },
  },
};
</script>
<style lang="scss">
.login {
<style lang="scss" scoped>
.init {
  height: 100%;
  position: relative;
  background-image: url("/images/login/背景图.png");
  background-image: url("/images/init/背景图.png");
  color: #fff;
  user-select: none;
  .title {
    position: absolute;
    top: 345px;
    left: 301px;
    color: #fff;
    text-align: center;
  .content {
    margin: 0 auto;
    width: 1000px;
    padding-top: 80px;
    .en {
      font-size: 120px;
    }
    .ch {
      font-size: 48px;
      letter-spacing: 9px;
    }
  }
  .left_footer {
    position: absolute;
    display: flex;
    justify-content: start;
    align-items: center;
    left: 358px;
    bottom: 40px;
    .logo {
      width: 136px;
      margin-right: 30px;
    }
    .web {
      font-size: 24px;
    .title {
      font-size: 28px;
      font-weight: 700;
      color: rgba(255, 255, 255, 0.7);
      margin-bottom: 50px;
      letter-spacing: 5px;
    }
    .el-steps ::v-deep {
      margin-left: 22px;
      text-align: left;
      .el-step__icon {
        width: 48px;
        height: 48px;
      }
      .el-step__line {
        left: 210px;
        right: -110px;
        border: 0.5px solid #fff;
        border-bottom: none;
        border-top: none;
        opacity: 0.1;
        top: 22px;
      }
      .is-success .el-step__icon {
        background: none;
        border: 2px solid rgba(255, 255, 255, 0.3);
        .el-icon-check::before {
          color: #fff;
          font-size: 24px;
          font-weight: 700;
        }
      }
      .is-process .el-step__icon {
        background-color: rgba(255, 255, 255, 0.3);
        border: none;
        .el-step__icon-inner {
          color: #fff;
          font-size: 24px;
          font-weight: 700;
        }
      }
      .is-wait .el-step__icon {
        border: 2px solid rgba(255, 255, 255);
        opacity: 0.5;
        background: none;
        .el-step__icon-inner {
          color: #fff;
          font-size: 24px;
          font-weight: 700;
        }
      }
      .el-step__main {
        margin-top: 20px;
        .is-success,
        .is-process {
          font-size: 16px;
          color: #fff;
          font-weight: normal;
        }
        .is-wait {
          font-size: 16px;
          color: #fff;
          font-weight: normal;
          opacity: 0.5;
        }
      }
    }
    .formAccount {
      margin-top: 157px;
      margin-left: 200px;
      width: 550px;
    }
    .formNet,
    .formInfo {
      margin-top: 90px;
      margin-left: 200px;
      width: 550px;
    }
    .control {
      position: fixed;
      display: flex;
      justify-content: center;
      align-items: center;
      bottom: 258px;
      left: 0;
      right: 0;
      line-height: 40px;
      .pre {
        margin-right: 20px;
        cursor: pointer;
        width: 260px;
        height: 40px;
        border: 2px solid rgba(255, 255, 255, 0.3);
        border-radius: 20px;
        font-weight: bold;
        color: #ffffff;
      }
      .next {
        cursor: pointer;
        width: 260px;
        height: 40px;
        background: rgba(255, 255, 255, 0.3);
        border-radius: 20px;
        font-weight: bold;
        color: #ffffff;
      }
    }
  }
  .login-form {
    position: absolute;
    width: 780px;
    height: 1000px;
    right: 40px;
    top: 40px;
    padding: 0 90px;
    box-sizing: border-box;
    background: #2a2344;
    opacity: 0.95;
    box-shadow: -4px 0px 10px rgba(0, 0, 0, 0.25);
    border-radius: 56px;
    .logo {
      margin-top: 100px;
      margin-bottom: 16px;
    }
    .el-form-item {
      background: rgba(0, 0, 0, 0);
    }
    .el-form-item:nth-child(2) {
      margin-top: 60px;
      margin-bottom: 80px;
    }
    .el-button {
      width: 600px;
      height: 60px;
      background: #4e94ff;
      border-radius: 30px;
      border: none;
    }
    .el-input {
      width: 100%;
      background: rgba(0, 0, 0, 0);
    }
    input {
      width: 100%;
      height: 56px;
      background: rgba(255, 255, 255, 0.1) !important;
      border: 1px solid #4e94ff;
      box-sizing: border-box;
      border-radius: 28px;
      color: #fff;
      caret-color: #fff; //光标颜色
      padding-left: 100px;
      padding-right: 50px;
      font-weight: 700;
    }
    input:-webkit-autofill,
    textarea:-webkit-autofill,
    select:-webkit-autofill {
      -webkit-text-fill-color: #ededed !important;
      -webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
      background-color: transparent;
      background-image: none;
      transition: background-color 50000s ease-in-out 0s; //背景色透明  ç”Ÿæ•ˆæ—¶é•¿  è¿‡æ¸¡æ•ˆæžœ  å¯ç”¨æ—¶å»¶è¿Ÿçš„æ—¶é—´
    }
    .el-form-item__error {
      top: 110%;
      left: 80px;
    }
    .icon {
      font-size: 32px;
      color: rgb(80, 151, 255);
    }
    .el-input__prefix {
      padding: 0 20px;
      height: 40px;
      left: 5px;
      top: 8px;
      border-right: 1px solid #4e94ff;
    }
    .el-input__suffix {
      right: 20px;
    }
    .el-icon-circle-close {
      display: none;
    }
  ::v-deep .el-carousel__indicators {
    display: none;
  }
  .login-form.empty {
    input {
      border-color: #999;
      color: #bbb;
    }
    .el-button {
      background-color: #999;
      color: #fff;
    }
    .icon {
      color: #fff;
    }
    .el-input__prefix {
      border-color: #d4d6d9;
    }
  ::v-deep .el-carousel__container button {
    display: none;
  }
}
// .right-bg {
//   position: fixed;
//   top: 0;
//   left: 0;
//   background-image: url("/images/login-net.png");
//   width: 100%;
//   height: 100%;
//   min-width: 1000px;
//   z-index: -10;
//   zoom: 1;
//   background-color: #fff;
//   background-repeat: no-repeat;
//   background-size: cover;
//   -webkit-background-size: cover;
//   -o-background-size: cover;
//   background-position: center 0;
// }
// .web-site {
//   position: absolute;
//   top: 55px;
//   left: 41px;
//   font-family: PingFangSC-Medium;
//   font-size: 20px;
//   color: #6170e1;
//   letter-spacing: 6.15px;
// }
// .lang-select {
//   float: right;
//   color: white !important;
//   font-size: 14px;
//   margin: 13px;
//   cursor: pointer;
// }
// .left-bg {
//   position: absolute;
//   top: 29%;
//   right: 18%;
//   width: 390px;
//   height: 426px;
//   background: rgba(146, 208, 255, 0.23);
//   border-radius: 4px;
//   text-align: center;
//   .login-logo {
//     margin-top: -53px;
//   }
//   .login-com {
//     font-family: PingFangSC-Medium;
//     font-size: 22px;
//     color: #ffffff;
//     letter-spacing: 0.44px;
//     margin: 15px;
//   }
//   .login-form {
//     margin: 40px 10px;
//   }
//   .gradient-text {
//     line-height: 36px;
//     font-size: 17px;
//     font-family: -webkit-pictograph;
//     font-weight: bolder;
//     position: relative;
//     b {
//       font-size: 20px;
//     }
//   }
//   .gradient-text-one {
//     background-image: linear-gradient(to right, #51feff 5%, #ff8725 100%);
//     -webkit-background-clip: text;
//     -webkit-text-fill-color: transparent;
//   }
//   .el-input__prefix {
//     left: 8px;
//   }
//   .el-form-item__error {
//     left: 54px;
//   }
// }
</style>
.white {
  height: 100%;
  background-color: #fff;
}
</style>
src/pages/index/api.ts
@@ -1,66 +1,67 @@
import request from '@/scripts/httpRequest'
import qs from 'qs'
// ç™»å½•
export const tologin = (query: any) => {
  // let query = 'username=' + user.loginName + '&password=' + user.password
 //获取是否保存过用户名密码 ä»¥åŠæ˜¯å¦ä¿å­˜è¿‡æ³¨å†Œä¿¡æ¯
export const getInitInfo = (query: any) => {
  return request({
    url: '/data/api-u/sys/login',
    method: 'post',
    data: qs.stringify(query)
  })
}
    url: "/data/api-v/sysinit/getInitInfo",
    method: "get",
    params: query
  });
};
// é€€å‡º
export const logout = () => {
//获取注册信息
export const getRegInfo = (query: any) => {
  return request({
    url: '/data/api-u/sys/logout',
    method: 'get'
  })
}
    url: "/data/api-v/sysinit/getRegInfo" ,
    method: "get",
    params: query
  });
};
// èŽ·å–ç”¨æˆ·ä¿¡æ¯
// export const getLoginUserData = () => {
//   let token =
//     sessionStorage.getItem('loginedInfo') &&
//     JSON.parse(sessionStorage.getItem('loginedInfo')).access_token
//   return request({
//     url: '/data/api-u/users/current',
//     method: 'get',
//     headers: {
//       'Content-Type': 'application/x-www-form-urlencoded',
//       Authorization: token || ''
//     }
//   })
// }
export const getLoginUserData = () => {
    let token =
      sessionStorage.getItem('loginedInfo') &&
      JSON.parse(sessionStorage.getItem('loginedInfo')).access_token
    return request({
      url: '/data/api-u/users/profile',
      method: 'get',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Authorization: token || ''
      }
    })
  }
//修改密码
export const updatePwd = (query: any) => {
//获取网卡列表
export const networkList = (query: any) => {
  return request({
    url: '/data/api-u/users/updatePwd',
    method: 'post',
    data: qs.stringify(query)
  })
}
    url: "/data/api-v/sysinit/networkList",
    method: "get",
    params: query
  });
};
//获取项目名称
export const getServerName = (query: any) => {
//保存用户名密码
export const savePassword = (data: any) => {
  return request({
    url: '/data/api-v/info/getServerName',
    method: 'get'
  })
}
    url: "/data/api-v/sysinit/savePassword",
    method: "post",
    data
  });
};
//初始化网络
export const initNetwork = (data: any) => {
  return request({
    url: "/data/api-v/sysinit/initNetwork",
    method: "post",
    data
  });
};
//保存注册信息
export const saveRegInfo = (data: any) => {
  return request({
    url:  "/data/api-v/sysinit/saveRegInfo" ,
    method: "post",
    data
  });
};
export const getList = (query: any) => {
  return request({
    url: "/data/api-v/gb28181/findAreaByParentId",
    method: "get",
    params: query
  });
};
src/pages/index/components/IPInput.vue
New file
@@ -0,0 +1,238 @@
<template>
  <div class="ip-input-container" ref="ip-input-container">
    <div class="ip-segment" v-for="(segment, index) in segments" :key="index">
      <input
        type="text"
        maxlength="3"
        class="ip-segment-input"
        :value="segment"
        :placeholder="placeholder"
        :disabled="disabled"
        @focus="showBorder"
        @keydown="onInputKeydown($event, index)"
        @input="onInput($event, index)"
        @blur="onInputBlur"
        @paste="onPaste($event, index)"
      />
      <i v-show="index != segments.length - 1">.</i>
    </div>
  </div>
</template>
<script>
/* global document*/
/**
 * get the cursor position of the element
 * @param  {Element} el the element
 * @return {Integer}    the position fo the cursor
 */
function getRange(el) {
  var cuRange;
  var tbRange;
  var headRange;
  var range;
  var dupRange;
  var ret = {};
  if (el.setSelectionRange) {
    // standard
    ret.begin = el.selectionStart;
    ret.end = el.selectionEnd;
    ret.result = el.value.substring(ret.begin, ret.end);
  } else if (document.selection) {
    // ie
    if (el.tagName.toLowerCase() === "input") {
      cuRange = document.selection.createRange();
      tbRange = el.createTextRange();
      tbRange.collapse(true);
      tbRange.select();
      headRange = document.selection.createRange();
      headRange.setEndPoint("EndToEnd", cuRange);
      ret.begin = headRange.text.length - cuRange.text.length;
      ret.end = headRange.text.length;
      ret.result = cuRange.text;
      cuRange.select();
    } else if (el.tagName.toLowerCase() === "textarea") {
      range = document.selection.createRange();
      dupRange = range.duplicate();
      dupRange.moveToElementText(el);
      dupRange.setEndPoint("EndToEnd", range);
      ret.begin = dupRange.text.length - range.text.length;
      ret.end = dupRange.text.length;
      ret.result = range.text;
    }
  }
  el.focus();
  return ret;
}
export default {
  props: {
    ip: {
      type: String,
      defalut: ""
    },
    item: {},
    placeholder: String,
    onChange: Function,
    onBlur: Function,
    onItemChange: Function,
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      segments: ["", "", "", ""]
    };
  },
  watch: {
    ip(ip) {
      this.syncIp(ip);
    }
  },
  methods: {
    showBorder(){
      this.$refs['ip-input-container'].style.border = '2px solid var(--colorCard)'
    },
    onInputKeydown(event, index) {
      var keyCode = event.keyCode || event.which;
      var value = event.target.value;
      if (keyCode === 8 || keyCode === 37) {
        // move the cursor to previous input if backspace and left arrow is pressed at the begin of one input
        if (
          (value.length === 0 || getRange(event.target).end === 0) &&
          index > 0
        ) {
          this.$el.getElementsByTagName("input")[index - 1].focus();
          // When jump to pre input(enter "backspace"), thr cursor should in the end.
          // before fix: 127.|0.0.0  =>   12|7.0.0.1
          // after fix: 127.|0.0.0 = >   127|.0.0.0
          // notes: "|" mean the cursor position.
          event.preventDefault();
        }
      } else if (keyCode === 39 && keyCode === 110) {
        if (getRange(event.target).end === value.length && index < 3) {
          // move to cursor to the next input if right arrow is pressed at the end of one input
          this.$el.getElementsByTagName("input")[index + 1].focus();
        }
      }
    },
    onInput(event, index) {
      var value = event.target.value;
      event.target.value = this.segments[index];
      var segment = Number(value);
      if (isNaN(segment)) {
        return;
      } else if (value === "") {
        this.segments.splice(index, 1, "");
      } else if (segment > 255 || segment < 0) {
        // set the segment to 255 if out of ip range
        this.segments.splice(index, 1, 255);
      } else {
        this.segments.splice(index, 1, segment);
      }
      // jump to next input
      if (
        (value.length === 3 && index < 3) ||
        value[value.length - 1] === "."
      ) {
        this.$el.getElementsByTagName("input")[index + 1].focus();
      }
    },
    onInputBlur() {
      this.$refs['ip-input-container'].style.border = '2px solid transparent'
      setTimeout(() => {
        this.$emit("on-blur", this.segments.join("."));
        if (this.onBlur) {
          this.onBlur(this.segments.join("."));
        }
        if (this.onItemChange) {
          this.onItemChange(this.segments.join("."), this.item)
        }
      }, 50);
    },
    onPaste(e, index) {
      var pasteText = e.clipboardData.getData("text/plain");
      var segments = pasteText.split(".");
      segments.forEach((segment, i) => {
        if (
          index + i < 4 &&
          !isNaN(segment) &&
          segment >= 0 &&
          segment <= 255
        ) {
          this.segments.splice(index + i, 1, segment);
        }
      });
      e.preventDefault();
    },
    syncIp(ip) {
      if (ip && ip.indexOf(".") !== -1) {
        ip.split(".").map((segment, index) => {
          if (isNaN(segment) || segment < 0 || segment > 255) {
            segment = 255;
          }
          this.segments.splice(index, 1, segment);
          return segment;
        });
      }
    }
  },
  mounted() {
    this.syncIp(this.ip);
    this.$watch(
      () => {
        return this.segments.join(".");
      },
      (val, oldValue) => {
        if (val !== oldValue) {
          if (val === "...") {
            val = "";
          }
          if (this.onChange) {
            this.onChange(val);
          }
        }
      }
    );
  }
};
</script>
<style lang="scss" scoped>
.ip-input-container {
  width: 100%;
  height: 32px;
  line-height: normal;
  border: 1px solid #dcdfe6;
  box-sizing: border-box;
  background-color: #fff;
  text-align: left;
  max-width: 360px;
  display: flex;
}
.ip-segment {
  display: inline-block;
  width: 25%;
    display: flex;
    align-items: center;
  line-height: normal;
  input {
    width: 90%;
    height: 32px;
    line-height: normal;
    border: none;
    outline: none;
    text-align: center;
    text-indent: 0px;
    margin: 0px;
    padding: 0px;
    background-color: transparent;
  }
  i {
    display: inline-block;
    font-size: 18px;
  }
}
</style>
src/pages/index/components/formAccount.vue
New file
@@ -0,0 +1,134 @@
<template>
  <div class="formAccount">
    <el-form ref="form" :model="form" label-width="90px" :rules="rules">
      <el-form-item label="用户名" prop="username">
        <el-input
          v-model="form.username"
          placeholder="2-10位字符,不能以数字开头,不可包含汉字"
        ></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input
          v-model="form.password"
          placeholder="至少为6位字符"
          type="password"
        ></el-input>
      </el-form-item>
      <el-form-item label="确认密码" prop="repassword">
        <el-input
          v-model="form.repassword"
          placeholder="请确认密码"
          type="password"
        ></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
import { getRegInfo } from "../api";
export default {
  data() {
    const validateName = (rule, value, callback) => {
      var reg = /^[A-Za-z][A-Za-z0-9]{0,}$/;
      if (!reg.test(value)) {
        return callback(new Error("不能以数字开头,不可包含汉字"));
      } else callback();
    };
    const validateRePass = (rule, value, callback) => {
      if (this.form.password != value) {
        return callback(new Error("两次密码不一致"));
      } else callback();
    };
    return {
      form: {
        username: "",
        password: "",
        repassword: "",
      },
      rules: {
        name: [
          { required: true, message: "请输入用户名", trigger: "blur" },
          {
            min: 2,
            max: 10,
            message: "长度在 2 åˆ° 10 ä¸ªå­—符",
            trigger: "blur",
          },
          { validator: validateName, trigger: "blur" },
        ],
        password: [
          { required: true, message: "请输入密码", trigger: "blur" },
          {
            min: 6,
            max: 24,
            message: "至少为6位字符",
            trigger: "blur",
          },
        ],
        repassword: [
          { required: true, message: "请确认密码", trigger: "blur" },
          { validator: validateRePass, trigger: "blur" },
        ],
      },
    };
  },
  methods: {
    getFormData() {
      const _this = this;
      let data = null;
      this.$refs["form"].validate((valid) => {
        if (valid) {
          data = _this.form;
        } else {
          return false;
        }
      });
      return data;
    },
    async getRegInfo() {
      const res = await getRegInfo();
      console.log(res);
    },
  },
};
</script>
<style lang="scss" scoped>
.formAccount {
  .el-form-item ::v-deep {
    label {
      font-size: 14px;
      color: #fff;
      text-align: left;
    }
    .el-form-item__content {
      margin-left: 110px !important;
    }
    input {
      background-color: rgba(0, 0, 0, 0.1);
      color: #fff;
      border: none;
      caret-color: #fff !important;
    }
    input:-webkit-autofill,
    textarea:-webkit-autofill,
    select:-webkit-autofill {
      -webkit-text-fill-color: #fff !important;
      -webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
      background-color: transparent;
      background-image: none;
      transition: background-color 50000s ease-in-out 0s; //背景色透明  ç”Ÿæ•ˆæ—¶é•¿  è¿‡æ¸¡æ•ˆæžœ  å¯ç”¨æ—¶å»¶è¿Ÿçš„æ—¶é—´
    }
  }
}
</style>
src/pages/index/components/formInfo.vue
New file
@@ -0,0 +1,259 @@
<template>
  <div class="formInfo">
    <el-form ref="form" :model="form" label-width="90px" :rules="rules">
      <el-form-item label="类型" prop="type">
        <el-radio v-model="form.userType" label="personal">个人</el-radio>
        <el-radio v-model="form.userType" label="company">公司</el-radio>
      </el-form-item>
      <el-form-item
        label="公司名称"
        prop="name1"
        v-if="form.userType == 'company'"
      >
        <el-input v-model="form.name1" placeholder="请输入公司名称"></el-input>
      </el-form-item>
      <el-form-item
        label="联系人姓名"
        prop="name2"
        v-if="form.userType == 'company'"
      >
        <el-input
          v-model="form.name2"
          placeholder="请输入联系人姓名"
        ></el-input>
      </el-form-item>
      <el-form-item label="姓名" prop="name" v-else>
        <el-input v-model="form.name" placeholder="请输入姓名"></el-input>
      </el-form-item>
      <el-form-item label="所在地" prop="addr">
        <el-cascader
          :props="props"
          popper-class="location"
          separator=" "
          @change="handleChange"
          v-model="form.addr"
        ></el-cascader>
      </el-form-item>
      <el-form-item label="邮箱" prop="email">
        <el-input v-model="form.email" placeholder="请输入邮箱"></el-input>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
import { getList } from "../api";
export default {
  created() {},
  data() {
    return {
      form: {
        userType: "personal",
        name: "",
        name1: "",
        name2: "",
        email: "",
        addr: "",
        provinceId: "",
        cityId: "",
        labelList: "",
      },
      rules: {
        name1: [{ required: true, message: "请输入公司名称", trigger: "blur" }],
        name2: [
          { required: true, message: "请输入联系人姓名", trigger: "blur" },
        ],
        name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
        addr: [{ required: true, message: "请选择所在地", trigger: "blur" }],
        email: [{ required: true, message: "请输入邮箱", trigger: "blur" }],
      },
      provinceOptions: [],
      props: {
        lazy: true, // å¼€å¯åŠ¨æ€åŠ è½½
        lazyLoad: async (node, resolve) => {
          // è®¾ç½®åŠ è½½æ•°æ®æºæ–¹æ³• é»˜è®¤æ‰§è¡Œä¸€æ¬¡
          // node ä¸ºå½“前点击的节点
          // resolve ä¸ºæ•°æ®åŠ è½½å®Œæˆçš„å›žè°ƒ(必须调用)
          /* node此时属性为:
                  å½“前叶子  level:0
                  loaded:true
                  loading:false
                  æ˜¯å¦æ˜¯æ ¹  root:ture
              */
          console.log(node);
          if (node.level == 0) {
            const res = await getList();
            this.provinceOptions = res.data.map((item) => {
              return {
                value: item.id,
                label: item.name, // é€‰é¡¹å
                leaf: false, // æ˜¯å¦ä¸ºæœ«å°¾
              };
            });
            resolve(this.provinceOptions);
            console.log(node.level);
          }
          if (node.level == 1) {
            console.log("-------------");
            this.provinceId = node.value;
            const res2 = await getList({
              parentId: node.value,
            });
            const arr = res2.data.map((item) => {
              return {
                value: item.id,
                label: item.name, // é€‰é¡¹å
                leaf: true, // æ˜¯å¦ä¸ºæœ«å°¾
              };
            });
            resolve(arr);
          } else {
            console.log(node);
          }
        },
      },
      value: [],
    };
  },
  methods: {
    getFormData() {
      const _this = this;
      let data = null;
      this.$refs["form"].validate((valid) => {
        if (valid) {
          console.log(_this.form.userType);
          if (_this.form.userType == "personal") {
            data = {
              userType: _this.form.userType,
              name: _this.form.name,
              email: _this.form.email,
              addr: _this.form.labelList,
              provinceId: _this.form.provinceId,
              cityId: _this.form.cityId,
            };
          } else {
            data = {
              userType: _this.form.userType,
              name: _this.form.name1 + " " + _this.form.name2,
              email: _this.form.email,
              addr: _this.form.labelList,
              provinceId: _this.form.provinceId,
              cityId: _this.form.cityId,
            };
          }
        } else {
          return false;
        }
      });
      return data;
    },
    handleChange(val) {
      this.form.provinceId = val[0] + "";
      this.form.cityId = val[1] + "";
      setTimeout(() => {
        this.form.labelList =
          document.querySelectorAll(".el-cascader input")[0].value;
      }, 200);
    },
  },
};
</script>
<style lang="scss" scoped>
.formInfo {
  .el-form-item ::v-deep {
    label {
      font-size: 14px;
      color: #fff;
      text-align: left;
    }
    .el-radio {
      .el-radio__inner {
        background: none;
        border-color: rgba(255, 255, 255, 0.3) !important;
        &::after {
          width: 6px;
          height: 6px;
        }
      }
      .el-radio__label {
        color: #fff !important;
      }
    }
    .el-form-item__content {
      margin-left: 110px !important;
      text-align: left;
    }
    input {
      background-color: rgba(0, 0, 0, 0.1);
      color: #fff;
      border: none;
      caret-color: #fff !important;
    }
    input:-webkit-autofill,
    textarea:-webkit-autofill,
    select:-webkit-autofill {
      -webkit-text-fill-color: #fff !important;
      -webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
      background-color: transparent;
      background-image: none;
      transition: background-color 50000s ease-in-out 0s; //背景色透明  ç”Ÿæ•ˆæ—¶é•¿  è¿‡æ¸¡æ•ˆæžœ  å¯ç”¨æ—¶å»¶è¿Ÿçš„æ—¶é—´
    }
    .el-cascader {
      width: 100%;
    }
  }
}
</style>
<style lang="scss">
.el-popper.el-cascader__dropdown.location {
  background-color: rgb(77, 72, 111);
  border: none;
  margin: 0 0;
  * {
    color: #fff;
    border-color: rgba(255, 255, 2555, 0.1);
  }
  .el-cascader-node:hover,
  .in-active-path,
  .is-active,
  .el-cascader-node {
    background-color: rgb(101, 93, 126) !important;
  }
  .popper__arrow::after,
  .popper__arrow {
    display: none;
  }
  .el-cascader-node__label {
    text-align: left;
  }
  .el-cascader-menu__wrap {
    width: 226px;
    height: 175px;
  }
}
</style>
src/pages/index/components/formNet.vue
New file
@@ -0,0 +1,141 @@
<template>
  <div class="formNet">
    <el-form ref="form" :model="form" label-width="80px">
      <el-form-item label="网卡">
        <el-select
          v-model="form.netName"
          placeholder="请选择网卡"
          popper-class="formNet_select"
        >
          <el-option
            v-for="(item, index) in options"
            :key="index"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="IP">
        <ipInput :ip="form.ip" @on-blur="form.ip = arguments[0]"></ipInput>
      </el-form-item>
      <el-form-item label="子网掩码">
        <ipInput
          :ip="form.subMask"
          @on-blur="form.subMask = arguments[0]"
        ></ipInput>
      </el-form-item>
      <el-form-item label="网关">
        <ipInput
          :ip="form.gateway"
          @on-blur="form.gateway = arguments[0]"
        ></ipInput>
      </el-form-item>
      <el-form-item label="DNS">
        <ipInput :ip="form.dns" @on-blur="form.dns = arguments[0]"></ipInput>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
import ipInput from "../components/IPInput";
import { networkList } from "../api";
export default {
  created() {
    this.networkList();
  },
  data() {
    return {
      form: { netName: "", ip: "", subMask: "", gateway: "", dns: "" },
      options: [],
    };
  },
  components: {
    ipInput,
  },
  methods: {
    getFormData() {
      return this.form;
    },
    async networkList() {
      const res = await networkList();
      res.data.forEach((item) => {
        this.options.push({
          value: item.name,
          label: item.name,
        });
      });
    },
  },
};
</script>
<style lang="scss" scoped>
.formNet {
  .el-form-item ::v-deep {
    label {
      font-size: 14px;
      color: #fff;
      text-align-last: left;
    }
    .el-form-item__content {
      margin-left: 110px !important;
    }
  }
  .ip-input-container ::v-deep {
    background-color: rgba(0, 0, 0, 0.1);
    border: none !important;
    height: 40px;
    max-width: none;
    .ip-segment-input {
      color: #fff;
    }
  }
  .el-select ::v-deep {
    width: 100%;
    input {
      background-color: rgba(0, 0, 0, 0.1);
      border: none !important;
      color: #fff;
    }
  }
}
</style>
<style lang="scss">
.el-select-dropdown.el-popper.formNet_select {
  background-color: rgb(60, 62, 99);
  border: none;
  margin: 0 0;
  z-index: 5;
  * {
    color: #fff;
  }
  li {
    z-index: 4;
  }
  .el-select-dropdown__item.hover {
    background-color: rgba(85, 82, 117) !important;
  }
  .popper__arrow::after,
  .popper__arrow {
    display: none;
  }
}
</style>
src/pages/login/App.vue
New file
@@ -0,0 +1,564 @@
<template>
  <!-- <div class v-loading="vLoading" :style="`width: ${currentWidth}px;height:${currentHeight}px`">
    <div class="web-site">
      <a href="http://www.smartai.com" target="_blank">www.smartai.com</a>
    </div>
    <lang-select class="lang-select"/>
    <licence />
    <div class="right-bg" style>
      <particle-network />
    </div>
    <div class="left-bg">
      <div class="login-logo">
        <img src="/images/login-logo.png" alt width="105px" height="105px" />
      </div>
      <div class="login-com">
        <span>{{ $t('login.company') }}</span>
      </div>
      <div class="login-form">
        <el-form
          :model="user"
          status-icon
          :rules="nullRule"
          :validate-on-rule-change="false"
          ref="ruleForm"
          class="demo-ruleForm"
        >
          <el-form-item prop="loginName">
            <el-input v-model="user.loginName" style="width:280px" :placeholder="$t('placeholder.enterUsername')">
              <i slot="prefix" class="iconfont iconyonghu1"></i>
            </el-input>
          </el-form-item>
          <el-form-item prop="password">
            <el-input
              show-password
              @keyup.enter.native="systemLogin()"
              v-model="user.password"
              autocomplete="off"
              style="width:280px"
              :placeholder="$t('placeholder.enterPassword')"
            >
              <i slot="prefix" class="iconfont iconmima"></i>
            </el-input>
          </el-form-item>
          <el-form-item>
            <el-button ref="submit" type="warning" @click="systemLogin()" style="width:280px">{{ $t('button.login') }}</el-button>
          </el-form-item>
        </el-form>
      </div>
      <p class="gradient-text gradient-text-one">
        â€”—
        <b>SmartAI</b> {{ $t('login.aios') }} â€”—
      </p>
      <p
        class="gradient-text gradient-text-one"
        style="letter-spacing: 1.8px;font-size:15px;"
      >V1.0.0</p>
    </div>
  </div> -->
  <div class="login">
    <div class="title">
      <div class="en">Smart AI</div>
      <div class="ch">人工智能操作系统</div>
    </div>
    <div class="left_footer">
      <img class="logo" src="/images/login/LOGO.png" alt="" />
      <div class="web">www.smartai.com</div>
    </div>
    <div
      class="login-form"
      :style="{ background: backgroundColor }"
      :class="{ empty: !user.loginName && !user.password }"
    >
      <img class="logo" src="/images/login/OS.png" alt="" />
      <el-form
        :model="user"
        status-icon
        :rules="nullRule"
        :validate-on-rule-change="false"
        ref="ruleForm"
        class="demo-ruleForm"
      >
        <el-form-item prop="loginName">
          <el-input
            v-model="user.loginName"
            :placeholder="$t('placeholder.enterUsername')"
          >
            <i slot="prefix" class="iconfont icon">&#xe7e5;</i>
          </el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input
            show-password
            @keyup.enter.native="systemLogin()"
            v-model="user.password"
            autocomplete="off"
            :placeholder="$t('placeholder.enterPassword')"
          >
            <i slot="prefix" class="iconfont icon">&#xe7e4;</i>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button ref="submit" type="warning" @click="systemLogin()">{{
            $t("button.login")
          }}</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>
<script>
import { tologin, getLoginUserData, getServerName } from "./api.ts";
import ParticleNetwork from "./ParticleNetwork";
import Licence from "@/components/licence";
import LangSelect from "@/components/langSelect";
import { getMenuListData } from "@/api/utils";
export default {
  name: "login-pgae",
  metaInfo: {
    title: "登录页",
  },
  components: {
    //  ParticleNetwork,
    // Licence,
    //  LangSelect
  },
  computed: {
    rules() {
      return {
        loginName: [
          {
            required: true,
            message: this.$t("placeholder.enterUsername"),
            trigger: "change",
          },
        ],
        password: [
          {
            required: true,
            message: this.$t("placeholder.enterPassword"),
            trigger: "change",
          },
        ],
      };
    },
  },
  data: () => ({
    serverTitle: "",
    user: {
      loginName: "",
      password: "",
      rememberMe: false,
    },
    nullRule: {},
    loading: "",
    vLoading: false,
    currentHeight: 1057,
    currentWidth: 1920,
    backgroundColor: "",
    backgroundList: [
      "#2A2344",
      "#342344",
      "#000000",
      "#233044",
      "#0B252E",
      "#150051",
      "#110040",
    ],
  }),
  created() {
    this.getServerName();
    this.getScreenHeight();
    this.backgroundColor =
      this.backgroundList[
        Math.floor(Math.random() * this.backgroundList.length)
      ];
  },
  mounted() {
    // è‡ªåŠ¨ç™»å½•æŽ¥å£
    this.loginRobot();
  },
  watch: {},
  beforeDestroy() {
    window.onresize = null;
  },
  methods: {
    loginRobot() {
      // è§£æžè·¯ç”±å‚数,并缓存
      let user = this.getQueryVariable("username");
      let passwd = this.getQueryVariable("password");
      if (user.length && passwd.length) {
        sessionStorage.setItem(
          "autoLogin",
          JSON.stringify({ username: user, passwd: passwd })
        );
        this.user.loginName = user;
        this.user.password = passwd;
        this.systemLogin();
        return;
      }
      // ç™»é™†è¶…时后的重新登陆
      let sessionInfo = sessionStorage.getItem("autoLogin");
      if (sessionInfo) {
        let authority = JSON.parse(sessionInfo);
        this.user.loginName = authority.username;
        this.user.password = authority.passwd;
        this.systemLogin();
      }
    },
    systemLogin() {
      this.nullRule = this.rules;
      this.$nextTick(() => {
        this.$refs["ruleForm"].validate((valid) => {
          if (valid) {
            this.loading = this.$loading({
              lock: true,
              text: "Loading",
              spinner: "el-icon-loading",
              background: "rgba(0, 0, 0, 0.7)",
            });
            this.testLogin();
          } else {
            this.nullRule = {};
          }
        });
        this.nullRule = {};
      });
    },
    async testLogin() {
      // location.assign("/view/desktop/")
      tologin({ username: this.user.loginName, password: this.user.password })
        .then((json) => {
          const loginedInfo = {
            access_token: json.token_type + " " + json.access_token,
            refresh_token: json.refresh_token,
          };
          sessionStorage.setItem("expires_in", json.expires_in);
          sessionStorage.setItem("loginedInfo", JSON.stringify(loginedInfo));
          this.loading.close();
          this.getLoginUserData();
        })
        .catch((err) => {
          this.loading.close();
          this.$notify({
            title: "提示",
            type: "error",
            message: err.msg,
          });
          this.$refs.pwd.focus();
        });
    },
    async getLoginUserData() {
      let res = await getLoginUserData();
      if (res.success) {
        sessionStorage.setItem("userInfo", JSON.stringify(res.data));
        this.$notify.success("登录成功!");
        // èŽ·å–æƒé™
        await this.getMenuList();
        location.assign("/view/desktop/");
        return res.data;
      } else {
        this.$notify.error("登录失败!");
      }
    },
    getScreenHeight() {
      this.currentHeight = document.documentElement.clientHeight;
      this.currentWidth = document.documentElement.clientWidth;
      window.onresize = () => {
        this.currentHeight = document.documentElement.clientHeight;
        this.currentWidth = document.documentElement.clientWidth;
        this.$forceUpdate();
      };
    },
    async getServerName() {
      let res = await getServerName();
      if (res && res.success) {
        this.serverTitle = res.data.serverName;
        window.document.title = res.data.serverName
          ? res.data.serverName
          : "SmartAI";
        sessionStorage.setItem("title", res.data.serverName);
      }
    },
    async getMenuList() {
      let results = await getMenuListData({});
      if (results && results.success) {
        /* å­˜å‚¨æƒé™ */
        let buttonAuthoritys = results.data;
        if (results && results.length && this.$route.query.is_login) {
          this.$router.replace(results[0].url);
        }
        sessionStorage.setItem(
          "buttonAuthoritys",
          "," + buttonAuthoritys + ","
        );
        sessionStorage.setItem("menuInfo", JSON.stringify(results));
      } else {
        this.$toast({
          type: "error",
          message: "菜单获取失败",
        });
      }
    },
    getQueryVariable(variable) {
      var query = window.location.search.substring(1);
      var vars = query.split("&");
      for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split("=");
        if (pair[0] == variable) {
          return pair[1];
        }
      }
      return false;
    },
  },
};
</script>
<style lang="scss">
.login {
  height: 100%;
  position: relative;
  background-image: url("/images/login/背景图.png");
  .title {
    position: absolute;
    top: 345px;
    left: 301px;
    color: #fff;
    text-align: center;
    .en {
      font-size: 120px;
    }
    .ch {
      font-size: 48px;
      letter-spacing: 9px;
    }
  }
  .left_footer {
    position: absolute;
    display: flex;
    justify-content: start;
    align-items: center;
    left: 358px;
    bottom: 40px;
    .logo {
      width: 136px;
      margin-right: 30px;
    }
    .web {
      font-size: 24px;
      font-weight: 700;
      color: rgba(255, 255, 255, 0.7);
    }
  }
  .login-form {
    position: absolute;
    width: 780px;
    height: 1000px;
    right: 40px;
    top: 40px;
    padding: 0 90px;
    box-sizing: border-box;
    background: #2a2344;
    opacity: 0.95;
    box-shadow: -4px 0px 10px rgba(0, 0, 0, 0.25);
    border-radius: 56px;
    .logo {
      margin-top: 100px;
      margin-bottom: 16px;
    }
    .el-form-item {
      background: rgba(0, 0, 0, 0);
    }
    .el-form-item:nth-child(2) {
      margin-top: 60px;
      margin-bottom: 80px;
    }
    .el-button {
      width: 600px;
      height: 60px;
      background: #4e94ff;
      border-radius: 30px;
      border: none;
    }
    .el-input {
      width: 100%;
      background: rgba(0, 0, 0, 0);
    }
    input {
      width: 100%;
      height: 56px;
      background: rgba(255, 255, 255, 0.1) !important;
      border: 1px solid #4e94ff;
      box-sizing: border-box;
      border-radius: 28px;
      color: #fff;
      caret-color: #fff; //光标颜色
      padding-left: 100px;
      padding-right: 50px;
      font-weight: 700;
    }
    input:-webkit-autofill,
    textarea:-webkit-autofill,
    select:-webkit-autofill {
      -webkit-text-fill-color: #ededed !important;
      -webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
      background-color: transparent;
      background-image: none;
      transition: background-color 50000s ease-in-out 0s; //背景色透明  ç”Ÿæ•ˆæ—¶é•¿  è¿‡æ¸¡æ•ˆæžœ  å¯ç”¨æ—¶å»¶è¿Ÿçš„æ—¶é—´
    }
    .el-form-item__error {
      top: 110%;
      left: 80px;
    }
    .icon {
      font-size: 32px;
      color: rgb(80, 151, 255);
    }
    .el-input__prefix {
      padding: 0 20px;
      height: 40px;
      left: 5px;
      top: 8px;
      border-right: 1px solid #4e94ff;
    }
    .el-input__suffix {
      right: 20px;
    }
    .el-icon-circle-close {
      display: none;
    }
  }
  .login-form.empty {
    input {
      border-color: #999;
      color: #bbb;
    }
    .el-button {
      background-color: #999;
      color: #fff;
    }
    .icon {
      color: #fff;
    }
    .el-input__prefix {
      border-color: #d4d6d9;
    }
  }
}
// .right-bg {
//   position: fixed;
//   top: 0;
//   left: 0;
//   background-image: url("/images/login-net.png");
//   width: 100%;
//   height: 100%;
//   min-width: 1000px;
//   z-index: -10;
//   zoom: 1;
//   background-color: #fff;
//   background-repeat: no-repeat;
//   background-size: cover;
//   -webkit-background-size: cover;
//   -o-background-size: cover;
//   background-position: center 0;
// }
// .web-site {
//   position: absolute;
//   top: 55px;
//   left: 41px;
//   font-family: PingFangSC-Medium;
//   font-size: 20px;
//   color: #6170e1;
//   letter-spacing: 6.15px;
// }
// .lang-select {
//   float: right;
//   color: white !important;
//   font-size: 14px;
//   margin: 13px;
//   cursor: pointer;
// }
// .left-bg {
//   position: absolute;
//   top: 29%;
//   right: 18%;
//   width: 390px;
//   height: 426px;
//   background: rgba(146, 208, 255, 0.23);
//   border-radius: 4px;
//   text-align: center;
//   .login-logo {
//     margin-top: -53px;
//   }
//   .login-com {
//     font-family: PingFangSC-Medium;
//     font-size: 22px;
//     color: #ffffff;
//     letter-spacing: 0.44px;
//     margin: 15px;
//   }
//   .login-form {
//     margin: 40px 10px;
//   }
//   .gradient-text {
//     line-height: 36px;
//     font-size: 17px;
//     font-family: -webkit-pictograph;
//     font-weight: bolder;
//     position: relative;
//     b {
//       font-size: 20px;
//     }
//   }
//   .gradient-text-one {
//     background-image: linear-gradient(to right, #51feff 5%, #ff8725 100%);
//     -webkit-background-clip: text;
//     -webkit-text-fill-color: transparent;
//   }
//   .el-input__prefix {
//     left: 8px;
//   }
//   .el-form-item__error {
//     left: 54px;
//   }
// }
</style>
src/pages/login/ParticleNetwork.vue
New file
@@ -0,0 +1,348 @@
<template>
  <div class="particle-network-animation" :style="`height:${height}px;width:${width}px`">
    <div style="display:none">
      <img ref="conf0" src="/images/login/0.png" />
      <img ref="conf1" src="/images/login/1.png" />
      <img ref="conf2" src="/images/login/2.png" />
      <img ref="conf3" src="/images/login/3.png" />
      <img ref="conf4" src="/images/login/4.png" />
      <img ref="conf5" src="/images/login/5.png" />
      <img ref="conf6" src="/images/login/6.png" />
      <img ref="conf7" src="/images/login/7.png" />
      <img ref="conf8" src="/images/login/8.png" />
      <img ref="conf9" src="/images/login/9.png" />
      <img ref="conf10" src="/images/login/10.png" />
      <img ref="conf11" src="/images/login/11.png" />
      <img ref="conf12" src="/images/login/12.png" />
      <img ref="conf13" src="/images/login/13.png" />
      <img ref="conf14" src="/images/login/14.png" />
      <img ref="conf15" src="/images/login/15.png" />
    </div>
  </div>
</template>
<script>
export default {
  name: 'particleNetwork',
  data() {
    return {
      imgNumber: 0,
      destoryed: false
    }
  },
  props: {
    height: {
      type: Number,
      default: 800
    },
    width: {
      type: Number,
      default: 1000
    }
  },
  mounted() {
    this.createCavas()
  },
  beforeDestroy() {
    this.destoryed = true
  },
  methods: {
    createCavas() {
      let that = this
      var ParticleNetworkAnimation, PNA
      ParticleNetworkAnimation = PNA = function () { }
      PNA.prototype.init = function (element) {
        // this.$el = $(element);
        this.container = element
        this.canvas = document.createElement('canvas')
        this.sizeCanvas()
        this.container.appendChild(this.canvas)
        this.ctx = this.canvas.getContext('2d')
        this.particleNetwork = new ParticleNetwork(this)
        return this
      }
      PNA.prototype.sizeCanvas = function () {
        this.canvas.width = this.container.offsetWidth
        this.canvas.height = this.container.offsetHeight
      }
      var Particle = function (parent, x, y) {
        this.network = parent
        this.imgNumber = that.imgNumber++
        this.canvas = parent.canvas
        this.ctx = parent.ctx
        this.particleColor = returnRandomArrayitem(
          this.network.options.particleColors
        )
        // æŽ§åˆ¶å¤§å°
        this.radius = getLimitedRandom(10, 30)
        this.opacity = 0
        // this.x = x || Math.random() * this.canvas.width;
        // this.y = y || Math.random() * this.canvas.height;
        // æŽ§åˆ¶åˆå§‹åæ ‡ï¼Œä¸è¦è¶…出范围
        this.x = x || getLimitedRandom(50, this.canvas.width - 50)
        this.y = y || getLimitedRandom(50, this.canvas.height - 50)
        this.velocity = {
          x: (Math.random() - 0.5) * parent.options.velocity,
          y: (Math.random() - 0.5) * parent.options.velocity
        }
      }
      Particle.prototype.update = function () {
        if (this.opacity < 0.8) {
          this.opacity += 0.01
        } else {
          this.opacity = 0.8
        }
        // ç§»åŠ¨åˆ°è¾¹ç¼˜æ—¶åå‘
        if (this.x > this.canvas.width - 50 || this.x < 50) {
          this.velocity.x = -this.velocity.x
        }
        if (this.y > this.canvas.height - 50 || this.y < 50) {
          this.velocity.y = -this.velocity.y
        }
        // æ›´æ–°åæ ‡
        this.x += this.velocity.x
        this.y += this.velocity.y
      }
      Particle.prototype.draw = function () {
        // Draw particle
        if (that.destoryed) {
          return
        }
        this.ctx.beginPath()
        this.ctx.fillStyle = this.particleColor
        this.ctx.globalAlpha = this.opacity
        this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI)
        this.ctx.fill()
        var prop = this.radius
        // let imgOdr = parseInt(Math.random() * 16, 10);
        var img = that.$refs['conf' + this.imgNumber]
        this.ctx.drawImage(
          img,
          this.x - this.radius * 0.8,
          this.y - this.radius * 0.8,
          this.radius * 1.6,
          this.radius * 1.6
        )
      }
      var ParticleNetwork = function (parent) {
        this.options = {
          velocity: 1, // the higher the faster
          density: 1500, // the lower the denser
          netLineDistance: 300,
          netLineColor: '#477bec',
          particleColors: ['#7E8BFA'] // ['#6D4E5C', '#aaa', '#FFC458' ]
        }
        this.canvas = parent.canvas
        this.ctx = parent.ctx
        this.init()
      }
      ParticleNetwork.prototype.init = function () {
        // Create particle objects
        this.createParticles(true)
        // Update canvas
        this.animationFrame = requestAnimationFrame(this.update.bind(this))
      }
      ParticleNetwork.prototype.createParticles = function (isInitial) {
        // Initialise / reset particles
        var me = this
        this.particles = []
        // var quantity = this.canvas.width * this.canvas.height / this.options.density;
        var quantity = 17
        if (isInitial) {
          var counter = 0
          clearInterval(this.createIntervalId)
          this.createIntervalId = setInterval(
            function () {
              if (counter < quantity - 1) {
                // Create particle object
                this.particles.push(new Particle(this))
              } else {
                clearInterval(me.createIntervalId)
              }
              counter++
            }.bind(this),
            250
          )
        } else {
          // Create particle objects
          for (var i = 0; i < quantity; i++) {
            this.particles.push(new Particle(this))
          }
        }
      }
      ParticleNetwork.prototype.destory = function (isInitial) {
        clearInterval(this.createIntervalId)
      }
      ParticleNetwork.prototype.update = function () {
        if (this.canvas) {
          this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
          this.ctx.globalAlpha = 1
          // Draw connections
          for (var i = 0; i < this.particles.length; i++) {
            for (var j = this.particles.length - 1; j > i; j--) {
              var distance,
                p1 = this.particles[i],
                p2 = this.particles[j]
              // check very simply if the two points are even a candidate for further measurements
              distance = Math.min(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y))
              if (distance > this.options.netLineDistance) {
                continue
              }
              // the two points seem close enough, now let's measure precisely
              distance = Math.sqrt(
                Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)
              )
              if (distance > this.options.netLineDistance) {
                continue
              }
              this.ctx.beginPath()
              this.ctx.strokeStyle = this.options.netLineColor
              this.ctx.globalAlpha =
                ((this.options.netLineDistance - distance) /
                  this.options.netLineDistance) *
                p1.opacity *
                p2.opacity
              this.ctx.lineWidth = 1.7
              this.ctx.moveTo(p1.x, p1.y)
              this.ctx.lineTo(p2.x, p2.y)
              this.ctx.stroke()
            }
          }
          // Draw particles
          for (var i = 0; i < this.particles.length; i++) {
            this.particles[i].update()
            this.particles[i].draw()
          }
          if (this.options.velocity !== 0) {
            this.animationFrame = requestAnimationFrame(this.update.bind(this))
          }
        } else {
          cancelAnimationFrame(this.animationFrame)
        }
      }
      var getLimitedRandom = function (min, max, roundToInteger) {
        var number = Math.random() * (max - min) + min
        if (roundToInteger) {
          number = Math.round(number)
        }
        return number
      }
      var returnRandomArrayitem = function (array) {
        return array[Math.floor(Math.random() * array.length)]
      }
      var elm = document.getElementsByClassName('particle-network-animation')[0]
      this.pna = new ParticleNetworkAnimation()
      this.pna.init(elm)
    }
  }
}
</script>
<style lang="scss">
.particle-network-animation {
  position: fixed;
  top: 20%;
  left: 0;
  right: 0;
  // background-color: #171717;
}
.particle-network-animation::before {
  z-index: -3;
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-size: cover;
  opacity: 0.2;
}
.glow {
  z-index: -2;
  position: fixed;
  top: 50%;
  left: 50%;
  background-image: radial-gradient(
    circle closest-side,
    rgba(255, 255, 255, 0.025),
    transparent
  );
}
.glow-1 {
  width: 150vw;
  height: 150vh;
  margin-top: -75vh;
  margin-left: -75vw;
  animation: glow-1-move 25s linear infinite both;
}
@keyframes glow-1-move {
  from {
    transform: translate(-100%, 100%);
  }
  to {
    transform: translate(100%, -100%);
  }
}
.glow-2 {
  width: 100vw;
  height: 100vh;
  margin-top: -50vh;
  margin-left: -50vw;
  animation: glow-2-move 25s linear 8.3333333333s infinite both;
}
@keyframes glow-2-move {
  from {
    transform: translate(-100%, 0%);
  }
  to {
    transform: translate(100%, 100%);
  }
}
.glow-3 {
  width: 120vw;
  height: 120vh;
  margin-top: -60vh;
  margin-left: -60vw;
  animation: glow-3-move 25s linear 16.6666666667s infinite both;
}
@keyframes glow-3-move {
  from {
    transform: translate(100%, 100%);
  }
  to {
    transform: translate(0%, -100%);
  }
}
</style>
src/pages/login/api.ts
New file
@@ -0,0 +1,66 @@
import request from '@/scripts/httpRequest'
import qs from 'qs'
// ç™»å½•
export const tologin = (query: any) => {
  // let query = 'username=' + user.loginName + '&password=' + user.password
  return request({
    url: '/data/api-u/sys/login',
    method: 'post',
    data: qs.stringify(query)
  })
}
// é€€å‡º
export const logout = () => {
  return request({
    url: '/data/api-u/sys/logout',
    method: 'get'
  })
}
// èŽ·å–ç”¨æˆ·ä¿¡æ¯
// export const getLoginUserData = () => {
//   let token =
//     sessionStorage.getItem('loginedInfo') &&
//     JSON.parse(sessionStorage.getItem('loginedInfo')).access_token
//   return request({
//     url: '/data/api-u/users/current',
//     method: 'get',
//     headers: {
//       'Content-Type': 'application/x-www-form-urlencoded',
//       Authorization: token || ''
//     }
//   })
// }
export const getLoginUserData = () => {
    let token =
      sessionStorage.getItem('loginedInfo') &&
      JSON.parse(sessionStorage.getItem('loginedInfo')).access_token
    return request({
      url: '/data/api-u/users/profile',
      method: 'get',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        Authorization: token || ''
      }
    })
  }
//修改密码
export const updatePwd = (query: any) => {
  return request({
    url: '/data/api-u/users/updatePwd',
    method: 'post',
    data: qs.stringify(query)
  })
}
//获取项目名称
export const getServerName = (query: any) => {
  return request({
    url: '/data/api-v/info/getServerName',
    method: 'get'
  })
}
src/pages/login/main.ts
New file
@@ -0,0 +1,18 @@
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import '@/assets/css/element-variables.scss'
import i18n from '@/lang'
Vue.use(ElementUI, {
  i18n: (key, value) => i18n.t(key, value),
})
new Vue({
  el: '#app',
  i18n,
  render: (h) => h(App),
})
vue.config.js
@@ -40,8 +40,8 @@
  // }
});
// const serverUrl = "http://192.168.20.189/:7009"; // ç¾Šäº”
const serverUrl = "http://192.168.8.10:7009";
const serverUrl = "http://192.168.20.189:7009"; // ç¾Šäº”
//  const serverUrl = "http://192.168.8.10:7009";
const serverUrl2 = "http://192.168.8.10:9000";
// const serverUrl = "http://192.168.20.10:7009";
// const serverUrl2 = "http://192.168.20.10:9000";