refactor(shop): 移除商品文章中的商户ID字段

- 从 ShopArticle 实体中删除 merchantId 字段
- 从 ShopArticleParam 参数中移除 merchantId 查询条件
- 更新 ShopArticleMapper.xml 中的 SQL 语句,移除与 merchantId 相关的条件
This commit is contained in:
2025-08-13 03:40:12 +08:00
parent 26311f7030
commit c85c74fb80
14 changed files with 750 additions and 476 deletions

View File

@@ -22,7 +22,7 @@ import java.util.List;
* 商品文章控制器
*
* @author 科技小王子
* @since 2025-08-13 01:10:45
* @since 2025-08-13 03:38:52
*/
@Tag(name = "商品文章管理")
@RestController
@@ -31,6 +31,7 @@ public class ShopArticleController extends BaseController {
@Resource
private ShopArticleService shopArticleService;
@PreAuthorize("hasAuthority('shop:shopArticle:list')")
@Operation(summary = "分页查询商品文章")
@GetMapping("/page")
public ApiResult<PageResult<ShopArticle>> page(ShopArticleParam param) {
@@ -38,6 +39,7 @@ public class ShopArticleController extends BaseController {
return success(shopArticleService.pageRel(param));
}
@PreAuthorize("hasAuthority('shop:shopArticle:list')")
@Operation(summary = "查询全部商品文章")
@GetMapping()
public ApiResult<List<ShopArticle>> list(ShopArticleParam param) {
@@ -45,6 +47,7 @@ public class ShopArticleController extends BaseController {
return success(shopArticleService.listRel(param));
}
@PreAuthorize("hasAuthority('shop:shopArticle:list')")
@Operation(summary = "根据id查询商品文章")
@GetMapping("/{id}")
public ApiResult<ShopArticle> get(@PathVariable("id") Integer id) {
@@ -52,6 +55,8 @@ public class ShopArticleController extends BaseController {
return success(shopArticleService.getByIdRel(id));
}
@PreAuthorize("hasAuthority('shop:shopArticle:save')")
@OperationLog
@Operation(summary = "添加商品文章")
@PostMapping()
public ApiResult<?> save(@RequestBody ShopArticle shopArticle) {
@@ -66,6 +71,8 @@ public class ShopArticleController extends BaseController {
return fail("添加失败");
}
@PreAuthorize("hasAuthority('shop:shopArticle:update')")
@OperationLog
@Operation(summary = "修改商品文章")
@PutMapping()
public ApiResult<?> update(@RequestBody ShopArticle shopArticle) {
@@ -75,6 +82,8 @@ public class ShopArticleController extends BaseController {
return fail("修改失败");
}
@PreAuthorize("hasAuthority('shop:shopArticle:remove')")
@OperationLog
@Operation(summary = "删除商品文章")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
@@ -84,6 +93,8 @@ public class ShopArticleController extends BaseController {
return fail("删除失败");
}
@PreAuthorize("hasAuthority('shop:shopArticle:save')")
@OperationLog
@Operation(summary = "批量添加商品文章")
@PostMapping("/batch")
public ApiResult<?> saveBatch(@RequestBody List<ShopArticle> list) {

View File

@@ -14,7 +14,7 @@ import lombok.EqualsAndHashCode;
* 商品文章
*
* @author 科技小王子
* @since 2025-08-13 01:10:45
* @since 2025-08-13 03:38:51
*/
@Data
@EqualsAndHashCode(callSuper = false)
@@ -143,9 +143,6 @@ public class ShopArticle implements Serializable {
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "商户ID")
private Integer merchantId;
@Schema(description = "项目ID")
private Integer projectId;

View File

@@ -12,7 +12,7 @@ import java.util.List;
* 商品文章Mapper
*
* @author 科技小王子
* @since 2025-08-13 01:10:45
* @since 2025-08-13 03:38:52
*/
public interface ShopArticleMapper extends BaseMapper<ShopArticle> {

View File

@@ -2,194 +2,188 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gxwebsoft.shop.mapper.ShopArticleMapper">
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM shop_article a
<where>
<if test="param.articleId != null">
AND a.article_id = #{param.articleId}
</if>
<if test="param.title != null">
AND a.title LIKE CONCAT('%', #{param.title}, '%')
</if>
<if test="param.type != null">
AND a.type = #{param.type}
</if>
<if test="param.model != null">
AND a.model LIKE CONCAT('%', #{param.model}, '%')
</if>
<if test="param.detail != null">
AND a.detail LIKE CONCAT('%', #{param.detail}, '%')
</if>
<if test="param.categoryId != null">
AND a.category_id = #{param.categoryId}
</if>
<if test="param.parentId != null">
AND a.parent_id = #{param.parentId}
</if>
<if test="param.topic != null">
AND a.topic LIKE CONCAT('%', #{param.topic}, '%')
</if>
<if test="param.tags != null">
AND a.tags LIKE CONCAT('%', #{param.tags}, '%')
</if>
<if test="param.image != null">
AND a.image LIKE CONCAT('%', #{param.image}, '%')
</if>
<if test="param.imageWidth != null">
AND a.image_width = #{param.imageWidth}
</if>
<if test="param.imageHeight != null">
AND a.image_height = #{param.imageHeight}
</if>
<if test="param.price != null">
AND a.price = #{param.price}
</if>
<if test="param.startTime != null">
AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%')
</if>
<if test="param.endTime != null">
AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%')
</if>
<if test="param.source != null">
AND a.source LIKE CONCAT('%', #{param.source}, '%')
</if>
<if test="param.overview != null">
AND a.overview LIKE CONCAT('%', #{param.overview}, '%')
</if>
<if test="param.virtualViews != null">
AND a.virtual_views = #{param.virtualViews}
</if>
<if test="param.actualViews != null">
AND a.actual_views = #{param.actualViews}
</if>
<if test="param.rate != null">
AND a.rate = #{param.rate}
</if>
<if test="param.showType != null">
AND a.show_type = #{param.showType}
</if>
<if test="param.password != null">
AND a.password LIKE CONCAT('%', #{param.password}, '%')
</if>
<if test="param.permission != null">
AND a.permission = #{param.permission}
</if>
<if test="param.platform != null">
AND a.platform LIKE CONCAT('%', #{param.platform}, '%')
</if>
<if test="param.files != null">
AND a.files LIKE CONCAT('%', #{param.files}, '%')
</if>
<if test="param.video != null">
AND a.video LIKE CONCAT('%', #{param.video}, '%')
</if>
<if test="param.accept != null">
AND a.accept LIKE CONCAT('%', #{param.accept}, '%')
</if>
<if test="param.longitude != null">
AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%')
</if>
<if test="param.latitude != null">
AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%')
</if>
<if test="param.province != null">
AND a.province LIKE CONCAT('%', #{param.province}, '%')
</if>
<if test="param.city != null">
AND a.city LIKE CONCAT('%', #{param.city}, '%')
</if>
<if test="param.region != null">
AND a.region LIKE CONCAT('%', #{param.region}, '%')
</if>
<if test="param.address != null">
AND a.address LIKE CONCAT('%', #{param.address}, '%')
</if>
<if test="param.likes != null">
AND a.likes = #{param.likes}
</if>
<if test="param.commentNumbers != null">
AND a.comment_numbers = #{param.commentNumbers}
</if>
<if test="param.toUsers != null">
AND a.to_users LIKE CONCAT('%', #{param.toUsers}, '%')
</if>
<if test="param.author != null">
AND a.author LIKE CONCAT('%', #{param.author}, '%')
</if>
<if test="param.recommend != null">
AND a.recommend = #{param.recommend}
</if>
<if test="param.bmUsers != null">
AND a.bm_users = #{param.bmUsers}
</if>
<if test="param.userId != null">
AND a.user_id = #{param.userId}
</if>
<if test="param.merchantId != null">
AND a.merchant_id = #{param.merchantId}
</if>
<if test="param.projectId != null">
AND a.project_id = #{param.projectId}
</if>
<if test="param.lang != null">
AND a.lang LIKE CONCAT('%', #{param.lang}, '%')
</if>
<if test="param.langArticleId != null">
AND a.lang_article_id = #{param.langArticleId}
</if>
<if test="param.translation != null">
AND a.translation = #{param.translation}
</if>
<if test="param.editor != null">
AND a.editor = #{param.editor}
</if>
<if test="param.pdfUrl != null">
AND a.pdf_url LIKE CONCAT('%', #{param.pdfUrl}, '%')
</if>
<if test="param.version != null">
AND a.version = #{param.version}
</if>
<if test="param.sortNumber != null">
AND a.sort_number = #{param.sortNumber}
</if>
<if test="param.comments != null">
AND a.comments LIKE CONCAT('%', #{param.comments}, '%')
</if>
<if test="param.status != null">
AND a.status = #{param.status}
</if>
<if test="param.deleted != null">
AND a.deleted = #{param.deleted}
</if>
<if test="param.deleted == null">
AND a.deleted = 0
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
<if test="param.keywords != null">
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}, '%')
)
</if>
</where>
</sql>
<!-- 关联查询sql -->
<sql id="selectSql">
SELECT a.*
FROM shop_article a
<where>
<if test="param.articleId != null">
AND a.article_id = #{param.articleId}
</if>
<if test="param.title != null">
AND a.title LIKE CONCAT('%', #{param.title}, '%')
</if>
<if test="param.type != null">
AND a.type = #{param.type}
</if>
<if test="param.model != null">
AND a.model LIKE CONCAT('%', #{param.model}, '%')
</if>
<if test="param.detail != null">
AND a.detail LIKE CONCAT('%', #{param.detail}, '%')
</if>
<if test="param.categoryId != null">
AND a.category_id = #{param.categoryId}
</if>
<if test="param.parentId != null">
AND a.parent_id = #{param.parentId}
</if>
<if test="param.topic != null">
AND a.topic LIKE CONCAT('%', #{param.topic}, '%')
</if>
<if test="param.tags != null">
AND a.tags LIKE CONCAT('%', #{param.tags}, '%')
</if>
<if test="param.image != null">
AND a.image LIKE CONCAT('%', #{param.image}, '%')
</if>
<if test="param.imageWidth != null">
AND a.image_width = #{param.imageWidth}
</if>
<if test="param.imageHeight != null">
AND a.image_height = #{param.imageHeight}
</if>
<if test="param.price != null">
AND a.price = #{param.price}
</if>
<if test="param.startTime != null">
AND a.start_time LIKE CONCAT('%', #{param.startTime}, '%')
</if>
<if test="param.endTime != null">
AND a.end_time LIKE CONCAT('%', #{param.endTime}, '%')
</if>
<if test="param.source != null">
AND a.source LIKE CONCAT('%', #{param.source}, '%')
</if>
<if test="param.overview != null">
AND a.overview LIKE CONCAT('%', #{param.overview}, '%')
</if>
<if test="param.virtualViews != null">
AND a.virtual_views = #{param.virtualViews}
</if>
<if test="param.actualViews != null">
AND a.actual_views = #{param.actualViews}
</if>
<if test="param.rate != null">
AND a.rate = #{param.rate}
</if>
<if test="param.showType != null">
AND a.show_type = #{param.showType}
</if>
<if test="param.password != null">
AND a.password LIKE CONCAT('%', #{param.password}, '%')
</if>
<if test="param.permission != null">
AND a.permission = #{param.permission}
</if>
<if test="param.platform != null">
AND a.platform LIKE CONCAT('%', #{param.platform}, '%')
</if>
<if test="param.files != null">
AND a.files LIKE CONCAT('%', #{param.files}, '%')
</if>
<if test="param.video != null">
AND a.video LIKE CONCAT('%', #{param.video}, '%')
</if>
<if test="param.accept != null">
AND a.accept LIKE CONCAT('%', #{param.accept}, '%')
</if>
<if test="param.longitude != null">
AND a.longitude LIKE CONCAT('%', #{param.longitude}, '%')
</if>
<if test="param.latitude != null">
AND a.latitude LIKE CONCAT('%', #{param.latitude}, '%')
</if>
<if test="param.province != null">
AND a.province LIKE CONCAT('%', #{param.province}, '%')
</if>
<if test="param.city != null">
AND a.city LIKE CONCAT('%', #{param.city}, '%')
</if>
<if test="param.region != null">
AND a.region LIKE CONCAT('%', #{param.region}, '%')
</if>
<if test="param.address != null">
AND a.address LIKE CONCAT('%', #{param.address}, '%')
</if>
<if test="param.likes != null">
AND a.likes = #{param.likes}
</if>
<if test="param.commentNumbers != null">
AND a.comment_numbers = #{param.commentNumbers}
</if>
<if test="param.toUsers != null">
AND a.to_users LIKE CONCAT('%', #{param.toUsers}, '%')
</if>
<if test="param.author != null">
AND a.author LIKE CONCAT('%', #{param.author}, '%')
</if>
<if test="param.recommend != null">
AND a.recommend = #{param.recommend}
</if>
<if test="param.bmUsers != null">
AND a.bm_users = #{param.bmUsers}
</if>
<if test="param.userId != null">
AND a.user_id = #{param.userId}
</if>
<if test="param.projectId != null">
AND a.project_id = #{param.projectId}
</if>
<if test="param.lang != null">
AND a.lang LIKE CONCAT('%', #{param.lang}, '%')
</if>
<if test="param.langArticleId != null">
AND a.lang_article_id = #{param.langArticleId}
</if>
<if test="param.translation != null">
AND a.translation = #{param.translation}
</if>
<if test="param.editor != null">
AND a.editor = #{param.editor}
</if>
<if test="param.pdfUrl != null">
AND a.pdf_url LIKE CONCAT('%', #{param.pdfUrl}, '%')
</if>
<if test="param.version != null">
AND a.version = #{param.version}
</if>
<if test="param.sortNumber != null">
AND a.sort_number = #{param.sortNumber}
</if>
<if test="param.comments != null">
AND a.comments LIKE CONCAT('%', #{param.comments}, '%')
</if>
<if test="param.status != null">
AND a.status = #{param.status}
</if>
<if test="param.deleted != null">
AND a.deleted = #{param.deleted}
</if>
<if test="param.deleted == null">
AND a.deleted = 0
</if>
<if test="param.createTimeStart != null">
AND a.create_time &gt;= #{param.createTimeStart}
</if>
<if test="param.createTimeEnd != null">
AND a.create_time &lt;= #{param.createTimeEnd}
</if>
<if test="param.keywords != null">
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
)
</if>
</where>
</sql>
<!-- 分页查询 -->
<select id="selectPageRel" resultType="com.gxwebsoft.shop.entity.ShopArticle">
<include refid="selectSql"></include>
</select>
<!-- 分页查询 -->
<select id="selectPageRel" resultType="com.gxwebsoft.shop.entity.ShopArticle">
<include refid="selectSql"></include>
</select>
<!-- 查询全部 -->
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopArticle">
<include refid="selectSql"></include>
</select>
<!-- 查询全部 -->
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopArticle">
<include refid="selectSql"></include>
</select>
</mapper>

View File

@@ -13,7 +13,7 @@ import lombok.EqualsAndHashCode;
* 商品文章查询参数
*
* @author 科技小王子
* @since 2025-08-13 01:10:45
* @since 2025-08-13 03:38:51
*/
@Data
@EqualsAndHashCode(callSuper = false)
@@ -159,10 +159,6 @@ public class ShopArticleParam extends BaseParam {
@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;

View File

@@ -11,7 +11,7 @@ import java.util.List;
* 商品文章Service
*
* @author 科技小王子
* @since 2025-08-13 01:10:45
* @since 2025-08-13 03:38:52
*/
public interface ShopArticleService extends IService<ShopArticle> {

View File

@@ -15,7 +15,7 @@ import java.util.List;
* 商品文章Service实现
*
* @author 科技小王子
* @since 2025-08-13 01:10:45
* @since 2025-08-13 03:38:52
*/
@Service
public class ShopArticleServiceImpl extends ServiceImpl<ShopArticleMapper, ShopArticle> implements ShopArticleService {

View File

@@ -0,0 +1,149 @@
package com.gxwebsoft.generator;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* 简单的测试生成器,用于验证模板文件的完整性
*/
public class SimpleTestGenerator {
public static void main(String[] args) {
System.out.println("=== 代码生成器模板验证 ===");
String templatesDir = "src/test/java/com/gxwebsoft/generator/templates";
// 检查必要的模板文件
String[] requiredTemplates = {
"index.vue.btl",
"components.edit.vue.btl",
"components.search.vue.btl",
"index.tsx.btl",
"add.tsx.btl",
"index.config.ts.btl",
"add.config.ts.btl",
"index.ts.uniapp.btl",
"model.ts.uniapp.btl",
"controller.java.btl",
"service.java.btl",
"serviceImpl.java.btl",
"mapper.java.btl",
"mapper.xml.btl",
"entity.java.btl",
"param.java.btl"
};
boolean allTemplatesExist = true;
for (String template : requiredTemplates) {
String filePath = templatesDir + "/" + template;
File file = new File(filePath);
if (file.exists()) {
try {
long fileSize = Files.size(Paths.get(filePath));
System.out.println("" + template + " (大小: " + fileSize + " 字节)");
} catch (Exception e) {
System.out.println("⚠️ " + template + " (无法读取文件大小)");
}
} else {
System.out.println("" + template + " (文件不存在)");
allTemplatesExist = false;
}
}
System.out.println("\n=== 验证结果 ===");
if (allTemplatesExist) {
System.out.println("✅ 所有模板文件都存在且可读");
// 检查关键模板的内容完整性
checkTemplateIntegrity();
} else {
System.out.println("❌ 部分模板文件缺失");
}
}
private static void checkTemplateIntegrity() {
System.out.println("\n=== 模板内容完整性检查 ===");
// 检查Vue模板
checkVueTemplate();
// 检查移动端模板
checkMobileTemplate();
// 检查API模板
checkApiTemplate();
}
private static void checkVueTemplate() {
try {
String content = new String(Files.readAllBytes(
Paths.get("src/test/java/com/gxwebsoft/generator/templates/index.vue.btl")));
boolean hasTemplate = content.contains("<template>");
boolean hasScript = content.contains("<script");
boolean hasImports = content.contains("import");
boolean hasExport = content.contains("export default");
System.out.println("Vue模板检查:");
System.out.println(" - Template标签: " + (hasTemplate ? "" : ""));
System.out.println(" - Script标签: " + (hasScript ? "" : ""));
System.out.println(" - Import语句: " + (hasImports ? "" : ""));
System.out.println(" - Export语句: " + (hasExport ? "" : ""));
} catch (Exception e) {
System.out.println("Vue模板检查失败: " + e.getMessage());
}
}
private static void checkMobileTemplate() {
try {
String content = new String(Files.readAllBytes(
Paths.get("src/test/java/com/gxwebsoft/generator/templates/index.tsx.btl")));
boolean hasImports = content.contains("import");
boolean hasComponent = content.contains("const") && content.contains("Manage");
boolean hasExport = content.contains("export default");
boolean hasSearchBar = content.contains("SearchBar");
boolean hasInfiniteLoading = content.contains("InfiniteLoading");
System.out.println("移动端模板检查:");
System.out.println(" - Import语句: " + (hasImports ? "" : ""));
System.out.println(" - 组件定义: " + (hasComponent ? "" : ""));
System.out.println(" - Export语句: " + (hasExport ? "" : ""));
System.out.println(" - 搜索功能: " + (hasSearchBar ? "" : ""));
System.out.println(" - 无限滚动: " + (hasInfiniteLoading ? "" : ""));
} catch (Exception e) {
System.out.println("移动端模板检查失败: " + e.getMessage());
}
}
private static void checkApiTemplate() {
try {
String content = new String(Files.readAllBytes(
Paths.get("src/test/java/com/gxwebsoft/generator/templates/index.ts.uniapp.btl")));
boolean hasPageFunction = content.contains("export async function page");
boolean hasListFunction = content.contains("export async function list");
boolean hasAddFunction = content.contains("export async function add");
boolean hasUpdateFunction = content.contains("export async function update");
boolean hasRemoveFunction = content.contains("export async function remove");
boolean hasGetFunction = content.contains("export async function get");
System.out.println("API模板检查:");
System.out.println(" - 分页查询: " + (hasPageFunction ? "" : ""));
System.out.println(" - 列表查询: " + (hasListFunction ? "" : ""));
System.out.println(" - 添加功能: " + (hasAddFunction ? "" : ""));
System.out.println(" - 更新功能: " + (hasUpdateFunction ? "" : ""));
System.out.println(" - 删除功能: " + (hasRemoveFunction ? "" : ""));
System.out.println(" - 详情查询: " + (hasGetFunction ? "" : ""));
} catch (Exception e) {
System.out.println("API模板检查失败: " + e.getMessage());
}
}
}

View File

@@ -1,295 +1,171 @@
import {useState} from "react";
import Taro, {useDidShow} from '@tarojs/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 {Button, Cell, CellGroup, Space, Empty, ConfigProvider, Divider} from '@nutui/nutui-react-taro'
import {Dongdong, ArrowRight, CheckNormal, Checked} from '@nutui/icons-react-taro'
import {View} from '@tarojs/components'
import {${entity}} from "@/api/${package.ModuleName}/${table.entityPath}/model";
import {page${entity}, remove${entity}} from "@/api/${package.ModuleName}/${table.entityPath}";
import FixedButton from "@/components/FixedButton";
import dayjs from "dayjs";
import {list${entity}, remove${entity}, update${entity}} from "@/api/${package.ModuleName}/${table.entityPath}";
const ${entity}Manage = () => {
const ${entity}List = () => {
const [list, setList] = 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)
<% var hasIsDefaultField = false; %>
<% for(field in table.fields){ %>
<% if(field.propertyName == 'isDefault'){ %>
<% hasIsDefaultField = true; %>
<% } %>
<% } %>
<% if(hasIsDefaultField){ %>
const [selectedItem, setSelectedItem] = useState<${entity}>()
<% } %>
const reload = async (isRefresh = false) => {
if (isRefresh) {
setPage(1)
setList([])
setHasMore(true)
}
setLoading(true)
try {
const currentPage = isRefresh ? 1 : page
const res = await page${entity}({
page: currentPage,
limit: 10,
keywords: searchValue
const reload = () => {
list${entity}({
// 添加查询条件
})
.then(data => {
setList(data || [])
<% if(hasIsDefaultField){ %>
// 设置默认选中项
setSelectedItem(data.find(item => item.isDefault))
<% } %>
})
.catch(() => {
Taro.showToast({
title: '获取数据失败',
icon: 'error'
});
})
}
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)
<% if(hasIsDefaultField){ %>
const onDefault = async (item: ${entity}) => {
if (selectedItem) {
await update${entity}({
...selectedItem,
isDefault: false
})
}
}
// 搜索功能
const handleSearch = (value: string) => {
setSearchValue(value)
reload(true)
}
// 下拉刷新
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'
});
}
}
}
});
}
// 编辑
const handleEdit = (item: ${entity}) => {
await update${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}}`
${primaryKey}: item.${primaryKey},
isDefault: true
})
Taro.showToast({
title: '设置成功',
icon: 'success'
});
reload();
}
// 查看详情
const handleView = (item: ${entity}) => {
// 可以跳转到详情页面
console.log('查看详情:', item)
}
<% 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 <Tag type="success">正常</Tag>
case 1:
return <Tag type="warning">待审核</Tag>
case 2:
return <Tag type="danger">禁用</Tag>
default:
return <Tag>未知</Tag>
const selectItem = async (item: ${entity}) => {
if (selectedItem) {
await update${entity}({
...selectedItem,
isDefault: false
})
}
await update${entity}({
${primaryKey}: item.${primaryKey},
isDefault: true
})
setTimeout(() => {
Taro.navigateBack()
},500)
}
<% } %>
// 加载更多
const loadMore = async () => {
if (!loading && hasMore) {
await reload(false)
}
const onDel = async (id?: number) => {
await remove${entity}(id)
Taro.showToast({
title: '删除成功',
icon: 'success'
});
reload();
}
useDidShow(() => {
reload(true).then()
reload()
});
if (list.length == 0) {
return (
<ConfigProvider>
<div className={'h-full flex flex-col justify-center items-center'} style={{
height: 'calc(100vh - 300px)',
}}>
<Empty
style={{
backgroundColor: 'transparent'
}}
description="暂无数据"
/>
<Space>
<Button onClick={() => Taro.navigateTo({url: '/${package.ModuleName}/${table.entityPath}/add'})}>新增${table.comment!'数据'}</Button>
</Space>
</div>
</ConfigProvider>
)
}
return (
<ConfigProvider>
{/* 搜索栏 */}
<View className="py-2">
<SearchBar
placeholder="搜索关键词"
value={searchValue}
onChange={setSearchValue}
onSearch={handleSearch}
/>
</View>
{/* 统计信息 */}
{total > 0 && (
<View className="px-4 py-2 text-sm text-gray-500">
共找到 {total} 条数据
</View>
)}
{/* 数据列表 */}
<PullToRefresh
onRefresh={handleRefresh}
pullDistance={60}
headHeight={60}
>
<View className="px-4" style={{ height: 'calc(100vh - 160px)', overflowY: 'auto' }} id="data-scroll">
{list.length === 0 && !loading ? (
<View className="flex flex-col justify-center items-center" style={{height: 'calc(100vh - 200px)'}}>
<Empty
description="暂无数据"
style={{backgroundColor: 'transparent'}}
/>
</View>
) : (
<InfiniteLoading
target="data-scroll"
hasMore={hasMore}
onLoadMore={loadMore}
loadingText={
<View className="flex justify-center items-center py-4">
<Loading />
<View className="ml-2">加载中...</View>
</View>
}
loadMoreText={
<View className="text-center py-4 text-gray-500">
{list.length === 0 ? "暂无数据" : "没有更多了"}
</View>
}
>
{list.map((item, index) => (
<CellGroup key={item.${primaryKey} || index} className="mb-4">
<Cell>
<View className="flex flex-col gap-3 w-full">
<>
{list.map((item, _) => (
<Cell.Group key={item.${primaryKey}}>
<% if(hasIsDefaultField){ %>
<Cell className={'flex flex-col gap-1'} onClick={() => selectItem(item)}>
<% } else { %>
<Cell className={'flex flex-col gap-1'}>
<% } %>
<View>
<% var displayFields = []; %>
<% for(field in table.fields){ %>
<% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime' && field.propertyName != 'status' && field.propertyName != 'tenantId'){ %>
<% if(field.propertyName != 'id' && field.propertyName != 'createTime' && field.propertyName != 'updateTime' && field.propertyName != 'isDefault'){ %>
<% displayFields.add(field); %>
<% if(displayFields.size() >= 3) break; %>
<% if(displayFields.size() >= 2) break; %>
<% } %>
<% } %>
{/* 主要信息 */}
<View className="flex justify-between items-start">
<View className="flex-1 pr-2">
<% if(displayFields.size() > 0){ %>
<View className="text-lg font-bold text-gray-900 line-clamp-2">
{item.${displayFields[0].propertyName}}
</View>
<View className={'font-medium text-sm'}>{item.${displayFields[0].propertyName}}</View>
<% } %>
</View>
<% if(statusField){ %>
{getStatusTag(item.status)}
<% } %>
</View>
</View>
<% if(displayFields.size() > 1){ %>
{/* 描述信息 */}
{item.${displayFields[1].propertyName} && (
<View className="text-sm text-gray-600 line-clamp-2">
{item.${displayFields[1].propertyName}}
</View>
)}
<View className={'text-xs'}>
{item.${displayFields[1].propertyName}}
</View>
<% } %>
{/* 时间信息 */}
<View className="flex justify-between items-center text-xs text-gray-500">
<View className="flex items-center gap-4">
<% if(displayFields.size() > 2){ %>
{item.${displayFields[2].propertyName} && <View>{item.${displayFields[2].propertyName}}</View>}
</Cell>
<Cell
align="center"
<% if(hasIsDefaultField){ %>
title={
<View className={'flex items-center gap-1'} onClick={() => onDefault(item)}>
{item.isDefault ? <Checked className={'text-green-600'} size={16}/> : <CheckNormal size={16}/>}
<View className={'text-gray-400'}>默认选项</View>
</View>
}
<% } %>
<View>创建: {dayjs(item.createTime).format('MM-DD HH:mm')}</View>
</View>
</View>
{/* 操作按钮 */}
<View className="flex justify-end gap-2 pt-2 border-t border-gray-100">
<Button
size="small"
fill="outline"
icon={<Eye/>}
onClick={() => handleView(item)}
>
查看
</Button>
<Button
size="small"
fill="outline"
icon={<Edit/>}
onClick={() => handleEdit(item)}
>
编辑
</Button>
<Button
size="small"
type="danger"
fill="outline"
icon={<Del/>}
onClick={() => handleDelete(item.${primaryKey})}
>
删除
</Button>
</View>
</View>
</Cell>
</CellGroup>
))}
</InfiniteLoading>
)}
</View>
</PullToRefresh>
{/* 底部浮动按钮 */}
<FixedButton
text="新增${table.comment!'数据'}"
icon={<Edit />}
onClick={() => Taro.navigateTo({url: '/${package.ModuleName}/${table.entityPath}/add'})}
/>
</ConfigProvider>
extra={
<>
<View className={'text-gray-400'} onClick={() => onDel(item.${primaryKey})}>
删除
</View>
<Divider direction={'vertical'}/>
<View className={'text-gray-400'}
onClick={() => Taro.navigateTo({url: '/${package.ModuleName}/${table.entityPath}/add?id=' + item.${primaryKey}})}>
修改
</View>
</>
}
/>
</Cell.Group>
))}
</>
);
};
export default ${entity}Manage;
export default ${entity}List;

View File

@@ -99,11 +99,8 @@
// 表格列配置
const columns = ref<ColumnItem[]>([
<% var displayedColumns = 0; %>
<% var maxColumns = 6; // 最多显示6列不包括操作列 %>
<% for(field in table.fields) { %>
<% if(field.propertyName != 'tenantId' && field.propertyName != 'updateTime' && field.propertyName != 'remark' && field.propertyName != 'description' && field.propertyName != 'content' && displayedColumns < maxColumns){ %>
<% displayedColumns = displayedColumns + 1; %>
<% if(field.propertyName != 'tenantId'){ %>
{
title: '${field.comment!field.propertyName}',
dataIndex: '${field.propertyName}',
@@ -111,19 +108,11 @@
align: 'center',
<% if(field.keyFlag){ %>
width: 90,
<% } else if(field.propertyName == 'createTime'){ %>
width: 120,
<% } %>
<% if(field.propertyName == 'createTime'){ %>
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
<% } %>
},
<% } %>

View File

@@ -82,13 +82,6 @@
<% } %>
<if test="param.keywords != null">
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}, '%')
<% } %>
<% } %>
)
</if>
</where>