Browse Source

feature:去掉钉钉登录相关代码,增加微信免登录

liuzhenlin 1 week ago
parent
commit
dff22275fb
12 changed files with 394 additions and 943 deletions
  1. 0 5
      .env.development
  2. 0 4
      .env.production
  3. 6 26
      App.vue
  4. 2 2
      README.md
  5. 1 6
      api/system/login.ts
  6. 313 800
      package-lock.json
  7. 0 1
      package.json
  8. 5 5
      pages/home/index.vue
  9. 41 14
      pages/login/index.vue
  10. 23 24
      pages/login/index1.vue
  11. 3 28
      store/modules/user.ts
  12. 0 28
      utils/dingtalk.ts

+ 0 - 5
.env.development

@@ -14,11 +14,6 @@ VITE_ADMIN = dashoo.labsop.admin-54000
 VITE_SCIENTIFIC = dashoo.labsop.scientific-54000
 VITE_SCIENTIFIC = dashoo.labsop.scientific-54000
 VITE_WORKFLOW = dashoo.labsop.workflow-54000
 VITE_WORKFLOW = dashoo.labsop.workflow-54000
 
 
-# 钉钉corpId
-VITE_DINGTALK_CORPID=dinga8b316209f5ee42435c2f4657eb6378f
-# 钉钉clientId (AppKey)
-VITE_DINGTALK_CLIENTID=
-
 VITE_SECRET = def456
 VITE_SECRET = def456
 
 
 # 租户ID 
 # 租户ID 

+ 0 - 4
.env.production

@@ -14,10 +14,6 @@ VITE_ADMIN = dashoo.labsop.admin-54000
 VITE_SCIENTIFIC = dashoo.labsop.scientific-54000
 VITE_SCIENTIFIC = dashoo.labsop.scientific-54000
 VITE_WORKFLOW = dashoo.labsop.workflow-54000
 VITE_WORKFLOW = dashoo.labsop.workflow-54000
 
 
-# 钉钉配置
-VITE_DINGTALK_CORPID = dinga8b316209f5ee42435c2f4657eb6378f
-VITE_DINGTALK_CLIENTID = dingo2thrapshzkv6uny
-
 VITE_SECRET = def456
 VITE_SECRET = def456
 
 
 # 租户ID 
 # 租户ID 

+ 6 - 26
App.vue

@@ -1,38 +1,18 @@
 <script setup>
 <script setup>
 import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
 import { onLaunch, onShow, onHide } from '@dcloudio/uni-app';
 import { useUserStore } from '@/store/modules/user';
 import { useUserStore } from '@/store/modules/user';
-import { getDingTalkAuthCode } from '@/utils/dingtalk';
-import * as dd from 'dingtalk-jsapi';
 
 
 const userStore = useUserStore();
 const userStore = useUserStore();
 
 
 onLaunch(async (options) => {
 onLaunch(async (options) => {
   console.log('App Launch');
   console.log('App Launch');
-  
-  // 仅在钉钉环境下尝试免登
-  if (dd.env.platform !== 'notInDingTalk') {
-    // 如果没有 token,或者用户信息为空,尝试免登
-    if (!userStore.token) {
-      userStore.setRequestLoading('isLogining', true);
-      try {
-        const corpId = options?.query?.corpId || import.meta.env.VITE_DINGTALK_CORPID;
-        const code = await getDingTalkAuthCode(corpId);
-        if (code) {
-          console.log('Got DingTalk AuthCode, logging in...', code);
-          await userStore.dingTalkLogin(code);
-          console.log('DingTalk Login Success');
-        }
-      } catch (err) {
-        console.error('DingTalk Auto Login Failed:', err);
-        // 如果免登失败(通常是没找到用户),则跳转注册页面
-        uni.reLaunch({ url: '/pages/login/index' });
-      } finally {
-        userStore.setRequestLoading('isLogining', false);
-      }
+
+  // 未登录时仅引导到登录页;如果当前启动携带 `code`(企业微信免登回调),让登录页自行处理
+  if (!userStore.token) {
+    const launchCode = options?.query?.code;
+    if (!launchCode) {
+      uni.reLaunch({ url: '/pages/login/index' });
     }
     }
-  } else if (!userStore.token) {
-    // 不在钉钉环境下且没登录,也引导去注册或者登录跳转(暂统一引导至注册或默认逻辑)
-    uni.reLaunch({ url: '/pages/login/index' });
   }
   }
 });
 });
 
 

