This commit is contained in:
@jyuhsin
2025-04-24 16:06:36 +08:00
parent e4ef2da1ae
commit fd3dda9bb2
25 changed files with 377 additions and 95 deletions
@@ -0,0 +1,92 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
*
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
*/
package io.v.nutz.base.utils;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.URLUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
/**
* 文件下载工具类,使用本类前,对参数校验的异常使用CommonResponseUtil.renderError()方法进行渲染
*
* @author xuyuxiang
* @date 2020/8/5 21:45
*/
@Slf4j
public class CommonDownloadUtil {
/**
* 下载文件
*
* @param file 要下载的文件
* @param response 响应
* @author xuyuxiang
* @date 2020/8/5 21:46
*/
public static void download(File file, HttpServletResponse response) {
download(file.getName(), FileUtil.readBytes(file), response);
}
/**
* 下载文件
*
* @param fileName
* @param workbook
* @param response
*/
public static void download(String fileName, Workbook workbook, HttpServletResponse response) {
ByteArrayOutputStream byteOs = new ByteArrayOutputStream();
try {
workbook.write(byteOs);
} catch (IOException e) {
e.printStackTrace();
log.error(">>> 文件下载异常:", e);
} finally {
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
IoUtil.close(byteOs);
}
download(fileName, byteOs.toByteArray(), response);
}
/**
* 下载文件
*
* @author xuyuxiang
* @date 2022/7/31 10:57
*/
public static void download(String fileName, byte[] fileBytes, HttpServletResponse response) {
try {
response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName));
response.addHeader("Content-Length", "" + fileBytes.length);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setContentType("application/octet-stream;charset=UTF-8");
IoUtil.write(response.getOutputStream(), true, fileBytes);
} catch (IOException e) {
log.error(">>> 文件下载异常:", e);
}
}
}
@@ -3,6 +3,7 @@ package io.v.nutz.zhgh.qsv.controller;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.page.Pagination;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.sys.models.Sys_home_activity;
import io.v.nutz.zhgh.qsv.models.QsvActivity;
import io.v.nutz.zhgh.qsv.models.QsvOption;
import io.v.nutz.zhgh.qsv.models.QsvSubject;
@@ -64,6 +65,12 @@ public class QsvActivityController {
}
}
dao.insertOrUpdate(qsvActivity);
if (!qsvActivity.getDelFlag()) {
Sys_home_activity sysHomeActivity = qsvActivity.covertToSysHomeActivity();
dao.insertOrUpdate(sysHomeActivity);
} else {
dao.delete(Sys_home_activity.class, qsvActivity.getId());
}
return Result.success();
}
@@ -55,7 +55,7 @@ public class QsvQuizRankController {
@At
@Ok("void")
@RequiresPermissions("qsv.quiz.rank")
public void exportXlsx(@Valid QsvQuizRankPageForm pageForm, HttpServletResponse response) {
public void exportXlsx(QsvQuizRankPageForm pageForm, HttpServletResponse response) {
qsvQuizRankService.exportXlsx(pageForm, response);
}
@@ -34,9 +34,10 @@ public class H5QsvController {
// 分页查询
@At
@RequiresAuthentication
public Result pageData(@Valid PageForm pageForm, @Valid String category) {
public Result pageData(@Valid PageForm pageForm, @Valid String category, String queryId) {
Cnd cnd = Cnd.NEW();
cnd.andEX("category", "=", category);
cnd.andEX("id", "=", queryId);
cnd.desc("startTime");
Pagination pagination = qsvActivityService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
return Result.success(pagination);
@@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.wizzer.framework.base.Result;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.activity.models.ActivityUserScope;
import io.v.nutz.zhgh.qsv.dto.QsvCheckAnswerResult;
import io.v.nutz.zhgh.qsv.models.QsvActivity;
import io.v.nutz.zhgh.qsv.models.QsvSubject;
@@ -60,6 +61,12 @@ public class H5QsvQuizController {
@RequiresAuthentication
public Result subjects(@Valid String activityId) {
QsvActivity activity = dao.fetch(QsvActivity.class, activityId);
int count = dao.count(ActivityUserScope.class, Cnd.where("groupId", "=", activity.getGroupId()).and("userId", "=", ShiroUtil.getUserId()));
if (count != 1) {
return Result.error("您无需参加此次答题,感谢您的关注!");
}
String mode = activity.getMode();
//能否重复答题
Boolean repeatable = activity.getRepeatable();
@@ -69,6 +76,8 @@ public class H5QsvQuizController {
Integer maxAttempts = activity.getMaxAttempts();
//题目显示模式
String displayMode = activity.getDisplayMode();
// 重复答题,显示提示
Boolean repeatTips = false;
//最终返回的题目数据
List<QsvSubject> resultSubjects = new ArrayList<>();
@@ -78,7 +87,7 @@ public class H5QsvQuizController {
List<QsvUserAnswerRecord> answerRecords = dao.query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
.and("userId", "=", ShiroUtil.getUserId()));
if (activity.getEndTime().after(new Date())) {
if (activity.getEndTime().before(new Date())) {
//已结束 查询最新一次的答题记录
Optional<QsvUserAnswerRecord> lastRecordOptional = answerRecords.stream().max(Comparator.comparing(QsvUserAnswerRecord::getAnswerTime));
if (lastRecordOptional.isPresent()) {
@@ -102,13 +111,13 @@ public class H5QsvQuizController {
}
} else {
if (mode.equals("REGULAR")) {
if ("REGULAR".equals(mode)) {
if (ObjectUtil.isEmpty(answerRecords)) {
//首次进来生成答题记录
if (displayMode.equals("ALL")) {
resultSubjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId));
if ("ALL".equals(displayMode)) {
resultSubjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
answerRecordId = qsvUserAnswerRecordService.insertRecord(activityId, resultSubjects.stream().map(QsvSubject::getId).collect(Collectors.toList())).getId();
} else if (displayMode.equals("RANDOM")) {
} else if ("RANDOM".equals(displayMode)) {
//单次随机抽取题目数量
Integer randomCount = activity.getRandomCount();
@@ -130,21 +139,31 @@ public class H5QsvQuizController {
resultSubjects = dao.query(QsvSubject.class, cnd);
}
} else {
if (displayMode.equals("ALL")) {
if ("ALL".equals(displayMode)) {
//判断能否重复答题 如果可重复要根据次数判断是否再次生成记录 不能重复直接返回最新的一次记录
if (repeatable) {
//已回答次数
if (answerRecords.size() < maxAttempts) {
//生成答题记录
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId));
answerRecordId = qsvUserAnswerRecordService.insertRecord(activityId, subjects.stream().map(QsvSubject::getId).collect(Collectors.toList())).getId();
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, answerRecordId);
QsvUserAnswerRecord fetch = dao.fetch(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
.and("userId", "=", ShiroUtil.getUserId()).and("isFinish", "=", false)
.desc("randomNumber"));
List<String> subjectIds = new ArrayList<>();
if (fetch == null) {
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
answerRecordId = qsvUserAnswerRecordService.insertRecord(activityId, subjects.stream().map(QsvSubject::getId).collect(Collectors.toList())).getId();
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, answerRecordId);
subjectIds = answerRecord.getSubjectIds();
List<String> subjectIds = answerRecord.getSubjectIds();
} else {
subjectIds = fetch.getSubjectIds();
answerRecordId = fetch.getId();
}
Cnd cnd = Cnd.where("id", "in", subjectIds);
String dynamic = subjectIds.stream().map(id -> "'" + id + "'").collect(Collectors.joining(","));
cnd.and(new Static("1=1 ORDER BY FIELD (id," + dynamic + ")"));
resultSubjects = dao.query(QsvSubject.class, cnd);
repeatTips = true;
} else {
//已达到最大次数 返回最新一次记录
Optional<QsvUserAnswerRecord> maxAnswerRecordOptional = answerRecords.stream().max(Comparator.comparingLong(QsvUserAnswerRecord::getRandomNumber));
@@ -172,7 +191,7 @@ public class H5QsvQuizController {
throw new RuntimeException("业务异常");
}
}
} else if (displayMode.equals("RANDOM")) {
} else if ("RANDOM".equals(displayMode)) {
//判断是否有未答完的记录
Optional<QsvUserAnswerRecord> notFinishRecordOptional = answerRecords.stream().filter(r -> !r.getIsFinish()).findFirst();
if (notFinishRecordOptional.isPresent()) {
@@ -200,7 +219,7 @@ public class H5QsvQuizController {
//进行下一次抽取
List<String> subjectIds = answerRecords.stream().map(QsvUserAnswerRecord::getSubjectIds).flatMap(Collection::stream).toList();
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId)
.and("id", "not in", subjectIds));
.and("id", "not in", subjectIds).asc("sortNum"));
if (subjects.size() < randomCount) {
throw new RuntimeException("题目数不够,无法生成题目");
@@ -230,7 +249,7 @@ public class H5QsvQuizController {
}
}
}
} else if (mode.equals("SCHEDULED")) {
} else if ("SCHEDULED".equals(mode)) {
//定时定题
//查询今天的题目
@@ -246,7 +265,7 @@ public class H5QsvQuizController {
if (todayAllFinish && todayRecords.size() < maxAttempts) {
//生成今天的记录
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId)
.and("displayDate", "=", DateUtil.today()));
.and("displayDate", "=", DateUtil.today()).asc("sortNum"));
QsvUserAnswerRecord answerRecord = qsvUserAnswerRecordService.insertRecord(activityId, subjects.stream().map(QsvSubject::getId).collect(Collectors.toList()));
answerRecordId = answerRecord.getId();
@@ -273,7 +292,7 @@ public class H5QsvQuizController {
} else {
//生成今天的记录
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId)
.and("displayDate", "=", DateUtil.today()));
.and("displayDate", "=", DateUtil.today()).asc("sortNum"));
QsvUserAnswerRecord answerRecord = qsvUserAnswerRecordService.insertRecord(activityId, subjects.stream().map(QsvSubject::getId).collect(Collectors.toList()));
answerRecordId = answerRecord.getId();
@@ -290,7 +309,8 @@ public class H5QsvQuizController {
resultSubjects.forEach(v -> v.setUserSelectOptionIds(new ArrayList<>()));
NutMap result = NutMap.NEW().addv("subjects", resultSubjects).addv("answerRecordId", answerRecordId).addv("activity", activity);
NutMap result = NutMap.NEW().addv("subjects", resultSubjects).addv("answerRecordId", answerRecordId)
.addv("activity", activity).addv("repeatTips", repeatTips);
return Result.success(result);
}
@@ -66,7 +66,7 @@ public class H5QsvSurveyController {
answerRecordId = answerRecord2.getId();
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("id", "in", answerRecord2.getSubjectIds()));
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("id", "in", answerRecord2.getSubjectIds()).asc("sortNum"));
dao.fetchLinks(subjects, "options", Cnd.NEW().asc("sortNum"));
for (QsvSubject subject : subjects) {
@@ -1,10 +1,16 @@
package io.v.nutz.zhgh.qsv.models;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.model.BaseModel;
import io.v.nutz.base.utils.DateUtil;
import io.v.nutz.sys.models.Sys_home_activity;
import io.v.nutz.sys.services.SysHomeConvert;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import org.nutz.lang.Lang;
import java.util.Date;
@@ -13,7 +19,8 @@ import java.util.Date;
@Table("qsv_activity")
@TableMeta("{'mysql-charset':'utf8mb4'}")
@Comment("问卷调查投票活动表")
public class QsvActivity extends BaseModel {
public class QsvActivity extends BaseModel implements SysHomeConvert {
@Name
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@@ -106,4 +113,24 @@ public class QsvActivity extends BaseModel {
@Comment("封面图片")
@ColDefine(type = ColType.VARCHAR, width = 255)
private String cover;
@Override
public Sys_home_activity covertToSysHomeActivity() {
Sys_home_activity sysHomeActivity = new Sys_home_activity();
sysHomeActivity.setId(this.getId());
sysHomeActivity.setName(this.getTitle());
if(StrUtil.isNotEmpty(this.getCover())){
sysHomeActivity.setCover(this.getCover());
}
sysHomeActivity.setUrl(null);
sysHomeActivity.setH5Url("/platform/h5/qsv?category=" + this.getCategory() + "&id=" + this.getId());
if (Lang.isNotEmpty(this.getStartTime())) {
sysHomeActivity.setStartDate(this.getStartTime());
sysHomeActivity.setEndDate(this.getEndTime());
}
sysHomeActivity.setAllowUserGroupId(this.getGroupId());
sysHomeActivity.setEnable(!this.getDelFlag());
sysHomeActivity.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
return sysHomeActivity;
}
}
@@ -7,6 +7,7 @@ import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.page.Pagination;
import io.v.nutz.base.service.impl.BaseServiceImpl;
import io.v.nutz.base.utils.CommonDownloadUtil;
import io.v.nutz.zhgh.qsv.models.QsvActivity;
import io.v.nutz.zhgh.qsv.models.QsvUserAnswerRecord;
import io.v.nutz.zhgh.qsv.param.QsvQuizRankPageForm;
@@ -83,7 +84,7 @@ public class QsvQuizRankServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord>
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
// CommonDownloadUtil.download(activity.getTitle() + "得分名单" + ".xlsx", workbook, response);
CommonDownloadUtil.download(activity.getTitle() + "得分名单" + ".xlsx", workbook, response);
}
private Sql buildQuerySql(String activityId, String mode, String scoreStatisticsMode, QsvQuizRankPageForm pageForm) {
@@ -92,6 +93,7 @@ public class QsvQuizRankServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord>
t1.userId,
t1.userName,
t1.loginName,
u.sex,
t1.unitName,
t1.unionName,
u.mobile,
@@ -8,6 +8,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import io.v.nutz.base.service.impl.BaseServiceImpl;
import io.v.nutz.base.utils.CommonDownloadUtil;
import io.v.nutz.zhgh.qsv.models.QsvActivity;
import io.v.nutz.zhgh.qsv.models.QsvOption;
import io.v.nutz.zhgh.qsv.models.QsvSubject;
@@ -45,7 +46,8 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
try {
// 查询用户答题记录
List<QsvUserAnswerRecord> answerRecords = dao().query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId));
List<QsvUserAnswerRecord> answerRecords = dao().query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
.and("isFinish", "=", true));
// 将答题记录的扩展JSON转换为JSONObject列表
List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
@@ -122,7 +124,8 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
}
// 查询用户答题记录
List<QsvUserAnswerRecord> answerRecords = dao().query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId));
List<QsvUserAnswerRecord> answerRecords = dao().query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
.and("isFinish", "=", true));
// 将答题记录的扩展JSON转换为JSONObject列表
List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
@@ -148,7 +151,7 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
exportParams.setType(ExcelType.XSSF);
// 导出Excel并下载
try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, excelExportEntities, list)) {
// CommonDownloadUtil.download(activity.getTitle() + "答题记录" + ".xlsx", workbook, response);
CommonDownloadUtil.download(activity.getTitle() + "答题记录" + ".xlsx", workbook, response);
}
} catch (Exception e) {
log.error("导出Excel失败", e);
@@ -165,9 +168,10 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
try {
// 查询用户答题记录
List<QsvUserAnswerRecord> answerRecords = dao().query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId));
List<QsvUserAnswerRecord> answerRecords = dao().query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
.and("isFinish", "=", true));
// 将答题记录的扩展JSON转换为JSONObject列表
List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
// List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
// 查询活动题目列表
List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId));
@@ -248,7 +252,7 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
} else if (type.equals("radio") || type.equals("checkbox")) {
JSONArray optionIds = jsonVal.getJSONArray("optionIds");
String selectOptionTexts = options.stream().filter(option -> optionIds.contains(option.getId()))
.map(QsvOption::getText).collect(Collectors.joining(";"));
.map(QsvOption::getText).collect(Collectors.joining(""));
map.addv(k, selectOptionTexts);
}
});
@@ -36,7 +36,7 @@ public class QsvUserAnswerRecordServiceImpl extends BaseServiceImpl<QsvUserAnswe
Boolean shuffleSubject = activity.getShuffleSubject();
//打乱题目顺序
if (category.equals("QUIZ") && shuffleSubject) {
if ("QUIZ".equals(category) && shuffleSubject) {
Collections.shuffle(subjectIds);
}
@@ -64,13 +64,13 @@ public class QsvUserAnswerRecordServiceImpl extends BaseServiceImpl<QsvUserAnswe
record.setUnionName(user.getUnionname());
//问卷模式
if (category.equals("QUIZ")) {
if (mode.equals("REGULAR")) {
if ("QUIZ".equals(category)) {
if ("REGULAR".equals(mode)) {
//常规模式 抽取随机题目
int count = dao().count(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
.and("userId", "=", ShiroUtil.getUserId()));
record.setRandomNumber(count + 1);
} else if (mode.equals("SCHEDULED")) {
} else if ("SCHEDULED".equals(mode)) {
//定时定题模式
int count = dao().count(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
.and("userId", "=", ShiroUtil.getUserId())
Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

@@ -3,10 +3,11 @@
<div>
<el-dialog
title="活动二维码"
:title="title ? title : '活动二维码'"
:visible.sync="codeDialogVisible"
:close-on-click-modal="false"
width="40%">
width="40%"
top="2%">
<div style="width: 100%;">
<div id="qrcode" style="width: 70%;left: 0;right: 0;margin: auto"></div>
</div>
@@ -27,7 +28,7 @@ module.exports = {
data() {
return {
codeDialogVisible: false,
title: '',
}
},
methods: {
@@ -47,7 +48,8 @@ module.exports = {
var filename = name + '_' + (new Date()).getTime() + '.' + type;
this.saveFile(dataurl, filename);
},
openCode(url) {
openCode(url, title) {
this.title = title
this.codeDialogVisible = true
this.$nextTick(() => {
$("#qrcode").html("")
+4 -3
View File
@@ -223,10 +223,11 @@ layout("/mobile/platform.html"){
<template slot="loading">
<van-loading size="13" type="spinner"/>
</template>
<template slot="error">
<van-image src="/assets/mobile/img/commonActivity.png" class="middle_item_img"></van-image>
</template>
</van-image>
<van-image height="84" src="xxxxxx" v-else width="120">
<template slot="error">图片查询失败</template>
</van-image>
<van-image src="/assets/mobile/img/commonActivity.png" class="middle_item_img" v-else></van-image>
</div>
<div class="middle_item_text">
@@ -110,9 +110,20 @@ layout("/mobile/platform.html"){
if (path) {
pjaxReplace(path + "?id=" + item.id)
}
},
init() {
const queryId = GetQueryString('id')
const category = GetQueryString('category')
if(category) {
this.pageForm.category = category
}
if(queryId) {
this.pageForm.queryId = queryId
}
}
},
created() {
this.init()
this.onLoad()
}
})
@@ -11,8 +11,8 @@ layout("/mobile/platform.html"){
text-align: center;
padding: 20px;
background: #ffffff;
/*margin: 10px 0;*/
margin-bottom: 10px;
margin: 0 0 10px 0 !important;
/*margin-bottom: 10px;*/
color: var(--color-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
@@ -80,7 +80,7 @@ layout("/mobile/platform.html"){
<h2 class="title">{{ activity.title }}</h2>
</van-sticky>
<div v-if="!answerRecord.isFinish">
<div style="margin-top: 50px" v-if="!answerRecord.isFinish">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
@@ -125,6 +125,7 @@ layout("/mobile/platform.html"){
return {
list: [],
id: GetQueryString("id"),
H5JumpTo: GetQueryString("H5JumpTo"),
subjects: [],
activity: {},
// remainingTime: 0,
@@ -161,8 +162,30 @@ layout("/mobile/platform.html"){
this.activity = res.data.activity
this.subjects = res.data.subjects
this.answerRecordId = res.data.answerRecordId
this.checkGroupPermission()
this.getAnswerRecord()
// this.checkGroupPermission()
if (!this.H5JumpTo && this.activity.repeatable && res.data.repeatTips){
// 如果是可重复答题,第二次答题进来弹出提示
vant.Dialog.confirm({
title: '温馨提示',
message: '您已完成本次答题,是否要重新答题?',
confirmButtonText: '重新答题',
cancelButtonText: '查看答题记录',
}).then(() => {
this.getAnswerRecord()
}).catch(() => {
pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
// pjaxReplace("/mobile/index")
});
} else {
this.getAnswerRecord()
}
} else {
vant.Dialog.alert({
title: '温馨提示',
message: res.msg,
}).then(() => {
pjaxReplace("/mobile/index")
})
}
})
},
@@ -174,7 +197,7 @@ layout("/mobile/platform.html"){
this.answerRecord = res.data
if (this.answerRecord.isFinish || this.$moment().unix() > this.$moment(this.activity.endTime)) {
this.$pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
}
this.initAnswer()
@@ -307,8 +330,7 @@ layout("/mobile/platform.html"){
//自动提交
autoSubmit(loading = null) {
$
.post("/platform/h5/qsv/quiz/submitAnswer", {
$.post("/platform/h5/qsv/quiz/submitAnswer", {
answer: JSON.stringify({
activityId: this.id,
answerRecordId: this.answerRecordId,
@@ -324,35 +346,35 @@ layout("/mobile/platform.html"){
.then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.$pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
pjaxReplace("/platform/h5/qsv/quiz/result?answerRecordId=" + this.answerRecordId)
// this.getAnswerRecord()
}
})
.finally(() => {
.always(() => {
if (loading) {
loading.clear()
}
})
},
async checkGroupPermission() {
const groupId = this.activity.groupId
if (groupId) {
const { code, data } = await $.post("/open/common/checkGroupPermission", { groupId })
if (code === 0) {
if (!data) {
this.$dialog
.alert({
title: "提示",
message: "您没有权限参与"
})
.then(() => {
location.back()
})
}
}
}
}
// async checkGroupPermission() {
// const groupId = this.activity.groupId
// if (groupId) {
// const { code, data } = await $.post("/open/common/checkGroupPermission", { groupId })
// if (code === 0) {
// if (!data) {
// this.$dialog
// .alert({
// title: "提示",
// message: "您没有权限参与"
// })
// .then(() => {
// location.back()
// })
// }
// }
// }
// }
},
created() {
if (this.timerInterval) {
@@ -10,6 +10,7 @@ layout("/mobile/platform.html"){
.container .title {
text-align: center;
padding: 20px;
margin: 0 !important;
background: #ffffff;
color: var(--color-primary);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
@@ -168,7 +169,7 @@ layout("/mobile/platform.html"){
</div>
</van-sticky>
<div>
<div style="margin-top: 50px">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div class="tag">
@@ -208,11 +209,14 @@ layout("/mobile/platform.html"){
</div>
<div class="button-control">
<van-button v-if="canAgainQuestion" type="primary" @click="againQuestion" block>重新答题</van-button>
<!-- 女性知识答题 -->
<van-button v-if="activity.id === 'c3372eb3ee774e86b373fcacf8eb89c7'" type="primary" @click="goWelfareChoose" block>纪念品选择</van-button>
<van-button type="primary" @click="openHistory" block>查看全部答题记录</van-button>
</div>
</div>
<van-action-sheet v-model="historyShow" title="历史记录">
<van-action-sheet v-model="historyShow" title="历史记录" >
<div class="history-list">
<div v-for="item in historyList" class="history-item">
<div class="history-header">
@@ -239,7 +243,9 @@ layout("/mobile/platform.html"){
activity: {},
list: [],
historyShow: false,
historyList: []
historyList: [],
canAgainQuestion: false
}
},
computed: {
@@ -268,12 +274,44 @@ layout("/mobile/platform.html"){
}
},
methods: {
/**
* 福利选择
*/
goWelfareChoose(){
// 女性答题的福利
pjaxReplace('/mobile/welfare/list/receive?projectId=8799d66b0bb640078f50feb029e506ed')
},
/**
* 重新答题
*/
againQuestion() {
vant.Dialog.confirm({
title: '温馨提示',
message: '确定要重新答题吗?',
}).then(() => {
pjaxReplace('/platform/h5/qsv/quiz?id=' + this.activity.id + "&H5JumpTo=true")
}).catch(() => {
// on cancel
});
},
getAnswerResult() {
$.post("/platform/h5/qsv/quiz/answerResult", { answerRecordId: this.answerRecordId }).then((res) => {
if (res.code === 0) {
this.subjects = res.data.subjects
this.activity = res.data.activity
this.getAnswerRecord()
if (this.activity.id === 'c3372eb3ee774e86b373fcacf8eb89c7') {
vant.Dialog.alert({
title: '温馨提示',
message: "感谢您参与女性健康知识竞赛。请选取活动纪念品",
}).then(() => {
this.getAnswerRecord()
this.getHistoryQuestion()
})
} else {
this.getAnswerRecord()
this.getHistoryQuestion()
}
}
})
},
@@ -305,16 +343,19 @@ layout("/mobile/platform.html"){
}
})
},
historyBack() {
pjaxReplace('/platform/h5/qsv')
},
openHistory() {
this.historyShow = true
},
getHistoryQuestion() {
$.post("/platform/h5/qsv/quiz/historyScore", { activityId: this.activity.id }).then((res) => {
if (res.code === 0) {
this.historyList = res.data
if (this.activity.maxAttempts > res.data.length) {
this.canAgainQuestion = true
}
}
})
}
@@ -90,6 +90,16 @@ layout("/mobile/platform.html"){
max-width: 100%!important;
}
.desc {
background: #ffffff;
margin: 0 0 10px 0;
padding: 10px;
line-height: 22px;
}
.desc p{
margin: 0;
}
</style>
@@ -97,6 +107,7 @@ layout("/mobile/platform.html"){
<van-nav-bar title="问卷调查" left-arrow @click-left="pjaxReplace('/mobile/index')" placeholder fixed></van-nav-bar>
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<h2 class="title">{{ activity.title }}</h2>
<div class="desc" v-html="activity.description"></div>
<div v-if="!isFinished">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
@@ -97,7 +97,7 @@ layout("/layouts/platform.html"){
code="PREPARED_BY"></dict-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">费用类型:</div>
<div class="search-item-option">
@@ -108,7 +108,7 @@ layout("/layouts/platform.html"){
code="USER_PERSONAL_STATUS"></dict-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">变更类型:</div>
<div class="search-item-option">
@@ -178,9 +178,9 @@ layout("/layouts/platform.html"){
<el-select v-model="pageForm.isMember" @change="doSearch()"
:clearable="false" size="small"
style="width: 130px;margin-right: 5px">
<el-option label="全部" value=""></el-option>
<el-option label="全部教工" value=""></el-option>
<el-option label="是会员" value="1"></el-option>
<el-option label="不是会员" value="0"></el-option>
<el-option label="会员" value="0"></el-option>
</el-select>
<el-radio-group v-model="pageForm.changed" @change="doSearch" class="mr5"
@@ -2,7 +2,7 @@ const basicForm = {
template: /*language=HTML*/ `
<el-dialog :visible.sync="dialogVisible" title="基础设置">
<div style="overflow-y: auto">
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="150px">
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="120px">
<el-form-item label="类型" prop="category">
<el-radio-group v-model="formData.category" size="small">
<el-radio v-for="item in dict.type.ACTIVITY_QSV_CATEGORY" :label="item.value"
@@ -44,8 +44,7 @@ const subjectForm = {
</div>
<div v-if="subject.type === 'checkbox'">
最大选择数:
<el-input v-model="subject.maxMulti" placeholder="最多可选数量"></el-input>
最大选择数:<el-input v-model="subject.maxMulti" placeholder="最多可选数量" style="width: 200px"></el-input>
</div>
@@ -127,7 +127,7 @@ layout("/layouts/platform.html"){
})
},
exportXlsx() {
// this.$downLoad("/platform/qsv/quizRank/exportXlsx", this.pageForm)
this.$downLoad("/platform/qsv/quizRank/exportXlsx", this.pageForm)
}
},
async created() {
@@ -1,13 +1,13 @@
const answer = {
/*language=HTML*/
template: `
<el-dialog title="查看答卷" :visible.sync="dialogVisible" width="50%">
<el-dialog title="查看答卷" :visible.sync="dialogVisible" width="70%" top="2%">
<el-row type="flex" justify="end" class="mb10">
<el-button type="primary" size="small" icon="el-icon-download" @click="exportUserAnswerXlsx">导出xlsx</el-button>
</el-row>
<el-table :data="tableData">
<el-table-column label="序号" type="index" width="70"></el-table-column>
<el-table-column v-for="item in tableColumns" :key="item.prop" :label="item.label" :prop="item.prop"></el-table-column>
<el-table-column v-for="item in tableColumns" :key="item.prop" :label="item.label" :prop="item.prop" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" fixed="right" width="100px">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" @click="onDelete(scope.row.id)"></el-button>
@@ -56,7 +56,7 @@ const answer = {
},
exportUserAnswerXlsx() {
// this.$downLoad("/platform/qsv/survey/exportUserAnswerXlsx", { activityId: this.activityId })
this.$downLoad("/platform/qsv/survey/exportUserAnswerXlsx", { activityId: this.activityId })
}
}
}
@@ -22,11 +22,11 @@ layout("/layouts/platform.html"){
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="数据列表">
<!-- <el-button @click="exportXlsx" icon="el-icon-download" size="small" type="primary" class="mr5">导出xlsx</el-button>-->
<!-- <el-button @click="exportXlsx" icon="el-icon-download" size="small" type="primary" class="mr5">导出xlsx</el-button>-->
</table-tool>
<el-table :data="tableData" ref="tableRef" @sort-change="pageOrder">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="标题" prop="title" width="120" sortable></el-table-column>
<el-table-column label="标题" prop="title" width="320" sortable></el-table-column>
<el-table-column label="类型" prop="category" sortable>
<template scope="{row}">
<dict-tag :options="dict.type.ACTIVITY_QSV_CATEGORY" :value="row.category"></dict-tag>
@@ -60,7 +60,7 @@ layout("/layouts/platform.html"){
},
methods: {
exportXlsx() {
$.post("/platform/qsv/survey/exportXlsx", this.pageForm)
this.$downLoad("/platform/qsv/survey/exportXlsx", this.pageForm)
}
},
created() {
@@ -1,8 +1,41 @@
const report = {
/*language=HTML*/
template: `
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="50%">
<div v-for="(subject,subjectIndex) in subjects" class="subject">
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="70%" top="2%">
<el-collapse v-model="activeName" accordion>
<el-collapse-item :name="subjectIndex + 1" v-for="(subject,subjectIndex) in subjects">
<template slot="title">
<div class="title">
{{subjectIndex+1}} {{subject.title}}
<span class="type" v-if="subject.type==='text'">[填空题]</span>
<span class="type" v-else-if="subject.type==='radio'">[单选题]</span>
<span class="type" v-else-if="subject.type==='text'">[多选题]</span>
</div>
</template>
<div v-if="subject.type==='text'">
{{subject.texts.join('、')}}
</div>
<div v-else-if="subject.type==='radio' || subject.type==='checkbox'">
<el-table :data="subject.options" size="small">
<el-table-column label="选项" prop="text"></el-table-column>
<el-table-column label="小计" prop="selectCount" width="100"></el-table-column>
<el-table-column label="比例" width="500">
<template slot-scope="scope">
<el-progress
:percentage="Math.round(scope.row.selectCount / subject.selectTotal * 100)"></el-progress>
</template>
</el-table-column>
<el-table-column label="详情" width="100px">
<template slot-scope="{row}">
<el-button type="text" @click="openDetail(subject.id,row.id)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-collapse-item>
</el-collapse>
<!--<div v-for="(subject,subjectIndex) in subjects" class="subject">
<div>
<div class="title">
{{subjectIndex+1}} {{subject.title}}
@@ -32,11 +65,10 @@ const report = {
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>-->
<el-dialog title="选择详情" :visible.sync="optionVisible" width="50%" append-to-body>
<el-dialog title="选择详情" :visible.sync="optionVisible" width="50%" append-to-body top="2%">
<el-table :data="optionUsers" size="small">
<el-table-column label="姓名" prop="userName"></el-table-column>
<el-table-column label="工号" prop="loginName"></el-table-column>
@@ -56,7 +88,8 @@ const report = {
report: null,
subjects: [],
optionVisible: false,
optionUsers: []
optionUsers: [],
activeName: 1
}
},
methods: {
@@ -91,10 +124,21 @@ const report = {
}
.subject .title{
margin-bottom: 5px;
font-weight: bold;
}
.subject .type{
color: #a6a6a6;
margin-left: 10px;
}
.el-collapse {
border-top: 0;
border-bottom: 0;
}
.el-collapse .title{
font-weight: bold;
}
.el-collapse-item__header,.el-collapse-item__wrap {
border-bottom: 0;
}
`
}
@@ -53,10 +53,8 @@ const activity = {
enterActivity(item) {
if (item.url) {
sublime.jumpPagePjax(item.url)
} else if (item.url) {
this.$refs.openQRCode.openCode(item.url, "该活动只支持手机端报名,请使用手机扫描二维码报名!")
} else {
this.$message.warning("该活动支持")
this.$refs.openQRCode.openCode(item.url, "该活动支持手机端报名,请使用手机扫描二维码报名!")
}
}
},