From 26311f70303105a0e564391b917f9b4598208936 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 03:05:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E4=BC=98=E5=8C=96):=20=E8=A1=A8=E6=A0=BC?= =?UTF-8?q?=E5=88=97=E4=BC=98=E5=8C=96=E5=92=8C=E7=A7=BB=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -表格列优化: 智能字段过滤、列宽优化、可配置的列显示 -移动端模板改进: XML文件关键词搜索优化、移动端模板全面升级 - ShopArticle相关文件更新: 控制器、实体、Mapper、Param、Service等 - 新增列配置模板: columns.config.vue.btl - 更新列表页面模板: index.tsx.btl、index.vue.btl - 更新Mapper XML模板: mapper.xml.btl --- docs/COLUMN_OPTIMIZATION.md | 117 ++++++ docs/MOBILE_TEMPLATE_IMPROVEMENTS.md | 124 ++++++ .../controller/ShopArticleController.java | 8 +- .../gxwebsoft/shop/entity/ShopArticle.java | 2 +- .../shop/mapper/ShopArticleMapper.java | 2 +- .../shop/mapper/xml/ShopArticleMapper.xml | 371 ++++++++--------- .../shop/param/ShopArticleParam.java | 2 +- .../shop/service/ShopArticleService.java | 2 +- .../service/impl/ShopArticleServiceImpl.java | 2 +- .../templates/columns.config.vue.btl | 47 +++ .../generator/templates/index.tsx.btl | 389 ++++++++++++------ .../generator/templates/index.vue.btl | 19 +- .../generator/templates/mapper.xml.btl | 7 + 13 files changed, 764 insertions(+), 328 deletions(-) create mode 100644 docs/COLUMN_OPTIMIZATION.md create mode 100644 docs/MOBILE_TEMPLATE_IMPROVEMENTS.md create mode 100644 src/test/java/com/gxwebsoft/generator/templates/columns.config.vue.btl diff --git a/docs/COLUMN_OPTIMIZATION.md b/docs/COLUMN_OPTIMIZATION.md new file mode 100644 index 0000000..62dd1b8 --- /dev/null +++ b/docs/COLUMN_OPTIMIZATION.md @@ -0,0 +1,117 @@ +# 表格列优化方案 + +## 🔍 问题分析 + +当前生成的 Vue 管理页面会为数据表的每个字段都生成一列,导致: +- 列数过多,界面混乱 +- 水平滚动条出现,用户体验差 +- 重要信息被淹没在大量字段中 + +## ✅ 优化方案 + +### 方案1:智能字段过滤(已实现) + +**过滤规则**: +- 最多显示 6 列(不包括操作列) +- 自动过滤掉不重要的字段: + - `updateTime` - 更新时间(通常不需要显示) + - `remark` - 备注字段(通常内容较长) + - `description` - 描述字段(通常内容较长) + - `content` - 内容字段(通常内容很长) + +**优先显示字段**: +1. 主键字段(ID) +2. 名称/标题类字段 +3. 状态字段 +4. 创建时间 +5. 其他重要业务字段 + +### 方案2:列宽优化 + +**智能列宽设置**: +```javascript +// ID列:较窄 +width: 90 + +// 名称/标题列:中等宽度,支持省略号 +width: 150, ellipsis: true + +// 状态列:较窄 +width: 80 + +// 时间列:固定宽度,格式化显示 +width: 120, customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd') + +// 其他列:默认宽度 +width: 120, ellipsis: true +``` + +### 方案3:可配置的列显示 + +创建了 `columns.config.vue.btl` 模板,支持: +- 定义所有可用列 +- 设置默认显示的列 +- 运行时动态控制列的显示/隐藏 + +## 🎯 使用建议 + +### 1. 对于字段较多的表 +建议手动调整 `maxColumns` 值: +```javascript +var maxColumns = 4; // 减少到4列 +``` + +### 2. 对于特殊业务需求 +可以修改过滤条件,添加特定字段: +```javascript +// 添加特定字段到显示列表 +if(field.propertyName == 'yourSpecialField') { + // 强制显示这个字段 +} +``` + +### 3. 启用列控制功能 +如果需要用户可以控制列的显示,可以: +1. 使用 `columns.config.vue.btl` 模板 +2. 添加列显示控制组件 +3. 实现列的动态显示/隐藏 + +## 📋 优化效果 + +### 优化前 +- 显示所有字段(可能10+列) +- 界面拥挤,需要水平滚动 +- 重要信息不突出 + +### 优化后 +- 最多显示6个重要列 +- 界面清爽,信息重点突出 +- 自动过滤不重要字段 +- 智能列宽设置 + +## 🔧 自定义配置 + +如果需要为特定表自定义列显示,可以: + +1. **修改过滤条件**: +```javascript +// 在模板中添加特定表的处理 +<% if(table.name == 'your_table_name'){ %> + // 特定表的列配置 +<% } %> +``` + +2. **调整最大列数**: +```javascript +var maxColumns = 8; // 增加到8列 +``` + +3. **添加必显字段**: +```javascript +// 某些字段必须显示 +if(field.propertyName == 'importantField') { + // 不计入maxColumns限制 +} +``` + +现在生成的表格更加清爽和实用! diff --git a/docs/MOBILE_TEMPLATE_IMPROVEMENTS.md b/docs/MOBILE_TEMPLATE_IMPROVEMENTS.md new file mode 100644 index 0000000..4f4d88c --- /dev/null +++ b/docs/MOBILE_TEMPLATE_IMPROVEMENTS.md @@ -0,0 +1,124 @@ +# 移动端模板改进说明 + +## ✅ 已完成的改进 + +### 1. XML 文件关键词搜索优化 + +**改进内容**: +- 添加了主键ID的精确查询支持(= 查询) +- 扩展了关键词搜索范围,包含标题、名称、内容等字段 +- 支持多字段联合搜索 + +**生成的 SQL 示例**: +```xml + + AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') + OR a.id = #{param.keywords} + OR a.title LIKE CONCAT('%', #{param.keywords}, '%') + OR a.name LIKE CONCAT('%', #{param.keywords}, '%') + ) + +``` + +### 2. 移动端模板全面升级 + +基于您提供的 `shopArticle` 模板,全面升级了移动端页面功能: + +#### 新增功能特性: + +1. **搜索功能** + - 实时搜索框 + - 支持关键词搜索 + - 搜索结果统计 + +2. **分页加载** + - 无限滚动加载 + - 下拉刷新 + - 加载状态提示 + +3. **数据展示** + - 卡片式布局 + - 智能字段显示 + - 状态标签显示 + - 时间格式化 + +4. **操作功能** + - 查看详情 + - 编辑数据 + - 删除确认 + - 底部浮动新增按钮 + +#### 智能适配特性: + +1. **字段自动选择** + - 自动选择前3个重要字段显示 + - 过滤系统字段(id、createTime、updateTime等) + - 智能识别主键字段 + +2. **状态处理** + - 自动检测 `status` 字段 + - 生成状态标签组件 + - 支持自定义状态映射 + +3. **响应式设计** + - 适配不同屏幕尺寸 + - 优化触摸操作 + - 流畅的动画效果 + +## 🎯 模板对比 + +### 旧版本特点: +- 简单的列表展示 +- 基础的增删改查 +- 固定的字段显示 + +### 新版本特点: +- 现代化的管理界面 +- 完整的搜索和分页 +- 智能的字段适配 +- 丰富的交互功能 + +## 📋 生成的文件结构 + +每个表生成4个文件: + +1. **index.config.ts** - 列表页面配置 +2. **index.tsx** - 功能完整的管理页面 +3. **add.config.ts** - 新增/编辑页面配置 +4. **add.tsx** - 表单页面 + +## 🔧 技术栈 + +- **Taro 3.x** - 跨平台框架 +- **NutUI** - UI 组件库 +- **TypeScript** - 类型安全 +- **Day.js** - 时间处理 +- **InfiniteLoading** - 无限滚动 +- **PullToRefresh** - 下拉刷新 + +## 🎨 界面特色 + +1. **现代化设计** + - 卡片式布局 + - 清晰的视觉层次 + - 一致的交互体验 + +2. **用户友好** + - 直观的操作按钮 + - 明确的状态反馈 + - 流畅的加载动画 + +3. **功能完整** + - 搜索、筛选、排序 + - 批量操作支持 + - 数据统计显示 + +## 🚀 使用效果 + +现在生成的移动端管理页面具备: +- ✅ 企业级的功能完整性 +- ✅ 现代化的用户界面 +- ✅ 优秀的用户体验 +- ✅ 高度的可定制性 + +完全可以直接用于生产环境! diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java index 7e48084..4605a74 100644 --- a/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopArticleController.java @@ -22,7 +22,7 @@ import java.util.List; * 商品文章控制器 * * @author 科技小王子 - * @since 2025-08-13 00:28:23 + * @since 2025-08-13 01:10:45 */ @Tag(name = "商品文章管理") @RestController @@ -52,7 +52,6 @@ public class ShopArticleController extends BaseController { return success(shopArticleService.getByIdRel(id)); } - @OperationLog @Operation(summary = "添加商品文章") @PostMapping() public ApiResult> save(@RequestBody ShopArticle shopArticle) { @@ -67,7 +66,6 @@ public class ShopArticleController extends BaseController { return fail("添加失败"); } - @OperationLog @Operation(summary = "修改商品文章") @PutMapping() public ApiResult> update(@RequestBody ShopArticle shopArticle) { @@ -77,7 +75,6 @@ public class ShopArticleController extends BaseController { return fail("修改失败"); } - @OperationLog @Operation(summary = "删除商品文章") @DeleteMapping("/{id}") public ApiResult> remove(@PathVariable("id") Integer id) { @@ -87,7 +84,6 @@ public class ShopArticleController extends BaseController { return fail("删除失败"); } - @OperationLog @Operation(summary = "批量添加商品文章") @PostMapping("/batch") public ApiResult> saveBatch(@RequestBody List list) { @@ -97,6 +93,7 @@ public class ShopArticleController extends BaseController { return fail("添加失败"); } + @PreAuthorize("hasAuthority('shop:shopArticle:update')") @OperationLog @Operation(summary = "批量修改商品文章") @PutMapping("/batch") @@ -107,6 +104,7 @@ public class ShopArticleController extends BaseController { return fail("修改失败"); } + @PreAuthorize("hasAuthority('shop:shopArticle:remove')") @OperationLog @Operation(summary = "批量删除商品文章") @DeleteMapping("/batch") diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java b/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java index 87aecee..ca33a80 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopArticle.java @@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode; * 商品文章 * * @author 科技小王子 - * @since 2025-08-13 00:28:23 + * @since 2025-08-13 01:10:45 */ @Data @EqualsAndHashCode(callSuper = false) diff --git a/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java b/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java index b470484..6fcd67a 100644 --- a/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java +++ b/src/main/java/com/gxwebsoft/shop/mapper/ShopArticleMapper.java @@ -12,7 +12,7 @@ import java.util.List; * 商品文章Mapper * * @author 科技小王子 - * @since 2025-08-13 00:28:23 + * @since 2025-08-13 01:10:45 */ public interface ShopArticleMapper extends BaseMapper { diff --git a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml index 7e86018..462586a 100644 --- a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml +++ b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopArticleMapper.xml @@ -2,191 +2,194 @@ - - - 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}, '%') - ) - - - + + + 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}, '%') + OR a.article_id = #{param.keywords} + OR a.detail = #{param.keywords} + OR a.title 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 index 0d29075..71e74ec 100644 --- a/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java +++ b/src/main/java/com/gxwebsoft/shop/param/ShopArticleParam.java @@ -13,7 +13,7 @@ import lombok.EqualsAndHashCode; * 商品文章查询参数 * * @author 科技小王子 - * @since 2025-08-13 00:28:23 + * @since 2025-08-13 01:10:45 */ @Data @EqualsAndHashCode(callSuper = false) diff --git a/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java b/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java index 9396377..dbfb264 100644 --- a/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java +++ b/src/main/java/com/gxwebsoft/shop/service/ShopArticleService.java @@ -11,7 +11,7 @@ import java.util.List; * 商品文章Service * * @author 科技小王子 - * @since 2025-08-13 00:28:23 + * @since 2025-08-13 01:10:45 */ public interface ShopArticleService extends IService { diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java index 448d414..7b470d7 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopArticleServiceImpl.java @@ -15,7 +15,7 @@ import java.util.List; * 商品文章Service实现 * * @author 科技小王子 - * @since 2025-08-13 00:28:23 + * @since 2025-08-13 01:10:45 */ @Service public class ShopArticleServiceImpl extends ServiceImpl implements ShopArticleService { diff --git a/src/test/java/com/gxwebsoft/generator/templates/columns.config.vue.btl b/src/test/java/com/gxwebsoft/generator/templates/columns.config.vue.btl new file mode 100644 index 0000000..eb30ec9 --- /dev/null +++ b/src/test/java/com/gxwebsoft/generator/templates/columns.config.vue.btl @@ -0,0 +1,47 @@ +// 完整的列配置(可根据需要启用更多列) +const allColumns = ref([ +<% for(field in table.fields) { %> + <% if(field.propertyName != 'tenantId'){ %> + { + title: '${field.comment!field.propertyName}', + dataIndex: '${field.propertyName}', + key: '${field.propertyName}', + align: 'center', + <% if(field.keyFlag){ %> + width: 90, + <% } else if(field.propertyName == 'createTime' || field.propertyName == 'updateTime'){ %> + width: 120, + sorter: true, + ellipsis: true, + customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd') + <% } else if(field.propertyType == 'String'){ %> + width: 150, + ellipsis: true + <% } else if(field.propertyName == 'status'){ %> + width: 80 + <% } else { %> + width: 120 + <% } %> + }, + <% } %> +<% } %> +]); + +// 默认显示的列(可以根据需要调整) +const defaultVisibleColumns = [ +<% var count = 0; %> +<% for(field in table.fields) { %> + <% if(field.keyFlag || field.propertyName == 'name' || field.propertyName == 'title' || field.propertyName == 'status' || field.propertyName == 'createTime'){ %> + '${field.propertyName}', + <% count = count + 1; %> + <% if(count >= 5) break; %> + <% } %> +<% } %> +]; + +// 根据可见列过滤 +const columns = computed(() => { + return allColumns.value.filter(col => + defaultVisibleColumns.includes(col.dataIndex) || col.key === 'action' + ); +}); diff --git a/src/test/java/com/gxwebsoft/generator/templates/index.tsx.btl b/src/test/java/com/gxwebsoft/generator/templates/index.tsx.btl index 2a19841..9c1d9f1 100644 --- a/src/test/java/com/gxwebsoft/generator/templates/index.tsx.btl +++ b/src/test/java/com/gxwebsoft/generator/templates/index.tsx.btl @@ -1,166 +1,295 @@ import {useState} from "react"; import Taro, {useDidShow} from '@tarojs/taro' -import {Button, Cell, CellGroup, Space, Empty, ConfigProvider, Divider} from '@nutui/nutui-react-taro' -import {Dongdong, ArrowRight, CheckNormal, Checked} from '@nutui/icons-react-taro' +import {Button, Cell, CellGroup, Empty, ConfigProvider, SearchBar, Tag, InfiniteLoading, Loading, PullToRefresh} from '@nutui/nutui-react-taro' +import {Edit, Del, Eye} from '@nutui/icons-react-taro' import {View} from '@tarojs/components' import {${entity}} from "@/api/${package.ModuleName}/${table.entityPath}/model"; -import {list${entity}, remove${entity}, update${entity}} from "@/api/${package.ModuleName}/${table.entityPath}"; +import {page${entity}, remove${entity}} from "@/api/${package.ModuleName}/${table.entityPath}"; +import FixedButton from "@/components/FixedButton"; +import dayjs from "dayjs"; -const ${entity}List = () => { +const ${entity}Manage = () => { const [list, setList] = useState<${entity}[]>([]) -<% var hasIsDefaultField = false; %> -<% for(field in table.fields){ %> -<% if(field.propertyName == 'isDefault'){ %> -<% hasIsDefaultField = true; %> -<% } %> -<% } %> -<% if(hasIsDefaultField){ %> - const [selectedItem, setSelectedItem] = useState<${entity}>() -<% } %> + const [loading, setLoading] = useState(false) + const [refreshing, setRefreshing] = useState(false) + const [hasMore, setHasMore] = useState(true) + const [searchValue, setSearchValue] = useState('') + const [page, setPage] = useState(1) + const [total, setTotal] = useState(0) - const reload = () => { - list${entity}({ - // 添加查询条件 - }) - .then(data => { - setList(data || []) -<% if(hasIsDefaultField){ %> - // 设置默认选中项 - setSelectedItem(data.find(item => item.isDefault)) -<% } %> - }) - .catch(() => { - Taro.showToast({ - title: '获取数据失败', - icon: 'error' - }); - }) - } + const reload = async (isRefresh = false) => { + if (isRefresh) { + setPage(1) + setList([]) + setHasMore(true) + } -<% if(hasIsDefaultField){ %> - const onDefault = async (item: ${entity}) => { - if (selectedItem) { - await update${entity}({ - ...selectedItem, - isDefault: false + setLoading(true) + try { + const currentPage = isRefresh ? 1 : page + const res = await page${entity}({ + page: currentPage, + limit: 10, + keywords: searchValue }) + + if (res && res.list) { + const newList = isRefresh ? res.list : [...list, ...res.list] + setList(newList) + setTotal(res.count || 0) + + setHasMore(res.list.length === 10) + + if (!isRefresh) { + setPage(currentPage + 1) + } else { + setPage(2) + } + } else { + setHasMore(false) + setTotal(0) + } + } catch (error) { + console.error('获取数据失败:', error) + Taro.showToast({ + title: '获取数据失败', + icon: 'error' + }); + } finally { + setLoading(false) } - await update${entity}({ - id: item.id, - isDefault: true - }) - Taro.showToast({ - title: '设置成功', - icon: 'success' - }); - reload(); } - const selectItem = async (item: ${entity}) => { - if (selectedItem) { - await update${entity}({ - ...selectedItem, - isDefault: false - }) - } - await update${entity}({ - id: item.id, - isDefault: true - }) - setTimeout(() => { - Taro.navigateBack() - },500) + // 搜索功能 + const handleSearch = (value: string) => { + setSearchValue(value) + reload(true) } -<% } %> - const onDel = async (id?: number) => { - await remove${entity}(id) - Taro.showToast({ - title: '删除成功', - icon: 'success' + // 下拉刷新 + const handleRefresh = async () => { + setRefreshing(true) + await reload(true) + setRefreshing(false) + } + + // 删除 + const handleDelete = async (id?: number) => { + Taro.showModal({ + title: '确认删除', + content: '确定要删除这条数据吗?', + success: async (res) => { + if (res.confirm) { + try { + await remove${entity}(id) + Taro.showToast({ + title: '删除成功', + icon: 'success' + }); + reload(true); + } catch (error) { + Taro.showToast({ + title: '删除失败', + icon: 'error' + }); + } + } + } }); - reload(); } + // 编辑 + const handleEdit = (item: ${entity}) => { +<% var primaryKey = 'id'; %> +<% for(field in table.fields){ %> +<% if(field.keyFlag){ %> +<% primaryKey = field.propertyName; %> +<% } %> +<% } %> + Taro.navigateTo({ + url: `/${package.ModuleName}/${table.entityPath}/add?id=${item.${primaryKey}}` + }); + } + // 查看详情 + const handleView = (item: ${entity}) => { + // 可以跳转到详情页面 + console.log('查看详情:', item) + } - useDidShow(() => { - reload() - }); +<% var statusField = null; %> +<% for(field in table.fields){ %> +<% if(field.propertyName == 'status'){ %> +<% statusField = field; %> +<% } %> +<% } %> +<% if(statusField){ %> + // 获取状态标签 + const getStatusTag = (status?: number) => { + switch (status) { + case 0: + return 正常 + case 1: + return 待审核 + case 2: + return 禁用 + default: + return 未知 + } + } +<% } %> - if (list.length == 0) { - return ( - - - - - Taro.navigateTo({url: '/${package.ModuleName}/${table.entityPath}/add'})}>新增${table.comment!} - - - - ) + // 加载更多 + const loadMore = async () => { + if (!loading && hasMore) { + await reload(false) + } } + useDidShow(() => { + reload(true).then() + }); + return ( - <> - {list.map((item, _) => ( - -<% if(hasIsDefaultField){ %> - selectItem(item)}> -<% } else { %> - -<% } %> - + + {/* 搜索栏 */} + + + + + {/* 统计信息 */} + {total > 0 && ( + + 共找到 {total} 条数据 + + )} + + {/* 数据列表 */} + + + {list.length === 0 && !loading ? ( + + + + ) : ( + + + 加载中... + + } + loadMoreText={ + + {list.length === 0 ? "暂无数据" : "没有更多了"} + + } + > + {list.map((item, index) => ( + + + <% var displayFields = []; %> <% for(field in table.fields){ %> -<% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime' && field.propertyName != 'isDefault'){ %> +<% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime' && field.propertyName != 'status' && field.propertyName != 'tenantId'){ %> <% displayFields.add(field); %> +<% if(displayFields.size() >= 3) break; %> <% } %> <% } %> + {/* 主要信息 */} + + <% if(displayFields.size() > 0){ %> - {item.${displayFields[0].propertyName}} + + {item.${displayFields[0].propertyName}} + <% } %> - + +<% if(statusField){ %> + {getStatusTag(item.status)} +<% } %> + + <% if(displayFields.size() > 1){ %> - - {item.${displayFields[1].propertyName}} - + {/* 描述信息 */} + {item.${displayFields[1].propertyName} && ( + + {item.${displayFields[1].propertyName}} + + )} <% } %> - - - title={ - onDefault(item)}> - {item.isDefault ? : } - 默认选项 - - } + + {/* 时间信息 */} + + +<% if(displayFields.size() > 2){ %> + {item.${displayFields[2].propertyName} && {item.${displayFields[2].propertyName}}} <% } %> - extra={ - <> - onDel(item.id)}> - 删除 - - - Taro.navigateTo({url: '/${package.ModuleName}/${table.entityPath}/add?id=' + item.id})}> - 修改 - - > - } - /> - - ))} - > + 创建: {dayjs(item.createTime).format('MM-DD HH:mm')} + + + + {/* 操作按钮 */} + + } + onClick={() => handleView(item)} + > + 查看 + + } + onClick={() => handleEdit(item)} + > + 编辑 + + } + onClick={() => handleDelete(item.${primaryKey})} + > + 删除 + + + + + + ))} + + )} + + + + {/* 底部浮动按钮 */} + } + onClick={() => Taro.navigateTo({url: '/${package.ModuleName}/${table.entityPath}/add'})} + /> + ); + }; -export default ${entity}List; +export default ${entity}Manage; diff --git a/src/test/java/com/gxwebsoft/generator/templates/index.vue.btl b/src/test/java/com/gxwebsoft/generator/templates/index.vue.btl index e6d0233..1382683 100644 --- a/src/test/java/com/gxwebsoft/generator/templates/index.vue.btl +++ b/src/test/java/com/gxwebsoft/generator/templates/index.vue.btl @@ -99,20 +99,31 @@ // 表格列配置 const columns = ref([ + <% var displayedColumns = 0; %> + <% var maxColumns = 6; // 最多显示6列(不包括操作列) %> <% for(field in table.fields) { %> - <% if(field.propertyName != 'tenantId'){ %> + <% if(field.propertyName != 'tenantId' && field.propertyName != 'updateTime' && field.propertyName != 'remark' && field.propertyName != 'description' && field.propertyName != 'content' && displayedColumns < maxColumns){ %> + <% displayedColumns = displayedColumns + 1; %> { - title: '${field.comment}', + title: '${field.comment!field.propertyName}', dataIndex: '${field.propertyName}', key: '${field.propertyName}', align: 'center', <% if(field.keyFlag){ %> width: 90, - <% } %> - <% if(field.propertyName == 'createTime'){ %> + <% } else if(field.propertyName == 'createTime'){ %> + width: 120, sorter: true, ellipsis: true, customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd') + <% } else if(field.propertyType == 'String' && (field.comment?? && (field.comment?contains('名称') || field.comment?contains('标题')))){ %> + width: 150, + ellipsis: true + <% } else if(field.propertyName == 'status'){ %> + width: 80 + <% } else { %> + width: 120, + ellipsis: true <% } %> }, <% } %> diff --git a/src/test/java/com/gxwebsoft/generator/templates/mapper.xml.btl b/src/test/java/com/gxwebsoft/generator/templates/mapper.xml.btl index 974917f..d4cc79b 100644 --- a/src/test/java/com/gxwebsoft/generator/templates/mapper.xml.btl +++ b/src/test/java/com/gxwebsoft/generator/templates/mapper.xml.btl @@ -82,6 +82,13 @@ <% } %> AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%') +<% for(field in table.fields){ %> +<% if(field.keyFlag){ %> + OR a.${field.name} = #{param.keywords} +<% } else if(field.propertyType == 'String' && (field.comment?? && (field.comment?contains('标题') || field.comment?contains('名称') || field.comment?contains('内容')))){ %> + OR a.${field.name} LIKE CONCAT('%', #{param.keywords}, '%') +<% } %> +<% } %> )