diff --git a/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserClubListController.java b/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserClubListController.java index 610b6f47..6524ede0 100644 --- a/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserClubListController.java +++ b/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserClubListController.java @@ -1,6 +1,7 @@ package com.budwk.app.zhgh.club.controller.apply; import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; import cn.hutool.core.util.StrUtil; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; @@ -47,8 +48,19 @@ public class ClubUserClubListController { public void index() { } + /** + * 打开移动端社团列表,共用电脑端的社团查询及入退会状态。 + * + * @return 无返回值,由模板渲染社团列表页面 + */ + @At("/h5") + @Ok("beetl:/platform/zhghh5/club/list/index.html") + @SaCheckPermission(value = {"h5.club.join.list", "h5.club.join.apply"}, mode = SaMode.OR) + public void h5Index() { + } + @At - @SaCheckPermission("club.join.list") + @SaCheckPermission(value = {"club.join.list", "h5.club.join.list", "h5.club.join.apply"}, mode = SaMode.OR) public Result pageData(@Valid PageForm pageForm, Boolean hasJoin, String clubName, String clubType) { Cnd cnd = Cnd.NEW(); cnd.and("dismiss", "=", false); @@ -71,7 +83,7 @@ public class ClubUserClubListController { } @At - @SaCheckPermission("club.join.list") + @SaCheckPermission(value = {"club.join.list", "h5.club.join.list", "h5.club.join.apply"}, mode = SaMode.OR) public Result getCount() { // 获取所有社团 List list = sysClubService.query(); @@ -96,7 +108,7 @@ public class ClubUserClubListController { } @At - @SaCheckPermission("club.join.list") + @SaCheckPermission(value = {"club.join.list", "h5.club.join.list", "h5.club.join.apply"}, mode = SaMode.OR) public Result findOne(@Valid String id) { ClubRegisterVo clubRegisterVo = sysClubService.findOne(id); return Result.success(clubRegisterVo); diff --git a/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserJoinApplyController.java b/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserJoinApplyController.java index 59d147cd..90629d45 100644 --- a/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserJoinApplyController.java +++ b/src/main/java/com/budwk/app/zhgh/club/controller/apply/ClubUserJoinApplyController.java @@ -74,10 +74,22 @@ public class ClubUserJoinApplyController { public void index() { } + /** + * 移动端首次入会先选择社团,已选社团或已有申请继续进入申请表单。 + * + * @param clubId 已选择的社团ID + * @param bizId 已有入会申请ID + * @param taskId 重新提交申请时的流程任务ID + * @return 无申请上下文时跳转社团列表,否则渲染原申请页面 + */ @At("/h5") @SaCheckPermission("h5.club.join.apply") - @Ok("beetl:/platform/zhghh5/club/apply/index.html") - public void h5Index() { + @Ok("re") + public String h5Index(@Param("clubId") String clubId, @Param("bizId") String bizId, @Param("taskId") String taskId) { + if (StrUtil.isBlank(clubId) && StrUtil.isBlank(bizId) && StrUtil.isBlank(taskId)) { + return ">>:/platform/club/join/list/h5"; + } + return "beetl:/platform/zhghh5/club/apply/index.html"; } @At diff --git a/src/main/java/com/budwk/app/zhgh/club/controller/common/ClubCommonController.java b/src/main/java/com/budwk/app/zhgh/club/controller/common/ClubCommonController.java index 860d7e8c..3b9ae892 100644 --- a/src/main/java/com/budwk/app/zhgh/club/controller/common/ClubCommonController.java +++ b/src/main/java/com/budwk/app/zhgh/club/controller/common/ClubCommonController.java @@ -2,12 +2,17 @@ package com.budwk.app.zhgh.club.controller.common; import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.result.Result; import com.budwk.app.base.service.BaseService; import com.budwk.app.bpm.enums.BpmProcessInstanceStatusEnum; import com.budwk.app.bpm.enums.BpmProcessTaskStatusEnum; import com.budwk.app.flow.enums.ProcessInstanceStateEnum; +import com.budwk.app.sys.enums.SysFileEngineTypeEnum; +import com.budwk.app.sys.services.SysFileService; import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.zhgh.club.model.ClubUser; @@ -19,10 +24,17 @@ import org.nutz.dao.Sqls; import org.nutz.dao.sql.Sql; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.AdaptBy; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.POST; +import org.nutz.mvc.annotation.Param; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; import java.util.List; +import java.util.Locale; +import java.util.Set; @IocBean @At("/platform/club/common") @@ -36,6 +48,36 @@ public class ClubCommonController { @Inject private SysClubService sysClubService; + @Inject + private SysFileService sysFileService; + + /** + * 上传社团缩略图,限制图片大小并复用系统文件服务校验图片内容及保存文件。 + * + * @param file 用户上传的 JPG、PNG 或 GIF 图片,大小不得超过 2MB + * @return 成功时返回图片下载地址,文件无效或超过限制时返回错误提示 + */ + @At + @POST + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @SaCheckPermission(value = {"club.register.apply", "club.infoManage.manage"}, mode = SaMode.OR) + public Result uploadThumbnail(@Param("file") TempFile file) { + if (file == null || StrUtil.isBlank(file.getSubmittedFileName())) { + return Result.error("请选择社团缩略图"); + } + if (file.getSize() > 2L * 1024 * 1024) { + return Result.error("社团缩略图大小不能超过2MB"); + } + String suffix = FileUtil.extName(file.getSubmittedFileName()).toLowerCase(Locale.ROOT); + if (!Set.of("jpg", "jpeg", "png", "gif").contains(suffix)) { + return Result.error("社团缩略图仅支持JPG、PNG、GIF图片"); + } + try { + return Result.success().addData(sysFileService.uploadReturnUrl(SysFileEngineTypeEnum.MINIO.getValue(), file)); + } catch (Exception e) { + return Result.error(e.getMessage()); + } + } @At @SaCheckLogin diff --git a/src/main/java/com/budwk/app/zhgh/club/model/SysClub.java b/src/main/java/com/budwk/app/zhgh/club/model/SysClub.java index 32a27cc3..2ea042cc 100644 --- a/src/main/java/com/budwk/app/zhgh/club/model/SysClub.java +++ b/src/main/java/com/budwk/app/zhgh/club/model/SysClub.java @@ -37,6 +37,11 @@ public class SysClub extends BaseModel { @NotEmpty(message = "社团名称不能为空") private String clubName; + @Column + @Comment("社团缩略图") + @ColDefine(type = ColType.VARCHAR, width = 1000) + private String thumbnail; + @Column @Comment("社团编码") @ColDefine(type = ColType.VARCHAR, width = 100) diff --git a/src/main/java/com/budwk/app/zhgh/club/service/impl/SysClubServiceImpl.java b/src/main/java/com/budwk/app/zhgh/club/service/impl/SysClubServiceImpl.java index 598d0265..d2a4bf4a 100644 --- a/src/main/java/com/budwk/app/zhgh/club/service/impl/SysClubServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/club/service/impl/SysClubServiceImpl.java @@ -112,11 +112,14 @@ public class SysClubServiceImpl extends BaseServiceImpl implements SysC if (StrUtil.isBlank(clubId)) { return new ClubRegisterVo(); } + // 与社团列表保持一致,按社团成员角色汇总会长、秘书长姓名,避免多名任职人员导致详情记录重复。 Sql sql = Sqls.create(""" SELECT club.*, d.NAME AS typeName, u.username concatPersonName, + (select GROUP_CONCAT(username) from sys_user where id in (select userId from club_user u where u.clubId=club.id and JSON_CONTAINS(u.roleCode, '"CLUB_PRESIDENT"'))) as clubLeader, + (select GROUP_CONCAT(username) from sys_user where id in (select userId from club_user u where u.clubId=club.id and JSON_CONTAINS(u.roleCode, '"CLUB_SECRETARY"'))) as clubSecretary, ( SELECT count( 1 ) FROM club_user scu WHERE scu.clubId = club.id ) currentPeopleNum, (select GROUP_CONCAT(username) from sys_user where id in (select sponsorId from sys_club_sponsor where clubId = club.id)) as sponsorName, (select GROUP_CONCAT(sponsorId) from sys_club_sponsor where clubId = club.id) as sponsor diff --git a/src/main/java/com/budwk/app/zhgh/club/vo/ClubRegisterVo.java b/src/main/java/com/budwk/app/zhgh/club/vo/ClubRegisterVo.java index 62c40195..e239d79b 100644 --- a/src/main/java/com/budwk/app/zhgh/club/vo/ClubRegisterVo.java +++ b/src/main/java/com/budwk/app/zhgh/club/vo/ClubRegisterVo.java @@ -19,4 +19,10 @@ public class ClubRegisterVo extends SysClub { private String sponsorName; private Integer currentPeopleNum; private String sponsor; + + @ApiModelProperty("会长") + private String clubLeader; + + @ApiModelProperty("秘书长") + private String clubSecretary; } diff --git a/src/main/resources/db/sys_club_add_thumbnail.sql b/src/main/resources/db/sys_club_add_thumbnail.sql new file mode 100644 index 00000000..a62f9ed9 --- /dev/null +++ b/src/main/resources/db/sys_club_add_thumbnail.sql @@ -0,0 +1,19 @@ +-- 社团缩略图保存系统文件下载地址;保留可空以兼容未上传图片的历史社团。 +-- 字段存在时跳过,避免重复执行迁移时报错。 +SET @club_thumbnail_column_count = ( + SELECT COUNT(*) + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'sys_club' + AND COLUMN_NAME = 'thumbnail' +); + +SET @club_thumbnail_ddl = IF( + @club_thumbnail_column_count = 0, + 'ALTER TABLE sys_club ADD COLUMN thumbnail VARCHAR(1000) NULL COMMENT ''社团缩略图'' AFTER clubName', + 'SELECT 1' +); + +PREPARE club_thumbnail_stmt FROM @club_thumbnail_ddl; +EXECUTE club_thumbnail_stmt; +DEALLOCATE PREPARE club_thumbnail_stmt; diff --git a/src/main/resources/static/assets/mobile/img/club/club-hero-v5.png b/src/main/resources/static/assets/mobile/img/club/club-hero-v5.png new file mode 100644 index 00000000..4a4cd69f Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/club/club-hero-v5.png differ diff --git a/src/main/resources/views/platform/zhgh/club/common/clubInfoComponent.js b/src/main/resources/views/platform/zhgh/club/common/clubInfoComponent.js index 98263f88..d95b32bb 100644 --- a/src/main/resources/views/platform/zhgh/club/common/clubInfoComponent.js +++ b/src/main/resources/views/platform/zhgh/club/common/clubInfoComponent.js @@ -8,6 +8,12 @@ const REGISTER_INFO_COMPONENT = { 点击查看流程图 + + + 暂无图片 + + 暂无图片 + {{viewData.clubName}} diff --git a/src/main/resources/views/platform/zhgh/club/join/apply/index.html b/src/main/resources/views/platform/zhgh/club/join/apply/index.html index 1256e05c..7bd95049 100644 --- a/src/main/resources/views/platform/zhgh/club/join/apply/index.html +++ b/src/main/resources/views/platform/zhgh/club/join/apply/index.html @@ -2,9 +2,19 @@ layout("/layouts/platform.html"){ #--> -
+ + +
- +
+ 返回 +
+ @@ -156,6 +166,9 @@ layout("/layouts/platform.html"){ } }, methods: { + backToClubList() { + commonUtil.pjaxPush('/platform/club/join/list'); + }, onSave() { this.$confirm("您确定保存吗?", "提示", { confirmButtonText: "确定", @@ -224,6 +237,16 @@ layout("/layouts/platform.html"){ this.$axios.post("/platform/club/common/listClub").then((res) => { if (res.code === 0) { this.clubOptions = res.data + // 从卡片进入新申请时预选社团,编辑已有申请仍使用原记录。 + const clubId = GetQueryString("clubId") + if (!this.bizId && clubId) { + const club = this.clubOptions.find(item => item.id === clubId) + if (club) { + this.$set(this.formData, "clubId", club.id) + this.$set(this.formData, "clubName", club.clubName) + this.checkApplyClub(club.id) + } + } } }) }, diff --git a/src/main/resources/views/platform/zhgh/club/join/list/index.html b/src/main/resources/views/platform/zhgh/club/join/list/index.html index 28f1fbf5..4320609d 100644 --- a/src/main/resources/views/platform/zhgh/club/join/list/index.html +++ b/src/main/resources/views/platform/zhgh/club/join/list/index.html @@ -11,9 +11,36 @@ layout("/layouts/platform.html"){ .el-tabs__header { margin: 0; } + .club-directory .club-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 20px; } + .club-directory .club-card { display: flex; flex-direction: column; min-width: 0; overflow: hidden; border: 1px solid #e4edf8; border-radius: 10px; background: #fff; box-shadow: 0 7px 20px rgba(55, 85, 126, .08); } + .club-directory .club-card-main { flex: 1; min-width: 0; } + .club-directory .club-card-cover { width: 100%; height: 180px; overflow: hidden; background: #edf4fc; } + .club-directory .club-card-cover .el-image { width: 100%; height: 100%; } + .club-directory .club-image-empty { display: flex; flex-direction: column; gap: 8px; height: 100%; align-items: center; justify-content: center; color: #8da1ba; font-size: 13px; background: #edf4fc; } + .club-directory .club-image-empty i { font-size: 34px; } + .club-directory .club-card-info { min-width: 0; padding: 14px 16px; } + .club-directory .club-card-name { margin: 0; color: #303846; font-size: 16px; font-weight: 400; line-height: 24px; overflow-wrap: anywhere; } + .club-directory .club-card-meta { margin: 5px 0 0; color: #98a2b2; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; } + .club-directory .club-card-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 10px; padding-top: 10px; border-top: 1px solid #edf1f6; } + .club-directory .club-card-tag { display: inline-flex; align-items: center; padding: 3px 8px; border-radius: 4px; background: #edf5ff; color: #397de0; font-size: 12px; line-height: 18px; } + .club-directory .club-card-tag-label { margin-right: 4px; color: #8aa7cf; } + .club-directory .club-card-actions { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 0 14px; margin: 0 16px; border-top: 1px solid #edf1f6; } + .club-directory .club-card-actions .el-button { height: 32px; margin: 0; padding: 0 14px; border: 0; border-radius: 16px; font-size: 13px; } + .club-directory .club-card-actions .el-button--primary { width: 108px; color: #fff; background: #1989fa; box-shadow: 0 5px 12px rgba(25, 137, 250, .18); } + .club-directory .club-card-actions .el-button--primary.is-plain { width: auto; color: #397de0; background: #edf5ff; box-shadow: none; } + .club-directory .club-card-actions .el-button--danger { width: 108px; color: #fff; background: #ee0a24; box-shadow: 0 5px 12px rgba(238, 10, 36, .18); } + .club-directory .club-card-sort { display: flex; justify-content: flex-end; margin-bottom: 16px; } + .club-directory .club-card-sort .el-select { width: 168px; } + .club-directory .club-detail-cover { width: 160px; max-width: 100%; height: 110px; overflow: hidden; border-radius: 8px; background: #f8fafc; } + .club-directory .club-detail-cover .el-image { display: block; width: 100%; height: 100%; border-radius: 8px; } + @media (max-width: 640px) { + .club-directory .club-card-grid { grid-template-columns: minmax(0, 1fr); } + .club-directory .club-card-cover { height: 150px; } + .club-directory .club-detail-cover { width: 120px; height: 90px; } + } -
+