4 Commity db8d70e39b ... 8867093155

Autor SHA1 Wiadomość Data
  fuwb 8867093155 1、添加薪资管理页面表格 3 miesięcy temu
  fuwb e58eb11222 1、添加扫码登录功能,并添加跳转 3 miesięcy temu
  fuwb 7ee164e020 1、修改浙政钉登录地址及登录方式 3 miesięcy temu
  fuwb 9b695b6708 1、添加专有钉钉登录功能,并测试完成 3 miesięcy temu

+ 3 - 1
client/.env.dev

@@ -5,6 +5,7 @@ VITE_DEV=false
 
 # 请求路径
 VITE_BASE_URL='http://60.191.110.205:28080'
+# VITE_BASE_URL='http://127.0.0.1:48080'
 
 # 上传路径
 VITE_UPLOAD_URL='/infra/file/upload'
@@ -19,7 +20,8 @@ VITE_UPLOAD_CLIENT_ID=20
 VITE_FILE_BASE_URI='/infra/file'
 
 # 流程详情页面路径
-VITE_PROCESS_DETAIL_URI = 'http:/60.191.110.205:48080/workflow'
+VITE_PROCESS_DETAIL_URI = 'http://60.191.110.205:28080/workflow'
+# VITE_PROCESS_DETAIL_URI = 'http://127.0.0.1:48080/workflow'
 
 # 接口前缀
 VITE_API_BASEPATH=/dev-api

+ 40 - 8
client/src/views/Login/OALogin.vue

@@ -51,10 +51,13 @@
 import * as LoginApi from '@/api/login'
 import { useRouter } from 'vue-router'
 import { useAppStore } from '@/store/modules/app'
+import * as authUtil from '@/utils/auth'
 defineOptions({ name: 'OALogin' })
 const appStore = useAppStore()
 const oaLoginTitle = ref(appStore.title)
 const dingCodeLogin = ref()
+const loading = ref()
+const loginLoading = ref(false)
 const redirect = ref<string>('')
 const { currentRoute, push } = useRouter()
 import { usePermissionStore } from '@/store/modules/permission'
@@ -68,13 +71,42 @@ const init = async (type) => {
     dingCodeLogin.value = res
   }
 }