+ 2 - 2
README.md

@@ -1,6 +1,6 @@
 # labsop_scientific_h5 移动端 温岭项目
 # labsop_scientific_h5 移动端 温岭项目
 
 
-基于 Vue 3 + Vite + Pinia + UniApp 框架研发的科研实验系统(钉钉小程序/移动端)。
+基于 Vue 3 + Vite + Pinia + UniApp 框架研发的科研实验系统(移动端)。
 
 
 ## 技术栈
 ## 技术栈
 
 
@@ -37,7 +37,7 @@
 1. **导入项目**:打开 HBuilderX,选择引入本项目(文件 -> 导入 -> 从本地目录导入)。
 1. **导入项目**:打开 HBuilderX,选择引入本项目(文件 -> 导入 -> 从本地目录导入)。
 2. **下载依赖**:在项目根目录打开终端执行 `npm install`。
 2. **下载依赖**:在项目根目录打开终端执行 `npm install`。
 3. **运行模式**:
 3. **运行模式**:
-   - 点击 HBuilderX 顶部菜单栏 `运行` -> `运行到内置浏览器` 或对应的 **钉钉小程序开发者工具** 进行预览和联调。
+   - 点击 HBuilderX 顶部菜单栏 `运行` -> `运行到内置浏览器` 或对应的平台开发者工具进行预览和联调。
 4. **发行编译**:
 4. **发行编译**:
    - 点击 HBuilderX 顶部菜单栏 `发行` -> 对应的平台生成最终代码。
    - 点击 HBuilderX 顶部菜单栏 `发行` -> 对应的平台生成最终代码。
 
 

+ 1 - 6
api/system/login.ts

@@ -26,11 +26,6 @@ export function useLoginApi() {
       return microRequest.postRequest(basePath, 'System', 'GetCaptchaImg');
       return microRequest.postRequest(basePath, 'System', 'GetCaptchaImg');
     },
     },
 
 
-    // 钉钉免登接口
-    dingTalkLogin: (data: { code: string }) => {
-      return microRequest.postRequest(basePath, 'DingDingApi', 'GetUserInfoByCode', data);
-    },
-
     register: (query?: object) => {
     register: (query?: object) => {
       return microRequest.postRequest(basePath, 'Personnel', 'RegisterPersonnel', query);
       return microRequest.postRequest(basePath, 'Personnel', 'RegisterPersonnel', query);
     },
     },
@@ -44,7 +39,7 @@ export function useLoginApi() {
       return microRequest.postRequest(basePath, 'Personnel', 'GeneratePassword');
       return microRequest.postRequest(basePath, 'Personnel', 'GeneratePassword');
     },
     },
 
 
-    // 钉钉免登接口
+    // 企业微信免登接口
     oAuthLogin(query: { code: string }) {
     oAuthLogin(query: { code: string }) {
       return microRequest.postRequest(basePath, 'System', 'QWechatLogin', query)
       return microRequest.postRequest(basePath, 'System', 'QWechatLogin', query)
     },
     },

File diff suppressed because it is too large
+ 313 - 800
package-lock.json


+ 0 - 1
package.json

@@ -14,7 +14,6 @@
     "axios": "^1.13.5",
     "axios": "^1.13.5",
     "crypto-js": "^4.2.0",
     "crypto-js": "^4.2.0",
     "dayjs": "^1.11.19",
     "dayjs": "^1.11.19",
-    "dingtalk-jsapi": "^3.2.8",
     "lodash-es": "^4.17.23",
     "lodash-es": "^4.17.23",
     "pinia": "^3.0.4",
     "pinia": "^3.0.4",
     "sm-crypto": "^0.4.0",
     "sm-crypto": "^0.4.0",

