WXL
11 小时以前 05c363fdd7ab04e3bd9a753e2c5d5bfff04d681c
pages/login/Login.vue
@@ -1,16 +1,20 @@
<template>
  <view class="login-container">
    <view v-if="isAutoLogining" class="sso-mask">
      <uni-load-more
        status="loading"
        :content-text="{ contentdown: '自动登录中...' }"
      ></uni-load-more>
    </view>
    <view class="header">
      <image src="/static/avatar/logo.png" class="logo" />
      <text class="hospital-name">青大附院OPO管理平台</text>
    </view>
    <view class="form-container">
      <view class="input-group">
        <uni-icons type="contact" size="24" color="#409EFF" />
        <input v-model="username" placeholder="请输入账号" class="input" />
      </view>
      <view class="input-group">
        <uni-icons type="locked" size="24" color="#409EFF" />
        <input
@@ -26,7 +30,6 @@
          @click="showPassword = !showPassword"
        />
      </view>
      <button
        class="login-btn"
        :class="{ active: username && password }"
@@ -35,11 +38,6 @@
      >
        登录
      </button>
      <!-- <view class="footer-links">
        <view @click="gotoRegister">注册账号</view>
        <view @click="gotoForgetPassword">忘记密码</view>
      </view> -->
    </view>
  </view>