-const handleMessage = (event) => {
-  var origin = event.origin
-  let loginBox: any = document.querySelector('.loginBox')
-  if (loginBox) {
-    loginBox.style = 'width:100%;height:100%;top:0;right:0;margin:0'
-    let iframe: any = document.querySelector('#iframe')
-    iframe.style = 'height:100%'
+const handleMessage = async (event) => {
+  try {
+    var origin = event.origin
+    const res = await LoginApi.socialLogin({
+      type: 20,
+      code: event.data.code,
+      state: event.data.state
+    })
+    if (!res) {
+      return
+    }
+    // socialLoading.value = ElLoading.service({
+    //   lock: true,
+    //   text: '正在加载系统中...',
+    //   background: 'rgba(0, 0, 0, 0.7)'
+    // })
+    authUtil.setToken(res)
+    if (!redirect.value) {
+      redirect.value = '/'
+    }
+    // 判断是否为SSO登录
+    if (redirect.value.indexOf('sso') !== -1) {
+      window.location.href = window.location.href.replace('/login?redirect=', '')
+    } else {
+      // push({ path: redirect.value || permissionStore.addRouters[0].path })
+      window.parent.pushWin() //触发iframe父页面的方法
+    }
+    // let loginBox: any = document.querySelector('.qr_login')
+    // if (loginBox) {
+    //   loginBox.style = 'width:100%;height:100%;top:0;right:0;margin:0'
+    //   let iframe: any = document.querySelector('#iframe')
+    //   iframe.style = 'height:100%'
+    // }
+  } finally {
+    loginLoading.value = false
+    loading.value.close()
   }
 }
 onMounted(() => {
@@ -201,7 +233,7 @@ onMounted(() => {
         &.qr_login {
           flex: 1;
           > .qr_box {
-            height: 200px;
+            height: 300px;
             iframe {
               height: 100%;
             }

+ 5 - 5
client/src/views/OaSystem/oaLayout/menus.vue

@@ -65,9 +65,9 @@ const userName = user.user.nickname ? user.user.nickname : 'Admin'
 
 const deptName = user.user.deptName ? user.user.deptName : '部门信息'
 const userId = user.user.id // 当前登录的编号
-const { data } = useQuery(['fetch-staff-detail-left', userId], async () => {
-  return await getRecordsDetail({ userId })
-})
+// const { data } = useQuery(['fetch-staff-detail-left', userId], async () => {
+//   return await getRecordsDetail({ userId })
+// })
 // 获取assets静态资源
 const getAssetsFile = (url: string) => {
   return new URL(`../../../assets/imgs/menu/${url}`, import.meta.url).href
@@ -123,14 +123,14 @@ const reactiveData: any = reactive({
 const initMenus = async () => {
   let locals: any = localStorage.getItem('roleRouters')
   let roleRouters = JSON.parse(JSON.parse(locals).v)?.[0]?.children
-
+  console.log(roleRouters)
   let childArr = roleRouters?.slice(0, roleRouters?.length)
   reactiveData.routes = childArr
 }
 
 const menuClick = (item: any, idx: any) => {
   if (item.children == null) {
-    push('/oaSystem/' + item.path)
+    push('/OaSystem/' + item.path)
   } else {
     return
   }

+ 39 - 2
client/src/views/OaSystem/searchCenter/salary/index.vue

@@ -1,6 +1,43 @@
 <template>
-  <div>
-    <h1>薪资管理</h1>
+  <div class="container-header">
+    <el-form :inline="true">
+      <el-form-item label="工作人员姓名">
+        <el-input v-model="searchKey" placeholder="请输入工作人员姓名" />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleSearch">搜索</el-button>
+      </el-form-item>
+      <el-form-item>
+        <el-button plain @click="resetSearchKey">重置</el-button>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleInsert">导入</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+  <div class="container-main">
+    <el-table style="width: 100%" :data="list" @row-click="handleRowClick">
+      <el-table-column prop="supplierName" label="供应商名称" />
+      <el-table-column prop="contactPerson" label="联系人" />
+      <el-table-column prop="contactPhone" label="联系电话" />
+      <el-table-column prop="unitAddress" label="所在地" />
+      <el-table-column label="操作" width="200px">
+        <template #default="scope">
+          <el-button size="small" @click.stop="handleEdit(scope.row)">修改</el-button>
+          <el-button size="small" type="danger" @click.stop="handleDelete(scope.row)">
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      background
+      layout="prev, pager, next"
+      :total="total"
+      style="margin-top: 20px"
+      :hide-on-single-page="true"
+      @current-change="handleCurrentChange"
+    />
   </div>
 </template>
 

+ 5 - 1
zjugis-framework/zjugis-spring-boot-starter-biz-social/src/main/java/com/zjugis/framework/social/core/enums/AuthExtendSource.java

@@ -1,5 +1,6 @@
 package com.zjugis.framework.social.core.enums;
 
+import com.sun.xml.internal.bind.v2.TODO;
 import com.xingyuv.jushauth.config.AuthSource;
 import com.xingyuv.jushauth.enums.AuthResponseStatus;
 import com.xingyuv.jushauth.exception.AuthException;
@@ -45,8 +46,11 @@ public enum AuthExtendSource implements AuthSource {
     },
     DINGTALK {
         @Override
+//        public String authorize() {
+//            return "https://login.dingtalk.com/oauth2/auth";
+//        }
         public String authorize() {
-            return "https://login.dingtalk.com/oauth2/auth";
+            return "https://login.on-premises.dingtalk.com/oauth2/auth.htm";
         }
 
         @Override

+ 3 - 2
zjugis-framework/zjugis-spring-boot-starter-biz-social/src/main/java/com/zjugis/framework/social/core/request/AuthDingtalkRequest.java

@@ -142,10 +142,11 @@ public class AuthDingtalkRequest extends AuthDefaultRequest {
         return UrlBuilder.fromBaseUrl(source.authorize())
                 .queryParam("response_type", "code")
                 .queryParam("client_id", config.getClientId())
-                .queryParam("scope", "openid")
+                .queryParam("scope", "get_user_info")
                 .queryParam("redirect_uri", config.getRedirectUri())
+                .queryParam("authType", "QRCODE")
+                .queryParam("embedMode", true)
                 .queryParam("state", getRealState(state))
-                .queryParam("prompt", "login%20consent")
                 .build();
     }
 

+ 13 - 1
zjugis-module-system/zjugis-module-system-biz/pom.xml

@@ -156,7 +156,19 @@
             <groupId>com.zjugis.cloud</groupId>
             <artifactId>zjugis-spring-boot-starter-monitor</artifactId>
         </dependency>
-
+        <!--  浙政钉SDK      -->
+        <dependency>
+            <groupId>com.alibaba.openplatform.shared</groupId>
+            <artifactId>sdk.client</artifactId>
+            <version>2.9.0-SNAPSHOT</version>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/src/main/resources/lib/zwdd-sdk-java-1.2.0.jar</systemPath>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+            <version>2.12.4</version>
+        </dependency>
     </dependencies>
     <build>
         <!-- 设置构建的 jar 包名 -->

+ 1 - 2
zjugis-module-system/zjugis-module-system-biz/src/main/java/com/zjugis/module/system/service/auth/AdminAuthServiceImpl.java

@@ -156,8 +156,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
     @Override
     public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
         // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
-        String userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
-                reqVO.getCode(), reqVO.getState());
+        String userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getCode(), reqVO.getState());
         if (userId == null) {
             throw exception(AUTH_MOBILE_NOT_EXISTS);
         }

+ 117 - 30
zjugis-module-system/zjugis-module-system-biz/src/main/java/com/zjugis/module/system/service/social/SocialUserServiceImpl.java

@@ -2,7 +2,12 @@ package com.zjugis.module.system.service.social;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
+import cn.hutool.log.Log;
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
+import com.alibaba.xxpt.gateway.shared.client.http.GetClient;
+import com.alibaba.xxpt.gateway.shared.client.http.PostClient;
 import com.xingyuv.jushauth.model.AuthCallback;
 import com.xingyuv.jushauth.model.AuthResponse;
 import com.xingyuv.jushauth.model.AuthUser;
@@ -21,8 +26,10 @@ import com.zjugis.module.system.dal.mysql.social.SocialUserMapper;
 import com.zjugis.module.system.dal.mysql.user.AdminUserMapper;
 import com.zjugis.module.system.enums.social.SocialTypeEnum;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
@@ -48,7 +55,6 @@ import static com.zjugis.module.system.enums.ErrorCodeConstants.SOCIAL_USER_MOBI
 @Validated
 @Slf4j
 public class SocialUserServiceImpl implements SocialUserService {
-
     @Resource// 由于自定义了 ZjugisAuthRequestFactory 无法覆盖默认的 AuthRequestFactory,所以只能注入它
     private ZjugisAuthRequestFactory zjugisAuthRequestFactory;
 
@@ -59,6 +65,12 @@ public class SocialUserServiceImpl implements SocialUserService {
     @Resource
     private AdminUserMapper adminUserMapper;
 
+    @Value("${dingding.appKey}")
+    private String appKey;
+    @Value("${dingding.appSecret}")
+    private String appSecret;
+    @Resource
+    private ExecutableClient client;
 
     @Override
     public String getAuthorizeUrl(Integer type, String redirectUri) {
@@ -73,29 +85,39 @@ public class SocialUserServiceImpl implements SocialUserService {
     public SocialUserDO authSocialUser(Integer type, String code, String state) {
         // 优先从 DB 中获取,因为 code 有且可以使用一次。
         // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
-        SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state);
-        if (socialUser != null) {
-            return socialUser;
-        }
+//        SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state);
+//        if (socialUser != null) {
+//            return socialUser;
+//        }
 
-        // 请求获取
-        AuthUser authUser = getAuthUser(type, code, state);
-        Assert.notNull(authUser, "三方用户不能为空");
+        // 请求获取用户信息
+//        AuthUser authUser = getAuthUser(type, code, state);
+        JSONObject accessToken = getAccessToken();
+        if (accessToken != null) {
+            String token = accessToken.getString("accessToken");
+            JSONObject userInfo = getUserInfo(token, code);
+            Assert.notNull(userInfo, "三方用户不能为空");
 
-        // 保存到 DB 中
-        socialUser = socialUserMapper.selectByTypeAndOpenid(type, authUser.getUuid());
-        if (socialUser == null) {
-            socialUser = new SocialUserDO();
-        }
-        socialUser.setType(type).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询
-                .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken())))
-                .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo()));
-        if (socialUser.getId() == null) {
-            socialUserMapper.insert(socialUser);
-        } else {
-            socialUserMapper.updateById(socialUser);
+            // 保存到 DB 中
+            SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, userInfo.getLong("accountId").toString());
+            if (socialUser == null) {
+                socialUser = new SocialUserDO();
+                socialUser.setType(type)
+                        .setState(state)
+                        .setOpenid(userInfo.getString("accountId"))
+                        .setToken(token)
+                        .setRawTokenInfo(toJsonString(accessToken))
+                        .setNickname(userInfo.getString("nickNameCn"))
+                        .setRawUserInfo(toJsonString(userInfo));
+            }
+            if (socialUser.getId() == null) {
+                socialUserMapper.insert(socialUser);
+            } else {
+                socialUserMapper.updateById(socialUser);
+            }
+            return socialUser;
         }
-        return socialUser;
+        return null;
     }
 
     @Override
@@ -152,28 +174,47 @@ public class SocialUserServiceImpl implements SocialUserService {
         String userId;
 
         // 如果未绑定的社交用户,进行自动绑定
-        SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType,
-                socialUser.getId());
+        SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, socialUser.getId());
         if (socialUserBind == null) {
             String rawUserInfo = socialUser.getRawUserInfo();
-            String mobile = JSONObject.parseObject(rawUserInfo).get("mobile").toString();
-            Object avatarUrl = JSONObject.parseObject(rawUserInfo).get("avatarUrl");
+            JSONObject jsonObject = JSONObject.parseObject(rawUserInfo);
+            // todo 手机号绑定未完成
+            String mobile = jsonObject.getString("account");
+            String accountId = jsonObject.getLong("accountId").toString();
+//            Object avatarUrl = JSONObject.parseObject(rawUserInfo).get("avatarUrl");
             AdminUserDO user = adminUserMapper.selectByMobile(mobile);
             if(user == null){
                 throw exception(SOCIAL_USER_MOBILE_NOT_FOUND);
             }
-            bindSocialUser(new SocialUserBindReqDTO(user.getId(), userType,
-                    type, code, state));
+//            bindSocialUser(new SocialUserBindReqDTO(user.getId(), userType, type, code, state));
+            bindSocialUser(user.getId(), userType, type, accountId);
             userId = user.getId();
-            if (avatarUrl != null) {
-                adminUserMapper.updateById(new AdminUserDO().setId(userId).setAvatar(avatarUrl.toString()));
-            }
+//            if (avatarUrl != null) {
+//                adminUserMapper.updateById(new AdminUserDO().setId(userId).setAvatar(avatarUrl.toString()));
+//            }
         } else {
             userId = socialUserBind.getUserId();
         }
         return userId;
     }
 
+    /**
+     * 绑定社交用户
+     *
+     * @param userId
+     * @param userType
+     * @param type
+     * @param accountId
+     */
+    private void bindSocialUser(String userId, Integer userType, Integer type, String accountId) {
+        SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, accountId);
+        // 绑定当前登录的社交用户
+        SocialUserBindDO socialUserBind = SocialUserBindDO.builder()
+                .userId(userId).userType(userType)
+                .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build();
+        socialUserBindMapper.insert(socialUserBind);
+    }
+
     @Override
     public List<String> getBindUserIds(Collection<String> socialIds, Integer socialType) {
         List<SocialUserBindDO> socialUserList = socialUserBindMapper.selectListBySocialIds(socialIds,
@@ -218,4 +259,50 @@ public class SocialUserServiceImpl implements SocialUserService {
         return (AuthUser) authResponse.getData();
     }
 
+    public JSONObject getUserInfo(String accessToken, String authCode) {
+        if (StringUtils.hasLength(accessToken)) {
+            PostClient postClient = client.newPostClient("/rpc/oauth2/getuserinfo_bycode.json");
+            postClient.addParameter("access_token", accessToken);
+            postClient.addParameter("code", authCode);
+            String post = postClient.post();
+            JSONObject jsonObject = JSON.parseObject(post);
+//            log.info("UserInfo :[{}]", jsonObject);
+            Boolean aBoolean = jsonObject.getBoolean("success");
+            if (aBoolean) {
+                JSONObject content = jsonObject.getJSONObject("content");
+                Boolean success = content.getBoolean("success");
+                if (success) {
+                    return content.getJSONObject("data");
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取专有钉钉AccessToken
+     *
+     * @return
+     */
+    private JSONObject getAccessToken() {
+        String api = "/gettoken.json";
+        GetClient getClient = client.newGetClient(api);
+        //设置参数
+        getClient.addParameter("appkey", appKey);
+        getClient.addParameter("appsecret", appSecret);
+        //调用API
+        String apiResult = getClient.get();
+        JSONObject jsonObject = JSONObject.parseObject(apiResult);
+        Boolean aBoolean = jsonObject.getBoolean("success");
+        Log.get().info("用户钉钉信息:{}", jsonObject);
+        if (aBoolean) {
+            JSONObject content = jsonObject.getJSONObject("content");
+            Boolean success = content.getBoolean("success");
+            if (success) {
+                return content.getJSONObject("data");
+            }
+        }
+        return null;
+    }
+
 }

+ 39 - 0
zjugis-module-system/zjugis-module-system-biz/src/main/java/com/zjugis/module/system/util/ExecutableClientConfig.java

@@ -0,0 +1,39 @@
+package com.zjugis.module.system.util;
+
+import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author: Fuwb
+ * @date: 2025/3/28
+ * @time: 9:24
+ * @description:
+ */
+@Component
+public class ExecutableClientConfig {
+    @Value("${dingding.appKey}")
+    private String appKey;
+
+    @Value("${dingding.appSecret}")
+    private String appSecret;
+
+    @Value("${dingding.domainName}")
+    private String domainName;
+
+    @Bean
+    public ExecutableClient executableClient() {
+        ExecutableClient instance = ExecutableClient.getInstance();
+        instance.setDomainName(domainName);
+        instance.setProtocal("https");
+        //应用App Key
+        instance.setAccessKey(appKey);
+        //应用App Secret
+        instance.setSecretKey(appSecret);
+        instance.init();
+        return instance;
+    }
+
+
+}

+ 9 - 2
zjugis-module-system/zjugis-module-system-biz/src/main/resources/application-dev.yaml

@@ -173,8 +173,10 @@ justauth:
   enabled: true
   type:
     DINGTALK: # 钉钉
-      client-id: dingk0ggukejc4xacgku
-      client-secret: 1Irqm3obWLCWTokhrCgbrcMIX7klSI3s_ljiBZrAzMfnpttJTUJHIBCi8C-2rD2O
+#      client-id: dingk0ggukejc4xacgku
+      client-id: ruian_oa_test_dingoa
+#      client-secret: 1Irqm3obWLCWTokhrCgbrcMIX7klSI3s_ljiBZrAzMfnpttJTUJHIBCi8C-2rD2O
+      client-secret: 7BJ74Ke76e8lil84oZzd7gV9zX3zild3DBWxYj7u
       ignore-check-redirect-uri: true
     WECHAT_ENTERPRISE: # 企业微信
       client-id: wwd411c69a39ad2e54
@@ -192,3 +194,8 @@ deptId:
 roleId:
   bj: 3000021
   normal: 2
+
+dingding:
+  appKey: ruian_oa_test_dingoa-7vhnQzQzi
+  appSecret: 7BJ74Ke76e8lil84oZzd7gV9zX3zild3DBWxYj7u
+  domainName: open.on-premises.dingtalk.com

BIN
zjugis-module-system/zjugis-module-system-biz/src/main/resources/lib/zwdd-sdk-java-1.2.0.jar