+ 5 - 5
pages/home/index.vue

@@ -7,7 +7,7 @@
 -->
 -->
 <template>
 <template>
   <view class="app-container">
   <view class="app-container">
-    <uv-loading-page :loading="isLogining && !token" text="科研钉钉平台登录中..." iconSize="40"></uv-loading-page>
+    <uv-loading-page :loading="isLogining && !token" text="正在登录中..." iconSize="40"></uv-loading-page>
     
     
     <view v-if="token">
     <view v-if="token">
     <view class="card">
     <view class="card">
@@ -117,7 +117,6 @@ import { useSystemApi } from '@/api/system';
 import { useExecutionApi } from '@/api/execution';
 import { useExecutionApi } from '@/api/execution';
 import { useProjectApi } from '@/api/project';
 import { useProjectApi } from '@/api/project';
 import to from 'await-to-js';
 import to from 'await-to-js';
-import * as dd from 'dingtalk-jsapi';
 
 
 const userStore = useUserStore();
 const userStore = useUserStore();
 const { token, isLogining } = storeToRefs(userStore);
 const { token, isLogining } = storeToRefs(userStore);
@@ -254,8 +253,9 @@ onShow(() => {
   if (token.value) {
   if (token.value) {
     refreshAllData();
     refreshAllData();
   } else {
   } else {
-    // 如果没有 token,且不在钉钉环境,跳转登录
-    if (dd.env.platform === 'notInDingTalk' && !isLogining.value) {
+    // 如果没有 token,则跳转登录
+    const launchCode = uni.getLaunchOptionsSync()?.query?.code;
+    if (!launchCode && !isLogining.value) {
       setTimeout(() => {
       setTimeout(() => {
         if (!token.value) {
         if (!token.value) {
           uni.reLaunch({ url: '/pages/login/index' });
           uni.reLaunch({ url: '/pages/login/index' });
@@ -272,7 +272,7 @@ watch(token, (newVal) => {
   }
   }
 });
 });
 
 
-// 自动检测钉钉登录状态并引导
+// token 获取后自动加载首页数据
 onMounted(() => {
 onMounted(() => {
   if (token.value) {
   if (token.value) {
     refreshAllData();
     refreshAllData();

+ 41 - 14
pages/login/index.vue

@@ -3,7 +3,12 @@
     <view class="bg-shape shadow"></view>
     <view class="bg-shape shadow"></view>
     <view class="bg-shape2 shadow"></view>
     <view class="bg-shape2 shadow"></view>
 
 
-    <view class="login-box">
+    <view v-if="showOAuthLoading" class="loading-box">
+      <uv-loading-icon color="#3b82f6" size="30"></uv-loading-icon>
+      <text class="loading-text">正在登录中...</text>
+    </view>
+
+    <view v-else class="login-box">
       <view class="header">
       <view class="header">
         <text class="title">欢迎登录</text>
         <text class="title">欢迎登录</text>
         <text class="subtitle">登录科研微信平台</text>
         <text class="subtitle">登录科研微信平台</text>
@@ -63,7 +68,7 @@
         customStyle="height: 100rpx; font-size: 32rpx; font-weight: 600; letter-spacing: 2rpx; box-shadow: 0 10rpx 20rpx rgba(37, 99, 235, 0.3); border: none; margin-top: 20rpx;" />
         customStyle="height: 100rpx; font-size: 32rpx; font-weight: 600; letter-spacing: 2rpx; box-shadow: 0 10rpx 20rpx rgba(37, 99, 235, 0.3); border: none; margin-top: 20rpx;" />
 
 
       <!-- 企业微信一键登录 -->
       <!-- 企业微信一键登录 -->
-      <view style="margin-top: 30rpx;">
+      <!-- <view style="margin-top: 30rpx;">
         <uv-button text="企业微信登录" @click="handleEnterpriseLoginClick" :loading="loading" shape="circle" plain
         <uv-button text="企业微信登录" @click="handleEnterpriseLoginClick" :loading="loading" shape="circle" plain
           color="#07c160"
           color="#07c160"
           customStyle="height: 100rpx; font-size: 30rpx; font-weight: 500; border: 2rpx solid #07c160; color: #07c160;">
           customStyle="height: 100rpx; font-size: 30rpx; font-weight: 500; border: 2rpx solid #07c160; color: #07c160;">
@@ -71,12 +76,12 @@
             <uv-icon name="weixin-fill" size="24" color="#07c160" customStyle="margin-right: 12rpx"></uv-icon>
             <uv-icon name="weixin-fill" size="24" color="#07c160" customStyle="margin-right: 12rpx"></uv-icon>
           </template>
           </template>
         </uv-button>
         </uv-button>
-      </view>
+      </view> -->
 
 
-      <view class="footer">
+      <!-- <view class="footer">
         <text class="footer-text">还没有账号?</text>
         <text class="footer-text">还没有账号?</text>
         <text class="footer-link" @click="goToRegister">立即注册</text>
         <text class="footer-link" @click="goToRegister">立即注册</text>
-      </view>
+      </view> -->
     </view>
     </view>
 
 
     <uv-toast ref="toastRef"></uv-toast>
     <uv-toast ref="toastRef"></uv-toast>
@@ -93,14 +98,12 @@ import { CACHE_KEY } from '@/constants/index';
 import { Local } from '@/utils/storage';
 import { Local } from '@/utils/storage';
 import { useLoginApi } from '@/api/system/login';
 import { useLoginApi } from '@/api/system/login';
 import { encryptWithBackendConfig } from '@/utils/aesCrypto';
 import { encryptWithBackendConfig } from '@/utils/aesCrypto';
-import { getDingTalkAuthCode } from '@/utils/dingtalk';
-import * as dd from 'dingtalk-jsapi';
 
 
 const userStore = useUserStore();
 const userStore = useUserStore();
 
 
 const { configSetting } = storeToRefs(userStore);
 const { configSetting } = storeToRefs(userStore);
 
 
-const { checkCaptcha, login, dingTalkLogin } = userStore;
+const { checkCaptcha, login } = userStore;
 
 
 const loginApi = useLoginApi();
 const loginApi = useLoginApi();
 
 
@@ -117,8 +120,11 @@ const loading = ref(false);
 const showPassword = ref(false);
 const showPassword = ref(false);
 const rememberMeArr = ref<string[]>([]);
 const rememberMeArr = ref<string[]>([]);
 const toastRef = ref<any>(null);
 const toastRef = ref<any>(null);
-// 是否在钉钉环境中
-const isInDingTalk = ref(dd.env.platform !== 'notInDingTalk');
+
+// 企业微信免登回调通常会在 URL 上带 `code`,进入本页后直接走免登并展示加载态
+const rawLaunchCode = (uni.getLaunchOptionsSync()?.query as any)?.code as undefined | string | string[];
+const initialUrlCode = Array.isArray(rawLaunchCode) ? rawLaunchCode[0] : rawLaunchCode;
+const showOAuthLoading = ref<boolean>(!!initialUrlCode);
 
 
 onMounted(async () => {
 onMounted(async () => {
   // --- 新增:登录拦截 ---
   // --- 新增:登录拦截 ---
@@ -126,6 +132,7 @@ onMounted(async () => {
   // 不应该停留在当前登录大厅,直接跳走回首页
   // 不应该停留在当前登录大厅,直接跳走回首页
   const existingToken = Local.get(CACHE_KEY.TOKEN);
   const existingToken = Local.get(CACHE_KEY.TOKEN);
   if (existingToken) {
   if (existingToken) {
+    showOAuthLoading.value = false;
     uni.switchTab({ url: '/pages/home/index' }).catch((err) => {
     uni.switchTab({ url: '/pages/home/index' }).catch((err) => {
       console.warn('switchTab failed, trying reLaunch:', err);
       console.warn('switchTab failed, trying reLaunch:', err);
       uni.reLaunch({ url: '/pages/home/index' });
       uni.reLaunch({ url: '/pages/home/index' });
@@ -144,10 +151,8 @@ onMounted(async () => {
   }
   }
 
 
   // 检测 URL 是否携带 code (企业微信免登)
   // 检测 URL 是否携带 code (企业微信免登)
-  const options = uni.getLaunchOptionsSync()?.query;
-  const urlCode = options?.code;
-  if (urlCode) {
-    handleEnterpriseLogin(urlCode);
+  if (initialUrlCode) {
+    await handleEnterpriseLogin(initialUrlCode);
     return;
     return;
   }
   }
 
 
@@ -246,6 +251,10 @@ const handleEnterpriseLogin = async (code: string) => {
       message: error.message || '企业快捷登录失败', 
       message: error.message || '企业快捷登录失败', 
       type: 'error' 
       type: 'error' 
     });
     });
+
+    // 免登失败后切回手动登录表单
+    showOAuthLoading.value = false;
+
     // 如果免登失败,正常加载验证码进入手动登录模式
     // 如果免登失败,正常加载验证码进入手动登录模式
     await checkCaptcha();
     await checkCaptcha();
     if (configSetting.value.isCaptcha === '10') {
     if (configSetting.value.isCaptcha === '10') {
@@ -284,6 +293,24 @@ const handleEnterpriseLoginClick = () => {
   padding: 0 40rpx;
   padding: 0 40rpx;
 }
 }
 
 
+.loading-box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  z-index: 10;
+  border-radius: 20rpx;
+  background: #f1f5f9;
+  flex-shrink: 0;
+  padding: 40rpx 30rpx;
+}
+
+.loading-text {
+  margin-top: 20rpx;
+  font-size: 26rpx;
+  color: #64748b;
+  font-weight: 500;
+}
+
 .bg-shape {
 .bg-shape {
   position: absolute;
   position: absolute;
   top: -100rpx;
   top: -100rpx;

+ 23 - 24
pages/login/index1.vue

@@ -15,8 +15,6 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import { ref, onMounted } from 'vue';
 import { ref, onMounted } from 'vue';
 import { useUserStore } from '@/store/modules/user';
 import { useUserStore } from '@/store/modules/user';
-import { getDingTalkAuthCode } from '@/utils/dingtalk';
-import * as dd from 'dingtalk-jsapi';
 
 
 const userStore = useUserStore();
 const userStore = useUserStore();
 const toastRef = ref<any>(null);
 const toastRef = ref<any>(null);
@@ -31,32 +29,33 @@ onMounted(async () => {
     return;
     return;
   }
   }
 
 
-  // 仅在钉钉环境下尝试免登
-  if (dd.env.platform !== 'notInDingTalk') {
+  // --- 新增:企业微信免登拦截(URL 带 code) ---
+  const urlCode = uni.getLaunchOptionsSync()?.query?.code as string | undefined;
+  if (urlCode) {
     try {
     try {
-      const corpId = uni.getLaunchOptionsSync()?.query?.corpId || import.meta.env.VITE_DINGTALK_CORPID;
-      const code = await getDingTalkAuthCode(corpId);
-      if (code) {
-        await userStore.dingTalkLogin(code);
-        toastRef.value.show({ message: '登录成功', type: 'success' });
-        // 成功,跳转首页
-        setTimeout(() => {
-          uni.switchTab({ url: '/pages/home/index' }).catch(() => {
-            uni.reLaunch({ url: '/pages/home/index' });
-          });
-        }, 800);
-      } else {
-        throw new Error('未获取到授权码');
-      }
-    } catch (error) {
-      console.error('DingTalk Login Failure in Login Page:', error);
-      // 免登失败(或账号未绑定),引导去注册
+      await userStore.oAuthLogin(urlCode);
+      toastRef.value.show({ message: '登录成功', type: 'success' });
+
+      // 成功跳转首页
+      setTimeout(() => {
+        uni.switchTab({ url: '/pages/home/index' }).catch(() => {
+          uni.reLaunch({ url: '/pages/home/index' });
+        });
+      }, 800);
+      return;
+    } catch (error: any) {
+      console.error('oAuthLogin Failure in Login Page:', error);
+      toastRef.value.show({
+        message: error?.message || '企业快捷登录失败',
+        type: 'error',
+      });
       uni.reLaunch({ url: '/pages/login/register' });
       uni.reLaunch({ url: '/pages/login/register' });
+      return;
     }
     }
-  } else {
-    // 不在钉钉环境下,直接跳转到注册页(因为不需要登录页)
-    uni.reLaunch({ url: '/pages/login/register' });
   }
   }
+
+  // 无法进行免登时,回到手动登录页
+  uni.reLaunch({ url: '/pages/login/index' });
 });
 });
 </script>
 </script>
 
 

+ 3 - 28
store/modules/user.ts

@@ -104,31 +104,6 @@ export const useUserStore = defineStore('user', () => {
     return res;
     return res;
   }
   }
 
 
-  /**
-   * 钉钉免登
-   */
-  async function dingTalkLogin(code: string) {
-    setRequestLoading('isLogining', true);
-    
-    const [err, res] = await to(loginApi.dingTalkLogin({ code }));
-    
-    setRequestLoading('isLogining', false);
-    
-    if (err) {
-      return Promise.reject(err);
-    }
-    
-    const resToken = res?.data?.token;
-    if (resToken) {
-      token.value = resToken;
-      Local.set(CACHE_KEY.TOKEN, resToken);
-      // 登录成功后主动获取用户信息
-      await fetchUserInfo();
-    }
-    
-    return res;
-  }
-
   /**
   /**
    * 企业微信免登
    * 企业微信免登
    */
    */
@@ -188,8 +163,9 @@ export const useUserStore = defineStore('user', () => {
       const achievementApi = useAchievementApi();
       const achievementApi = useAchievementApi();
       const [sciErr, sciRes] = await to(achievementApi.getSciToken(userInfo.value.id));
       const [sciErr, sciRes] = await to(achievementApi.getSciToken(userInfo.value.id));
       console.log(sciRes)
       console.log(sciRes)
-      if (!sciErr && sciRes?.token) {
-        Local.set(CACHE_KEY.SCITOKEN, sciRes.token);
+      const sciToken = sciRes?.data?.token;
+      if (!sciErr && sciToken) {
+        Local.set(CACHE_KEY.SCITOKEN, sciToken);
       }
       }
     }
     }
   }
   }
@@ -220,7 +196,6 @@ export const useUserStore = defineStore('user', () => {
     roles,
     roles,
     configSetting,
     configSetting,
     login,
     login,
-    dingTalkLogin,
     oAuthLogin,
     oAuthLogin,
     fetchUserInfo,
     fetchUserInfo,
     logout,
     logout,

+ 0 - 28
utils/dingtalk.ts

@@ -1,28 +0,0 @@
-import * as dd from 'dingtalk-jsapi';
-
-/**
- * 获取钉钉免登授权码
- * @param {string} corpId 企业的corpId (可选,如果不传则尝试从环境或URL获取)
- * @param {string} clientId 应用的clientId (可选,如果不传则从环境获取)
- */
-export function getDingTalkAuthCode(corpId?: string, clientId?: string) {
-  return new Promise<string>((resolve, reject) => {
-    // 钉钉环境判断
-    if (dd.env.platform === 'notInDingTalk') {
-      reject(new Error('请在钉钉客户端打开'));
-      return;
-    }
-
-    // @ts-ignore 新版写法,可能类型定义未及时更新
-    dd.requestAuthCode({
-      corpId: corpId || '',
-      clientId: clientId || import.meta.env.VITE_DINGTALK_CLIENTID || '',
-      onSuccess: (result: { code: string }) => {
-        resolve(result.code);
-      },
-      onFail: (err: any) => {
-        reject(err);
-      }
-    });
-  });
-}

Some files were not shown because too many files changed in this diff