Commit 79e3bfa9 authored by yuwenwen's avatar yuwenwen
parents 8e6b76a6 3734696e
...@@ -2,7 +2,6 @@ package com.tangguo.web.controller.system; ...@@ -2,7 +2,6 @@ package com.tangguo.web.controller.system;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.tangguo.common.annotation.Log;
import com.tangguo.common.constant.Constants; import com.tangguo.common.constant.Constants;
import com.tangguo.common.core.domain.AjaxResult; import com.tangguo.common.core.domain.AjaxResult;
import com.tangguo.common.core.domain.entity.SysMenu; import com.tangguo.common.core.domain.entity.SysMenu;
...@@ -11,10 +10,8 @@ import com.tangguo.common.core.domain.entity.SysUser; ...@@ -11,10 +10,8 @@ import com.tangguo.common.core.domain.entity.SysUser;
import com.tangguo.common.core.domain.model.LoginBody; import com.tangguo.common.core.domain.model.LoginBody;
import com.tangguo.common.core.domain.model.LoginUser; import com.tangguo.common.core.domain.model.LoginUser;
import com.tangguo.common.core.domain.model.WxcpCodeLogin; import com.tangguo.common.core.domain.model.WxcpCodeLogin;
import com.tangguo.common.enums.BusinessType;
import com.tangguo.common.exception.ServiceException; import com.tangguo.common.exception.ServiceException;
import com.tangguo.common.utils.SecurityUtils; import com.tangguo.common.utils.SecurityUtils;
import com.tangguo.common.utils.StringUtils;
import com.tangguo.framework.config.ServerConfig; import com.tangguo.framework.config.ServerConfig;
import com.tangguo.framework.web.service.SysLoginService; import com.tangguo.framework.web.service.SysLoginService;
import com.tangguo.framework.web.service.SysPermissionService; import com.tangguo.framework.web.service.SysPermissionService;
...@@ -59,7 +56,10 @@ public class SysLoginController { ...@@ -59,7 +56,10 @@ public class SysLoginController {
private TokenService tokenService; private TokenService tokenService;
@Autowired @Autowired
private WxCpService wxCpService; private WxCpService mobileWxCpService;
@Autowired
private WxCpService pcWxCpService;
@Autowired @Autowired
private ServerConfig serverConfig; private ServerConfig serverConfig;
...@@ -67,8 +67,12 @@ public class SysLoginController { ...@@ -67,8 +67,12 @@ public class SysLoginController {
@Autowired @Autowired
private ISysUserService userService; private ISysUserService userService;
@Value("${wx.cp.redirect-url}")
private String redirectUrl; @Value("${wx.cp.pc-redirect-url}")
private String pcRedirectUrl;
@Value("${wx.cp.mobile-redirect-url}")
private String mobileRedirectUrl;
...@@ -88,6 +92,47 @@ public class SysLoginController { ...@@ -88,6 +92,47 @@ public class SysLoginController {
return ajax; return ajax;
} }
/**
* 企微用户Code登录
*
* @param bo 登录参数
* @return 登录结果
*/
@PostMapping("/pc/code/login")
public AjaxResult pcCodeLogin(@RequestBody WxcpCodeLogin bo) {
LoginUser loginUser = SecurityUtils.getLoginUserNotEx();
log.info("=> 登录请求参数:{}", bo);
log.info("=> 当前登录用户:{}", loginUser);
// 企微登录认证链接
String authCode = bo.getCode();
WxCpOAuth2Service oauth2Service = this.pcWxCpService.getOauth2Service();
if (Objects.isNull(loginUser) && StrUtil.isBlank(authCode)) {
String oauth2Url = oauth2Service.buildAuthorizationUrl(this.pcRedirectUrl, null);
log.info("=> 认证失败,返回Oauth2登录链接:{}", oauth2Url);
return AjaxResult.error(401, "身份认证失败", oauth2Url);
}
// 查询企微用户信息
String token = null;
if (Objects.isNull(loginUser) && StrUtil.isNotBlank(authCode)) {
try {
WxCpOauth2UserInfo userInfo = oauth2Service.getUserInfo(authCode);
log.info("=> 查询企微用户信息,返回结果:{},{}", authCode, JSON.toJSONString(userInfo));
UserDetails userDetails = this.userDetailsServiceImpl.loadUserByUsername2(userInfo.getUserId());
token = this.tokenService.createToken((LoginUser) userDetails);
} catch (Exception e) {
log.error("=> 查询用户信息失败:", e);
throw new ServiceException("登录失败,查询用户信息失败。");
}
}
log.info("=> 登录结果:{}", token);
return AjaxResult.success("登录成功", token);
}
/** /**
* 获取用户信息 * 获取用户信息
* *
...@@ -129,16 +174,16 @@ public class SysLoginController { ...@@ -129,16 +174,16 @@ public class SysLoginController {
* @return 登录结果 * @return 登录结果
*/ */
@PostMapping("/bbs/mobile/user/code/login") @PostMapping("/bbs/mobile/user/code/login")
public AjaxResult codeLogin(@RequestBody WxcpCodeLogin bo) { public AjaxResult mobileCodeLogin(@RequestBody WxcpCodeLogin bo) {
LoginUser loginUser = SecurityUtils.getLoginUserNotEx(); LoginUser loginUser = SecurityUtils.getLoginUserNotEx();
log.info("=> 登录请求参数:{}", bo); log.info("=> 登录请求参数:{}", bo);
log.info("=> 当前登录用户:{}", loginUser); log.info("=> 当前登录用户:{}", loginUser);
// 企微登录认证链接 // 企微登录认证链接
String authCode = bo.getCode(); String authCode = bo.getCode();
WxCpOAuth2Service oauth2Service = this.wxCpService.getOauth2Service(); WxCpOAuth2Service oauth2Service = this.mobileWxCpService.getOauth2Service();
if (Objects.isNull(loginUser) && StrUtil.isBlank(authCode)) { if (Objects.isNull(loginUser) && StrUtil.isBlank(authCode)) {
String oauth2Url = oauth2Service.buildAuthorizationUrl(this.redirectUrl, null); String oauth2Url = oauth2Service.buildAuthorizationUrl(this.mobileRedirectUrl, null);
log.info("=> 认证失败,返回Oauth2登录链接:{}", oauth2Url); log.info("=> 认证失败,返回Oauth2登录链接:{}", oauth2Url);
return AjaxResult.error(401, "身份认证失败", oauth2Url); return AjaxResult.error(401, "身份认证失败", oauth2Url);
} }
......
...@@ -92,11 +92,17 @@ spring: ...@@ -92,11 +92,17 @@ spring:
listener: listener:
max-concurrency: 3 max-concurrency: 3
# 企业微信配置 # 企业微信配置
wx: wx:
cp: cp:
redirect-url: https://test.tangguo.ren/bbsh5/pages/login/login pc-redirect-url: https://test.tangguo.ren/bbs/pc/wechatlogin
mobile-redirect-url: https://test.tangguo.ren/bbsh5/pages/login/login
corp-id: ww63ca87d5f8647514 corp-id: ww63ca87d5f8647514
app-config: app-configs:
agent-id: 1000072 - name: '移动端应用配置'
secret: O2KXf2b9oGG2GBrpzDgf4EFdhGwl2KaS9BWtJQT1I64 agent-id: 1000072
secret: O2KXf2b9oGG2GBrpzDgf4EFdhGwl2KaS9BWtJQT1I64
- name: '管理端应用配置'
agent-id: 1000072
secret: O2KXf2b9oGG2GBrpzDgf4EFdhGwl2KaS9BWtJQT1I64
...@@ -95,8 +95,13 @@ spring: ...@@ -95,8 +95,13 @@ spring:
# 企业微信配置 # 企业微信配置
wx: wx:
cp: cp:
redirect-url: https://wecom.jift.edu.cn/bbsh5/pages/login/login pc-redirect-url: https://wecom.jift.edu.cn/bbs/pc/wechatlogin
mobile-redirect-url: https://wecom.jift.edu.cn/bbs/h5/pages/login/login
corp-id: wxd2a84aa7529d3801 corp-id: wxd2a84aa7529d3801
app-config: app-configs:
agent-id: 1000218 - name: '移动端应用配置'
secret: UubIP6xbLBzw3DwcIyOARYf1e4cm5GNJKNFZTlVfgyo agent-id: 1000218
secret: UubIP6xbLBzw3DwcIyOARYf1e4cm5GNJKNFZTlVfgyo
- name: '管理端应用配置'
agent-id: 1000219
secret: OEMM3DAd-2FK-9Ggiu3xsD7Sg4SlPuV7os1hAWrTIwk
...@@ -95,7 +95,13 @@ spring: ...@@ -95,7 +95,13 @@ spring:
# 企业微信配置 # 企业微信配置
wx: wx:
cp: cp:
pc-redirect-url: https://test.tangguo.ren/bbs/pc/wechatlogin
mobile-redirect-url: https://test.tangguo.ren/bbsh5/pages/login/login
corp-id: ww63ca87d5f8647514 corp-id: ww63ca87d5f8647514
app-config: app-configs:
agent-id: 1000072 - name: '移动端应用配置'
secret: O2KXf2b9oGG2GBrpzDgf4EFdhGwl2KaS9BWtJQT1I64 agent-id: 1000072
secret: O2KXf2b9oGG2GBrpzDgf4EFdhGwl2KaS9BWtJQT1I64
- name: '管理端应用配置'
agent-id: 1000072
secret: O2KXf2b9oGG2GBrpzDgf4EFdhGwl2KaS9BWtJQT1I64
...@@ -119,14 +119,3 @@ xss: ...@@ -119,14 +119,3 @@ xss:
excludes: /system/notice excludes: /system/notice
# 匹配链接 # 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/* urlPatterns: /system/*,/monitor/*,/tool/*
mobile:
auth:
res-token-name: token
req-token-name: Authorization
issuer: Mobile-Auth
algorithm-id: HS512
sign-key: SignKey2025@.
effective-time: 7d
path-patterns: /bbs/mobile/**
...@@ -23,14 +23,14 @@ public class ApplicationTest { ...@@ -23,14 +23,14 @@ public class ApplicationTest {
private JmsTemplate jmsTemplate; private JmsTemplate jmsTemplate;
@Resource @Resource
private WxCpService wxCpService; private WxCpService mobileWxCpService;
@Test @Test
public void test() { public void test() {
WxCpOAuth2Service oauth2Service = this.wxCpService.getOauth2Service(); WxCpOAuth2Service oauth2Service = this.mobileWxCpService.getOauth2Service();
System.out.println(oauth2Service.buildAuthorizationUrl("https://test.tangguo.ren/bbs/h5/pages/login/login/", "")); System.out.println(oauth2Service.buildAuthorizationUrl("https://qywx.tangguo.ren/bbs/h5/pages/login/login/", ""));
} }
......
...@@ -56,4 +56,16 @@ export function getCodeImg() { ...@@ -56,4 +56,16 @@ export function getCodeImg() {
method: 'get', method: 'get',
timeout: 20000 timeout: 20000
}) })
} }
\ No newline at end of file
// 企业
export function loginByWechatWork(data) {
return request({
url: '/pc/code/login',
headers: {
isToken: false
},
method: 'post',
data: data
})
}
...@@ -8,7 +8,7 @@ import { isRelogin } from '@/utils/request' ...@@ -8,7 +8,7 @@ import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register'] const whiteList = ['/login', '/register','/wechatlogin']
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start()
......
...@@ -46,6 +46,11 @@ export const constantRoutes = [ ...@@ -46,6 +46,11 @@ export const constantRoutes = [
component: () => import('@/views/login'), component: () => import('@/views/login'),
hidden: true hidden: true
}, },
{
path: '/wechatlogin',
component: () => import('@/views/wechatlogin'),
hidden: true
},
{ {
path: '/register', path: '/register',
component: () => import('@/views/register'), component: () => import('@/views/register'),
...@@ -177,7 +182,7 @@ Router.prototype.replace = function push(location) { ...@@ -177,7 +182,7 @@ Router.prototype.replace = function push(location) {
} }
export default new Router({ export default new Router({
base:'/bbspc', base:'/bbs/pc',
mode: 'history', // 去掉url中的# mode: 'history', // 去掉url中的#
scrollBehavior: () => ({ y: 0 }), scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes routes: constantRoutes
......
import { login, logout, getInfo } from '@/api/login' import { login, logout, getInfo, loginByWechatWork } from "@/api/login";
import { getToken, setToken, removeToken } from '@/utils/auth' import { getToken, setToken, removeToken } from "@/utils/auth";
const user = { const user = {
state: { state: {
token: getToken(), token: getToken(),
name: '', name: "",
avatar: '', avatar: "",
roles: [], roles: [],
permissions: [] permissions: [],
}, },
mutations: { mutations: {
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token state.token = token;
}, },
SET_NAME: (state, name) => { SET_NAME: (state, name) => {
state.name = name state.name = name;
}, },
SET_AVATAR: (state, avatar) => { SET_AVATAR: (state, avatar) => {
state.avatar = avatar state.avatar = avatar;
}, },
SET_ROLES: (state, roles) => { SET_ROLES: (state, roles) => {
state.roles = roles state.roles = roles;
}, },
SET_PERMISSIONS: (state, permissions) => { SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions state.permissions = permissions;
} },
}, },
actions: { actions: {
getWechatLogin({ commit }, code) {
return new Promise((resolve, reject) => {
loginByWechatWork({ code })
.then((res) => {
setToken(res.data);
commit("SET_TOKEN", res.data);
resolve(res);
})
.catch((error) => {
reject(error);
});
});
},
// 登录 // 登录
Login({ commit }, userInfo) { Login({ commit }, userInfo) {
const username = userInfo.username.trim() const username = userInfo.username.trim();
const password = userInfo.password const password = userInfo.password;
const code = userInfo.code const code = userInfo.code;
const uuid = userInfo.uuid const uuid = userInfo.uuid;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => { login(username, password, code, uuid)
setToken(res.token) .then((res) => {
commit('SET_TOKEN', res.token) setToken(res.token);
resolve() commit("SET_TOKEN", res.token);
}).catch(error => { resolve();
reject(error) })
}) .catch((error) => {
}) reject(error);
});
});
}, },
// 获取用户信息 // 获取用户信息
GetInfo({ commit, state }) { GetInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo().then(res => { getInfo()
const user = res.user .then((res) => {
const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar; const user = res.user;
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 const avatar =
commit('SET_ROLES', res.roles) user.avatar == "" || user.avatar == null
commit('SET_PERMISSIONS', res.permissions) ? require("@/assets/images/profile.jpg")
} else { : process.env.VUE_APP_BASE_API + user.avatar;
commit('SET_ROLES', ['ROLE_DEFAULT']) if (res.roles && res.roles.length > 0) {
} // 验证返回的roles是否是一个非空数组
commit('SET_NAME', user.userName) commit("SET_ROLES", res.roles);
commit('SET_AVATAR', avatar) commit("SET_PERMISSIONS", res.permissions);
resolve(res) } else {
}).catch(error => { commit("SET_ROLES", ["ROLE_DEFAULT"]);
reject(error) }
}) commit("SET_NAME", user.userName);
}) commit("SET_AVATAR", avatar);
resolve(res);
})
.catch((error) => {
reject(error);
});
});
}, },
// 退出系统 // 退出系统
LogOut({ commit, state }) { LogOut({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token).then(() => { logout(state.token)
commit('SET_TOKEN', '') .then(() => {
commit('SET_ROLES', []) commit("SET_TOKEN", "");
commit('SET_PERMISSIONS', []) commit("SET_ROLES", []);
removeToken() commit("SET_PERMISSIONS", []);
resolve() removeToken();
}).catch(error => { resolve();
reject(error) })
}) .catch((error) => {
}) reject(error);
});
});
}, },
// 前端 登出 // 前端 登出
FedLogOut({ commit }) { FedLogOut({ commit }) {
return new Promise(resolve => { return new Promise((resolve) => {
commit('SET_TOKEN', '') commit("SET_TOKEN", "");
removeToken() removeToken();
resolve() resolve();
}) });
} },
} },
} };
export default user export default user;
This diff is collapsed.
<template>
<div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
mounted() {
if (this.isWeComEnv()) {
// 企业微信环境处理
const code = this.$route.query.code
this.getWechatLogin(code).then(() => {
this.$router.replace('/')
})
} else {
// 非企业微信环境,跳转到普通登录页
this.$router.replace('/login')
}
},
methods: {
// 判断是否为企业微信环境
isWeComEnv() {
// return true
const userAgent = window.navigator.userAgent.toLowerCase()
return userAgent.includes('wxwork') || (userAgent.includes('micromessenger') && userAgent.includes('wxwork'))
},
// 映射 Vuex 中的 getWechatLogin 方法
...mapActions(['getWechatLogin'])
}
}
</script>
...@@ -18,7 +18,7 @@ module.exports = { ...@@ -18,7 +18,7 @@ module.exports = {
// 部署生产环境和开发环境下的URL。 // 部署生产环境和开发环境下的URL。
// 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: process.env.NODE_ENV === "production" ? "/bbspc" : "/", publicPath: process.env.NODE_ENV === "production" ? "/bbs/pc" : "/",
// 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist) // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
outputDir: 'dist', outputDir: 'dist',
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
......
{ {
"name" : "社区", "name" : "社区",
"appid" : "__UNI__E3457E1", "appid" : "__UNI__69A40B9",
"description" : "", "description" : "",
"versionName" : "1.0.0", "versionName" : "1.0.0",
"versionCode" : "100", "versionCode" : "100",
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
"h5" : { "h5" : {
"router" : { "router" : {
"mode" : "history", "mode" : "history",
"base" : "/bbsh5/" "base" : "/bbs/h5/"
} }
} }
} }
...@@ -110,7 +110,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -110,7 +110,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 过滤请求 // 过滤请求
.authorizeRequests() .authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/bbs/mobile/user/code/login", "/register", "/captchaImage").permitAll() .antMatchers("/login", "/bbs/mobile/user/code/login", "/pc/code/login", "/register", "/captchaImage").permitAll()
// 静态资源,可匿名访问 // 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
......
...@@ -33,10 +33,10 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S ...@@ -33,10 +33,10 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S
private static final long serialVersionUID = -8970718410437077606L; private static final long serialVersionUID = -8970718410437077606L;
@Autowired @Autowired
private WxCpService wxCpService; private WxCpService mobileWxCpService;
@Value("${wx.cp.redirect-url}") @Value("${wx.cp.mobile-redirect-url}")
private String redirectUrl; private String mobileRedirectUrl;
@Override @Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
...@@ -47,8 +47,8 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S ...@@ -47,8 +47,8 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S
log.info("=> 身份认证失败,Token:{}", request.getHeader("Authorization")); log.info("=> 身份认证失败,Token:{}", request.getHeader("Authorization"));
if (uri.startsWith("/bbs/mobile")) { if (uri.startsWith("/bbs/mobile")) {
WxCpOAuth2Service oauth2Service = this.wxCpService.getOauth2Service(); WxCpOAuth2Service oauth2Service = this.mobileWxCpService.getOauth2Service();
String oauth2Url = oauth2Service.buildAuthorizationUrl(this.redirectUrl, null); String oauth2Url = oauth2Service.buildAuthorizationUrl(this.mobileRedirectUrl, null);
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(401, "身份认证失败", oauth2Url))); ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(401, "身份认证失败", oauth2Url)));
} else { } else {
String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", uri); String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", uri);
......
...@@ -65,7 +65,7 @@ public class SysLoginService { ...@@ -65,7 +65,7 @@ public class SysLoginService {
private UserDetailsServiceImpl userDetailsServiceImpl; private UserDetailsServiceImpl userDetailsServiceImpl;
@Autowired @Autowired
private WxCpService wxCpService; private WxCpService mobileWxCpService;
/** /**
......
...@@ -9,6 +9,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties ...@@ -9,6 +9,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.Objects; import java.util.Objects;
...@@ -29,10 +30,11 @@ public class WxCpConfiguration { ...@@ -29,10 +30,11 @@ public class WxCpConfiguration {
/** /**
* 配置 WxCpService 实例 * 配置 WxCpService 实例
*/ */
@Bean @Bean("mobileWxCpService")
public WxCpService wxCpService() { public WxCpService mobileWxCpService() {
WxCpProperties.AppConfig appConfig = this.properties.getAppConfig(); List<WxCpProperties.AppConfig> appConfigs = this.properties.getAppConfigs();
WxCpDefaultConfigImpl configStorage = new WxCpDefaultConfigImpl(); WxCpProperties.AppConfig appConfig = appConfigs.get(0);
WxCpDefaultConfigImpl configStorage = new WxCpDefaultConfigImpl();
configStorage.setCorpId(this.properties.getCorpId()); configStorage.setCorpId(this.properties.getCorpId());
configStorage.setAgentId(appConfig.getAgentId()); configStorage.setAgentId(appConfig.getAgentId());
configStorage.setCorpSecret(appConfig.getSecret()); configStorage.setCorpSecret(appConfig.getSecret());
...@@ -43,4 +45,23 @@ public class WxCpConfiguration { ...@@ -43,4 +45,23 @@ public class WxCpConfiguration {
return service; return service;
} }
/**
* 配置 WxCpService 实例
*/
@Bean("pcWxCpService")
public WxCpService pcWxCpService() {
List<WxCpProperties.AppConfig> appConfigs = this.properties.getAppConfigs();
WxCpProperties.AppConfig appConfig = appConfigs.get(1);
WxCpDefaultConfigImpl configStorage = new WxCpDefaultConfigImpl();
configStorage.setCorpId(this.properties.getCorpId());
configStorage.setAgentId(appConfig.getAgentId());
configStorage.setCorpSecret(appConfig.getSecret());
configStorage.setToken(appConfig.getToken());
configStorage.setAesKey(appConfig.getAesKey());
WxCpService service = new WxCpServiceImpl();
service.setWxCpConfigStorage(configStorage);
return service;
}
} }
...@@ -3,6 +3,8 @@ package com.tangguo.framework.wxcp; ...@@ -3,6 +3,8 @@ package com.tangguo.framework.wxcp;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/** /**
* 企业微信配置类 * 企业微信配置类
* *
...@@ -21,12 +23,14 @@ public class WxCpProperties { ...@@ -21,12 +23,14 @@ public class WxCpProperties {
/** /**
* 多应用配置 * 多应用配置
*/ */
private AppConfig appConfig; private List<AppConfig> appConfigs;
@Data @Data
public static class AppConfig { public static class AppConfig {
private String name;
/** /**
* 设置企业微信应用的AgentId * 设置企业微信应用的AgentId
*/ */
......
...@@ -14,6 +14,8 @@ import com.tangguo.service.IBbsMomentCommentService; ...@@ -14,6 +14,8 @@ import com.tangguo.service.IBbsMomentCommentService;
import com.tangguo.service.IBbsMomentService; import com.tangguo.service.IBbsMomentService;
import com.tangguo.service.IBbsMomentVoteOptionService; import com.tangguo.service.IBbsMomentVoteOptionService;
import com.tangguo.service.IBbsMomentVoteService; import com.tangguo.service.IBbsMomentVoteService;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
...@@ -216,4 +218,16 @@ public class MBbsMomentController { ...@@ -216,4 +218,16 @@ public class MBbsMomentController {
return AjaxResult.success(); return AjaxResult.success();
} }
/**
* 置顶评论
*/
@ApiOperation("置顶评论")
@PostMapping("/comment/top")
public AjaxResult topComment(@RequestBody BbsCommentTopBO bo) {
ValidateOperations.generalValidate(bo);
this.momentService.userTopComment(bo);
return AjaxResult.success();
}
} }
...@@ -6,9 +6,11 @@ import com.tangguo.common.core.domain.AjaxResult; ...@@ -6,9 +6,11 @@ import com.tangguo.common.core.domain.AjaxResult;
import com.tangguo.common.core.page.TableDataInfo; import com.tangguo.common.core.page.TableDataInfo;
import com.tangguo.common.enums.BusinessType; import com.tangguo.common.enums.BusinessType;
import com.tangguo.domain.BbsMomentComment; import com.tangguo.domain.BbsMomentComment;
import com.tangguo.domain.bo.BbsCommentTopBO;
import com.tangguo.service.IBbsMomentCommentService; import com.tangguo.service.IBbsMomentCommentService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.checkerframework.checker.units.qual.A;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
...@@ -79,4 +81,16 @@ public class BbsMomentCommentController extends BaseController { ...@@ -79,4 +81,16 @@ public class BbsMomentCommentController extends BaseController {
return getDataTable(list); return getDataTable(list);
} }
/**
* 置顶评论
*/
@ApiOperation("置顶评论")
@PreAuthorize("@ss.hasPermi('moment:comment:top')")
@PostMapping("/top")
public AjaxResult topComment(@RequestBody BbsCommentTopBO bo) {
this.bbsMomentCommentService.topMomentComment(bo);
return AjaxResult.success();
}
} }
...@@ -13,6 +13,7 @@ import lombok.NoArgsConstructor; ...@@ -13,6 +13,7 @@ import lombok.NoArgsConstructor;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
...@@ -90,6 +91,14 @@ public class BbsMomentComment extends BaseEntity { ...@@ -90,6 +91,14 @@ public class BbsMomentComment extends BaseEntity {
@ApiModelProperty("删除评论内容") @ApiModelProperty("删除评论内容")
private String deleteComment; private String deleteComment;
/** 评论是否置顶:0 否、1 是 */
@ApiModelProperty("评论是否置顶:0 否、1 是")
private Integer isTop;
/** 评论置顶时间 */
@ApiModelProperty("评论置顶时间")
private Date topTime;
/** /**
* 动态内容 * 动态内容
*/ */
......
package com.tangguo.domain.bo;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
*
*
* @author 谈笑
* @createTime 2025-11-05 16:12:43 星期三
*/
@Data
public class BbsCommentTopBO {
/**
* 动态Id
*/
@NotNull(message = "动态Id不能为空")
private Long momentId;
/**
* 评论Id
*/
@NotNull(message = "评论Id不能为空")
private Long commentId;
/**
* 置顶状态:0 取消置顶、1 置顶
*/
@NotNull(message = "置顶状态不能为空")
private Integer isTop;
}
...@@ -2,6 +2,7 @@ package com.tangguo.service; ...@@ -2,6 +2,7 @@ package com.tangguo.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.tangguo.domain.BbsMomentComment; import com.tangguo.domain.BbsMomentComment;
import com.tangguo.domain.bo.BbsCommentTopBO;
import com.tangguo.domain.vo.BbsCommentDetailVO; import com.tangguo.domain.vo.BbsCommentDetailVO;
import java.util.List; import java.util.List;
...@@ -68,4 +69,12 @@ public interface IBbsMomentCommentService extends IService<BbsMomentComment> { ...@@ -68,4 +69,12 @@ public interface IBbsMomentCommentService extends IService<BbsMomentComment> {
*/ */
void deleteMomentComments(Long momentId); void deleteMomentComments(Long momentId);
/**
* 置顶评论
*
* @param bo 请求参数
*/
void topMomentComment(BbsCommentTopBO bo);
} }
...@@ -133,4 +133,12 @@ public interface IBbsMomentService extends IService<BbsMoment> { ...@@ -133,4 +133,12 @@ public interface IBbsMomentService extends IService<BbsMoment> {
*/ */
void userFeaturedComment(FeaturedCommentBO bo); void userFeaturedComment(FeaturedCommentBO bo);
/**
* 置顶评论
*
* @param bo 评论
*/
void userTopComment(BbsCommentTopBO bo);
} }
package com.tangguo.service.impl; package com.tangguo.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tangguo.common.exception.ServiceException;
import com.tangguo.domain.BbsMomentComment; import com.tangguo.domain.BbsMomentComment;
import com.tangguo.domain.bo.BbsCommentTopBO;
import com.tangguo.domain.vo.BbsCommentDetailVO; import com.tangguo.domain.vo.BbsCommentDetailVO;
import com.tangguo.mapper.BbsMomentCommentMapper; import com.tangguo.mapper.BbsMomentCommentMapper;
import com.tangguo.service.IBbsMomentCommentService; import com.tangguo.service.IBbsMomentCommentService;
...@@ -11,6 +15,7 @@ import org.springframework.stereotype.Service; ...@@ -11,6 +15,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
...@@ -110,4 +115,29 @@ public class BbsMomentCommentServiceImpl extends ServiceImpl<BbsMomentCommentMap ...@@ -110,4 +115,29 @@ public class BbsMomentCommentServiceImpl extends ServiceImpl<BbsMomentCommentMap
); );
} }
/**
* 置顶评论
*
* @param bo 请求参数
*/
@Override
public void topMomentComment(BbsCommentTopBO bo) {
BbsMomentComment dbComment = this.getById(bo.getCommentId());
if (Objects.isNull(dbComment)) {
throw new ServiceException("操作失败,未查询到当前评论数据。");
}
LambdaUpdateWrapper<BbsMomentComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(BbsMomentComment::getId, dbComment.getId());
if (bo.getIsTop() == 1) {
wrapper.set(BbsMomentComment::getIsTop, 1);
wrapper.set(BbsMomentComment::getTopTime, new Date());
} else {
wrapper.set(BbsMomentComment::getIsTop, 0);
wrapper.set(BbsMomentComment::getTopTime, null);
}
this.update(wrapper);
}
} }
...@@ -467,8 +467,29 @@ public class BbsMomentServiceImpl extends ServiceImpl<BbsMomentMapper, BbsMoment ...@@ -467,8 +467,29 @@ public class BbsMomentServiceImpl extends ServiceImpl<BbsMomentMapper, BbsMoment
this.commentService.updateById(updComment); this.commentService.updateById(updComment);
} }
/**
/** * 置顶评论
*
* @param bo 评论
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void userTopComment(BbsCommentTopBO bo) {
BbsMoment dbMoment = this.getById(bo.getMomentId());
if (Objects.isNull(dbMoment)) {
throw new ServiceException("操作失败,未查询到当前动态数据。");
}
String userName = SecurityUtils.getUsername();
if (!dbMoment.getUserName().equals(userName)) {
throw new ServiceException("操作失败,没有对当前动态评论的操作权限。");
}
this.commentService.topMomentComment(bo);
}
/**
* 构建动态实体 * 构建动态实体
* *
* @param bo 动态 * @param bo 动态
......
...@@ -27,7 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -27,7 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</if> </if>
</where> </where>
ORDER BY ORDER BY
c.create_time DESC c.is_top DESC, c.top_time DESC, c.create_time DESC
</select> </select>
...@@ -41,7 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -41,7 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHERE WHERE
status = 1 AND FIND_IN_SET(#{commentId}, r.ancestor_path) AND r.id != #{commentId} status = 1 AND FIND_IN_SET(#{commentId}, r.ancestor_path) AND r.id != #{commentId}
ORDER BY ORDER BY
r.create_time r.is_top DESC, r.top_time DESC, r.create_time
</select> </select>
...@@ -53,7 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -53,7 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHERE WHERE
status = 1 AND moment_id = #{momentId} status = 1 AND moment_id = #{momentId}
ORDER BY ORDER BY
create_time is_top DESC, top_time DESC, create_time
</select> </select>
...@@ -94,6 +94,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -94,6 +94,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
OR m.is_enable_featured_comment = 0 OR m.is_enable_featured_comment = 0
OR (m.is_enable_featured_comment = 1 AND (c.user_name = #{userName} OR c.is_featured = 1)) OR (m.is_enable_featured_comment = 1 AND (c.user_name = #{userName} OR c.is_featured = 1))
) )
ORDER BY
c.is_top DESC, c.top_time DESC, c.create_time
) AS c ) AS c
WHERE rn &lt;= #{rows}; WHERE rn &lt;= #{rows};
</select> </select>
...@@ -126,7 +128,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -126,7 +128,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
OR (m.is_enable_featured_comment = 1 AND (c.user_name = #{userName} OR c.is_featured = 1)) OR (m.is_enable_featured_comment = 1 AND (c.user_name = #{userName} OR c.is_featured = 1))
) )
ORDER BY ORDER BY
c.create_time c.is_top DESC, c.top_time DESC, c.create_time
</select> </select>
</mapper> </mapper>
...@@ -20,6 +20,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -20,6 +20,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="moment.content != null and moment.content != ''"> <if test="moment.content != null and moment.content != ''">
m.content LIKE CONCAT('%', #{moment.content}, '%') m.content LIKE CONCAT('%', #{moment.content}, '%')
</if> </if>
<if test="moment.userName != null and moment.userName != ''">
AND uv.user_name LIKE CONCAT('%', #{moment.userName}, '%')
</if>
<if test="moment.nickName != null and moment.nickName != ''">
AND uv.nick_name LIKE CONCAT('%', #{moment.nickName}, '%')
</if>
<if test="moment.topicNames != null and moment.topicNames != ''"> <if test="moment.topicNames != null and moment.topicNames != ''">
AND m.topic_names LIKE CONCAT('%', #{moment.topicNames}, '%') AND m.topic_names LIKE CONCAT('%', #{moment.topicNames}, '%')
</if> </if>
...@@ -133,7 +139,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -133,7 +139,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) v ON v.moment_id = m.id ) v ON v.moment_id = m.id
<where> <where>
<if test="bo.content != null and bo.content != ''"> <if test="bo.content != null and bo.content != ''">
m.content LIKE CONCAT('%', #{bo.content}, '%') (m.content LIKE CONCAT('%', #{bo.content}, '%')
OR uv.user_name LIKE CONCAT('%', #{bo.content}, '%')
OR uv.nick_name LIKE CONCAT('%', #{bo.content}, '%'))
</if> </if>
<if test="bo.topicName != null and bo.topicName != ''"> <if test="bo.topicName != null and bo.topicName != ''">
AND m.topic_names LIKE CONCAT('%', #{bo.topicName}, '%') AND m.topic_names LIKE CONCAT('%', #{bo.topicName}, '%')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment