定时任务修正
This commit is contained in:
@@ -148,7 +148,6 @@ INSERT INTO `tb_sys_menu` VALUES
|
||||
('4001', 'menu_admin_banner', 'Banner管理', 'menu_admin_content_manage', '/admin/manage/content/banner', 'admin/manage/content/BannerManagementView', NULL, 1, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||
('4002', 'menu_admin_tag', '标签管理', 'menu_admin_content_manage', '/admin/manage/content/tag', 'admin/manage/content/TagManagementView', NULL, 2, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||
('4003', 'menu_admin_column', '栏目管理', 'menu_admin_content_manage', '/admin/manage/content/column', 'admin/manage/content/ColumnManagementView', NULL, 3, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||
('4004', 'menu_admin_content', '内容管理', 'menu_admin_content_manage', '/admin/manage/content/content', 'admin/manage/content/ContentManagementView', NULL, 4, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||
('5000', 'menu_admin_study_manage', '学习管理', NULL, '', '', 'admin/study.svg', 5, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:52:46', NULL, 0),
|
||||
('5002', 'menu_admin_task_manage', '任务管理', 'menu_admin_study_manage', '/admin/manage/study/task-manage', 'admin/manage/study/TaskManageView', NULL, 2, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
('5003', 'menu_admin_study_records', '学习记录', 'menu_admin_study_manage', '/admin/manage/study/study-records', 'admin/manage/study/StudyRecordsView', NULL, 3, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||
@@ -211,7 +210,6 @@ INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, creat
|
||||
('214', 'perm_news_manage', 'menu_admin_banner', '1', now()),
|
||||
('215', 'perm_news_manage', 'menu_admin_tag', '1', now()),
|
||||
('216', 'perm_news_manage', 'menu_admin_column', '1', now()),
|
||||
('217', 'perm_news_manage', 'menu_admin_content', '1', now()),
|
||||
('218', 'perm_study_manage', 'menu_admin_study_manage', '1', now()),
|
||||
('220', 'perm_study_manage', 'menu_admin_task_manage', '1', now()),
|
||||
('221', 'perm_study_manage', 'menu_admin_study_records', '1', now()),
|
||||
|
||||
@@ -39,11 +39,11 @@ public interface ResourceService {
|
||||
* @description 获取资源分页(按浏览次数排序)
|
||||
* @param filter 过滤条件
|
||||
* @param pageParam 分页参数
|
||||
* @return ResultDomain<TbResource> 资源分页
|
||||
* @return ResultDomain<ResourceVO> 资源分页(包含推荐信息)
|
||||
* @author yslg
|
||||
* @since 2025-10-15
|
||||
*/
|
||||
ResultDomain<TbResource> getResourcePageOrderByViewCount(TbResource filter, PageParam pageParam);
|
||||
ResultDomain<ResourceVO> getResourcePageOrderByViewCount(TbResource filter, PageParam pageParam);
|
||||
/**
|
||||
* @description 根据ID获取资源详情
|
||||
* @param resourceID 资源ID
|
||||
|
||||
@@ -97,8 +97,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
logger.debug("用户认证成功(从缓存),userId: {}", userId);
|
||||
|
||||
// 记录UV:以用户ID为维度,按天去重
|
||||
try {
|
||||
String today = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
|
||||
@@ -25,14 +25,14 @@ public class ResourceVO implements Serializable{
|
||||
private List<TbTag> tags;
|
||||
|
||||
/**
|
||||
* 是否推荐(用于首页展示)
|
||||
* 是否为TOP推荐
|
||||
*/
|
||||
private Boolean isRecommended;
|
||||
private Boolean isTopRecommend;
|
||||
|
||||
/**
|
||||
* 推荐类型(1-热门资源,2-思政资源)
|
||||
* 是否为思政推荐
|
||||
*/
|
||||
private Integer recommendType;
|
||||
private Boolean isIdeologicalRecommend;
|
||||
|
||||
public TbResource getResource() {
|
||||
return resource;
|
||||
@@ -50,19 +50,19 @@ public class ResourceVO implements Serializable{
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public Boolean getIsRecommended() {
|
||||
return isRecommended;
|
||||
public Boolean getIsTopRecommend() {
|
||||
return isTopRecommend;
|
||||
}
|
||||
|
||||
public void setIsRecommended(Boolean isRecommended) {
|
||||
this.isRecommended = isRecommended;
|
||||
public void setIsTopRecommend(Boolean isTopRecommend) {
|
||||
this.isTopRecommend = isTopRecommend;
|
||||
}
|
||||
|
||||
public Integer getRecommendType() {
|
||||
return recommendType;
|
||||
public Boolean getIsIdeologicalRecommend() {
|
||||
return isIdeologicalRecommend;
|
||||
}
|
||||
|
||||
public void setRecommendType(Integer recommendType) {
|
||||
this.recommendType = recommendType;
|
||||
public void setIsIdeologicalRecommend(Boolean isIdeologicalRecommend) {
|
||||
this.isIdeologicalRecommend = isIdeologicalRecommend;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabTask;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabLog;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.crontab.pojo.CrontabItem;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
@@ -19,7 +18,6 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import org.xyzh.common.utils.spring.SpringContextUtil;
|
||||
import org.xyzh.crontab.config.CrontabProperties;
|
||||
|
||||
import java.util.Date;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@@ -57,7 +55,6 @@ public class CrontabController {
|
||||
method->{
|
||||
method.setClazz(null);
|
||||
method.setExcuete_method(null);
|
||||
method.setPath(null);
|
||||
}));
|
||||
rd.success("ok", props.getItems());
|
||||
} catch (Exception e) {
|
||||
@@ -75,25 +72,41 @@ public class CrontabController {
|
||||
public ResultDomain<TbCrontabTask> createCrontab(@RequestBody TbCrontabTask crontabItem) {
|
||||
ResultDomain<TbCrontabTask> rd = new ResultDomain<>();
|
||||
try {
|
||||
// 根据taskGroup和methodName查找配置并填充beanName和methodName
|
||||
if (crontabItem.getBeanName() == null || crontabItem.getBeanName().isEmpty()) {
|
||||
CrontabItem.CrontabMethod method = findMethodByTaskGroupAndMethodName(
|
||||
crontabItem.getTaskGroup(),
|
||||
crontabItem.getMethodName()
|
||||
);
|
||||
if (method != null) {
|
||||
crontabItem.setBeanName(method.getClazz()); // 设置Bean名称
|
||||
crontabItem.setMethodName(method.getExcuete_method()); // 设置执行方法名
|
||||
JSONObject methodParams = JSON.parseObject(crontabItem.getMethodParams());
|
||||
methodParams.put("scriptPath", method.getPath());
|
||||
crontabItem.setMethodParams(methodParams.toJSONString());
|
||||
|
||||
} else {
|
||||
rd.fail("未找到对应的配置: taskGroup=" + crontabItem.getTaskGroup()
|
||||
+ ", methodName=" + crontabItem.getMethodName());
|
||||
return rd;
|
||||
}
|
||||
// 根据前端传入的taskGroup和methodName(都是中文显示名)查找配置
|
||||
if (crontabItem.getTaskGroup() == null || crontabItem.getTaskGroup().isEmpty()) {
|
||||
rd.fail("任务分组不能为空");
|
||||
return rd;
|
||||
}
|
||||
if (crontabItem.getMethodName() == null || crontabItem.getMethodName().isEmpty()) {
|
||||
rd.fail("方法名称不能为空");
|
||||
return rd;
|
||||
}
|
||||
|
||||
// 根据taskGroup和methodName查找配置
|
||||
CrontabItem.CrontabMethod method = findMethodByTaskGroupAndMethodName(
|
||||
crontabItem.getTaskGroup(),
|
||||
crontabItem.getMethodName()
|
||||
);
|
||||
|
||||
if (method != null) {
|
||||
// 填充beanName和实际的Java方法名
|
||||
crontabItem.setBeanName(method.getClazz());
|
||||
crontabItem.setMethodName(method.getExcuete_method());
|
||||
|
||||
// 将scriptPath添加到methodParams中
|
||||
JSONObject methodParams = JSON.parseObject(crontabItem.getMethodParams());
|
||||
methodParams.put("scriptPath", method.getPath());
|
||||
crontabItem.setMethodParams(methodParams.toJSONString());
|
||||
|
||||
logger.info("创建任务 - taskGroup: {}, methodName: {}, beanName: {}, excuete_method: {}, scriptPath: {}",
|
||||
crontabItem.getTaskGroup(), method.getName(), method.getClazz(),
|
||||
method.getExcuete_method(), method.getPath());
|
||||
} else {
|
||||
rd.fail("未找到对应的配置: taskGroup=" + crontabItem.getTaskGroup()
|
||||
+ ", methodName=" + crontabItem.getMethodName());
|
||||
return rd;
|
||||
}
|
||||
|
||||
return crontabService.createTask(crontabItem);
|
||||
} catch (Exception e) {
|
||||
logger.error("创建定时任务失败", e);
|
||||
@@ -132,21 +145,46 @@ public class CrontabController {
|
||||
public ResultDomain<TbCrontabTask> updateCrontab(@RequestBody TbCrontabTask crontabItem) {
|
||||
ResultDomain<TbCrontabTask> rd = new ResultDomain<>();
|
||||
try {
|
||||
// 根据taskGroup和methodName查找配置并填充beanName和methodName
|
||||
if (crontabItem.getBeanName() == null || crontabItem.getBeanName().isEmpty()) {
|
||||
CrontabItem.CrontabMethod method = findMethodByTaskGroupAndMethodName(
|
||||
crontabItem.getTaskGroup(),
|
||||
crontabItem.getMethodName()
|
||||
);
|
||||
if (method != null) {
|
||||
crontabItem.setBeanName(method.getClazz()); // 设置Bean名称
|
||||
crontabItem.setMethodName(method.getExcuete_method()); // 设置执行方法名
|
||||
} else {
|
||||
rd.fail("未找到对应的配置: taskGroup=" + crontabItem.getTaskGroup()
|
||||
+ ", methodName=" + crontabItem.getMethodName());
|
||||
return rd;
|
||||
}
|
||||
// 确保id字段正确传递(用于数据库更新)
|
||||
if (crontabItem.getTaskId() != null && crontabItem.getID() == null) {
|
||||
crontabItem.setID(crontabItem.getTaskId());
|
||||
}
|
||||
|
||||
// 根据前端传入的taskGroup和methodName(都是中文显示名)查找配置
|
||||
if (crontabItem.getTaskGroup() == null || crontabItem.getTaskGroup().isEmpty()) {
|
||||
rd.fail("任务分组不能为空");
|
||||
return rd;
|
||||
}
|
||||
if (crontabItem.getMethodName() == null || crontabItem.getMethodName().isEmpty()) {
|
||||
rd.fail("方法名称不能为空");
|
||||
return rd;
|
||||
}
|
||||
|
||||
// 根据taskGroup和methodName查找配置
|
||||
CrontabItem.CrontabMethod method = findMethodByTaskGroupAndMethodName(
|
||||
crontabItem.getTaskGroup(),
|
||||
crontabItem.getMethodName()
|
||||
);
|
||||
|
||||
if (method != null) {
|
||||
// 填充beanName和实际的Java方法名
|
||||
crontabItem.setBeanName(method.getClazz());
|
||||
crontabItem.setMethodName(method.getExcuete_method());
|
||||
|
||||
// 将scriptPath添加到methodParams中
|
||||
JSONObject methodParams = JSON.parseObject(crontabItem.getMethodParams());
|
||||
methodParams.put("scriptPath", method.getPath());
|
||||
crontabItem.setMethodParams(methodParams.toJSONString());
|
||||
|
||||
logger.info("更新任务 - id: {}, taskGroup: {}, methodName: {}, beanName: {}, excuete_method: {}, scriptPath: {}",
|
||||
crontabItem.getID(), crontabItem.getTaskGroup(), method.getName(), method.getClazz(),
|
||||
method.getExcuete_method(), method.getPath());
|
||||
} else {
|
||||
rd.fail("未找到对应的配置: taskGroup=" + crontabItem.getTaskGroup()
|
||||
+ ", methodName=" + crontabItem.getMethodName());
|
||||
return rd;
|
||||
}
|
||||
|
||||
return crontabService.updateTask(crontabItem);
|
||||
} catch (Exception e) {
|
||||
logger.error("更新定时任务失败", e);
|
||||
|
||||
@@ -18,8 +18,6 @@ import org.xyzh.crontab.mapper.CrontabTaskMapper;
|
||||
import org.xyzh.crontab.mapper.CrontabLogMapper;
|
||||
import org.xyzh.crontab.scheduler.SchedulerManager;
|
||||
import org.xyzh.api.system.permission.ResourcePermissionService;
|
||||
import org.xyzh.common.dto.user.TbSysUser;
|
||||
import org.xyzh.common.dto.user.TbSysUserDeptRole;
|
||||
import org.xyzh.common.core.enums.ResourceType;
|
||||
import org.xyzh.system.utils.LoginUtil;
|
||||
|
||||
@@ -122,7 +120,7 @@ public class CrontabServiceImpl implements CrontabService {
|
||||
public ResultDomain<TbCrontabTask> updateTask(TbCrontabTask task) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (task.getID() == null) {
|
||||
if (task.getTaskId() == null) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
@@ -140,7 +138,7 @@ public class CrontabServiceImpl implements CrontabService {
|
||||
logger.info("更新定时任务成功: {}", task.getTaskName());
|
||||
|
||||
// 重新调度任务
|
||||
TbCrontabTask dbTask = taskMapper.selectTaskById(task.getID());
|
||||
TbCrontabTask dbTask = taskMapper.selectTaskById(task.getTaskId());
|
||||
if (dbTask != null && dbTask.getStatus() == 1) {
|
||||
schedulerManager.rescheduleTask(dbTask);
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@ public class ResourceController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源分页(按浏览次数排序)
|
||||
* 获取资源分页(按浏览次数排序,包含推荐信息)
|
||||
*/
|
||||
@PostMapping("/page/view-count")
|
||||
public ResultDomain<TbResource> getResourcePageOrderByViewCount(@RequestBody PageRequest<TbResource> request) {
|
||||
public ResultDomain<ResourceVO> getResourcePageOrderByViewCount(@RequestBody PageRequest<TbResource> request) {
|
||||
TbResource filter = request.getFilter();
|
||||
PageParam pageParam = request.getPageParam();
|
||||
return resourceService.getResourcePageOrderByViewCount(filter, pageParam);
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.dto.resource.TbResource;
|
||||
import org.xyzh.common.vo.ResourceVO;
|
||||
import org.xyzh.common.vo.UserDeptRoleVO;
|
||||
|
||||
import java.util.List;
|
||||
@@ -166,16 +167,15 @@ public interface ResourceMapper extends BaseMapper<TbResource> {
|
||||
List<TbResource> selectResourcesPage(@Param("filter") TbResource filter, @Param("pageParam") PageParam pageParam, @Param("userDeptRoles") List<UserDeptRoleVO> userDeptRoles);
|
||||
|
||||
/**
|
||||
* @description 分页查询资源
|
||||
* @description 获取资源分页(按浏览次数排序,包含推荐信息)
|
||||
* @param filter 过滤条件
|
||||
* @param pageParam 分页参数
|
||||
* @param userDeptRoles 用户部门角色列表
|
||||
* @return List<TbResource> 资源列表
|
||||
* @return List<ResourceVO> 资源VO列表(包含推荐信息)
|
||||
* @author yslg
|
||||
* @since 2025-10-15
|
||||
*/
|
||||
List<TbResource> selectResourcesPageOrderByViewCount(@Param("filter") TbResource filter, @Param("pageParam") PageParam pageParam, @Param("userDeptRoles") List<UserDeptRoleVO> userDeptRoles);
|
||||
|
||||
List<ResourceVO> selectResourcesPageOrderByViewCount(@Param("filter") TbResource filter, @Param("pageParam") PageParam pageParam, @Param("userDeptRoles") List<UserDeptRoleVO> userDeptRoles);
|
||||
|
||||
/**
|
||||
* @description 统计资源总数
|
||||
|
||||
@@ -96,19 +96,21 @@ public class NCResourceServiceImpl implements ResourceService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbResource> getResourcePageOrderByViewCount(TbResource filter, PageParam pageParam) {
|
||||
ResultDomain<TbResource> resultDomain = new ResultDomain<>();
|
||||
public ResultDomain<ResourceVO> getResourcePageOrderByViewCount(TbResource filter, PageParam pageParam) {
|
||||
ResultDomain<ResourceVO> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (filter == null) {
|
||||
filter = new TbResource();
|
||||
}
|
||||
// 获取当前用户的部门角色
|
||||
List<UserDeptRoleVO> userDeptRoles = LoginUtil.getCurrentDeptRole();
|
||||
List<TbResource> list = resourceMapper.selectResourcesPageOrderByViewCount(filter, pageParam, userDeptRoles);
|
||||
// 直接查询ResourceVO列表,SQL已经LEFT JOIN了recommend表
|
||||
List<ResourceVO> resourceVOList = resourceMapper.selectResourcesPageOrderByViewCount(filter, pageParam, userDeptRoles);
|
||||
long total = resourceMapper.countResources(filter, userDeptRoles);
|
||||
pageParam.setTotalElements(total);
|
||||
pageParam.setTotalPages((int) Math.ceil((double) total / pageParam.getPageSize()));
|
||||
resultDomain.success("获取资源分页(按浏览次数排序)成功", new PageDomain<TbResource>(pageParam, list));
|
||||
|
||||
resultDomain.success("获取资源分页(按浏览次数排序)成功", new PageDomain<ResourceVO>(pageParam, resourceVOList));
|
||||
return resultDomain;
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
@@ -336,9 +336,44 @@
|
||||
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
|
||||
</select>
|
||||
|
||||
<select id="selectResourcesPageOrderByViewCount" resultMap="BaseResultMap">
|
||||
SELECT DISTINCT r.*
|
||||
<!-- ResourceVO结果映射(包含推荐信息) -->
|
||||
<resultMap id="ResourceVOResultMap" type="org.xyzh.common.vo.ResourceVO">
|
||||
<result column="is_top_recommend" property="isTopRecommend" jdbcType="BOOLEAN"/>
|
||||
<result column="is_ideological_recommend" property="isIdeologicalRecommend" jdbcType="BOOLEAN"/>
|
||||
<association property="resource" javaType="org.xyzh.common.dto.resource.TbResource">
|
||||
<id column="id" property="id" jdbcType="VARCHAR"/>
|
||||
<result column="resource_id" property="resourceID" jdbcType="VARCHAR"/>
|
||||
<result column="title" property="title" jdbcType="VARCHAR"/>
|
||||
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
|
||||
<result column="summary" property="summary" jdbcType="VARCHAR"/>
|
||||
<result column="cover_image" property="coverImage" jdbcType="VARCHAR"/>
|
||||
<result column="tag_id" property="tagID" jdbcType="VARCHAR"/>
|
||||
<result column="author" property="author" jdbcType="VARCHAR"/>
|
||||
<result column="source" property="source" jdbcType="VARCHAR"/>
|
||||
<result column="source_url" property="sourceUrl" jdbcType="VARCHAR"/>
|
||||
<result column="view_count" property="viewCount" jdbcType="INTEGER"/>
|
||||
<result column="like_count" property="likeCount" jdbcType="INTEGER"/>
|
||||
<result column="collect_count" property="collectCount" jdbcType="INTEGER"/>
|
||||
<result column="status" property="status" jdbcType="INTEGER"/>
|
||||
<result column="is_recommend" property="isRecommend" jdbcType="BOOLEAN"/>
|
||||
<result column="is_banner" property="isBanner" jdbcType="BOOLEAN"/>
|
||||
<result column="publish_time" property="publishTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="creator" property="creator" jdbcType="VARCHAR"/>
|
||||
<result column="updater" property="updater" jdbcType="VARCHAR"/>
|
||||
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="delete_time" property="deleteTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="deleted" property="deleted" jdbcType="BOOLEAN"/>
|
||||
</association>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectResourcesPageOrderByViewCount" resultMap="ResourceVOResultMap">
|
||||
SELECT
|
||||
r.*,
|
||||
MAX(CASE WHEN rec.recommend_type = 1 THEN 1 ELSE 0 END) AS is_top_recommend,
|
||||
MAX(CASE WHEN rec.recommend_type = 2 THEN 1 ELSE 0 END) AS is_ideological_recommend
|
||||
FROM tb_resource r
|
||||
LEFT JOIN tb_resource_recommend rec ON r.resource_id = rec.resource_id AND rec.deleted = 0
|
||||
<include refid="Permission_Filter"/>
|
||||
WHERE r.deleted = 0
|
||||
<if test="filter.title != null and filter.title != ''">
|
||||
@@ -359,6 +394,10 @@
|
||||
<if test="filter.isBanner != null">
|
||||
AND r.is_banner = #{filter.isBanner}
|
||||
</if>
|
||||
GROUP BY r.id, r.resource_id, r.title, r.content, r.summary, r.cover_image, r.tag_id,
|
||||
r.author, r.source, r.source_url, r.view_count, r.like_count, r.collect_count,
|
||||
r.status, r.is_recommend, r.is_banner, r.publish_time, r.creator, r.updater,
|
||||
r.create_time, r.update_time, r.delete_time, r.deleted
|
||||
ORDER BY r.view_count DESC, r.publish_time DESC, r.create_time DESC
|
||||
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user