</template>
@@ -59,151 +57,142 @@
const showPassword = ref(false);
const redirect = ref("");
onLoad((options) => {
  console.log("登录页onLoad,完整参数:", options);
  console.log("页面栈:", getCurrentPages());
// tabBar 页面列表(与 pages.json 保持一致)
const tabBarPages = [
  "/pages/index/index",
  "/pages/appointment/index",
  "/pages/consultation/index",
  "/pages/my/index",
];
  // ✅ 获取完整URL参数
  const pages = getCurrentPages();
  if (pages.length > 0) {
    const currentPage = pages[pages.length - 1];
    console.log("当前页面对象:", currentPage);
onLoad(async (options) => {
  console.log("登录页onLoad,原始参数:", options);
  const launchQuery = uni.getLaunchOptionsSync().query || {};
  const allParams = { ...launchQuery, ...options };
  console.log("合并后参数:", allParams);
  // 提取 redirect
  if (allParams.redirect) {
    redirect.value = decodeURIComponent(allParams.redirect);
  }
  // 处理redirect参数
  if (options.redirect) {
    redirect.value = decodeURIComponent(options.redirect);
  } else if (options.userName && options.passWord) {
    // 如果没有redirect但有SSO参数,尝试从referrer获取
    const launchOptions = uni.getLaunchOptionsSync();
    if (launchOptions.referrerInfo && launchOptions.referrerInfo.extraData) {
      const referrer = launchOptions.referrerInfo.extraData;
      console.log("referrer信息:", referrer);
  // ✅ 优先处理 code 免登
  const code = allParams.code;
  if (code) {
    console.log("检测到免登码,开始解析:", code);
    // 显示 loading
    uni.showLoading({ title: "解析免登信息...", mask: true });
    try {
      // 调用解析接口
      const res = await uni.$uapi.get("/GiLink/getCode", { code });
      uni.hideLoading();
      console.log(res.data);
      res.data.passWord = res.data.userPhone;
      if (!res.data || !res.data.userName || !res.data.passWord) {
        throw new Error("解析免登码失败");
      }
      let obj = JSON.parse(res.data.extContent);
      // const { userName, passWord, ...otherParams } = res;
      console.log(res.data.userName);
      const userName = res.data.userName;
      const passWord = res.data.passWord;
      const otherParams = {
        id: obj.infoId,
        type: obj.type,
        status: obj.status,
        fcid: obj.id,
      };
      console.log("解析结果:", { userName, otherParams });
      // 清除可能存在的旧 token
      if (getToken()) uni.removeStorageSync("token");
      // 执行 SSO 登录,并将其他业务参数传递下去
      await handleSSOLogin(userName, passWord, otherParams);
    } catch (err) {
      uni.hideLoading();
      console.error("免登码解析失败:", err);
      uni.showToast({ title: "免登录失败,请手动登录", icon: "none" });
    }
  }
  // 检查是否已有token
  if (getToken()) {
    console.log("已存在token,直接跳转");
    setTimeout(() => {
      navigateToTarget();
    }, 100);
    return;
  }
  // ✅ SSO登录:检查所有可能的参数位置
  let ssoUserName = options.userName;
  let ssoPassWord = options.passWord;
  // 如果没有从options获取到,尝试从启动参数获取
  if (!ssoUserName || !ssoPassWord) {
    const launchOptions = uni.getLaunchOptionsSync();
    if (launchOptions.query) {
      ssoUserName = ssoUserName || launchOptions.query.userName;
      ssoPassWord = ssoPassWord || launchOptions.query.passWord;
    }
  // 原有逻辑:无 code 且已有 token 跳转目标页
  if (getToken()) {
    setTimeout(() => navigateToTarget(), 100);
    return;
  }
  if (ssoUserName && ssoPassWord) {
    console.log("检测到SSO参数,自动登录", { ssoUserName });
    // 合并所有页面参数
    const pageParams = { ...options };
    delete pageParams.userName;
    delete pageParams.passWord;
    delete pageParams.redirect;
    handleSSOLogin(ssoUserName, ssoPassWord, pageParams);
  } else {
    // 普通登录
    password.value = "";
    username.value = "";
  }
  // 普通登录,清空表单
  username.value = "";
  password.value = "";
});
onShow(() => {
  console.log("登录页onShow");
  if (hasAutoLogin) {
    hasAutoLogin = false;
  }
  if (hasAutoLogin) hasAutoLogin = false;
});
// ✅ 改进的SSO登录函数
/**
 * SSO 免登
 */
const handleSSOLogin = async (userName, passWord, pageParams = {}) => {
  if (isAutoLogining) {
    console.log("正在自动登录中,跳过");
    return;
  }
  if (isAutoLogining) return;
  isAutoLogining = true;
  console.log("开始SSO免登:", { userName, pageParams });
  uni.showLoading({ title: "自动登录中...", mask: true });
  try {
    console.log(11);
    // 1. 获取token
    const tokenRes = await uni.$uapi.post("/getToken", {
      userName,
      passWord,
    });
    console.log(tokenRes.data);
    const tokenRes = await uni.$uapi.post("/getToken", { userName, passWord });
    uni.hideLoading();
    if (!tokenRes.data.token) {
      throw new Error("获取token失败");
    }
    if (!tokenRes.data?.token) throw new Error("获取token失败");
    console.log("获取到token成功");
    // 2. 保存token
    setToken(tokenRes.data.token);
    // 3. 获取用户信息
    const userStore = useUserStore();
    const userInfo = await uni.$uapi.get("/getInfo");
    if (userInfo) {
      userStore.setUserInfo(userInfo);
    if (userInfo && userInfo.user) {
      userStore.setUserInfo(userInfo.user);
      if (userInfo.roles) userStore.setroleKey(userInfo.roles);
    }
    // 4. 构建目标页面URL
    // 确定目标页面
    let targetPage = redirect.value;
    if (!targetPage && Object.keys(pageParams).length > 0) {
      // 尝试从原始访问路径构建
    if (!targetPage) {
      const launchOptions = uni.getLaunchOptionsSync();
      if (launchOptions.path && !launchOptions.path.includes("login/Login")) {
        targetPage = "/" + launchOptions.path;
      const originalPath = launchOptions.path;
      if (originalPath && !originalPath.includes("login/Login")) {
        targetPage = "/" + originalPath;
      }
    }
    if (!targetPage) targetPage = "/pages/index/index";
    // 5. 跳转
    hasAutoLogin = true;
    // 跳转时携带 pageParams(业务参数)
    await navigateToTargetPage(targetPage, pageParams);
  } catch (err) {
    uni.hideLoading();
    console.error("SSO免登失败:", err);
    uni.showToast({
      title: "自动登录失败,请手动登录",
      title: err.message || "自动登录失败,请手动登录",
      icon: "none",
      duration: 3000,
    });
    uni.removeStorageSync("token");
  } finally {
    isAutoLogining = false;
  }
};
// 普通登录
/**
 * 普通登录
 */
const handleLogin = async () => {
  try {
    if (!username.value || !password.value) {
      uni.showToast({ title: "请输入账号密码", icon: "none" });
      return;
    }
    uni.showLoading({ title: "登录中...", mask: true });
    const userStore = useUserStore();
@@ -215,15 +204,14 @@
      password: encryptedPassword,
    });
    if (!loginRes || !loginRes.token) {
      throw new Error("登录失败");
    }
    if (!loginRes || !loginRes.token) throw new Error("登录失败");
    setToken(loginRes.token);
    const userInfo = await uni.$uapi.get("/getInfo");
    if (userInfo) {
      userStore.setUserInfo(userInfo);
    if (userInfo && userInfo.user) {
      userStore.setUserInfo(userInfo.user);
      if (userInfo.roles) userStore.setroleKey(userInfo.roles);
    }
    uni.hideLoading();
@@ -239,65 +227,67 @@
  }
};
// ✅ 改进的跳转函数
/**
 * 根据 redirect 跳转
 */
const navigateToTarget = () => {
  return navigateToTargetPage(redirect.value, {});
  if (redirect.value) {
    return navigateToTargetPage(redirect.value, {});
  } else {
    console.log("没有目标页面,跳转首页");
    uni.switchTab({ url: "/pages/index/index" });
    return Promise.resolve(true);
  }
};
/**
 * 通用跳转函数
 * @param {string} targetPage 目标页面路径
 * @param {object} pageParams 附加参数
 */
const navigateToTargetPage = (targetPage, pageParams = {}) => {
  return new Promise((resolve) => {
    if (!targetPage) {
      console.log("目标页为空,跳转首页");
      uni.switchTab({ url: "/pages/index/index" });
      resolve(true);
      return;
    }
    let finalUrl = targetPage;
    const paramKeys = Object.keys(pageParams).filter(
      (key) => pageParams[key] !== undefined && pageParams[key] !== null,
    );
    if (paramKeys.length > 0) {
      const queryStr = paramKeys
        .map((key) => `${key}=${encodeURIComponent(pageParams[key])}`)
        .join("&");
      finalUrl += (finalUrl.includes("?") ? "&" : "?") + queryStr + "&sso=1";
    }
    console.log("最终跳转目标URL:", finalUrl);
    const baseUrl = finalUrl.split("?")[0];
    const isTabBar = tabBarPages.includes(baseUrl);
    setTimeout(() => {
      let targetUrl = targetPage || "/pages/index/index";
      // 处理页面参数
      const paramKeys = Object.keys(pageParams).filter(
        (key) =>
          pageParams[key] !== undefined &&
          pageParams[key] !== null &&
          key !== "userName" &&
          key !== "passWord" &&
          key !== "redirect",
      );
      if (paramKeys.length > 0) {
        const queryStr = paramKeys
          .map((key) => `${key}=${encodeURIComponent(pageParams[key])}`)
          .join("&");
        targetUrl = targetUrl.includes("?")
          ? `${targetUrl}&${queryStr}`
          : `${targetUrl}?${queryStr}`;
      }
      console.log("最终跳转目标:", targetUrl);
      const tabBarPages = [
        "/pages/index/index",
        "/pages/appointment/index",
        "/pages/consultation/index",
        "/pages/my/index",
      ];
      const baseUrl = targetUrl.split("?")[0];
      const isTabBar = tabBarPages.includes(baseUrl);
      if (isTabBar) {
        uni.switchTab({
          url: baseUrl,
          success: () => resolve(true),
          fail: () => {
            uni.redirectTo({ url: "/pages/index/index" });
          fail: (err) => {
            console.error("switchTab失败:", err);
            uni.switchTab({ url: "/pages/index/index" });
            resolve(false);
          },
        });
      } else {
        uni.redirectTo({
          url: targetUrl,
          url: finalUrl,
          success: () => resolve(true),
          fail: (err) => {
            console.error("跳转失败:", err);
            // 如果目标页跳转失败,跳首页
            uni.redirectTo({ url: "/pages/index/index" });
            console.error("redirectTo失败:", err);
            uni.switchTab({ url: "/pages/index/index" });
            resolve(false);
          },
        });
@@ -313,6 +303,20 @@
  background: linear-gradient(to bottom, #e6f7ff, #ffffff);
  height: 100vh;
  box-sizing: border-box;
  position: relative;
}
.sso-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}
.header {
@@ -381,16 +385,5 @@
.button-hover {
  opacity: 0.8;
}
.footer-links {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  text-align: center;
  margin-top: 30rpx;
  color: #1890ff;
  font-size: 28rpx;
  width: 100%;
}
</style>