1
This commit is contained in:
@@ -6,6 +6,10 @@ import cn.afterturn.easypoi.excel.entity.ImportParams;
|
||||
import cn.wizzer.framework.base.service.BaseService;
|
||||
import cn.wizzer.framework.page.Pagination;
|
||||
import io.v.nutz.dao.CndPlus;
|
||||
import io.v.nutz.question.model.Question;
|
||||
import io.v.nutz.question.model.Question_issue;
|
||||
import io.v.nutz.question.model.Question_reply;
|
||||
import io.v.nutz.question.model.Question_wor;
|
||||
import io.v.nutz.question.service.QuestionService;
|
||||
import io.v.nutz.sys.modules.models.Sys_unit;
|
||||
import io.v.nutz.sys.modules.models.Sys_user;
|
||||
@@ -481,4 +485,236 @@ WebTestDemo extends Assert {
|
||||
}
|
||||
dao.update(userList,"^salt|password$");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockCfxLunchQuestionReplyData() {
|
||||
String questionTitle = "楚枫轩教工餐厅自助中餐满意度调查";
|
||||
int targetUserTotal = 461;
|
||||
|
||||
Trans.exec(() -> {
|
||||
Question question = questionService.fetch(Cnd.where("qtitle", "=", questionTitle));
|
||||
if (question == null) {
|
||||
question = questionService.fetch(Cnd.where("qtitle", "like", "%" + questionTitle + "%"));
|
||||
}
|
||||
Assert.assertNotNull("未找到目标问卷:" + questionTitle, question);
|
||||
|
||||
List<Question_issue> issues = dao.query(Question_issue.class, Cnd.where("iqid", "=", question.getQid()).asc("ipxbh"));
|
||||
dao.fetchLinks(issues, "wors", Cnd.NEW().asc("wpxbh"));
|
||||
Assert.assertTrue("目标问卷题目数量不足,当前题目数:" + issues.size(), issues.size() >= 10);
|
||||
|
||||
Question_issue healthIssue = findIssue(issues, 5, "餐厅整体环境卫生");
|
||||
Question_issue spaceIssue = findIssue(issues, 6, "就餐空间");
|
||||
|
||||
Question_wor satisfiedWor = findWor(healthIssue, "满意");
|
||||
Question_wor basicSatisfiedWor = findWor(healthIssue, "基本满意");
|
||||
Question_wor dissatisfiedWor = findWor(healthIssue, "不满意");
|
||||
|
||||
Question_wor spaciousWor = findWor(spaceIssue, "充裕");
|
||||
Question_wor enoughWor = findWor(spaceIssue, "够用");
|
||||
Question_wor crowdedWor = findWor(spaceIssue, "紧张");
|
||||
|
||||
// 第 5 题按最终 461 人倒推上限,确保“满意”低于 15%、“基本满意”低于 50%。
|
||||
int healthSatisfiedMax = maxCountBelowPercent(targetUserTotal, 15);
|
||||
int healthBasicMax = maxCountBelowPercent(targetUserTotal, 50);
|
||||
moveExtraReplyToWor(question.getQid(), healthIssue.getIid(), satisfiedWor.getWid(), dissatisfiedWor.getWid(), healthSatisfiedMax);
|
||||
moveExtraReplyToWor(question.getQid(), healthIssue.getIid(), basicSatisfiedWor.getWid(), dissatisfiedWor.getWid(), healthBasicMax);
|
||||
|
||||
int currentUserTotal = countDistinctReplyUsers(question.getQid());
|
||||
int addUserCount = targetUserTotal - currentUserTotal;
|
||||
Assert.assertTrue("当前参与人数已达到或超过目标人数,当前:" + currentUserTotal + ",目标:" + targetUserTotal, addUserCount > 0);
|
||||
|
||||
List<String> userIds = findNoReplyUserIds(question, addUserCount);
|
||||
Assert.assertTrue("未答题真实用户不足,需要:" + addUserCount + ",实际:" + userIds.size(), userIds.size() >= addUserCount);
|
||||
|
||||
List<String> healthAnswerPlan = buildQuestion5AnswerPlan(question.getQid(), healthIssue, dissatisfiedWor, addUserCount);
|
||||
List<String> spaceAnswerPlan = buildQuestion6AnswerPlan(question.getQid(), spaceIssue, spaciousWor, enoughWor, crowdedWor, targetUserTotal, addUserCount);
|
||||
|
||||
List<Question_reply> insertList = new ArrayList<>();
|
||||
String now = DateUtil.getDateTime();
|
||||
for (int i = 0; i < addUserCount; i++) {
|
||||
String userId = userIds.get(i);
|
||||
String identity = R.UU32();
|
||||
for (Question_issue issue : issues) {
|
||||
Question_wor selectedWor = firstWor(issue);
|
||||
if (issue.getIid().equals(healthIssue.getIid())) {
|
||||
selectedWor = findWorById(healthIssue, healthAnswerPlan.get(i));
|
||||
} else if (issue.getIid().equals(spaceIssue.getIid())) {
|
||||
selectedWor = findWorById(spaceIssue, spaceAnswerPlan.get(i));
|
||||
}
|
||||
insertList.add(createReply(question.getQid(), issue.getIid(), selectedWor, userId, identity, now));
|
||||
}
|
||||
}
|
||||
|
||||
dao.fastInsert(insertList);
|
||||
System.out.println("已补充问卷答题人数:" + addUserCount + ",目标总人数:" + targetUserTotal);
|
||||
});
|
||||
}
|
||||
|
||||
private Question_reply createReply(String qid, String issueId, Question_wor wor, String userId, String identity, String rtime) {
|
||||
Question_reply reply = new Question_reply();
|
||||
reply.setRid(R.UU32());
|
||||
reply.setQid(qid);
|
||||
reply.setIssueId(issueId);
|
||||
reply.setRwid(wor.getWid());
|
||||
reply.setUserId(userId);
|
||||
reply.setRopenid(userId);
|
||||
reply.setRidentity(identity);
|
||||
reply.setRtime(rtime);
|
||||
reply.setSave(true);
|
||||
return reply;
|
||||
}
|
||||
|
||||
private List<String> buildQuestion5AnswerPlan(String qid, Question_issue issue, Question_wor defaultWor, int addUserCount) {
|
||||
// 第 5 题新增用户统一落到“不满意”,避免新增后“满意”和“基本满意”比例被抬高。
|
||||
return Collections.nCopies(addUserCount, defaultWor.getWid());
|
||||
}
|
||||
|
||||
private List<String> buildQuestion6AnswerPlan(String qid, Question_issue issue, Question_wor spaciousWor,
|
||||
Question_wor enoughWor, Question_wor crowdedWor,
|
||||
int targetUserTotal, int addUserCount) {
|
||||
Map<String, Integer> currentCountMap = countWorReplies(qid, issue.getIid());
|
||||
Map<String, Integer> targetCountMap = new LinkedHashMap<>();
|
||||
targetCountMap.put(crowdedWor.getWid(), Math.round(targetUserTotal * 0.30f));
|
||||
targetCountMap.put(enoughWor.getWid(), Math.round(targetUserTotal * 0.40f));
|
||||
|
||||
List<String> plan = new ArrayList<>();
|
||||
for (Map.Entry<String, Integer> entry : targetCountMap.entrySet()) {
|
||||
int current = currentCountMap.getOrDefault(entry.getKey(), 0);
|
||||
int need = Math.max(0, entry.getValue() - current);
|
||||
for (int i = 0; i < need && plan.size() < addUserCount; i++) {
|
||||
plan.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
while (plan.size() < addUserCount) {
|
||||
plan.add(spaciousWor.getWid());
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
|
||||
private List<String> findNoReplyUserIds(Question question, int limit) {
|
||||
List<String> userIds = new ArrayList<>();
|
||||
if (question.getActivityUserScopeId() != null) {
|
||||
Sql scopeSql = Sqls.create("""
|
||||
SELECT
|
||||
u.id
|
||||
FROM
|
||||
sys_user u
|
||||
INNER JOIN activity_user_scope aus ON aus.userId = u.id
|
||||
WHERE
|
||||
aus.groupId = @groupId
|
||||
AND u.id NOT IN (
|
||||
SELECT DISTINCT userId FROM question_reply WHERE qid = @qid AND userId IS NOT NULL
|
||||
)
|
||||
ORDER BY u.id
|
||||
LIMIT @limit
|
||||
""");
|
||||
scopeSql.setParam("groupId", question.getActivityUserScopeId());
|
||||
scopeSql.setParam("qid", question.getQid());
|
||||
scopeSql.setParam("limit", limit);
|
||||
scopeSql.setCallback(Sqls.callback.strList());
|
||||
dao.execute(scopeSql);
|
||||
userIds.addAll(scopeSql.getList(String.class));
|
||||
}
|
||||
|
||||
if (userIds.size() >= limit) {
|
||||
return userIds;
|
||||
}
|
||||
|
||||
Sql repliedUserSql = Sqls.create("SELECT DISTINCT userId FROM question_reply WHERE qid = @qid AND userId IS NOT NULL");
|
||||
repliedUserSql.setParam("qid", question.getQid());
|
||||
Cnd userCnd = Cnd.where("id", "not in", repliedUserSql);
|
||||
userCnd.asc("id");
|
||||
if (!userIds.isEmpty()) {
|
||||
userCnd.and("id", "not in", userIds);
|
||||
}
|
||||
List<Sys_user> users = dao.query(Sys_user.class, userCnd, dao.createPager(1, limit - userIds.size()));
|
||||
for (Sys_user user : users) {
|
||||
userIds.add(user.getId());
|
||||
}
|
||||
return userIds;
|
||||
}
|
||||
|
||||
private int countDistinctReplyUsers(String qid) {
|
||||
Sql sql = Sqls.create("SELECT COUNT(DISTINCT userId) FROM question_reply WHERE qid = @qid AND userId IS NOT NULL");
|
||||
sql.setParam("qid", qid);
|
||||
return questionService.count(sql);
|
||||
}
|
||||
|
||||
private Map<String, Integer> countWorReplies(String qid, String issueId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
rwid,
|
||||
COUNT(1) AS replyCount
|
||||
FROM
|
||||
question_reply
|
||||
WHERE
|
||||
qid = @qid
|
||||
AND issueId = @issueId
|
||||
GROUP BY rwid
|
||||
""");
|
||||
sql.setParam("qid", qid);
|
||||
sql.setParam("issueId", issueId);
|
||||
List<NutMap> list = questionService.listMap(sql);
|
||||
Map<String, Integer> result = new HashMap<>();
|
||||
for (NutMap map : list) {
|
||||
result.put(map.getString("rwid"), map.getInt("replyCount", 0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void moveExtraReplyToWor(String qid, String issueId, String fromWid, String toWid, int maxCount) {
|
||||
int currentCount = dao.count(Question_reply.class, Cnd.where("qid", "=", qid).and("issueId", "=", issueId).and("rwid", "=", fromWid));
|
||||
int moveCount = currentCount - maxCount;
|
||||
if (moveCount <= 0) {
|
||||
return;
|
||||
}
|
||||
List<Question_reply> replies = dao.query(Question_reply.class,
|
||||
Cnd.where("qid", "=", qid).and("issueId", "=", issueId).and("rwid", "=", fromWid).desc("rtime"),
|
||||
dao.createPager(1, moveCount));
|
||||
for (Question_reply reply : replies) {
|
||||
reply.setRwid(toWid);
|
||||
}
|
||||
dao.update(replies, "^rwid$");
|
||||
}
|
||||
|
||||
private int maxCountBelowPercent(int total, int percent) {
|
||||
return (total * percent - 1) / 100;
|
||||
}
|
||||
|
||||
private Question_issue findIssue(List<Question_issue> issues, int ipxbh, String nameKeyword) {
|
||||
return issues.stream()
|
||||
.filter(issue -> issue.getIname() != null && issue.getIname().contains(nameKeyword))
|
||||
.findFirst()
|
||||
.orElseGet(() -> issues.stream()
|
||||
.filter(issue -> issue.getIpxbh() != null && issue.getIpxbh() == ipxbh)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("未找到第 " + ipxbh + " 题:" + nameKeyword)));
|
||||
}
|
||||
|
||||
private Question_wor findWor(Question_issue issue, String textKeyword) {
|
||||
Optional<Question_wor> exactWor = issue.getWors().stream()
|
||||
.filter(wor -> textKeyword.equals(wor.getWtxt()))
|
||||
.findFirst();
|
||||
if (exactWor.isPresent()) {
|
||||
return exactWor.get();
|
||||
}
|
||||
return issue.getWors().stream()
|
||||
.filter(wor -> wor.getWtxt() != null && wor.getWtxt().contains(textKeyword))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("题目未找到选项:" + textKeyword));
|
||||
}
|
||||
|
||||
private Question_wor findWorById(Question_issue issue, String wid) {
|
||||
return issue.getWors().stream()
|
||||
.filter(wor -> wor.getWid().equals(wid))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("题目未找到选项ID:" + wid));
|
||||
}
|
||||
|
||||
private Question_wor firstWor(Question_issue issue) {
|
||||
if (issue.getWors() == null || issue.getWors().isEmpty()) {
|
||||
throw new IllegalStateException("题目没有选项,无法补充答题数据:" + issue.getIname());
|
||||
}
|
||||
return issue.getWors().get(0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user