0.4.1更新消息提醒

This commit is contained in:
磷叶 2025-02-22 17:44:00 +08:00
parent 6a43d7d7a7
commit 5676466435
247 changed files with 1729 additions and 83 deletions

View File

@ -1,3 +1,4 @@
{
"java.compile.nullAnalysis.mode": "automatic"
"java.compile.nullAnalysis.mode": "automatic",
"java.configuration.updateBuildConfiguration": "interactive"
}

View File

@ -16,7 +16,6 @@
<module>ruoyi-common</module>
<module>ruoyi-generator</module>
<module>ruoyi-quartz</module>
<module>ruoyi-system</module>
<module>ruoyi-framework</module>
</modules>

View File

@ -61,4 +61,8 @@ public class CacheConstants
* 资源分类名称列表
*/
public static final String ATTACH_CLASSIFY_NAME_LIST = "attach_classify_name_list";
/**
* websocket用户session
*/
public static final String WS_USER_SESSION = "ws_user_session:";
}

View File

@ -22,4 +22,6 @@ public class DictType {
public static final String NOTICE_LEVEL = "notice_level";
// 客户跟进方式
public static final String CUSTOMER_FOLLOW_TYPE = "customer_follow_type";
// 通知类型
public static final String NOTICE_TYPE = "notice_type";
}

View File

@ -56,7 +56,7 @@
<!-- 系统模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId>
<artifactId>ruoyi-service</artifactId>
</dependency>
</dependencies>

View File

