diff --git a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java index a224060..c4cd8b2 100644 --- a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java +++ b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java @@ -191,6 +191,7 @@ public class AppletApiLoginService { user.setCreateTime(new Date()); user.setCreateBy("system"); user.setInviter(inviter); + user.setIsPromote("N"); // TODO: 如果需要unionid字段,需要在AppletUser实体类中添加该字段 // user.setUnionid(unionid); diff --git a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java index a41516a..6598909 100644 --- a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java @@ -84,20 +84,21 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService { // 获取必要的配置信息 String xcxSharePage = appletConfigService.getContentByCode("xcxSharePage"); String backgroundImageUrl = appletConfigService.getContentByCode("qr_code_bg"); + + // 获取二维码位置配置参数 + int qrCodeX = appletConfigService.getContentByCodeAsInt("qr_code_x"); + int qrCodeY = appletConfigService.getContentByCodeAsInt("qr_code_y"); - // 优化缓存策略:使用更精确的缓存key,包含所有影响因素(包括背景图片URL) - String cacheKey = String.format("inviteCode:final:%s:%s:%s:%s", user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode()); - String imageCacheKey = String.format("inviteCode:image:%s:%s:%s:%s", user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode()); + // 优化缓存策略:使用更精确的缓存key,包含所有影响因素(包括背景图片URL和二维码位置配置) + String cacheKey = String.format("inviteCode:final:%s:%s:%s:%s:%s:%s", + user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode(), qrCodeX, qrCodeY); - // 首先检查是否有最终合成图片的缓存 - byte[] cachedImage = (byte[]) redisUtil.get(imageCacheKey); - if (cachedImage != null) { - log.info("从缓存返回邀请码图片,用户ID: {}", user.getId()); - return cachedImage; - } + // 移除图片数据的Redis缓存,避免类型转换错误 + // 直接检查OSS中是否已存在最终图片 // 检查OSS中是否已存在最终图片 - String finalPath = "invite/final/" + user.getId() + "_" + xcxSharePage + "_" + trial + ".jpg"; + String finalPath = String.format("invite/final/%s_%s_%s_%s_%s_%s.jpg", + user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode(), qrCodeX, qrCodeY); try { InputStream ossFile = OssBootUtil.getOssFile(finalPath, null); if (ossFile != null) { @@ -112,8 +113,7 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService { buffer.flush(); byte[] ossImageBytes = buffer.toByteArray(); - // 将OSS中的图片缓存到Redis,设置24小时过期 - redisUtil.set(imageCacheKey, ossImageBytes, 24 * 60 * 60); + // 直接返回OSS中的图片,不再缓存到Redis log.info("从OSS返回邀请码图片,用户ID: {}", user.getId()); return ossImageBytes; } finally { @@ -125,26 +125,15 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService { } try { - // 检查是否有小程序码的缓存 - String qrCodeCacheKey = String.format("inviteCode:qrcode:%s:%s:%s", user.getId(), trial, xcxSharePage.hashCode()); - byte[] cachedQrCode = (byte[]) redisUtil.get(qrCodeCacheKey); - - byte[] qrCodeBytes; - if (cachedQrCode != null) { - log.info("使用缓存的小程序码,用户ID: {}", user.getId()); - qrCodeBytes = cachedQrCode; - } else { - log.info("生成新的小程序码,用户ID: {}", user.getId()); - qrCodeBytes = generateWxQrCode(user, xcxSharePage, trial); - // 缓存小程序码,设置7天过期(小程序码相对稳定) - redisUtil.set(qrCodeCacheKey, qrCodeBytes, 7 * 24 * 60 * 60); - } + // 直接生成小程序码,移除Redis缓存避免类型转换错误 + log.info("生成小程序码,用户ID: {}", user.getId()); + byte[] qrCodeBytes = generateWxQrCode(user, xcxSharePage, trial); - // 生成最终合成图片 - byte[] finalImage = this.generateAndCombineImagesFromUrl2(qrCodeBytes, backgroundImageUrl); + // 生成最终合成图片,传递已获取的配置参数避免重复调用 + byte[] finalImage = this.generateAndCombineImagesFromUrl2(qrCodeBytes, backgroundImageUrl, qrCodeX, qrCodeY); - // 异步上传到OSS并缓存 - uploadAndCacheAsync(finalImage, finalPath, imageCacheKey); + // 异步上传到OSS(移除Redis缓存) + uploadToOssAsync(finalImage, finalPath); return finalImage; } catch (Exception e) { @@ -187,10 +176,10 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService { } /** - * 异步上传到OSS并缓存到Redis + * 异步上传到OSS */ - private void uploadAndCacheAsync(byte[] imageBytes, String ossPath, String cacheKey) { - // 使用线程池异步执行上传和缓存操作 + private void uploadToOssAsync(byte[] imageBytes, String ossPath) { + // 使用线程池异步执行上传操作 CompletableFuture.runAsync(() -> { try { // 上传到OSS @@ -199,48 +188,28 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService { } catch (Exception e) { log.error("异步上传OSS失败,路径: {}", ossPath, e); } - }, asyncExecutor).thenRunAsync(() -> { - try { - // 缓存到Redis,设置24小时过期 - redisUtil.set(cacheKey, imageBytes, 24 * 60 * 60); - log.info("异步缓存完成,key: {}", cacheKey); - } catch (Exception e) { - log.error("异步缓存失败,key: {}", cacheKey, e); - } }, asyncExecutor); } - public byte[] generateAndCombineImagesFromUrl2(byte[] qrCodeImageByte, String backgroundUrl) { + public byte[] generateAndCombineImagesFromUrl2(byte[] qrCodeImageByte, String backgroundUrl, int qr_code_x, int qr_code_y) { File file = null; try { - // 缓存背景图片,避免重复下载 - String bgCacheKey = "background_image:" + backgroundUrl.hashCode(); - BufferedImage backgroundImage = (BufferedImage) redisUtil.get(bgCacheKey); - - if (backgroundImage == null) { - // 从URL加载背景图像 - URL backgroundImageUrl = new URL(backgroundUrl); - backgroundImage = ImageIO.read(backgroundImageUrl); - // 缓存背景图片,设置1小时过期 - redisUtil.set(bgCacheKey, backgroundImage, 60 * 60); - log.debug("背景图片已缓存"); - } else { - log.debug("使用缓存的背景图片"); - } + // 直接从URL加载背景图像,移除Redis缓存避免类型转换问题 + URL backgroundImageUrl = new URL(backgroundUrl); + BufferedImage backgroundImage = ImageIO.read(backgroundImageUrl); + log.debug("从URL加载背景图片: {}", backgroundUrl); // 从字节数组加载小程序码图像 BufferedImage qrCodeImage = ImageIO.read(new ByteArrayInputStream(qrCodeImageByte)); - // 获取配置参数 - int qr_code_y = appletConfigService.getContentByCodeAsInt("qr_code_y"); - int qr_code_x = appletConfigService.getContentByCodeAsInt("qr_code_x"); + // 使用传入的配置参数,避免重复调用配置服务 - // 创建一个新的BufferedImage来保存合并后的图像(复制背景图片) + // 直接使用背景图片作为基础,避免创建新的图像导致黑边 BufferedImage combinedImage = new BufferedImage( backgroundImage.getWidth(), backgroundImage.getHeight(), - BufferedImage.TYPE_INT_RGB + backgroundImage.getType() // 使用背景图片的原始类型,保持透明度 ); Graphics2D g2d = combinedImage.createGraphics(); @@ -250,8 +219,8 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService { g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - // 绘制背景图像 - g2d.drawImage(backgroundImage, 0, 0, null); + // 先绘制背景图像,完全覆盖画布 + g2d.drawImage(backgroundImage, 0, 0, backgroundImage.getWidth(), backgroundImage.getHeight(), null); int wh = backgroundImage.getWidth() / 3; @@ -259,7 +228,7 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService { int qrCodeX = (backgroundImage.getWidth() - wh) / 2; int qrCodeY = (int) ((backgroundImage.getHeight() - wh) * 0.6); - // 绘制小程序码图像 + // 绘制小程序码图像,使用传入的位置参数 g2d.drawImage(qrCodeImage, qrCodeX + qr_code_x, qrCodeY + qr_code_y, wh, wh, null); // 释放Graphics2D资源 diff --git a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/controller/AppletConfigController.java b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/controller/AppletConfigController.java index 1f1748b..d8f4362 100644 --- a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/controller/AppletConfigController.java +++ b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/controller/AppletConfigController.java @@ -29,6 +29,7 @@ import org.jeecgframework.poi.excel.entity.ImportParams; import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; import org.jeecg.common.system.base.controller.JeecgController; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; @@ -90,6 +91,7 @@ public class AppletConfigController extends JeecgController add(@RequestBody AppletConfig appletConfig) { appletConfigService.save(appletConfig); @@ -106,6 +108,7 @@ public class AppletConfigController extends JeecgController edit(@RequestBody AppletConfig appletConfig) { appletConfigService.updateById(appletConfig); return Result.OK("编辑成功!"); @@ -121,6 +124,7 @@ public class AppletConfigController extends JeecgController delete(@RequestParam(name="id",required=true) String id) { appletConfigService.removeById(id); return Result.OK("删除成功!"); @@ -136,6 +140,7 @@ public class AppletConfigController extends JeecgController deleteBatch(@RequestParam(name="ids",required=true) String ids) { this.appletConfigService.removeByIds(Arrays.asList(ids.split(","))); return Result.OK("批量删除成功!"); diff --git a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/service/impl/AppletConfigServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/service/impl/AppletConfigServiceImpl.java index 2b46fc0..31b97aa 100644 --- a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/service/impl/AppletConfigServiceImpl.java +++ b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletConfig/service/impl/AppletConfigServiceImpl.java @@ -3,6 +3,7 @@ package org.jeecg.modules.demo.appletConfig.service.impl; import org.jeecg.modules.demo.appletConfig.entity.AppletConfig; import org.jeecg.modules.demo.appletConfig.mapper.AppletConfigMapper; import org.jeecg.modules.demo.appletConfig.service.IAppletConfigService; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -19,6 +20,7 @@ import java.util.List; public class AppletConfigServiceImpl extends ServiceImpl implements IAppletConfigService { @Override + @Cacheable(value = "appletConfig", key = "#code") public String getContentByCode(String code) { AppletConfig config = lambdaQuery() .eq(AppletConfig::getCode, code) @@ -28,6 +30,7 @@ public class AppletConfigServiceImpl extends ServiceImpl - defHttp.get({url: Api.list, params}); - -/** - * 删除单个 - */ -export const deleteOne = (params,handleSuccess) => { - return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { - handleSuccess(); - }); -} -/** - * 批量删除 - * @param params - */ -export const batchDelete = (params, handleSuccess) => { - createConfirm({ - iconType: 'warning', - title: '确认删除', - content: '是否删除选中数据', - okText: '确认', - cancelText: '取消', - onOk: () => { - return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { - handleSuccess(); - }); - } - }); -} -/** - * 保存或者更新 - * @param params - */ -export const saveOrUpdate = (params, isUpdate) => { - let url = isUpdate ? Api.edit : Api.save; - return defHttp.post({url: url, params}); -} diff --git a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawal.data.ts b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawal.data.ts deleted file mode 100644 index 5025cf4..0000000 --- a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawal.data.ts +++ /dev/null @@ -1,142 +0,0 @@ -import {BasicColumn} from '/@/components/Table'; -import {FormSchema} from '/@/components/Table'; -import { rules} from '/@/utils/helper/validator'; -import { render } from '/@/utils/common/renderUtils'; -import { getWeekMonthQuarterYear } from '/@/utils'; -//列表数据 -export const columns: BasicColumn[] = [ - { - title: '用户id', - align:"center", - dataIndex: 'userId_dictText' - }, - { - title: '申请人', - align:"center", - dataIndex: 'name' - }, - { - title: '提现金额', - align:"center", - dataIndex: 'money' - }, - { - title: '提现方式', - align:"center", - dataIndex: 'method_dictText' - }, - { - title: '凭证上传', - align:"center", - dataIndex: 'upload', - customRender:({text}) => { - return render.renderSwitch(text, [{text:'是',value:'Y'},{text:'否',value:'N'}]) - }, - }, - { - title: '审核状态', - align:"center", - dataIndex: 'status_dictText' - }, - { - title: '提现状态', - align:"center", - dataIndex: 'withdrawStatus_dictText' - }, - { - title: '流水号', - align:"center", - dataIndex: 'waterId_dictText' - }, -]; -//查询数据 -export const searchFormSchema: FormSchema[] = [ -]; -//表单数据 -export const formSchema: FormSchema[] = [ - { - label: '用户id', - field: 'userId', - component: 'JSearchSelect', - componentProps:{ - dict:"applet_user,name,id" - }, - }, - { - label: '申请人', - field: 'name', - component: 'Input', - }, - { - label: '提现金额', - field: 'money', - component: 'InputNumber', - }, - { - label: '提现方式', - field: 'method', - component: 'JDictSelectTag', - componentProps:{ - dictCode:"applett_translate_type" - }, - }, - { - label: '凭证上传', - field: 'upload', - component: 'JSwitch', - componentProps:{ - }, - }, - { - label: '审核状态', - field: 'status', - component: 'JDictSelectTag', - componentProps:{ - dictCode:"applett_money_type" - }, - }, - { - label: '提现状态', - field: 'withdrawStatus', - component: 'JDictSelectTag', - componentProps:{ - dictCode:"applet_withdraw_type" - }, - }, - { - label: '流水号', - field: 'waterId', - component: 'JSearchSelect', - componentProps:{ - dict:"applet_water,number,id" - }, - }, - // TODO 主键隐藏字段,目前写死为ID - { - label: '', - field: 'id', - component: 'Input', - show: false - }, -]; - -// 高级查询数据 -export const superQuerySchema = { - userId: {title: '用户id',order: 0,view: 'sel_search', type: 'string',dictTable: "applet_user", dictCode: 'id', dictText: 'name',}, - name: {title: '申请人',order: 1,view: 'text', type: 'string',}, - money: {title: '提现金额',order: 2,view: 'number', type: 'number',}, - method: {title: '提现方式',order: 3,view: 'list', type: 'string',dictCode: 'applett_translate_type',}, - upload: {title: '凭证上传',order: 4,view: 'switch', type: 'string',}, - status: {title: '审核状态',order: 5,view: 'list', type: 'string',dictCode: 'applett_money_type',}, - withdrawStatus: {title: '提现状态',order: 6,view: 'list', type: 'string',dictCode: 'applet_withdraw_type',}, - waterId: {title: '流水号',order: 7,view: 'sel_search', type: 'string',dictTable: "applet_water", dictCode: 'id', dictText: 'number',}, -}; - -/** -* 流程表单调用这个方法获取formSchema -* @param param -*/ -export function getBpmFormSchema(_formData): FormSchema[]{ - // 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema - return formSchema; -} \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawalList.vue b/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawalList.vue deleted file mode 100644 index 2d0e503..0000000 --- a/jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawalList.vue +++ /dev/null @@ -1,206 +0,0 @@ - - - - - \ No newline at end of file diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/java/org/jeecg/JeecgSystemApplication.java b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/java/org/jeecg/JeecgSystemApplication.java index 64c6c2c..4a973a5 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/java/org/jeecg/JeecgSystemApplication.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/java/org/jeecg/JeecgSystemApplication.java @@ -6,6 +6,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.Environment; @@ -19,6 +20,7 @@ import java.util.Map; */ @Slf4j @SpringBootApplication +@EnableCaching public class JeecgSystemApplication extends SpringBootServletInitializer { @Override diff --git a/jeecgboot-vue3/src/views/applet/course-page/components/WordTable.vue b/jeecgboot-vue3/src/views/applet/course-page/components/WordTable.vue index a1456ea..171b1ed 100644 --- a/jeecgboot-vue3/src/views/applet/course-page/components/WordTable.vue +++ b/jeecgboot-vue3/src/views/applet/course-page/components/WordTable.vue @@ -120,7 +120,7 @@