From eac1102eb1060878263796b0d2237700eee65d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 13 Aug 2025 00:31:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(generator):=20=E4=BC=98=E5=8C=96=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91=E5=B9=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 改进 index.tsx 模板,增加智能字段检测和条件性功能生成 - 修复字段注释为空时模板渲染失败的问题 - 添加自动更新 app.config.ts 页面路径的功能 - 新增 ShopArticle相关的实体、Mapper、Service 等代码 - 优化 add.tsx 和 add.config.ts模板,提高用户体验 --- docs/INDEX_TSX_IMPROVEMENTS.md | 108 +++++++++ docs/MOBILE_GENERATOR_SUMMARY.md | 8 +- docs/TEMPLATE_FIXES.md | 91 ++++++++ docs/update_app_config.sh | 82 +++++++ .../controller/ShopArticleController.java | 120 ++++++++++ .../gxwebsoft/shop/entity/ShopArticle.java | 192 ++++++++++++++++ .../shop/mapper/ShopArticleMapper.java | 37 ++++ .../shop/mapper/xml/ShopArticleMapper.xml | 192 ++++++++++++++++ .../shop/param/ShopArticleParam.java | 207 ++++++++++++++++++ .../shop/service/ShopArticleService.java | 42 ++++ .../service/impl/ShopArticleServiceImpl.java | 47 ++++ .../com/gxwebsoft/generator/CmsGenerator.java | 88 +++++++- .../gxwebsoft/generator/ShopGenerator.java | 87 ++++++++ .../generator/templates/add.config.ts.btl | 2 +- .../gxwebsoft/generator/templates/add.tsx.btl | 12 +- .../generator/templates/controller.java.btl | 8 + .../generator/templates/index.config.ts.btl | 2 +- .../generator/templates/index.tsx.btl | 52 ++++- 18 files changed, 1356 insertions(+), 21 deletions(-) create mode 100644 docs/INDEX_TSX_IMPROVEMENTS.md create mode 100644 docs/TEMPLATE_FIXES.md create mode 100755 docs/update_app_config.sh create mode 100644 src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java create mode 100644 src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java create mode 100644 src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java create mode 100644 src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml create mode 100644 src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java create mode 100644 src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java create mode 100644 src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java diff --git a/docs/INDEX_TSX_IMPROVEMENTS.md b/docs/INDEX_TSX_IMPROVEMENTS.md new file mode 100644 index 0000000..ebafb79 --- /dev/null +++ b/docs/INDEX_TSX_IMPROVEMENTS.md @@ -0,0 +1,108 @@ +# index.tsx 模板改进说明 + +## 🔍 发现的问题 + +### 1. 硬编码字段名 +**问题**:原模板假设所有表都有 `name` 和 `description` 字段 +```typescript +// 原来的硬编码方式 +{item.name} +{item.description} +``` + +### 2. 固定的业务逻辑 +**问题**:所有表都生成"默认选项"功能,即使表中没有 `isDefault` 字段 + +### 3. 不够灵活的显示方式 +**问题**:没有根据实际表结构动态调整显示内容 + +## ✅ 改进内容 + +### 1. 智能字段检测 +```typescript +<% var hasIsDefaultField = false; %> +<% for(field in table.fields){ %> +<% if(field.propertyName == 'isDefault'){ %> +<% hasIsDefaultField = true; %> +<% } %> +<% } %> +``` + +### 2. 条件性功能生成 +- **有 `isDefault` 字段**:生成完整的默认选项功能 +- **无 `isDefault` 字段**:只生成基本的列表和编辑功能 + +### 3. 动态字段显示 +```typescript +<% var displayFields = []; %> +<% for(field in table.fields){ %> +<% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime' && field.propertyName != 'isDefault'){ %> +<% displayFields.add(field); %> +<% } %> +<% } %> +``` + +自动选择前两个可显示字段作为主要显示内容。 + +## 🎯 改进效果 + +### 有 `isDefault` 字段的表(如地址、支付方式) +- ✅ 生成默认选项设置功能 +- ✅ 支持点击选择默认项 +- ✅ 显示默认选项状态图标 + +### 无 `isDefault` 字段的表(如商品、分类) +- ✅ 只生成基本的列表显示 +- ✅ 支持编辑和删除操作 +- ✅ 不生成不必要的默认选项功能 + +### 字段显示逻辑 +- **第一个字段**:作为主标题显示(较大字体) +- **第二个字段**:作为副标题显示(较小字体) +- **自动过滤**:排除 `id`、`createTime`、`updateTime`、`isDefault` 等系统字段 + +## 📋 生成示例 + +### 地址表(有 isDefault 字段) +```typescript +// 会生成完整的默认地址功能 +const selectItem = async (item: ShopUserAddress) => { + // 设置默认地址逻辑 +} + +// 显示默认选项图标 +{item.isDefault ? : } +``` + +### 商品表(无 isDefault 字段) +```typescript +// 只生成基本列表功能,无默认选项相关代码 + + {item.name} // 第一个字段 + {item.description} // 第二个字段 + +``` + +## 🔧 技术实现 + +### Beetl 模板语法 +- `<% var hasIsDefaultField = false; %>` - 定义变量 +- `<% displayFields.add(field); %>` - 数组操作 +- `<% if(hasIsDefaultField){ %>` - 条件判断 +- `${displayFields[0].propertyName}` - 动态字段访问 + +### 字段过滤规则 +排除以下系统字段: +- `id` - 主键 +- `createTime` - 创建时间 +- `updateTime` - 更新时间 +- `isDefault` - 默认标志(单独处理) + +## 🎉 优势 + +1. **更加通用**:适用于各种不同结构的表 +2. **智能适配**:根据表结构自动调整功能 +3. **减少冗余**:不生成不必要的代码 +4. **更好维护**:生成的代码更符合实际业务需求 + +现在生成的移动端列表页面更加智能和实用了! diff --git a/docs/MOBILE_GENERATOR_SUMMARY.md b/docs/MOBILE_GENERATOR_SUMMARY.md index 05671eb..6b73a01 100644 --- a/docs/MOBILE_GENERATOR_SUMMARY.md +++ b/docs/MOBILE_GENERATOR_SUMMARY.md @@ -62,10 +62,16 @@ private static final String[] TABLE_NAMES = new String[]{ # 运行商城模块生成器 java com.gxwebsoft.generator.ShopGenerator -# 运行CMS模块生成器 +# 运行CMS模块生成器 java com.gxwebsoft.generator.CmsGenerator ``` +**🎉 新功能:自动更新 app.config.ts** +- 生成器现在会自动更新 `app.config.ts` 文件 +- 自动添加新生成页面的路径配置 +- 自动备份原文件,避免数据丢失 +- 避免重复添加已存在的页面路径 + ### 3. 检查生成结果 生成的文件位于: ``` diff --git a/docs/TEMPLATE_FIXES.md b/docs/TEMPLATE_FIXES.md new file mode 100644 index 0000000..f936b0b --- /dev/null +++ b/docs/TEMPLATE_FIXES.md @@ -0,0 +1,91 @@ +# 模板修复说明 + +## 🔧 修复的问题 + +### 1. 字段注释为空的问题 + +**问题描述**: +- 当数据库表的字段没有注释时,模板渲染会失败 +- 错误信息:`field.comment为空` + +**修复内容**: + +#### add.tsx.btl 模板 +- **修复前**:`${field.comment!}` - 注释为空时显示空字符串 +- **修复后**:`${field.comment!'字段'}` - 注释为空时显示默认值 + +具体修改: +```typescript +// 标签显示 +label="${field.comment!field.propertyName}" + +// 输入框提示 +placeholder="请输入${field.comment!'字段'}" +placeholder="请输入${field.comment!'内容'}" + +// 条件判断 +<% if(field.propertyType == 'String' && field.comment?? && (field.comment?contains('描述') || field.comment?contains('备注') || field.comment?contains('内容'))){ %> +``` + +#### 配置文件模板 +- **index.config.ts.btl**:`'${table.comment!'数据'}管理'` +- **add.config.ts.btl**:`'新增${table.comment!'数据'}'` + +### 2. 智能 userId 字段检测 + +**问题描述**: +- 所有表都生成设置 userId 的代码,即使表中没有 user_id 字段 + +**修复内容**: + +#### controller.java.btl 模板 +添加了字段检测逻辑: +```java +<% var hasUserIdField = false; %> +<% for(field in table.fields){ %> +<% if(field.propertyName == 'userId'){ %> +<% hasUserIdField = true; %> +<% } %> +<% } %> +<% if(hasUserIdField){ %> +// 记录当前登录用户id +User loginUser = getLoginUser(); +if (loginUser != null) { + ${table.entityPath}.setUserId(loginUser.getUserId()); +} +<% } %> +``` + +## ✅ 修复效果 + +### 1. 空注释处理 +- **有注释的字段**:正常显示字段注释 +- **无注释的字段**:显示字段名或默认提示文本 +- **空表注释**:显示"数据"作为默认值 + +### 2. 智能 userId 处理 +- **有 user_id 字段的表**:生成完整的用户ID设置代码 +- **无 user_id 字段的表**:不生成用户ID相关代码 + +## 🎯 Beetl 模板语法说明 + +### 空值处理 +- `${field.comment!}` - 为空时显示空字符串 +- `${field.comment!'默认值'}` - 为空时显示默认值 +- `${field.comment!field.propertyName}` - 为空时显示字段名 + +### 条件判断 +- `field.comment??` - 检查字段是否不为null +- `field.comment?contains('文本')` - 检查字段是否包含指定文本 + +### 变量定义 +- `<% var hasUserIdField = false; %>` - 定义布尔变量 +- `<% if(hasUserIdField){ %>` - 条件判断 + +## 🚀 使用建议 + +1. **数据库设计**:建议为表和字段添加有意义的注释 +2. **模板测试**:生成代码前先测试模板在各种数据情况下的表现 +3. **错误处理**:模板中添加适当的默认值和空值处理 + +现在模板更加健壮,能够处理各种边界情况! diff --git a/docs/update_app_config.sh b/docs/update_app_config.sh new file mode 100755 index 0000000..edf5420 --- /dev/null +++ b/docs/update_app_config.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +# 自动更新 app.config.ts 页面路径的脚本 + +APP_CONFIG_PATH="/Users/gxwebsoft/VUE/template-10550/src/app.config.ts" +SRC_PATH="/Users/gxwebsoft/VUE/template-10550/src" + +echo "=== 自动更新 app.config.ts 页面路径 ===" +echo "" + +# 检查 app.config.ts 是否存在 +if [ ! -f "$APP_CONFIG_PATH" ]; then + echo "❌ app.config.ts 文件不存在: $APP_CONFIG_PATH" + exit 1 +fi + +echo "✅ 找到 app.config.ts 文件" + +# 备份原文件 +cp "$APP_CONFIG_PATH" "$APP_CONFIG_PATH.backup.$(date +%Y%m%d_%H%M%S)" +echo "✅ 已备份原文件" + +# 查找所有生成的页面路径配置文件 +echo "" +echo "🔍 查找生成的页面路径配置:" + +# 查找 shop 模块的页面 +SHOP_PAGES="" +if [ -d "$SRC_PATH/shop" ]; then + for dir in "$SRC_PATH/shop"/*; do + if [ -d "$dir" ] && [ -f "$dir/index.tsx" ] && [ -f "$dir/add.tsx" ]; then + page_name=$(basename "$dir") + echo " 找到 shop 页面: $page_name" + SHOP_PAGES="$SHOP_PAGES '$page_name/index',\n '$page_name/add',\n" + fi + done +fi + +# 查找 cms 模块的页面 +CMS_PAGES="" +if [ -d "$SRC_PATH/cms" ]; then + for dir in "$SRC_PATH/cms"/*; do + if [ -d "$dir" ] && [ -f "$dir/index.tsx" ] && [ -f "$dir/add.tsx" ]; then + page_name=$(basename "$dir") + echo " 找到 cms 页面: $page_name" + CMS_PAGES="$CMS_PAGES '$page_name/index',\n '$page_name/add',\n" + fi + done +fi + +echo "" +echo "📝 需要添加到 app.config.ts 的页面路径:" +echo "" + +if [ -n "$SHOP_PAGES" ]; then + echo "Shop 模块页面:" + echo -e "$SHOP_PAGES" +fi + +if [ -n "$CMS_PAGES" ]; then + echo "CMS 模块页面:" + echo -e "$CMS_PAGES" +fi + +echo "" +echo "⚠️ 请手动将上述页面路径添加到 app.config.ts 的对应子包中" +echo "" +echo "示例:" +echo "在 shop 子包的 pages 数组中添加:" +if [ -n "$SHOP_PAGES" ]; then + echo -e "$SHOP_PAGES" +fi + +echo "" +echo "在 cms 子包的 pages 数组中添加:" +if [ -n "$CMS_PAGES" ]; then + echo -e "$CMS_PAGES" +fi + +echo "" +echo "=== 完成 ===" +echo "备份文件位置: $APP_CONFIG_PATH.backup.*" diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java new file mode 100644 index 0000000..7e48084 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java @@ -0,0 +1,120 @@ +package com.gxwebsoft.shop.controller; + +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.shop.service.ShopArticleService; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.annotation.OperationLog; +import com.gxwebsoft.common.system.entity.User; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品文章控制器 + * + * @author 科技小王子 + * @since 2025-08-13 00:28:23 + */ +@Tag(name = "商品文章管理") +@RestController +@RequestMapping("/api/shop/shop-article") +public class ShopArticleController extends BaseController { + @Resource + private ShopArticleService shopArticleService; + + @Operation(summary = "分页查询商品文章") + @GetMapping("/page") + public ApiResult> page(ShopArticleParam param) { + // 使用关联查询 + return success(shopArticleService.pageRel(param)); + } + + @Operation(summary = "查询全部商品文章") + @GetMapping() + public ApiResult> list(ShopArticleParam param) { + // 使用关联查询 + return success(shopArticleService.listRel(param)); + } + + @Operation(summary = "根据id查询商品文章") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + // 使用关联查询 + return success(shopArticleService.getByIdRel(id)); + } + + @OperationLog + @Operation(summary = "添加商品文章") + @PostMapping() + public ApiResult save(@RequestBody ShopArticle shopArticle) { + // 记录当前登录用户id + User loginUser = getLoginUser(); + if (loginUser != null) { + shopArticle.setUserId(loginUser.getUserId()); + } + if (shopArticleService.save(shopArticle)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @OperationLog + @Operation(summary = "修改商品文章") + @PutMapping() + public ApiResult update(@RequestBody ShopArticle shopArticle) { + if (shopArticleService.updateById(shopArticle)) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @OperationLog + @Operation(summary = "删除商品文章") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (shopArticleService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @OperationLog + @Operation(summary = "批量添加商品文章") + @PostMapping("/batch") + public ApiResult saveBatch(@RequestBody List list) { + if (shopArticleService.saveBatch(list)) { + return success("添加成功"); + } + return fail("添加失败"); + } + + @OperationLog + @Operation(summary = "批量修改商品文章") + @PutMapping("/batch") + public ApiResult removeBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(shopArticleService, "article_id")) { + return success("修改成功"); + } + return fail("修改失败"); + } + + @OperationLog + @Operation(summary = "批量删除商品文章") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (shopArticleService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + +} diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java b/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java new file mode 100644 index 0000000..87aecee --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java @@ -0,0 +1,192 @@ +package com.gxwebsoft.shop.entity; + +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品文章 + * + * @author 科技小王子 + * @since 2025-08-13 00:28:23 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "ShopArticle对象", description = "商品文章") +public class ShopArticle implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章ID") + @TableId(value = "article_id", type = IdType.AUTO) + private Integer articleId; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章类型 0常规 1视频") + private Integer type; + + @Schema(description = "模型") + private String model; + + @Schema(description = "详情页模板") + private String detail; + + @Schema(description = "文章分类ID") + private Integer categoryId; + + @Schema(description = "上级id, 0是顶级") + private Integer parentId; + + @Schema(description = "话题") + private String topic; + + @Schema(description = "标签") + private String tags; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "封面图宽") + private Integer imageWidth; + + @Schema(description = "封面图高") + private Integer imageHeight; + + @Schema(description = "付费金额") + private BigDecimal price; + + @Schema(description = "开始时间") + private LocalDateTime startTime; + + @Schema(description = "结束时间") + private LocalDateTime endTime; + + @Schema(description = "来源") + private String source; + + @Schema(description = "产品概述") + private String overview; + + @Schema(description = "虚拟阅读量(仅用作展示)") + private Integer virtualViews; + + @Schema(description = "实际阅读量") + private Integer actualViews; + + @Schema(description = "评分") + private BigDecimal rate; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + private Integer showType; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + private Integer permission; + + @Schema(description = "发布来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "文章附件") + private String files; + + @Schema(description = "视频地址") + private String video; + + @Schema(description = "接受的文件类型") + private String accept; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "点赞数") + private Integer likes; + + @Schema(description = "评论数") + private Integer commentNumbers; + + @Schema(description = "提醒谁看") + private String toUsers; + + @Schema(description = "作者") + private String author; + + @Schema(description = "推荐") + private Integer recommend; + + @Schema(description = "报名人数") + private Integer bmUsers; + + @Schema(description = "用户ID") + private Integer userId; + + @Schema(description = "商户ID") + private Integer merchantId; + + @Schema(description = "项目ID") + private Integer projectId; + + @Schema(description = "语言") + private String lang; + + @Schema(description = "关联默认语言的文章ID") + private Integer langArticleId; + + @Schema(description = "是否自动翻译") + private Boolean translation; + + @Schema(description = "编辑器类型 0 Markdown编辑器 1 富文本编辑器 ") + private Boolean editor; + + @Schema(description = "pdf文件地址") + private String pdfUrl; + + @Schema(description = "版本号") + private Integer version; + + @Schema(description = "排序(数字越小越靠前)") + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户id") + private Integer tenantId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java b/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java new file mode 100644 index 0000000..b470484 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java @@ -0,0 +1,37 @@ +package com.gxwebsoft.shop.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品文章Mapper + * + * @author 科技小王子 + * @since 2025-08-13 00:28:23 + */ +public interface ShopArticleMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") ShopArticleParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") ShopArticleParam param); + +} diff --git a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml new file mode 100644 index 0000000..7e86018 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml @@ -0,0 +1,192 @@ + + + + + + + SELECT a.* + FROM shop_article a + + + AND a.article_id = #{param.articleId} + + + AND a.title LIKE CONCAT('%', #{param.title}, '%') + + + AND a.type = #{param.type} + + + AND a.model LIKE CONCAT('%', #{param.model}, '%') + + + AND a.detail LIKE CONCAT('%', #{param.detail}, '%') + + + AND a.category_id = #{param.categoryId} + + + AND a.parent_id = #{param.parentId} + + + AND a.topic LIKE CONCAT('%', #{param.topic}, '%') + + + AND a.tags LIKE CONCAT('%', #{param.tags}, '%') + + + AND a.image LIKE CONCAT('%', #{param.image}, '%') + + + AND a.image_width = #{param.imageWidth} + + + AND a.image_height = #{param.imageHeight} + + + AND a.price = #{param.price} + + + AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%') + + + AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%') + + + AND a.source LIKE CONCAT('%', #{param.source}, '%') + + + AND a.overview LIKE CONCAT('%', #{param.overview}, '%') + + + AND a.virtual_views = #{param.virtualViews} + + + AND a.actual_views = #{param.actualViews} + + + AND a.rate = #{param.rate} + + + AND a.show_type = #{param.showType} + + + AND a.password LIKE CONCAT('%', #{param.password}, '%') + + + AND a.permission = #{param.permission} + + + AND a.platform LIKE CONCAT('%', #{param.platform}, '%') + + + AND a.files LIKE CONCAT('%', #{param.files}, '%') + + + AND a.video LIKE CONCAT('%', #{param.video}, '%') + + + AND a.accept LIKE CONCAT('%', #{param.accept}, '%') + + + AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%') + + + AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%') + + + AND a.province LIKE CONCAT('%', #{param.province}, '%') + + + AND a.city LIKE CONCAT('%', #{param.city}, '%') + + + AND a.region LIKE CONCAT('%', #{param.region}, '%') + + + AND a.address LIKE CONCAT('%', #{param.address}, '%') + + + AND a.likes = #{param.likes} + + + AND a.comment_numbers = #{param.commentNumbers} + + + AND a.to_users LIKE CONCAT('%', #{param.toUsers}, '%') + + + AND a.author LIKE CONCAT('%', #{param.author}, '%') + + + AND a.recommend = #{param.recommend} + + + AND a.bm_users = #{param.bmUsers} + + + AND a.user_id = #{param.userId} + + + AND a.merchant_id = #{param.merchantId} + + + AND a.project_id = #{param.projectId} + + + AND a.lang LIKE CONCAT('%', #{param.lang}, '%') + + + AND a.lang_article_id = #{param.langArticleId} + + + AND a.translation = #{param.translation} + + + AND a.editor = #{param.editor} + + + AND a.pdf_url LIKE CONCAT('%', #{param.pdfUrl}, '%') + + + AND a.version = #{param.version} + + + AND a.sort_number = #{param.sortNumber} + + + AND a.comments LIKE CONCAT('%', #{param.comments}, '%') + + + AND a.status = #{param.status} + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java b/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java new file mode 100644 index 0000000..0d29075 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java @@ -0,0 +1,207 @@ +package com.gxwebsoft.shop.param; + +import java.math.BigDecimal; +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品文章查询参数 + * + * @author 科技小王子 + * @since 2025-08-13 00:28:23 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "ShopArticleParam对象", description = "商品文章查询参数") +public class ShopArticleParam extends BaseParam { + private static final long serialVersionUID = 1L; + + @Schema(description = "文章ID") + @QueryField(type = QueryType.EQ) + private Integer articleId; + + @Schema(description = "文章标题") + private String title; + + @Schema(description = "文章类型 0常规 1视频") + @QueryField(type = QueryType.EQ) + private Integer type; + + @Schema(description = "模型") + private String model; + + @Schema(description = "详情页模板") + private String detail; + + @Schema(description = "文章分类ID") + @QueryField(type = QueryType.EQ) + private Integer categoryId; + + @Schema(description = "上级id, 0是顶级") + @QueryField(type = QueryType.EQ) + private Integer parentId; + + @Schema(description = "话题") + private String topic; + + @Schema(description = "标签") + private String tags; + + @Schema(description = "封面图") + private String image; + + @Schema(description = "封面图宽") + @QueryField(type = QueryType.EQ) + private Integer imageWidth; + + @Schema(description = "封面图高") + @QueryField(type = QueryType.EQ) + private Integer imageHeight; + + @Schema(description = "付费金额") + @QueryField(type = QueryType.EQ) + private BigDecimal price; + + @Schema(description = "开始时间") + private String startTime; + + @Schema(description = "结束时间") + private String endTime; + + @Schema(description = "来源") + private String source; + + @Schema(description = "产品概述") + private String overview; + + @Schema(description = "虚拟阅读量(仅用作展示)") + @QueryField(type = QueryType.EQ) + private Integer virtualViews; + + @Schema(description = "实际阅读量") + @QueryField(type = QueryType.EQ) + private Integer actualViews; + + @Schema(description = "评分") + @QueryField(type = QueryType.EQ) + private BigDecimal rate; + + @Schema(description = "列表显示方式(10小图展示 20大图展示)") + @QueryField(type = QueryType.EQ) + private Integer showType; + + @Schema(description = "访问密码") + private String password; + + @Schema(description = "可见类型 0所有人 1登录可见 2密码可见") + @QueryField(type = QueryType.EQ) + private Integer permission; + + @Schema(description = "发布来源客户端 (APP、H5、小程序等)") + private String platform; + + @Schema(description = "文章附件") + private String files; + + @Schema(description = "视频地址") + private String video; + + @Schema(description = "接受的文件类型") + private String accept; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "所在省份") + private String province; + + @Schema(description = "所在城市") + private String city; + + @Schema(description = "所在辖区") + private String region; + + @Schema(description = "街道地址") + private String address; + + @Schema(description = "点赞数") + @QueryField(type = QueryType.EQ) + private Integer likes; + + @Schema(description = "评论数") + @QueryField(type = QueryType.EQ) + private Integer commentNumbers; + + @Schema(description = "提醒谁看") + private String toUsers; + + @Schema(description = "作者") + private String author; + + @Schema(description = "推荐") + @QueryField(type = QueryType.EQ) + private Integer recommend; + + @Schema(description = "报名人数") + @QueryField(type = QueryType.EQ) + private Integer bmUsers; + + @Schema(description = "用户ID") + @QueryField(type = QueryType.EQ) + private Integer userId; + + @Schema(description = "商户ID") + @QueryField(type = QueryType.EQ) + private Long merchantId; + + @Schema(description = "项目ID") + @QueryField(type = QueryType.EQ) + private Integer projectId; + + @Schema(description = "语言") + private String lang; + + @Schema(description = "关联默认语言的文章ID") + @QueryField(type = QueryType.EQ) + private Integer langArticleId; + + @Schema(description = "是否自动翻译") + @QueryField(type = QueryType.EQ) + private Boolean translation; + + @Schema(description = "编辑器类型 0 Markdown编辑器 1 富文本编辑器 ") + @QueryField(type = QueryType.EQ) + private Boolean editor; + + @Schema(description = "pdf文件地址") + private String pdfUrl; + + @Schema(description = "版本号") + @QueryField(type = QueryType.EQ) + private Integer version; + + @Schema(description = "排序(数字越小越靠前)") + @QueryField(type = QueryType.EQ) + private Integer sortNumber; + + @Schema(description = "备注") + private String comments; + + @Schema(description = "状态, 0已发布, 1待审核 2已驳回 3违规内容") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; + +} diff --git a/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java b/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java new file mode 100644 index 0000000..9396377 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.shop.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; + +import java.util.List; + +/** + * 商品文章Service + * + * @author 科技小王子 + * @since 2025-08-13 00:28:23 + */ +public interface ShopArticleService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(ShopArticleParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(ShopArticleParam param); + + /** + * 根据id查询 + * + * @param articleId 文章ID + * @return ShopArticle + */ + ShopArticle getByIdRel(Integer articleId); + +} diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java new file mode 100644 index 0000000..448d414 --- /dev/null +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java @@ -0,0 +1,47 @@ +package com.gxwebsoft.shop.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopArticleMapper; +import com.gxwebsoft.shop.service.ShopArticleService; +import com.gxwebsoft.shop.entity.ShopArticle; +import com.gxwebsoft.shop.param.ShopArticleParam; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 商品文章Service实现 + * + * @author 科技小王子 + * @since 2025-08-13 00:28:23 + */ +@Service +public class ShopArticleServiceImpl extends ServiceImpl implements ShopArticleService { + + @Override + public PageResult pageRel(ShopArticleParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("sort_number asc, create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(ShopArticleParam param) { + List list = baseMapper.selectListRel(param); + // 排序 + PageParam page = new PageParam<>(); + page.setDefaultOrder("sort_number asc, create_time desc"); + return page.sortRecords(list); + } + + @Override + public ShopArticle getByIdRel(Integer articleId) { + ShopArticleParam param = new ShopArticleParam(); + param.setArticleId(articleId); + return param.getOne(baseMapper.selectListRel(param)); + } + +} diff --git a/src/test/java/com/gxwebsoft/generator/CmsGenerator.java b/src/test/java/com/gxwebsoft/generator/CmsGenerator.java index 13e2537..0759a23 100644 --- a/src/test/java/com/gxwebsoft/generator/CmsGenerator.java +++ b/src/test/java/com/gxwebsoft/generator/CmsGenerator.java @@ -13,6 +13,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.regex.Pattern; +import java.util.regex.Matcher; /** * CMS模块-代码生成工具 @@ -56,7 +61,7 @@ public class CmsGenerator { // "cms_docs_book", // "cms_docs_content", // "cms_ad", - "cms_ad_record", +// "cms_ad_record", // "cms_navigation", // "cms_design", // "cms_design_record", @@ -315,6 +320,87 @@ public class CmsGenerator { mpg.setCfg(cfg); mpg.execute(); + + // 自动更新 app.config.ts + updateAppConfig(TABLE_NAMES, MODULE_NAME); + } + + /** + * 自动更新 app.config.ts 文件,添加新生成的页面路径 + */ + private static void updateAppConfig(String[] tableNames, String moduleName) { + String appConfigPath = OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + "/app.config.ts"; + + try { + // 读取原文件内容 + String content = new String(Files.readAllBytes(Paths.get(appConfigPath))); + + // 为每个表生成页面路径 + StringBuilder newPages = new StringBuilder(); + for (String tableName : tableNames) { + String entityPath = tableName.replaceAll("_", ""); + // 转换为驼峰命名 + String[] parts = tableName.split("_"); + StringBuilder camelCase = new StringBuilder(parts[0]); + for (int i = 1; i < parts.length; i++) { + camelCase.append(parts[i].substring(0, 1).toUpperCase()).append(parts[i].substring(1)); + } + entityPath = camelCase.toString(); + + newPages.append(" '").append(entityPath).append("/index',\n"); + newPages.append(" '").append(entityPath).append("/add',\n"); + } + + // 查找对应模块的子包配置 + String modulePattern = "\"root\":\\s*\"" + moduleName + "\",\\s*\"pages\":\\s*\\[([^\\]]*)]"; + Pattern pattern = Pattern.compile(modulePattern, Pattern.DOTALL); + Matcher matcher = pattern.matcher(content); + + if (matcher.find()) { + String existingPages = matcher.group(1); + + // 检查页面是否已存在,避免重复添加 + boolean needUpdate = false; + String[] newPageArray = newPages.toString().split("\n"); + for (String newPage : newPageArray) { + if (!newPage.trim().isEmpty() && !existingPages.contains(newPage.trim().replace(" ", "").replace(",", ""))) { + needUpdate = true; + break; + } + } + + if (needUpdate) { + // 备份原文件 + String backupPath = appConfigPath + ".backup." + System.currentTimeMillis(); + Files.copy(Paths.get(appConfigPath), Paths.get(backupPath)); + System.out.println("已备份原文件到: " + backupPath); + + // 在现有页面列表末尾添加新页面 + String updatedPages = existingPages.trim(); + if (!updatedPages.endsWith(",")) { + updatedPages += ","; + } + updatedPages += "\n" + newPages.toString().trim(); + + // 替换内容 + String updatedContent = content.replace(matcher.group(1), updatedPages); + + // 写入更新后的内容 + Files.write(Paths.get(appConfigPath), updatedContent.getBytes()); + + System.out.println("✅ 已自动更新 app.config.ts,添加了以下页面路径:"); + System.out.println(newPages.toString()); + } else { + System.out.println("ℹ️ app.config.ts 中已包含所有页面路径,无需更新"); + } + } else { + System.out.println("⚠️ 未找到 " + moduleName + " 模块的子包配置,请手动添加页面路径"); + } + + } catch (Exception e) { + System.err.println("❌ 更新 app.config.ts 失败: " + e.getMessage()); + e.printStackTrace(); + } } } diff --git a/src/test/java/com/gxwebsoft/generator/ShopGenerator.java b/src/test/java/com/gxwebsoft/generator/ShopGenerator.java index ea28661..9d1224c 100644 --- a/src/test/java/com/gxwebsoft/generator/ShopGenerator.java +++ b/src/test/java/com/gxwebsoft/generator/ShopGenerator.java @@ -13,6 +13,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.regex.Pattern; +import java.util.regex.Matcher; /** * CMS模块-代码生成工具 @@ -100,6 +105,7 @@ public class ShopGenerator { // "shop_express_template", // "shop_express_template_detail", // "shop_gift" + "shop_article" }; // 需要去除的表前缀 private static final String[] TABLE_PREFIX = new String[]{ @@ -343,6 +349,87 @@ public class ShopGenerator { mpg.setCfg(cfg); mpg.execute(); + + // 自动更新 app.config.ts + updateAppConfig(TABLE_NAMES, MODULE_NAME); + } + + /** + * 自动更新 app.config.ts 文件,添加新生成的页面路径 + */ + private static void updateAppConfig(String[] tableNames, String moduleName) { + String appConfigPath = OUTPUT_LOCATION_UNIAPP + OUTPUT_DIR_VUE + "/app.config.ts"; + + try { + // 读取原文件内容 + String content = new String(Files.readAllBytes(Paths.get(appConfigPath))); + + // 为每个表生成页面路径 + StringBuilder newPages = new StringBuilder(); + for (String tableName : tableNames) { + String entityPath = tableName.replaceAll("_", ""); + // 转换为驼峰命名 + String[] parts = tableName.split("_"); + StringBuilder camelCase = new StringBuilder(parts[0]); + for (int i = 1; i < parts.length; i++) { + camelCase.append(parts[i].substring(0, 1).toUpperCase()).append(parts[i].substring(1)); + } + entityPath = camelCase.toString(); + + newPages.append(" '").append(entityPath).append("/index',\n"); + newPages.append(" '").append(entityPath).append("/add',\n"); + } + + // 查找对应模块的子包配置 + String modulePattern = "\"root\":\\s*\"" + moduleName + "\",\\s*\"pages\":\\s*\\[([^\\]]*)]"; + Pattern pattern = Pattern.compile(modulePattern, Pattern.DOTALL); + Matcher matcher = pattern.matcher(content); + + if (matcher.find()) { + String existingPages = matcher.group(1); + + // 检查页面是否已存在,避免重复添加 + boolean needUpdate = false; + String[] newPageArray = newPages.toString().split("\n"); + for (String newPage : newPageArray) { + if (!newPage.trim().isEmpty() && !existingPages.contains(newPage.trim().replace(" ", "").replace(",", ""))) { + needUpdate = true; + break; + } + } + + if (needUpdate) { + // 备份原文件 + String backupPath = appConfigPath + ".backup." + System.currentTimeMillis(); + Files.copy(Paths.get(appConfigPath), Paths.get(backupPath)); + System.out.println("已备份原文件到: " + backupPath); + + // 在现有页面列表末尾添加新页面 + String updatedPages = existingPages.trim(); + if (!updatedPages.endsWith(",")) { + updatedPages += ","; + } + updatedPages += "\n" + newPages.toString().trim(); + + // 替换内容 + String updatedContent = content.replace(matcher.group(1), updatedPages); + + // 写入更新后的内容 + Files.write(Paths.get(appConfigPath), updatedContent.getBytes()); + + System.out.println("✅ 已自动更新 app.config.ts,添加了以下页面路径:"); + System.out.println(newPages.toString()); + } else { + System.out.println("ℹ️ app.config.ts 中已包含所有页面路径,无需更新"); + } + } else { + System.out.println("⚠️ 未找到 " + moduleName + " 模块的子包配置,请手动添加页面路径"); + } + + } catch (Exception e) { + System.err.println("❌ 更新 app.config.ts 失败: " + e.getMessage()); + e.printStackTrace(); + } } } diff --git a/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl b/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl index 7ec7304..a93cafd 100644 --- a/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl +++ b/src/test/java/com/gxwebsoft/generator/templates/add.config.ts.btl @@ -1,4 +1,4 @@ export default definePageConfig({ - navigationBarTitleText: '新增${table.comment!}', + navigationBarTitleText: '新增${table.comment!'数据'}', navigationBarTextStyle: 'black' }) diff --git a/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl b/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl index 63e53f9..73055da 100644 --- a/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl +++ b/src/test/java/com/gxwebsoft/generator/templates/add.tsx.btl @@ -36,7 +36,7 @@ const Add${entity} = () => { } Taro.showToast({ - title: `${params.id ? '更新' : '保存'}成功`, + title: `操作成功`, icon: 'success' }) @@ -45,7 +45,7 @@ const Add${entity} = () => { }, 1000) } catch (error) { Taro.showToast({ - title: `${params.id ? '更新' : '保存'}失败`, + title: `操作失败`, icon: 'error' }); } @@ -97,11 +97,11 @@ const Add${entity} = () => { <% for(field in table.fields){ %> <% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime'){ %> - -<% if(field.propertyType == 'String' && (field.comment?contains('描述') || field.comment?contains('备注') || field.comment?contains('内容'))){ %> -