WXL (wul)
昨天 e06cd3953ba8a6e0eee11c235bce9ced419a2800
src/views/loginSSO.vue
@@ -11,82 +11,229 @@
      <div v-else class="loading-content">
        <i class="el-icon-loading"></i>
        <p>单点登录中,请稍候...</p>
        <p class="loading-detail">{{ loadingDetail }}</p>
      </div>
    </div>
  </div>
</template>
<script>
import { setToken } from '@/utils/auth'
import { setToken, removeToken } from "@/utils/auth";
export default {
  name: 'SSORedirect',
  name: "SSORedirect",
  data() {
    return {
      errorMessage: '',
      loading: true
    }
      errorMessage: "",
      loading: true,
      loadingDetail: "正在处理SSO令牌...",
    };
  },
  created() {
    this.handleSSORedirect()
    this.handleSSORedirect();
  },
  methods: {
    // 匹配orgid - 优化为对象映射
    mateOrgid(orgid) {
      const orgMap = {
        "30001002": {
          orgname: "省立同德翠苑院区",
          ZuHuID: "1400361376454545408",
          deptCode: "1017",
        },
        "30001003": {
          orgname: "省立同德之江院区",
          ZuHuID: "1400360867068907520",
          deptCode: "01040201",
        },
        "30001004": {
          orgname: "省立同德闲林院区",
          ZuHuID: "1429338802177000002",
          deptCode: "",
        },
        "30001005": {
          orgname: "省立同德天目山路院区",
          ZuHuID: "1429338802177000003",
          deptCode: "",
        },
        "30001006": {
          orgname: "省立同德青山湖院区",
          ZuHuID: "1429338802177000004",
          deptCode: "",
        },
        "30001007": {
          orgname: "测试院区",
          ZuHuID: "1429338802177000005",
          deptCode: "",
        },
      };
      const orgInfo = orgMap[orgid];
      if (orgInfo) {
        localStorage.setItem("orgname", orgInfo.orgname);
        localStorage.setItem("ZuHuID", orgInfo.ZuHuID);
        localStorage.setItem("deptCode", orgInfo.deptCode);
        return orgInfo;
      }
      return null;
    },
    // 清理旧系统的本地存储
    clearOldSystemData() {
      // 清理可能冲突的旧系统数据
      const oldKeys = ["old-token", "old-user-info", "old-session"];
      oldKeys.forEach((key) => {
        localStorage.removeItem(key);
        sessionStorage.removeItem(key);
      });
      // 清理特定前缀的存储
      Object.keys(localStorage).forEach((key) => {
        if (key.startsWith("old-system-") || key.startsWith("legacy-")) {
          localStorage.removeItem(key);
        }
      });
    },
    // 获取默认重定向路径
    getDefaultRedirectPath() {
      try {
        const roles = this.$store.state.user?.roles || [];
        const username = this.$store.state.user?.name || "";
        if (roles.includes("admin") || username === "admin") {
          return "/index";
        }
        return "/followvisit/discharge";
      } catch (error) {
        console.warn("获取默认重定向路径失败:", error);
        return "/followvisit/discharge";
      }
    },
    // 验证SSO参数
    validateSSOParams(params) {
      const { token, orgid } = params;
      if (!token) {
        throw new Error("缺少认证令牌(token)");
      }
      if (!orgid) {
        console.warn("SSO登录缺少orgid参数");
      }
      // 验证token格式(简单验证)
      if (token.length < 10) {
        throw new Error("令牌格式无效");
      }
      return true;
    },
    // 主处理函数
    async handleSSORedirect() {
      try {
        // 从URL参数中获取token和机构信息
        const { token, orgid, orgname, ZuHuID, deptCode, redirect } = this.$route.query
        console.log("SSO重定向开始处理...");
        // 验证必要参数
        if (!token) {
          throw new Error('缺少认证令牌(token)')
        }
        setToken(token)
        this.$store.commit('SET_TOKEN', token)
        // 1. 获取URL参数
        const params = this.$route.query;
        console.log("SSO参数:", params);
        // 存储机构信息到localStorage
        // 2. 验证必要参数
        this.validateSSOParams(params);
        this.loadingDetail = "验证令牌中...";
        // 3. 清理旧系统数据
        this.clearOldSystemData();
        const { token, orgid, orgname, ZuHuID, deptCode, redirect } = params;
        // 4. 存储token
        setToken(token);
        this.$store.commit("SET_TOKEN", token);
        this.loadingDetail = "设置用户令牌...";
        // 5. 处理机构信息
        if (orgid) {
          localStorage.setItem('orgid', orgid)
          this.$store.dispatch('UpdateOrgId', orgid)
        }
        if (orgname) localStorage.setItem('orgname', orgname)
        if (ZuHuID) localStorage.setItem('ZuHuID', ZuHuID)
        if (deptCode) localStorage.setItem('deptCode', deptCode)
          // 优先使用mateOrgid映射
          const orgInfo = this.mateOrgid(orgid);
          if (!orgInfo) {
            // 如果没有映射,使用传入的参数
            if (orgname) localStorage.setItem("orgname", orgname);
            if (ZuHuID) localStorage.setItem("ZuHuID", ZuHuID);
            if (deptCode) localStorage.setItem("deptCode", deptCode);
          }
        // 获取用户信息
        await this.$store.dispatch('GetInfo')
        // 确定重定向路径
        let redirectPath = '/index'
        if (redirect) {
          redirectPath = decodeURIComponent(redirect)
        } else {
          // 根据用户角色决定默认跳转页面
          const roles = this.$store.state.user.roles
          const username = this.$store.state.user.name
          if (roles.includes('admin') || username === 'admin') {
            redirectPath = '/index'
          } else {
            redirectPath = '/followvisit/discharge'
          localStorage.setItem("orgid", orgid);
          if (this.$store.dispatch && typeof this.$store.dispatch === "function") {
            await this.$store.dispatch("UpdateOrgId", orgid);
          }
        }
        this.loadingDetail = "设置机构信息...";
        // 跳转到目标页面
        this.$router.replace({ path: redirectPath })
        // 6. 获取用户信息
        if (this.$store.dispatch && typeof this.$store.dispatch === "function") {
          await this.$store.dispatch("GetInfo");
        }
        this.loadingDetail = "获取用户信息...";
        // 7. 处理重定向路径
        let redirectPath = "/followvisit/discharge";
        if (redirect) {
          // 解码传入的重定向路径
          try {
            redirectPath = decodeURIComponent(redirect);
            console.log("使用传入的重定向路径:", redirectPath);
          } catch (e) {
            console.error("解码重定向路径失败:", e);
            redirectPath = this.getDefaultRedirectPath();
          }
        } else {
          redirectPath = this.getDefaultRedirectPath();
        }
        // 8. 移除URL中的token参数(安全考虑)
        this.$router.replace({ query: {} });
        // 9. 延迟跳转,确保状态已更新
        setTimeout(() => {
          this.loadingDetail = "跳转到目标页面...";
          console.log("准备跳转到:", redirectPath);
          // ✅ 使用 push 而不是 replace,保留历史记录
          this.$router.push({ path: redirectPath }).then(() => {
            console.log("SSO登录成功,跳转完成");
          }).catch((error) => {
            console.error("路由跳转失败:", error);
            // 回退到默认页面
            this.$router.push({ path: "/followvisit/discharge" });
          });
        }, 500);
      } catch (error) {
        console.error('SSO登录失败:', error)
        this.errorMessage = `单点登录失败: ${error.message || '未知错误'}`
        this.loading = false
        console.error("SSO登录失败:", error);
        this.errorMessage = `单点登录失败: ${error.message || "未知错误"}`;
        this.loading = false;
        // 清理token
        removeToken();
        this.$store.commit("SET_TOKEN", "");
        // 显示错误详情(开发环境)
        if (process.env.NODE_ENV === "development") {
          this.errorMessage += ` (详情: ${error.toString()})`;
        }
        // 5秒后跳转到普通登录页
        setTimeout(() => {
          this.$router.replace('/login')
        }, 5000)
          this.$router.replace("/login");
        }, 5000);
      }
    }
  }
}
    },
  },
};
</script>
<style scoped>
@@ -95,29 +242,73 @@
  justify-content: center;
  align-items: center;
  height: 100vh;
  min-height: 500px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  background-color: #f5f7fa;
  padding: 20px;
  box-sizing: border-box;
}
.loading-container {
  text-align: center;
  padding: 20px;
  background: white;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  padding: 40px 60px;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  min-width: 400px;
  max-width: 500px;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
}
.loading-content {
  padding: 20px;
  padding: 30px 20px;
}
.el-icon-loading {
  font-size: 40px;
  color: #409EFF;
  margin-bottom: 10px;
  font-size: 60px;
  color: #409eff;
  margin-bottom: 20px;
  animation: spin 1.5s linear infinite;
}
p {
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.loading-content p {
  margin: 0;
  color: #606266;
  font-size: 16px;
  line-height: 1.6;
}
.loading-detail {
  margin-top: 10px !important;
  font-size: 14px !important;
  color: #909399 !important;
  opacity: 0.8;
}
/* 响应式设计 */
@media (max-width: 768px) {
  .sso-redirect {
    padding: 10px;
  }
  .loading-container {
    padding: 30px 20px;
    min-width: 300px;
    max-width: 90vw;
  }
  .el-icon-loading {
    font-size: 50px;
  }
  .loading-content p {
    font-size: 15px;
  }
}
</style>