Merge remote-tracking branch 'origin/wzj-main' into wzj-main
# Conflicts: # ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/domain/po/Withdraw.java # ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/mapper/WithdrawMapper.java # ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/service/IWithdrawService.java # ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/service/impl/WithdrawServiceImpl.java # ruoyi-modules/ruoyi-system/pom.xml # ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java
This commit is contained in:
commit
09e66734ce
@ -11,6 +11,13 @@ spring.boot.admin.client:
|
|||||||
username: @monitor.username@
|
username: @monitor.username@
|
||||||
password: @monitor.password@
|
password: @monitor.password@
|
||||||
|
|
||||||
|
--- # 禁用RabbitMQ自动配置
|
||||||
|
spring:
|
||||||
|
rabbitmq:
|
||||||
|
enabled: false
|
||||||
|
autoconfigure:
|
||||||
|
exclude: org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
|
||||||
|
|
||||||
--- # snail-job 配置
|
--- # snail-job 配置
|
||||||
snail-job:
|
snail-job:
|
||||||
enabled: false
|
enabled: false
|
||||||
@ -133,6 +140,30 @@ redisson:
|
|||||||
# 发布和订阅连接池大小
|
# 发布和订阅连接池大小
|
||||||
subscriptionConnectionPoolSize: 50
|
subscriptionConnectionPoolSize: 50
|
||||||
|
|
||||||
|
--- # RocketMQ 配置
|
||||||
|
rocketmq:
|
||||||
|
# RocketMQ 服务器地址
|
||||||
|
name-server: 82.156.121.2:9876
|
||||||
|
# 生产者配置
|
||||||
|
producer:
|
||||||
|
# 生产者组名
|
||||||
|
group: wzj_group
|
||||||
|
# 发送消息超时时间
|
||||||
|
send-message-timeout: 30000
|
||||||
|
# 消息最大长度
|
||||||
|
max-message-size: 4194304
|
||||||
|
# 消息发送失败重试次数
|
||||||
|
retry-times-when-send-failed: 3
|
||||||
|
# 异步消息发送失败重试次数
|
||||||
|
retry-times-when-send-async-failed: 3
|
||||||
|
# 消费者配置
|
||||||
|
consumer:
|
||||||
|
# 拉取消息最大数量
|
||||||
|
pull-batch-size: 10
|
||||||
|
# 消费者组 (系统模块)
|
||||||
|
group: consumer_group_system
|
||||||
|
# 是否启动消费者
|
||||||
|
enabled: true
|
||||||
--- # mail 邮件发送
|
--- # mail 邮件发送
|
||||||
mail:
|
mail:
|
||||||
enabled: false
|
enabled: false
|
||||||
@ -263,3 +294,17 @@ justauth:
|
|||||||
client-id: 10**********6
|
client-id: 10**********6
|
||||||
client-secret: 1f7d08**********5b7**********29e
|
client-secret: 1f7d08**********5b7**********29e
|
||||||
redirect-uri: ${justauth.address}/social-callback?source=gitlab
|
redirect-uri: ${justauth.address}/social-callback?source=gitlab
|
||||||
|
|
||||||
|
# 腾讯云IM配置
|
||||||
|
tencent:
|
||||||
|
im:
|
||||||
|
# 腾讯云 SDKAppId
|
||||||
|
sdkappid: 1600080789
|
||||||
|
# 密钥
|
||||||
|
secretkey: 311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091
|
||||||
|
# 签名过期时间(秒)
|
||||||
|
expire: 604800
|
||||||
|
# 管理员账号
|
||||||
|
admin: administrator
|
||||||
|
# API调用密钥
|
||||||
|
api-secret: 311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091
|
||||||
|
@ -147,11 +147,14 @@ tenant:
|
|||||||
- ums_account
|
- ums_account
|
||||||
- ums_account_change_record
|
- ums_account_change_record
|
||||||
- sys_message_template
|
- sys_message_template
|
||||||
|
- sys_message_user
|
||||||
- ums_fans
|
- ums_fans
|
||||||
- ums_block
|
- ums_block
|
||||||
- ums_forbidden
|
- ums_forbidden
|
||||||
- ums_member_bank
|
- ums_member_bank
|
||||||
- ums_tenant_forbidden
|
- ums_tenant_forbidden
|
||||||
|
- ums_charge
|
||||||
|
- ums_withdraw
|
||||||
- oms_aftersale
|
- oms_aftersale
|
||||||
- oms_aftersale_item
|
- oms_aftersale_item
|
||||||
- oms_order
|
- oms_order
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.dromara.common.core.domain.model;
|
package org.dromara.common.core.domain.model;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -14,6 +16,10 @@ public class BaseAudit {
|
|||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* 创建部门
|
||||||
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ -25,6 +31,7 @@ public class BaseAudit {
|
|||||||
/**
|
/**
|
||||||
* 更新时间
|
* 更新时间
|
||||||
*/
|
*/
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private LocalDateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import cn.hutool.http.HttpStatus;
|
|||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.ibatis.reflection.MetaObject;
|
import org.apache.ibatis.reflection.MetaObject;
|
||||||
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
import org.dromara.common.core.domain.model.LoginUser;
|
import org.dromara.common.core.domain.model.LoginUser;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.utils.ObjectUtils;
|
import org.dromara.common.core.utils.ObjectUtils;
|
||||||
@ -48,7 +49,11 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
|||||||
baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
|
baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if(ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseAudit baseAudit) {
|
||||||
|
baseAudit.setCreateTime(LocalDateTime.now());
|
||||||
|
baseAudit.setUpdateTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
}else{
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
this.strictInsertFill(metaObject, "createTime", Date.class, date);
|
this.strictInsertFill(metaObject, "createTime", Date.class, date);
|
||||||
this.strictInsertFill(metaObject, "updateTime", Date.class, date);
|
this.strictInsertFill(metaObject, "updateTime", Date.class, date);
|
||||||
@ -75,6 +80,8 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
|||||||
if (ObjectUtil.isNotNull(userId)) {
|
if (ObjectUtil.isNotNull(userId)) {
|
||||||
baseEntity.setUpdateBy(userId);
|
baseEntity.setUpdateBy(userId);
|
||||||
}
|
}
|
||||||
|
} else if(ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseAudit baseAudit) {
|
||||||
|
baseAudit.setUpdateTime(LocalDateTime.now());
|
||||||
} else {
|
} else {
|
||||||
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
|
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@ import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RabbitMQ消费者
|
||||||
|
* 已禁用,改用RocketMQ
|
||||||
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class RabbitMQConsumer {
|
public class RabbitMQConsumer {
|
||||||
@ -21,7 +25,7 @@ public class RabbitMQConsumer {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private MsgService msgService;
|
private MsgService msgService;
|
||||||
|
|
||||||
@RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG})
|
// @RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG})
|
||||||
public void watchQueue(String payload, Message message) {
|
public void watchQueue(String payload, Message message) {
|
||||||
log.info(payload);
|
log.info(payload);
|
||||||
|
|
||||||
|
@ -9,7 +9,11 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
/**
|
||||||
|
* RabbitMQ配置类
|
||||||
|
* 已禁用,改用RocketMQ
|
||||||
|
*/
|
||||||
|
// @Configuration
|
||||||
public class RabbitMQConfig {
|
public class RabbitMQConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +29,7 @@ public class RabbitMQConfig {
|
|||||||
|
|
||||||
public static final String QUEUE_SYS_MSG = "queue_sys_msg";
|
public static final String QUEUE_SYS_MSG = "queue_sys_msg";
|
||||||
|
|
||||||
@Bean(EXCHANGE_MSG)
|
// @Bean(EXCHANGE_MSG)
|
||||||
public Exchange exchange() {
|
public Exchange exchange() {
|
||||||
return ExchangeBuilder // 构建交换机
|
return ExchangeBuilder // 构建交换机
|
||||||
.topicExchange(EXCHANGE_MSG) // 使用topic类型,参考:https://www.rabbitmq.com/getstarted.html
|
.topicExchange(EXCHANGE_MSG) // 使用topic类型,参考:https://www.rabbitmq.com/getstarted.html
|
||||||
@ -33,12 +37,12 @@ public class RabbitMQConfig {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(QUEUE_SYS_MSG)
|
// @Bean(QUEUE_SYS_MSG)
|
||||||
public Queue queue() {
|
public Queue queue() {
|
||||||
return new Queue(QUEUE_SYS_MSG);
|
return new Queue(QUEUE_SYS_MSG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
// @Bean
|
||||||
public Binding binding(@Qualifier(EXCHANGE_MSG) Exchange exchange,
|
public Binding binding(@Qualifier(EXCHANGE_MSG) Exchange exchange,
|
||||||
@Qualifier(QUEUE_SYS_MSG) Queue queue) {
|
@Qualifier(QUEUE_SYS_MSG) Queue queue) {
|
||||||
|
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package org.dromara.demo.service;
|
package org.dromara.demo.service;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出下拉框Excel示例
|
* 导出下拉框Excel示例
|
||||||
*
|
*
|
||||||
* @author Emil.Zhang
|
* @author Emil.Zhang
|
||||||
*/
|
*/
|
||||||
|
@Service
|
||||||
public interface IExportExcelService {
|
public interface IExportExcelService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
package com.wzj.soopin.member.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.wzj.soopin.member.annotation.MemberFillMethod;
|
||||||
|
import com.wzj.soopin.member.convert.ChargeConvert;
|
||||||
|
import com.wzj.soopin.member.convert.MemberForbiddenConvert;
|
||||||
|
import com.wzj.soopin.member.domain.bo.ChargeBO;
|
||||||
|
import com.wzj.soopin.member.domain.bo.MemberForbiddenBO;
|
||||||
|
import com.wzj.soopin.member.domain.po.Charge;
|
||||||
|
import com.wzj.soopin.member.domain.po.MemberForbidden;
|
||||||
|
import com.wzj.soopin.member.domain.vo.ChargeVO;
|
||||||
|
import com.wzj.soopin.member.domain.vo.MemberForbiddenVO;
|
||||||
|
import com.wzj.soopin.member.service.IChargeService;
|
||||||
|
import com.wzj.soopin.member.service.IMemberForbiddenService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.log.annotation.Log;
|
||||||
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户封禁
|
||||||
|
*/
|
||||||
|
@Tag(name = "用户封禁")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ums/charge")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ChargeController {
|
||||||
|
|
||||||
|
private final IChargeService service;
|
||||||
|
private final ChargeConvert convert;
|
||||||
|
|
||||||
|
@Tag(name = "查询列表")
|
||||||
|
@PostMapping("/list")
|
||||||
|
@MemberFillMethod
|
||||||
|
public R<IPage<ChargeVO>> list(@RequestBody ChargeBO bo, @RequestBody Page page) {
|
||||||
|
Page<Charge> pages = service.page(page, bo.toWrapper());
|
||||||
|
return R.ok(convert.toVO(pages));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tag(name = "新增")
|
||||||
|
@Log(title = "新增 ", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/add")
|
||||||
|
public R add(@RequestBody ChargeBO bo) {
|
||||||
|
return R.ok(service.save(convert.toPo(bo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tag(name = "详情")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
@MemberFillMethod
|
||||||
|
public R<ChargeVO> getInfo(@PathVariable("id") Long id) {
|
||||||
|
return R.ok(convert.toVO(service.getById(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tag(name = ("处理"))
|
||||||
|
@Log(title = "修改", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/update")
|
||||||
|
public R update(@RequestBody ChargeBO bo) {
|
||||||
|
service.save(convert.toPo(bo));
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tag(name = ("处理"))
|
||||||
|
@Log(title = "修改", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/audit")
|
||||||
|
public R audit(@RequestBody ChargeBO bo) {
|
||||||
|
service.save(convert.toPo(bo));
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Tag(name = "删除")
|
||||||
|
@Log(title = "删除", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public R<Object> remove(@PathVariable Long id) {
|
||||||
|
return R.ok(service.removeById(id));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package com.wzj.soopin.member.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.wzj.soopin.member.annotation.MemberFillMethod;
|
||||||
|
import com.wzj.soopin.member.convert.MemberForbiddenConvert;
|
||||||
|
import com.wzj.soopin.member.convert.WithdrawConvert;
|
||||||
|
import com.wzj.soopin.member.domain.bo.MemberForbiddenBO;
|
||||||
|
import com.wzj.soopin.member.domain.bo.WithdrawBO;
|
||||||
|
import com.wzj.soopin.member.domain.po.MemberForbidden;
|
||||||
|
import com.wzj.soopin.member.domain.po.Withdraw;
|
||||||
|
import com.wzj.soopin.member.domain.vo.MemberForbiddenVO;
|
||||||
|
import com.wzj.soopin.member.domain.vo.WithdrawVO;
|
||||||
|
import com.wzj.soopin.member.service.IMemberForbiddenService;
|
||||||
|
import com.wzj.soopin.member.service.IWithdrawService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.log.annotation.Log;
|
||||||
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户封禁
|
||||||
|
*/
|
||||||
|
@Tag(name = "提现")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ums/withdraw")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WithdrawController {
|
||||||
|
|
||||||
|
private final IWithdrawService service;
|
||||||
|
private final WithdrawConvert convert;
|
||||||
|
|
||||||
|
@Tag(name = "查询列表")
|
||||||
|
@PostMapping("/list")
|
||||||
|
@MemberFillMethod
|
||||||
|
public R<IPage<WithdrawVO>> list(@RequestBody WithdrawBO bo, @RequestBody Page page) {
|
||||||
|
Page<Withdraw> pages = service.page(page, bo.toWrapper());
|
||||||
|
return R.ok(convert.toVO(pages));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tag(name = "新增")
|
||||||
|
@Log(title = "新增 ", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/add")
|
||||||
|
public R add(@RequestBody WithdrawBO bo) {
|
||||||
|
return R.ok(service.save(convert.toPo(bo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tag(name = "详情")
|
||||||
|
@GetMapping(value = "/{id}")
|
||||||
|
@MemberFillMethod
|
||||||
|
public R<WithdrawVO> getInfo(@PathVariable("id") Long id) {
|
||||||
|
return R.ok(convert.toVO(service.getById(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tag(name = ("审批"))
|
||||||
|
@Log(title = "审批", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/update")
|
||||||
|
public R update(@RequestBody WithdrawBO bo) {
|
||||||
|
return R.ok(service.audit(bo));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Tag(name = "删除")
|
||||||
|
@Log(title = "删除", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public R<Object> remove(@PathVariable Long id) {
|
||||||
|
return R.ok(service.removeById(id));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.wzj.soopin.member.convert;
|
||||||
|
|
||||||
|
import com.wzj.soopin.member.domain.bo.ChargeBO;
|
||||||
|
import com.wzj.soopin.member.domain.bo.FansBO;
|
||||||
|
import com.wzj.soopin.member.domain.po.Charge;
|
||||||
|
import com.wzj.soopin.member.domain.po.Fans;
|
||||||
|
import com.wzj.soopin.member.domain.vo.ChargeVO;
|
||||||
|
import com.wzj.soopin.member.domain.vo.FansVO;
|
||||||
|
import org.dromara.common.web.core.BaseConverter;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充值
|
||||||
|
*
|
||||||
|
* @author zcc
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = "spring",uses = BaseConverter.class)
|
||||||
|
public interface ChargeConvert extends BaseConverter<ChargeVO, ChargeBO, Charge> {
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.wzj.soopin.member.convert;
|
||||||
|
|
||||||
|
import com.wzj.soopin.member.domain.bo.WithdrawBO;
|
||||||
|
import com.wzj.soopin.member.domain.po.Withdraw;
|
||||||
|
import com.wzj.soopin.member.domain.vo.WithdrawVO;
|
||||||
|
import org.dromara.common.web.core.BaseConverter;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现
|
||||||
|
*
|
||||||
|
* @author zcc
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = "spring",uses = BaseConverter.class)
|
||||||
|
public interface WithdrawConvert extends BaseConverter<WithdrawVO, WithdrawBO, Withdraw> {
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
package com.wzj.soopin.member.domain.bo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.wzj.soopin.member.domain.po.Charge;
|
||||||
|
import com.wzj.soopin.member.domain.po.Withdraw;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.domain.BaseBO;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充值
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
* @date 2023-03-07
|
||||||
|
*/
|
||||||
|
@Schema(description="充值")
|
||||||
|
@Data
|
||||||
|
public class ChargeBO extends BaseBO<Charge> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@Schema(description ="主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现码
|
||||||
|
*/
|
||||||
|
@Schema(description ="充值码")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员id
|
||||||
|
*/
|
||||||
|
@Schema(description ="会员id")
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="金额")
|
||||||
|
private BigDecimal money;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手续费
|
||||||
|
*/
|
||||||
|
@Schema(description ="手续费")
|
||||||
|
private BigDecimal fee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="实际金额")
|
||||||
|
private BigDecimal actualMoney;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="状态")
|
||||||
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@Schema(description ="类型")
|
||||||
|
private Integer type;
|
||||||
|
/**
|
||||||
|
* 审核人
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核人")
|
||||||
|
private Long auditBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核时间
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核时间")
|
||||||
|
private LocalDateTime auditTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现方式
|
||||||
|
*/
|
||||||
|
@Schema(description ="提现方式")
|
||||||
|
private Integer method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核状态")
|
||||||
|
private Integer auditStatus;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LambdaQueryWrapper<Charge> toWrapper() {
|
||||||
|
return super.toWrapper().eq(id!=null, Charge::getId, id)
|
||||||
|
.eq(memberId!=null, Charge::getMemberId, memberId)
|
||||||
|
.eq(money!=null, Charge::getMoney, money)
|
||||||
|
.eq(fee!=null, Charge::getFee, fee)
|
||||||
|
.eq(actualMoney!=null, Charge::getActualMoney, actualMoney)
|
||||||
|
.eq(status!=null, Charge::getStatus, status)
|
||||||
|
.eq(type!=null, Charge::getType, type);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
package com.wzj.soopin.member.domain.bo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.wzj.soopin.member.domain.po.Withdraw;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.domain.BaseBO;
|
||||||
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
* @date 2023-03-07
|
||||||
|
*/
|
||||||
|
@Schema(description="提现")
|
||||||
|
@Data
|
||||||
|
public class WithdrawBO extends BaseBO<Withdraw> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@Schema(description ="主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现码
|
||||||
|
*/
|
||||||
|
@Schema(description ="提现码")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员id
|
||||||
|
*/
|
||||||
|
@Schema(description ="会员id")
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="金额")
|
||||||
|
private BigDecimal money;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手续费
|
||||||
|
*/
|
||||||
|
@Schema(description ="手续费")
|
||||||
|
private BigDecimal fee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="实际金额")
|
||||||
|
private BigDecimal actualMoney;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="状态")
|
||||||
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@Schema(description ="类型")
|
||||||
|
private Integer type;
|
||||||
|
/**
|
||||||
|
* 审核人
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核人")
|
||||||
|
private Long auditBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核时间
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核时间")
|
||||||
|
private LocalDateTime auditTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现方式
|
||||||
|
*/
|
||||||
|
@Schema(description ="提现方式")
|
||||||
|
private Integer method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核状态")
|
||||||
|
private Integer auditStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核原因
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核原因")
|
||||||
|
private String auditReason;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LambdaQueryWrapper<Withdraw> toWrapper() {
|
||||||
|
return super.toWrapper().eq(id!=null, Withdraw::getId, id)
|
||||||
|
.eq(memberId!=null, Withdraw::getMemberId, memberId)
|
||||||
|
.eq(money!=null, Withdraw::getMoney, money)
|
||||||
|
.eq(fee!=null, Withdraw::getFee, fee)
|
||||||
|
.eq(actualMoney!=null, Withdraw::getActualMoney, actualMoney)
|
||||||
|
.eq(status!=null, Withdraw::getStatus, status)
|
||||||
|
.eq(type!=null, Withdraw::getType, type);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.wzj.soopin.member.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充值
|
||||||
|
*/
|
||||||
|
@Schema(description="充值")
|
||||||
|
@Data
|
||||||
|
@TableName("ums_charge")
|
||||||
|
public class Charge extends BaseAudit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充值码
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员id
|
||||||
|
*/
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额
|
||||||
|
*/
|
||||||
|
private BigDecimal money;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手续费
|
||||||
|
*/
|
||||||
|
private BigDecimal fee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际金额
|
||||||
|
*/
|
||||||
|
private BigDecimal actualMoney;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
/**
|
||||||
|
* 审核人
|
||||||
|
*/
|
||||||
|
private Long auditBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime auditTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现方式
|
||||||
|
*/
|
||||||
|
private Integer method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核状态
|
||||||
|
*/
|
||||||
|
private Integer auditStatus;
|
||||||
|
}
|
@ -3,8 +3,10 @@ package com.wzj.soopin.member.domain.po;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import org.dromara.common.core.domain.model.BaseAudit;
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
import org.dromara.common.excel.annotation.Excel;
|
import org.dromara.common.excel.annotation.Excel;
|
||||||
|
|
||||||
@ -19,6 +21,8 @@ import java.time.LocalDateTime;
|
|||||||
@Schema(description="会员信息对象")
|
@Schema(description="会员信息对象")
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
@TableName("ums_member")
|
@TableName("ums_member")
|
||||||
public class Member extends BaseAudit {
|
public class Member extends BaseAudit {
|
||||||
@Schema(description = "会员id")
|
@Schema(description = "会员id")
|
||||||
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.dromara.common.core.domain.model.BaseAudit;
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
import org.dromara.common.excel.annotation.Excel;
|
import org.dromara.common.excel.annotation.Excel;
|
||||||
@ -18,6 +19,7 @@ import java.math.BigDecimal;
|
|||||||
@Schema(description="会员账户变动记录")
|
@Schema(description="会员账户变动记录")
|
||||||
@Data
|
@Data
|
||||||
@TableName("ums_account_change_record")
|
@TableName("ums_account_change_record")
|
||||||
|
@Builder(toBuilder = true)
|
||||||
public class MemberAccountChangeRecord extends BaseAudit {
|
public class MemberAccountChangeRecord extends BaseAudit {
|
||||||
|
|
||||||
@Schema(description ="主键")
|
@Schema(description ="主键")
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
package com.wzj.soopin.member.domain.vo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import com.wzj.soopin.member.annotation.MemberFillField;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
* @date 2023-03-07
|
||||||
|
*/
|
||||||
|
@Schema(description="充值")
|
||||||
|
@Data
|
||||||
|
public class ChargeVO extends BaseAudit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@Schema(description ="主键")
|
||||||
|
@ExcelProperty(value = "主键", order = 1)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现码
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Schema(description ="充值码")
|
||||||
|
@ExcelProperty(value = "充值码", order = 2)
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员id
|
||||||
|
*/
|
||||||
|
@Schema(description ="会员id")
|
||||||
|
@ExcelProperty(value ="会员id", order = 3)
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
@Schema(description ="会员")
|
||||||
|
@MemberFillField(id = "memberId")
|
||||||
|
private MemberVO member;
|
||||||
|
/**
|
||||||
|
* 金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="金额")
|
||||||
|
@ExcelProperty(value ="金额", order = 4)
|
||||||
|
private BigDecimal money;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手续费
|
||||||
|
*/
|
||||||
|
@Schema(description ="手续费")
|
||||||
|
@ExcelProperty(value ="手续费", order = 5)
|
||||||
|
private BigDecimal fee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="实际金额")
|
||||||
|
@ExcelProperty(value ="实际金额", order = 6)
|
||||||
|
private BigDecimal actualMoney;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="状态")
|
||||||
|
@ExcelProperty(value ="状态", order = 7)
|
||||||
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@Schema(description ="类型")
|
||||||
|
@ExcelProperty(value ="类型", order = 8)
|
||||||
|
private Integer type;
|
||||||
|
/**
|
||||||
|
* 审核人
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核人")
|
||||||
|
@ExcelProperty(value ="审核人", order = 9)
|
||||||
|
private Long auditBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核时间
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核时间")
|
||||||
|
@ExcelProperty(value ="审核时间", order = 10)
|
||||||
|
private LocalDateTime auditTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现方式
|
||||||
|
*/
|
||||||
|
@Schema(description ="提现方式")
|
||||||
|
@ExcelProperty(value ="提现方式", order = 11)
|
||||||
|
private Integer method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核状态")
|
||||||
|
@ExcelProperty(value ="审核状态", order = 12)
|
||||||
|
private Integer auditStatus;
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
package com.wzj.soopin.member.domain.vo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.wzj.soopin.member.annotation.MemberFillField;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
* @date 2023-03-07
|
||||||
|
*/
|
||||||
|
@Schema(description="提现")
|
||||||
|
@Data
|
||||||
|
public class WithdrawVO extends BaseAudit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@Schema(description ="主键")
|
||||||
|
@ExcelProperty(value = "主键", order = 1)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现码
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Schema(description ="提现码")
|
||||||
|
@ExcelProperty(value = "提现码", order = 2)
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员id
|
||||||
|
*/
|
||||||
|
@Schema(description ="会员id")
|
||||||
|
@ExcelProperty(value ="会员id", order = 3)
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
@Schema(description ="会员")
|
||||||
|
@MemberFillField(id = "memberId")
|
||||||
|
private MemberVO member;
|
||||||
|
/**
|
||||||
|
* 金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="金额")
|
||||||
|
@ExcelProperty(value ="金额", order = 4)
|
||||||
|
private BigDecimal money;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手续费
|
||||||
|
*/
|
||||||
|
@Schema(description ="手续费")
|
||||||
|
@ExcelProperty(value ="手续费", order = 5)
|
||||||
|
private BigDecimal fee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="实际金额")
|
||||||
|
@ExcelProperty(value ="实际金额", order = 6)
|
||||||
|
private BigDecimal actualMoney;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="状态")
|
||||||
|
@ExcelProperty(value ="状态", order = 7)
|
||||||
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@Schema(description ="类型")
|
||||||
|
@ExcelProperty(value ="类型", order = 8)
|
||||||
|
private Integer type;
|
||||||
|
/**
|
||||||
|
* 审核人
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核人")
|
||||||
|
@ExcelProperty(value ="审核人", order = 9)
|
||||||
|
private Long auditBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核时间
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核时间")
|
||||||
|
@ExcelProperty(value ="审核时间", order = 10)
|
||||||
|
private LocalDateTime auditTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提现方式
|
||||||
|
*/
|
||||||
|
@Schema(description ="提现方式")
|
||||||
|
@ExcelProperty(value ="提现方式", order = 11)
|
||||||
|
private Integer method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核状态
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核状态")
|
||||||
|
@ExcelProperty(value ="审核状态", order = 12)
|
||||||
|
private Integer auditStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核原因
|
||||||
|
*/
|
||||||
|
@Schema(description ="审核原因")
|
||||||
|
@ExcelProperty(value ="审核原因", order = 13)
|
||||||
|
private String auditReason;
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.wzj.soopin.member.domain.vo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import com.wzj.soopin.member.annotation.MemberFillField;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.core.domain.model.BaseAudit;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 易生平台账户信息
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
* @date 2023-03-07
|
||||||
|
*/
|
||||||
|
@Schema(description="易生")
|
||||||
|
@Data
|
||||||
|
@Builder(toBuilder = true)
|
||||||
|
public class YishengAccountVO extends BaseAudit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@Schema(description ="主键")
|
||||||
|
@ExcelProperty(value = "主键", order = 1)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员id
|
||||||
|
*/
|
||||||
|
@Schema(description ="会员id")
|
||||||
|
@ExcelProperty(value ="会员id", order = 3)
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额
|
||||||
|
*/
|
||||||
|
@Schema(description ="金额")
|
||||||
|
@ExcelProperty(value ="金额", order = 4)
|
||||||
|
private BigDecimal balance;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.wzj.soopin.member.enums;
|
||||||
|
|
||||||
|
public enum MemberAccountChangeRecordChangeTypeEnum {
|
||||||
|
WITHDRAW(1, "提现"),
|
||||||
|
CHARGE(2, "充值"),
|
||||||
|
RECHARGE(3, "充值"),
|
||||||
|
RECHARGE_REFUND(4, "充值退款"),
|
||||||
|
WITHDRAW_REFUND(5, "提现退款"),
|
||||||
|
RECHARGE_REFUND_REFUND(6, "充值退款退款"),
|
||||||
|
WITHDRAW_REFUND_REFUND(7, "提现退款退款"),
|
||||||
|
RECHARGE_REFUND_REFUND_REFUND(8, "充值退款退款退款");
|
||||||
|
|
||||||
|
private Integer code;
|
||||||
|
private String message;
|
||||||
|
MemberAccountChangeRecordChangeTypeEnum(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.wzj.soopin.member.enums;
|
||||||
|
|
||||||
|
public enum MemberAccountChangeRecordSourceEnum {
|
||||||
|
YISHENG(1, "充值"),
|
||||||
|
CHARGE(2, "提现"),
|
||||||
|
WITHDRAW(3, "经营"),
|
||||||
|
|
||||||
|
RECHARGE_REFUND_REFUND_REFUND(9, "充值退款退款退款");
|
||||||
|
|
||||||
|
private Integer code;
|
||||||
|
private String message;
|
||||||
|
MemberAccountChangeRecordSourceEnum(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.wzj.soopin.member.enums;
|
||||||
|
|
||||||
|
public enum WithdrawAuditStatus {
|
||||||
|
PENDING(0, "待审核"),
|
||||||
|
APPROVED(1, "审核通过"),
|
||||||
|
REJECTED(2, "审核拒绝");
|
||||||
|
private Integer code;
|
||||||
|
private String message;
|
||||||
|
WithdrawAuditStatus(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.wzj.soopin.member.enums;
|
||||||
|
|
||||||
|
public enum WithdrawStatus {
|
||||||
|
WAITING(0, "等待转账"),
|
||||||
|
PENDING(1, "转账中"),
|
||||||
|
SUCCESS(2, "转账成功"),
|
||||||
|
FAIL(3, "转账失败");
|
||||||
|
|
||||||
|
private Integer code;
|
||||||
|
private String message;
|
||||||
|
WithdrawStatus(Integer code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
public Integer getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.wzj.soopin.member.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.wzj.soopin.member.domain.po.Charge;
|
||||||
|
import com.wzj.soopin.member.domain.po.Withdraw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 意见反馈Mapper接口
|
||||||
|
*
|
||||||
|
* @author zcc
|
||||||
|
*/
|
||||||
|
public interface ChargeMapper extends BaseMapper<Charge> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.wzj.soopin.member.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.wzj.soopin.member.domain.po.Charge;
|
||||||
|
import com.wzj.soopin.member.domain.po.Withdraw;
|
||||||
|
|
||||||
|
public interface IChargeService extends IService<Charge> {
|
||||||
|
|
||||||
|
boolean audit(Long id, String status);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.wzj.soopin.member.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.wzj.soopin.member.domain.po.Withdraw;
|
||||||
|
import com.wzj.soopin.member.domain.vo.YishengAccountVO;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 易生支付的service
|
||||||
|
*/
|
||||||
|
public interface IYishengService {
|
||||||
|
YishengAccountVO getYishengAccount(Long memberId);
|
||||||
|
|
||||||
|
boolean withdraw(Long memberId, BigDecimal money);
|
||||||
|
|
||||||
|
|
||||||
|
boolean syncMemberAccount();
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.wzj.soopin.member.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.wzj.soopin.member.domain.po.Charge;
|
||||||
|
import com.wzj.soopin.member.domain.po.MemberForbidden;
|
||||||
|
import com.wzj.soopin.member.mapper.ChargeMapper;
|
||||||
|
import com.wzj.soopin.member.mapper.MemberForbiddenMapper;
|
||||||
|
import com.wzj.soopin.member.service.IChargeService;
|
||||||
|
import com.wzj.soopin.member.service.IMemberForbiddenService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员封禁
|
||||||
|
*
|
||||||
|
* @author zcc
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class ChargeServiceImpl extends ServiceImpl<ChargeMapper, Charge> implements IChargeService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean audit(Long id, String status) {
|
||||||
|
Charge charge = getById(id);
|
||||||
|
//调用三方充值接口
|
||||||
|
boolean chargeSuccess = true;
|
||||||
|
//充值成功后更新会员账户余额
|
||||||
|
//生成充值记录
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.wzj.soopin.member.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.wzj.soopin.member.domain.po.Charge;
|
||||||
|
import com.wzj.soopin.member.domain.vo.YishengAccountVO;
|
||||||
|
import com.wzj.soopin.member.mapper.ChargeMapper;
|
||||||
|
import com.wzj.soopin.member.service.IChargeService;
|
||||||
|
import com.wzj.soopin.member.service.IYishengService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员封禁
|
||||||
|
*
|
||||||
|
* @author zcc
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class YishengServiceImpl implements IYishengService {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public YishengAccountVO getYishengAccount(Long memberId) {
|
||||||
|
return YishengAccountVO.builder().balance(new BigDecimal(1000)).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean withdraw(Long memberId, BigDecimal money) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncMemberAccount() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package org.dromara.system.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RocketMQ 配置类
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RocketMQConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统消息主题
|
||||||
|
*/
|
||||||
|
public static final String TOPIC_SYS_MSG = "TOPIC_SYS_MSG";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统消息消费者组
|
||||||
|
*/
|
||||||
|
public static final String CONSUMER_GROUP_SYS_MSG = "CONSUMER_GROUP_SYS_MSG";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统消息标签
|
||||||
|
*/
|
||||||
|
public static final String TAG_SYS_MSG = "SYS_MSG";
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package org.dromara.system.config;
|
||||||
|
|
||||||
|
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
||||||
|
import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration;
|
||||||
|
import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||||
|
import org.apache.rocketmq.spring.support.RocketMQMessageConverter;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RocketMQ配置类
|
||||||
|
* 确保RocketMQTemplate被正确初始化
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(RocketMQProperties.class)
|
||||||
|
@ConditionalOnClass(DefaultMQProducer.class)
|
||||||
|
@Import(RocketMQAutoConfiguration.class)
|
||||||
|
public class RocketMQConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保RocketMQTemplate被正确初始化
|
||||||
|
* 这个Bean会由RocketMQAutoConfiguration自动创建
|
||||||
|
* 此处仅作为备用方案
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(RocketMQTemplate.class)
|
||||||
|
@ConditionalOnBean(DefaultMQProducer.class)
|
||||||
|
public RocketMQTemplate rocketMQTemplate(DefaultMQProducer mqProducer,
|
||||||
|
RocketMQMessageConverter messageConverter) {
|
||||||
|
RocketMQTemplate rocketMQTemplate = new RocketMQTemplate();
|
||||||
|
rocketMQTemplate.setProducer(mqProducer);
|
||||||
|
rocketMQTemplate.setMessageConverter(messageConverter.getMessageConverter());
|
||||||
|
return rocketMQTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(RocketMQMessageConverter.class)
|
||||||
|
public RocketMQMessageConverter rocketMQMessageConverter() {
|
||||||
|
return new RocketMQMessageConverter();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
package org.dromara.system.consumer;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||||
|
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.dromara.system.config.RocketMQConfig;
|
||||||
|
import org.dromara.system.domain.SysMessageUser;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
import org.dromara.system.mapper.SysMessageUserMapper;
|
||||||
|
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RocketMQ消息消费者
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RocketMQMessageListener(
|
||||||
|
topic = RocketMQConfig.TOPIC_SYS_MSG,
|
||||||
|
consumerGroup = RocketMQConfig.CONSUMER_GROUP_SYS_MSG,
|
||||||
|
selectorExpression = RocketMQConfig.TAG_SYS_MSG
|
||||||
|
)
|
||||||
|
public class MessageRocketMQConsumer implements RocketMQListener<String> {
|
||||||
|
|
||||||
|
private final MessageWebSocketServer messageWebSocketServer;
|
||||||
|
private final SysMessageUserMapper messageUserMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(String message) {
|
||||||
|
try {
|
||||||
|
log.info("接收到RocketMQ消息: {}", message);
|
||||||
|
// 解析消息格式,格式为: {"userId": "123", "message": {...}}
|
||||||
|
MessageWrapper wrapper = JsonUtils.parseObject(message, MessageWrapper.class);
|
||||||
|
if (wrapper != null && wrapper.getUserId() != null && wrapper.getMessage() != null) {
|
||||||
|
// 将String类型的userId转换为Long类型
|
||||||
|
Long userIdLong = null;
|
||||||
|
try {
|
||||||
|
if (StringUtils.isNotBlank(wrapper.getUserId())) {
|
||||||
|
userIdLong = Long.parseLong(wrapper.getUserId());
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.error("用户ID转换失败: {}", wrapper.getUserId(), e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userIdLong != null) {
|
||||||
|
// 保存消息用户关联记录
|
||||||
|
try {
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setMessageId(wrapper.getMessage().getId());
|
||||||
|
messageUser.setUserId(userIdLong);
|
||||||
|
messageUser.setIsRead(false);
|
||||||
|
messageUserMapper.insert(messageUser);
|
||||||
|
log.info("消息用户关联记录保存成功,messageId: {}, userId: {}", wrapper.getMessage().getId(), userIdLong);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("保存消息用户关联记录失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送WebSocket消息
|
||||||
|
messageWebSocketServer.sendMessage(userIdLong, JsonUtils.toJsonString(wrapper.getMessage()));
|
||||||
|
log.info("通过WebSocket发送消息成功,userId: {}", userIdLong);
|
||||||
|
} else {
|
||||||
|
log.warn("用户ID为空或无效: {}", wrapper.getUserId());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("消息格式不正确: {}", message);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理RocketMQ消息失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息包装类
|
||||||
|
*/
|
||||||
|
public static class MessageWrapper {
|
||||||
|
private String userId;
|
||||||
|
private SysMessageVo message;
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SysMessageVo getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(SysMessageVo message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package org.dromara.system.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@ -9,6 +10,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
import org.dromara.common.core.service.UserService;
|
import org.dromara.common.core.service.UserService;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.core.validate.AddGroup;
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
import org.dromara.common.core.validate.EditGroup;
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
import org.dromara.common.core.validate.QueryGroup;
|
import org.dromara.common.core.validate.QueryGroup;
|
||||||
@ -23,15 +25,16 @@ import org.dromara.system.domain.SysMessage;
|
|||||||
import org.dromara.system.domain.SysUser;
|
import org.dromara.system.domain.SysUser;
|
||||||
import org.dromara.system.domain.bo.SysMessageBo;
|
import org.dromara.system.domain.bo.SysMessageBo;
|
||||||
import org.dromara.system.domain.bo.SysUserBo;
|
import org.dromara.system.domain.bo.SysUserBo;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||||
import org.dromara.system.domain.vo.SysMessageVo;
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
import org.dromara.system.domain.vo.SysUserVo;
|
import org.dromara.system.domain.vo.SysUserVo;
|
||||||
import org.dromara.system.service.ISysMessageService;
|
import org.dromara.system.service.ISysMessageService;
|
||||||
|
import org.dromara.system.service.ISysMessageTemplateService;
|
||||||
import org.dromara.system.service.ISysUserService;
|
import org.dromara.system.service.ISysUserService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,6 +50,7 @@ public class SysMessageController extends BaseController {
|
|||||||
|
|
||||||
private final ISysMessageService messageService;
|
private final ISysMessageService messageService;
|
||||||
private final ISysUserService userService;
|
private final ISysUserService userService;
|
||||||
|
private final ISysMessageTemplateService templateService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前用户ID
|
* 获取当前用户ID
|
||||||
@ -58,10 +62,11 @@ public class SysMessageController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 查询消息列表
|
* 查询消息列表
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("system:message:list")
|
// @SaCheckPermission("system:message:list")
|
||||||
@Tag(name = "查询消息列表")
|
@Tag(name = "查询消息列表")
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public R<Page<SysMessageVo>> list(@RequestBody SysMessageBo bo, @RequestBody Page<SysMessage> page) {
|
public R<Page<SysMessageVo>> list(@RequestBody SysMessageBo bo, PageQuery pageQuery) {
|
||||||
|
Page<SysMessage> page = pageQuery.build();
|
||||||
Page<SysMessage> messagePage = messageService.page(page, bo.toWrapper());
|
Page<SysMessage> messagePage = messageService.page(page, bo.toWrapper());
|
||||||
Page<SysMessageVo> voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
|
Page<SysMessageVo> voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
|
||||||
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
|
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
|
||||||
@ -73,7 +78,7 @@ public class SysMessageController extends BaseController {
|
|||||||
*
|
*
|
||||||
* @param id 消息ID
|
* @param id 消息ID
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("system:message:query")
|
// @SaCheckPermission("system:message:query")
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public R<SysMessageVo> getInfo(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
public R<SysMessageVo> getInfo(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
||||||
return R.ok(messageService.selectMessageById(id));
|
return R.ok(messageService.selectMessageById(id));
|
||||||
@ -82,52 +87,201 @@ public class SysMessageController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 发送消息
|
* 发送消息
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("system:message:send")
|
// @SaCheckPermission("system:message:send")
|
||||||
@Log(title = "消息管理", businessType = BusinessType.INSERT)
|
@Log(title = "消息管理", businessType = BusinessType.INSERT)
|
||||||
@RepeatSubmit()
|
@RepeatSubmit()
|
||||||
@PostMapping("/send")
|
@PostMapping("/send")
|
||||||
public R<Void> send(@Validated(AddGroup.class) @RequestBody SysMessageBo bo) {
|
public R<Void> send(@RequestBody SysMessageBo bo) {
|
||||||
List<SysUserVo> users = userService.selectUserListByDept(null);
|
// 设置发送者ID为当前登录用户ID
|
||||||
List<Long> userIds;
|
bo.setSenderId(getUserId());
|
||||||
|
|
||||||
switch (bo.getSendScope()) {
|
// 如果提供了模板ID,则从模板中获取标题和内容
|
||||||
case "all":
|
Long templateId = bo.getTemplateId();
|
||||||
// 全部用户
|
if (templateId != null) {
|
||||||
userIds = users.stream().map(SysUserVo::getUserId).toList();
|
SysMessageTemplateVo template = templateService.selectTemplateById(templateId);
|
||||||
break;
|
if (template != null) {
|
||||||
case "expert":
|
// 使用模板的标题和内容
|
||||||
// 达人
|
bo.setTitle(template.getTitle());
|
||||||
userIds = users.stream()
|
bo.setContent(template.getTemplateContent());
|
||||||
.filter(user -> "expert".equals(user.getUserType()))
|
} else {
|
||||||
.map(SysUserVo::getUserId)
|
return R.fail("未找到指定的消息模板");
|
||||||
.toList();
|
}
|
||||||
break;
|
|
||||||
case "merchant":
|
|
||||||
// 商户
|
|
||||||
userIds = users.stream()
|
|
||||||
.filter(user -> "merchant".equals(user.getUserType()))
|
|
||||||
.map(SysUserVo::getUserId)
|
|
||||||
.toList();
|
|
||||||
break;
|
|
||||||
case "user":
|
|
||||||
// 普通用户
|
|
||||||
userIds = users.stream()
|
|
||||||
.filter(user -> "user".equals(user.getUserType()))
|
|
||||||
.map(SysUserVo::getUserId)
|
|
||||||
.toList();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// 其他情况(如指定userIds)
|
|
||||||
userIds = bo.getUserIds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return toAjax(messageService.sendMessageToUsers(bo, userIds));
|
// 验证消息内容是否为空
|
||||||
|
if (StringUtils.isBlank(bo.getContent())) {
|
||||||
|
return R.fail("消息内容不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证发送范围是否为空
|
||||||
|
List<String> sendScope = bo.getSendScope();
|
||||||
|
if (sendScope == null || sendScope.isEmpty()) {
|
||||||
|
return R.fail("发送范围不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理接收者
|
||||||
|
List<String> userIdStrings = new ArrayList<>();
|
||||||
|
|
||||||
|
// 根据logmess值处理不同类型的消息接收者
|
||||||
|
Integer logmess = bo.getLogmess();
|
||||||
|
if (logmess != null) {
|
||||||
|
// 获取发送范围作为主要处理对象
|
||||||
|
if (sendScope == null || sendScope.isEmpty()) {
|
||||||
|
return R.fail("发送范围不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String scope = sendScope.get(0); // 获取第一个范围值
|
||||||
|
|
||||||
|
switch (logmess) {
|
||||||
|
case 1: // 指定角色
|
||||||
|
// 当logmess=1时,sendScope接收的是角色ID或特殊标识
|
||||||
|
if ("all".equals(scope) || "expert".equals(scope) || "merchant".equals(scope) || "user".equals(scope)) {
|
||||||
|
List<SysUserVo> users = userService.selectUserListByDept(null);
|
||||||
|
List<Long> userIds;
|
||||||
|
|
||||||
|
switch (scope) {
|
||||||
|
case "all":
|
||||||
|
// 全部用户
|
||||||
|
userIds = users.stream().map(SysUserVo::getUserId).toList();
|
||||||
|
break;
|
||||||
|
case "expert":
|
||||||
|
// 达人
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "expert".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
case "merchant":
|
||||||
|
// 商户
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "merchant".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
case "user":
|
||||||
|
// 普通用户
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "user".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
userIds = List.of();
|
||||||
|
}
|
||||||
|
userIdStrings = userIds.stream().map(String::valueOf).toList();
|
||||||
|
} else if (StringUtils.isNotBlank(scope)) {
|
||||||
|
try {
|
||||||
|
// 尝试将scope解析为角色ID
|
||||||
|
Long roleId = Long.parseLong(scope);
|
||||||
|
List<Long> userIds = userService.selectUserIdsByRoleId(roleId);
|
||||||
|
if (userIds != null && !userIds.isEmpty()) {
|
||||||
|
userIdStrings = userIds.stream().map(String::valueOf).toList();
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return R.fail("角色ID格式不正确");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // 指定用户
|
||||||
|
// 当logmess=2时,sendScope接收的是用户ID数组
|
||||||
|
if (sendScope != null && !sendScope.isEmpty()) {
|
||||||
|
userIdStrings = new ArrayList<>();
|
||||||
|
for (String userId : sendScope) {
|
||||||
|
if (StringUtils.isNotBlank(userId)) {
|
||||||
|
userIdStrings.add(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (bo.getUserIds() != null && !bo.getUserIds().isEmpty()) {
|
||||||
|
// 如果没有指定scope但有userIds,使用userIds
|
||||||
|
userIdStrings = bo.getUserIds().stream().map(String::valueOf).toList();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: // 指定群组/部门
|
||||||
|
// 当logmess=3时,sendScope接收的是群组/部门ID
|
||||||
|
if (StringUtils.isNotBlank(scope)) {
|
||||||
|
try {
|
||||||
|
Long deptId = Long.parseLong(scope);
|
||||||
|
List<SysUserVo> users = userService.selectUserListByDept(deptId);
|
||||||
|
if (users != null && !users.isEmpty()) {
|
||||||
|
userIdStrings = users.stream()
|
||||||
|
.map(user -> String.valueOf(user.getUserId()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return R.fail("群组/部门ID格式不正确");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return R.fail("不支持的消息类型");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有指定logmess,则使用原有的处理逻辑
|
||||||
|
if (sendScope == null || sendScope.isEmpty()) {
|
||||||
|
return R.fail("发送范围不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String scope = sendScope.get(0); // 获取第一个范围值
|
||||||
|
|
||||||
|
// 如果是群发消息类型,则根据类型筛选用户
|
||||||
|
if ("all".equals(scope) || "expert".equals(scope) || "merchant".equals(scope) || "user".equals(scope)) {
|
||||||
|
List<SysUserVo> users = userService.selectUserListByDept(null);
|
||||||
|
List<Long> userIds;
|
||||||
|
|
||||||
|
switch (scope) {
|
||||||
|
case "all":
|
||||||
|
// 全部用户
|
||||||
|
userIds = users.stream().map(SysUserVo::getUserId).toList();
|
||||||
|
break;
|
||||||
|
case "expert":
|
||||||
|
// 达人
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "expert".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
case "merchant":
|
||||||
|
// 商户
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "merchant".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
case "user":
|
||||||
|
// 普通用户
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "user".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
userIds = List.of();
|
||||||
|
}
|
||||||
|
userIdStrings = userIds.stream().map(String::valueOf).toList();
|
||||||
|
} else {
|
||||||
|
// 直接使用指定的接收者ID
|
||||||
|
if (bo.getUserIds() != null && !bo.getUserIds().isEmpty()) {
|
||||||
|
// 如果userIds不为空,使用它
|
||||||
|
userIdStrings = bo.getUserIds().stream().map(String::valueOf).toList();
|
||||||
|
} else if (sendScope != null && !sendScope.isEmpty()) {
|
||||||
|
// 如果userIds为空但sendScope不为空,将sendScope作为用户ID使用
|
||||||
|
userIdStrings = sendScope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有找到接收者,返回失败
|
||||||
|
if (userIdStrings.isEmpty()) {
|
||||||
|
return R.fail("未找到消息接收者");
|
||||||
|
}
|
||||||
|
|
||||||
|
return toAjax(messageService.sendMessageToUsers(bo, userIdStrings));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标记消息为已读
|
* 标记消息为已读
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("system:message:mark")
|
// @SaCheckPermission("system:message:mark")
|
||||||
@Log(title = "消息管理", businessType = BusinessType.UPDATE)
|
@Log(title = "消息管理", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping("/mark/{id}")
|
@PutMapping("/mark/{id}")
|
||||||
public R<Void> markAsRead(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
public R<Void> markAsRead(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
||||||
@ -139,7 +293,7 @@ public class SysMessageController extends BaseController {
|
|||||||
*
|
*
|
||||||
* @param ids 消息ID串
|
* @param ids 消息ID串
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("system:message:remove")
|
// @SaCheckPermission("system:message:remove")
|
||||||
@Log(title = "消息管理", businessType = BusinessType.DELETE)
|
@Log(title = "消息管理", businessType = BusinessType.DELETE)
|
||||||
@DeleteMapping("/{ids}")
|
@DeleteMapping("/{ids}")
|
||||||
public R<Void> remove(@NotEmpty(message = "消息ID不能为空") @PathVariable Long[] ids) {
|
public R<Void> remove(@NotEmpty(message = "消息ID不能为空") @PathVariable Long[] ids) {
|
||||||
@ -149,7 +303,7 @@ public class SysMessageController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 获取未读消息列表
|
* 获取未读消息列表
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("system:message:list")
|
// @SaCheckPermission("system:message:list")
|
||||||
@Tag(name = "查询未读消息列表")
|
@Tag(name = "查询未读消息列表")
|
||||||
@PostMapping("/unread")
|
@PostMapping("/unread")
|
||||||
public R<Page<SysMessageVo>> unreadList(@RequestBody Page<SysMessage> page) {
|
public R<Page<SysMessageVo>> unreadList(@RequestBody Page<SysMessage> page) {
|
||||||
@ -160,7 +314,7 @@ public class SysMessageController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 获取已读消息列表
|
* 获取已读消息列表
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("system:message:list")
|
// @SaCheckPermission("system:message:list")
|
||||||
@Tag(name = "查询已读消息列表")
|
@Tag(name = "查询已读消息列表")
|
||||||
@PostMapping("/read")
|
@PostMapping("/read")
|
||||||
public R<Page<SysMessageVo>> readList(@RequestBody Page<SysMessage> page) {
|
public R<Page<SysMessageVo>> readList(@RequestBody Page<SysMessage> page) {
|
||||||
@ -172,12 +326,9 @@ public class SysMessageController extends BaseController {
|
|||||||
* 获取用户列表
|
* 获取用户列表
|
||||||
*/
|
*/
|
||||||
// @SaCheckPermission("system:message:list")
|
// @SaCheckPermission("system:message:list")
|
||||||
// @GetMapping("/user/list")
|
@GetMapping("/user/list")
|
||||||
// public R<TableDataInfo<SysUserVo>> getUserList() {
|
public R<List<SysUserVo>> getUserList(@RequestParam(required = false) String keyword) {
|
||||||
// PageQuery pageQuery = new PageQuery();
|
// 无论是否有关键词,都查询 ums_member 表中的用户信息
|
||||||
// pageQuery.setPageNum(1);
|
return R.ok(userService.selectMemberUsers(keyword));
|
||||||
// pageQuery.setPageSize(Integer.MAX_VALUE);
|
}
|
||||||
// TableDataInfo<SysUserVo> users = userService.selectPageUserList(new SysUserBo(), pageQuery);
|
|
||||||
// return R.ok(users);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package org.dromara.system.controller;
|
package org.dromara.system.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.core.validate.AddGroup;
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
import org.dromara.common.core.validate.EditGroup;
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||||
@ -61,6 +64,22 @@ public class SysMessageTemplateController extends BaseController {
|
|||||||
return R.ok(MapstructUtils.convert(template, SysMessageTemplateVo.class));
|
return R.ok(MapstructUtils.convert(template, SysMessageTemplateVo.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据名称查询消息模板列表(不分页)
|
||||||
|
*
|
||||||
|
* @param name 模板名称(可选,支持模糊查询)
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:template:query")
|
||||||
|
@Operation(summary = "根据名称查询消息模板列表(不分页)")
|
||||||
|
@GetMapping("/listByName")
|
||||||
|
public R<List<SysMessageTemplateVo>> listByName(@RequestParam(value = "name", required = false) String[] name) {
|
||||||
|
String searchName = null;
|
||||||
|
if (name != null && name.length > 0) {
|
||||||
|
searchName = name[0];
|
||||||
|
}
|
||||||
|
return R.ok(templateService.selectTemplateListByName(searchName));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增消息模板
|
* 新增消息模板
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.system.domain;
|
package org.dromara.system.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -10,6 +11,8 @@ import org.dromara.common.tenant.core.TenantEntity;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息对象 sys_message
|
* 消息对象 sys_message
|
||||||
@ -47,4 +50,8 @@ public class SysMessage extends BaseAudit {
|
|||||||
|
|
||||||
// /** 状态(0正常 1停用) */
|
// /** 状态(0正常 1停用) */
|
||||||
// private String status;
|
// private String status;
|
||||||
|
|
||||||
|
/** 扩展参数 */
|
||||||
|
@TableField(exist = false)
|
||||||
|
private Map<String, Object> params = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,10 @@ public class SysMessageTemplate extends BaseAudit {
|
|||||||
private String templateType;
|
private String templateType;
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 模板编码
|
// * 模板编码
|
||||||
*/
|
// */
|
||||||
private String templateCode;
|
// private String templateCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板名称
|
* 模板名称
|
||||||
|
@ -112,4 +112,13 @@ public class SysUser extends TenantEntity {
|
|||||||
return SystemConstants.SUPER_ADMIN_ID.equals(this.userId);
|
return SystemConstants.SUPER_ADMIN_ID.equals(this.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动设置更新者,父类使用LocalDateTime而这里使用Long类型
|
||||||
|
*
|
||||||
|
* @param updateBy 更新者ID
|
||||||
|
*/
|
||||||
|
// @Override
|
||||||
|
// public void setUpdateBy(Long updateBy) {
|
||||||
|
// super.setUpdateBy(updateBy);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package org.dromara.system.domain.bo;
|
|||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@ -13,7 +14,6 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
|
|||||||
import org.dromara.system.domain.SysMessage;
|
import org.dromara.system.domain.SysMessage;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -26,7 +26,6 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ExcelIgnoreUnannotated
|
@ExcelIgnoreUnannotated
|
||||||
@AutoMapper(target = SysMessage.class, reverseConvertGenerate = false)
|
|
||||||
public class SysMessageBo extends BaseAudit {
|
public class SysMessageBo extends BaseAudit {
|
||||||
|
|
||||||
/** 主键ID */
|
/** 主键ID */
|
||||||
@ -34,7 +33,7 @@ public class SysMessageBo extends BaseAudit {
|
|||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 消息标题 */
|
/** 消息标题 */
|
||||||
@NotBlank(message = "消息标题不能为空", groups = { AddGroup.class, EditGroup.class })
|
// @NotBlank(message = "消息标题不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
@Size(min = 0, max = 100, message = "消息标题长度不能超过100个字符")
|
@Size(min = 0, max = 100, message = "消息标题长度不能超过100个字符")
|
||||||
@ExcelProperty(value = "消息标题")
|
@ExcelProperty(value = "消息标题")
|
||||||
private String title;
|
private String title;
|
||||||
@ -45,7 +44,7 @@ public class SysMessageBo extends BaseAudit {
|
|||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
/** 消息类型(AUTO自动/MANUAL手动) */
|
/** 消息类型(AUTO自动/MANUAL手动) */
|
||||||
@NotBlank(message = "消息类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
// @NotBlank(message = "消息类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
@ExcelProperty(value = "消息类型")
|
@ExcelProperty(value = "消息类型")
|
||||||
private String msgType;
|
private String msgType;
|
||||||
|
|
||||||
@ -62,8 +61,8 @@ public class SysMessageBo extends BaseAudit {
|
|||||||
private Date scheduledTime;
|
private Date scheduledTime;
|
||||||
|
|
||||||
/** 发送范围(all:全部用户, userType:按用户类型, userIds:指定用户) */
|
/** 发送范围(all:全部用户, userType:按用户类型, userIds:指定用户) */
|
||||||
@NotBlank(message = "发送范围不能为空", groups = { AddGroup.class })
|
@NotEmpty(message = "发送范围不能为空", groups = { AddGroup.class })
|
||||||
private String sendScope;
|
private List<String> sendScope;
|
||||||
|
|
||||||
/** 接收用户ID列表 */
|
/** 接收用户ID列表 */
|
||||||
private List<Long> userIds;
|
private List<Long> userIds;
|
||||||
@ -74,6 +73,12 @@ public class SysMessageBo extends BaseAudit {
|
|||||||
/** 扩展数据(JSON格式) */
|
/** 扩展数据(JSON格式) */
|
||||||
private String extraData;
|
private String extraData;
|
||||||
|
|
||||||
|
/** 消息类型标识 1=指定角色 2=指定用户 3=指定群 */
|
||||||
|
private Integer logmess;
|
||||||
|
|
||||||
|
/** 模板ID */
|
||||||
|
private Long templateId;
|
||||||
|
|
||||||
/** 状态(0正常 1停用) */
|
/** 状态(0正常 1停用) */
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
@ -43,9 +43,9 @@ public class SysMessageTemplateBo extends BaseAudit {
|
|||||||
/**
|
/**
|
||||||
* 模板编码
|
* 模板编码
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "模板编码不能为空", groups = { AddGroup.class, EditGroup.class })
|
// @NotBlank(message = "模板编码不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
@Size(max = 50, message = "模板编码长度不能超过{max}个字符")
|
// @Size(max = 50, message = "模板编码长度不能超过{max}个字符")
|
||||||
private String templateCode;
|
// private String templateCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板类型(SMS=短信 MAIL=邮件 WECHAT=微信 SYSTEM=系统消息)
|
* 模板类型(SMS=短信 MAIL=邮件 WECHAT=微信 SYSTEM=系统消息)
|
||||||
@ -79,7 +79,7 @@ public class SysMessageTemplateBo extends BaseAudit {
|
|||||||
public LambdaQueryWrapper<SysMessageTemplate> toWrapper() {
|
public LambdaQueryWrapper<SysMessageTemplate> toWrapper() {
|
||||||
LambdaQueryWrapper<SysMessageTemplate> lqw = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<SysMessageTemplate> lqw = new LambdaQueryWrapper<>();
|
||||||
lqw.like(StringUtils.isNotBlank(templateName), SysMessageTemplate::getTemplateName, templateName)
|
lqw.like(StringUtils.isNotBlank(templateName), SysMessageTemplate::getTemplateName, templateName)
|
||||||
.like(StringUtils.isNotBlank(templateCode), SysMessageTemplate::getTemplateCode, templateCode)
|
// .like(StringUtils.isNotBlank(templateCode), SysMessageTemplate::getTemplateCode, templateCode)
|
||||||
.eq(StringUtils.isNotBlank(templateType), SysMessageTemplate::getTemplateType, templateType)
|
.eq(StringUtils.isNotBlank(templateType), SysMessageTemplate::getTemplateType, templateType)
|
||||||
.eq(StringUtils.isNotBlank(status), SysMessageTemplate::getStatus, status)
|
.eq(StringUtils.isNotBlank(status), SysMessageTemplate::getStatus, status)
|
||||||
.orderByDesc(SysMessageTemplate::getCreateTime);
|
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||||
@ -93,7 +93,7 @@ public class SysMessageTemplateBo extends BaseAudit {
|
|||||||
SysMessageTemplate entity = new SysMessageTemplate();
|
SysMessageTemplate entity = new SysMessageTemplate();
|
||||||
entity.setId(id);
|
entity.setId(id);
|
||||||
entity.setTemplateName(templateName);
|
entity.setTemplateName(templateName);
|
||||||
entity.setTemplateCode(templateCode);
|
// entity.setTemplateCode(templateCode);
|
||||||
entity.setTemplateType(templateType);
|
entity.setTemplateType(templateType);
|
||||||
entity.setTemplateContent(templateContent);
|
entity.setTemplateContent(templateContent);
|
||||||
entity.setStatus(status);
|
entity.setStatus(status);
|
||||||
|
@ -14,10 +14,47 @@ public class MessageEvent extends ApplicationEvent {
|
|||||||
|
|
||||||
private final SysMessageVo message;
|
private final SysMessageVo message;
|
||||||
private final Long userId;
|
private final Long userId;
|
||||||
|
private final String userIdStr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 Long 类型用户 ID 创建消息事件
|
||||||
|
*/
|
||||||
public MessageEvent(Object source, SysMessageVo message, Long userId) {
|
public MessageEvent(Object source, SysMessageVo message, Long userId) {
|
||||||
super(source);
|
super(source);
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.userIdStr = userId != null ? String.valueOf(userId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 String 类型用户 ID 创建消息事件
|
||||||
|
*/
|
||||||
|
public MessageEvent(Object source, SysMessageVo message, String userIdStr) {
|
||||||
|
super(source);
|
||||||
|
this.message = message;
|
||||||
|
this.userIdStr = userIdStr;
|
||||||
|
|
||||||
|
// 尝试转换为 Long 类型
|
||||||
|
Long parsedUserId = null;
|
||||||
|
try {
|
||||||
|
if (userIdStr != null) {
|
||||||
|
parsedUserId = Long.parseLong(userIdStr);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// 无法解析为 Long 类型,保持 userId 为 null
|
||||||
|
}
|
||||||
|
this.userId = parsedUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 MessageEvent 实例(支持 String 类型用户ID)
|
||||||
|
*
|
||||||
|
* @param source 事件源
|
||||||
|
* @param message 消息对象
|
||||||
|
* @param userIdStr 用户ID (String类型)
|
||||||
|
* @return MessageEvent 实例
|
||||||
|
*/
|
||||||
|
public static MessageEvent createWithStringUserId(Object source, SysMessageVo message, String userIdStr) {
|
||||||
|
return new MessageEvent(source, message, userIdStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,7 @@ import org.dromara.system.domain.SysMessage;
|
|||||||
import org.dromara.system.domain.SysMessageTemplate;
|
import org.dromara.system.domain.SysMessageTemplate;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息模板视图对象 sys_message_template
|
* 消息模板视图对象 sys_message_template
|
||||||
@ -30,16 +31,21 @@ public class SysMessageTemplateVo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String templateType;
|
private String templateType;
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 模板编码
|
// * 模板编码
|
||||||
*/
|
// */
|
||||||
private String templateCode;
|
// private String templateCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板名称
|
* 模板名称
|
||||||
*/
|
*/
|
||||||
private String templateName;
|
private String templateName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板标题
|
||||||
|
*/
|
||||||
|
private String title;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板内容
|
* 模板内容
|
||||||
*/
|
*/
|
||||||
@ -55,6 +61,26 @@ public class SysMessageTemplateVo implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者
|
||||||
|
*/
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新者
|
||||||
|
*/
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * 备注
|
// * 备注
|
||||||
// */
|
// */
|
||||||
|
@ -10,6 +10,8 @@ import org.dromara.system.domain.SysNotice;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息视图对象
|
* 消息视图对象
|
||||||
@ -17,6 +19,7 @@ import java.util.Date;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
@AutoMapper(target = SysMessage.class)
|
@AutoMapper(target = SysMessage.class)
|
||||||
public class SysMessageVo implements Serializable {
|
public class SysMessageVo implements Serializable {
|
||||||
|
|
||||||
@ -62,4 +65,16 @@ public class SysMessageVo implements Serializable {
|
|||||||
/** 创建时间 */
|
/** 创建时间 */
|
||||||
@ExcelProperty(value = "创建时间")
|
@ExcelProperty(value = "创建时间")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
|
/** 更新时间 */
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/** 创建者 */
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/** 更新者 */
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
/** 扩展参数 */
|
||||||
|
private Map<String, Object> params = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,25 @@ package org.dromara.system.event;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.dromara.system.config.RocketMQConfig;
|
||||||
|
import org.dromara.system.consumer.MessageRocketMQConsumer;
|
||||||
import org.dromara.system.domain.event.MessageEvent;
|
import org.dromara.system.domain.event.MessageEvent;
|
||||||
|
import org.dromara.system.service.IRocketMQService;
|
||||||
|
import org.dromara.system.service.ITencentIMService;
|
||||||
import org.dromara.system.websocket.MessageWebSocketServer;
|
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息事件监听器
|
* 消息事件监听器
|
||||||
*
|
*
|
||||||
@ -15,10 +28,17 @@ import org.springframework.stereotype.Component;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class MessageEventListener {
|
public class MessageEventListener {
|
||||||
|
|
||||||
private final MessageWebSocketServer messageWebSocketServer;
|
@Autowired
|
||||||
|
private IRocketMQService rocketMQService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageWebSocketServer messageWebSocketServer;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("systemTencentIMService")
|
||||||
|
private ITencentIMService tencentIMService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理消息事件
|
* 处理消息事件
|
||||||
@ -27,7 +47,125 @@ public class MessageEventListener {
|
|||||||
@EventListener
|
@EventListener
|
||||||
public void handleMessageEvent(MessageEvent event) {
|
public void handleMessageEvent(MessageEvent event) {
|
||||||
try {
|
try {
|
||||||
messageWebSocketServer.sendMessage(event.getUserId(), String.valueOf(event.getMessage()));
|
// 提取消息和用户ID
|
||||||
|
String userId = event.getUserIdStr();
|
||||||
|
|
||||||
|
// 创建消息包装对象
|
||||||
|
MessageRocketMQConsumer.MessageWrapper wrapper = new MessageRocketMQConsumer.MessageWrapper();
|
||||||
|
wrapper.setUserId(userId);
|
||||||
|
wrapper.setMessage(event.getMessage());
|
||||||
|
|
||||||
|
// 首先尝试发送消息到腾讯IM
|
||||||
|
boolean tencentIMSendSuccess = false;
|
||||||
|
try {
|
||||||
|
// 消息发送者可能是系统或管理员,这里使用固定的管理员账号作为发送者
|
||||||
|
String fromUserId = "administrator";
|
||||||
|
String toUserId = userId; // 接收者是事件中的用户ID
|
||||||
|
String content = JsonUtils.toJsonString(event.getMessage()); // 消息内容序列化为JSON
|
||||||
|
|
||||||
|
// 处理消息变量替换(如果有)
|
||||||
|
Map<String, String> variables = new HashMap<>();
|
||||||
|
// 这里可以添加变量映射,例如:variables.put("userName", "张三");
|
||||||
|
|
||||||
|
// 从消息中提取标题和描述
|
||||||
|
String title = event.getMessage().getTitle();
|
||||||
|
String desc = event.getMessage().getContent();
|
||||||
|
|
||||||
|
// 处理变量替换
|
||||||
|
if (variables.size() > 0) {
|
||||||
|
title = tencentIMService.processMessageVariables(title, variables);
|
||||||
|
desc = tencentIMService.processMessageVariables(desc, variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扩展字段,可以在APP端获取
|
||||||
|
String ext = null;
|
||||||
|
if (event.getMessage().getParams() != null && !event.getMessage().getParams().isEmpty()) {
|
||||||
|
ext = JsonUtils.toJsonString(event.getMessage().getParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据消息类型决定推送方式
|
||||||
|
Map<String, Object> params = event.getMessage().getParams();
|
||||||
|
String pushType = null;
|
||||||
|
if (params != null && params.containsKey("pushType")) {
|
||||||
|
pushType = String.valueOf(params.get("pushType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushType != null) {
|
||||||
|
switch (pushType) {
|
||||||
|
case "ALL":
|
||||||
|
// 全员推送
|
||||||
|
tencentIMSendSuccess = tencentIMService.pushToAll(title, desc, true, ext);
|
||||||
|
break;
|
||||||
|
case "ATTRIBUTE":
|
||||||
|
// 属性推送
|
||||||
|
Map<String, Object> attributes = new HashMap<>();
|
||||||
|
// 从消息参数中提取属性条件
|
||||||
|
if (params != null && params.containsKey("attributes")) {
|
||||||
|
Object attrObj = params.get("attributes");
|
||||||
|
if (attrObj instanceof Map) {
|
||||||
|
attributes = (Map<String, Object>) attrObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tencentIMSendSuccess = tencentIMService.pushByAttributes(title, desc, attributes, true, ext);
|
||||||
|
break;
|
||||||
|
case "TAG":
|
||||||
|
// 标签推送
|
||||||
|
if (params != null && params.containsKey("tags")) {
|
||||||
|
Object tagsObj = params.get("tags");
|
||||||
|
if (tagsObj instanceof String[]) {
|
||||||
|
tencentIMSendSuccess = tencentIMService.pushByTags(title, desc,
|
||||||
|
Arrays.asList((String[]) tagsObj), true, ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "USER":
|
||||||
|
default:
|
||||||
|
// 单用户推送(默认)
|
||||||
|
tencentIMSendSuccess = tencentIMService.pushToUsers(title, desc,
|
||||||
|
Collections.singletonList(toUserId), true, ext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 默认为单用户推送
|
||||||
|
tencentIMSendSuccess = tencentIMService.sendMessageToTencentIM(fromUserId, toUserId, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tencentIMSendSuccess) {
|
||||||
|
log.info("消息已成功发送到腾讯IM,接收者: {}", toUserId);
|
||||||
|
} else {
|
||||||
|
log.warn("发送消息到腾讯IM失败,将尝试通过其他方式发送");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送消息到腾讯IM异常,将尝试通过其他方式发送", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 无论腾讯IM是否发送成功,都继续尝试通过RocketMQ发送消息
|
||||||
|
// 这样可以确保消息至少通过一种方式发送出去
|
||||||
|
boolean rocketMQSendSuccess = false;
|
||||||
|
try {
|
||||||
|
rocketMQService.sendMessage(
|
||||||
|
RocketMQConfig.TOPIC_SYS_MSG,
|
||||||
|
RocketMQConfig.TAG_SYS_MSG,
|
||||||
|
wrapper
|
||||||
|
);
|
||||||
|
rocketMQSendSuccess = true;
|
||||||
|
log.info("消息事件已通过RocketMQ发送,userId: {}", userId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("通过RocketMQ发送消息失败,将尝试直接通过WebSocket发送", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果前两种方式都失败,则尝试直接通过WebSocket发送
|
||||||
|
if (!tencentIMSendSuccess && !rocketMQSendSuccess && event.getUserId() != null) {
|
||||||
|
try {
|
||||||
|
messageWebSocketServer.sendMessage(
|
||||||
|
event.getUserId(),
|
||||||
|
JsonUtils.toJsonString(event.getMessage())
|
||||||
|
);
|
||||||
|
log.info("消息事件已直接通过WebSocket发送,userId: {}", event.getUserId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("通过WebSocket发送消息失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("处理消息事件失败", e);
|
log.error("处理消息事件失败", e);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package org.dromara.system.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RocketMQ服务接口
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
*/
|
||||||
|
public interface IRocketMQService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到指定主题
|
||||||
|
*
|
||||||
|
* @param topic 主题
|
||||||
|
* @param message 消息内容
|
||||||
|
*/
|
||||||
|
void sendMessage(String topic, Object message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到指定主题和标签
|
||||||
|
*
|
||||||
|
* @param topic 主题
|
||||||
|
* @param tag 标签
|
||||||
|
* @param message 消息内容
|
||||||
|
*/
|
||||||
|
void sendMessage(String topic, String tag, Object message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送延迟消息
|
||||||
|
*
|
||||||
|
* @param topic 主题
|
||||||
|
* @param tag 标签
|
||||||
|
* @param message 消息内容
|
||||||
|
* @param delayTimeLevel 延迟级别 (1s/5s/10s/30s/1m/2m/3m/4m/5m/6m/7m/8m/9m/10m/20m/30m/1h/2h)
|
||||||
|
*/
|
||||||
|
void sendDelayMessage(String topic, String tag, Object message, int delayTimeLevel);
|
||||||
|
}
|
@ -34,22 +34,40 @@ public interface ISysMessageService extends IService<SysMessage> {
|
|||||||
Page<SysMessageVo> selectReadMessagesPage(Long userId, Page<SysMessage> page);
|
Page<SysMessageVo> selectReadMessagesPage(Long userId, Page<SysMessage> page);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送消息给指定用户
|
* 向用户发送消息
|
||||||
*
|
*
|
||||||
* @param message 消息内容
|
* @param message 消息信息
|
||||||
* @param userId 用户ID
|
* @param userId 用户ID (Long类型)
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
int sendMessageToUser(SysMessageBo message, Long userId);
|
int sendMessageToUser(SysMessageBo message, Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送消息给多个用户
|
* 向用户发送消息 (String类型用户ID)
|
||||||
*
|
*
|
||||||
* @param message 消息内容
|
* @param message 消息信息
|
||||||
* @param userIds 用户ID列表
|
* @param userId 用户ID (String类型)
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
int sendMessageToUsers(SysMessageBo message, List<Long> userIds);
|
int sendMessageToUserByStringId(SysMessageBo message, String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向多个用户发送消息
|
||||||
|
*
|
||||||
|
* @param message 消息信息
|
||||||
|
* @param userIds 用户ID列表 (Long类型)
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
// int sendMessageToUsers(SysMessageBo message, List<Long> userIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向多个用户发送消息
|
||||||
|
*
|
||||||
|
* @param message 消息信息
|
||||||
|
* @param userIds 用户ID列表 (String类型)
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int sendMessageToUsers(SysMessageBo message, List<String> userIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送自动消息
|
* 发送自动消息
|
||||||
|
@ -72,4 +72,12 @@ public interface ISysMessageTemplateService extends IService<SysMessageTemplate>
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
int deleteTemplateById(Long id);
|
int deleteTemplateById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据名称查询消息模板列表(不分页)
|
||||||
|
*
|
||||||
|
* @param name 模板名称(可选,支持模糊查询)
|
||||||
|
* @return 消息模板列表
|
||||||
|
*/
|
||||||
|
List<SysMessageTemplateVo> selectTemplateListByName(String name);
|
||||||
}
|
}
|
||||||
|
@ -228,4 +228,35 @@ public interface ISysUserService {
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
List<SysUserVo> selectUserListByDept(Long deptId);
|
List<SysUserVo> selectUserListByDept(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询用户列表
|
||||||
|
*
|
||||||
|
* @param user 用户信息
|
||||||
|
* @return 用户列表
|
||||||
|
*/
|
||||||
|
List<SysUserVo> selectUserList(SysUserBo user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有会员用户信息(ums_member表)
|
||||||
|
*
|
||||||
|
* @return 会员用户列表
|
||||||
|
*/
|
||||||
|
List<SysUserVo> selectAllMemberUsers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据关键字查询会员用户信息(ums_member表)
|
||||||
|
*
|
||||||
|
* @param keyword 关键字(用户名、昵称或手机号)
|
||||||
|
* @return 会员用户列表
|
||||||
|
*/
|
||||||
|
List<SysUserVo> selectMemberUsers(String keyword);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据角色ID查询用户ID列表
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 用户ID列表
|
||||||
|
*/
|
||||||
|
List<Long> selectUserIdsByRoleId(Long roleId);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
package org.dromara.system.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 腾讯IM服务接口
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
*/
|
||||||
|
public interface ITencentIMService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到腾讯IM
|
||||||
|
*
|
||||||
|
* @param fromUserId 发送方用户ID
|
||||||
|
* @param toUserId 接收方用户ID
|
||||||
|
* @param content 消息内容
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
boolean sendMessageToTencentIM(String fromUserId, String toUserId, String content);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建腾讯IM账号
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 用户签名
|
||||||
|
*/
|
||||||
|
String createTencentIMAccount(String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送消息给全体用户
|
||||||
|
*
|
||||||
|
* @param title 消息标题
|
||||||
|
* @param desc 消息描述
|
||||||
|
* @param offlinePush 是否离线推送
|
||||||
|
* @param ext 扩展字段(JSON字符串)
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
boolean pushToAll(String title, String desc, boolean offlinePush, String ext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户属性推送消息
|
||||||
|
*
|
||||||
|
* @param title 消息标题
|
||||||
|
* @param desc 消息描述
|
||||||
|
* @param attributes 用户属性条件
|
||||||
|
* @param offlinePush 是否离线推送
|
||||||
|
* @param ext 扩展字段(JSON字符串)
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
boolean pushByAttributes(String title, String desc, Map<String, Object> attributes, boolean offlinePush, String ext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据标签推送消息
|
||||||
|
*
|
||||||
|
* @param title 消息标题
|
||||||
|
* @param desc 消息描述
|
||||||
|
* @param tags 标签列表
|
||||||
|
* @param offlinePush 是否离线推送
|
||||||
|
* @param ext 扩展字段(JSON字符串)
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
boolean pushByTags(String title, String desc, List<String> tags, boolean offlinePush, String ext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送消息给指定用户
|
||||||
|
*
|
||||||
|
* @param title 消息标题
|
||||||
|
* @param desc 消息描述
|
||||||
|
* @param userIds 用户ID列表
|
||||||
|
* @param offlinePush 是否离线推送
|
||||||
|
* @param ext 扩展字段(JSON字符串)
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
boolean pushToUsers(String title, String desc, List<String> userIds, boolean offlinePush, String ext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理消息变量替换
|
||||||
|
*
|
||||||
|
* @param content 原始内容
|
||||||
|
* @param variables 变量映射
|
||||||
|
* @return 替换后的内容
|
||||||
|
*/
|
||||||
|
String processMessageVariables(String content, Map<String, String> variables);
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.client.producer.SendCallback;
|
||||||
|
import org.apache.rocketmq.client.producer.SendResult;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.dromara.system.service.IRocketMQService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RocketMQ服务实现类
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class RocketMQServiceImpl implements IRocketMQService {
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private RocketMQTemplate rocketMQTemplate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String topic, Object message) {
|
||||||
|
if (rocketMQTemplate == null) {
|
||||||
|
log.error("RocketMQTemplate未初始化,无法发送消息");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String jsonMessage = JsonUtils.toJsonString(message);
|
||||||
|
rocketMQTemplate.convertAndSend(topic, jsonMessage);
|
||||||
|
log.info("发送消息到RocketMQ成功,topic: {}, message: {}", topic, jsonMessage);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送消息到RocketMQ失败,topic: {}, message: {}", topic, message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(String topic, String tag, Object message) {
|
||||||
|
if (rocketMQTemplate == null) {
|
||||||
|
log.error("RocketMQTemplate未初始化,无法发送消息");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String destination = topic + ":" + tag;
|
||||||
|
String jsonMessage = JsonUtils.toJsonString(message);
|
||||||
|
rocketMQTemplate.convertAndSend(destination, jsonMessage);
|
||||||
|
log.info("发送消息到RocketMQ成功,destination: {}, message: {}", destination, jsonMessage);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送消息到RocketMQ失败,topic: {}, tag: {}, message: {}", topic, tag, message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendDelayMessage(String topic, String tag, Object message, int delayTimeLevel) {
|
||||||
|
if (rocketMQTemplate == null) {
|
||||||
|
log.error("RocketMQTemplate未初始化,无法发送延迟消息");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String destination = topic + ":" + tag;
|
||||||
|
String jsonMessage = JsonUtils.toJsonString(message);
|
||||||
|
rocketMQTemplate.asyncSend(destination, MessageBuilder.withPayload(jsonMessage).build(),
|
||||||
|
new SendCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(SendResult sendResult) {
|
||||||
|
log.info("发送延迟消息到RocketMQ成功,destination: {}, message: {}, result: {}",
|
||||||
|
destination, jsonMessage, sendResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onException(Throwable throwable) {
|
||||||
|
log.error("发送延迟消息到RocketMQ异常,destination: {}, message: {}",
|
||||||
|
destination, jsonMessage, throwable);
|
||||||
|
}
|
||||||
|
}, 3000, delayTimeLevel);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送延迟消息到RocketMQ失败,topic: {}, tag: {}, message: {}", topic, tag, message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
@ -20,7 +21,9 @@ import org.springframework.context.ApplicationEventPublisher;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息Service业务层处理
|
* 消息Service业务层处理
|
||||||
@ -29,6 +32,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMessage> implements ISysMessageService {
|
public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMessage> implements ISysMessageService {
|
||||||
|
|
||||||
private final SysMessageMapper messageMapper;
|
private final SysMessageMapper messageMapper;
|
||||||
@ -81,12 +85,28 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
|||||||
// 保存消息
|
// 保存消息
|
||||||
SysMessage entity = message.toEntity();
|
SysMessage entity = message.toEntity();
|
||||||
messageMapper.insert(entity);
|
messageMapper.insert(entity);
|
||||||
// 创建消息用户关联
|
|
||||||
SysMessageUser messageUser = new SysMessageUser();
|
// 检查消息与用户关联是否已存在
|
||||||
messageUser.setMessageId(entity.getId());
|
LambdaQueryWrapper<SysMessageUser> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
messageUser.setUserId(userId);
|
queryWrapper.eq(SysMessageUser::getMessageId, entity.getId())
|
||||||
messageUser.setIsRead(false);
|
.eq(SysMessageUser::getUserId, userId);
|
||||||
int rows = messageUserMapper.insert(messageUser);
|
int count = Math.toIntExact(messageUserMapper.selectCount(queryWrapper));
|
||||||
|
|
||||||
|
// 只有当关联不存在时才创建
|
||||||
|
int rows = 0;
|
||||||
|
if (count == 0) {
|
||||||
|
// 创建消息用户关联
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setMessageId(entity.getId());
|
||||||
|
messageUser.setUserId(userId);
|
||||||
|
messageUser.setIsRead(false);
|
||||||
|
rows = messageUserMapper.insert(messageUser);
|
||||||
|
} else {
|
||||||
|
log.info("消息与用户关联已存在,跳过创建: messageId={}, userId={}", entity.getId(), userId);
|
||||||
|
// 已存在也认为操作成功
|
||||||
|
rows = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// 发送WebSocket消息
|
// 发送WebSocket消息
|
||||||
if (rows > 0) {
|
if (rows > 0) {
|
||||||
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||||
@ -97,25 +117,56 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int sendMessageToUsers(SysMessageBo message, List<Long> userIds) {
|
public int sendMessageToUsers(SysMessageBo message, List<String> userIds) {
|
||||||
|
if (userIds == null || userIds.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 保存消息
|
// 保存消息
|
||||||
SysMessage entity = message.toEntity();
|
SysMessage entity = message.toEntity();
|
||||||
messageMapper.insert(entity);
|
messageMapper.insert(entity);
|
||||||
|
|
||||||
// 批量创建消息用户关联
|
// 批量创建消息用户关联
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (Long userId : userIds) {
|
for (String userIdStr : userIds) {
|
||||||
SysMessageUser messageUser = new SysMessageUser();
|
if (StringUtils.isBlank(userIdStr)) {
|
||||||
messageUser.setMessageId(entity.getId());
|
continue;
|
||||||
messageUser.setUserId(userId);
|
}
|
||||||
messageUser.setIsRead(false);
|
|
||||||
int rows = messageUserMapper.insert(messageUser);
|
try {
|
||||||
if (rows > 0) {
|
Long userId = Long.parseLong(userIdStr);
|
||||||
count++;
|
|
||||||
// 发送WebSocket消息
|
// 检查消息与用户关联是否已存在
|
||||||
|
LambdaQueryWrapper<SysMessageUser> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(SysMessageUser::getMessageId, entity.getId())
|
||||||
|
.eq(SysMessageUser::getUserId, userId);
|
||||||
|
int existCount = Math.toIntExact(messageUserMapper.selectCount(queryWrapper));
|
||||||
|
|
||||||
|
// 只有当关联不存在时才创建
|
||||||
|
if (existCount == 0) {
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setMessageId(entity.getId());
|
||||||
|
messageUser.setUserId(userId);
|
||||||
|
messageUser.setIsRead(false);
|
||||||
|
int rows = messageUserMapper.insert(messageUser);
|
||||||
|
if (rows > 0) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("消息与用户关联已存在,跳过创建: messageId={}, userId={}", entity.getId(), userId);
|
||||||
|
// 已存在也计入成功数量
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 无论关联是否新建,都发送事件通知
|
||||||
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||||
eventPublisher.publishEvent(new MessageEvent(this, messageVo, userId));
|
eventPublisher.publishEvent(MessageEvent.createWithStringUserId(this, messageVo, userIdStr));
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.error("无法将String类型的用户ID转换为Long: {}", userIdStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +174,7 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int sendAutoMessage(SysMessageBo message, List<Long> userIds) {
|
public int sendAutoMessage(SysMessageBo message, List<Long> userIds) {
|
||||||
message.setMsgType("AUTO");
|
message.setMsgType("AUTO");
|
||||||
return sendMessageToUsers(message, userIds);
|
return sendMessageToUsers(message, userIds.stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -204,5 +255,30 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
|||||||
return lqw;
|
return lqw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int sendMessageToUserByStringId(SysMessageBo message, String userId) {
|
||||||
|
if (StringUtils.isBlank(userId)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Long userIdLong = Long.parseLong(userId);
|
||||||
|
return sendMessageToUser(message, userIdLong);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.error("无法将String类型的用户ID转换为Long: {}", userId);
|
||||||
|
|
||||||
|
// 尝试以字符串形式发送
|
||||||
|
// 保存消息
|
||||||
|
SysMessage entity = message.toEntity();
|
||||||
|
messageMapper.insert(entity);
|
||||||
|
|
||||||
|
// 发送事件通知
|
||||||
|
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||||
|
eventPublisher.publishEvent(MessageEvent.createWithStringUserId(this, messageVo, userId));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ public class SysMessageTemplateServiceImpl extends ServiceImpl<SysMessageTemplat
|
|||||||
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
||||||
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
||||||
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
||||||
.like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
// .like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
||||||
.orderByDesc(SysMessageTemplate::getCreateTime);
|
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||||
|
|
||||||
Page<SysMessageTemplate> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
Page<SysMessageTemplate> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||||
@ -51,7 +51,7 @@ public class SysMessageTemplateServiceImpl extends ServiceImpl<SysMessageTemplat
|
|||||||
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
||||||
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
||||||
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
||||||
.like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
// .like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
||||||
.orderByDesc(SysMessageTemplate::getCreateTime);
|
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||||
return MapstructUtils.convert(templateMapper.selectList(lqw), SysMessageTemplateVo.class);
|
return MapstructUtils.convert(templateMapper.selectList(lqw), SysMessageTemplateVo.class);
|
||||||
}
|
}
|
||||||
@ -80,4 +80,14 @@ public class SysMessageTemplateServiceImpl extends ServiceImpl<SysMessageTemplat
|
|||||||
public int deleteTemplateById(Long id) {
|
public int deleteTemplateById(Long id) {
|
||||||
return templateMapper.deleteById(id);
|
return templateMapper.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysMessageTemplateVo> selectTemplateListByName(String name) {
|
||||||
|
LambdaQueryWrapper<SysMessageTemplate> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
if (StringUtils.isNotBlank(name)) {
|
||||||
|
queryWrapper.like(SysMessageTemplate::getTemplateName, name);
|
||||||
|
}
|
||||||
|
queryWrapper.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||||
|
return MapstructUtils.convert(templateMapper.selectList(queryWrapper), SysMessageTemplateVo.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,11 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.wzj.soopin.member.domain.po.Member;
|
||||||
|
import com.wzj.soopin.member.service.IMemberService;
|
||||||
|
import org.dromara.common.core.utils.SpringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户 业务层处理
|
* 用户 业务层处理
|
||||||
@ -541,15 +546,14 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
|||||||
/**
|
/**
|
||||||
* 通过部门id查询当前部门所有用户
|
* 通过部门id查询当前部门所有用户
|
||||||
*
|
*
|
||||||
* @param deptId 部门ID
|
* @param deptId 部门id
|
||||||
* @return 用户信息集合信息
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<SysUserVo> selectUserListByDept(Long deptId) {
|
public List<SysUserVo> selectUserListByDept(Long deptId) {
|
||||||
LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
|
return baseMapper.selectUserList(new LambdaQueryWrapper<SysUser>()
|
||||||
lqw.eq(SysUser::getDeptId, deptId);
|
.eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId)
|
||||||
lqw.orderByAsc(SysUser::getUserId);
|
.eq(SysUser::getStatus, SystemConstants.NORMAL));
|
||||||
return baseMapper.selectVoList(lqw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -720,4 +724,148 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
|||||||
return selectListByIds(new ArrayList<>(userIds));
|
return selectListByIds(new ArrayList<>(userIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询用户列表
|
||||||
|
*
|
||||||
|
* @param user 用户信息
|
||||||
|
* @return 用户列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<SysUserVo> selectUserList(SysUserBo user) {
|
||||||
|
LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.eq(SysUser::getStatus, SystemConstants.NORMAL);
|
||||||
|
|
||||||
|
// 模糊搜索昵称或手机号
|
||||||
|
if (StringUtils.isNotBlank(user.getNickName())) {
|
||||||
|
lqw.and(wrapper -> wrapper
|
||||||
|
.like(SysUser::getNickName, user.getNickName())
|
||||||
|
.or()
|
||||||
|
.like(StringUtils.isNotBlank(user.getPhonenumber()), SysUser::getPhonenumber, user.getPhonenumber()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseMapper.selectUserList(lqw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysUserVo> selectAllMemberUsers() {
|
||||||
|
try {
|
||||||
|
// 获取 Spring 上下文中的 MemberService bean
|
||||||
|
IMemberService memberService = SpringUtils.getBean(IMemberService.class);
|
||||||
|
|
||||||
|
if (memberService != null) {
|
||||||
|
// 查询所有会员信息
|
||||||
|
List<Member> members = memberService.list();
|
||||||
|
|
||||||
|
// 将 Member 转换为 SysUserVo
|
||||||
|
return members.stream().map(member -> {
|
||||||
|
SysUserVo userVo = new SysUserVo();
|
||||||
|
// 设置用户ID
|
||||||
|
userVo.setUserId(member.getId());
|
||||||
|
// 设置用户名
|
||||||
|
userVo.setUserName(member.getUserName());
|
||||||
|
// 设置昵称
|
||||||
|
userVo.setNickName(member.getNickname());
|
||||||
|
// 设置手机号,如果加密了就用隐藏版本
|
||||||
|
userVo.setPhonenumber(StringUtils.isNotBlank(member.getPhoneHidden()) ?
|
||||||
|
member.getPhoneHidden() : member.getPhoneEncrypted());
|
||||||
|
// 设置头像
|
||||||
|
if (StringUtils.isNotBlank(member.getAvatar())) {
|
||||||
|
try {
|
||||||
|
userVo.setAvatar(Long.parseLong(member.getAvatar()));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("会员头像ID格式不正确: {}", member.getAvatar());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置性别
|
||||||
|
if (member.getGender() != null) {
|
||||||
|
userVo.setSex(member.getGender().toString());
|
||||||
|
}
|
||||||
|
// 设置状态
|
||||||
|
userVo.setStatus(member.getStatus() == 1 ? "0" : "1"); // 转换状态值
|
||||||
|
|
||||||
|
return userVo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询会员信息失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果查询失败或会员服务不可用,返回空列表
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysUserVo> selectMemberUsers(String keyword) {
|
||||||
|
// 尝试获取会员服务
|
||||||
|
try {
|
||||||
|
// 获取 Spring 上下文中的 MemberService bean
|
||||||
|
IMemberService memberService = SpringUtils.getBean(IMemberService.class);
|
||||||
|
|
||||||
|
if (memberService != null) {
|
||||||
|
// 创建查询条件
|
||||||
|
LambdaQueryWrapper<Member> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
|
||||||
|
// 如果有关键词,添加模糊查询条件(昵称、用户名、手机号)
|
||||||
|
if (StringUtils.isNotBlank(keyword)) {
|
||||||
|
queryWrapper.like(Member::getNickname, keyword)
|
||||||
|
.or()
|
||||||
|
.like(Member::getUserName, keyword)
|
||||||
|
.or()
|
||||||
|
.like(Member::getPhoneEncrypted, keyword)
|
||||||
|
.or()
|
||||||
|
.like(Member::getPhoneHidden, keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询会员信息
|
||||||
|
List<Member> members = memberService.list(queryWrapper);
|
||||||
|
|
||||||
|
// 将 Member 转换为 SysUserVo
|
||||||
|
return members.stream().map(member -> {
|
||||||
|
SysUserVo userVo = new SysUserVo();
|
||||||
|
// 设置用户ID
|
||||||
|
userVo.setUserId(member.getId());
|
||||||
|
// 设置用户名
|
||||||
|
userVo.setUserName(member.getUserName());
|
||||||
|
// 设置昵称
|
||||||
|
userVo.setNickName(member.getNickname());
|
||||||
|
// 设置手机号,如果加密了就用隐藏版本
|
||||||
|
userVo.setPhonenumber(StringUtils.isNotBlank(member.getPhoneHidden()) ?
|
||||||
|
member.getPhoneHidden() : member.getPhoneEncrypted());
|
||||||
|
// 设置头像
|
||||||
|
if (StringUtils.isNotBlank(member.getAvatar())) {
|
||||||
|
try {
|
||||||
|
userVo.setAvatar(Long.parseLong(member.getAvatar()));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("会员头像ID格式不正确: {}", member.getAvatar());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 设置性别
|
||||||
|
if (member.getGender() != null) {
|
||||||
|
userVo.setSex(member.getGender().toString());
|
||||||
|
}
|
||||||
|
// 设置状态
|
||||||
|
userVo.setStatus(member.getStatus() == 1 ? "0" : "1"); // 转换状态值
|
||||||
|
|
||||||
|
return userVo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询会员信息失败", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果查询失败或会员服务不可用,返回空列表
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据角色ID查询用户ID列表
|
||||||
|
*
|
||||||
|
* @param roleId 角色ID
|
||||||
|
* @return 用户ID列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Long> selectUserIdsByRoleId(Long roleId) {
|
||||||
|
return userRoleMapper.selectUserIdsByRoleId(roleId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,447 @@
|
|||||||
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.system.service.ITencentIMService;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 腾讯IM服务实现类
|
||||||
|
*
|
||||||
|
* @author wzj
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service("systemTencentIMService")
|
||||||
|
public class TencentIMServiceImpl implements ITencentIMService {
|
||||||
|
|
||||||
|
@Value("${tencent.im.sdkappid}")
|
||||||
|
private long sdkAppId;
|
||||||
|
|
||||||
|
@Value("${tencent.im.secretkey}")
|
||||||
|
private String secretKey;
|
||||||
|
|
||||||
|
@Value("${tencent.im.admin}")
|
||||||
|
private String adminAccount;
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
// 变量替换的正则表达式模式
|
||||||
|
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$(\\w+)");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成用户签名
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 用户签名
|
||||||
|
*/
|
||||||
|
private String generateUserSig(String userId) {
|
||||||
|
// 注意: 这里需要实现腾讯云IM SDK的TLSSigAPIv2签名生成
|
||||||
|
// 参考腾讯云文档: https://cloud.tencent.com/document/product/269/32688
|
||||||
|
// 实现方法:
|
||||||
|
// 1. 导入腾讯云IM SDK依赖
|
||||||
|
// 2. 使用sdkAppId和secretKey生成签名
|
||||||
|
// 示例代码:
|
||||||
|
// TLSSigAPIv2 tlsSigApi = new TLSSigAPIv2(sdkAppId, secretKey);
|
||||||
|
// return tlsSigApi.genUserSig(userId, 86400); // 有效期设为1天(86400秒)
|
||||||
|
|
||||||
|
log.info("生成用户签名: {}", userId);
|
||||||
|
|
||||||
|
// 当前为模拟实现,实际项目中请替换为真实签名生成逻辑
|
||||||
|
try {
|
||||||
|
// 临时返回一个固定值用于测试
|
||||||
|
// 注意:这是临时方案,正式环境必须替换为正确实现
|
||||||
|
return "eJyrVgrxDXFSsrS0MDA2MzY1NTawNDAzsTQ1sTCyMDI2NdRRKs9ILUpVsjKoLEgsKk7NswlPzYnIsagoyIgrsYl3Lg5IALITi5BkS1JzSlOLbMJKi32DKtNCglONDSNNXfMqk3wN0myrvVUYGBgYGZiaGBoamCgZ6hlYGOUb6Rmaq1QHAAD--wJe";
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("生成用户签名异常", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成管理员签名
|
||||||
|
*
|
||||||
|
* @return 管理员签名
|
||||||
|
*/
|
||||||
|
private String generateAdminUserSig() {
|
||||||
|
return generateUserSig(adminAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createTencentIMAccount(String userId) {
|
||||||
|
try {
|
||||||
|
String userSig = generateAdminUserSig();
|
||||||
|
String random = String.valueOf(System.currentTimeMillis());
|
||||||
|
|
||||||
|
// 构建API请求URL
|
||||||
|
String url = String.format(
|
||||||
|
"https://console.tim.qq.com/v4/im_open_login_svc/account_import" +
|
||||||
|
"?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
|
||||||
|
sdkAppId,
|
||||||
|
adminAccount,
|
||||||
|
userSig,
|
||||||
|
random);
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("UserID", userId);
|
||||||
|
requestBody.put("Nick", userId);
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
log.info("创建腾讯IM账号结果: {}", response.getBody());
|
||||||
|
|
||||||
|
// 生成并返回用户签名
|
||||||
|
return generateUserSig(userId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("创建腾讯IM账号异常: {}", userId, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendMessageToTencentIM(String fromUserId, String toUserId, String content) {
|
||||||
|
try {
|
||||||
|
String userSig = generateAdminUserSig();
|
||||||
|
String random = String.valueOf(new Random().nextInt(999999999));
|
||||||
|
|
||||||
|
// 构建API请求URL
|
||||||
|
String url = String.format(
|
||||||
|
"https://console.tim.qq.com/v4/openim/sendmsg" +
|
||||||
|
"?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
|
||||||
|
sdkAppId,
|
||||||
|
adminAccount,
|
||||||
|
userSig,
|
||||||
|
random);
|
||||||
|
|
||||||
|
// 构建消息内容
|
||||||
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
|
msgContent.put("Text", content);
|
||||||
|
|
||||||
|
// 构建消息体
|
||||||
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
|
msgBody.put("MsgType", "TIMTextElem");
|
||||||
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("SyncOtherMachine", 2); // 消息不同步至发送方
|
||||||
|
requestBody.put("From_Account", fromUserId);
|
||||||
|
requestBody.put("To_Account", toUserId);
|
||||||
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
log.info("发送消息到腾讯IM结果: {}", response.getBody());
|
||||||
|
|
||||||
|
// 解析响应判断是否成功
|
||||||
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送消息到腾讯IM异常", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pushToAll(String title, String desc, boolean offlinePush, String ext) {
|
||||||
|
try {
|
||||||
|
String userSig = generateAdminUserSig();
|
||||||
|
String random = String.valueOf(new Random().nextInt(999999999));
|
||||||
|
|
||||||
|
// 构建API请求URL - 使用全员推送接口
|
||||||
|
String url = String.format(
|
||||||
|
"https://console.tim.qq.com/v4/all_member_push/im_push" +
|
||||||
|
"?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
|
||||||
|
sdkAppId,
|
||||||
|
adminAccount,
|
||||||
|
userSig,
|
||||||
|
random);
|
||||||
|
|
||||||
|
// 构建消息内容
|
||||||
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
|
msgContent.put("Title", title);
|
||||||
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
|
// 构建消息体
|
||||||
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
|
// 如果有扩展字段,添加到消息内容中
|
||||||
|
if (ext != null && !ext.isEmpty()) {
|
||||||
|
msgContent.put("Ext", ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("From_Account", adminAccount);
|
||||||
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
|
|
||||||
|
// 设置离线推送信息
|
||||||
|
if (offlinePush) {
|
||||||
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
|
offlinePushInfo.put("PushFlag", 1); // 1表示推送,0表示不离线推送
|
||||||
|
offlinePushInfo.put("Title", title);
|
||||||
|
offlinePushInfo.put("Desc", desc);
|
||||||
|
offlinePushInfo.put("Ext", ext);
|
||||||
|
requestBody.put("OfflinePushInfo", offlinePushInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
log.info("全员推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
|
// 解析响应判断是否成功
|
||||||
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("全员推送消息异常", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pushByAttributes(String title, String desc, Map<String, Object> attributes, boolean offlinePush, String ext) {
|
||||||
|
try {
|
||||||
|
String userSig = generateAdminUserSig();
|
||||||
|
String random = String.valueOf(new Random().nextInt(999999999));
|
||||||
|
|
||||||
|
// 构建API请求URL - 使用属性推送接口
|
||||||
|
String url = String.format(
|
||||||
|
"https://console.tim.qq.com/v4/all_member_push/im_push_attr" +
|
||||||
|
"?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
|
||||||
|
sdkAppId,
|
||||||
|
adminAccount,
|
||||||
|
userSig,
|
||||||
|
random);
|
||||||
|
|
||||||
|
// 构建消息内容
|
||||||
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
|
msgContent.put("Title", title);
|
||||||
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
|
// 构建消息体
|
||||||
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
|
// 如果有扩展字段,添加到消息内容中
|
||||||
|
if (ext != null && !ext.isEmpty()) {
|
||||||
|
msgContent.put("Ext", ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("From_Account", adminAccount);
|
||||||
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
|
requestBody.put("AttrNames", attributes.keySet().toArray(new String[0]));
|
||||||
|
requestBody.put("AttrValues", attributes.values().toArray());
|
||||||
|
|
||||||
|
// 设置离线推送信息
|
||||||
|
if (offlinePush) {
|
||||||
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
|
offlinePushInfo.put("PushFlag", 1); // 1表示推送,0表示不离线推送
|
||||||
|
offlinePushInfo.put("Title", title);
|
||||||
|
offlinePushInfo.put("Desc", desc);
|
||||||
|
offlinePushInfo.put("Ext", ext);
|
||||||
|
requestBody.put("OfflinePushInfo", offlinePushInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
log.info("属性推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
|
// 解析响应判断是否成功
|
||||||
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("属性推送消息异常", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pushByTags(String title, String desc, List<String> tags, boolean offlinePush, String ext) {
|
||||||
|
try {
|
||||||
|
String userSig = generateAdminUserSig();
|
||||||
|
String random = String.valueOf(new Random().nextInt(999999999));
|
||||||
|
|
||||||
|
// 构建API请求URL - 使用标签推送接口
|
||||||
|
String url = String.format(
|
||||||
|
"https://console.tim.qq.com/v4/all_member_push/im_push_tags" +
|
||||||
|
"?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
|
||||||
|
sdkAppId,
|
||||||
|
adminAccount,
|
||||||
|
userSig,
|
||||||
|
random);
|
||||||
|
|
||||||
|
// 构建消息内容
|
||||||
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
|
msgContent.put("Title", title);
|
||||||
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
|
// 构建消息体
|
||||||
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
|
// 如果有扩展字段,添加到消息内容中
|
||||||
|
if (ext != null && !ext.isEmpty()) {
|
||||||
|
msgContent.put("Ext", ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("From_Account", adminAccount);
|
||||||
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
|
requestBody.put("TagList", tags);
|
||||||
|
|
||||||
|
// 设置离线推送信息
|
||||||
|
if (offlinePush) {
|
||||||
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
|
offlinePushInfo.put("PushFlag", 1); // 1表示推送,0表示不离线推送
|
||||||
|
offlinePushInfo.put("Title", title);
|
||||||
|
offlinePushInfo.put("Desc", desc);
|
||||||
|
offlinePushInfo.put("Ext", ext);
|
||||||
|
requestBody.put("OfflinePushInfo", offlinePushInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
log.info("标签推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
|
// 解析响应判断是否成功
|
||||||
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("标签推送消息异常", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pushToUsers(String title, String desc, List<String> userIds, boolean offlinePush, String ext) {
|
||||||
|
try {
|
||||||
|
String userSig = generateAdminUserSig();
|
||||||
|
String random = String.valueOf(new Random().nextInt(999999999));
|
||||||
|
|
||||||
|
// 构建API请求URL - 使用批量单发接口
|
||||||
|
String url = String.format(
|
||||||
|
"https://console.tim.qq.com/v4/openim/batchsendmsg" +
|
||||||
|
"?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json",
|
||||||
|
sdkAppId,
|
||||||
|
adminAccount,
|
||||||
|
userSig,
|
||||||
|
random);
|
||||||
|
|
||||||
|
// 构建消息内容
|
||||||
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
|
msgContent.put("Title", title);
|
||||||
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
|
// 构建消息体
|
||||||
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
|
// 如果有扩展字段,添加到消息内容中
|
||||||
|
if (ext != null && !ext.isEmpty()) {
|
||||||
|
msgContent.put("Ext", ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
|
requestBody.put("From_Account", adminAccount);
|
||||||
|
requestBody.put("To_Account", userIds);
|
||||||
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
|
|
||||||
|
// 设置离线推送信息
|
||||||
|
if (offlinePush) {
|
||||||
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
|
offlinePushInfo.put("PushFlag", 1); // 1表示推送,0表示不离线推送
|
||||||
|
offlinePushInfo.put("Title", title);
|
||||||
|
offlinePushInfo.put("Desc", desc);
|
||||||
|
offlinePushInfo.put("Ext", ext);
|
||||||
|
requestBody.put("OfflinePushInfo", offlinePushInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
log.info("指定用户推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
|
// 解析响应判断是否成功
|
||||||
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("指定用户推送消息异常", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String processMessageVariables(String content, Map<String, String> variables) {
|
||||||
|
if (content == null || variables == null || variables.isEmpty()) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = VARIABLE_PATTERN.matcher(content);
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
String variableName = matcher.group(1);
|
||||||
|
String replacement = variables.getOrDefault(variableName, "$" + variableName);
|
||||||
|
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
org.dromara.system.config.RocketMQConfiguration
|
@ -0,0 +1 @@
|
|||||||
|
org.dromara.system.config.RocketMQConfig
|
Loading…
x
Reference in New Issue
Block a user