主管理员 3 days ago
parent
commit
502e353d11
8 changed files with 222 additions and 68 deletions
  1. +5
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/Final/AppletCouponType.java
  2. +10
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java
  3. +50
    -24
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletCoupon/entity/AppletCoupon.java
  4. +8
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletCoupon/service/IAppletCouponService.java
  5. +12
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletCoupon/service/impl/AppletCouponServiceImpl.java
  6. +18
    -3
      jeecgboot-vue3/src/views/applet/coupon/AppletCoupon.data.ts
  7. +96
    -35
      jeecgboot-vue3/src/views/applet/course-page/AppletCoursePageList.vue
  8. +23
    -6
      jeecgboot-vue3/src/views/applet/course-page/components/ContentEditor.vue

+ 5
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/Final/AppletCouponType.java View File

@ -1,4 +1,9 @@
package org.jeecg.modules.applet.Final;
public class AppletCouponType {
public static final String MANUAL = "0";
public static final String NEW_USER = "1";//新用户自动领取
}

+ 10
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiLoginService.java View File

@ -11,15 +11,19 @@ import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.AppletUser;
import org.jeecg.common.api.IAppletUserService;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.applet.Final.AppletCouponType;
import org.jeecg.modules.applet.Final.LoginType;
import org.jeecg.modules.common.wxUtils.WxHttpClientUtil;
import org.jeecg.modules.common.wxUtils.WxHttpUtils;
import org.jeecg.modules.demo.appletCoupon.entity.AppletCoupon;
import org.jeecg.modules.demo.appletCoupon.service.IAppletCouponService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -42,6 +46,9 @@ public class AppletApiLoginService {
@Autowired
private RedisUtil redisUtil;
@Autowired
private IAppletCouponService appletCouponService;
private JSONObject openLogin(String code, String type){
log.info("开始小程序登录,code: {}", code);
// 调用微信API获取openid和session_key
@ -236,6 +243,9 @@ public class AppletApiLoginService {
// 保存到数据库
appletUserService.save(user);
log.info("创建小程序用户成功: {}", user.getName());
appletCouponService.distributeCouponByType(AppletCouponType.NEW_USER, user.getId());
} else {
log.info("找到已存在的小程序用户: {}", user.getName());
}


+ 50
- 24
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletCoupon/entity/AppletCoupon.java View File

@ -33,49 +33,75 @@ import lombok.experimental.Accessors;
public class AppletCoupon implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
/**
* 主键
*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private java.lang.String id;
/**创建人*/
/**
* 创建人
*/
@Schema(description = "创建人")
private java.lang.String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
/**
* 创建日期
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Schema(description = "创建日期")
private java.util.Date createTime;
/**更新人*/
/**
* 更新人
*/
@Schema(description = "更新人")
private java.lang.String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
/**
* 更新日期
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Schema(description = "更新日期")
private java.util.Date updateTime;
/**所属部门*/
/**
* 所属部门
*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**优惠券名称*/
@Excel(name = "优惠券名称", width = 15)
/**
* 优惠券名称
*/
@Excel(name = "优惠券名称", width = 15)
@Schema(description = "优惠券名称")
private java.lang.String name;
/**面额*/
@Excel(name = "面额", width = 15)
/**
* 面额
*/
@Excel(name = "面额", width = 15)
@Schema(description = "面额")
private java.math.BigDecimal money;
/**有效期*/
@Excel(name = "有效期", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
/**
* 有效期
*/
@Excel(name = "有效期", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Schema(description = "有效期")
private java.util.Date endTime;
/**发放数量*/
@Excel(name = "发放数量", width = 15)
/**
* 发放数量
*/
@Excel(name = "发放数量", width = 15)
@Schema(description = "发放数量")
private java.lang.Integer count;
/**已使用数量*/
@Excel(name = "已使用数量", width = 15)
/**
* 已使用数量
*/
@Excel(name = "已使用数量", width = 15)
@Schema(description = "已使用数量")
private java.lang.Integer quantityused;
}
@Dict(dicCode = "applet_discount_coupon_type")
private java.lang.String type;
}

+ 8
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletCoupon/service/IAppletCouponService.java View File

@ -19,6 +19,14 @@ public interface IAppletCouponService extends IService<AppletCoupon> {
*/
void distributeCoupon(String couponId, String userIds);
/**
* 优惠券根据类型批量发放
* @param type 优惠券类型
* @param userIds 用户ID列表为空表示发放给所有用户
*/
void distributeCouponByType(String type, String userIds);
/**
* 优惠券核销
* @param recordId 优惠券记录ID


+ 12
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletCoupon/service/impl/AppletCouponServiceImpl.java View File

@ -1,6 +1,7 @@
package org.jeecg.modules.demo.appletCoupon.service.impl;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.applet.Final.AppletCouponType;
import org.jeecg.modules.demo.appletCoupon.entity.AppletCoupon;
import org.jeecg.modules.demo.appletCoupon.mapper.AppletCouponMapper;
import org.jeecg.modules.demo.appletCoupon.service.IAppletCouponService;
@ -86,6 +87,17 @@ public class AppletCouponServiceImpl extends ServiceImpl<AppletCouponMapper, App
updateById(coupon);
}
@Override
public void distributeCouponByType(String type, String userIds) {
//新用户领取
List<AppletCoupon> list = lambdaQuery()
.eq(AppletCoupon::getType, type)
.list();
for (AppletCoupon coupon : list){
distributeCoupon(coupon.getId(), userIds);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public AppletCouponRecord useCoupon(String recordId, String userId) {


+ 18
- 3
jeecgboot-vue3/src/views/applet/coupon/AppletCoupon.data.ts View File

@ -15,6 +15,11 @@ export const columns: BasicColumn[] = [
align:"center",
dataIndex: 'money'
},
{
title: '优惠券类型',
align:"center",
dataIndex: 'type_dictText'
},
{
title: '有效期',
align:"center",
@ -46,6 +51,15 @@ export const formSchema: FormSchema[] = [
field: 'money',
component: 'InputNumber',
},
{
label: '优惠券类型',
field: 'type',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'applet_discount_coupon_type',
type: 'radio',
},
},
{
label: '有效期',
field: 'endTime',
@ -78,9 +92,10 @@ export const formSchema: FormSchema[] = [
export const superQuerySchema = {
name: {title: '优惠券名称',order: 0,view: 'text', type: 'string',},
money: {title: '面额',order: 1,view: 'number', type: 'number',},
endTime: {title: '有效期',order: 2,view: 'datetime', type: 'string',},
count: {title: '发放数量',order: 3,view: 'text', type: 'string',},
quantityused: {title: '已使用数量',order: 4,view: 'text', type: 'string',},
type: {title: '优惠券类型',order: 2,view: 'list', type: 'string',dictCode: 'applet_discount_coupon_type',},
endTime: {title: '有效期',order: 3,view: 'datetime', type: 'string',},
count: {title: '发放数量',order: 4,view: 'text', type: 'string',},
quantityused: {title: '已使用数量',order: 5,view: 'text', type: 'string',},
};
/**


+ 96
- 35
jeecgboot-vue3/src/views/applet/course-page/AppletCoursePageList.vue View File

@ -24,15 +24,8 @@
<!-- 上方课程页面列表横向滑动 -->
<div class="page-list-container">
<div class="page-list-scroll">
<draggable
v-model="pageList"
class="page-list"
item-key="id"
handle=".drag-handle"
:animation="200"
@start="onPageDragStart"
@end="onPageDragEnd"
>
<draggable v-model="pageList" class="page-list" item-key="id" handle=".drag-handle" :animation="200"
@start="onPageDragStart" @end="onPageDragEnd">
<template #item="{ element: page, index }">
<div :class="['page-item', { active: currentPageId === page.id }]" @click="selectPage(page)">
<!-- 拖拽手柄 -->
@ -73,7 +66,7 @@
<a-form :model="currentPage" layout="vertical" class="page-form">
<!-- 内容编辑组件 -->
<ContentEditor v-model:components="contentComponents" />
<!-- 重点单词表格组件 -->
<WordTable :course-page-id="currentPage.id" ref="wordTableRef" />
</a-form>
@ -97,11 +90,7 @@
</a-form-item>
<a-form-item label="页面类型" name="type">
<a-select v-model:value="currentPage.type" placeholder="选择类型">
<a-select-option
v-for="option in pageTypeOptions"
:key="option.value"
:value="option.value"
>
<a-select-option v-for="option in pageTypeOptions" :key="option.value" :value="option.value">
{{ option.label }}
</a-select-option>
</a-select>
@ -117,10 +106,7 @@
</div>
<!-- 右侧手机预览区域 -->
<MobilePreview
:content-components="contentComponents"
@refresh="refreshPreview"
/>
<MobilePreview :content-components="contentComponents" @refresh="refreshPreview" />
</div>
</div>
</div>
@ -241,7 +227,7 @@ async function loadPageList() {
const result = await list(params);
const records = result.records || [];
pageList.value = records;
//
if (pageList.value.length === 0) {
await handleAddPage();
@ -256,7 +242,7 @@ async function loadPageList() {
*/
function selectPage(page: any) {
currentPageId.value = page.id;
//
loadPageData(page.id);
}
@ -268,12 +254,32 @@ async function loadPageData(id: string) {
if (!id) {
return;
}
try {
const result = await getById({ id });
Object.assign(currentPage, result);
//
const originalContent = result.content;
// content
parseContentToComponents(result.content);
// style
const updatedContent = componentsToContent();
//
if (originalContent !== updatedContent) {
try {
await edit({
id: currentPage.id,
content: updatedContent
});
console.log('自动保存了组件样式初始化数据');
} catch (error) {
console.error('自动保存组件样式失败:', error);
}
}
} catch (error) {
createMessage.error('加载页面数据失败');
}
@ -289,19 +295,69 @@ function parseContentToComponents(content: string) {
try {
const parsed = JSON.parse(content);
if (Array.isArray(parsed)) {
// language
//
contentComponents.value = parsed.map(component => {
if (component.type === 'text' && !component.language) {
return { ...component, language: 'zh' }; //
const updatedComponent = { ...component };
if (component.type == 'text') {
if (!updatedComponent.language) {
updatedComponent.language = 'zh'; //
}
// style
if (!updatedComponent.style) {
updatedComponent.style = {};
}
// style40rpx
if (!updatedComponent.style.fontSize) {
updatedComponent.style.fontSize = '40rpx';
} else {
// fontSize
let fontSize = updatedComponent.style.fontSize;
if (typeof fontSize === 'string') {
// rpxrrpx, rrrpx, 40rrrrrrpx
fontSize = fontSize.replace(/r+px$/i, 'rpx');
//
const numMatch = fontSize.match(/(\d+)/);
if (numMatch) {
const num = numMatch[1];
// rpx
updatedComponent.style.fontSize = `${num}rpx`;
} else {
// 使
updatedComponent.style.fontSize = '40rpx';
}
}
}
// style#333
if (!updatedComponent.style.color) {
updatedComponent.style.color = '#333';
}
// style
if (!updatedComponent.style.fontFamily) {
updatedComponent.style.fontFamily = 'SimSun';
}
}
return component;
return updatedComponent;
});
console.log('解析后的组件列表:', contentComponents.value);
} else {
//
contentComponents.value = [{
type: 'text',
content: content,
language: 'zh' //
language: 'zh', //
style: {
fontSize: '40rpx', //
color: '#333', //
fontFamily: '宋体' //
}
}];
}
} catch (error) {
@ -309,7 +365,12 @@ function parseContentToComponents(content: string) {
contentComponents.value = [{
type: 'text',
content: content,
language: 'zh' //
language: 'zh', //
style: {
fontSize: '40rpx', //
color: '#333', //
fontFamily: '宋体' //
}
}];
}
}
@ -348,18 +409,18 @@ async function handleAddPage() {
if (result.id) {
// ID
newPage.id = result.id;
//
pageList.value.push(newPage);
//
updatePageSortOrder();
//
Object.assign(currentPage, newPage);
contentComponents.value = [];
currentPageId.value = newPage.id;
createMessage.success('新增页面成功');
} else {
createMessage.error(result.message || '新增页面失败');
@ -472,7 +533,7 @@ async function savePageOrder() {
return edit({ id: page.id, sort: page.sort });
}
}).filter(Boolean);
await Promise.all(updatePromises);
} catch (error) {
console.error('保存页面排序失败:', error);
@ -506,10 +567,10 @@ async function handleSave() {
const result = await edit(pageData);
if (result) {
// createMessage.success('');
//
await loadPageList();
//
if (currentPageId.value) {
const currentPageInList = pageList.value.find(p => p.id === currentPageId.value);


+ 23
- 6
jeecgboot-vue3/src/views/applet/course-page/components/ContentEditor.vue View File

@ -181,14 +181,23 @@ watch(
if (!c.style.fontFamily) c.style.fontFamily = 'SimSun';
if (!c.style.fontWeight) c.style.fontWeight = 'normal';
if (typeof c.isLead === 'undefined') c.isLead = false;
// px rpx rpx rpx
//
if (typeof c.style.fontSize === 'string') {
if (/px$/i.test(c.style.fontSize)) {
c.style.fontSize = c.style.fontSize.replace(/px$/i, 'rpx');
} else if (/^\d+$/.test(c.style.fontSize)) {
c.style.fontSize = `${c.style.fontSize}rpx`;
let fontSize = c.style.fontSize;
// rpxrrpx, rrrpx, 40rrrrrrpx
fontSize = fontSize.replace(/r+px$/i, 'rpx');
//
const numMatch = fontSize.match(/(\d+)/);
if (numMatch) {
const num = numMatch[1];
// rpx
c.style.fontSize = `${num}rpx`;
} else {
// 使
c.style.fontSize = '40rpx';
}
// rpx
}
}
return c;
@ -284,6 +293,14 @@ function setFontSizeNumber(component: any, value: number) {
if (isNaN(numValue) || numValue <= 0) {
component.style.fontSize = '40rpx'; //
} else {
// fontSize
let currentFontSize = component.style.fontSize;
if (typeof currentFontSize === 'string') {
// rpxrrpx, rrrpx, 40rrrrrrpx
currentFontSize = currentFontSize.replace(/r+px$/i, 'rpx');
}
// rpx
component.style.fontSize = `${numValue}rpx`;
}
emitUpdate();


Loading…
Cancel
Save