陈婷婷
2026-01-26 ce24f31ca213fd677b02a6e08235bbddf269f4f7
tms登录页面
2个文件已添加
6个文件已修改
707 ■■■■■ 已修改文件
.env.development 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/permission.js 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/loginSource.js 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login.vue 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/loginTMS.vue 608 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -6,9 +6,9 @@
# 智云迈思L-MOM管理系统/开发环境
# VUE_APP_BASE_API = http://localhost:81/API/
# VUE_APP_BASE_API = 'http://47.96.97.237/API/'
VUE_APP_BASE_API = 'http://47.96.97.237/API/'
# VUE_APP_BASE_API = 'http://220.189.218.155:9010/API/'
VUE_APP_BASE_API = 'http://localhost:8082/LuBaoAPI/'
# VUE_APP_BASE_API = 'http://localhost:8082/LuBaoAPI/'
#锦隆
# # VUE_APP_BASE_API_INNER = 'http://192.168.1.11/API/'
# # VUE_APP_BASE_API = http://61.174.29.234:8880/API/
src/permission.js
@@ -7,10 +7,12 @@
import { isPathMatch } from "@/utils/validate";
import { isRelogin } from "@/utils/request";
NProgress.configure({ showSpinner: false });
const whiteList = [
  "/login",
  "/loginTMS",
  "/register",
  "/printList",
  "/hBarPlanPrint",
@@ -51,6 +53,7 @@
        // 判断当前用户是否已拉取完user_info信息
        store .dispatch("GetInfo").then(() => {
            isRelogin.show = false;
            store.dispatch("GenerateRoutes").then((accessRoutes) => {
              // 根据roles权限生成可访问的路由表
              router.addRoutes(accessRoutes); // 动态添加可访问路由表
src/router/index.js
@@ -86,7 +86,13 @@
    hidden: true,
  },
  //#endregion
  //#region 登录TMS
  {
    path: "/loginTMS",
    component: () => import("@/views/loginTMS"),
    hidden: true,
  },
  //#endregion
  //#region 注册
  {
    path: "/register",
src/store/modules/permission.js
@@ -4,7 +4,7 @@
import Layout from "@/layout/index";
import ParentView from "@/components/ParentView";
import InnerLink from "@/layout/components/InnerLink";
import { getLoginPageSource } from "@/utils/loginSource"; // 导入登录来源判断工具
const permission = {
  state: {
    routes: [],
@@ -31,6 +31,10 @@
  actions: {
    // 生成路由
    GenerateRoutes({ commit }) {
      // 示例:根据登录来源执行不同的逻辑
      const loginSource = getLoginPageSource();
      console.log(`用户从 ${loginSource} 页面登录`);
      return new Promise((resolve) => {
        // 向后端请求路由数据
        let data = [
@@ -88,21 +92,24 @@
                path: "WayBillPaymentBill",
                redirect: "noRedirect",
                component: "Layout",
                children: [{
                  meta: {
                    icon: "build",
                    link: null,
                    noCache: false,
                    title: "运单费用结算单",
                children: [
                  {
                    meta: {
                      icon: "build",
                      link: null,
                      noCache: false,
                      title: "运单费用结算单",
                    },
                    component: () =>
                      import(
                        "@/views/logistics/WayBillPaymentBill/Pay_WayBillPaymentBillList.vue"
                      ),
                    hidden: false,
                    name: "payWayBillPaymentBillList",
                    path: "PayWayBillPaymentBillList",
                  },
                  component: () =>
                    import("@/views/logistics/WayBillPaymentBill/Pay_WayBillPaymentBillList.vue"),
                  hidden: false,
                  name: "payWayBillPaymentBillList",
                  path: "PayWayBillPaymentBillList",
                }
                ]
              }
                ],
              },
            ],
          },
          {
src/store/modules/user.js
@@ -48,9 +48,13 @@
      // const code = userInfo.code
      // const uuid = userInfo.uuid
      const HOrgName = userInfo.HOrgName;
      const loginPage = userInfo.loginPage || 'login'; // 添加登录页面来源标记
      return new Promise((resolve, reject) => {
        login(username, password, HOrgName)
          .then((res) => {
            // 存储登录页面来源
            sessionStorage["loginPage"] = loginPage;
            sessionStorage["OrganizationID"] = userInfo.HOrgName;
            sessionStorage["Organization"] = userInfo.Organization;
            sessionStorage["HTranSlate"] = userInfo.HTranSlate;
src/utils/loginSource.js
New file
@@ -0,0 +1,38 @@
// 判断登录来源的工具函数
/**
 * 获取登录页面来源
 * @returns {string} 返回 'login' 或 'loginTMS'
 */
export function getLoginPageSource() {
  return sessionStorage.getItem('loginPage') || 'login';
}
/**
 * 判断是否来自TMS登录页面
 * @returns {boolean} 如果是TMS登录页面返回true,否则返回false
 */
export function isFromTMSLogin() {
  return getLoginPageSource() === 'loginTMS';
}
/**
 * 判断是否来自普通登录页面
 * @returns {boolean} 如果是普通登录页面返回true,否则返回false
 */
export function isFromNormalLogin() {
  return getLoginPageSource() === 'login';
}
/**
 * 根据登录来源执行不同的逻辑
 * @param {Function} tmsCallback - 来自TMS登录时的回调函数
 * @param {Function} normalCallback - 来自普通登录时的回调函数
 */
export function executeByLoginSource(tmsCallback, normalCallback) {
  if (isFromTMSLogin()) {
    tmsCallback && tmsCallback();
  } else {
    normalCallback && normalCallback();
  }
}
src/views/login.vue
@@ -203,7 +203,10 @@
            Cookies.remove("password")
            Cookies.remove('rememberMe')
          }
          this.$store.dispatch("Login", this.loginForm).then(res => {
          this.$store.dispatch("Login", {
            ...this.loginForm,
            loginPage: 'login'  // 添加登录页面来源标记
          }).then(res => {
            this.$router.push({ path: this.redirect || "/" }).catch(() => { })
          }).catch(() => {
            this.loading = false
src/views/loginTMS.vue
New file
@@ -0,0 +1,608 @@
<template>
  <div class="login-container">
    <div class="login-bg">
      <div class="bg-overlay"></div>
      <div class="floating-shapes">
        <div class="shape shape-1"></div>
        <div class="shape shape-2"></div>
        <div class="shape shape-3"></div>
        <div class="shape shape-4"></div>
      </div>
    </div>
    <div class="login-content">
      <div class="login-card">
        <div class="login-header">
          <div class="logo-container">
            <div class="logo-icon">
              <i class="el-icon-truck"></i>
            </div>
          </div>
          <h3 class="title" v-if="!loginForm.HLogoLabel">智云迈思L-MOM管理系统</h3>
          <h3 class="title" v-else>{{ loginForm.HLogoLabel }}</h3>
          <p class="subtitle">运输管理系统</p>
        </div>
        <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
          <div class="form-group">
            <label class="form-label">语言</label>
            <el-select v-model="loginForm.HTranSlate" :placeholder="languageSel" @change="languageChange" class="custom-select">
              <el-option v-for="item in tranSlateList" :key="item.value" :label="item.label" :value="item.value">
              </el-option>
            </el-select>
          </div>
          <div class="form-group">
            <label class="form-label">组织</label>
            <el-select v-model="loginForm.HOrgName" placeholder="请选择" @change="OrgChange" class="custom-select">
              <el-option v-for="item in organizationList" :key="item.ID" :label="item.Name" :value="item.ID">
              </el-option>
            </el-select>
          </div>
          <div class="form-group">
            <el-form-item prop="username">
              <div class="input-wrapper">
                <div class="input-icon">
                  <i class="el-icon-user"></i>
                </div>
                <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号" class="custom-input">
                </el-input>
              </div>
            </el-form-item>
          </div>
          <div class="form-group">
            <el-form-item prop="password">
              <div class="input-wrapper">
                <div class="input-icon">
                  <i class="el-icon-lock"></i>
                </div>
                <el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码"
                  @keyup.enter.native="handleLogin" class="custom-input">
                </el-input>
              </div>
            </el-form-item>
          </div>
          <div class="form-group" v-if="captchaEnabled">
            <el-form-item prop="code">
              <div class="captcha-wrapper">
                <div class="input-wrapper">
                  <div class="input-icon">
                    <i class="el-icon-key"></i>
                  </div>
                  <el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码"
                    @keyup.enter.native="handleLogin" class="custom-input captcha-input">
                  </el-input>
                </div>
                <div class="captcha-image" @click="getCode">
                  <img :src="codeUrl" alt="验证码" />
                </div>
              </div>
            </el-form-item>
          </div>
          <div class="form-options">
            <el-checkbox v-model="loginForm.rememberMe" class="remember-me">记住密码</el-checkbox>
          </div>
          <div class="form-actions">
            <el-button :loading="loading" class="login-btn" @click.native.prevent="handleLogin">
              <span v-if="!loading">登 录</span>
              <span v-else>登 录 中...</span>
            </el-button>
            <div class="register-link" v-if="register">
              <router-link :to="'/register'">立即注册</router-link>
            </div>
          </div>
        </el-form>
      </div>
    </div>
    <!--  底部  -->
    <div class="login-footer">
      <span>Copyright © 2025 All Rights Reserved.</span>
    </div>
  </div>
</template>
<script>
import { getCodeImg, getOrganizations, webBaseInfo, webGetDataBases } from "@/api/login"
import Cookies from "js-cookie"
import { encrypt, decrypt } from '@/utils/jsencrypt'
export default {
  name: "Login",
  data() {
    return {
      tranSlateList: [{ label: '中文', value: '1' }, { label: 'Eeglish', value: '2' }, { label: 'Spanish', value: '3' },],
      tranData: {},
      languageSel: '语言',
      organizationList: [],//组织列表
      title: process.env.VUE_APP_TITLE,
      codeUrl: "",
      loginForm: {
        username: "",
        password: "",
        rememberMe: false,
        HOrgName: 1,
        code: "",
        uuid: "",
        HTranSlate: '1',
        HLogoLabel: '智云迈思L-MOM管理系统',
        HMenuLabel: null,
        HCusName: null,
        Organization: null,
      },
      loginRules: {
        username: [
          { required: true, trigger: "blur", message: "请输入您的账号" }
        ],
        password: [
          { required: true, trigger: "blur", message: "请输入您的密码" }
        ],
        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
      },
      loading: false,
      // 验证码开关
      captchaEnabled: false,
      // 注册开关
      register: false,
      redirect: undefined
    }
  },
  watch: {
    $route: {
      handler: function (route) {
        this.redirect = route.query && route.query.redirect
      },
      immediate: true
    }
  },
  created() {
    // this.getCode()
    this.getInfoData()
    this.getCookie()
  },
  methods: {
    //语言的选择
    languageChange() {
      this.loginForm.HCusName = this.tranData.HCusName
      if (this.loginForm.HTranSlate == "1" || !this.loginForm.HTranSlate) {
        this.loginForm.HLogoLabel = this.tranData.HLogoLabel;
        this.loginForm.HMenuLabel = this.tranData.HMenuLabel;
      } else if (this.loginForm.HTranSlate == "2") {
        this.loginForm.HLogoLabel = this.tranData.HLogoTranslationText_English;
        this.loginForm.HMenuLabel = this.tranData.HMenuTranslationText_English;
      } else if (this.loginForm.HTranSlate == "3") {
        this.loginForm.HLogoLabel = this.tranData.HLogoTranslationText_Spain;
        this.loginForm.HMenuLabel = this.tranData.HMenuTranslationText_Spain;
      }
    },
    OrgChange(val) {
      this.organizationList.map(item => {
        if (item.ID == val) {
          this.loginForm.Organization = item.Name
        }
      })
    },
    //数据
    getInfoData() {
      //组织列表
      getOrganizations().then(res => {
        if (res.count == 1) {
          this.organizationList = res.data
          sessionStorage[this.organizationList] = res.data;
          this.$nextTick(() => {
            this.OrgChange(this.loginForm.HOrgName)
          })
        }
      })
      //语言
      webBaseInfo().then(res => {
        if (res.count == 1) {
          this.tranData = res.data[0];
          this.$nextTick(() => {
            this.languageChange()
          })
        }
      })
      //数据库
      webGetDataBases().then(res => {
        if (res.count == 1) {
          sessionStorage["数据库"] = res.data[0].Name
        }
      })
    },
    getCode() {
      getCodeImg().then(res => {
        this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
        if (this.captchaEnabled) {
          this.codeUrl = "data:image/gif;base64," + res.img
          this.loginForm.uuid = res.uuid
        }
      })
    },
    getCookie() {
      const username = Cookies.get("username")
      const password = Cookies.get("password")
      const HOrgName = Cookies.get('HOrgName')
      const HTranSlate = Cookies.get('HTranSlate')
      const rememberMe = Cookies.get('rememberMe')
      this.loginForm = {
        HOrgName: HOrgName === undefined ? this.loginForm.HOrgName - 0 : HOrgName - 0,
        username: username === undefined ? this.loginForm.username : username,
        password: password === undefined ? this.loginForm.password : decrypt(password),
        HTranSlate: HTranSlate === undefined ? this.loginForm.HTranSlate : HTranSlate,
        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
      }
    },
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          if (this.loginForm.rememberMe) {
            Cookies.set("HTranSlate", this.loginForm.HTranSlate, { expires: 30 })
            Cookies.set("HOrgName", this.loginForm.HOrgName, { expires: 30 })
            Cookies.set("username", this.loginForm.username, { expires: 30 })
            Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 })
            Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
          } else {
            Cookies.remove("HTranSlate")
            Cookies.remove("HOrgName")
            Cookies.remove("username")
            Cookies.remove("password")
            Cookies.remove('rememberMe')
          }
          this.$store.dispatch("Login", {
            ...this.loginForm,
            loginPage: 'loginTMS'  // 添加登录页面来源标记
          }).then(res => {
            this.$router.push({ path: this.redirect || "/" }).catch(() => { })
          }).catch(() => {
            this.loading = false
            if (this.captchaEnabled) {
              this.getCode()
            }
          })
        }
      })
    }
  },
}
</script>
<style rel="stylesheet/scss" lang="scss">
.login-container {
  position: relative;
  height: 100vh;
  overflow: hidden;
  font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.login-bg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #1a3a8f 0%, #0d1b4e 100%);
  z-index: 1;
}
.bg-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: url("../assets/images/login-background.jpg") no-repeat center center;
  background-size: cover;
  opacity: 0.2;
}
.floating-shapes {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  z-index: 1;
}
.shape {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.05);
  animation: float 20s infinite ease-in-out;
}
.shape-1 {
  width: 80px;
  height: 80px;
  top: 20%;
  left: 10%;
  animation-delay: 0s;
}
.shape-2 {
  width: 120px;
  height: 120px;
  top: 60%;
  right: 10%;
  animation-delay: 2s;
}
.shape-3 {
  width: 60px;
  height: 60px;
  bottom: 20%;
  left: 30%;
  animation-delay: 4s;
}
.shape-4 {
  width: 100px;
  height: 100px;
  top: 10%;
  right: 30%;
  animation-delay: 6s;
}
@keyframes float {
  0%, 100% {
    transform: translateY(0) rotate(0deg);
  }
  50% {
    transform: translateY(-20px) rotate(180deg);
  }
}
.login-content {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  z-index: 2;
}
.login-card {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border-radius: 16px;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
  width: 420px;
  padding: 40px;
  transition: all 0.3s ease;
  &:hover {
    transform: translateY(-5px);
    box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
  }
}
.login-header {
  text-align: center;
  margin-bottom: 30px;
}
.logo-container {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}
.logo-icon {
  width: 70px;
  height: 70px;
  background: linear-gradient(135deg, #1a3a8f 0%, #0d1b4e 100%);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 32px;
  box-shadow: 0 8px 16px rgba(26, 58, 143, 0.3);
}
.title {
  margin: 0 0 8px 0;
  font-size: 24px;
  font-weight: 600;
  color: #1a3a8f;
}
.subtitle {
  margin: 0;
  font-size: 14px;
  color: #666;
  font-weight: 400;
}
.login-form {
  .form-group {
    margin-bottom: 20px;
    .form-label {
      display: block;
      margin-bottom: 8px;
      font-size: 14px;
      color: #333;
      font-weight: 500;
    }
  }
  .custom-select {
    width: 100%;
    .el-input__inner {
      height: 46px;
      line-height: 46px;
      border-radius: 8px;
      border: 1px solid #e0e0e0;
      transition: all 0.3s ease;
      &:focus {
        border-color: #1a3a8f;
        box-shadow: 0 0 0 2px rgba(26, 58, 143, 0.2);
      }
    }
  }
  .input-wrapper {
    position: relative;
    display: flex;
    align-items: center;
  }
  .input-icon {
    position: absolute;
    left: 15px;
    z-index: 1;
    color: #999;
    font-size: 18px;
  }
  .custom-input {
    .el-input__inner {
      height: 46px;
      line-height: 46px;
      padding-left: 45px;
      border-radius: 8px;
      border: 1px solid #e0e0e0;
      transition: all 0.3s ease;
      &:focus {
        border-color: #1a3a8f;
        box-shadow: 0 0 0 2px rgba(26, 58, 143, 0.2);
      }
    }
  }
  .captcha-wrapper {
    display: flex;
    gap: 10px;
    .captcha-input {
      flex: 1;
    }
    .captcha-image {
      width: 100px;
      height: 46px;
      border-radius: 8px;
      overflow: hidden;
      cursor: pointer;
      border: 1px solid #e0e0e0;
      transition: all 0.3s ease;
      &:hover {
        border-color: #1a3a8f;
      }
      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    }
  }
  .form-options {
    margin-bottom: 25px;
    .remember-me {
      .el-checkbox__label {
        font-size: 14px;
        color: #666;
      }
    }
  }
  .form-actions {
    .login-btn {
      width: 100%;
      height: 46px;
      background: linear-gradient(135deg, #1a3a8f 0%, #0d1b4e 100%);
      border: none;
      border-radius: 8px;
      font-size: 16px;
      font-weight: 500;
      transition: all 0.3s ease;
      &:hover {
        background: linear-gradient(135deg, #0d1b4e 0%, #1a3a8f 100%);
        transform: translateY(-2px);
        box-shadow: 0 8px 16px rgba(26, 58, 143, 0.3);
      }
      &:active {
        transform: translateY(0);
      }
    }
    .register-link {
      text-align: center;
      margin-top: 15px;
      a {
        color: #1a3a8f;
        font-size: 14px;
        text-decoration: none;
        transition: all 0.3s ease;
        &:hover {
          color: #0d1b4e;
          text-decoration: underline;
        }
      }
    }
  }
}
.login-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  text-align: center;
  padding: 15px 0;
  color: rgba(255, 255, 255, 0.7);
  font-size: 12px;
  z-index: 2;
}
/* 响应式设计 */
@media (max-width: 768px) {
  .login-card {
    width: 90%;
    margin: 0 20px;
    padding: 30px 20px;
  }
  .title {
    font-size: 20px;
  }
  .subtitle {
    font-size: 12px;
  }
  .logo-icon {
    width: 60px;
    height: 60px;
    font-size: 28px;
  }
}
@media (max-width: 480px) {
  .login-card {
    width: 95%;
    padding: 20px 15px;
  }
  .captcha-wrapper {
    flex-direction: column;
    .captcha-image {
      width: 100%;
      height: 46px;
    }
  }
}
</style>