From 2ecb9c82bd92eb1b1e8e7d3bf3b460543c378b8a Mon Sep 17 00:00:00 2001 From: zhouhefeng Date: Tue, 23 Sep 2025 10:33:01 +0800 Subject: [PATCH] commit --- ...TeacherCongressDelegatePushController.java | 162 +++++ .../models/TeacherCongressDelegatePush.java | 186 ++++++ .../teachercongress/delegate/push/index.html | 181 ++++++ .../delegate/push/push-formal-dialog.js | 135 ++++ .../delegate/push/push-progress.js | 575 ++++++++++++++++++ 5 files changed, 1239 insertions(+) create mode 100644 src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/controller/TeacherCongressDelegatePushController.java create mode 100644 src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/models/TeacherCongressDelegatePush.java create mode 100644 src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/index.html create mode 100644 src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-formal-dialog.js create mode 100644 src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-progress.js diff --git a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/controller/TeacherCongressDelegatePushController.java b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/controller/TeacherCongressDelegatePushController.java new file mode 100644 index 00000000..d6288488 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/controller/TeacherCongressDelegatePushController.java @@ -0,0 +1,162 @@ +package com.budwk.app.zhgh.democratic.teachercongress.delegate.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.base.result.Result; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.sys.views.View_user; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.TeacherCongressDelegatePush; +import com.budwk.app.zhgh.democratic.teachercongress.delegate.models.Teacher_congress_delegate; +import io.swagger.annotations.Api; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +import java.time.LocalDate; +import java.time.Period; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * @author zhf + * @date 2025/9/22 20:41 + * @description + */ +@IocBean +@At("/platform/teacherCongress/delegate/push") +@Ok("json:full") +@Api(value = "/platform/teacherCongress/delegate/push", tags = "教代会代表推选") +public class TeacherCongressDelegatePushController { + + @Inject + private Dao dao; + + @Inject + private BaseService baseService; + + @At("") + @Ok("beetl:/platform/zhgh/democratic/teachercongress/delegate/push/index.html") + @SaCheckPermission("tc.delegate.push") + public void index() { + } + + + /** + * 获取本分工会下的非代表用户 + * + * @param sessionId + * @return + */ + @At + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission("tc.delegate.push") + @SLog(tag = "民主管理-教代会代表推选", msg = "获取本分工会下的非代表用户") + public Result getUnionUser(String sessionId, String unionId) { + // 查询预选中的代表 + Cnd cndx = Cnd.where("sessionId", "=", sessionId); + cndx.andEX("unionId", "=", SecurityUtil.getUnionId()); + List delegateList = dao.query(Teacher_congress_delegate.class, cndx); +// u.professionalTitle, +// u.professionalLevel, + Sql sql = Sqls.create(""" + SELECT + u.id AS userId, + u.loginname as loginName, + u.username as userName, + + u.sex, + u.birthday, + u.nation, + TIMESTAMPDIFF(YEAR, u.birthday, CURDATE()) AS age + FROM + `vw_user` u + LEFT JOIN teacher_congress_delegate tcd ON tcd.userId = u.id + AND tcd.sessionId = @sessionId + LEFT JOIN teacher_congress_delegate_push tcdp ON tcdp.userId = tcdp.id + AND tcdp.sessionId = @sessionId + $condition + """); + sql.setParam("sessionId", sessionId); + Cnd cnd = Cnd.NEW(); + cnd.and("u.member", "=", 1); + cnd.and("tcd.userId", "is", null); + cnd.and("tcdp.id", "is", null); + cnd.and("u.unionId", "=", SecurityUtil.getUnionId()); + sql.setCondition(cnd); + List userList = baseService.listMap(sql); + return Result.success(Map.of("userData", userList, "userValue", delegateList)); + } + + + /** + * 推选代表 + */ + @At + @Aop(TransAop.READ_COMMITTED) + public Object addPreselectionDb(@Param("userValue") String[] userValue, String sessionId, String representativeType) { + List list = new ArrayList<>(); + for (String id : userValue) { + View_user user = dao.fetch(View_user.class, Cnd.where("id", "=", id)); + + TeacherCongressDelegatePush tmd = new TeacherCongressDelegatePush(); + tmd.setUserId(user.getId()); + tmd.setSessionId(sessionId); + tmd.setDelegationId(null); + tmd.setUserName(user.getUsername()); + tmd.setLoginName(user.getLoginname()); + tmd.setSex(user.getSex()); + tmd.setNation(user.getNation()); + tmd.setEducation(user.getEducation()); + tmd.setAcademicDegree(user.getAcademicDegree()); + tmd.setPolitical(user.getPolitical()); + tmd.setProfessionalTitle(user.getProfessionalTitle()); + tmd.setProfessionalLevel(user.getProfessionalLevel()); + + tmd.setBirthday(user.getBirthday()); + tmd.setUnitId(user.getUnitId()); + tmd.setUnitName(user.getUnitName()); + tmd.setUnionId(user.getUnionId()); + tmd.setUnionName(user.getUnionName()); + + tmd.setOrdinaryTeacher(false); + tmd.setSeniorTeacher(false); + tmd.setSchoolLeader(false); + tmd.setMiddleLevelLeader(false); + + tmd.setMobile(user.getMobile()); + + tmd.setIsJdh(true); + tmd.setIsGdh(false); + tmd.setRepresentativeType(representativeType); + if (ObjectUtil.isNotEmpty(user.getBirthday())) { + Date birthdayDate = user.getBirthday(); + LocalDate birthday = birthdayDate.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate currentDate = LocalDate.now(); + int age = Period.between(birthday, currentDate).getYears(); + tmd.setAge(age); + } + tmd.setPushTime(new Date()); + list.add(tmd); + } + dao.insert(list); + return Result.success(); + } + + +} diff --git a/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/models/TeacherCongressDelegatePush.java b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/models/TeacherCongressDelegatePush.java new file mode 100644 index 00000000..18f07e94 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/democratic/teachercongress/delegate/models/TeacherCongressDelegatePush.java @@ -0,0 +1,186 @@ +package com.budwk.app.zhgh.democratic.teachercongress.delegate.models; + +import com.budwk.app.base.model.BaseModel; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; + +/** + * @author zhf + * @date 2025/9/22 20:40 + * @description 代表推选表 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Table("teacher_congress_delegate_push") +@TableMeta("{'mysql-charset':'utf8mb4'}") +@Comment("代表推选表") +public class TeacherCongressDelegatePush extends BaseModel { + + @Name + @Comment("ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @Comment("代表用户ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String userId; + + @Column + @Comment("所属教代会ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String sessionId; + + @Column + @Comment("所属代表团 当用户为校领导是该字段不为空") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String delegationId; + + @Column + @Comment("姓名") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String userName; + + @Column + @Comment("工号") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String loginName; + + @Column + @Comment("性别") + @ColDefine(type = ColType.VARCHAR, width = 2) + private String sex; + + @Column + @Comment("出生日期") + @ColDefine(type = ColType.DATETIME) + @JsonFormat(pattern = "yyyy-MM-dd") + private Date birthday; + + @Column + @Comment("民族") + @ColDefine(type = ColType.VARCHAR, width = 10) + private String nation; + + @Column + @Comment("政治面貌") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String political; + + @Column + @Comment("学历") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String education; + + @Column + @Comment("学位") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String academicDegree; + + @Column + @Comment("职称") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String professionalTitle; + + @Column + @Comment("职级") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String professionalLevel; + + @Column + @Comment("是否专任教师") + @ColDefine(type = ColType.BOOLEAN) + @Default("0") + private Boolean ordinaryTeacher; + + @Column + @Comment("是否高级职称专任教师") + @ColDefine(type = ColType.BOOLEAN) + @Default("0") + private Boolean seniorTeacher; + + @Column + @Comment("是否校领导") + @ColDefine(type = ColType.BOOLEAN) + @Default("0") + private Boolean schoolLeader; + + @Column + @Comment("是否中层领导") + @ColDefine(type = ColType.BOOLEAN) + @Default("0") + private Boolean middleLevelLeader; + + @Column + @Comment("行政职称===>position") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String administrativeTitle; + + @Column + @Comment("年龄") + @ColDefine(type = ColType.INT) + private Integer age; + + @Column + @Comment("单位ID") + @ColDefine(type = ColType.VARCHAR) + private String unitId; + + @Column + @Comment("单位名称") + @ColDefine(type = ColType.VARCHAR) + private String unitName; + + @Column + @Comment("分工会ID") + @ColDefine(type = ColType.VARCHAR) + private String unionId; + + @Column + @Comment("分工会名称") + @ColDefine(type = ColType.VARCHAR) + private String unionName; + + @Column + @Comment("手机号") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String mobile; + + @Column + @Comment("推送时间") + @ColDefine(type = ColType.DATETIME) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date pushTime; + + + @Column + @Comment("教代会代表类型") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String roleId; + + @Column + @Comment("教代会") + @ColDefine(type = ColType.BOOLEAN) + private Boolean isJdh; + + @Column + @Comment("工代会") + @ColDefine(type = ColType.BOOLEAN) + private Boolean isGdh; + + @Column + @Comment("备注") + @ColDefine(type = ColType.VARCHAR, width = 20) + private String bz; + + @Column + @Comment("代表类型(正式代表 列席代表)") + @ColDefine(type = ColType.VARCHAR, width = 4) + private String representativeType; +} diff --git a/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/index.html b/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/index.html new file mode 100644 index 00000000..80925489 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/index.html @@ -0,0 +1,181 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + 正式代表预选 + + 列席代表预选 + + 导出 + + 正式代表提交上报 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + diff --git a/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-formal-dialog.js b/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-formal-dialog.js new file mode 100644 index 00000000..37e265ff --- /dev/null +++ b/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-formal-dialog.js @@ -0,0 +1,135 @@ +const pushFormalDialog = { + template: /*language=HTML*/ ` + + +
+
+
{{ option.userName }} - {{ option.loginName }}
+
+ {{ option.sex}} + {{ option.age }}岁 + {{ option.jobTitle }} + {{ option.jobTitleLevel }} + {{ option.nation }} +
+
+
+
+ + 取 消 + 确 定 + +
+ `, + data() { + return { + dialogVisible: false, + userValue: [], + userData: [], + rightChecked: [], + attendanceRightChecked: [], + sessionId: null + } + }, + methods: { + async onOpen(sessionId, unionId) { + this.dialogVisible = true + this.sessionId = sessionId + this.userValue = [] + this.userData = [] + const {code, data} = await $.get('/platform/teacherCongress/delegate/push/getUnionUser', { + sessionId: sessionId, + unionId: unionId + }) + if (code === 0) { + data.userData.forEach(v => { + this.userData.push({id: v.userId, ...v}) + }) + } + }, + filterMethod(query, item) { + return item.userName.indexOf(query) > -1 + }, + async onConfirm() { + const {code, msg} = await $.post('/platform/teacherCongress/delegate/push/addPreselectionDb', { + userValue: JSON.stringify(this.userValue), + sessionId: this.sessionId, + representativeType: '正式代表' + }) + if (code === 0) { + this.dialogVisible = false + this.$message.success(msg) + this.$emit('refresh') + } + } + }, + style: /*language=CSS*/ ` + .push-formal-dialog ::v-deep .el-transfer{ + text-align: center!important; + } + + .push-formal-dialog ::v-deep .el-transfer-panel__item.el-checkbox { + height: auto; + display: block; + margin-right: 0; + padding: 0 15px; + } + + .push-formal-dialog ::v-deep .el-checkbox__input { + vertical-align: top; + margin-top: 5px; + } + + .push-formal-dialog ::v-deep .transfer-item { + padding: 5px; + font-size: 12px; + border-bottom: 1px solid #f0f0f0; + } + + .push-formal-dialog ::v-deep .transfer-item-name { + font-weight: bold; + margin-bottom: 3px; + color: #303133; + } + + .push-formal-dialog ::v-deep .transfer-item-details { + display: flex; + flex-wrap: wrap; + gap: 6px; + color: #606266; + } + + .push-formal-dialog ::v-deep .detail-item { + display: inline-flex; + align-items: center; + } + + .push-formal-dialog ::v-deep .el-transfer-panel{ + height: 60vh; + text-align: left !important; + width: 35% !important; + } + + .push-formal-dialog ::v-deep .el-transfer-panel__body { + height: calc(100% - 40px) !important; + display: flex; + flex-direction: column; + } + + .push-formal-dialog ::v-deep .el-transfer-panel__list.is-filterable { + flex: 1; + } + ` +} diff --git a/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-progress.js b/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-progress.js new file mode 100644 index 00000000..02894f6e --- /dev/null +++ b/src/main/resources/views/platform/zhgh/democratic/teachercongress/delegate/push/push-progress.js @@ -0,0 +1,575 @@ +const pushProgress = { + template: /*language=HTML*/ ` +
+
+ +
+
+
+

正式代表名额分配概况

+

{{teacherMeetName}}教职工代表大会代表名额分配情况

+
+
+ +
+
+ +
+ +
+
+
+
总代表数
+
+ {{ metrics.total.current }} + + / {{ metrics.total.target }} + +
+
+
+ +
+
+
+
+
+
+ + 已超出 + + + 未达标 + + + 已达标 + + +
+
+ + +
+
+
+
高级职称专任教师
+
{{ metrics.seniorTeacher.current }}/ {{ metrics.seniorTeacher.target }}
+
+
+ +
+
+
+
+
+
+ + 已达标 + + + 未达标 + + 剩余 {{ metrics.seniorTeacher.remaining }} 人 +
+
+ + +
+
+
+
专任教师代表
+
{{ metrics.ordinaryTeacher.current }}/ {{ metrics.ordinaryTeacher.target }}
+
+
+ +
+
+
+
+
+
+ + 已达标 + + + 未达标 + + 剩余 {{ metrics.ordinaryTeacher.remaining }} 人 +
+
+ + +
+
+
+
女代表数
+
{{ metrics.female.current }}/ {{ metrics.female.target }}
+
+
+ +
+
+
+
+
+
+ + 已达标 + + + 未达标 + + 剩余 {{ + metrics.female.remaining + }} 人 +
+
+ + +
+
+
+
45岁以下代表
+
{{ metrics.under45.current }}/ {{ metrics.under45.target }}
+
+
+ +
+
+
+
+
+
+ + 已达标 + + + 未达标 + + 剩余 {{ + metrics.under45.remaining + }} 人 +
+
+ + +
+
+
+
少数民族代表
+
{{ metrics.ethnicMinority.current }}/ {{ metrics.ethnicMinority.target }}
+
+
+ +
+
+
+
+
+
+ + 已达标 + + + 未达标 + + 剩余 {{ + metrics.ethnicMinority.remaining + }} 人 +
+
+ + +
+
+
+
校级领导代表
+
{{ metrics.schoolLeader.current }}/ {{ metrics.schoolLeader.target }}
+
+
+ +
+
+
+
+
+
+ + 已达标 + + + 未达标 + + 剩余 {{ + metrics.schoolLeader.remaining + }} 人 +
+
+ + +
+
+
+
中层领导
+
{{ metrics.middleLevelLeader.current }}/ {{ metrics.middleLevelLeader.target }}
+
+
+ +
+
+
+
+
+
+ + 已达标 + + + 未达标 + + 剩余 {{ + metrics.middleLevelLeader.remaining + }} 人 +
+
+ +
+
+ +
+

指标说明

+
+
+
+ 已达标:当前数量已达到或超过目标值 +
+
+
+ 未达标:当前数量未达到目标值,但已有代表选派 +
+
+
+
+ +
+

上报说明

+
+
+
+ 正式代表完成信息填写后才能进行上报,列席代表可直接上报且不计入名额 +
+
+
+ +
+
+ `, + props: { + sessionId: { + type: String, + required: false, + default: null + }, + unionId: { + type: String, + required: false, + default: null + } + }, + data() { + return { + metrics: { + total: { + current: 15, + target: 15, + progress: 100, + remaining: 0 + }, + female: { + current: 3, + target: 5, + progress: 60, + remaining: 2 + }, + seniorTeacher: { + current: 4, + target: 6, + progress: 66.7, + remaining: 2 + }, + ordinaryTeacher: { + current: 8, + target: 10, + progress: 80, + remaining: 2 + }, + under45: { + current: 5, + target: 7, + progress: 71.4, + remaining: 2 + }, + ethnicMinority:{ + current: 1, + target: 2, + progress: 50, + remaining: 1 + }, + schoolLeader:{ + current: 2, + target: 3, + progress: 66.7, + remaining: 1 + }, + middleLevelLeader:{ + current: 1, + target: 2, + progress: 33.3, + remaining: 1 + } + }, + teacherMeetName: null + } + }, + watch: { + sessionId(val) { + this.refreshData() + } + }, + methods: { + async refreshData(sessionId, teacherMeetName, unionId) { + this.teacherMeetName = teacherMeetName + const {code, data} = await $.get('/platform/teacherCongress/delegate/push/selfUnionPushMetric', { + teacherMeetId: sessionId, + unionId: unionId + }) + if (code === 0) { + if (data) { + this.metrics = data + } else { + this.$message.error('暂未分配名额') + } + } + } + }, + style: /*language=CSS*/ ` + .representative-allocation { + margin: 0; + padding: 0; + } + + .representative-allocation .card { + background-color: white; + border-radius: 8px; + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03); + margin-bottom: 24px; + } + + .representative-allocation .header-x { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24px; + } + + .representative-allocation .header-x .title h1 { + font-size: 24px; + font-weight: 700; + margin: 0; + color: #111827; + } + + .representative-allocation .header-x .title p { + font-size: 14px; + color: #6b7280; + margin-top: 8px; + margin-bottom: 0; + } + + .representative-allocation .buttons { + display: flex; + gap: 16px; + } + + .representative-allocation .grid-cols-3 { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 24px; + } + + .representative-allocation .metric-card { + background-color: #f3f3f3; + border-radius: 8px; + padding: 24px; + } + + .representative-allocation .metric-card .metric-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 16px; + } + + .representative-allocation .metric-card .metric-header .metric-title { + font-size: 14px; + color: #6b7280; + margin-bottom: 4px; + font-weight: 600; + } + + .representative-allocation .metric-card .metric-header .metric-value { + font-size: 30px; + font-weight: 700; + color: #111827; + } + + .representative-allocation .metric-card .metric-header .metric-value .metric-target { + font-size: 14px; + color: #6b7280; + margin-left: 4px; + } + + .representative-allocation .metric-card .metric-icon { + width: 40px; + height: 40px; + border-radius: 50%; + align-items: center; + justify-content: center; + display: none; + } + + .representative-allocation .progress-bar { + height: 4px; + border-radius: 2px; + background-color: #f0f0f0; + overflow: hidden; + } + + .representative-allocation .progress-bar .progress-bar-inner { + height: 100%; + transition: width 0.3s ease; + } + + .representative-allocation .progress-info { + display: flex; + justify-content: space-between; + margin-top: 8px; + font-size: 12px; + } + + .representative-allocation .bg-primary { + background-color: #1677ff; + } + + .representative-allocation .bg-primary-light { + background-color: rgba(22, 119, 255, 0.1); + } + + .representative-allocation .text-primary { + color: #1677ff; + } + + .representative-allocation .bg-secondary { + background-color: #4096ff; + } + + .representative-allocation .bg-success { + background-color: #52c41a; + } + + .representative-allocation .text-success { + color: #52c41a; + } + + .representative-allocation .bg-warning { + background-color: #faad14; + } + + .representative-allocation .text-warning { + color: #faad14; + } + + .representative-allocation .bg-warning-light { + background-color: rgba(250, 173, 20, 0.1); + } + + .representative-allocation .text-gray-500 { + color: #6b7280; + } + + .representative-allocation .legend-title { + font-size: 18px; + font-weight: 700; + color: #111827; + margin-bottom: 16px; + } + + .representative-allocation .legend-container { + display: grid; + grid-template-columns: 1fr; + gap: 16px; + } + + .representative-allocation .legend-item { + display: flex; + align-items: center; + } + + .representative-allocation .legend-item .legend-color { + width: 12px; + height: 12px; + border-radius: 50%; + margin-right: 8px; + } + + .representative-allocation .legend-item .legend-text { + color: #6b7280; + } + + .representative-allocation .update-time { + font-size: 14px; + color: #6b7280; + margin-top: 16px; + } + + ` +}