..
This commit is contained in:
+15
@@ -11,8 +11,10 @@ import com.budwk.app.module.activity.models.Activity;
|
|||||||
import com.budwk.app.web.commons.auth.satoken.StpClientUtil;
|
import com.budwk.app.web.commons.auth.satoken.StpClientUtil;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.dao.FieldFilter;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
|
import org.nutz.dao.util.Daos;
|
||||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
@@ -165,5 +167,18 @@ public class ClientActivityController {
|
|||||||
return Result.success(actUser);
|
return Result.success(actUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户协议
|
||||||
|
*/
|
||||||
|
@At("/agreement/?")
|
||||||
|
public Result agreement(Long activityId) {
|
||||||
|
Dao extDao = Daos.ext(dao, FieldFilter.create(Activity.class, "protocol"));
|
||||||
|
Activity activity = extDao.fetch(Activity.class, activityId);
|
||||||
|
if (activity == null) {
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
return Result.success().addData(activity.getProtocol());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+74
-8
@@ -7,9 +7,11 @@ import com.budwk.app.base.result.Result;
|
|||||||
import com.budwk.app.module.activity.models.ActGroup;
|
import com.budwk.app.module.activity.models.ActGroup;
|
||||||
import com.budwk.app.module.activity.models.ActGroupUser;
|
import com.budwk.app.module.activity.models.ActGroupUser;
|
||||||
import com.budwk.app.module.activity.models.ActItemGroupScore;
|
import com.budwk.app.module.activity.models.ActItemGroupScore;
|
||||||
|
import com.budwk.app.module.activity.models.ActivityItem;
|
||||||
import com.budwk.app.module.activity.service.ActGroupService;
|
import com.budwk.app.module.activity.service.ActGroupService;
|
||||||
import com.budwk.app.module.activity.service.ActUserService;
|
import com.budwk.app.module.activity.service.ActUserService;
|
||||||
import com.budwk.app.module.activity.vo.ActGroupVo;
|
import com.budwk.app.module.activity.vo.ActGroupVo;
|
||||||
|
import com.budwk.app.module.activity.vo.ActManualGroupVo;
|
||||||
import com.budwk.app.module.activity.vo.ActUnGroupUserVo;
|
import com.budwk.app.module.activity.vo.ActUnGroupUserVo;
|
||||||
import com.budwk.app.web.commons.slog.annotation.SLog;
|
import com.budwk.app.web.commons.slog.annotation.SLog;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -29,6 +31,7 @@ import org.nutz.mvc.annotation.Param;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
@@ -59,7 +62,7 @@ public class ActGroupController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.group")
|
@SaCheckPermission("activity.group")
|
||||||
public Result pageData(PageForm pageForm, String activityId, String groupName){
|
public Result pageData(PageForm pageForm, String activityId, String groupName) {
|
||||||
Sql sql = Sqls.create("""
|
Sql sql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
ag.*,
|
ag.*,
|
||||||
@@ -95,12 +98,13 @@ public class ActGroupController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询签到人员
|
* 查询签到人员
|
||||||
|
*
|
||||||
* @param activityId
|
* @param activityId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.group")
|
@SaCheckPermission("activity.group")
|
||||||
public Result querySingUpData(String activityId){
|
public Result querySingUpData(String activityId) {
|
||||||
Sql sql = Sqls.create("""
|
Sql sql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
act.id AS activityId,
|
act.id AS activityId,
|
||||||
@@ -136,7 +140,7 @@ public class ActGroupController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.group")
|
@SaCheckPermission("activity.group")
|
||||||
public Result queryGroupList(String activityId){
|
public Result queryGroupList(String activityId) {
|
||||||
List<ActGroup> query = dao.query(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", activityId));
|
List<ActGroup> query = dao.query(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", activityId));
|
||||||
return Result.success().addData(query);
|
return Result.success().addData(query);
|
||||||
}
|
}
|
||||||
@@ -144,7 +148,7 @@ public class ActGroupController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.group")
|
@SaCheckPermission("activity.group")
|
||||||
public Result queryGroupUser(String activityId, String groupId){
|
public Result queryGroupUser(String activityId, String groupId) {
|
||||||
Sql sql = Sqls.create("""
|
Sql sql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
u.*,
|
u.*,
|
||||||
@@ -167,7 +171,7 @@ public class ActGroupController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.group")
|
@SaCheckPermission("activity.group")
|
||||||
@SLog(tag = "活动分组", msg = "随机分组")
|
@SLog(tag = "活动分组", msg = "随机分组")
|
||||||
public Result groupSetting(ActGroupVo actGroupVo){
|
public Result groupSetting(ActGroupVo actGroupVo) {
|
||||||
// 查询所有签到的用户,按照分组参数进行分组
|
// 查询所有签到的用户,按照分组参数进行分组
|
||||||
actGroupService.groupSetting(actGroupVo);
|
actGroupService.groupSetting(actGroupVo);
|
||||||
return Result.success();
|
return Result.success();
|
||||||
@@ -176,8 +180,8 @@ public class ActGroupController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.group")
|
@SaCheckPermission("activity.group")
|
||||||
public Result queryUnGroupUser(String activityId){
|
public Result queryUnGroupUser(String activityId) {
|
||||||
Sql sql = Sqls.create("""
|
Sql sql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
u.*
|
u.*
|
||||||
FROM
|
FROM
|
||||||
@@ -193,8 +197,70 @@ public class ActGroupController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.group")
|
@SaCheckPermission("activity.group")
|
||||||
@SLog(tag = "活动分组", msg = "设置未分组人员")
|
@SLog(tag = "活动分组", msg = "设置未分组人员")
|
||||||
public Result unGroupUserSetting(ActUnGroupUserVo actUnGroupUserVo){
|
public Result unGroupUserSetting(ActUnGroupUserVo actUnGroupUserVo) {
|
||||||
actGroupService.unGroupUserSetting(actUnGroupUserVo);
|
actGroupService.unGroupUserSetting(actUnGroupUserVo);
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("activity.group")
|
||||||
|
@SLog(tag = "活动分组", msg = "查询未分组人员")
|
||||||
|
public Result unGroupUsers(Long activityId) {
|
||||||
|
List<NutMap> list = actGroupService.unGroupUsers(activityId);
|
||||||
|
return Result.success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("activity.group")
|
||||||
|
@SLog(tag = "活动分组", msg = "查询分组信息及组员")
|
||||||
|
public Result listGroup(Long activityId) {
|
||||||
|
List<NutMap> list = actGroupService.listGroupAndUsers(activityId);
|
||||||
|
return Result.success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("activity.group")
|
||||||
|
@SLog(tag = "活动分组", msg = "手动设置分组")
|
||||||
|
public Result manualSetGroup(@Param("actGroups") ActGroup[] actGroups, @Param("activityId") Long activityId) {
|
||||||
|
dao.clear(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", activityId));
|
||||||
|
dao.clear(ActGroupUser.class, Cnd.where(ActGroupUser::getActivityId, "=", activityId));
|
||||||
|
|
||||||
|
for (int i = 0; i < actGroups.length; i++) {
|
||||||
|
actGroups[i].setActivityId(activityId);
|
||||||
|
actGroups[i].setSort(i + 1);
|
||||||
|
dao.insert(actGroups[i]);
|
||||||
|
for (ActGroupUser user : actGroups[i].getGroupUsers()) {
|
||||||
|
user.setActivityId(activityId);
|
||||||
|
user.setGroupId(actGroups[i].getId());
|
||||||
|
if (user.getUserId() == null) {
|
||||||
|
return Result.error("用户ID不能为空");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dao.insert(actGroups[i].getGroupUsers());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 查询项目列表
|
||||||
|
List<ActivityItem> items = dao.query(ActivityItem.class, Cnd.where(ActivityItem::getActivityId, "=", activityId));
|
||||||
|
|
||||||
|
// 清空分组积分
|
||||||
|
dao.clear(ActItemGroupScore.class, Cnd.where(ActItemGroupScore::getActivityId, "=", activityId));
|
||||||
|
|
||||||
|
// 往项目得分表里面插记录
|
||||||
|
List<ActItemGroupScore> itemGroupScoreList = new ArrayList<>();
|
||||||
|
for (ActGroup group : actGroups) {
|
||||||
|
// 构建小组项目得分表
|
||||||
|
List<ActItemGroupScore> groupScoreList = items.stream().map(item -> {
|
||||||
|
ActItemGroupScore itemGroupScore = new ActItemGroupScore();
|
||||||
|
itemGroupScore.setActivityId(activityId);
|
||||||
|
itemGroupScore.setItemId(item.getId());
|
||||||
|
itemGroupScore.setGroupId(group.getId());
|
||||||
|
return itemGroupScore;
|
||||||
|
}).toList();
|
||||||
|
itemGroupScoreList.addAll(groupScoreList);
|
||||||
|
}
|
||||||
|
dao.insert(itemGroupScoreList);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
package com.budwk.app.module.activity.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import com.budwk.app.base.page.PageForm;
|
||||||
|
import com.budwk.app.base.page.Pagination;
|
||||||
|
import com.budwk.app.base.result.Result;
|
||||||
|
import com.budwk.app.module.activity.models.ActRankScore;
|
||||||
|
import com.budwk.app.module.activity.service.ActRankScoreService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
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.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/activity/rankScore")
|
||||||
|
@Slf4j
|
||||||
|
@Ok("json:full")
|
||||||
|
@Api(tags = "活动名次积分对应")
|
||||||
|
public class ActRankScoreController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ActRankScoreService actRankScoreService;
|
||||||
|
|
||||||
|
@At("")
|
||||||
|
@SaCheckPermission("activity.rankScore")
|
||||||
|
@Ok("beetl:/platform/activity/rankScore/index.html")
|
||||||
|
public void index() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("activity.rankScore")
|
||||||
|
@ApiOperation(value = "分页查询", nickname = "/pageData", httpMethod = "GET")
|
||||||
|
public Result pageData(PageForm pageForm) {
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.desc(ActRankScore::getScore);
|
||||||
|
Pagination pagination = actRankScoreService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||||
|
return Result.success(pagination);
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("activity.rankScore")
|
||||||
|
@ApiOperation(value = "保存", nickname = "/save", httpMethod = "POST")
|
||||||
|
public Result save(@Param("actRankScore") ActRankScore[] actRankScore) {
|
||||||
|
// 名次不能重复
|
||||||
|
long count = Arrays.stream(actRankScore).map(ActRankScore::getRanking).distinct().count();
|
||||||
|
if (count != actRankScore.length) {
|
||||||
|
return Result.error("名次不能重复");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> rankingList = Arrays.stream(actRankScore).map(ActRankScore::getRanking).toList();
|
||||||
|
if (actRankScoreService.count(Cnd.where(ActRankScore::getRanking, "in", rankingList)) > 0) {
|
||||||
|
return Result.error("名次已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
actRankScoreService.insertOrUpdate(actRankScore);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("activity.rankScore")
|
||||||
|
@ApiOperation(value = "更新", nickname = "/update", httpMethod = "POST")
|
||||||
|
public Result update(ActRankScore actRankScore){
|
||||||
|
// 名次不能重复
|
||||||
|
long count = actRankScoreService.count(Cnd.where(ActRankScore::getRanking, "=", actRankScore.getRanking())
|
||||||
|
.and(ActRankScore::getId, "!=", actRankScore.getId()));
|
||||||
|
if (count > 0) {
|
||||||
|
return Result.error("名次已存在");
|
||||||
|
}
|
||||||
|
actRankScoreService.updateIgnoreNull(actRankScore);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation(value = "删除", nickname = "/delete", httpMethod = "POST")
|
||||||
|
public Result delete(Long id) {
|
||||||
|
actRankScoreService.delete(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
package com.budwk.app.module.activity.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import com.budwk.app.base.result.Result;
|
||||||
|
import com.budwk.app.module.activity.models.ActGroup;
|
||||||
|
import com.budwk.app.module.activity.models.ActItemGroupScore;
|
||||||
|
import com.budwk.app.module.activity.models.ActRankScore;
|
||||||
|
import com.budwk.app.module.activity.models.ActivityItem;
|
||||||
|
import com.budwk.app.module.activity.service.ActivityManageService;
|
||||||
|
import com.budwk.app.web.commons.slog.annotation.SLog;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.nutz.dao.Chain;
|
||||||
|
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.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.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/activity/scoreEntry")
|
||||||
|
@Ok("json:full")
|
||||||
|
@Api(tags = "成绩录入", value = "/platform/activity/scoreEntry")
|
||||||
|
public class ActScoreEntryController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Dao dao;
|
||||||
|
@Inject
|
||||||
|
private ActivityManageService activityService;
|
||||||
|
|
||||||
|
@At("")
|
||||||
|
@SaCheckPermission("activity.scoreEntry")
|
||||||
|
@Ok("beetl:/platform/activity/scoreEntry/index.html")
|
||||||
|
public void index() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@At("/list-activity")
|
||||||
|
@SaCheckPermission("activity.scoreEntry")
|
||||||
|
@ApiOperation(value = "获取活动列表", nickname = "/list-activity", httpMethod = "GET")
|
||||||
|
public Result listAct(Integer year) {
|
||||||
|
Sql sql = Sqls.create("select id,title from activity $condition");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.andEX("YEAR(startTime)", "=", year);
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
return Result.success(activityService.listMap(sql));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取队伍
|
||||||
|
*/
|
||||||
|
@At("/list-group/?")
|
||||||
|
@SaCheckPermission("activity.scoreEntry")
|
||||||
|
@ApiOperation(value = "获取队伍", nickname = "/list-group", httpMethod = "GET")
|
||||||
|
public Result listGroup(Long activityId) {
|
||||||
|
List<ActGroup> groupList = activityService.dao().query(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", activityId));
|
||||||
|
return Result.success(groupList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取项目列表
|
||||||
|
*/
|
||||||
|
@At("/list-item/?")
|
||||||
|
@SaCheckPermission("activity.scoreEntry")
|
||||||
|
@ApiOperation(value = "获取项目列表", nickname = "/list-item", httpMethod = "GET")
|
||||||
|
public Result listItem(Long activityId) {
|
||||||
|
List<ActivityItem> items = dao.query(ActivityItem.class, Cnd.where(ActivityItem::getActivityId, "=", activityId).asc(ActivityItem::getSort));
|
||||||
|
return Result.success(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@At("/list-item-score/?")
|
||||||
|
@SaCheckPermission("activity.scoreEntry")
|
||||||
|
@ApiOperation(value = "获取队伍项目名次得分", nickname = "/list-item-score", httpMethod = "GET")
|
||||||
|
public Result listItemScore(Long activityId) {
|
||||||
|
List<ActItemGroupScore> scoreList = dao.query(ActItemGroupScore.class, Cnd.where(ActItemGroupScore::getActivityId, "=", activityId));
|
||||||
|
return Result.success(scoreList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@At("/list-rank-score")
|
||||||
|
@SaCheckPermission("activity.scoreEntry")
|
||||||
|
@ApiOperation(value = "获取名次积分对应", nickname = "/list-rank-score", httpMethod = "GET")
|
||||||
|
public Result listRankScore() {
|
||||||
|
List<ActRankScore> rankScores = dao.query(ActRankScore.class, Cnd.NEW().desc(ActRankScore::getScore));
|
||||||
|
return Result.success(rankScores);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@At("/save-score")
|
||||||
|
@SaCheckPermission("activity.group")
|
||||||
|
@ApiOperation(value = "保存成绩", nickname = "/save-score", httpMethod = "POST")
|
||||||
|
public Result saveScore(@Param("scores") ActItemGroupScore[] actItemGroupScore) {
|
||||||
|
// 更新分数和名次
|
||||||
|
dao.updateIgnoreNull(actItemGroupScore);
|
||||||
|
|
||||||
|
// 更新总得分
|
||||||
|
// ActGroup actGroup = dao.fetch(ActGroup.class, actItemGroupScore.getGroupId());
|
||||||
|
// BigDecimal newTotalScore = actGroup.getTotalScore().add(actItemGroupScore.getScore());
|
||||||
|
// actGroup.setTotalScore(newTotalScore);
|
||||||
|
// dao.update(actGroup);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+20
-10
@@ -71,7 +71,7 @@ public class ActUserController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
public Result pageData(ActUserPageForm pageForm){
|
public Result pageData(ActUserPageForm pageForm) {
|
||||||
Sql sql = actUserService.getSignUpSql(pageForm);
|
Sql sql = actUserService.getSignUpSql(pageForm);
|
||||||
Pagination pagination = actUserService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
Pagination pagination = actUserService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
return Result.success(pagination);
|
return Result.success(pagination);
|
||||||
@@ -83,7 +83,7 @@ public class ActUserController {
|
|||||||
@Aop(TransAop.READ_COMMITTED)
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
@SLog(tag = "报名人员管理", msg = "电脑端替他人报名")
|
@SLog(tag = "报名人员管理", msg = "电脑端替他人报名")
|
||||||
public Result doAddActUser(ClientActivitySignVO vo){
|
public Result doAddActUser(ClientActivitySignVO vo) {
|
||||||
try {
|
try {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
// 报名时间
|
// 报名时间
|
||||||
@@ -158,7 +158,8 @@ public class ActUserController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
@SLog(tag = "报名人员管理", msg = "删除报名人员")
|
@SLog(tag = "报名人员管理", msg = "删除报名人员")
|
||||||
public Result doDeleteActUser(Long id){
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public Result doDeleteActUser(Long id) {
|
||||||
dao.delete(ActUser.class, id);
|
dao.delete(ActUser.class, id);
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
@@ -167,7 +168,7 @@ public class ActUserController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
@SLog(tag = "报名人员管理", msg = "修改报名人员信息")
|
@SLog(tag = "报名人员管理", msg = "修改报名人员信息")
|
||||||
public Result doModifyActUser(ActUser actUser){
|
public Result doModifyActUser(ActUser actUser) {
|
||||||
dao.updateIgnoreNull(actUser);
|
dao.updateIgnoreNull(actUser);
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
@@ -175,14 +176,23 @@ public class ActUserController {
|
|||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
@SLog(tag = "报名人员管理", msg = "设置已签到")
|
@SLog(tag = "报名人员管理", msg = "设置已签到")
|
||||||
public Result proxySignIn(Long id){
|
public Result proxySignIn(Long id) {
|
||||||
dao.update(ActUser.class, Chain.make("isSignIn",1).add("signInTime",LocalDateTime.now()),Cnd.where(ActUser::getId,"=",id));
|
dao.update(ActUser.class, Chain.make("isSignIn", 1).add("signInTime", LocalDateTime.now()), Cnd.where(ActUser::getId, "=", id));
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
public Result findSignUserInfo(Long id){
|
@SLog(tag = "报名人员管理", msg = "取消签到")
|
||||||
|
public Result cancelSignIn(Long id) {
|
||||||
|
dao.update(ActUser.class, Chain.make("isSignIn", 0).add("signInTime", null), Cnd.where(ActUser::getId, "=", id));
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("activity.user")
|
||||||
|
public Result findSignUserInfo(Long id) {
|
||||||
return Result.success(dao.fetch(ActUser.class, Cnd.where(ActUser::getId, "=", id)));
|
return Result.success(dao.fetch(ActUser.class, Cnd.where(ActUser::getId, "=", id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +202,7 @@ public class ActUserController {
|
|||||||
*/
|
*/
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
public Result getActivityList(String year){
|
public Result getActivityList(String year) {
|
||||||
List<Activity> activityList = dao.query(Activity.class, Cnd.NEW().andEX("YEAR(startTime)", "=", year).and(Activity::getDelFlag, "=", false));
|
List<Activity> activityList = dao.query(Activity.class, Cnd.NEW().andEX("YEAR(startTime)", "=", year).and(Activity::getDelFlag, "=", false));
|
||||||
return Result.success(activityList);
|
return Result.success(activityList);
|
||||||
}
|
}
|
||||||
@@ -200,7 +210,7 @@ public class ActUserController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@SaCheckPermission("activity.user")
|
@SaCheckPermission("activity.user")
|
||||||
public Result queryUser(String query, String activityId){
|
public Result queryUser(String query, String activityId) {
|
||||||
Sql sql = Sqls.create("SELECT id,username,phone FROM client_user $condition");
|
Sql sql = Sqls.create("SELECT id,username,phone FROM client_user $condition");
|
||||||
Cnd cnd = Cnd.NEW();
|
Cnd cnd = Cnd.NEW();
|
||||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
@@ -239,7 +249,7 @@ public class ActUserController {
|
|||||||
exportParams.setType(ExcelType.XSSF);
|
exportParams.setType(ExcelType.XSSF);
|
||||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, nutMaps);
|
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, nutMaps);
|
||||||
workbook.write(response.getOutputStream());
|
workbook.write(response.getOutputStream());
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.budwk.app.module.activity.models;
|
||||||
|
|
||||||
|
import com.budwk.app.base.model.BaseModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.nutz.dao.entity.annotation.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Table("act_rank_score")
|
||||||
|
@Comment("项目名次积分对应表")
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||||
|
public class ActRankScore extends BaseModel {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Comment("ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("名次")
|
||||||
|
private String ranking;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("积分")
|
||||||
|
@ColDefine(customType = "decimal", width = 10, precision = 2)
|
||||||
|
private BigDecimal score;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -122,4 +122,27 @@ public class ActUser extends BaseModel {
|
|||||||
@ColDefine(type = ColType.BOOLEAN)
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
@Default("0")
|
@Default("0")
|
||||||
private Boolean isGrant;
|
private Boolean isGrant;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("是否展示才艺")
|
||||||
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
|
@Default("0")
|
||||||
|
private Boolean isShowSkill;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("才艺名称")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String skillName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("所需器材")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String equip;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("是否参加嘉年华")
|
||||||
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
|
@Default("0")
|
||||||
|
private Boolean isParty;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import com.budwk.app.base.service.BaseService;
|
|||||||
import com.budwk.app.module.activity.models.ActGroup;
|
import com.budwk.app.module.activity.models.ActGroup;
|
||||||
import com.budwk.app.module.activity.vo.ActGroupVo;
|
import com.budwk.app.module.activity.vo.ActGroupVo;
|
||||||
import com.budwk.app.module.activity.vo.ActUnGroupUserVo;
|
import com.budwk.app.module.activity.vo.ActUnGroupUserVo;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ClassName ActGroupService
|
* @ClassName ActGroupService
|
||||||
@@ -26,4 +29,16 @@ public interface ActGroupService extends BaseService<ActGroup> {
|
|||||||
* @param unGroupUserVo
|
* @param unGroupUserVo
|
||||||
*/
|
*/
|
||||||
void unGroupUserSetting(ActUnGroupUserVo unGroupUserVo);
|
void unGroupUserSetting(ActUnGroupUserVo unGroupUserVo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询未分组人员
|
||||||
|
* @param activityId
|
||||||
|
*/
|
||||||
|
List<NutMap> unGroupUsers(Long activityId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询分组信息及组员
|
||||||
|
* @param activityId
|
||||||
|
*/
|
||||||
|
List<NutMap> listGroupAndUsers(Long activityId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.budwk.app.module.activity.service;
|
||||||
|
|
||||||
|
import com.budwk.app.base.service.BaseService;
|
||||||
|
import com.budwk.app.module.activity.models.ActRankScore;
|
||||||
|
|
||||||
|
public interface ActRankScoreService extends BaseService<ActRankScore> {
|
||||||
|
}
|
||||||
+198
-156
@@ -1,5 +1,6 @@
|
|||||||
package com.budwk.app.module.activity.service.impl;
|
package com.budwk.app.module.activity.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.module.activity.models.*;
|
import com.budwk.app.module.activity.models.*;
|
||||||
import com.budwk.app.module.activity.service.ActGroupService;
|
import com.budwk.app.module.activity.service.ActGroupService;
|
||||||
@@ -12,6 +13,7 @@ import org.nutz.dao.Sqls;
|
|||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
import org.nutz.ioc.aop.Aop;
|
import org.nutz.ioc.aop.Aop;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -27,187 +29,227 @@ import java.util.stream.IntStream;
|
|||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class ActGroupServiceImpl extends BaseServiceImpl<ActGroup> implements ActGroupService {
|
public class ActGroupServiceImpl extends BaseServiceImpl<ActGroup> implements ActGroupService {
|
||||||
|
|
||||||
public ActGroupServiceImpl(Dao dao) {
|
public ActGroupServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public void groupSetting(ActGroupVo groupVo) {
|
public void groupSetting(ActGroupVo groupVo) {
|
||||||
// 删除已经存在的分组信息
|
// 删除已经存在的分组信息
|
||||||
dao().clear(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", groupVo.getActivityId()));
|
dao().clear(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", groupVo.getActivityId()));
|
||||||
dao().clear(ActGroupUser.class, Cnd.where(ActGroupUser::getActivityId, "=", groupVo.getActivityId()));
|
dao().clear(ActGroupUser.class, Cnd.where(ActGroupUser::getActivityId, "=", groupVo.getActivityId()));
|
||||||
dao().clear(ActUnGroupUser.class, Cnd.where(ActUnGroupUser::getActivityId, "=", groupVo.getActivityId()));
|
dao().clear(ActUnGroupUser.class, Cnd.where(ActUnGroupUser::getActivityId, "=", groupVo.getActivityId()));
|
||||||
dao().clear(ActItemGroupScore.class, Cnd.where(ActItemGroupScore::getActivityId, "=", groupVo.getActivityId()));
|
dao().clear(ActItemGroupScore.class, Cnd.where(ActItemGroupScore::getActivityId, "=", groupVo.getActivityId()));
|
||||||
|
|
||||||
// 查询报名了并且已经完成签到的人员
|
// 查询报名了并且已经完成签到的人员
|
||||||
List<ActUser> signUpUserList = dao().query(ActUser.class, Cnd.where(ActUser::getActivityId, "=", groupVo.getActivityId())
|
List<ActUser> signUpUserList = dao().query(ActUser.class, Cnd.where(ActUser::getActivityId, "=", groupVo.getActivityId())
|
||||||
.and(ActUser::getIsSignIn, "=", 1));
|
.and(ActUser::getIsSignIn, "=", 1));
|
||||||
|
|
||||||
int size = signUpUserList.size();
|
int size = signUpUserList.size();
|
||||||
Integer oneGroupLimitUserNum = groupVo.getOneGroupLimitUserNum();
|
Integer oneGroupLimitUserNum = groupVo.getOneGroupLimitUserNum();
|
||||||
|
|
||||||
int result = Math.floorDiv(size, oneGroupLimitUserNum);
|
int result = Math.floorDiv(size, oneGroupLimitUserNum);
|
||||||
// 初始化分组
|
// 初始化分组
|
||||||
List<List<ActUser>> groups = new ArrayList<>();
|
List<List<ActUser>> groups = new ArrayList<>();
|
||||||
for (int i = 0; i < result; i++) {
|
for (int i = 0; i < result; i++) {
|
||||||
groups.add(new ArrayList<>());
|
groups.add(new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分离男女用户
|
// 分离男女用户
|
||||||
Map<String, List<ActUser>> genderMap = signUpUserList.stream()
|
Map<String, List<ActUser>> genderMap = signUpUserList.stream()
|
||||||
.collect(Collectors.groupingBy(user -> "男".equals(user.getSex()) ? "男" : "女"));
|
.collect(Collectors.groupingBy(user -> "男".equals(user.getSex()) ? "男" : "女"));
|
||||||
|
|
||||||
List<ActUser> males = genderMap.getOrDefault("男", Collections.emptyList());
|
List<ActUser> males = genderMap.getOrDefault("男", Collections.emptyList());
|
||||||
List<ActUser> females = genderMap.getOrDefault("女", Collections.emptyList());
|
List<ActUser> females = genderMap.getOrDefault("女", Collections.emptyList());
|
||||||
|
|
||||||
// 随机化列表
|
// 随机化列表
|
||||||
Collections.shuffle(males);
|
Collections.shuffle(males);
|
||||||
Collections.shuffle(females);
|
Collections.shuffle(females);
|
||||||
|
|
||||||
// 尝试分配
|
// 尝试分配
|
||||||
List<ActUser> unassignedUsers = new ArrayList<>();
|
List<ActUser> unassignedUsers = new ArrayList<>();
|
||||||
|
|
||||||
int maleIndex = 0, femaleIndex = 0;
|
int maleIndex = 0, femaleIndex = 0;
|
||||||
while (maleIndex < males.size() || femaleIndex < females.size()) {
|
while (maleIndex < males.size() || femaleIndex < females.size()) {
|
||||||
boolean assigned = false;
|
boolean assigned = false;
|
||||||
for (List<ActUser> group : groups) {
|
for (List<ActUser> group : groups) {
|
||||||
if (group.size() < groupVo.getOneGroupLimitUserNum()) {
|
if (group.size() < groupVo.getOneGroupLimitUserNum()) {
|
||||||
int currentMaleCount = (int) group.stream().filter(u -> "男".equals(u.getSex())).count();
|
int currentMaleCount = (int) group.stream().filter(u -> "男".equals(u.getSex())).count();
|
||||||
int currentFemaleCount = (int) group.stream().filter(u -> "女".equals(u.getSex())).count();
|
int currentFemaleCount = (int) group.stream().filter(u -> "女".equals(u.getSex())).count();
|
||||||
|
|
||||||
if (maleIndex < males.size() && (groupVo.getManUserNum() == -1 || currentMaleCount < groupVo.getManUserNum())) {
|
if (maleIndex < males.size() && (groupVo.getManUserNum() == -1 || currentMaleCount < groupVo.getManUserNum())) {
|
||||||
group.add(males.get(maleIndex++));
|
group.add(males.get(maleIndex++));
|
||||||
assigned = true;
|
assigned = true;
|
||||||
} else if (femaleIndex < females.size() && (groupVo.getWomanUserNum() == -1 || currentFemaleCount < groupVo.getWomanUserNum())) {
|
} else if (femaleIndex < females.size() && (groupVo.getWomanUserNum() == -1 || currentFemaleCount < groupVo.getWomanUserNum())) {
|
||||||
group.add(females.get(femaleIndex++));
|
group.add(females.get(femaleIndex++));
|
||||||
assigned = true;
|
assigned = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!assigned) {
|
if (!assigned) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unassignedUsers.addAll(males.subList(maleIndex, males.size()));
|
unassignedUsers.addAll(males.subList(maleIndex, males.size()));
|
||||||
unassignedUsers.addAll(females.subList(femaleIndex, females.size()));
|
unassignedUsers.addAll(females.subList(femaleIndex, females.size()));
|
||||||
|
|
||||||
// 往组别表里面添加记录
|
// 往组别表里面添加记录
|
||||||
List<ActGroup> groupList = IntStream.range(0, groups.size())
|
List<ActGroup> groupList = IntStream.range(0, groups.size())
|
||||||
.mapToObj(index -> {
|
.mapToObj(index -> {
|
||||||
ActGroup actGroup = new ActGroup();
|
ActGroup actGroup = new ActGroup();
|
||||||
actGroup.setActivityId(groupVo.getActivityId());
|
actGroup.setActivityId(groupVo.getActivityId());
|
||||||
actGroup.setGroupName("第" + (index + 1) + "队");
|
actGroup.setGroupName("第" + (index + 1) + "队");
|
||||||
actGroup.setSort(index + 1);
|
actGroup.setSort(index + 1);
|
||||||
|
|
||||||
List<ActGroupUser> userList = groups.get(index).stream().map(v -> {
|
List<ActGroupUser> userList = groups.get(index).stream().map(v -> {
|
||||||
ActGroupUser user = new ActGroupUser();
|
ActGroupUser user = new ActGroupUser();
|
||||||
user.setUserId(v.getUserId());
|
user.setUserId(v.getUserId());
|
||||||
user.setActivityId(groupVo.getActivityId());
|
user.setActivityId(groupVo.getActivityId());
|
||||||
return user;
|
return user;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
actGroup.setGroupUsers(userList);
|
actGroup.setGroupUsers(userList);
|
||||||
return actGroup;
|
return actGroup;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
|
||||||
// 所有项目
|
// 所有项目
|
||||||
List<ActivityItem> actItemList = dao().query(ActivityItem.class, Cnd.where(ActivityItem::getActivityId, "=", groupVo.getActivityId()));
|
List<ActivityItem> actItemList = dao().query(ActivityItem.class, Cnd.where(ActivityItem::getActivityId, "=", groupVo.getActivityId()));
|
||||||
// 往项目得分表里面插记录
|
// 往项目得分表里面插记录
|
||||||
List<ActItemGroupScore> itemGroupScoreList = new ArrayList<>();
|
List<ActItemGroupScore> itemGroupScoreList = new ArrayList<>();
|
||||||
|
|
||||||
for (ActGroup group : groupList) {
|
for (ActGroup group : groupList) {
|
||||||
dao().insertWith(group, "groupUsers");
|
dao().insertWith(group, "groupUsers");
|
||||||
|
|
||||||
// 构建小组项目得分表
|
// 构建小组项目得分表
|
||||||
List<ActItemGroupScore> groupScoreList = actItemList.stream().map(item -> {
|
List<ActItemGroupScore> groupScoreList = actItemList.stream().map(item -> {
|
||||||
ActItemGroupScore itemGroupScore = new ActItemGroupScore();
|
ActItemGroupScore itemGroupScore = new ActItemGroupScore();
|
||||||
itemGroupScore.setActivityId(groupVo.getActivityId());
|
itemGroupScore.setActivityId(groupVo.getActivityId());
|
||||||
itemGroupScore.setItemId(item.getId());
|
itemGroupScore.setItemId(item.getId());
|
||||||
itemGroupScore.setGroupId(group.getId());
|
itemGroupScore.setGroupId(group.getId());
|
||||||
return itemGroupScore;
|
return itemGroupScore;
|
||||||
}).toList();
|
}).toList();
|
||||||
itemGroupScoreList.addAll(groupScoreList);
|
itemGroupScoreList.addAll(groupScoreList);
|
||||||
}
|
}
|
||||||
dao().insert(itemGroupScoreList);
|
dao().insert(itemGroupScoreList);
|
||||||
|
|
||||||
// 添加未能正确分组的人员
|
// 添加未能正确分组的人员
|
||||||
List<ActUnGroupUser> userList = unassignedUsers.stream().map(v -> {
|
List<ActUnGroupUser> userList = unassignedUsers.stream().map(v -> {
|
||||||
ActUnGroupUser user = new ActUnGroupUser();
|
ActUnGroupUser user = new ActUnGroupUser();
|
||||||
user.setUserId(v.getUserId());
|
user.setUserId(v.getUserId());
|
||||||
user.setActivityId(groupVo.getActivityId());
|
user.setActivityId(groupVo.getActivityId());
|
||||||
return user;
|
return user;
|
||||||
}).toList();
|
}).toList();
|
||||||
dao().insert(userList);
|
dao().insert(userList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public void unGroupUserSetting(ActUnGroupUserVo unGroupUserVo) {
|
public void unGroupUserSetting(ActUnGroupUserVo unGroupUserVo) {
|
||||||
// 查询还没有分组的人员
|
// 查询还没有分组的人员
|
||||||
List<ActUnGroupUser> query = dao().query(ActUnGroupUser.class, Cnd.where(ActUnGroupUser::getActivityId, "=", unGroupUserVo.getActivityId()));
|
List<ActUnGroupUser> query = dao().query(ActUnGroupUser.class, Cnd.where(ActUnGroupUser::getActivityId, "=", unGroupUserVo.getActivityId()));
|
||||||
Set<Long> userIds = query.stream().map(ActUnGroupUser::getUserId).collect(Collectors.toSet());
|
Set<Long> userIds = query.stream().map(ActUnGroupUser::getUserId).collect(Collectors.toSet());
|
||||||
// 删除这些人员的分组信息
|
// 删除这些人员的分组信息
|
||||||
dao().clear(ActGroupUser.class, Cnd.where(ActGroupUser::getActivityId, "=", unGroupUserVo.getActivityId()).and(ActGroupUser::getUserId, "in", userIds));
|
dao().clear(ActGroupUser.class, Cnd.where(ActGroupUser::getActivityId, "=", unGroupUserVo.getActivityId()).and(ActGroupUser::getUserId, "in", userIds));
|
||||||
|
|
||||||
if (unGroupUserVo.getIsSeparateGroup() != null && unGroupUserVo.getIsSeparateGroup()) {
|
if (unGroupUserVo.getIsSeparateGroup() != null && unGroupUserVo.getIsSeparateGroup()) {
|
||||||
// 构建分组用户
|
// 构建分组用户
|
||||||
List<ActGroupUser> userList = query.stream().map(v -> {
|
List<ActGroupUser> userList = query.stream().map(v -> {
|
||||||
ActGroupUser user = new ActGroupUser();
|
ActGroupUser user = new ActGroupUser();
|
||||||
user.setActivityId(unGroupUserVo.getActivityId());
|
user.setActivityId(unGroupUserVo.getActivityId());
|
||||||
user.setUserId(v.getUserId());
|
user.setUserId(v.getUserId());
|
||||||
if (v.getUserId().equals(unGroupUserVo.getLeaderId())) {
|
if (v.getUserId().equals(unGroupUserVo.getLeaderId())) {
|
||||||
user.setIsLeader(true);
|
user.setIsLeader(true);
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
// 查询出这个活动下最大的排序
|
// 查询出这个活动下最大的排序
|
||||||
ActGroup sort = dao().fetch(ActGroup.class, Cnd.NEW().desc("sort"));
|
ActGroup sort = dao().fetch(ActGroup.class, Cnd.NEW().desc("sort"));
|
||||||
|
|
||||||
// 单独分组构建
|
// 单独分组构建
|
||||||
ActGroup actGroup = new ActGroup();
|
ActGroup actGroup = new ActGroup();
|
||||||
actGroup.setActivityId(unGroupUserVo.getActivityId());
|
actGroup.setActivityId(unGroupUserVo.getActivityId());
|
||||||
actGroup.setGroupName(unGroupUserVo.getGroupName());
|
actGroup.setGroupName(unGroupUserVo.getGroupName());
|
||||||
actGroup.setSort(sort.getSort() + 1);
|
actGroup.setSort(sort.getSort() + 1);
|
||||||
actGroup.setGroupUsers(userList);
|
actGroup.setGroupUsers(userList);
|
||||||
dao().insertWith(actGroup, "groupUsers");
|
dao().insertWith(actGroup, "groupUsers");
|
||||||
|
|
||||||
// 同时还要往小组得分记录表中查活动项目的数据
|
// 同时还要往小组得分记录表中查活动项目的数据
|
||||||
List<ActivityItem> itemList = dao().query(ActivityItem.class, Cnd.where(ActivityItem::getActivityId, "=", unGroupUserVo.getActivityId()));
|
List<ActivityItem> itemList = dao().query(ActivityItem.class, Cnd.where(ActivityItem::getActivityId, "=", unGroupUserVo.getActivityId()));
|
||||||
// 构建小组项目得分表
|
// 构建小组项目得分表
|
||||||
List<ActItemGroupScore> scoreList = itemList.stream().map(v -> {
|
List<ActItemGroupScore> scoreList = itemList.stream().map(v -> {
|
||||||
ActItemGroupScore itemGroupScore = new ActItemGroupScore();
|
ActItemGroupScore itemGroupScore = new ActItemGroupScore();
|
||||||
itemGroupScore.setActivityId(unGroupUserVo.getActivityId());
|
itemGroupScore.setActivityId(unGroupUserVo.getActivityId());
|
||||||
itemGroupScore.setItemId(v.getId());
|
itemGroupScore.setItemId(v.getId());
|
||||||
itemGroupScore.setGroupId(actGroup.getId());
|
itemGroupScore.setGroupId(actGroup.getId());
|
||||||
return itemGroupScore;
|
return itemGroupScore;
|
||||||
}).toList();
|
}).toList();
|
||||||
dao().insert(scoreList);
|
dao().insert(scoreList);
|
||||||
} else {
|
} else {
|
||||||
// 不单独分组,分配到其他队伍
|
// 不单独分组,分配到其他队伍
|
||||||
List<ActGroupUser> unGroupUser = unGroupUserVo.getUnGroupUser();
|
List<ActGroupUser> unGroupUser = unGroupUserVo.getUnGroupUser();
|
||||||
Map<Long, ActGroupUser> map = unGroupUser.stream().collect(Collectors.toMap(ActGroupUser::getUserId, v -> v));
|
Map<Long, ActGroupUser> map = unGroupUser.stream().collect(Collectors.toMap(ActGroupUser::getUserId, v -> v));
|
||||||
|
|
||||||
List<ActGroupUser> userList = query.stream().map(v -> {
|
List<ActGroupUser> userList = query.stream().map(v -> {
|
||||||
// 要保证传递过来的数据中,不在数据表中存储的这些人员不插入
|
// 要保证传递过来的数据中,不在数据表中存储的这些人员不插入
|
||||||
ActGroupUser groupUser = map.get(v.getUserId());
|
ActGroupUser groupUser = map.get(v.getUserId());
|
||||||
if (groupUser != null) {
|
if (groupUser != null) {
|
||||||
groupUser.setUserId(v.getUserId());
|
groupUser.setUserId(v.getUserId());
|
||||||
groupUser.setActivityId(unGroupUserVo.getActivityId());
|
groupUser.setActivityId(unGroupUserVo.getActivityId());
|
||||||
groupUser.setGroupId(groupUser.getGroupId());
|
groupUser.setGroupId(groupUser.getGroupId());
|
||||||
return groupUser;
|
return groupUser;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).filter(Objects::nonNull).toList();
|
}).filter(Objects::nonNull).toList();
|
||||||
dao().insert(userList);
|
dao().insert(userList);
|
||||||
}
|
}
|
||||||
// 分完之后,删除这个活动下的未分组人员
|
// 分完之后,删除这个活动下的未分组人员
|
||||||
dao().clear(ActUnGroupUser.class, Cnd.where(ActUnGroupUser::getActivityId, "=", unGroupUserVo.getActivityId()));
|
dao().clear(ActUnGroupUser.class, Cnd.where(ActUnGroupUser::getActivityId, "=", unGroupUserVo.getActivityId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<NutMap> unGroupUsers(Long activityId) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
au.*
|
||||||
|
FROM
|
||||||
|
act_user au
|
||||||
|
LEFT JOIN act_group_user agu ON au.userId = agu.userId
|
||||||
|
AND agu.activityId = @activityId
|
||||||
|
WHERE
|
||||||
|
au.activityId = @activityId
|
||||||
|
AND au.isSignIn = 1
|
||||||
|
AND agu.userId IS NULL
|
||||||
|
""");
|
||||||
|
sql.params().set("activityId", activityId);
|
||||||
|
return listMap(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<NutMap> listGroupAndUsers(Long activityId) {
|
||||||
|
List<ActGroup> groups = dao().query(ActGroup.class, Cnd.where(ActGroup::getActivityId, "=", activityId));
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
u.*,
|
||||||
|
augu.groupId
|
||||||
|
FROM
|
||||||
|
act_group_user augu
|
||||||
|
LEFT JOIN act_user u ON u.userId = augu.userId
|
||||||
|
WHERE augu.activityId = @activityId
|
||||||
|
""");
|
||||||
|
sql.setParam("activityId", activityId);
|
||||||
|
List<NutMap> users = listMap(sql);
|
||||||
|
|
||||||
|
List<NutMap> groupFull = BeanUtil.copyToList(groups, NutMap.class);
|
||||||
|
for (NutMap group : groupFull) {
|
||||||
|
group.setv("members", users.stream().filter(v -> v.getLong("groupId") == group.getLong("id")).toList());
|
||||||
|
}
|
||||||
|
return groupFull;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.budwk.app.module.activity.service.impl;
|
||||||
|
|
||||||
|
import com.budwk.app.base.service.BaseService;
|
||||||
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
|
import com.budwk.app.module.activity.models.ActRankScore;
|
||||||
|
import com.budwk.app.module.activity.service.ActRankScoreService;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
|
@IocBean(args = {"refer:dao"})
|
||||||
|
public class ActRankScoreServiceImpl extends BaseServiceImpl<ActRankScore> implements ActRankScoreService {
|
||||||
|
public ActRankScoreServiceImpl(Dao dao) {
|
||||||
|
super(dao);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.budwk.app.module.activity.vo;
|
||||||
|
|
||||||
|
import com.budwk.app.module.activity.models.ActGroupUser;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ActManualGroupVo {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private Long groupName;
|
||||||
|
|
||||||
|
private List<ActGroupUser> members;
|
||||||
|
}
|
||||||
@@ -38,7 +38,8 @@ public class SysHomeController {
|
|||||||
// return "beetl:/platform/sys/dashboard.html";
|
// return "beetl:/platform/sys/dashboard.html";
|
||||||
// }
|
// }
|
||||||
// return "beetl:/platform/sys/home.html";
|
// return "beetl:/platform/sys/home.html";
|
||||||
return "beetl:/platform/activity/manage/index.html";
|
// return "beetl:/platform/activity/manage/index.html";
|
||||||
|
return ">>:/platform/activity/manage";
|
||||||
}
|
}
|
||||||
|
|
||||||
@At("/403")
|
@At("/403")
|
||||||
|
|||||||
@@ -60,6 +60,6 @@
|
|||||||
|
|
||||||
.el-button--primary {
|
.el-button--primary {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #1867b0;
|
background-color: #3E54AC;
|
||||||
border-color: #1867b0;
|
border-color: #3E54AC;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
Vue.mixin({
|
||||||
|
mounted() {
|
||||||
|
if (this.$options.style) {
|
||||||
|
const styleId = `style-${this._uid}`
|
||||||
|
const style = document.createElement("style")
|
||||||
|
style.id = styleId
|
||||||
|
//支持函数和字符串
|
||||||
|
const css = typeof this.$options.style === "function" ? this.$options.style.call(this) : this.$options.style
|
||||||
|
style.textContent = css
|
||||||
|
document.head.appendChild(style)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.$options.style) {
|
||||||
|
const styleId = `style-${this._uid}`
|
||||||
|
const style = document.getElementById(styleId)
|
||||||
|
if (style) {
|
||||||
|
document.head.removeChild(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
Vue.mixin({
|
||||||
|
mounted() {
|
||||||
|
if (this.$options.style) {
|
||||||
|
const styleId = `style-${this._uid}`
|
||||||
|
const style = document.createElement("style")
|
||||||
|
style.id = styleId
|
||||||
|
//支持函数和字符串
|
||||||
|
const css = typeof this.$options.style === "function" ? this.$options.style.call(this) : this.$options.style
|
||||||
|
style.textContent = css
|
||||||
|
document.head.appendChild(style)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.$options.style) {
|
||||||
|
const styleId = `style-${this._uid}`
|
||||||
|
const style = document.getElementById(styleId)
|
||||||
|
if (style) {
|
||||||
|
document.head.removeChild(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
+2
-2
File diff suppressed because one or more lines are too long
@@ -39,8 +39,11 @@
|
|||||||
<script src="${base!}/assets/platform/plugins/echarts/echarts.min.js"></script>
|
<script src="${base!}/assets/platform/plugins/echarts/echarts.min.js"></script>
|
||||||
<!-- qrcode -->
|
<!-- qrcode -->
|
||||||
<script src="${base!}/assets/platform/plugins/qrcode/qrcode.min.js"></script>
|
<script src="${base!}/assets/platform/plugins/qrcode/qrcode.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.24.3/vuedraggable.umd.min.js"></script>
|
||||||
<!-- 自定义工具类 -->
|
<!-- 自定义工具类 -->
|
||||||
<script src="${base!}/assets/platform/module/mixins/initTableMixins.js?v=1.0.0"></script>
|
<script src="${base!}/assets/platform/module/mixins/initTableMixins.js?v=1.0.0"></script>
|
||||||
|
<script src="${base!}/assets/platform/module/mixins/styleMixin.js"></script>
|
||||||
<!-- main -->
|
<!-- main -->
|
||||||
<script src="${base!}/assets/platform/js/main.js?v=1.0.1"></script>
|
<script src="${base!}/assets/platform/js/main.js?v=1.0.1"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -58,14 +58,19 @@ layout("/layouts/platform_1.html"){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<el-card shadow="never" class="mt-3">
|
<el-card shadow="never" class="mt-3">
|
||||||
<el-row type="flex" style="justify-content: flex-start" class="mb-3">
|
<el-row type="flex" style="justify-content: flex-start" class="mb-3">
|
||||||
<el-button type="primary" size="small" @click="openGrouping">开始分组</el-button>
|
<el-button type="primary" size="small" @click="openGrouping">开始分组</el-button>
|
||||||
<div v-if="unGroupUser && unGroupUser.length > 0" style="margin-left: 10px; display: inline-block;">
|
<!-- <div v-if="unGroupUser && unGroupUser.length > 0" style="margin-left: 10px; display: inline-block;">-->
|
||||||
<el-button type="warning" size="small" style="position: relative;" @click="doUnGroupUserSetting">
|
<!-- <el-button type="warning" size="small" style="position: relative;" @click="doUnGroupUserSetting">-->
|
||||||
未分组人员
|
<!-- 未分组人员-->
|
||||||
<span class="un_group_user_span">{{ unGroupUser.length }}</span>
|
<!-- <span class="un_group_user_span">{{ unGroupUser.length }}</span>-->
|
||||||
|
<!-- </el-button>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<div style="margin-left: 10px; display: inline-block;">
|
||||||
|
<el-button type="warning" size="small" style="position: relative;" @click="$refs.manualGroupRef.onOpen(pageForm.activityId)">
|
||||||
|
手动分组
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -96,16 +101,19 @@ layout("/layouts/platform_1.html"){
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<group-setting ref="groupSettingRef" @success="successGroup"></group-setting>
|
<group-setting ref="groupSettingRef" @success="successGroup"></group-setting>
|
||||||
|
|
||||||
<un-group-user ref="unGroupUserRef" @success="successGroup"></un-group-user>
|
<un-group-user ref="unGroupUserRef" @success="successGroup"></un-group-user>
|
||||||
|
|
||||||
|
<manual-group ref="manualGroupRef" @success="successGroup"></manual-group>
|
||||||
|
|
||||||
<view-info ref="viewInfoRef"></view-info>
|
<view-info ref="viewInfoRef"></view-info>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
<!--#include('groupSetting.js'){}#-->
|
<!--#include('groupSetting.js'){}#-->
|
||||||
<!--#include('unGroupUser.js'){}#-->
|
<!--#include('unGroupUser.js'){}#-->
|
||||||
|
<!--#include('manualGroup.js'){}#-->
|
||||||
<!--#include('viewInfo.js'){}#-->
|
<!--#include('viewInfo.js'){}#-->
|
||||||
new Vue({
|
new Vue({
|
||||||
el: "#app",
|
el: "#app",
|
||||||
@@ -113,6 +121,7 @@ layout("/layouts/platform_1.html"){
|
|||||||
components: {
|
components: {
|
||||||
"group-setting": GROUP_SETTING,
|
"group-setting": GROUP_SETTING,
|
||||||
"un-group-user": UN_GROUP_USER,
|
"un-group-user": UN_GROUP_USER,
|
||||||
|
"manual-group": manualGroup,
|
||||||
"view-info": VIEW_INFO
|
"view-info": VIEW_INFO
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -0,0 +1,749 @@
|
|||||||
|
const manualGroup = {
|
||||||
|
template: /*language=HTML*/ `
|
||||||
|
<el-dialog title="手动分组" :visible.sync="groupingDialog" width="80%" class="manual-group-dialog" fullscreen>
|
||||||
|
<div class="manual-group-content-wrap">
|
||||||
|
<div class="personnel-pool">
|
||||||
|
<div class="pool-header">
|
||||||
|
<h3>人员池</h3>
|
||||||
|
</div>
|
||||||
|
<div class="pool-content">
|
||||||
|
<div class="search-wrapper">
|
||||||
|
<i class="el-icon-search search-icon"></i>
|
||||||
|
<el-input
|
||||||
|
v-model="searchQuery"
|
||||||
|
placeholder="搜索人员..."
|
||||||
|
clearable>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="personnel-list">
|
||||||
|
<draggable
|
||||||
|
:list="filteredPersonnel"
|
||||||
|
:group="{name:'people', pull: pullFunction, put: true}"
|
||||||
|
class="dragArea"
|
||||||
|
ghost-class="ghost"
|
||||||
|
@end="onDragEnd"
|
||||||
|
@add="onPersonnelAdd">
|
||||||
|
<div v-for="(person, index) in filteredPersonnel" :key="index" class="person-card">
|
||||||
|
<div class="person-header">
|
||||||
|
<div class="person-name">{{ person.userName }}</div>
|
||||||
|
<div class="person-gender" :class="person.sex === '男' ? 'male' : 'female'">
|
||||||
|
{{ person.sex }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="person-unit">{{ person.unitName }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="filteredPersonnel.length === 0" class="no-members">
|
||||||
|
<i class="el-icon-warning-outline" style="margin-right: 5px;"></i> 无可用人员
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stats">
|
||||||
|
<i class="el-icon-user stats-icon"></i>
|
||||||
|
共 {{ availablePersonnel.length }} 人可分配
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="groups-area">
|
||||||
|
<div class="group-container-header">
|
||||||
|
<h3>分组管理</h3>
|
||||||
|
<div class="create-text" @click="addNewGroup">
|
||||||
|
<i class="el-icon-plus"></i> 创建新分组
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="groups-container">
|
||||||
|
<div v-for="(group, groupIndex) in groups" :key="groupIndex" class="group-card">
|
||||||
|
<div class="group-header">
|
||||||
|
<div class="group-title">
|
||||||
|
<el-input
|
||||||
|
v-model="group.groupName"
|
||||||
|
placeholder="请输入组名"
|
||||||
|
size="small"
|
||||||
|
class="group-title-input">
|
||||||
|
</el-input>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
size="mini"
|
||||||
|
circle
|
||||||
|
@click="removeGroup(groupIndex)">
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="group-content">
|
||||||
|
<div>
|
||||||
|
<div class="group-members-header">
|
||||||
|
<div class="members-title">
|
||||||
|
队员 <span class="members-count">{{ group.members.length }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<draggable
|
||||||
|
v-model="group.members"
|
||||||
|
:group="{name: 'people', pull: true, put: true}"
|
||||||
|
class="group-members"
|
||||||
|
ghost-class="ghost"
|
||||||
|
@end="onDragEnd"
|
||||||
|
@remove="onMemberRemove">
|
||||||
|
<div v-for="(member, memberIndex) in group.members" :key="memberIndex"
|
||||||
|
class="person-card">
|
||||||
|
<div class="person-header">
|
||||||
|
<div class="person-name">{{ member.userName }}</div>
|
||||||
|
<div class="person-gender"
|
||||||
|
:class="member.sex === '男' ? 'male' : 'female'">{{ member.sex }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="person-unit">{{ member.unitName }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="group.members.length === 0" class="no-members">
|
||||||
|
<i class="el-icon-d-arrow-left"></i> 拖动人员至此添加队员
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="groups.length === 0" class="empty-groups">
|
||||||
|
<i class="el-icon-collection empty-icon"></i>
|
||||||
|
<div class="empty-text">暂无分组,请点击上方"创建新分组"按钮开始组建团队</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="groupingDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
groupingDialog: false,
|
||||||
|
searchQuery: "",
|
||||||
|
availablePersonnel: [],
|
||||||
|
groups: [],
|
||||||
|
activityId: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredPersonnel() {
|
||||||
|
if (!this.searchQuery) {
|
||||||
|
return this.availablePersonnel
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = this.searchQuery.toLowerCase()
|
||||||
|
return this.availablePersonnel.filter(person => {
|
||||||
|
return person.userName?.toLowerCase().includes(query) ||
|
||||||
|
person.unitName?.toLowerCase().includes(query)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 控制拖动行为
|
||||||
|
pullFunction() {
|
||||||
|
return "clone" // 使用克隆模式,这样拖动不会改变原始数组
|
||||||
|
},
|
||||||
|
async onOpen(activityId) {
|
||||||
|
this.groupingDialog = true
|
||||||
|
this.activityId = activityId
|
||||||
|
|
||||||
|
$.post("/platform/activity/group/unGroupUsers", { activityId }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.availablePersonnel = res.data
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$.post("/platform/activity/group/listGroup", { activityId }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.groups = res.data
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSubmit() {
|
||||||
|
// 准备每个小组的数据
|
||||||
|
const groupData = this.groups.map(group => {
|
||||||
|
return {
|
||||||
|
id: group.id,
|
||||||
|
groupName: group.groupName,
|
||||||
|
groupUsers: group.members.map(member => ({
|
||||||
|
userId: member.userId,
|
||||||
|
groupId: group.id,
|
||||||
|
userName: member.userName
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 打印每个小组的数据
|
||||||
|
console.log("分组数据:", JSON.stringify(groupData, null, 2))
|
||||||
|
|
||||||
|
// 检查是否有空组名
|
||||||
|
const emptyNameGroup = this.groups.find(group => !group.groupName || group.groupName.trim() === "")
|
||||||
|
if (emptyNameGroup) {
|
||||||
|
this.$message.warning("存在未命名的分组,请为所有分组命名")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查重复组名
|
||||||
|
const duplicateNameGroup = this.groups.find(group => {
|
||||||
|
const groupName = group.groupName.trim()
|
||||||
|
return groupName && this.groups.some(g => g !== group && g.groupName.trim() === groupName)
|
||||||
|
})
|
||||||
|
if (duplicateNameGroup) {
|
||||||
|
this.$message.warning("存在重复的分组名称,请修改分组名称")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有空组
|
||||||
|
const emptyGroup = this.groups.find(group => group.members.length === 0)
|
||||||
|
if (emptyGroup) {
|
||||||
|
this.$confirm("分组" + emptyGroup.groupName + "中没有成员,是否继续保存?", "提示", {
|
||||||
|
confirmButtonText: "继续保存",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.saveGroups(groupData)
|
||||||
|
}).catch(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.saveGroups(groupData)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async saveGroups(groupData) {
|
||||||
|
// 显示加载状态
|
||||||
|
const loading = this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: "保存中...",
|
||||||
|
spinner: "el-icon-loading",
|
||||||
|
background: "rgba(0, 0, 0, 0.7)"
|
||||||
|
})
|
||||||
|
|
||||||
|
const { code, msg } = await $.post("/platform/activity/group/manualSetGroup", {
|
||||||
|
actGroups: JSON.stringify(groupData),
|
||||||
|
activityId: this.activityId
|
||||||
|
})
|
||||||
|
loading.close()
|
||||||
|
if (code === 0) {
|
||||||
|
this.groupingDialog = false
|
||||||
|
this.$message.success(msg)
|
||||||
|
this.$emit("success")
|
||||||
|
} else {
|
||||||
|
this.$message.error(msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDragEnd(evt) {
|
||||||
|
if (evt.from.className.includes("dragArea") && evt.to.className.includes("group-members")) {
|
||||||
|
// 从人员池拖到分组时,需要从availablePersonnel中移除
|
||||||
|
const draggedPerson = this.filteredPersonnel[evt.oldIndex]
|
||||||
|
const indexInAvailable = this.availablePersonnel.findIndex(p => p.userId === draggedPerson.userId)
|
||||||
|
|
||||||
|
if (indexInAvailable > -1) {
|
||||||
|
this.availablePersonnel.splice(indexInAvailable, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置目标组的groupId
|
||||||
|
const targetGroup = this.findGroupByDomElement(evt.to)
|
||||||
|
if (targetGroup) {
|
||||||
|
// 找到刚刚拖入的成员并设置其groupId
|
||||||
|
const newIndex = evt.newIndex
|
||||||
|
if (targetGroup.members[newIndex]) {
|
||||||
|
targetGroup.members[newIndex].groupId = targetGroup.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (evt.from.className.includes("group-members") && evt.to.className.includes("group-members")) {
|
||||||
|
// 在分组之间拖动时,确保正确设置groupId
|
||||||
|
const targetGroup = this.findGroupByDomElement(evt.to)
|
||||||
|
if (targetGroup) {
|
||||||
|
// 找到刚刚拖入的成员并设置其groupId
|
||||||
|
const newIndex = evt.newIndex
|
||||||
|
if (targetGroup.members[newIndex]) {
|
||||||
|
targetGroup.members[newIndex].groupId = targetGroup.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保所有组内都没有重复的人员
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.removeDuplicates()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeDuplicates() {
|
||||||
|
// 收集所有已分配人员的ID
|
||||||
|
const assignedIds = new Set()
|
||||||
|
|
||||||
|
// 检查每个组的成员
|
||||||
|
this.groups.forEach(group => {
|
||||||
|
// 检查组内成员是否有重复
|
||||||
|
const uniqueMembers = []
|
||||||
|
group.members.forEach(member => {
|
||||||
|
if (!assignedIds.has(member.userId)) {
|
||||||
|
assignedIds.add(member.userId)
|
||||||
|
uniqueMembers.push(member)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
group.members = uniqueMembers
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新availablePersonnel,移除已分配的人员
|
||||||
|
this.availablePersonnel = this.availablePersonnel.filter(person => !assignedIds.has(person.userId))
|
||||||
|
},
|
||||||
|
addNewGroup() {
|
||||||
|
this.groups.push({
|
||||||
|
id: Date.now(), // 临时ID,后端会重新分配
|
||||||
|
groupName: "分组 " + (this.groups.length + 1),
|
||||||
|
activityId: this.activityId,
|
||||||
|
members: []
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$notify({
|
||||||
|
title: "成功",
|
||||||
|
message: "已创建新分组",
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeGroup(index) {
|
||||||
|
this.$confirm("确定要删除该分组吗?所有队员将返回人员池", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
// 将组内人员返回到人员池
|
||||||
|
const group = this.groups[index]
|
||||||
|
group.members.forEach(member => {
|
||||||
|
this.availablePersonnel.push({ ...member })
|
||||||
|
})
|
||||||
|
|
||||||
|
// 删除组
|
||||||
|
this.groups.splice(index, 1)
|
||||||
|
this.$message({
|
||||||
|
type: "success",
|
||||||
|
message: "删除成功!"
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
// 取消删除
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onPersonnelAdd(evt) {
|
||||||
|
// 当成员被拖回人员池时,会触发此方法
|
||||||
|
// 不需要特殊处理,因为:
|
||||||
|
// 1. Vue自动处理了filteredPersonnel的更新
|
||||||
|
// 2. 源组的成员会在拖动结束时自动移除
|
||||||
|
// 3. removeDuplicates方法会确保没有重复
|
||||||
|
|
||||||
|
// 确保availablePersonnel同步更新
|
||||||
|
if (!this.availablePersonnel.some(p => p.userId === this.filteredPersonnel[evt.newIndex].userId)) {
|
||||||
|
this.availablePersonnel.push(this.filteredPersonnel[evt.newIndex])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
findGroupByDomElement(element) {
|
||||||
|
// 通过DOM元素查找对应的分组数据
|
||||||
|
const groupIndex = this.findGroupIndexByDomElement(element)
|
||||||
|
return groupIndex !== -1 ? this.groups[groupIndex] : null
|
||||||
|
},
|
||||||
|
findGroupIndexByDomElement(element) {
|
||||||
|
// 查找包含该DOM元素的分组索引
|
||||||
|
const groupCard = this.findParentWithClass(element, "group-card")
|
||||||
|
if (!groupCard) return -1
|
||||||
|
|
||||||
|
const groupCards = Array.from(document.querySelectorAll(".group-card"))
|
||||||
|
return groupCards.indexOf(groupCard)
|
||||||
|
},
|
||||||
|
findParentWithClass(element, className) {
|
||||||
|
// 查找具有特定类名的父元素
|
||||||
|
let parent = element
|
||||||
|
while (parent && !parent.classList.contains(className)) {
|
||||||
|
parent = parent.parentElement
|
||||||
|
}
|
||||||
|
return parent
|
||||||
|
},
|
||||||
|
onMemberRemove(evt) {
|
||||||
|
// 当成员被从分组移除时触发(可能是拖到人员池或其他分组)
|
||||||
|
// 如果是拖到人员池,我们需要确保availablePersonnel中添加了这个成员
|
||||||
|
const groupIndex = this.findGroupIndexByDomElement(evt.from)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: /*language=CSS*/ `
|
||||||
|
.manual-group-dialog .el-dialog__body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-group-content-wrap {
|
||||||
|
display: flex;
|
||||||
|
padding: 20px;
|
||||||
|
gap: 20px;
|
||||||
|
min-height: 500px;
|
||||||
|
height: calc(100vh - 115px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.personnel-pool {
|
||||||
|
width: 300px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
height: fit-content;
|
||||||
|
max-height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pool-header, .group-container-header {
|
||||||
|
background-color: #3E54AC;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pool-header h3, .group-container-header h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pool-content {
|
||||||
|
padding: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
cursor: move;
|
||||||
|
border-left: 3px solid #7286D3;
|
||||||
|
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(135deg, rgba(114, 134, 211, 0.12), transparent);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-card:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-card:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #2B3A55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-gender {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: white;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.male {
|
||||||
|
background-color: #7286D3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.female {
|
||||||
|
background-color: #F87474;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-unit {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-unit::before {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background-color: #64748b;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.groups-area {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.groups-container {
|
||||||
|
flex: 1;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
grid-auto-rows: min-content;
|
||||||
|
align-content: start;
|
||||||
|
align-items: start;
|
||||||
|
justify-items: stretch;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
max-height: 500px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-top: 5px solid #3E54AC;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-header {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: var(--primary-light);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-title-input .el-input__inner {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2B3A55;
|
||||||
|
height: 36px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-title-input .el-input__inner:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-content {
|
||||||
|
padding: 15px;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 150px;
|
||||||
|
/*max-height: 384px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-leader {
|
||||||
|
background: #f0f9ff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
position: relative;
|
||||||
|
border-left: 3px solid #36AE7C;
|
||||||
|
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.leader-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: -8px;
|
||||||
|
right: -8px;
|
||||||
|
background-color: #36AE7C;
|
||||||
|
color: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 2px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-members-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2B3A55;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-count {
|
||||||
|
background-color: var(--primary-light);
|
||||||
|
color: #3E54AC;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-members {
|
||||||
|
min-height: 50px;
|
||||||
|
padding: 8px 0;
|
||||||
|
/*max-height: 250px;*/
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost {
|
||||||
|
opacity: 0.4;
|
||||||
|
background: #e0f2fe !important;
|
||||||
|
border: 1px dashed #7286D3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-members {
|
||||||
|
color: #94a3b8;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
border: 2px dashed #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats {
|
||||||
|
margin-top: 12px;
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background-color: var(--primary-light);
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #3E54AC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrapper {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-wrapper .el-input__inner {
|
||||||
|
border-radius: 25px;
|
||||||
|
padding-left: 35px;
|
||||||
|
background-color: #f8fafc;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #94a3b8;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-text {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.15);
|
||||||
|
height: 24px; /* 与header高度匹配 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-text:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.25);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-text:active {
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-text i {
|
||||||
|
margin-right: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-leader, .leader-badge, .leader-actions {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-groups {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 50px 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 50px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.personnel-list {
|
||||||
|
overflow-y: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
@@ -0,0 +1,368 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_1.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.el-card {
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card__header {
|
||||||
|
background: #3E54AC;
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table {
|
||||||
|
margin: 15px 0;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-medal {
|
||||||
|
display: inline-block;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-medal-1 {
|
||||||
|
background-color: #f5c518;
|
||||||
|
box-shadow: 0 2px 4px rgba(245, 197, 24, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-medal-2 {
|
||||||
|
background-color: #c0c0c0;
|
||||||
|
box-shadow: 0 2px 4px rgba(192, 192, 192, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-medal-3 {
|
||||||
|
background-color: #cd7f32;
|
||||||
|
box-shadow: 0 2px 4px rgba(205, 127, 50, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-value {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-data {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 0;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-data i {
|
||||||
|
font-size: 50px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<el-card shadow="hover" class="" style="width: 800px;margin: 0 auto">
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span><i class="el-icon-trophy"></i> 名次积分管理</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="action-buttons">
|
||||||
|
<el-button-group>
|
||||||
|
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAddMultiple">批量添加</el-button>
|
||||||
|
<el-button type="success" size="small" icon="el-icon-refresh" @click="doSearch">刷新数据</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table v-loading="tableLoading" :data="tableData" border stripe>
|
||||||
|
<el-table-column label="名次">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<template v-if="scope.row.ranking === '第一名' || scope.row.ranking === '冠军' || scope.row.ranking === '1'">
|
||||||
|
<span class="rank-medal rank-medal-1">1</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="scope.row.ranking === '第二名' || scope.row.ranking === '亚军' || scope.row.ranking === '2'">
|
||||||
|
<span class="rank-medal rank-medal-2">2</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="scope.row.ranking === '第三名' || scope.row.ranking === '季军' || scope.row.ranking === '3'">
|
||||||
|
<span class="rank-medal rank-medal-3">3</span>
|
||||||
|
</template>
|
||||||
|
<span>{{ scope.row.ranking }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="积分">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span class="score-value">{{ scope.row.score }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="150" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="primary" icon="el-icon-edit" circle @click="handleEdit(scope.row)"></el-button>
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="handleDelete(scope.row)"></el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
|
|
||||||
|
<template v-if="tableData.length === 0">
|
||||||
|
<div class="empty-data">
|
||||||
|
<i class="el-icon-document"></i>
|
||||||
|
<p>暂无名次积分数据,请点击"批量添加"按钮添加</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-dialog title="编辑名次积分" :visible.sync="editDialogVisible" width="30%">
|
||||||
|
<el-form :model="editForm" :rules="rules" ref="editForm" label-width="80px">
|
||||||
|
<el-form-item label="名次" prop="ranking">
|
||||||
|
<el-input v-model="editForm.ranking" placeholder="请输入名次,可以是中文" prefix-icon="el-icon-trophy"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="积分" prop="score">
|
||||||
|
<el-input-number v-model="editForm.score" :precision="2" :step="1" :min="0"
|
||||||
|
style="width: 100%"></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="editDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitEditForm">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog title="批量添加名次积分" :visible.sync="batchAddDialogVisible" width="800px">
|
||||||
|
<el-form :model="batchForm" ref="batchForm">
|
||||||
|
<div class="batch-actions">
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" size="small" icon="el-icon-plus" @click="addBatchRow">添加一行</el-button>
|
||||||
|
<el-button type="danger" size="small" icon="el-icon-delete" @click="clearBatchRows">清空</el-button>
|
||||||
|
</div>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button size="small" type="primary" plain @click="addPresetRanks('123')">添加前三名</el-button>
|
||||||
|
<el-button size="small" type="primary" plain @click="addPresetRanks('champion')">添加冠亚季军</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
<el-table :data="batchForm.items" border style="width: 100%" stripe>
|
||||||
|
<el-table-column label="名次" width="180">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-form-item :prop="'items.' + scope.$index + '.ranking'" :rules="rules.ranking"
|
||||||
|
style="margin-bottom: 0;">
|
||||||
|
<el-input v-model="scope.row.ranking" placeholder="请输入名次" prefix-icon="el-icon-trophy"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="积分">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-form-item :prop="'items.' + scope.$index + '.score'" :rules="rules.score"
|
||||||
|
style="margin-bottom: 0;">
|
||||||
|
<el-input-number v-model="scope.row.score" :precision="2" :step="1" :min="0"
|
||||||
|
controls-position="right" style="width: 100%"></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="80" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-delete" circle
|
||||||
|
@click="removeBatchRow(scope.$index)"></el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="mt-2" v-if="batchError">
|
||||||
|
<el-alert :title="batchError" type="error" show-icon></el-alert>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="batchAddDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitBatchForm">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editDialogVisible: false,
|
||||||
|
batchAddDialogVisible: false,
|
||||||
|
editForm: {
|
||||||
|
id: null,
|
||||||
|
ranking: "",
|
||||||
|
score: 0
|
||||||
|
},
|
||||||
|
batchForm: {
|
||||||
|
items: []
|
||||||
|
},
|
||||||
|
batchError: "",
|
||||||
|
rules: {
|
||||||
|
ranking: [
|
||||||
|
{ required: true, message: "请输入名次", trigger: "blur" }
|
||||||
|
],
|
||||||
|
score: [
|
||||||
|
{ required: true, message: "请输入积分", trigger: "blur" },
|
||||||
|
{ type: "number", message: "积分必须是数字", trigger: "blur" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
editIndex: -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleAddMultiple() {
|
||||||
|
this.batchForm.items = [this.createEmptyBatchItem()]
|
||||||
|
this.batchError = ""
|
||||||
|
this.batchAddDialogVisible = true
|
||||||
|
},
|
||||||
|
createEmptyBatchItem() {
|
||||||
|
return {
|
||||||
|
id: null,
|
||||||
|
ranking: "",
|
||||||
|
score: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addBatchRow() {
|
||||||
|
this.batchForm.items.push(this.createEmptyBatchItem())
|
||||||
|
},
|
||||||
|
removeBatchRow(index) {
|
||||||
|
this.batchForm.items.splice(index, 1)
|
||||||
|
},
|
||||||
|
clearBatchRows() {
|
||||||
|
this.batchForm.items = []
|
||||||
|
},
|
||||||
|
addPresetRanks(type) {
|
||||||
|
if (type === '123') {
|
||||||
|
this.batchForm.items = [
|
||||||
|
{ id: null, ranking: "第一名", score: 100 },
|
||||||
|
{ id: null, ranking: "第二名", score: 80 },
|
||||||
|
{ id: null, ranking: "第三名", score: 60 }
|
||||||
|
]
|
||||||
|
} else if (type === 'champion') {
|
||||||
|
this.batchForm.items = [
|
||||||
|
{ id: null, ranking: "冠军", score: 100 },
|
||||||
|
{ id: null, ranking: "亚军", score: 80 },
|
||||||
|
{ id: null, ranking: "季军", score: 60 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleEdit(row) {
|
||||||
|
this.editForm = JSON.parse(JSON.stringify(row))
|
||||||
|
this.editIndex = this.tableData.findIndex(item => item.id === row.id)
|
||||||
|
this.editDialogVisible = true
|
||||||
|
},
|
||||||
|
handleDelete(row) {
|
||||||
|
this.$confirm("确定要删除这条记录吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
if (row.id) {
|
||||||
|
$.post("/platform/activity/rankScore/delete", { id: row.id }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success("删除成功")
|
||||||
|
this.pageData()
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const index = this.tableData.findIndex(item => item === row)
|
||||||
|
if (index !== -1) {
|
||||||
|
this.tableData.splice(index, 1)
|
||||||
|
this.$message.success("删除成功")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitEditForm() {
|
||||||
|
this.$refs.editForm.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
$.post("/platform/activity/rankScore/update").then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success("修改成功")
|
||||||
|
this.editDialogVisible = false
|
||||||
|
this.pageData()
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitBatchForm() {
|
||||||
|
if (this.batchForm.items.length === 0) {
|
||||||
|
this.$message.error("请至少添加一条记录")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.batchForm.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查新添加的记录中是否有重复的名次
|
||||||
|
const allRankings = this.batchForm.items.map(item => item.ranking)
|
||||||
|
const uniqueRankings = [...new Set(allRankings)]
|
||||||
|
if (allRankings.length !== uniqueRankings.length) {
|
||||||
|
this.batchError = "批量添加的数据中存在重复的名次,请检查"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$.post("/platform/activity/rankScore/save", { actRankScore: JSON.stringify(this.batchForm.items) }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success("保存成功")
|
||||||
|
this.batchAddDialogVisible = false
|
||||||
|
this.pageData()
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
// 检查是否有重复的名次
|
||||||
|
const rankings = this.tableData.map(item => item.ranking)
|
||||||
|
const uniqueRankings = [...new Set(rankings)]
|
||||||
|
if (rankings.length !== uniqueRankings.length) {
|
||||||
|
this.$message.error("存在重复的名次,请检查后重新提交")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$.post("/platform/activity/rankScore/save", { actRankScore: JSON.stringify(this.tableData) }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success("保存成功")
|
||||||
|
this.pageData()
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
@@ -0,0 +1,551 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_1.html"){
|
||||||
|
#-->
|
||||||
|
<div id="app">
|
||||||
|
<el-card shadow="never" class="filter-card">
|
||||||
|
<div class="search">
|
||||||
|
<div class="search-item">
|
||||||
|
<div class="search-item-label">年度</div>
|
||||||
|
<div class="search-item-option">
|
||||||
|
<el-date-picker
|
||||||
|
:clearable="false"
|
||||||
|
placeholder="选择年"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="listAct"
|
||||||
|
type="year"
|
||||||
|
v-model="pageForm.year"
|
||||||
|
value-format="yyyy"
|
||||||
|
></el-date-picker>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="search-item">
|
||||||
|
<div class="search-item-label">所属活动</div>
|
||||||
|
<div class="search-item-option">
|
||||||
|
<el-select v-model="pageForm.activityId" placeholder="请选择活动" @change="activityChange">
|
||||||
|
<el-option
|
||||||
|
v-for="item in activityOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.title"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-query">
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<div class="score-entry-container mt-3">
|
||||||
|
<div class="score-entry-header">
|
||||||
|
<div class="header-title">活动项目名次设置</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!pageForm.activityId" class="empty-state">
|
||||||
|
<i class="el-icon-data-analysis empty-icon"></i>
|
||||||
|
<div class="empty-text">请先选择活动</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="itemOptions.length === 0" class="empty-state">
|
||||||
|
<i class="el-icon-collection empty-icon"></i>
|
||||||
|
<div class="empty-text">暂无项目数据</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="score-tabs-container">
|
||||||
|
<el-tabs type="border-card" class="custom-tabs">
|
||||||
|
<el-tab-pane v-for="item in itemOptions" :key="item.id" :label="item.name">
|
||||||
|
<div class="item-info">
|
||||||
|
<div class="item-details">
|
||||||
|
<div class="detail-item">
|
||||||
|
<i class="el-icon-aim detail-icon"></i>
|
||||||
|
<span class="detail-label">项目形式:</span>
|
||||||
|
<span class="detail-content">{{item.form}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<i class="el-icon-set-up detail-icon"></i>
|
||||||
|
<span class="detail-label">项目规则:</span>
|
||||||
|
<span class="detail-content">{{item.rule}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-actions">
|
||||||
|
<el-button type="primary" size="small" @click="saveItemScores(item.id)" :loading="item.saving">
|
||||||
|
<i class="el-icon-check"></i> 保存此项目分数
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="teams-table-container">
|
||||||
|
<el-table
|
||||||
|
:data="groupOptions"
|
||||||
|
border
|
||||||
|
style="width: 100%"
|
||||||
|
v-loading="loading"
|
||||||
|
:header-cell-style="{background:'#f5f7fa', color: '#606266'}"
|
||||||
|
class="custom-table">
|
||||||
|
<el-table-column label="队伍名称" width="150">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div class="team-name">
|
||||||
|
<i class="el-icon-user-solid team-icon"></i>
|
||||||
|
{{ scope.row.groupName }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="名次设置" width="220">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-select
|
||||||
|
v-model="getScoreRecord(item.id, scope.row.id).rankingObj"
|
||||||
|
placeholder="请选择名次"
|
||||||
|
@change="updateScore(item.id, scope.row.id)"
|
||||||
|
class="rank-select">
|
||||||
|
<el-option
|
||||||
|
v-for="(rank, index) in rankScoreOptions"
|
||||||
|
:key="rank.id"
|
||||||
|
:label="rank.ranking"
|
||||||
|
:value="index + 1">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="得分">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div class="score-value"
|
||||||
|
:class="{'has-score': getScoreRecord(item.id, scope.row.id).score}">
|
||||||
|
{{ getScoreRecord(item.id, scope.row.id).score || '-' }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" width="250">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input
|
||||||
|
v-model="getScoreRecord(item.id, scope.row.id).remark"
|
||||||
|
placeholder="请输入备注"
|
||||||
|
type="textarea"
|
||||||
|
class="remark-input"
|
||||||
|
:rows="2">
|
||||||
|
</el-input>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const vue = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
year: new Date().getFullYear() + ""
|
||||||
|
},
|
||||||
|
activityOptions: [],
|
||||||
|
groupOptions: [],
|
||||||
|
itemOptions: [],
|
||||||
|
itemScoreList: [],
|
||||||
|
rankScoreOptions: [],
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取活动
|
||||||
|
listAct() {
|
||||||
|
$.get("/platform/activity/scoreEntry/list-activity", this.pageForm).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.activityOptions = res.data
|
||||||
|
if (this.activityOptions.length > 0) {
|
||||||
|
this.pageForm.activityId = this.activityOptions[0].id
|
||||||
|
this.activityChange()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取队伍
|
||||||
|
async listGroup() {
|
||||||
|
const {
|
||||||
|
code,
|
||||||
|
data,
|
||||||
|
msg
|
||||||
|
} = await $.get("/platform/activity/scoreEntry/list-group/" + this.pageForm.activityId)
|
||||||
|
if (code === 0) {
|
||||||
|
this.groupOptions = data
|
||||||
|
} else {
|
||||||
|
this.$message.error(msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 获取项目
|
||||||
|
async listItem() {
|
||||||
|
const {
|
||||||
|
code,
|
||||||
|
data,
|
||||||
|
msg
|
||||||
|
} = await $.get("/platform/activity/scoreEntry/list-item/" + this.pageForm.activityId)
|
||||||
|
if (code === 0) {
|
||||||
|
// 添加保存状态标志
|
||||||
|
this.itemOptions = data.map(item => ({
|
||||||
|
...item,
|
||||||
|
saving: false
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
this.$message.error(msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 获取名次积分对应
|
||||||
|
async listRankScore() {
|
||||||
|
const {
|
||||||
|
code,
|
||||||
|
data,
|
||||||
|
msg
|
||||||
|
} = await $.get("/platform/activity/scoreEntry/list-rank-score")
|
||||||
|
if (code === 0) {
|
||||||
|
this.rankScoreOptions = data
|
||||||
|
} else {
|
||||||
|
this.$message.error(msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取项目得分列表
|
||||||
|
async listItemScore() {
|
||||||
|
const {
|
||||||
|
code,
|
||||||
|
data,
|
||||||
|
msg
|
||||||
|
} = await $.get("/platform/activity/scoreEntry/list-item-score/" + this.pageForm.activityId)
|
||||||
|
if (code === 0) {
|
||||||
|
this.itemScoreList = data
|
||||||
|
|
||||||
|
// 为每条记录添加rankingObj属性,用于下拉框绑定
|
||||||
|
this.itemScoreList.forEach(score => {
|
||||||
|
score.rankingObj = score.ranking || null
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$message.error(msg)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取特定项目和队伍的得分记录
|
||||||
|
getScoreRecord(itemId, groupId) {
|
||||||
|
// 在已有的记录中查找
|
||||||
|
let record = this.itemScoreList.find(score =>
|
||||||
|
score.itemId === itemId && score.groupId === groupId
|
||||||
|
)
|
||||||
|
|
||||||
|
// 如果没有找到,创建一个新记录
|
||||||
|
if (!record) {
|
||||||
|
record = {
|
||||||
|
activityId: this.pageForm.activityId,
|
||||||
|
itemId: itemId,
|
||||||
|
groupId: groupId,
|
||||||
|
score: null,
|
||||||
|
ranking: null,
|
||||||
|
rankingObj: null,
|
||||||
|
remark: ""
|
||||||
|
}
|
||||||
|
this.itemScoreList.push(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保remark字段存在
|
||||||
|
if (!record.hasOwnProperty("remark")) {
|
||||||
|
record.remark = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保rankingObj字段存在
|
||||||
|
if (!record.hasOwnProperty("rankingObj")) {
|
||||||
|
record.rankingObj = record.ranking
|
||||||
|
}
|
||||||
|
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更新分数
|
||||||
|
updateScore(itemId, groupId) {
|
||||||
|
const record = this.getScoreRecord(itemId, groupId)
|
||||||
|
const rankingValue = record.rankingObj
|
||||||
|
|
||||||
|
// 同步ranking字段和rankingObj字段
|
||||||
|
record.ranking = rankingValue
|
||||||
|
|
||||||
|
if (rankingValue) {
|
||||||
|
// 查找对应名次的分数
|
||||||
|
const rankScore = this.rankScoreOptions[rankingValue - 1]
|
||||||
|
if (rankScore) {
|
||||||
|
record.score = rankScore.score
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
record.score = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 保存单个项目的分数
|
||||||
|
async saveItemScores(itemId) {
|
||||||
|
if (!this.pageForm.activityId) {
|
||||||
|
this.$message.warning("请先选择活动")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到当前项目
|
||||||
|
const currentItem = this.itemOptions.find(item => item.id === itemId)
|
||||||
|
if (!currentItem) return
|
||||||
|
|
||||||
|
// 设置保存状态
|
||||||
|
currentItem.saving = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 过滤出当前项目的有效分数记录
|
||||||
|
const validScores = this.itemScoreList.filter(score =>
|
||||||
|
score.itemId === itemId && score.ranking !== null
|
||||||
|
)
|
||||||
|
|
||||||
|
// 转换为后端需要的数据格式
|
||||||
|
const postData = validScores.map(score => ({
|
||||||
|
id: score.id,
|
||||||
|
activityId: score.activityId,
|
||||||
|
itemId: score.itemId,
|
||||||
|
groupId: score.groupId,
|
||||||
|
score: score.score,
|
||||||
|
ranking: score.ranking
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { code, msg } = await $.post("/platform/activity/scoreEntry/save-score", {
|
||||||
|
scores: JSON.stringify(postData)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (code === 0) {
|
||||||
|
this.$message.success(currentItem.name+'项目分数保存成功')
|
||||||
|
await this.listItemScore()
|
||||||
|
} else {
|
||||||
|
this.$message.error(msg || "保存失败")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
this.$message.error("保存失败:" + (error.message || "未知错误"))
|
||||||
|
} finally {
|
||||||
|
currentItem.saving = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 活动改变
|
||||||
|
async activityChange() {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
await this.listGroup()
|
||||||
|
await this.listItem()
|
||||||
|
await this.listItemScore()
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
doSearch() {
|
||||||
|
if (this.pageForm.activityId) {
|
||||||
|
this.activityChange()
|
||||||
|
} else {
|
||||||
|
this.$message.warning("请先选择活动")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.listAct()
|
||||||
|
this.listRankScore()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.filter-card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-entry-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.05);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-entry-header {
|
||||||
|
background-color: #3E54AC;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs {
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__header {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
padding: 0 15px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__item.is-active {
|
||||||
|
color: #3E54AC;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__nav-wrap::after {
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tabs .el-tabs__active-bar {
|
||||||
|
background-color: #3E54AC;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-info {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-details {
|
||||||
|
line-height: 1.6;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-actions {
|
||||||
|
margin-left: 15px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-icon {
|
||||||
|
color: #3E54AC;
|
||||||
|
margin-right: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2B3A55;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-content {
|
||||||
|
color: #64748b;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teams-table-container {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-table {
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #2B3A55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-icon {
|
||||||
|
color: #7286D3;
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-select .el-input__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-value {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-value.has-score {
|
||||||
|
color: #36AE7C;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remark-input .el-textarea__inner {
|
||||||
|
border-radius: 4px;
|
||||||
|
resize: none;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remark-input .el-textarea__inner:focus {
|
||||||
|
border-color: #7286D3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 80px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
font-size: 60px;
|
||||||
|
color: #cbd5e1;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs__content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
@@ -97,20 +97,20 @@ layout("/layouts/platform_1.html"){
|
|||||||
{{row.isStay?'住宿':'不住宿'}}
|
{{row.isStay?'住宿':'不住宿'}}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="物品发放" prop="isGrant">
|
<!-- <el-table-column label="物品发放" prop="isGrant">-->
|
||||||
<template slot-scope="scope">
|
<!-- <template slot-scope="scope">-->
|
||||||
<el-tag v-if="scope.row.isGrant" type="success">已发放</el-tag>
|
<!-- <el-tag v-if="scope.row.isGrant" type="success">已发放</el-tag>-->
|
||||||
<el-tag v-else type="danger">未发放</el-tag>
|
<!-- <el-tag v-else type="danger">未发放</el-tag>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
</el-table-column>
|
<!-- </el-table-column>-->
|
||||||
<el-table-column label="操作" fixed="right" width="200">
|
<!-- <el-table-column label="操作" fixed="right" width="200">-->
|
||||||
<template #default="{row}">
|
<!-- <template #default="{row}">-->
|
||||||
<el-button v-if="!row.isGrant || row.isGrant === 0" type="primary" size="mini"
|
<!-- <el-button v-if="!row.isGrant || row.isGrant === 0" type="primary" size="mini"-->
|
||||||
@click="doGrant(row, true)">设为已发放物品
|
<!-- @click="doGrant(row, true)">设为已发放物品-->
|
||||||
</el-button>
|
<!-- </el-button>-->
|
||||||
<el-button v-else type="danger" size="mini" @click="doGrant(row, false)">设为未发放物品</el-button>
|
<!-- <el-button v-else type="danger" size="mini" @click="doGrant(row, false)">设为未发放物品</el-button>-->
|
||||||
</template>
|
<!-- </template>-->
|
||||||
</el-table-column>
|
<!-- </el-table-column>-->
|
||||||
</el-table>
|
</el-table>
|
||||||
<!--#include("/layouts/pagination.html"){}#-->
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ layout("/layouts/platform_1.html"){
|
|||||||
</el-row>
|
</el-row>
|
||||||
<el-table v-loading="tableLoading" show-overflow-tooltip :data="tableData">
|
<el-table v-loading="tableLoading" show-overflow-tooltip :data="tableData">
|
||||||
<el-table-column label="序号" type="index" header-align="center" align="center"
|
<el-table-column label="序号" type="index" header-align="center" align="center"
|
||||||
|
:index="indexMethod"
|
||||||
width="50"></el-table-column>
|
width="50"></el-table-column>
|
||||||
<el-table-column label="姓名" prop="userName"></el-table-column>
|
<el-table-column label="姓名" prop="userName"></el-table-column>
|
||||||
<el-table-column label="性别" prop="sex"></el-table-column>
|
<el-table-column label="性别" prop="sex"></el-table-column>
|
||||||
@@ -93,6 +94,7 @@ layout("/layouts/platform_1.html"){
|
|||||||
<el-table-column label="操作" fixed="right" width="300">
|
<el-table-column label="操作" fixed="right" width="300">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" size="mini" @click="proxySignIn(scope.row.id)" v-if="!scope.row.isSignIn">签到</el-button>
|
<el-button type="primary" size="mini" @click="proxySignIn(scope.row.id)" v-if="!scope.row.isSignIn">签到</el-button>
|
||||||
|
<el-button type="primary" size="mini" @click="cancelSignIn(scope.row.id)" v-if="scope.row.isSignIn">取消签到</el-button>
|
||||||
<el-button type="primary" size="mini" @click="openModify(scope.row)">修改</el-button>
|
<el-button type="primary" size="mini" @click="openModify(scope.row)">修改</el-button>
|
||||||
<el-button type="danger" size="mini" @click="doRemove(scope.row.id)">删除</el-button>
|
<el-button type="danger" size="mini" @click="doRemove(scope.row.id)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -466,7 +468,22 @@ layout("/layouts/platform_1.html"){
|
|||||||
this.doSearch()
|
this.doSearch()
|
||||||
this.$message.success(resp.msg)
|
this.$message.success(resp.msg)
|
||||||
} else {
|
} else {
|
||||||
this.$message.warning('操作失败')
|
this.$message.warning(resp.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
cancelSignIn(id){
|
||||||
|
this.$confirm('您确定要取消签到吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(async () => {
|
||||||
|
const resp = await $.post('/platform/activity/user/cancelSignIn', {id})
|
||||||
|
if (resp.code === 0) {
|
||||||
|
this.$message.success(resp.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}else{
|
||||||
|
this.$message.warning(resp.msg)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ layout("/layouts/platform_1.html"){
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card shadow="never" class="mt-3">
|
<el-card shadow="never" class="mt-3">
|
||||||
<el-table :key="tableKey" :data="tableData" style="width: 100%" size="small"
|
<el-table :key="tableKey" :data="tableData" style="width: 100%"
|
||||||
:highlight-current-row="true" row-key="id" lazy
|
:highlight-current-row="true" row-key="id" lazy
|
||||||
:load="loadChild">
|
:load="loadChild">
|
||||||
<el-table-column label="菜单名称" header-align="center" prop="name"
|
<el-table-column label="菜单名称" header-align="center" prop="name"
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
package com.budwk.app;
|
package com.budwk.app;
|
||||||
|
|
||||||
|
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||||
|
import cn.afterturn.easypoi.excel.ExcelImportUtil;
|
||||||
|
import cn.afterturn.easypoi.excel.annotation.Excel;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.ImportParams;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.utils.PwdUtil;
|
import com.budwk.app.base.utils.PwdUtil;
|
||||||
import com.budwk.app.sys.models.Sys_dict;
|
import com.budwk.app.sys.models.Sys_dict;
|
||||||
import com.budwk.app.sys.services.SysDictService;
|
import com.budwk.app.sys.services.SysDictService;
|
||||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.nutz.boot.test.junit4.NbJUnit4Runner;
|
import org.nutz.boot.test.junit4.NbJUnit4Runner;
|
||||||
@@ -11,8 +20,14 @@ import org.nutz.dao.Dao;
|
|||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.lang.random.R;
|
import org.nutz.lang.random.R;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@IocBean
|
@IocBean
|
||||||
@RunWith(NbJUnit4Runner.class)
|
@RunWith(NbJUnit4Runner.class)
|
||||||
@@ -24,7 +39,7 @@ public class Test1 {
|
|||||||
private SysDictService sysDictService;
|
private SysDictService sysDictService;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void to01(){
|
public void to01() {
|
||||||
String str = """
|
String str = """
|
||||||
'旅行', '摄影', '音乐', '电影', '美食', '健身', '阅读', '跑步','游泳', '爬山', '滑雪', '烹饪', '绘画', '书法', '手工', '舞蹈','瑜伽', '钢琴', '吉他', '写作', '篮球', '足球', '网球', '羽毛球','动漫', '游戏', '宠物', '园艺', '咖啡', '茶艺', '插花', '收藏','志愿服务', '数码', '科技', '投资', '理财', '历史', '哲学', '心理学'
|
'旅行', '摄影', '音乐', '电影', '美食', '健身', '阅读', '跑步','游泳', '爬山', '滑雪', '烹饪', '绘画', '书法', '手工', '舞蹈','瑜伽', '钢琴', '吉他', '写作', '篮球', '足球', '网球', '羽毛球','动漫', '游戏', '宠物', '园艺', '咖啡', '茶艺', '插花', '收藏','志愿服务', '数码', '科技', '投资', '理财', '历史', '哲学', '心理学'
|
||||||
""";
|
""";
|
||||||
@@ -42,11 +57,56 @@ public class Test1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void t002(){
|
public void t002() {
|
||||||
String salt = R.UU32();
|
List<ExcelUser> list = ExcelImportUtil.importExcel(new File("C:\\Users\\jug\\Desktop\\工作簿3.xlsx"), ExcelUser.class, new ImportParams());
|
||||||
System.out.println(salt);
|
|
||||||
String password = PwdUtil.getPassword("dd3s@#2025", salt);
|
List<ExcelUser> list2 = ExcelImportUtil.importExcel(new File("D:\\downloads\\会员名单 (3).xls"), ExcelUser.class, new ImportParams());
|
||||||
System.out.println(password);
|
|
||||||
|
|
||||||
|
List<NutMap> changeUsers = new ArrayList<>();
|
||||||
|
|
||||||
|
// 找出list中的人员在list2中单位不一样的数据
|
||||||
|
list.forEach(e -> {
|
||||||
|
Optional<ExcelUser> first = list2.stream().filter(e2 -> e2.getGh().equals(e.getGh())).findFirst();
|
||||||
|
if (first.isPresent()) {
|
||||||
|
String dw = StrUtil.blankToDefault(first.get().getDw(), "");
|
||||||
|
if (!dw.equals(e.getDw())) {
|
||||||
|
// System.out.println("姓名:" + e.getName() + ",工号:" + e.getGh() + ",原单位:" + e.getDw() + ",现单位:" + dw);
|
||||||
|
changeUsers.add(NutMap.NEW()
|
||||||
|
.addv("name", e.getName())
|
||||||
|
.addv("gh", e.getGh())
|
||||||
|
.addv("ydw", e.getDw())
|
||||||
|
.addv("xdw", dw));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ArrayList<ExcelExportEntity> entities = new ArrayList<>();
|
||||||
|
entities.add(new ExcelExportEntity("姓名", "name"));
|
||||||
|
entities.add(new ExcelExportEntity("工号", "gh"));
|
||||||
|
entities.add(new ExcelExportEntity("原单位", "ydw"));
|
||||||
|
entities.add(new ExcelExportEntity("现单位", "xdw"));
|
||||||
|
|
||||||
|
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entities, changeUsers);
|
||||||
|
try {
|
||||||
|
FileOutputStream outputStream = new FileOutputStream("C:\\Users\\jug\\Desktop\\单位变动人员.xlsx");
|
||||||
|
workbook.write(outputStream);
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ExcelUser {
|
||||||
|
@Excel(name = "工号")
|
||||||
|
private String gh;
|
||||||
|
|
||||||
|
@Excel(name = "姓名")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Excel(name = "单位")
|
||||||
|
private String dw;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page-container">
|
<view class="page-container">
|
||||||
|
<!-- 人员选项卡区域 -->
|
||||||
|
<view class="tabs-container">
|
||||||
|
<view class="tabs-header">
|
||||||
|
<view class="tabs-title">
|
||||||
|
<text class="title-text">报名人员</text>
|
||||||
|
<view class="header-actions">
|
||||||
|
<view class="person-counter">
|
||||||
|
<text class="counter-text">{{ formData.userList.length }}人</text>
|
||||||
|
</view>
|
||||||
|
<view class="header-add-btn" @click="addNewUser">
|
||||||
|
<t-icon name="add" size="16px"></t-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-x="true" class="tabs-scroll-view" show-scrollbar="false">
|
||||||
|
<view class="tabs">
|
||||||
|
<view
|
||||||
|
v-for="(user, index) in formData.userList"
|
||||||
|
:key="index"
|
||||||
|
class="tab"
|
||||||
|
:class="{ active: activeTabIndex === index }"
|
||||||
|
@click="switchTab(index)"
|
||||||
|
>
|
||||||
|
<view class="tab-content">
|
||||||
|
<view class="tab-icon" v-if="activeTabIndex === index">
|
||||||
|
<t-icon name="user" size="16px"></t-icon>
|
||||||
|
</view>
|
||||||
|
<text class="tab-text">{{ user.userName || `人员${index + 1}` }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="tabs-indicator"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="form-area">
|
<view class="form-area">
|
||||||
<t-form
|
<t-form
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
@@ -9,6 +45,7 @@
|
|||||||
label-align="left"
|
label-align="left"
|
||||||
scroll-to-first-error="auto"
|
scroll-to-first-error="auto"
|
||||||
labelWidth="90px"
|
labelWidth="90px"
|
||||||
|
:requiredMark="true"
|
||||||
>
|
>
|
||||||
<!-- <view class="form-block">-->
|
<!-- <view class="form-block">-->
|
||||||
<!-- <view class="form-block-title">-->
|
<!-- <view class="form-block-title">-->
|
||||||
@@ -29,20 +66,19 @@
|
|||||||
<view class="form-block">
|
<view class="form-block">
|
||||||
<view class="form-block-title">
|
<view class="form-block-title">
|
||||||
<t-icon name="usergroup"></t-icon>
|
<t-icon name="usergroup"></t-icon>
|
||||||
报名人员信息
|
<text>报名人员信息</text>
|
||||||
</view>
|
<text class="form-subtitle">{{ activeTabIndex + 1 }}/{{ formData.userList.length }}</text>
|
||||||
<view v-for="(user,index) in formData.userList" :key="index" class="user-card">
|
<view class="user-actions">
|
||||||
<view class="user-card-header">
|
<view class="remove-user" @click="removeUser(activeTabIndex)" v-if="formData.userList.length > 1">
|
||||||
<view class="user-card-header-title">
|
|
||||||
<span>{{ index + 1 }}</span>
|
|
||||||
</view>
|
|
||||||
<view class="remove" @click="removeUser(index)">
|
|
||||||
<t-icon name="delete" size="18px"></t-icon>
|
<t-icon name="delete" size="18px"></t-icon>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 所有人员的表单,使用v-show控制显示 -->
|
||||||
|
<view v-for="(user, index) in formData.userList" :key="index" class="form-fields-container" v-show="activeTabIndex === index">
|
||||||
<t-form-item label="姓名" :name="`userList[${index}].userName`"
|
<t-form-item label="姓名" :name="`userList[${index}].userName`"
|
||||||
:rules="[{required:true,message: '请输入姓名'}]">
|
:rules="[{required:true,message: '请输入姓名'}]">
|
||||||
<t-input v-model="user.userName" borderless placeholder="请输入内容"></t-input>
|
<t-input v-model="user.userName" borderless placeholder="请输入内容"></t-input>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
<t-form-item label="性别" :name="`userList[${index}].sex`" :rules="[{required:true,message: '请选择性别'}]">
|
<t-form-item label="性别" :name="`userList[${index}].sex`" :rules="[{required:true,message: '请选择性别'}]">
|
||||||
@@ -51,47 +87,65 @@
|
|||||||
<t-radio :block="false" label="女" value="女"/>
|
<t-radio :block="false" label="女" value="女"/>
|
||||||
</t-radio-group>
|
</t-radio-group>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
|
<t-form-item label="单位名称">
|
||||||
|
<t-input v-model="user.unitName" borderless placeholder="请输入单位名称" readonly></t-input>
|
||||||
|
</t-form-item>
|
||||||
<t-form-item label="职务" :name="`userList[${index}].position`"
|
<t-form-item label="职务" :name="`userList[${index}].position`"
|
||||||
:rules="[{required:true,message: '请输入职务'}]">
|
:rules="[{required:true,message: '请输入职务'}]">
|
||||||
<t-input v-model="user.position" borderless placeholder="请输入职务"></t-input>
|
<t-input v-model="user.position" borderless placeholder="请输入职务"></t-input>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
<t-form-item label="身份证号" :name="`userList[${index}].idCard`"
|
<t-form-item label="身份证号" :name="`userList[${index}].idCard`"
|
||||||
:rules="[{required:true,message: '请输入身份证号码'},{idcard:true, message: '请输入正确的身份证号码'}]">
|
:rules="[{required:true,message: '请输入身份证号码'},{idcard:true, message: '请输入正确的身份证号码'}]">
|
||||||
<t-input v-model="user.idCard" borderless placeholder="请输入身份证号码"></t-input>
|
<t-input v-model="user.idCard" borderless placeholder="请输入身份证号码"></t-input>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
<t-form-item label="联系电话" :name="`userList[${index}].phone`"
|
<t-form-item label="联系电话" :name="`userList[${index}].phone`"
|
||||||
:rules="[{required:true,message: '请输入联系电话'},{telnumber:true, message: '请输入正确的联系电话'}]">
|
:rules="[{required:true,message: '请输入联系电话'},{telnumber:true, message: '请输入正确的联系电话'}]">
|
||||||
<t-input v-model="user.phone" borderless placeholder="请输入联系电话"></t-input>
|
<t-input v-model="user.phone" borderless placeholder="请输入联系电话"></t-input>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
<t-form-item label="是否住宿" :name="`userList[${index}].isStay`"
|
<t-form-item label="是否住宿" :name="`userList[${index}].isStay`"
|
||||||
:rules="[{required:true,message: '请选择是否住宿'}]">
|
:rules="[{required:true,message: '请选择是否住宿'}]">
|
||||||
<t-radio-group v-model="user.isStay" class="radio-box">
|
<t-radio-group v-model="user.isStay" class="radio-box">
|
||||||
<t-radio :block="false" name="radio" :value="true" label="是"/>
|
<t-radio :block="false" name="radio" :value="true" label="是"/>
|
||||||
<t-radio :block="false" name="radio" :value="false" label="否"/>
|
<t-radio :block="false" name="radio" :value="false" label="否"/>
|
||||||
</t-radio-group>
|
</t-radio-group>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
<t-form-item label="是否联系人" :name="`userList[${index}].isContacts`"
|
<t-form-item label="是否联系人" :name="`userList[${index}].isContacts`"
|
||||||
:rules="[{required:true,message: '请选择是否为联系人'}]">
|
:rules="[{required:true,message: '请选择是否为联系人'}]">
|
||||||
<t-radio-group v-model="user.isContacts" class="radio-box">
|
<t-radio-group v-model="user.isContacts" class="radio-box">
|
||||||
<t-radio :block="false" name="radio" :value="true" label="是"/>
|
<t-radio :block="false" name="radio" :value="true" label="是"/>
|
||||||
<t-radio :block="false" name="radio" :value="false" label="否"/>
|
<t-radio :block="false" name="radio" :value="false" label="否"/>
|
||||||
</t-radio-group>
|
</t-radio-group>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
|
<t-form-item label="展示才艺" :name="`userList[${index}].isShowSkill`" :rules="[{required:true,message: '请选择是否展示才艺'}]">
|
||||||
|
<t-radio-group v-model="user.isShowSkill" class="radio-box">
|
||||||
|
<t-radio :block="false" name="radio" :value="true" label="是"/>
|
||||||
|
<t-radio :block="false" name="radio" :value="false" label="否"/>
|
||||||
|
</t-radio-group>
|
||||||
|
</t-form-item>
|
||||||
|
<template v-if="`userList[${index}].isShowSkill`">
|
||||||
|
<t-form-item label="才艺名称" :name="`userList[${index}].skillName`" :rules="[{required:user.isShowSkill===true,message: '请填写才艺名称'}]">
|
||||||
|
<t-input v-model="user.skillName" borderless placeholder="请输入才艺名称"></t-input>
|
||||||
|
</t-form-item>
|
||||||
|
<t-form-item label="所需器材" :name="`userList[${index}].equip`" :rules="[{required:user.isShowSkill===true,message: '请填写才艺所需器材'}]">
|
||||||
|
<t-input v-model="user.equip" borderless placeholder="请填写才艺所需器材"></t-input>
|
||||||
|
</t-form-item>
|
||||||
|
</template>
|
||||||
|
<t-form-item label="参加嘉年华" :name="`userList[${index}].isParty`" :rules="[{required:true,message: '请选择是否参加嘉年华'}]">
|
||||||
|
<t-radio-group v-model="user.isParty" class="radio-box">
|
||||||
|
<t-radio :block="false" name="radio" :value="true" label="是"/>
|
||||||
|
<t-radio :block="false" name="radio" :value="false" label="否"/>
|
||||||
|
</t-radio-group>
|
||||||
|
</t-form-item>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</t-form>
|
</t-form>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 悬浮添加按钮 -->
|
|
||||||
<view class="float-add-btn" @click="formData.userList.push({})">
|
|
||||||
<t-icon name="plus" size="24px" color="#fff"></t-icon>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="footer">
|
<view class="footer">
|
||||||
<view class="agreement-checkbox">
|
<view class="agreement-checkbox">
|
||||||
<t-checkbox label="多选" icon="rectangle" v-model:checked="agreementChecked" default-checked>
|
<t-checkbox label="多选" icon="rectangle" v-model:checked="agreementChecked" default-checked>
|
||||||
<label>我已阅读并同意
|
<label>我已阅读并同意
|
||||||
<text class="agreement-link">《参赛承诺书》</text>
|
<text class="agreement-link" @click="showAgreementPopup">《参赛承诺书》</text>
|
||||||
</label>
|
</label>
|
||||||
</t-checkbox>
|
</t-checkbox>
|
||||||
</view>
|
</view>
|
||||||
@@ -112,12 +166,32 @@
|
|||||||
:steps="guideSteps"
|
:steps="guideSteps"
|
||||||
>
|
>
|
||||||
</t-guide>
|
</t-guide>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 协议确认弹窗 -->
|
||||||
|
<t-popup v-model:visible="agreementPopupVisible" placement="center" :close-on-overlay-click="false">
|
||||||
|
<view class="agreement-popup">
|
||||||
|
<view class="agreement-popup-header">
|
||||||
|
<text class="agreement-popup-title">参赛条款与免责声明</text>
|
||||||
|
</view>
|
||||||
|
<view class="agreement-popup-content">
|
||||||
|
<view class="agreement-popup-text">
|
||||||
|
<!-- 阅读并同意本承诺书内容,点击"确定并报名"即表示您已充分理解并接受所有条款,承担相应法律责任。-->
|
||||||
|
<rich-text :nodes="agreementContent"></rich-text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="agreement-popup-footer">
|
||||||
|
<t-button variant="outline" block @click="closeAgreementPopup" class="agreement-btn">取消</t-button>
|
||||||
|
<t-button theme="primary" block :disabled="!canConfirmAgreement" @click="confirmAgreement" class="agreement-btn">
|
||||||
|
{{ canConfirmAgreement ? '确定并报名' : `请阅读(${agreementCountdown}秒)` }}
|
||||||
|
</t-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</t-popup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref} from 'vue'
|
import {ref, computed} from 'vue'
|
||||||
import {useRequest} from '@/utils/request';
|
import {useRequest} from '@/utils/request';
|
||||||
import {Dialog, Toast} from "tdesign-mobile-vue";
|
import {Dialog, Toast} from "tdesign-mobile-vue";
|
||||||
import {onLoad} from "@dcloudio/uni-app";
|
import {onLoad} from "@dcloudio/uni-app";
|
||||||
@@ -126,19 +200,84 @@ import {useUserStore} from "@/store";
|
|||||||
const request = useRequest()
|
const request = useRequest()
|
||||||
const userStore= useUserStore()
|
const userStore= useUserStore()
|
||||||
|
|
||||||
|
// 当前选中的选项卡索引
|
||||||
|
const activeTabIndex = ref(0)
|
||||||
|
|
||||||
|
// 切换选项卡
|
||||||
|
function switchTab(index) {
|
||||||
|
activeTabIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新用户
|
||||||
|
function addNewUser() {
|
||||||
|
formData.value.userList.push({
|
||||||
|
userName: '',
|
||||||
|
sex: null,
|
||||||
|
unitName: userStore?.userInfo?.unit?.name,
|
||||||
|
position: null,
|
||||||
|
idCard: null,
|
||||||
|
phone: null,
|
||||||
|
isStay: null,
|
||||||
|
isContacts: false,
|
||||||
|
isShowSkill: false,
|
||||||
|
skillName: null,
|
||||||
|
equip: null,
|
||||||
|
isParty: false
|
||||||
|
})
|
||||||
|
// 切换到新添加的用户选项卡
|
||||||
|
setTimeout(() => {
|
||||||
|
activeTabIndex.value = formData.value.userList.length - 1
|
||||||
|
// 滚动到最右边
|
||||||
|
scrollToRight()
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动到指定选项卡
|
||||||
|
function scrollToTab(index) {
|
||||||
|
const query = uni.createSelectorQuery()
|
||||||
|
query.selectAll('.tab').boundingClientRect()
|
||||||
|
query.select('.tabs-scroll-view').boundingClientRect()
|
||||||
|
query.exec((res) => {
|
||||||
|
if (res && res[0] && res[0][index] && res[1]) {
|
||||||
|
const tabElement = res[0][index]
|
||||||
|
const scrollView = res[1]
|
||||||
|
const scrollLeft = tabElement.left - scrollView.left - (scrollView.width / 2) + (tabElement.width / 2)
|
||||||
|
uni.pageScrollTo({
|
||||||
|
scrollLeft: scrollLeft > 0 ? scrollLeft : 0,
|
||||||
|
duration: 300
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动到最右边
|
||||||
|
function scrollToRight() {
|
||||||
|
const query = uni.createSelectorQuery()
|
||||||
|
query.select('.tabs-scroll-view').boundingClientRect()
|
||||||
|
query.exec((res) => {
|
||||||
|
if (res && res[0]) {
|
||||||
|
const scrollView = res[0]
|
||||||
|
const scrollWidth = scrollView.scrollWidth
|
||||||
|
const clientWidth = scrollView.width
|
||||||
|
const scrollLeft = scrollWidth - clientWidth
|
||||||
|
if (scrollLeft > 0) {
|
||||||
|
uni.pageScrollTo({
|
||||||
|
scrollLeft: scrollLeft,
|
||||||
|
duration: 300
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 引导部分
|
// 引导部分
|
||||||
const guideCurrent = ref(-1)
|
const guideCurrent = ref(-1)
|
||||||
const guideSteps = [
|
const guideSteps = [
|
||||||
{
|
{
|
||||||
element:()=> document.querySelector('.float-add-btn'),
|
element:()=> document.querySelector('.header-add-btn'),
|
||||||
title: '添加活动报名人员',
|
title: '添加活动报名人员',
|
||||||
placement: 'top'
|
placement: 'top'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
element:()=> document.querySelector('.t-form'),
|
|
||||||
title: '填写报名信息',
|
|
||||||
placement: 'top'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
element:()=> document.querySelector('.footer'),
|
element:()=> document.querySelector('.footer'),
|
||||||
title: '提交报名信息',
|
title: '提交报名信息',
|
||||||
@@ -152,25 +291,52 @@ const isSignUp = ref(null)
|
|||||||
const agreementChecked = ref(false)
|
const agreementChecked = ref(false)
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
userList: [{}]
|
userList: []
|
||||||
})
|
})
|
||||||
|
// 协议弹窗相关
|
||||||
|
const agreementPopupVisible = ref(false)
|
||||||
|
const agreementCountdown = ref(5)
|
||||||
|
const countdownTimer = ref(null)
|
||||||
|
const canConfirmAgreement = ref(false)
|
||||||
|
const agreementContent = ref(null)
|
||||||
|
|
||||||
onLoad((option) => {
|
onLoad(async (option) => {
|
||||||
if (option.id) {
|
if (option.id) {
|
||||||
actId.value = option.id
|
actId.value = option.id
|
||||||
formData.value.activityId = option.id
|
formData.value.activityId = option.id
|
||||||
listSignUpUser()
|
await listSignUpUser()
|
||||||
getIsSignUp()
|
await getIsSignUp()
|
||||||
|
await getAgreement()
|
||||||
// 没报名进行引导
|
// 没报名进行引导
|
||||||
if(formData.value.userList.length === 0){
|
if(!formData.value.userList || formData.value.userList.length === 0){
|
||||||
guideCurrent.value = 0
|
guideCurrent.value = 0
|
||||||
//formData.value.unitName = userStore.userInfo?.unit.name
|
// 默认是本人的信息
|
||||||
|
formData.value.userList.push({
|
||||||
|
userName: userStore.userInfo.userName,
|
||||||
|
sex: userStore.userInfo.sex,
|
||||||
|
unitName: userStore?.userInfo?.unit?.name,
|
||||||
|
position: null,
|
||||||
|
idCard: userStore.userInfo.idCard,
|
||||||
|
phone: userStore.userInfo.phone,
|
||||||
|
isStay: null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast({message: 'ID不存在', theme: 'error'});
|
Toast({message: 'ID不存在', theme: 'error'});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 查询参赛承诺书
|
||||||
|
async function getAgreement() {
|
||||||
|
try {
|
||||||
|
const {code, data} = await request.get('/client/activity/agreement/' + actId.value)
|
||||||
|
if (code === 0 && data) {
|
||||||
|
agreementContent.value = data
|
||||||
|
}
|
||||||
|
}catch (e){
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 查询报名人员信息
|
// 查询报名人员信息
|
||||||
async function listSignUpUser() {
|
async function listSignUpUser() {
|
||||||
@@ -216,28 +382,86 @@ async function validaForm() {
|
|||||||
// 承诺书
|
// 承诺书
|
||||||
async function validateAgreement() {
|
async function validateAgreement() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (agreementChecked.value) {
|
// Always show the popup regardless of checkbox state
|
||||||
resolve(true)
|
// if (agreementChecked.value) {
|
||||||
return
|
// resolve(true)
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
Dialog.confirm({
|
// 重置倒计时
|
||||||
title: '提示',
|
agreementCountdown.value = 5
|
||||||
content: '参赛条款与免责声明:阅读并同意本承诺书内容,点击"确定并报名"即表示您已充分理解并接受所有条款,承担相应法律责任。',
|
canConfirmAgreement.value = false
|
||||||
confirmBtn: '确定并报名',
|
|
||||||
cancelBtn: '取消',
|
// 显示弹窗
|
||||||
onConfirm: () => {
|
agreementPopupVisible.value = true
|
||||||
agreementChecked.value = true
|
|
||||||
resolve(true)
|
// 启动倒计时
|
||||||
},
|
startAgreementCountdown(resolve)
|
||||||
onCancel: () => {
|
|
||||||
agreementChecked.value = false
|
|
||||||
resolve(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 启动协议倒计时
|
||||||
|
function startAgreementCountdown(resolvePromise) {
|
||||||
|
// 清除可能存在的旧计时器
|
||||||
|
if (countdownTimer.value) {
|
||||||
|
clearInterval(countdownTimer.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置新的计时器
|
||||||
|
countdownTimer.value = setInterval(() => {
|
||||||
|
agreementCountdown.value--
|
||||||
|
|
||||||
|
if (agreementCountdown.value <= 0) {
|
||||||
|
// 倒计时结束,允许确认
|
||||||
|
clearInterval(countdownTimer.value)
|
||||||
|
canConfirmAgreement.value = true
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
// 保存 Promise 的 resolve 函数,以便在确认或取消时使用
|
||||||
|
window._resolveAgreementPromise = resolvePromise
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认协议
|
||||||
|
function confirmAgreement() {
|
||||||
|
// 只有在倒计时结束后才能确认
|
||||||
|
if (!canConfirmAgreement.value) return
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
agreementPopupVisible.value = false
|
||||||
|
|
||||||
|
// 清除计时器
|
||||||
|
if (countdownTimer.value) {
|
||||||
|
clearInterval(countdownTimer.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记已同意协议
|
||||||
|
agreementChecked.value = true
|
||||||
|
|
||||||
|
// 解析 Promise
|
||||||
|
if (window._resolveAgreementPromise) {
|
||||||
|
window._resolveAgreementPromise(true)
|
||||||
|
window._resolveAgreementPromise = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭协议弹窗
|
||||||
|
function closeAgreementPopup() {
|
||||||
|
// 关闭弹窗
|
||||||
|
agreementPopupVisible.value = false
|
||||||
|
|
||||||
|
// 清除计时器
|
||||||
|
if (countdownTimer.value) {
|
||||||
|
clearInterval(countdownTimer.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析 Promise 为 false(未同意)
|
||||||
|
if (window._resolveAgreementPromise) {
|
||||||
|
window._resolveAgreementPromise(false)
|
||||||
|
window._resolveAgreementPromise = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 提交表单
|
// 提交表单
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
const formRes = await validaForm()
|
const formRes = await validaForm()
|
||||||
@@ -287,12 +511,177 @@ async function removeUser(index) {
|
|||||||
Toast('至少需要一个报名人员')
|
Toast('至少需要一个报名人员')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
formData.value.userList.splice(index, 1)
|
|
||||||
|
Dialog.confirm({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定要删除该报名人员吗?',
|
||||||
|
confirmBtn: '确定',
|
||||||
|
cancelBtn: '取消',
|
||||||
|
onConfirm: () => {
|
||||||
|
formData.value.userList.splice(index, 1)
|
||||||
|
// 如果删除的是当前选中的选项卡,则选中第一个选项卡
|
||||||
|
if (index === activeTabIndex.value) {
|
||||||
|
activeTabIndex.value = 0
|
||||||
|
}
|
||||||
|
// 如果删除的是前面的选项卡,则当前选中的选项卡索引减1
|
||||||
|
else if (index < activeTabIndex.value) {
|
||||||
|
activeTabIndex.value--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示协议弹窗
|
||||||
|
function showAgreementPopup() {
|
||||||
|
// 重置倒计时
|
||||||
|
agreementCountdown.value = 5
|
||||||
|
canConfirmAgreement.value = false
|
||||||
|
|
||||||
|
// 显示弹窗
|
||||||
|
agreementPopupVisible.value = true
|
||||||
|
|
||||||
|
// 启动倒计时
|
||||||
|
startAgreementCountdown(() => {
|
||||||
|
// 这里不需要处理,因为协议弹窗会自动显示
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
.tabs-container {
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-header {
|
||||||
|
padding: 10px 16px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-counter {
|
||||||
|
background-color: #f45a5a;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2px 10px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counter-text {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-add-btn {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, #f45a5a, #ff7676);
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 2px 6px rgba(244, 90, 90, 0.25);
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-add-btn:active {
|
||||||
|
transform: scale(0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-scroll-view {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-scroll-view::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 90px;
|
||||||
|
height: 35px;
|
||||||
|
padding: 0 14px;
|
||||||
|
margin: 0 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border-radius: 19px;
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-text {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab.active {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #f45a5a;
|
||||||
|
box-shadow: 0 3px 8px rgba(244, 90, 90, 0.25);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-indicator {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -1px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(244, 90, 90, 0.3), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
.act-info {
|
.act-info {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 44px;
|
top: 44px;
|
||||||
@@ -340,6 +729,7 @@ async function removeUser(index) {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
margin-bottom: 130px;
|
margin-bottom: 130px;
|
||||||
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-block {
|
.form-block {
|
||||||
@@ -347,6 +737,7 @@ async function removeUser(index) {
|
|||||||
background: white;
|
background: white;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
.form-block-title {
|
.form-block-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@@ -355,83 +746,45 @@ async function removeUser(index) {
|
|||||||
color: #333;
|
color: #333;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
.t-icon {
|
.t-icon {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
color: var(--td-brand-color);
|
color: var(--td-brand-color);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-card {
|
.form-subtitle {
|
||||||
background: white;
|
font-size: 12px;
|
||||||
margin-bottom: 20px;
|
color: #999;
|
||||||
position: relative;
|
margin-left: 8px;
|
||||||
border-left: 3px solid #e74c3c;
|
font-weight: normal;
|
||||||
padding-left: 12px;
|
|
||||||
|
|
||||||
.user-card-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
|
|
||||||
.user-card-header-title {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
font-size: 15px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
background-color: #e74c3c;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
font-size: 14px;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.remove {
|
|
||||||
color: #e74c3c;
|
|
||||||
//font-size: 14px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-add-btn {
|
.form-fields-container {
|
||||||
position: fixed;
|
animation: fadeIn 0.3s ease;
|
||||||
right: 32rpx;
|
}
|
||||||
bottom: 160rpx;
|
|
||||||
width: 110rpx;
|
@keyframes fadeIn {
|
||||||
height: 110rpx;
|
from { opacity: 0.6; }
|
||||||
border-radius: 50%;
|
to { opacity: 1; }
|
||||||
background-color: #e74c3c;
|
}
|
||||||
|
|
||||||
|
.user-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
margin-left: auto;
|
||||||
z-index: 100;
|
|
||||||
transition: transform 0.2s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-add-btn:active {
|
.remove-user {
|
||||||
transform: scale(0.95);
|
padding: 5px;
|
||||||
|
color: #f45a5a;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.radio-box {
|
.radio-box {
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
column-gap: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
@@ -439,12 +792,95 @@ async function removeUser(index) {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: 0 16px 16px;
|
padding: 16px;
|
||||||
background-color: white;
|
background: white;
|
||||||
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||||
z-index: 10;
|
z-index: 99;
|
||||||
max-width: 750px;
|
}
|
||||||
margin: 0 auto;
|
|
||||||
width: 100%;
|
.agreement-checkbox {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-link {
|
||||||
|
color: var(--td-brand-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-nav {
|
||||||
|
position: fixed;
|
||||||
|
right: 16px;
|
||||||
|
bottom: 140px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
z-index: 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-nav-btn {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: rgba(244, 90, 90, 0.9);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
transition: transform 0.2s ease, background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-nav-btn:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
background-color: rgba(244, 90, 90, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 协议弹窗样式 */
|
||||||
|
.agreement-popup {
|
||||||
|
width: 85vw;
|
||||||
|
max-width: 320px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-popup-header {
|
||||||
|
padding: 20px 16px 10px;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-popup-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-popup-content {
|
||||||
|
padding: 20px 16px;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-popup-text {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #666;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-popup-footer {
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-btn {
|
||||||
|
height: 44px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -78,12 +78,7 @@ const navigateToEdit = () => {
|
|||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.page-container {
|
.page-container {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding-bottom: 50px;
|
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
min-height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 成功内容区域 */
|
/* 成功内容区域 */
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<view class="title-content">
|
<view class="title-content">
|
||||||
<text class="main-title">第二届“钟声杯”直属工会趣味运动会</text>
|
<text class="main-title">第二届"钟声杯"直属工会趣味运动会</text>
|
||||||
<view class="sub-title-container">
|
<view class="sub-title-container">
|
||||||
<text class="sub-title">欢迎使用</text>
|
<text class="sub-title">欢迎使用</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -128,6 +128,13 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部信息 -->
|
||||||
|
<view class="footer-info">
|
||||||
|
<view class="footer-item">主办单位:浙江省教育工会</view>
|
||||||
|
<view class="footer-item">承办单位:杭州医学院工会</view>
|
||||||
|
<view class="footer-item">技术支持:武汉地大三思科技有限公司</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -290,7 +297,7 @@ async function handleLogin() {
|
|||||||
Toast({message: '登录成功', theme: 'success'})
|
Toast({message: '登录成功', theme: 'success'})
|
||||||
const redirect = uni.getStorageSync("REDIRECT_URL")
|
const redirect = uni.getStorageSync("REDIRECT_URL")
|
||||||
if(redirect){
|
if(redirect){
|
||||||
if(redirect.startsWith('/pages/index/index') || redirect.startsWith('/pages/profile/index')){
|
if(redirect.startsWith('/pages/index/index') || redirect.startsWith('/pages/activity/rank/index') || redirect.startsWith('/pages/profile/index')){
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: redirect
|
url: redirect
|
||||||
})
|
})
|
||||||
@@ -515,4 +522,17 @@ body {
|
|||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 底部信息样式 */
|
||||||
|
.footer-info {
|
||||||
|
padding: 20px 30px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-item {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<view class="title-content">
|
<view class="title-content">
|
||||||
<text class="main-title">第二届“钟声杯”直属工会趣味运动会</text>
|
<text class="main-title">第二届"钟声杯"直属工会趣味运动会</text>
|
||||||
<view class="sub-title-container">
|
<view class="sub-title-container">
|
||||||
<text class="sub-title">用户注册</text>
|
<text class="sub-title">用户注册</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -134,6 +134,13 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部信息 -->
|
||||||
|
<view class="footer-info">
|
||||||
|
<view class="footer-item">主办单位:浙江省教育工会</view>
|
||||||
|
<view class="footer-item">承办单位:杭州医学院工会</view>
|
||||||
|
<view class="footer-item">技术支持:武汉地大三思科技有限公司</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 自定义单位选择弹窗 -->
|
<!-- 自定义单位选择弹窗 -->
|
||||||
<t-popup v-model="showUnitPicker" placement="bottom">
|
<t-popup v-model="showUnitPicker" placement="bottom">
|
||||||
<view class="custom-picker">
|
<view class="custom-picker">
|
||||||
@@ -687,4 +694,17 @@ onMounted(() => {
|
|||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 底部信息样式 */
|
||||||
|
.footer-info {
|
||||||
|
padding: 20px 30px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-item {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ export default defineConfig({
|
|||||||
},*/
|
},*/
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://119.91.224.39:9090/',
|
// target: 'http://119.91.224.39:9090/',
|
||||||
|
target: 'http://192.168.118.1:9090/',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, '')
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user