@ -1,10 +1,5 @@
package com.ruoyi.framework.config;
import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
import com.ruoyi.framework.security.filter.CustomLoginAuthenticationProvider;
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -21,6 +16,12 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
import com.ruoyi.framework.security.filter.CustomLoginAuthenticationProvider;
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
/**
* spring security配置
*
@ -115,6 +116,8 @@ public class SecurityConfig
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
// 允许WebSocket连接
.antMatchers("/ws/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
})

View File

@ -3,12 +3,15 @@ package com.ruoyi.framework.web.service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
@ -18,6 +21,7 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
@ -63,6 +67,17 @@ public class TokenService
{
// 获取请求携带的令牌
String token = getToken(request);
return this.getLoginUser(token);
}
/**
* 获取用户身份信息
*
* @param token 令牌
* @return 用户信息
*/
public LoginUser getLoginUser(String token)
{
if (StringUtils.isNotEmpty(token))
{
try

View File

@ -171,7 +171,7 @@
<!-- 系统模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId>
<artifactId>ruoyi-service</artifactId>
<version>${ruoyi.version}</version>
</dependency>
@ -187,6 +187,7 @@
<modules>
<module>ruoyi-web</module>
<module>ruoyi-service</module>
<module>common-ruoyi</module>
</modules>
<packaging>pom</packaging>

View File

@ -3,26 +3,30 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common-ruoyi</artifactId>
<artifactId>project-manager-java</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.8</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-system</artifactId>
<artifactId>ruoyi-service</artifactId>
<description>
system系统模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<!-- WebSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -43,4 +43,8 @@ public class Attach extends BaseEntity
@ApiModelProperty("创建人")
private Long createId;
@Excel(name = "所属部门")
@ApiModelProperty("所属部门")
private Long deptId;
}

View File

@ -11,5 +11,8 @@ public class AttachVO extends Attach {
@ApiModelProperty("创建人")
private String createName;
@ApiModelProperty("所属部门")
private String deptName;
}

View File

@ -15,11 +15,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ba.create_id,
ba.create_time,
ba.deleted,
ba.dept_id,
bac.name as classify_name,
su.nick_name as create_name
su.nick_name as create_name,
sd.dept_name as dept_name
from bst_attach ba
left join bst_attach_classify bac on bac.id = ba.classify_id
left join sys_user su on su.user_id = ba.create_id
left join sys_dept sd on sd.dept_id = ba.dept_id
</sql>
<sql id="searchCondition">
@ -33,6 +36,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.deleted != null"> and ba.deleted = #{query.deleted}</if>
<if test="query.deleted == null"> and ba.deleted = false</if>
<if test="query.createName != null and query.createName != ''"> and su.nick_name like concat('%', #{query.createName}, '%')</if>
<if test="query.deptId != null "> and ba.dept_id = #{query.deptId}</if>
<if test="query.deptName != null and query.deptName != ''"> and sd.dept_name like concat('%', #{query.deptName}, '%')</if>
<if test="query.classifyAncestorId != null">
and bac.id = #{query.classifyAncestorId} or find_in_set(#{query.classifyAncestorId}, bac.ancestors)
</if>
@ -58,6 +63,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="name != null and name != ''">name,</if>
<if test="url != null and url != ''">url,</if>
<if test="createId != null">create_id,</if>
<if test="deptId != null">dept_id,</if>
<if test="createTime != null">create_time,</if>
<if test="deleted != null">deleted,</if>
</trim>
@ -66,6 +72,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="name != null and name != ''">#{name},</if>
<if test="url != null and url != ''">#{url},</if>
<if test="createId != null">#{createId},</if>
<if test="deptId != null">#{deptId},</if>
<if test="createTime != null">#{createTime},</if>
<if test="deleted != null">#{deleted},</if>
</trim>
@ -78,6 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
name,
url,
create_id,
dept_id,
create_time,
deleted,
</trim>
@ -92,6 +100,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="i.url == null or i.url == ''">default,</if>
<if test="i.createId != null ">#{i.createId},</if>
<if test="i.createId == null ">default,</if>
<if test="i.deptId != null ">#{i.deptId},</if>
<if test="i.deptId == null ">default,</if>
<if test="i.createTime != null ">#{i.createTime},</if>
<if test="i.createTime == null ">default,</if>
<if test="i.deleted != null ">#{i.deleted},</if>
@ -163,6 +173,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</otherwise>
</choose>
</foreach>
<foreach open="dept_id = CASE id" collection="list" item="item" close="END,">
<choose>
<when test="item.deptId != null ">
WHEN #{item.id} THEN #{item.deptId}
</when>
<otherwise>
WHEN #{item.id} THEN `dept_id`
</otherwise>
</choose>
</foreach>
</trim>
where id in
<foreach item="item" collection="list" open="(" separator="," close=")">
@ -184,6 +204,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.url != null and data.url != ''">url = #{data.url},</if>
<if test="data.createId != null">create_id = #{data.createId},</if>
<if test="data.createTime != null">create_time = #{data.createTime},</if>
<if test="data.deptId != null">dept_id = #{data.deptId},</if>
</sql>
<delete id="deleteAttachById" parameterType="Long">

View File

@ -29,6 +29,7 @@ public class AttachConverterImpl implements AttachConverter {
po.setCreateId(data.getCreateId());
po.setClassifyId(data.getClassifyId());
po.setCreateId(SecurityUtils.getUserId());
po.setDeptId(data.getDeptId());
result.add(po);
}
@ -45,6 +46,7 @@ public class AttachConverterImpl implements AttachConverter {
po.setId(data.getId());
po.setClassifyId(data.getClassifyId());
po.setName(data.getName());
po.setDeptId(data.getDeptId());
return po;
}

View File

@ -92,4 +92,26 @@ public class Customer extends BaseEntity
@Excel(name = "创建人ID")
@ApiModelProperty("创建人ID")
private Long createId;
@Excel(name = "顾虑点")
@ApiModelProperty("顾虑点")
@Size(max = 200, message = "顾虑点长度不能超过200个字符")
private String concern;
@Excel(name = "痛点")
@ApiModelProperty("痛点")
@Size(max = 200, message = "痛点长度不能超过200个字符")
private String pain;
@Excel(name = "关注点")
@ApiModelProperty("关注点")
@Size(max = 200, message = "关注点长度不能超过200个字符")
private String attention;
@Excel(name = "需求")
@ApiModelProperty("需求")
@Size(max = 200, message = "需求长度不能超过200个字符")
private String demand;
}

View File

@ -26,6 +26,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bc.create_time,
bc.update_time,
bc.deleted,
bc.concern,
bc.pain,
bc.attention,
bc.demand,
suf.nick_name as follow_name,
su.nick_name as create_name
from bst_customer bc
@ -53,6 +57,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.followName != null and query.followName != ''"> and suf.nick_name like concat('%', #{query.followName}, '%')</if>
<if test="query.createName != null and query.createName != ''"> and su.nick_name like concat('%', #{query.createName}, '%')</if>
<if test="query.createId != null "> and su.user_id = #{query.createId}</if>
<if test="query.concern != null and query.concern != ''"> and bc.concern like concat('%', #{query.concern}, '%')</if>
<if test="query.pain != null and query.pain != ''"> and bc.pain like concat('%', #{query.pain}, '%')</if>
<if test="query.attention != null and query.attention != ''"> and bc.attention like concat('%', #{query.attention}, '%')</if>
<if test="query.demand != null and query.demand != ''"> and bc.demand like concat('%', #{query.demand}, '%')</if>
<if test="query.createDateRange != null and query.createDateRange.size() > 1">
and date(bc.create_time) >= #{query.createDateRange[0]}
and date(bc.create_time) &lt;= #{query.createDateRange[1]}
@ -69,6 +77,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{item}
</foreach>
</if>
${@com.ruoyi.framework.util.DataScopeUtil@dataScope(
null,
"bc.create_id,bc.follow_id",
null,
null,
query.scope
)}
${query.params.dataScope}
</sql>
@ -103,6 +118,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deleted != null">deleted,</if>
<if test="createId != null">create_id,</if>
<if test="nextFollowTime != null">next_follow_time,</if>
<if test="concern != null and concern != ''">concern,</if>
<if test="pain != null and pain != ''">pain,</if>
<if test="attention != null and attention != ''">attention,</if>
<if test="demand != null and demand != ''">demand,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="code != null and code != ''">#{code},</if>
@ -121,6 +140,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deleted != null">#{deleted},</if>
<if test="createId != null">#{createId},</if>
<if test="nextFollowTime != null">#{nextFollowTime},</if>
<if test="concern != null and concern != ''">#{concern},</if>
<if test="pain != null and pain != ''">#{pain},</if>
<if test="attention != null and attention != ''">#{attention},</if>
<if test="demand != null and demand != ''">#{demand},</if>
</trim>
</insert>
@ -149,6 +172,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.deleted != null">deleted = #{data.deleted},</if>
<if test="data.createId != null">create_id = #{data.createId},</if>
<if test="data.nextFollowTime != null">next_follow_time = #{data.nextFollowTime},</if>
<if test="data.concern != null">concern = #{data.concern},</if>
<if test="data.pain != null">pain = #{data.pain},</if>
<if test="data.attention != null">attention = #{data.attention},</if>
<if test="data.demand != null">demand = #{data.demand},</if>
</sql>

View File

@ -7,7 +7,6 @@ import com.ruoyi.bst.customer.domain.Customer;
import com.ruoyi.bst.customer.domain.CustomerQuery;
import com.ruoyi.bst.customer.domain.CustomerVO;
import com.ruoyi.bst.customer.domain.dto.CustomerAddDTO;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.vo.LocalDateIntegerVO;
import com.ruoyi.common.vo.StringIntegerVO;
@ -84,16 +83,6 @@ public interface CustomerService
*/
int updateFollowTime(Long customerId, LocalDateTime lastFollowTime, LocalDateTime nextFollowTime);
/**
* 查询客户列表并根据数据权限过滤
* @param query
* @return
*/
@DataScope(userAlias = "bc.create_id,bc.follow_id")
default List<CustomerVO> selectCustomerListScope(CustomerQuery query) {
return selectCustomerList(query);
}
/**
* 逻辑删除
* @param ids

View File

@ -10,7 +10,6 @@ import com.ruoyi.bst.customerFollow.domain.CustomerFollow;
@Service
public class CustomerConverterImpl implements CustomerConverter {
@Override
public CustomerAddDTO toDTOByCreate(CustomerAddDTO customer) {
if (customer == null) {
@ -24,9 +23,13 @@ public class CustomerConverterImpl implements CustomerConverter {
po.setWechat(customer.getWechat());
po.setSource(customer.getSource());
po.setIntents(customer.getIntents());
po.setFollowId(customer.getFollowId());
po.setRemark(customer.getRemark());
po.setFollow(customer.getFollow());
po.setFollowId(customer.getFollowId());
po.setConcern(customer.getConcern());
po.setPain(customer.getPain());
po.setAttention(customer.getAttention());
po.setDemand(customer.getDemand());
return po;
}
@ -46,6 +49,10 @@ public class CustomerConverterImpl implements CustomerConverter {
po.setIntents(customer.getIntents());
po.setFollowId(customer.getFollowId());
po.setRemark(customer.getRemark());
po.setConcern(customer.getConcern());
po.setPain(customer.getPain());
po.setAttention(customer.getAttention());
po.setDemand(customer.getDemand());
return po;
}

View File

@ -34,6 +34,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.customerName != null and query.customerName != ''"> and bc.name like concat('%', #{query.customerName}, '%')</if>
<if test="query.customerCode != null and query.customerCode != ''"> and bc.code like concat('%', #{query.customerCode}, '%')</if>
<if test="query.userName != null and query.userName != ''"> and su.nick_name like concat('%', #{query.userName}, '%')</if>
${@com.ruoyi.framework.util.DataScopeUtil@dataScope(
null,
"bcf.user_id",
null,
null,
query.scope
)}
${query.params.dataScope}
</sql>

View File

@ -5,7 +5,6 @@ import java.util.List;
import com.ruoyi.bst.customerFollow.domain.CustomerFollow;
import com.ruoyi.bst.customerFollow.domain.CustomerFollowQuery;
import com.ruoyi.bst.customerFollow.domain.CustomerFollowVO;
import com.ruoyi.common.annotation.DataScope;
/**
* 客户跟进记录Service接口
@ -62,14 +61,4 @@ public interface CustomerFollowService
* @return 结果
*/
public int deleteCustomerFollowByFollowId(Long followId);
/**
* 查询客户跟进记录列表并根据数据权限过滤
* @param query
* @return
*/
@DataScope(userAlias = "bcf.user_id")
default List<CustomerFollowVO> selectCustomerFollowListScope(CustomerFollowQuery query) {
return selectCustomerFollowList(query);
}
}

View File

@ -0,0 +1,55 @@
package com.ruoyi.bst.message.domain;
import java.time.LocalDateTime;
import org.springframework.format.annotation.DateTimeFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 消息对象 bst_message
*
* @author ruoyi
* @date 2025-02-22
*/
@Data
public class Message extends BaseEntity
{
private static final long serialVersionUID = 1L;
private Long id;
@Excel(name = "接收人")
@ApiModelProperty("接收人")
private Long userId;
@Excel(name = "业务类型")
@ApiModelProperty("业务类型")
private String bstType;
@Excel(name = "业务ID")
@ApiModelProperty("业务ID")
private Long bstId;
@Excel(name = "标题")
@ApiModelProperty("标题")
private String title;
@Excel(name = "内容")
@ApiModelProperty("内容")
private String content;
@Excel(name = "是否已读")
@ApiModelProperty("是否已读")
private Boolean isRead;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "已读时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("已读时间")
private LocalDateTime readTime;
}

View File

@ -0,0 +1,8 @@
package com.ruoyi.bst.message.domain;
import lombok.Data;
@Data
public class MessageQuery extends MessageVO {
}

View File

@ -0,0 +1,8 @@
package com.ruoyi.bst.message.domain;
import lombok.Data;
@Data
public class MessageVO extends Message{
}

View File

@ -0,0 +1,17 @@
package com.ruoyi.bst.message.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum MessageBstType {
TASK("task", "任务"),
TASK_SUBMIT("task_submit", "任务提交"),
CUSTOMER("customer", "客户");
private String value;
private String name;
}

View File

@ -0,0 +1,88 @@
package com.ruoyi.bst.message.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.bst.message.domain.Message;
import com.ruoyi.bst.message.domain.MessageQuery;
import com.ruoyi.bst.message.domain.MessageVO;
/**
* 消息Mapper接口
*
* @author ruoyi
* @date 2025-02-22
*/
public interface MessageMapper
{
/**
* 查询消息
*
* @param id 消息主键
* @return 消息
*/
MessageVO selectMessageById(Long id);
/**
* 查询消息列表
*
* @param query 消息
* @return 消息集合
*/
List<MessageVO> selectMessageList(@Param("query")MessageQuery query);
/**
* 新增消息
*
* @param message 消息
* @return 结果
*/
int insertMessage(Message message);
/**
* 修改消息
*
* @param message 消息
* @return 结果
*/
public int updateMessage(@Param("data") Message message);
/**
* 删除消息
*
* @param id 消息主键
* @return 结果
*/
int deleteMessageById(Long id);
/**
* 批量删除消息
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteMessageByIds(Long[] ids);
/**
* 根据条件更新
* @param data
* @param query
* @return
*/
int updateByQuery(@Param("data") Message data, @Param("query") MessageQuery query);
/**
* 查询数量
* @param query
* @return
*/
int selectCount(@Param("query") MessageQuery query);
/**
* 批量插入消息
* @param list
* @return
*/
int batchInsert(@Param("list") List<Message> list);
}

View File

@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.bst.message.mapper.MessageMapper">
<resultMap type="MessageVO" id="MessageResult" autoMapping="true"/>
<sql id="selectMessageVo">
select
bm.id,
bm.user_id,
bm.bst_type,
bm.bst_id,
bm.title,
bm.content,
bm.is_read,
bm.create_time,
bm.read_time
from bst_message bm
</sql>
<sql id="searchCondition">
<if test="query.id != null "> and bm.id = #{query.id}</if>
<if test="query.userId != null "> and bm.user_id = #{query.userId}</if>
<if test="query.bstType != null and query.bstType != ''"> and bm.bst_type = #{query.bstType}</if>
<if test="query.bstId != null "> and bm.bst_id = #{query.bstId}</if>
<if test="query.title != null and query.title != ''"> and bm.title like concat('%', #{query.title}, '%')</if>
<if test="query.content != null and query.content != ''"> and bm.content like concat('%', #{query.content}, '%')</if>
<if test="query.isRead != null "> and bm.is_read = #{query.isRead}</if>
<if test="query.readTime != null "> and bm.read_time = #{query.readTime}</if>
${@com.ruoyi.framework.util.DataScopeUtil@dataScope(
null,
"bm.user_id",
null,
null,
query.scope
)}
${query.params.dataScope}
</sql>
<select id="selectMessageList" parameterType="MessageQuery" resultMap="MessageResult">
<include refid="selectMessageVo"/>
<where>
<include refid="searchCondition"/>
</where>
</select>
<select id="selectMessageById" parameterType="Long" resultMap="MessageResult">
<include refid="selectMessageVo"/>
where bm.id = #{id}
</select>
<insert id="insertMessage" parameterType="Message" useGeneratedKeys="true" keyProperty="id">
insert into bst_message
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userId != null">user_id,</if>
<if test="bstType != null and bstType != ''">bst_type,</if>
<if test="bstId != null">bst_id,</if>
<if test="title != null and title != ''">title,</if>
<if test="content != null">content,</if>
<if test="isRead != null">is_read,</if>
<if test="createTime != null">create_time,</if>
<if test="readTime != null">read_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">#{userId},</if>
<if test="bstType != null and bstType != ''">#{bstType},</if>
<if test="bstId != null">#{bstId},</if>
<if test="title != null and title != ''">#{title},</if>
<if test="content != null">#{content},</if>
<if test="isRead != null">#{isRead},</if>
<if test="createTime != null">#{createTime},</if>
<if test="readTime != null">#{readTime},</if>
</trim>
</insert>
<insert id="batchInsert" parameterType="Message" useGeneratedKeys="true" keyProperty="id">
insert into bst_message
<trim prefix="(" suffix=")" suffixOverrides=",">
user_id,
bst_type,
bst_id,
title,
content,
is_read,
create_time,
read_time,
</trim>
values
<foreach collection="list" item="i" separator=",">
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="i.userId != null ">#{i.userId},</if>
<if test="i.userId == null ">default,</if>
<if test="i.bstType != null and i.bstType != ''">#{i.bstType},</if>
<if test="i.bstType == null or i.bstType == ''">default,</if>
<if test="i.bstId != null ">#{i.bstId},</if>
<if test="i.bstId == null ">default,</if>
<if test="i.title != null and i.title != ''">#{i.title},</if>
<if test="i.title == null or i.title == ''">default,</if>
<if test="i.content != null ">#{i.content},</if>
<if test="i.content == null ">default,</if>
<if test="i.isRead != null ">#{i.isRead},</if>
<if test="i.isRead == null ">default,</if>
<if test="i.createTime != null ">#{i.createTime},</if>
<if test="i.createTime == null ">default,</if>
<if test="i.readTime != null ">#{i.readTime},</if>
<if test="i.readTime == null ">default,</if>
</trim>
</foreach>
</insert>
<update id="updateMessage" parameterType="Message">
update bst_message
<trim prefix="SET" suffixOverrides=",">
<include refid="updateColumns"/>
</trim>
where id = #{data.id}
</update>
<sql id="updateColumns">
<if test="data.userId != null">user_id = #{data.userId},</if>
<if test="data.bstType != null and data.bstType != ''">bst_type = #{data.bstType},</if>
<if test="data.bstId != null">bst_id = #{data.bstId},</if>
<if test="data.title != null and data.title != ''">title = #{data.title},</if>
<if test="data.content != null">content = #{data.content},</if>
<if test="data.isRead != null">is_read = #{data.isRead},</if>
<if test="data.createTime != null">create_time = #{data.createTime},</if>
<if test="data.readTime != null">read_time = #{data.readTime},</if>
</sql>
<delete id="deleteMessageById" parameterType="Long">
delete from bst_message where id = #{id}
</delete>
<delete id="deleteMessageByIds" parameterType="String">
delete from bst_message where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<!-- updateByQuery -->
<update id="updateByQuery">
update bst_message bm
<trim prefix="SET" suffixOverrides=",">
<include refid="updateColumns"/>
</trim>
<where>
<include refid="searchCondition"/>
</where>
</update>
<!-- selectCount -->
<select id="selectCount" parameterType="MessageQuery" resultType="int">
select count(bm.id)
from bst_message bm
<where>
<include refid="searchCondition"/>
</where>
</select>
</mapper>

View File

@ -0,0 +1,46 @@
package com.ruoyi.bst.message.service;
import java.util.List;
import com.ruoyi.bst.message.domain.Message;
import com.ruoyi.bst.task.domain.TaskVO;
import com.ruoyi.bst.taskSubmit.domain.TaskSubmitVO;
public interface MessageConverter {
/**
* 将任务创建消息转换为消息实体
* @param vo
* @return
*/
List<Message> toPoByTaskCreate(TaskVO vo);
/**
* 将任务更新消息转换为消息实体
* @param vo
* @return
*/
List<Message> toPoByTaskUpdate(TaskVO vo);
/**
* 将任务提交消息转换为消息实体
* @param vo
* @return
*/
List<Message> toPoByTaskSubmit(TaskSubmitVO vo);
/**
* 将任务完成消息转换为消息实体
* @param vo
* @return
*/
List<Message> toPoByTaskPass(TaskVO vo);
/**
* 将任务取消消息转换为消息实体
* @param vo
* @return
*/
List<Message> toPoByTaskCancel(TaskVO vo);
}

View File

@ -0,0 +1,86 @@
package com.ruoyi.bst.message.service;
import java.util.List;
import com.ruoyi.bst.message.domain.Message;
import com.ruoyi.bst.message.domain.MessageQuery;
import com.ruoyi.bst.message.domain.MessageVO;
/**
* 消息Service接口
*
* @author ruoyi
* @date 2025-02-22
*/
public interface MessageService
{
/**
* 查询消息
*
* @param id 消息主键
* @return 消息
*/
public MessageVO selectMessageById(Long id);
/**
* 查询消息列表
*
* @param message 消息
* @return 消息集合
*/
public List<MessageVO> selectMessageList(MessageQuery message);
/**
* 新增消息
*
* @param message 消息
* @return 结果
*/
public int insertMessage(Message message);
/**
* 修改消息
*
* @param message 消息
* @return 结果
*/
public int updateMessage(Message message);
/**
* 批量删除消息
*
* @param ids 需要删除的消息主键集合
* @return 结果
*/
public int deleteMessageByIds(Long[] ids);
/**
* 删除消息信息
*
* @param id 消息主键
* @return 结果
*/
public int deleteMessageById(Long id);
/**
* 消息已读
* @param userId
* @param id
* @return
*/
public int read(Long userId, Long id);
/**
* 查询未读消息数量
* @param query
* @return
*/
public int selectCount(MessageQuery query);
/**
* 批量插入消息
* @param list
* @return
*/
public int batchInsert(List<Message> list);
}

View File

@ -0,0 +1,148 @@
package com.ruoyi.bst.message.service.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import com.google.common.base.Objects;
import com.ruoyi.bst.message.domain.Message;
import com.ruoyi.bst.message.domain.enums.MessageBstType;
import com.ruoyi.bst.message.service.MessageConverter;
import com.ruoyi.bst.task.domain.TaskVO;
import com.ruoyi.bst.taskSubmit.domain.TaskSubmitVO;
import com.ruoyi.common.utils.collection.CollectionUtils;
@Service
public class MessageConverterImpl implements MessageConverter {
@Override
public List<Message> toPoByTaskCreate(TaskVO vo) {
if (vo == null || CollectionUtils.isEmptyElement(vo.getOwnerIds())) {
return Collections.emptyList();
}
List<Message> result = new ArrayList<>();
String bstType = MessageBstType.TASK.getValue();
String title = "新任务";
String content = String.format("%s创建了一个新任务%s\n截止时间%s", vo.getCreateName(), vo.getDescription(), vo.getExpireTime());
for (Long ownerId : vo.getOwnerIds()) {
Message message = new Message();
message.setBstType(bstType);
message.setBstId(vo.getId());
message.setUserId(ownerId);
message.setTitle(title);
message.setContent(content);
result.add(message);
}
return result;
}
@Override
public List<Message> toPoByTaskUpdate(TaskVO vo) {
if (vo == null || CollectionUtils.isEmptyElement(vo.getOwnerIds())) {
return Collections.emptyList();
}
List<Message> result = new ArrayList<>();
String bstType = MessageBstType.TASK.getValue();
String title = "任务更新";
String content = String.format("新内容:%s", vo.getDescription());
for (Long ownerId : vo.getOwnerIds()) {
Message message = new Message();
message.setBstType(bstType);
message.setBstId(vo.getId());
message.setUserId(ownerId);
message.setTitle(title);
message.setContent(content);
result.add(message);
}
return result;
}
@Override
public List<Message> toPoByTaskSubmit(TaskSubmitVO vo) {
if (vo == null) {
return Collections.emptyList();
}
List<Message> result = new ArrayList<>();
String bstType = MessageBstType.TASK.getValue();
String title = "任务提交";
String remark = vo.getRemark() == null ? "--" : vo.getRemark();
String content = String.format("%s提交了任务%s\n备注%s", vo.getUserName(), vo.getTaskDescription(), remark);
// 获取通知人任务创建人除了提交人以外的任务负责人
List<Long> userIds = vo.getTaskOwnerIds() == null ? new ArrayList<>() : vo.getTaskOwnerIds();
userIds.add(vo.getTaskCreateId());
userIds = userIds.stream().filter(item -> {
return item != null && !Objects.equal(item, vo.getUserId());
}).collect(Collectors.toList());
for (Long ownerId : userIds) {
Message message = new Message();
message.setBstType(bstType);
message.setBstId(vo.getTaskId());
message.setUserId(ownerId);
message.setTitle(title);
message.setContent(content);
result.add(message);
}
return result;
}
@Override
public List<Message> toPoByTaskPass(TaskVO vo) {
if (vo == null) {
return Collections.emptyList();
}
List<Message> result = new ArrayList<>();
String bstType = MessageBstType.TASK.getValue();
String title = "任务完成";
String content = String.format("任务:%s已完成", vo.getDescription());
Message message = new Message();
message.setBstType(bstType);
message.setBstId(vo.getId());
message.setUserId(vo.getCreateId());
message.setTitle(title);
message.setContent(content);
result.add(message);
return result;
}
@Override
public List<Message> toPoByTaskCancel(TaskVO vo) {
if (vo == null) {
return Collections.emptyList();
}
List<Message> result = new ArrayList<>();
String bstType = MessageBstType.TASK.getValue();
String title = "任务取消";
String content = String.format("任务:%s已取消\n取消原因%s", vo.getDescription(), vo.getCancelRemark());
for (Long ownerId : vo.getOwnerIds()) {
Message message = new Message();
message.setBstType(bstType);
message.setBstId(vo.getId());
message.setUserId(ownerId);
message.setTitle(title);
message.setContent(content);
result.add(message);
}
return result;
}
}

View File

@ -0,0 +1,163 @@
package com.ruoyi.bst.message.service.impl;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.bst.message.domain.Message;
import com.ruoyi.bst.message.domain.MessageQuery;
import com.ruoyi.bst.message.domain.MessageVO;
import com.ruoyi.bst.message.mapper.MessageMapper;
import com.ruoyi.bst.message.service.MessageService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ws.service.WebSocketService;
import lombok.extern.slf4j.Slf4j;
/**
* 消息Service业务层处理
*
* @author ruoyi
* @date 2025-02-22
*/
@Service
@Slf4j
public class MessageServiceImpl implements MessageService
{
@Autowired
private MessageMapper messageMapper;
@Autowired
private WebSocketService webSocketService;
/**
* 查询消息
*
* @param id 消息主键
* @return 消息
*/
@Override
public MessageVO selectMessageById(Long id)
{
return messageMapper.selectMessageById(id);
}
/**
* 查询消息列表
*
* @param message 消息
* @return 消息
*/
@Override
public List<MessageVO> selectMessageList(MessageQuery message)
{
return messageMapper.selectMessageList(message);
}
/**
* 新增消息
*
* @param message 消息
* @return 结果
*/
@Override
public int insertMessage(Message message)
{
message.setCreateTime(DateUtils.getNowDate());
int rows = messageMapper.insertMessage(message);
if (rows > 0) {
if (message.getUserId() != null) {
webSocketService.sendMessageToUser(message, message.getUserId());
}
}
return rows;
}
/**
* 修改消息
*
* @param message 消息
* @return 结果
*/
@Override
public int updateMessage(Message message)
{
return messageMapper.updateMessage(message);
}
/**
* 批量删除消息
*
* @param ids 需要删除的消息主键
* @return 结果
*/
@Override
public int deleteMessageByIds(Long[] ids)
{
return messageMapper.deleteMessageByIds(ids);
}
/**
* 删除消息信息
*
* @param id 消息主键
* @return 结果
*/
@Override
public int deleteMessageById(Long id)
{
return messageMapper.deleteMessageById(id);
}
@Override
public int read(Long userId, Long id){
// 两个条件不允许同时为空
if (id == null && userId == null) {
return 0;
}
Message data = new Message();
data.setIsRead(true);
data.setReadTime(LocalDateTime.now());
MessageQuery query = new MessageQuery();
query.setUserId(userId);
query.setId(id);
query.setIsRead(false);
return messageMapper.updateByQuery(data, query);
}
@Override
public int selectCount(MessageQuery query)
{
return messageMapper.selectCount(query);
}
@Override
public int batchInsert(List<Message> list) {
if (CollectionUtils.isEmptyElement(list)) {
return 0;
}
Date now = DateUtils.getNowDate();
list.forEach(message -> {
message.setCreateTime(now);
});
int rows = messageMapper.batchInsert(list);
if (rows > 0) {
for (Message message : list) {
try {
if (message.getUserId() != null) {
webSocketService.sendMessageToUser(message, message.getUserId());
}
} catch (Exception e) {
log.error("发送消息给用户{}失败", message.getUserId(), e);
}
}
}
return rows;
}
}

View File

@ -1,16 +1,21 @@
package com.ruoyi.bst.notice.service.impl;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.bst.message.domain.Message;
import com.ruoyi.bst.notice.domain.Notice;
import com.ruoyi.bst.notice.domain.NoticeQuery;
import com.ruoyi.bst.notice.domain.NoticeVO;
import com.ruoyi.bst.notice.mapper.NoticeMapper;
import com.ruoyi.bst.notice.service.NoticeService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.user.service.UserService;
import com.ruoyi.ws.service.WebSocketService;
/**
* 公告Service业务层处理
@ -24,6 +29,13 @@ public class NoticeServiceImpl implements NoticeService
@Autowired
private NoticeMapper noticeMapper;
@Autowired
private WebSocketService webSocketService;
@Autowired
private UserService userService;
/**
* 查询公告
*
@ -58,7 +70,12 @@ public class NoticeServiceImpl implements NoticeService
public int insertNotice(Notice notice)
{
notice.setCreateTime(DateUtils.getNowDate());
return noticeMapper.insertNotice(notice);
int rows = noticeMapper.insertNotice(notice);
// 发送消息给接收人
this.sendNotice(notice.getId());
return rows;
}
/**
@ -70,7 +87,36 @@ public class NoticeServiceImpl implements NoticeService
@Override
public int updateNotice(Notice notice)
{
return noticeMapper.updateNotice(notice);
int rows = noticeMapper.updateNotice(notice);
// 发送消息给接收人
this.sendNotice(notice.getId());
return rows;
}
/**
* 发送消息给接收人
* @param id
*/
private boolean sendNotice(Long id) {
NoticeVO vo = this.selectNoticeById(id);
if (vo == null) {
return false;
}
// 获取接收人ID列表
Set<Long> userIds = vo.getReceiveUserIds() == null ? new HashSet<>() : new HashSet<>(vo.getReceiveUserIds());
userIds.addAll(userService.selectUserIdsByDeptIds(vo.getReceiveDeptIds()));
// 发送消息给接收人
Message message = new Message();
message.setTitle("【公告】" + vo.getTitle());
message.setContent(vo.getContent());
webSocketService.sendMessageToUser(message, userIds);
return true;
}
/**

View File

@ -1,5 +1,7 @@
package com.ruoyi.bst.project.domain.vo;
import java.util.List;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -12,4 +14,13 @@ public class ProjectNameVO {
@ApiModelProperty("项目名称")
private String name;
@ApiModelProperty("项目负责人ID")
private Long ownerId;
@ApiModelProperty("项目跟进人ID")
private Long followId;
@ApiModelProperty("项目成员ID列表")
private List<Long> memberIds;
}

View File

@ -199,10 +199,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and deleted = false
</update>
<select id="selectNameList" parameterType="ProjectQuery" resultType="ProjectNameVO">
<resultMap type="ProjectNameVO" id="ProjectNameResult" autoMapping="true">
<result property="memberIds" column="member_ids" typeHandler="com.ruoyi.common.mybatis.typehandler.LongSplitListTypeHandler"/>
</resultMap>
<select id="selectNameList" parameterType="ProjectQuery" resultMap="ProjectNameResult">
select
bp.id,
bp.name
bp.name,
bp.owner_id,
bp.follow_id,
bp.member_ids
from bst_project bp
<where>
<include refid="searchCondition"/>

View File

@ -18,6 +18,6 @@ public class TaskQuery extends TaskVO{
private List<String> statusList;
@ApiModelProperty("任务id列表")
private List<Long> taskIds;
private List<Long> ids;
}

View File

@ -34,4 +34,13 @@ public class TaskVO extends Task{
@ApiModelProperty("是否逾期")
private Boolean overdue;
@ApiModelProperty("项目负责人ID")
private Long projectOwnerId;
@ApiModelProperty("项目跟进人ID")
private Long projectFollowId;
@ApiModelProperty("项目成员ID列表")
private List<Long> projectMemberIds;
}

View File

@ -6,6 +6,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="TaskVO" id="TaskResult" autoMapping="true">
<result property="ownerIds" column="owner_ids" typeHandler="com.ruoyi.common.mybatis.typehandler.LongSplitListTypeHandler"/>
<result property="projectMemberIds" column="project_member_ids" typeHandler="com.ruoyi.common.mybatis.typehandler.LongSplitListTypeHandler"/>
</resultMap>
<!-- 是否逾期 -->
@ -34,6 +35,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bt.cancel_remark,
<include refid="overdue"/> as overdue,
bp.name as project_name,
bp.owner_id as project_owner_id,
bp.follow_id as project_follow_id,
bp.member_ids as project_member_ids,
su.nick_name as create_name,
cu.nick_name as cancel_user_name
from bst_task bt
@ -63,12 +67,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.overdue != null">
and <include refid="overdue"/> = #{query.overdue}
</if>
<if test="query.projectOwnerId != null"> and bp.owner_id = #{query.projectOwnerId}</if>
<if test="query.projectFollowId != null"> and bp.follow_id = #{query.projectFollowId}</if>
<if test="query.statusList != null and query.statusList.size() > 0">
and bt.status in
<foreach item="item" collection="query.statusList" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="query.ids != null and query.ids.size() > 0">
and bt.id in
<foreach item="item" collection="query.ids" open="(" separator="," close=")">
#{item}
</foreach>
</if>
${@com.ruoyi.framework.util.DataScopeUtil@dataScope(
null,
"bt.cancel_user_id,bt.create_id",

View File

@ -1,5 +1,7 @@
package com.ruoyi.bst.task.service;
import com.ruoyi.bst.task.domain.TaskVO;
public interface TaskValidator {
/**
@ -17,5 +19,11 @@ public interface TaskValidator {
* @return 是否能开始
*/
boolean allowStart(Long id, Long userId);
/**
* 校验任务
* @param vo 任务VO
*/
void validate(TaskVO vo);
}

View File

@ -9,9 +9,9 @@ import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.bst.task.domain.TaskQuery;
import com.ruoyi.bst.task.domain.TaskVO;
import com.ruoyi.bst.task.service.TaskAssembler;
import com.ruoyi.bst.taskSubmit.domain.TaskSubmitQuery;
import com.ruoyi.bst.taskSubmit.domain.TaskSubmitVO;
import com.ruoyi.bst.taskSubmit.domain.enums.TaskSubmitStatus;
import com.ruoyi.bst.taskSubmit.service.TaskSubmitService;
@ -75,7 +75,7 @@ public class TaskAssemblerImpl implements TaskAssembler {
}
List<Long> taskIds = CollectionUtils.map(list, TaskVO::getId);
TaskQuery query = new TaskQuery();
TaskSubmitQuery query = new TaskSubmitQuery();
query.setTaskIds(taskIds);
Map<Long, Integer> map = taskSubmitService.selectCountGroupByTaskId(query)
.stream().collect(Collectors.toMap(LongIntegerVO::getKey, LongIntegerVO::getValue));
@ -97,7 +97,7 @@ public class TaskAssemblerImpl implements TaskAssembler {
}
List<Long> taskIds = CollectionUtils.map(list, TaskVO::getId);
TaskQuery query = new TaskQuery();
TaskSubmitQuery query = new TaskSubmitQuery();
query.setTaskIds(taskIds);
query.setStatus(TaskSubmitStatus.PASS.getCode());
Map<Long, Integer> map = taskSubmitService.selectCountGroupByTaskId(query)
@ -108,7 +108,7 @@ public class TaskAssemblerImpl implements TaskAssembler {
if (count == null) {
count = 0;
}
vo.setSubmitCount(count);
vo.setPassCount(count);
}
}
}

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