13 changed files with 336 additions and 77 deletions
@ -0,0 +1,76 @@ |
|||||||
|
package apelet.association.plugin.clueManage; |
||||||
|
|
||||||
|
import apelet.common.core.exception.MyRuntimeException; |
||||||
|
import apelet.common.core.object.ObjectCollection; |
||||||
|
import apelet.common.core.object.ObjectValue; |
||||||
|
import apelet.common.core.object.TokenData; |
||||||
|
import apelet.common.core.util.ApplicationContextHolder; |
||||||
|
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
||||||
|
import apelet.common.online.plugin.*; |
||||||
|
import apelet.common.orm.impl.Selector; |
||||||
|
import apelet.common.orm.impl.SelectorItem; |
||||||
|
import cn.hutool.core.date.DateUtil; |
||||||
|
import org.redisson.api.RBucket; |
||||||
|
import org.redisson.api.RedissonClient; |
||||||
|
|
||||||
|
import java.time.LocalDate; |
||||||
|
import java.time.LocalDateTime; |
||||||
|
import java.time.temporal.ChronoUnit; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
/** |
||||||
|
* @ClassName: ClueActivateOpPlugin |
||||||
|
* @Author: lihuangbin |
||||||
|
* @Date: 2026/5/11 |
||||||
|
* @Description: 激活放弃的线索 |
||||||
|
*/ |
||||||
|
|
||||||
|
public class ClueSaveOpPlugin extends OperationServicePlugIn { |
||||||
|
|
||||||
|
private final OrmGenDataSourceUtil ormGenDataSourceUtil; |
||||||
|
private final RedissonClient redissonClient; |
||||||
|
|
||||||
|
public ClueSaveOpPlugin() { |
||||||
|
ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class); |
||||||
|
redissonClient = ApplicationContextHolder.getBean(RedissonClient.class); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void endOperationTransaction(EndOperationTransactionArgs e) { |
||||||
|
ObjectValue objectValue = e.getModel(); |
||||||
|
String redisKey = "clue -- " + DateUtil.today(); |
||||||
|
RBucket<Map<Long, Map<Long, String>>> bucket = redissonClient.getBucket(redisKey); |
||||||
|
Map<Long, Map<Long, String>> map; |
||||||
|
// 修复:key存在则读取,不存在新建空map
|
||||||
|
if (bucket.isExists()) { |
||||||
|
map = bucket.get(); |
||||||
|
} else { |
||||||
|
map = new HashMap<>(); |
||||||
|
} |
||||||
|
Long userId = TokenData.takeFromRequest().getUserId(); |
||||||
|
Map<Long, String> userClueMap = map.get(userId); |
||||||
|
if (userClueMap == null || userClueMap.isEmpty()) { |
||||||
|
userClueMap = new HashMap<>(); |
||||||
|
} |
||||||
|
String context = "完成线索, 名称: " +objectValue.getString("name") |
||||||
|
+ ", 咨询内容: " + objectValue.getString("seek_info"); |
||||||
|
userClueMap.put(objectValue.getLong("id"), context); |
||||||
|
map.put(userId, userClueMap); |
||||||
|
|
||||||
|
bucket.set(map); |
||||||
|
|
||||||
|
// 判断:key不存在,写入同时设置过期;key已经存在,只更新value,**不修改TTL**
|
||||||
|
if (!bucket.isExists()) { |
||||||
|
// 计算到次日0点毫秒
|
||||||
|
LocalDateTime tomorrowZero = LocalDate.now().plusDays(1).atStartOfDay(); |
||||||
|
long expireMs = ChronoUnit.MILLIS.between(LocalDateTime.now(), tomorrowZero); |
||||||
|
// 原子:只有key不存在才写入并设置过期
|
||||||
|
bucket.expire(expireMs, TimeUnit.MILLISECONDS); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,82 @@ |
|||||||
|
package apelet.association.utils; |
||||||
|
|
||||||
|
import com.deepoove.poi.XWPFTemplate; |
||||||
|
import com.deepoove.poi.config.Configure; |
||||||
|
import com.deepoove.poi.data.PictureRenderData; |
||||||
|
import com.deepoove.poi.data.PictureType; |
||||||
|
import com.deepoove.poi.data.Pictures; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
public class WordDocUtil { |
||||||
|
|
||||||
|
/** |
||||||
|
* 本地模板生成docx文件,输出到本地磁盘 |
||||||
|
* |
||||||
|
* @param templateLocalPath 本地模板绝对路径 |
||||||
|
* @param outLocalPath 输出文件路径 |
||||||
|
* @param dataMap 填充数据 |
||||||
|
* @throws Exception IO异常 |
||||||
|
*/ |
||||||
|
public static void renderLocalDoc(String templateLocalPath, String outLocalPath, Map<String, Object> dataMap) throws Exception { |
||||||
|
// 自动创建输出文件夹
|
||||||
|
File outFile = new File(outLocalPath); |
||||||
|
if (!outFile.getParentFile().exists()) { |
||||||
|
outFile.getParentFile().mkdirs(); |
||||||
|
} |
||||||
|
Configure config = Configure.builder() |
||||||
|
.buildGramer("#{", "}") |
||||||
|
.build(); |
||||||
|
try (InputStream templateIn = new FileInputStream(templateLocalPath); |
||||||
|
OutputStream fileOut = new FileOutputStream(outLocalPath); |
||||||
|
XWPFTemplate template = XWPFTemplate.compile(templateIn, config).render(dataMap)) { |
||||||
|
template.write(fileOut); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* ✅【新增】模板渲染直接输出到输出流(用于浏览器下载,不生成本地临时文件) |
||||||
|
* @param templateLocalPath 模板文件路径 |
||||||
|
* @param outputStream response.getOutputStream() |
||||||
|
* @param dataMap 填充数据 |
||||||
|
* @throws Exception ex |
||||||
|
*/ |
||||||
|
public static void renderToOutputStream(String templateLocalPath, OutputStream outputStream, Map<String, Object> dataMap) throws Exception { |
||||||
|
Configure config = Configure.builder() |
||||||
|
.buildGramer("#{", "}") |
||||||
|
.build(); |
||||||
|
try (InputStream templateIn = new FileInputStream(templateLocalPath); |
||||||
|
XWPFTemplate template = XWPFTemplate.compile(templateIn, config).render(dataMap)) { |
||||||
|
template.write(outputStream); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* OSS/网络URL图片构建(签字图片专用) |
||||||
|
* |
||||||
|
* @param ossUrl OSS完整图片地址 https://xxx.oss-cn-beijing.aliyuncs.com/sign/sign001.png
|
||||||
|
* @param widthCm 图片宽度 单位cm |
||||||
|
* @param heightCm 图片高度 单位cm |
||||||
|
* @return PictureRenderData |
||||||
|
*/ |
||||||
|
public static PictureRenderData getOssPic(String ossUrl, double widthCm, double heightCm) { |
||||||
|
// poi‑tl size 参数单位是 像素,注意:不是厘米!!!
|
||||||
|
return Pictures.ofUrl(ossUrl) |
||||||
|
.size((int) widthCm, (int) heightCm) |
||||||
|
.create(); |
||||||
|
} |
||||||
|
|
||||||
|
// 本地图片(备用)
|
||||||
|
public static PictureRenderData getLocalPic(String imgLocalPath, double width, double height) { |
||||||
|
return Pictures.ofLocal(imgLocalPath).size((int) width, (int) height).create(); |
||||||
|
} |
||||||
|
|
||||||
|
// base64图片(备用)
|
||||||
|
public static PictureRenderData getBase64Pic(String base64Str, double width, double height) { |
||||||
|
return Pictures.ofBase64(base64Str, PictureType.PNG) |
||||||
|
.size((int) width, (int) height) |
||||||
|
.create(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue