This commit is contained in:
@jyuhsin
2025-11-22 15:57:31 +08:00
parent e865951a7c
commit 34dc3b118c
13 changed files with 517 additions and 485 deletions
@@ -41,190 +41,193 @@ import java.util.*;
@Slf4j @Slf4j
public class FlowDesignController { public class FlowDesignController {
@Inject @Inject
private SysUserService sysUserService; private SysUserService sysUserService;
@Inject @Inject
private ProcessDesignService processDesignService; private ProcessDesignService processDesignService;
@Inject @Inject
private Dao dao; private Dao dao;
// 获取所有任务参与者处理类 // 获取所有任务参与者处理类
public static final List<JSONObject> ASSIGMENT_HANDLER_LIST; public static final List<JSONObject> ASSIGMENT_HANDLER_LIST;
// 获取所有候选用户处理类 // 获取所有候选用户处理类
public static final List<JSONObject> CANDIDATE_HANDLER_LIST; public static final List<JSONObject> CANDIDATE_HANDLER_LIST;
static { static {
Set<Class<?>> classes = ClassScanner.scanPackageBySuper("com.budwk.app", AssignmentHandler.class); Set<Class<?>> classes = ClassScanner.scanPackageBySuper("com.budwk.app", AssignmentHandler.class);
ArrayList<JSONObject> list = new ArrayList<>(classes.size()); ArrayList<JSONObject> list = new ArrayList<>(classes.size());
for (Class<?> aClass : classes) { for (Class<?> aClass : classes) {
try { try {
AssignmentHandler handler = (AssignmentHandler) ReflectUtil.newInstance(aClass); AssignmentHandler handler = (AssignmentHandler) ReflectUtil.newInstance(aClass);
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.set("value", handler.getClass().getName()); jsonObject.set("value", handler.getClass().getName());
jsonObject.set("order", handler.getOrder()); jsonObject.set("order", handler.getOrder());
jsonObject.set("name", handler.getMessage()); jsonObject.set("name", handler.getMessage());
list.add(jsonObject); list.add(jsonObject);
} catch (Exception e) { } catch (Exception e) {
log.error("初始化AssignmentHandler失败: {}", aClass.getName()); log.error("初始化AssignmentHandler失败: {}", aClass.getName());
} }
} }
// 排序 按order // 排序 按order
list.sort(Comparator.comparingInt(o -> o.getInt("order"))); list.sort(Comparator.comparingInt(o -> o.getInt("order")));
ASSIGMENT_HANDLER_LIST = Collections.unmodifiableList(list); ASSIGMENT_HANDLER_LIST = Collections.unmodifiableList(list);
} }
static { static {
Set<Class<?>> classes = ClassScanner.scanPackageBySuper("com.budwk.app", CandidateHandler.class); Set<Class<?>> classes = ClassScanner.scanPackageBySuper("com.budwk.app", CandidateHandler.class);
ArrayList<JSONObject> list = new ArrayList<>(classes.size()); ArrayList<JSONObject> list = new ArrayList<>(classes.size());
for (Class<?> aClass : classes) { for (Class<?> aClass : classes) {
try { try {
CandidateHandler handler = (CandidateHandler) ReflectUtil.newInstance(aClass); CandidateHandler handler = (CandidateHandler) ReflectUtil.newInstance(aClass);
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.set("value", handler.getClass().getName()); jsonObject.set("value", handler.getClass().getName());
jsonObject.set("order", handler.getOrder()); jsonObject.set("order", handler.getOrder());
jsonObject.set("name", handler.getMessage()); jsonObject.set("name", handler.getMessage());
list.add(jsonObject); list.add(jsonObject);
} catch (Exception e) { } catch (Exception e) {
log.error("初始化CandidateHandler失败: {}", aClass.getName()); log.error("初始化CandidateHandler失败: {}", aClass.getName());
} }
} }
// 排序 按order // 排序 按order
list.sort(Comparator.comparingInt(o -> o.getInt("order"))); list.sort(Comparator.comparingInt(o -> o.getInt("order")));
CANDIDATE_HANDLER_LIST = Collections.unmodifiableList(list); CANDIDATE_HANDLER_LIST = Collections.unmodifiableList(list);
} }
@At("") @At("")
@Ok("beetl:/platform/flow/design/index.html") @Ok("beetl:/platform/flow/design/index.html")
@SaCheckPermission("flow.design") @SaCheckPermission("flow.design")
public void index() { public void index() {
} }
@At @At
@Ok("beetl:/platform/flow/design/designer.html") @Ok("beetl:/platform/flow/design/designer.html")
@SaCheckLogin @SaCheckLogin
public void designer(HttpServletRequest request) { public void designer(HttpServletRequest request) {
request.setAttribute("id", request.getParameter("id")); request.setAttribute("id", request.getParameter("id"));
} }
@At @At
@ApiOperation("获取流程设计分页列表") @ApiOperation("获取流程设计分页列表")
@SaCheckPermission("flow.design") @SaCheckPermission("flow.design")
public Result pageData(PageForm pageForm, String displayName, String name, String category, Boolean deployed) { public Result pageData(PageForm pageForm, String displayName, String name, String category, Boolean deployed) {
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
cnd.and(Cnd.likeEX(ProcessDesign::getDisplayName, displayName)); cnd.and(Cnd.likeEX(ProcessDesign::getDisplayName, displayName));
cnd.and(Cnd.likeEX(ProcessDesign::getName, name)); cnd.and(Cnd.likeEX(ProcessDesign::getName, name));
cnd.andEX(ProcessDesign::getCategory, "=", category); cnd.andEX(ProcessDesign::getCategory, "=", category);
cnd.andEX(ProcessDesign::getIsDeployed, "=", deployed); cnd.andEX(ProcessDesign::getIsDeployed, "=", deployed);
Pagination pagination = processDesignService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd); Pagination pagination = processDesignService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
return Result.success(pagination); return Result.success(pagination);
} }
@At @At
@ApiOperation("保存流程设计") @ApiOperation("保存流程设计")
@SaCheckPermission("flow.design") @SaCheckPermission("flow.design")
public Result insert(@Param("design") ProcessDesign processDesign) { public Result insert(@Param("design") ProcessDesign processDesign) {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.set("name", processDesign.getName()); jsonObject.set("name", processDesign.getName());
jsonObject.set("displayName", processDesign.getDisplayName()); jsonObject.set("displayName", processDesign.getDisplayName());
jsonObject.set("category", processDesign.getCategory()); jsonObject.set("category", processDesign.getCategory());
jsonObject.set("instanceUrl", processDesign.getInstanceUrl()); jsonObject.set("instanceUrl", processDesign.getInstanceUrl());
jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl()); jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl());
jsonObject.set("instanceViewUrl", processDesign.getInstanceViewUrl()); jsonObject.set("instanceViewUrl", processDesign.getInstanceViewUrl());
jsonObject.set("h5InstanceViewUrl", processDesign.getH5InstanceViewUrl()); jsonObject.set("h5InstanceViewUrl", processDesign.getH5InstanceViewUrl());
jsonObject.set("icon", processDesign.getIcon()); jsonObject.set("icon", processDesign.getIcon());
jsonObject.set("description", processDesign.getDescription()); jsonObject.set("picIcon", processDesign.getPicIcon());
processDesign.setContent(jsonObject); jsonObject.set("description", processDesign.getDescription());
dao.insert(processDesign); processDesign.setContent(jsonObject);
return Result.success(); dao.insert(processDesign);
} return Result.success();
}
@At @At
@ApiOperation("修改流程设计") @ApiOperation("修改流程设计")
@SaCheckPermission("flow.design") @SaCheckPermission("flow.design")
public Result update(@Param("design") ProcessDesign processDesign) { public Result update(@Param("design") ProcessDesign processDesign) {
JSONObject jsonObject = processDesign.getContent(); JSONObject jsonObject = processDesign.getContent();
jsonObject.set("name", processDesign.getName()); jsonObject.set("name", processDesign.getName());
jsonObject.set("displayName", processDesign.getDisplayName()); jsonObject.set("displayName", processDesign.getDisplayName());
jsonObject.set("category", processDesign.getCategory()); jsonObject.set("category", processDesign.getCategory());
jsonObject.set("instanceUrl", processDesign.getInstanceUrl()); jsonObject.set("instanceUrl", processDesign.getInstanceUrl());
jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl()); jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl());
jsonObject.set("instanceViewUrl", processDesign.getInstanceViewUrl()); jsonObject.set("instanceViewUrl", processDesign.getInstanceViewUrl());
jsonObject.set("h5InstanceViewUrl", processDesign.getH5InstanceViewUrl()); jsonObject.set("h5InstanceViewUrl", processDesign.getH5InstanceViewUrl());
jsonObject.set("icon", processDesign.getIcon()); jsonObject.set("icon", processDesign.getIcon());
jsonObject.set("description", processDesign.getDescription()); jsonObject.set("picIcon", processDesign.getPicIcon());
processDesign.setContent(jsonObject); jsonObject.set("description", processDesign.getDescription());
processDesignService.update(processDesign); processDesign.setContent(jsonObject);
return Result.success(); processDesignService.update(processDesign);
} return Result.success();
}
@At @At
@ApiOperation("修改流程设计") @ApiOperation("修改流程设计")
@SaCheckPermission("flow.design") @SaCheckPermission("flow.design")
public Result updateContent(@Param("design") ProcessDesign processDesign) { public Result updateContent(@Param("design") ProcessDesign processDesign) {
JSONObject jsonObject = processDesign.getContent(); JSONObject jsonObject = processDesign.getContent();
jsonObject.set("name", processDesign.getName()); jsonObject.set("name", processDesign.getName());
jsonObject.set("displayName", processDesign.getDisplayName()); jsonObject.set("displayName", processDesign.getDisplayName());
jsonObject.set("category", processDesign.getCategory()); jsonObject.set("category", processDesign.getCategory());
jsonObject.set("instanceUrl", processDesign.getInstanceUrl()); jsonObject.set("instanceUrl", processDesign.getInstanceUrl());
jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl()); jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl());
jsonObject.set("instanceViewUrl", processDesign.getInstanceViewUrl()); jsonObject.set("instanceViewUrl", processDesign.getInstanceViewUrl());
jsonObject.set("h5InstanceViewUrl", processDesign.getH5InstanceViewUrl()); jsonObject.set("h5InstanceViewUrl", processDesign.getH5InstanceViewUrl());
jsonObject.set("icon", processDesign.getIcon()); jsonObject.set("icon", processDesign.getIcon());
jsonObject.set("description", processDesign.getDescription()); jsonObject.set("picIcon", processDesign.getPicIcon());
processDesign.setContent(jsonObject); jsonObject.set("description", processDesign.getDescription());
processDesignService.update(processDesign); processDesign.setContent(jsonObject);
return Result.success(); processDesignService.update(processDesign);
} return Result.success();
}
@At @At
@ApiOperation("删除流程设计") @ApiOperation("删除流程设计")
@SaCheckPermission("flow.design") @SaCheckPermission("flow.design")
public Result delete(@Param("id") Long id) { public Result delete(@Param("id") Long id) {
dao.delete(ProcessDesign.class, id); dao.delete(ProcessDesign.class, id);
return Result.success(); return Result.success();
} }
@At @At
@SaCheckLogin @SaCheckLogin
@ApiOperation("流程设计详情") @ApiOperation("流程设计详情")
public Result detail(@Param("id") Long id) { public Result detail(@Param("id") Long id) {
ProcessDesign design = dao.fetch(ProcessDesign.class, id); ProcessDesign design = dao.fetch(ProcessDesign.class, id);
return Result.success(design); return Result.success(design);
} }
@At @At
@ApiOperation("发布流程设计") @ApiOperation("发布流程设计")
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("flow.design") @SaCheckPermission("flow.design")
public Result deploy(@Param("id") Long id) { public Result deploy(@Param("id") Long id) {
processDesignService.deploy(id); processDesignService.deploy(id);
return Result.success(); return Result.success();
} }
@At @At
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取流程设计任务参与者处理类") @ApiOperation("获取流程设计任务参与者处理类")
public Result assigmentHandlerClass() { public Result assigmentHandlerClass() {
return Result.success(ASSIGMENT_HANDLER_LIST); return Result.success(ASSIGMENT_HANDLER_LIST);
} }
@At @At
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取流程设计任务参与者处理类") @ApiOperation("获取流程设计任务参与者处理类")
public Result candidateHandlerClass() { public Result candidateHandlerClass() {
return Result.success(CANDIDATE_HANDLER_LIST); return Result.success(CANDIDATE_HANDLER_LIST);
} }
@At @At
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取流程设计任务参与者分页数据") @ApiOperation("获取流程设计任务参与者分页数据")
public Result assigneePage(Integer pageNumber, Integer pageSize, String searchKeyword, @Param("userIds") String[] userIds) { public Result assigneePage(Integer pageNumber, Integer pageSize, String searchKeyword, @Param("userIds") String[] userIds) {
Sql sql = Sqls.create("select id,loginname,username,unitName from vw_user $condition"); Sql sql = Sqls.create("select id,loginname,username,unitName from vw_user $condition");
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
if(StrUtil.isNotBlank(searchKeyword)) { if(StrUtil.isNotBlank(searchKeyword)) {
SqlExpressionGroup group = new SqlExpressionGroup(); SqlExpressionGroup group = new SqlExpressionGroup();
group.orLike("username", searchKeyword); group.orLike("username", searchKeyword);
@@ -233,17 +236,17 @@ public class FlowDesignController {
} }
sql.setCondition(cnd); sql.setCondition(cnd);
// cnd.andEX("id", "in", userIds); // cnd.andEX("id", "in", userIds);
Pagination pagination = sysUserService.listPageMap(pageNumber, pageSize, sql); Pagination pagination = sysUserService.listPageMap(pageNumber, pageSize, sql);
return Result.success(pagination); return Result.success(pagination);
} }
@At @At
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取流程设计任务参与者分页数据回显") @ApiOperation("获取流程设计任务参与者分页数据回显")
public Result assigneeEcho(@Param("userIds") String[] userIds) { public Result assigneeEcho(@Param("userIds") String[] userIds) {
Sql sql = Sqls.create("select id,loginname,username,unitName from vw_user where id in (@userIds)"); Sql sql = Sqls.create("select id,loginname,username,unitName from vw_user where id in (@userIds)");
sql.setParam("userIds", userIds); sql.setParam("userIds", userIds);
List<NutMap> list = sysUserService.listMap(sql); List<NutMap> list = sysUserService.listMap(sql);
return Result.success(list); return Result.success(list);
} }
} }
@@ -12,20 +12,25 @@ import org.nutz.dao.interceptor.annotation.PrevInsert;
@Comment("流程分类") @Comment("流程分类")
public class ProcessCategory extends BaseModel { public class ProcessCategory extends BaseModel {
@Name @Name
@Comment("ID") @Comment("ID")
@PrevInsert(uu32 = true) @PrevInsert(uu32 = true)
@ColDefine(type = ColType.VARCHAR, width = 32) @ColDefine(type = ColType.VARCHAR, width = 32)
private String id; private String id;
@Comment("名称") @Comment("名称")
@Column @Column
@ColDefine(type = ColType.VARCHAR, width = 10) @ColDefine(type = ColType.VARCHAR, width = 10)
private String name; private String name;
@Comment("图标") @Comment("片图")
@Column @Column
@ColDefine(type = ColType.VARCHAR, width = 255) @ColDefine(type = ColType.VARCHAR, width = 255)
private String icon; private String picIcon;
@Comment("图标")
@Column
@ColDefine(type = ColType.VARCHAR, width = 255)
private String icon;
} }
@@ -20,62 +20,66 @@ import org.nutz.dao.entity.annotation.*;
@Comment("流程设计") @Comment("流程设计")
public class ProcessDesign extends BaseModel { public class ProcessDesign extends BaseModel {
@Comment("主键") @Comment("主键")
@Id @Id
private Long id; private Long id;
@Comment("唯一编码") @Comment("唯一编码")
@Column @Column
private String name; private String name;
@Comment("显示名称") @Comment("显示名称")
@Column @Column
private String displayName; private String displayName;
@Comment("流程分类") @Comment("流程分类")
@Column @Column
private String type; private String type;
@Comment("流程分类") @Comment("流程分类")
@Column @Column
private String category; private String category;
@Comment("电脑端发起地址") @Comment("电脑端发起地址")
@Column @Column
private String instanceUrl; private String instanceUrl;
@Comment("手机端发起地址") @Comment("手机端发起地址")
@Column @Column
private String h5InstanceUrl; private String h5InstanceUrl;
@Comment("电脑端发起地址") @Comment("电脑端发起地址")
@Column @Column
private String instanceViewUrl; private String instanceViewUrl;
@Comment("手机端发起地址") @Comment("手机端发起地址")
@Column @Column
private String h5InstanceViewUrl; private String h5InstanceViewUrl;
@Comment("图标") @Comment("片图")
@Column @Column
private String icon; private String picIcon;
@Comment("是否已部署") @Comment("图标")
@Column @Column
private Integer isDeployed; private String icon;
@Comment("备注") @Comment("是否已部署")
@Column @Column
private String remark; private Integer isDeployed;
@Comment("流程描述") @Comment("备注")
@Column @Column
@ColDefine(type = ColType.TEXT) private String remark;
private String description;
@Comment("流程定义") @Comment("流程描述")
@Column @Column
@ColDefine(type = ColType.MYSQL_JSON) @ColDefine(type = ColType.TEXT)
private JSONObject content; private String description;
@Comment("流程定义")
@Column
@ColDefine(type = ColType.MYSQL_JSON)
private JSONObject content;
} }
@@ -35,36 +35,37 @@ import java.util.Map;
@Api(value = "应用中心接口", tags = "应用中心接口") @Api(value = "应用中心接口", tags = "应用中心接口")
public class SysV4AppsController { public class SysV4AppsController {
@Inject @Inject
private Dao dao; private Dao dao;
@Inject @Inject
private SysMenuService sysMenuService; private SysMenuService sysMenuService;
@Inject @Inject
private SysUserService sysUserService; private SysUserService sysUserService;
@At("/categories") @At("/categories")
@Ok("json") @Ok("json")
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取应用分类") @ApiOperation("获取应用分类")
public Result categories(@Param(value = "platform", df = "PC") String platform) { public Result categories(@Param(value = "platform", df = "PC") String platform) {
List<Sys_module> list = dao.query(Sys_module.class, Cnd.where(Sys_module::getPlatform, "=", platform).asc(Sys_module::getSortNum)); List<Sys_module> list = dao.query(Sys_module.class, Cnd.where(Sys_module::getPlatform, "=", platform).asc(Sys_module::getSortNum));
List<Map<String, Object>> categories = list.stream().map(module -> { List<Map<String, Object>> categories = list.stream().map(module -> {
Map<String, Object> category = new HashMap<>(); Map<String, Object> category = new HashMap<>();
category.put("id", module.getId()); category.put("id", module.getId());
category.put("name", module.getName()); category.put("name", module.getName());
category.put("icon", module.getIcon()); category.put("icon", module.getFaIcon());
return category; category.put("picIcon", module.getIcon());
}).toList(); return category;
return Result.success("获取应用分类成功").addData(categories); }).toList();
} return Result.success("获取应用分类成功").addData(categories);
}
@At("/list") @At("/list")
@Ok("json:full") @Ok("json:full")
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取应用列表") @ApiOperation("获取应用列表")
public Result list(@Param("categoryId") String categoryId, @Param("letter") String letter, @Param("keyword") String keyword, @Param(value = "platform", df = "PC") String platform, HttpServletRequest req) { public Result list(@Param("categoryId") String categoryId, @Param("letter") String letter, @Param("keyword") String keyword, @Param(value = "platform", df = "PC") String platform, HttpServletRequest req) {
List<Sys_menu> menus = sysUserService.getMenus(SecurityUtil.getUserId()); List<Sys_menu> menus = sysUserService.getMenus(SecurityUtil.getUserId());
Sql sql = Sqls.create(""" Sql sql = Sqls.create("""
SELECT SELECT
m.id, m.id,
m.`name`, m.`name`,
@@ -83,28 +84,28 @@ public class SysV4AppsController {
LEFT JOIN sys_module sm ON sm.id = m.moduleId LEFT JOIN sys_module sm ON sm.id = m.moduleId
$condition $condition
"""); """);
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
cnd.and("m.platform", "=", platform); cnd.and("m.platform", "=", platform);
cnd.and("m.disabled", "=", false); cnd.and("m.disabled", "=", false);
cnd.and(Cnd.exps("m.parentId", "is", null).or("m.parentId", "=", "")); cnd.and(Cnd.exps("m.parentId", "is", null).or("m.parentId", "=", ""));
cnd.and("m.id","in", menus.stream().map(Sys_menu::getId).toArray()); cnd.and("m.id","in", menus.stream().map(Sys_menu::getId).toArray());
cnd.andEX("m.moduleId", "=", categoryId); cnd.andEX("m.moduleId", "=", categoryId);
cnd.asc("m.location"); cnd.asc("m.location");
if (StrUtil.isNotBlank(keyword)) { if (StrUtil.isNotBlank(keyword)) {
cnd.where().andLike("m.name", keyword); cnd.where().andLike("m.name", keyword);
} }
cnd.andEX("m.initialPinyinName", "=", letter); cnd.andEX("m.initialPinyinName", "=", letter);
sql.setCondition(cnd); sql.setCondition(cnd);
sql.setParam("userId", SecurityUtil.getUserId()); sql.setParam("userId", SecurityUtil.getUserId());
List<NutMap> list = sysMenuService.listMap(sql); List<NutMap> list = sysMenuService.listMap(sql);
return Result.success(list); return Result.success(list);
} }
@At("/recommended") @At("/recommended")
@Ok("json") @Ok("json")
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取推荐应用") @ApiOperation("获取推荐应用")
public Result recommended(HttpServletRequest req) { public Result recommended(HttpServletRequest req) {
// // 这里简单地返回前6个应用作为推荐应用 // // 这里简单地返回前6个应用作为推荐应用
// int recommendCount = Math.min(6, APPS.size()); // int recommendCount = Math.min(6, APPS.size());
// List<Map<String, Object>> recommendedApps = new ArrayList<>(); // List<Map<String, Object>> recommendedApps = new ArrayList<>();
@@ -129,15 +130,15 @@ public class SysV4AppsController {
// data.put("pageSize", recommendedApps.size()); // data.put("pageSize", recommendedApps.size());
// data.put("totalPage", 1); // data.put("totalPage", 1);
return Result.success("获取推荐应用成功"); return Result.success("获取推荐应用成功");
} }
@At("/favorite") @At("/favorite")
@Ok("json:full") @Ok("json:full")
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取收藏的应用") @ApiOperation("获取收藏的应用")
public Result favorite(HttpServletRequest req) { public Result favorite(HttpServletRequest req) {
Sql sql = Sqls.create(""" Sql sql = Sqls.create("""
SELECT SELECT
m.id, m.id,
m.`name`, m.`name`,
@@ -160,39 +161,39 @@ public class SysV4AppsController {
ORDER BY ORDER BY
m.location ASC; m.location ASC;
"""); """);
sql.setParam("userId", SecurityUtil.getUserId()); sql.setParam("userId", SecurityUtil.getUserId());
List<NutMap> list = sysMenuService.listMap(sql); List<NutMap> list = sysMenuService.listMap(sql);
return Result.success(list); return Result.success(list);
} }
@At("/addFavorite") @At("/addFavorite")
@Ok("json") @Ok("json")
@SaCheckLogin @SaCheckLogin
@ApiOperation("添加收藏") @ApiOperation("添加收藏")
@Aop(TransAop.READ_COMMITTED) @Aop(TransAop.READ_COMMITTED)
public Result addFavorite(@Param("appId") String appId, HttpServletRequest req) { public Result addFavorite(@Param("appId") String appId, HttpServletRequest req) {
if (Strings.isBlank(appId)) { if (Strings.isBlank(appId)) {
return Result.error("应用ID不能为空"); return Result.error("应用ID不能为空");
} }
dao.clear(Sys_user_favorite_app.class, Cnd.where(Sys_user_favorite_app::getAppId, "=", appId).and(Sys_user_favorite_app::getUserId, "=", SecurityUtil.getUserId())); dao.clear(Sys_user_favorite_app.class, Cnd.where(Sys_user_favorite_app::getAppId, "=", appId).and(Sys_user_favorite_app::getUserId, "=", SecurityUtil.getUserId()));
Sys_user_favorite_app app = new Sys_user_favorite_app(); Sys_user_favorite_app app = new Sys_user_favorite_app();
app.setAppId(appId); app.setAppId(appId);
app.setUserId(SecurityUtil.getUserId()); app.setUserId(SecurityUtil.getUserId());
dao.insert(app); dao.insert(app);
return Result.success("收藏成功"); return Result.success("收藏成功");
} }
@At("/removeFavorite") @At("/removeFavorite")
@Ok("json") @Ok("json")
@SaCheckLogin @SaCheckLogin
@ApiOperation("取消收藏") @ApiOperation("取消收藏")
public Result removeFavorite(@Param("appId") String appId, HttpServletRequest req) { public Result removeFavorite(@Param("appId") String appId, HttpServletRequest req) {
if (Strings.isBlank(appId)) { if (Strings.isBlank(appId)) {
return Result.error("应用ID不能为空"); return Result.error("应用ID不能为空");
} }
dao.clear(Sys_user_favorite_app.class, Cnd.where(Sys_user_favorite_app::getAppId, "=", appId).and(Sys_user_favorite_app::getUserId, "=", SecurityUtil.getUserId())); dao.clear(Sys_user_favorite_app.class, Cnd.where(Sys_user_favorite_app::getAppId, "=", appId).and(Sys_user_favorite_app::getUserId, "=", SecurityUtil.getUserId()));
return Result.success("取消收藏成功"); return Result.success("取消收藏成功");
} }
} }
@@ -26,27 +26,27 @@ import java.util.List;
@Api(value = "服务中心接口", tags = "服务中心接口") @Api(value = "服务中心接口", tags = "服务中心接口")
public class SysV4ServController { public class SysV4ServController {
@Inject @Inject
private Dao dao; private Dao dao;
@Inject @Inject
private SysMenuService sysMenuService; private SysMenuService sysMenuService;
@At("/categories") @At("/categories")
@Ok("json") @Ok("json")
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取分类") @ApiOperation("获取分类")
public Result categories() { public Result categories() {
List<ProcessCategory> list = dao.query(ProcessCategory.class, Cnd.NEW()); List<ProcessCategory> list = dao.query(ProcessCategory.class, Cnd.NEW());
return Result.success(list); return Result.success(list);
} }
@At("/list") @At("/list")
@Ok("json:full") @Ok("json:full")
@SaCheckLogin @SaCheckLogin
@ApiOperation("获取应用列表") @ApiOperation("获取应用列表")
public Result list(@Param("categoryId") String categoryId, @Param("letter") String letter, @Param("keyword") String keyword, HttpServletRequest req) { public Result list(@Param("categoryId") String categoryId, @Param("letter") String letter, @Param("keyword") String keyword, HttpServletRequest req) {
Sql sql = Sqls.create(""" Sql sql = Sqls.create("""
SELECT t.* SELECT t.*,(select picIcon from wf_process_design where name = t.name) as picIcon
FROM wf_process_define t FROM wf_process_define t
INNER JOIN ( INNER JOIN (
SELECT name, MAX(id) AS max_id SELECT name, MAX(id) AS max_id
@@ -55,15 +55,15 @@ public class SysV4ServController {
) sub ON t.name = sub.name AND t.id = sub.max_id ) sub ON t.name = sub.name AND t.id = sub.max_id
$condition $condition
"""); """);
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(keyword)) { if (StrUtil.isNotBlank(keyword)) {
cnd.where().andLike("t.disPlayName", keyword); cnd.where().andLike("t.disPlayName", keyword);
} }
cnd.andEX("t.category", "=", categoryId); cnd.andEX("t.category", "=", categoryId);
sql.setCondition(cnd); sql.setCondition(cnd);
List<NutMap> list = sysMenuService.listMap(sql); List<NutMap> list = sysMenuService.listMap(sql);
return Result.success(list); return Result.success(list);
} }
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

+26 -22
View File
@@ -159,6 +159,7 @@ layout("/layouts/v4/baseLayout.html"){
align-items: center; align-items: center;
padding: 15px; padding: 15px;
position: relative; position: relative;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
} }
.app-card:hover { .app-card:hover {
@@ -193,7 +194,7 @@ layout("/layouts/v4/baseLayout.html"){
.favorite-icon { .favorite-icon {
position: absolute; position: absolute;
bottom: 10px; top: 10px;
right: 10px; right: 10px;
cursor: pointer; cursor: pointer;
transition: all 0.3s; transition: all 0.3s;
@@ -338,7 +339,8 @@ layout("/layouts/v4/baseLayout.html"){
:class="['apps-sidebar-item', activeCategory === category.id ? 'active' : '']" :class="['apps-sidebar-item', activeCategory === category.id ? 'active' : '']"
@click="changeCategory(category.id)" @click="changeCategory(category.id)"
> >
<i :class="category.icon || 'fa fa-th-large'"></i> <img v-if="category.picIcon" :src="category.picIcon" :alt="category.name || ''" style="width: 20px"/>
<i v-else :class="category.icon || 'fa fa-th-large'"></i>
{{ category.name }} {{ category.name }}
</div> </div>
</div> </div>
@@ -354,33 +356,35 @@ layout("/layouts/v4/baseLayout.html"){
</div> </div>
<!-- 字母过滤 --> <!-- 字母过滤 -->
<div class="apps-filter"> <!-- <div class="apps-filter">-->
<div class="apps-filter-title">首字母:</div> <!-- <div class="apps-filter-title">首字母:</div>-->
<div class="apps-filter-tags alphabet-filter"> <!-- <div class="apps-filter-tags alphabet-filter">-->
<div :class="['filter-tag', activeAlphabet === '' ? 'active' : '']" @click="changeAlphabet('')">全部</div> <!-- <div :class="['filter-tag', activeAlphabet === '' ? 'active' : '']" @click="changeAlphabet('')">全部</div>-->
<div <!-- <div-->
v-for="letter in alphabets" <!-- v-for="letter in alphabets"-->
:key="letter" <!-- :key="letter"-->
:class="['alphabet-item', activeAlphabet === letter ? 'active' : '']" <!-- :class="['alphabet-item', activeAlphabet === letter ? 'active' : '']"-->
@click="changeAlphabet(letter)" <!-- @click="changeAlphabet(letter)"-->
> <!-- >-->
{{ letter }} <!-- {{ letter }}-->
</div> <!-- </div>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
</div> </div>
<!-- 应用网格 --> <!-- 应用网格 -->
<div class="apps-grid" v-if="applications.length > 0"> <div class="apps-grid" v-if="applications.length > 0">
<div v-for="app in applications" :key="app.id" class="app-card" @click.stop="openApp(app)"> <div v-for="app in applications" :key="app.id" class="app-card" @click.stop="openApp(app)">
<div :class="['app-icon', app.iconType]"> <div :class="['app-icon', app.iconType]">
<!-- <i v-if="app.icon && !app.picIcon" :class="app.icon"></i>--> <!--<i v-if="app.icon && !app.picIcon" :class="app.icon"></i>
<!-- <img v-else-if="app.picIcon" :src="app.picIcon" :alt="app.name || ''" />--> <img v-else-if="app.picIcon" :src="app.picIcon" :alt="app.name || ''" />-->
<i class="fa fa-skype"></i> <!--<i class="fa fa-skype"></i>-->
<img v-if="app.picIcon" :src="app.picIcon" :alt="app.name || ''" />
<i v-else class="fa fa-skype"></i>
</div> </div>
<div class="app-info"> <div class="app-info">
<div class="app-title">{{ app.name }}</div> <div class="app-title">{{ app.name }}</div>
<div class="app-desc" v-if="app.department">{{ app.department }}</div> <div class="app-desc" v-if="app.moduleName">{{ app.moduleName }}</div>
</div> </div>
<div class="app-status" v-if="app.status">{{ app.status }}</div> <div class="app-status" v-if="app.status">{{ app.status }}</div>
<div <div
@@ -504,8 +508,8 @@ layout("/layouts/v4/baseLayout.html"){
this.activeCategory === "all" this.activeCategory === "all"
? "" ? ""
: this.activeCategory === "favorites" || this.activeCategory === "recommended" : this.activeCategory === "favorites" || this.activeCategory === "recommended"
? this.activeCategory ? this.activeCategory
: this.activeCategory, : this.activeCategory,
letter: this.activeAlphabet, letter: this.activeAlphabet,
keyword: this.searchKeyword keyword: this.searchKeyword
} }
@@ -1,39 +1,35 @@
const entry = { const entry = {
template: /*language=HTML*/ ` template: /*language=HTML*/ `
<div class="entry-wrapper"> <div class="entry-wrapper">
<!-- 标签页导航 --> <!-- 标签页导航 -->
<div class="tabs"> <div class="tabs">
<div class="tab-item" :class="{ active: activeCategory === 'serv' }" <div class="tab-item" :class="{ active: activeCategory === 'serv' }"
@click="setActiveCategory('serv')"> @click="setActiveCategory('serv')">
<i class="fa fa-star"></i> 推荐服务 <i class="fa fa-star"></i> 推荐服务
</div> </div>
<div class="tab-item" :class="{ active: activeCategory === 'app' }" <div class="tab-item" :class="{ active: activeCategory === 'app' }"
@click="setActiveCategory('app')"> @click="setActiveCategory('app')">
<i class="fa fa-fire"></i> 推荐应用 <i class="fa fa-fire"></i> 推荐应用
</div> </div>
<div class="tab-item" :class="{ active: activeCategory === 'fav' }" <div class="tab-item" :class="{ active: activeCategory === 'fav' }"
@click="setActiveCategory('fav')"> @click="setActiveCategory('fav')">
<i class="fa fa-heart"></i> 我的收藏 <i class="fa fa-heart"></i> 我的收藏
</div> </div>
</div> </div>
<!-- 应用块区域 --> <!-- 应用块区域 -->
<div class="apps-container"> <div class="apps-container">
<div class="app-grid"> <div class="app-grid">
<div v-if="currentServices && currentServices.length > 0" class="app-item" v-for="(item, index) in currentServices" :key="index" <div class="app-item" v-for="(item, index) in currentServices" :key="index"
@click="openService(item)"> @click="openService(item)">
<div class="app-icon"> <div class="app-icon">
<img :src="item.picIcon" alt="" /> <img :src="item.picIcon" alt="" />
</div> </div>
<div class="app-name">{{ item.name }}</div> <div class="app-name">{{ item.name }}</div>
</div>
<div v-if="currentServices.length === 0" class="no-entry-placeholder">
<div class="icon">📅</div>
<p>暂无数据</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
`, `,
data() { data() {
return { return {
@@ -129,7 +125,6 @@ const entry = {
margin-top: 5px; margin-top: 5px;
display: flex; display: flex;
gap: 20px; gap: 20px;
margin-bottom: 20px;
border-bottom: 2px solid #e8e8e8; border-bottom: 2px solid #e8e8e8;
padding-bottom: 10px; padding-bottom: 10px;
} }
@@ -173,12 +168,12 @@ const entry = {
justify-items: center; /* 子项内容居中(图标和文字) */ justify-items: center; /* 子项内容居中(图标和文字) */
justify-content: start; /* 整体网格靠左对齐,避免居中 */ justify-content: start; /* 整体网格靠左对齐,避免居中 */
gap: 12px; gap: 4px;
padding: 12px; padding: 12px 4px;
background: #fff; background: #fff;
overflow-x: hidden; overflow-x: hidden;
height: calc(350px - 74px); max-height: calc(350px - 74px);
overflow-y: auto; overflow-y: auto;
} }
@@ -187,11 +182,11 @@ const entry = {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
padding: 12px;
border-radius: 8px; border-radius: 8px;
background: #fff; background: #fff;
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
padding: 6px;
transition: transform 0.2s ease, box-shadow 0.2s ease; transition: transform 0.2s ease, box-shadow 0.2s ease;
} }
@@ -248,32 +243,5 @@ const entry = {
gap: 12px; gap: 12px;
} }
} }
.no-entry-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 20px;
color: #94a3b8;
text-align: center;
}
.no-entry-placeholder .icon {
font-size: 48px;
margin-bottom: 12px;
opacity: 0.6;
}
.no-entry-placeholder p {
margin: 4px 0 0;
font-size: 16px;
font-weight: 500;
}
.no-entry-placeholder .subtext {
font-size: 13px;
opacity: 0.8;
}
` `
}; };
@@ -1,6 +1,9 @@
const stats = { const stats = {
template: /*language=HTML*/ ` template: /*language=HTML*/ `
<div class="stats-section"> <div class="stats-section">
<div class="stats-family">
<img src="/assets/platform/img/home/family.png"/>
</div>
<div class="stats-grid"> <div class="stats-grid">
<!-- 待办 --> <!-- 待办 -->
<div <div
@@ -110,22 +113,22 @@ const stats = {
style: /*language=CSS*/ ` style: /*language=CSS*/ `
/* 右侧统计区域 */ /* 右侧统计区域 */
.stats-section { .stats-section {
position: absolute;
bottom: 24px;
right: 24px;
/*background: white;*/ /*background: white;*/
color: #333; color: #333;
padding: 20px; padding: 20px;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
z-index: 10; z-index: 10;
width: 680px; width: 80%;
display: flex;
justify-content: space-between;
align-items: center;
margin: -130px auto 0;
/*border: 1px solid #e8e8e8;*/ /*border: 1px solid #e8e8e8;*/
} }
.stats-grid { .stats-grid {
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 16px; gap: 16px;
} }
@@ -140,13 +143,15 @@ const stats = {
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
box-shadow: 0 2px 6px rgba(0,0,0,0.08); box-shadow: 0 2px 6px rgba(0,0,0,0.08);
width: 200px;
height: 90px;
} }
.stat-icon { .stat-icon {
font-size: 20px; font-size: 30px;
width: 36px; width: 50px;
height: 36px; height: 50px;
background: #e6f7ff; background: #e6f7ff;
color: #1890ff; color: #1890ff;
border-radius: 50%; border-radius: 50%;
@@ -178,6 +183,7 @@ const stats = {
.stat-content { .stat-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-left: 10px;
} }
.stat-label { .stat-label {
@@ -192,5 +198,14 @@ const stats = {
font-weight: bold; font-weight: bold;
margin-top: 2px; margin-top: 2px;
} }
.stats-family {
width: 68%;
}
.stats-family img {
height: 190px !important;
border-radius: 30px;
}
` `
}; };
+23 -22
View File
@@ -329,12 +329,13 @@ layout("/layouts/v4/baseLayout.html"){
<!-- Left Sidebar --> <!-- Left Sidebar -->
<div class="apps-sidebar"> <div class="apps-sidebar">
<div <div
v-for="category in allCategories" v-for="category in allCategories"
:key="category.id" :key="category.id"
:class="['apps-sidebar-item', activeCategory === category.id ? 'active' : '']" :class="['apps-sidebar-item', activeCategory === category.id ? 'active' : '']"
@click="changeCategory(category.id)" @click="changeCategory(category.id)"
> >
<i :class="category.icon || 'fa fa-th-large'"></i> <img v-if="category.picIcon" :src="category.picIcon" :alt="category.name || ''" style="width: 20px"/>
<i v-else :class="category.icon || 'fa fa-th-large'"></i>
{{ category.name }} {{ category.name }}
</div> </div>
</div> </div>
@@ -350,29 +351,29 @@ layout("/layouts/v4/baseLayout.html"){
</div> </div>
<!-- 字母过滤 --> <!-- 字母过滤 -->
<!-- <div class="apps-filter">--> <!-- <div class="apps-filter">-->
<!-- <div class="apps-filter-title">首字母:</div>--> <!-- <div class="apps-filter-title">首字母:</div>-->
<!-- <div class="apps-filter-tags alphabet-filter">--> <!-- <div class="apps-filter-tags alphabet-filter">-->
<!-- <div :class="['filter-tag', activeAlphabet === '' ? 'active' : '']" @click="changeAlphabet('')">--> <!-- <div :class="['filter-tag', activeAlphabet === '' ? 'active' : '']" @click="changeAlphabet('')">-->
<!-- 全部--> <!-- 全部-->
<!-- </div>--> <!-- </div>-->
<!-- <div--> <!-- <div-->
<!-- v-for="letter in alphabets"--> <!-- v-for="letter in alphabets"-->
<!-- :key="letter"--> <!-- :key="letter"-->
<!-- :class="['alphabet-item', activeAlphabet === letter ? 'active' : '']"--> <!-- :class="['alphabet-item', activeAlphabet === letter ? 'active' : '']"-->
<!-- @click="changeAlphabet(letter)"--> <!-- @click="changeAlphabet(letter)"-->
<!-- >--> <!-- >-->
<!-- {{ letter }}--> <!-- {{ letter }}-->
<!-- </div>--> <!-- </div>-->
<!-- </div>--> <!-- </div>-->
<!-- </div>--> <!-- </div>-->
</div> </div>
<!-- 应用网格 --> <!-- 应用网格 -->
<div class="apps-grid" v-if="applications.length > 0"> <div class="apps-grid" v-if="applications.length > 0">
<div v-for="app in applications" :key="app.id" class="app-card" @click.stop="openApp(app)"> <div v-for="app in applications" :key="app.id" class="app-card" @click.stop="openApp(app)">
<div :class="['app-icon', app.iconType]"> <div :class="['app-icon', app.iconType]">
<i v-if="app.icon" :class="app.icon"></i> <img v-if="app.picIcon" :src="app.picIcon" :alt="app.name || ''" />
<i v-else class="fa fa-skype"></i> <i v-else class="fa fa-skype"></i>
</div> </div>
<div class="app-info"> <div class="app-info">
@@ -43,6 +43,15 @@ layout("/layouts/platform.html"){
:rules="{ required: true, message: '请输入类型名称', trigger: 'blur' }"> :rules="{ required: true, message: '请输入类型名称', trigger: 'blur' }">
<el-input v-model="formData.name" placeholder="请输入类型名称"></el-input> <el-input v-model="formData.name" placeholder="请输入类型名称"></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="picIcon" label="图片图标">
<file-upload
:value.sync="formData.picIcon"
:upload_number="1"
upload_mode="image"
upload_result_category="interval"
upload_result_type="url"
></file-upload>
</el-form-item>
<el-form-item label="图标" prop="icon"> <el-form-item label="图标" prop="icon">
<el-input v-model="formData.icon" placeholder="请输入图标"></el-input> <el-input v-model="formData.icon" placeholder="请输入图标"></el-input>
</el-form-item> </el-form-item>
@@ -101,6 +101,15 @@ layout("/layouts/platform.html"){
<el-form-item label="手机端查看地址" prop="h5InstanceViewUrl"> <el-form-item label="手机端查看地址" prop="h5InstanceViewUrl">
<el-input v-model="formData.h5InstanceViewUrl" placeholder="请输入手机端发起地址"></el-input> <el-input v-model="formData.h5InstanceViewUrl" placeholder="请输入手机端发起地址"></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="picIcon" label="图片图标">
<file-upload
:value.sync="formData.picIcon"
:upload_number="1"
upload_mode="image"
upload_result_category="interval"
upload_result_type="url"
></file-upload>
</el-form-item>
<el-form-item label="图标" prop="icon"> <el-form-item label="图标" prop="icon">
<el-input v-model="formData.icon" placeholder="请输入图标"></el-input> <el-input v-model="formData.icon" placeholder="请输入图标"></el-input>
</el-form-item> </el-form-item>
@@ -5,11 +5,11 @@ const apps = {
<!-- 搜索栏 --> <!-- 搜索栏 -->
<van-sticky offset-top="46px"> <van-sticky offset-top="46px">
<van-search <van-search
v-model="searchKeyword" v-model="searchKeyword"
placeholder="搜索应用" placeholder="搜索应用"
show-action show-action
@search="onSearch" @search="onSearch"
@cancel="onCancel" @cancel="onCancel"
></van-search> ></van-search>
</van-sticky> </van-sticky>
@@ -17,14 +17,16 @@ const apps = {
<!-- 左侧导航 --> <!-- 左侧导航 -->
<div class="tree-nav"> <div class="tree-nav">
<div <div
v-for="(category, index) in allCategories" v-for="(category, index) in allCategories"
:key="category.id" :key="category.id"
:class="['nav-item', { active: activeTab === index }]" :class="['nav-item', { active: activeTab === index }]"
@click="onClickNav(index)" @click="onClickNav(index)"
> >
<div class="nav-icon"> <div class="nav-icon">
<van-icon v-if="category.icon" :name="category.icon" size="28"></van-icon> <!--<i v-if="category.icon" :class="category.icon"></i>
<i v-else class="fa fa-book"></i> <i v-else class="fa fa-book"></i>-->
<img v-if="category.picIcon" :src="category.picIcon" :alt="category.name || ''" style="width: 18px"/>
<i v-else :class="category.icon || 'fa fa-th-large'"></i>
</div> </div>
<div class="nav-text">{{ category.name }}</div> <div class="nav-text">{{ category.name }}</div>
<div class="nav-indicator" v-if="activeTab === index"></div> <div class="nav-indicator" v-if="activeTab === index"></div>
@@ -46,8 +48,7 @@ const apps = {
@touchmove="onTouchMove"> @touchmove="onTouchMove">
<!-- 图标 --> <!-- 图标 -->
<div class="app-grid-icon"> <div class="app-grid-icon">
<van-icon v-if="app.picIcon" :name="app.picIcon" size="45" <van-icon v-if="app.picIcon" :name="app.picIcon" size="45"></van-icon>
style="border-radius: 12px; width: 45px; height: 45px;"></van-icon>
<van-icon v-else-if="app.icon" :name="app.icon" size="28"></van-icon> <van-icon v-else-if="app.icon" :name="app.icon" size="28"></van-icon>
<van-icon v-else name="apps-o" size="28"></van-icon> <van-icon v-else name="apps-o" size="28"></van-icon>
</div> </div>
@@ -71,12 +72,13 @@ const apps = {
</div> </div>
<div class="menu-grid"> <div class="menu-grid">
<div <div
v-for="menu in currentMenus" v-for="menu in currentMenus"
:key="menu.id" :key="menu.id"
class="grid-item" class="grid-item"
@click="navigateToMenu(menu)" @click="navigateToMenu(menu)"
> >
<div class="grid-icon"> <img v-if="menu.picIcon" :src="menu.picIcon" :alt="menu.name || ''" style="width: 48px" class="grid-img"/>
<div v-else class="grid-icon">
<van-icon :name="menu.icon || 'apps-o'" size="24"></van-icon> <van-icon :name="menu.icon || 'apps-o'" size="24"></van-icon>
</div> </div>
<div class="grid-name">{{ menu.name }}</div> <div class="grid-name">{{ menu.name }}</div>
@@ -408,11 +410,11 @@ const apps = {
.app-grid { .app-grid {
display: grid; display: grid;
/* 改为自适应列数:每格最小 80px,自动换行 */ /* 改为自适应列数:每格最小 80px,自动换行 */
grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
justify-items: center; /* 子项内容居中(图标和文字) */ justify-items: center; /* 子项内容居中(图标和文字) */
justify-content: start; /* 整体网格靠左对齐,避免居中 */ justify-content: start; /* 整体网格靠左对齐,避免居中 */
gap: 12px; gap: 12px;
padding: 12px; padding: 12px;
background: #fff; background: #fff;
@@ -445,23 +447,23 @@ const apps = {
.app-grid-icon { .app-grid-icon {
width: 45px; width: 45px;
height: 45px; height: 45px;
max-width: 64px; max-width: 45px;
max-height: 60px; max-height: 45px;
border-radius: 12px; /*border-radius: 12px;
background: #f2f3f5; background: #f2f3f5;*/
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-bottom: 6px; margin-bottom: 6px;
overflow: hidden; overflow: hidden;
border: 2px solid transparent; /*border: 2px solid transparent;*/
transition: all 0.2s ease; transition: all 0.2s ease;
} }
.app-grid-name { .app-grid-name {
width: 100%; width: 100%;
font-size: 12px; font-size: 14px;
color: #323233; color: #323233;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
@@ -541,6 +543,17 @@ const apps = {
color: #fff; color: #fff;
} }
/deep/ .grid-img {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12px;
color: #fff;
}
/deep/ .grid-name { /deep/ .grid-name {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
@@ -577,6 +590,6 @@ const apps = {
font-size: 16px; font-size: 16px;
color: #c8c9cc; color: #c8c9cc;
} }
` `
} }