commit
This commit is contained in:
@@ -51,7 +51,7 @@ public class QsvSurveyController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
// 报告
|
||||
// 报告
|
||||
@At
|
||||
@RequiresPermissions("qsv.survey")
|
||||
public Result report(@Valid String activityId) {
|
||||
@@ -59,7 +59,16 @@ public class QsvSurveyController {
|
||||
return Result.success(report);
|
||||
}
|
||||
|
||||
// 选项选择详情
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@RequiresPermissions("qsv.survey")
|
||||
public void exportReportXlsx(String activityId, HttpServletResponse response){
|
||||
qsvSurveyService.exportReportXlsx(activityId, response);
|
||||
}
|
||||
|
||||
|
||||
// 选项选择详情
|
||||
@At
|
||||
@RequiresPermissions("qsv.survey")
|
||||
public Result selectOptionUsers(@Valid String activityId, @Valid String subjectId, @Valid String optionId) {
|
||||
@@ -69,16 +78,17 @@ public class QsvSurveyController {
|
||||
}
|
||||
|
||||
|
||||
// 用户答题
|
||||
// 用户答题
|
||||
@At
|
||||
@RequiresPermissions("qsv.survey")
|
||||
public Result userAnswer(@Valid String activityId) {
|
||||
NutMap map = qsvSurveyService.userAnswer(activityId);
|
||||
public Result userAnswer(PageForm pageForm, @Valid String activityId) { //@Valid String activityId
|
||||
// NutMap map = qsvSurveyService.userAnswer(activityId);
|
||||
NutMap map = qsvSurveyService.userAnswer(pageForm, activityId);
|
||||
return Result.success(map);
|
||||
}
|
||||
|
||||
|
||||
// 删除用户答题记录
|
||||
// 删除用户答题记录
|
||||
@At
|
||||
@RequiresPermissions("qsv.survey")
|
||||
public Result deleteUserAnswer(@Valid String id) {
|
||||
@@ -87,8 +97,9 @@ public class QsvSurveyController {
|
||||
}
|
||||
|
||||
|
||||
// 导出用户答题记录xlsx
|
||||
// 导出用户答题记录xlsx
|
||||
@At
|
||||
@Ok("void")
|
||||
@RequiresPermissions("qsv.survey")
|
||||
public void exportUserAnswerXlsx(@Valid String activityId, HttpServletResponse response) {
|
||||
qsvSurveyService.exportUserAnswerXlsx(activityId, response);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.v.nutz.zhgh.qsv.service;
|
||||
|
||||
import io.v.nutz.base.query.PageForm;
|
||||
import io.v.nutz.base.service.BaseService;
|
||||
import io.v.nutz.zhgh.qsv.models.QsvUserAnswerRecord;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
@@ -11,7 +12,10 @@ public interface QsvSurveyService extends BaseService<QsvUserAnswerRecord> {
|
||||
|
||||
List<NutMap> report(String activityId);
|
||||
|
||||
void exportReportXlsx(String activityId, HttpServletResponse response);
|
||||
|
||||
void exportUserAnswerXlsx(String activityId, HttpServletResponse response);
|
||||
|
||||
NutMap userAnswer(String activityId);
|
||||
// NutMap userAnswer(String activityId);
|
||||
NutMap userAnswer(PageForm pageForm, String activityId);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.afterturn.easypoi.excel.export.ExcelExportService;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import io.v.nutz.base.page.Pagination;
|
||||
import io.v.nutz.base.query.PageForm;
|
||||
import io.v.nutz.base.service.impl.BaseServiceImpl;
|
||||
import io.v.nutz.base.utils.CommonDownloadUtil;
|
||||
import io.v.nutz.zhgh.qsv.models.QsvActivity;
|
||||
@@ -16,6 +19,7 @@ import io.v.nutz.zhgh.qsv.models.QsvUserAnswerRecord;
|
||||
import io.v.nutz.zhgh.qsv.service.QsvSurveyService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -79,6 +83,10 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
||||
}
|
||||
// 处理单选类型题目 处理多选类型题目
|
||||
else if ("radio".equals(subjectType) || "checkbox".equals(subjectType)) {
|
||||
long selectTotal = answerExtList.stream()
|
||||
.filter(ext -> ext.containsKey(subject.getString("id")))
|
||||
.count();
|
||||
|
||||
subjectOptions.forEach(subjectOption -> {
|
||||
long selectCount = answerExtList.stream()
|
||||
.filter(ext ->
|
||||
@@ -89,15 +97,22 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
||||
&& jsonObject.getJSONArray("optionIds").contains(subjectOption.getString("id"));
|
||||
})
|
||||
.count();
|
||||
long round = Math.round((double) selectCount / selectTotal * 100);
|
||||
subjectOption.put("selectPercent", round + "%");
|
||||
subjectOption.put("selectCount", selectCount);
|
||||
});
|
||||
|
||||
long selectTotal = answerExtList.stream()
|
||||
.filter(ext -> ext.containsKey(subject.getString("id")))
|
||||
.count();
|
||||
subjectOptions.sort((o1, o2) -> {
|
||||
int count1 = o1.getInt("selectCount");
|
||||
int count2 = o2.getInt("selectCount");
|
||||
if (count1 == count2) {
|
||||
return Integer.compare(o1.getInt("sortNum"), o2.getInt("sortNum"));
|
||||
}
|
||||
return Integer.compare(count2, count1);
|
||||
});
|
||||
|
||||
subject.put("selectTotal", selectTotal);
|
||||
}
|
||||
|
||||
// 添加选项到题目中
|
||||
subject.addv("options", subjectOptions);
|
||||
}
|
||||
@@ -109,6 +124,32 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void exportReportXlsx(String activityId, HttpServletResponse response) {
|
||||
List<NutMap> report = report(activityId);
|
||||
|
||||
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||
exportEntities.add(new ExcelExportEntity("选项名称", "text", 80));
|
||||
exportEntities.add(new ExcelExportEntity("选择人数", "selectCount", 20));
|
||||
exportEntities.add(new ExcelExportEntity("选择比例", "selectPercent", 20));
|
||||
|
||||
Map<String, List<NutMap>> listMap = report.stream().collect(Collectors.groupingBy(v -> v.getString("id")));
|
||||
Workbook workbook = new XSSFWorkbook();
|
||||
listMap.forEach((k, v) -> {
|
||||
NutMap nutMap = v.get(0);
|
||||
ExcelExportService service = new ExcelExportService();
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setTitle(nutMap.getString("title"));
|
||||
exportParams.setSheetName(nutMap.getString("title"));
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
service.createSheetForMap(workbook, exportParams, exportEntities, nutMap.getList("options", NutMap.class));
|
||||
});
|
||||
|
||||
CommonDownloadUtil.download("调研分析.xlsx", workbook, response);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportUserAnswerXlsx(String activityId, HttpServletResponse response) {
|
||||
// 检查活动ID是否为空
|
||||
@@ -160,16 +201,24 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap userAnswer(String activityId) {
|
||||
public NutMap userAnswer(PageForm pageForm, String activityId) {
|
||||
// 检查活动ID是否为空
|
||||
if (activityId == null || activityId.isEmpty()) {
|
||||
throw new IllegalArgumentException("活动ID不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("activityId", "=", activityId);
|
||||
cnd.and("isFinish", "=", true);
|
||||
// Cnd.where("activityId", "=", activityId)
|
||||
// .and("isFinish", "=", true)
|
||||
Pagination pagination = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
List<NutMap> answerRecords = pagination.getList();
|
||||
|
||||
// 查询用户答题记录
|
||||
List<QsvUserAnswerRecord> answerRecords = dao().query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
|
||||
.and("isFinish", "=", true));
|
||||
// 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();
|
||||
|
||||
@@ -188,7 +237,33 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
||||
// 构建Excel导出实体
|
||||
List<ExcelExportEntity> excelExportEntities = buildExcelExportEntities(subjects);
|
||||
// 构建答题记录列表
|
||||
List<NutMap> list = buildAnswerRecords(answerRecords, subjectMap, options);
|
||||
List<NutMap> list = answerRecords.stream().map(record -> {
|
||||
NutMap map = NutMap.NEW()
|
||||
.addv("id", record.getString("id"))
|
||||
.addv("loginName", record.getString("loginName"))
|
||||
.addv("userName", record.getString("userName"))
|
||||
.addv("unitName", record.getString("unitName"))
|
||||
.addv("unionName", record.getString("unionName"));
|
||||
JSONObject extJson = record.getAs("extJson", JSONObject.class);
|
||||
extJson.forEach((k, v) -> {
|
||||
JSONObject jsonVal = (JSONObject) v;
|
||||
|
||||
String type = subjectMap.get(k).getType();
|
||||
if (type.equals("text")) {
|
||||
map.addv(k, jsonVal.getStr("text"));
|
||||
} 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.addv(k, selectOptionTexts);
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}).toList();
|
||||
pagination.setList(list);
|
||||
|
||||
|
||||
// List<NutMap> list = buildAnswerRecords(answerRecords, subjectMap, options);
|
||||
|
||||
// 构建表格列信息
|
||||
List<NutMap> tableColumns = excelExportEntities.stream()
|
||||
@@ -197,7 +272,7 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
||||
|
||||
return NutMap.NEW()
|
||||
.addv("tableColumns", tableColumns)
|
||||
.addv("tableData", list);
|
||||
.addv("tableData", pagination);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("获取用户答题记录失败", e);
|
||||
}
|
||||
@@ -252,7 +327,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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,45 @@
|
||||
const commonUtil = {
|
||||
//axios配置
|
||||
axiosService() {
|
||||
// 创建 axios 实例
|
||||
const axiosService = axios.create({
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
|
||||
"x-requested-with": "XMLHttpRequest"
|
||||
}
|
||||
})
|
||||
//axios拦截器
|
||||
axiosService.interceptors.response.use(
|
||||
(response) => {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera
|
||||
const isMobile = /iPad|iPhone|iPod|Android/.test(userAgent)
|
||||
//判断是否为blob 不处理直接返回文件流
|
||||
if (response.config.responseType === "blob") {
|
||||
return response
|
||||
}
|
||||
if (response.data && response.data.code !== 0) {
|
||||
if (isMobile) {
|
||||
vant.Toast(response.data.msg)
|
||||
} else {
|
||||
ELEMENT.Message.error(response.data.msg)
|
||||
}
|
||||
return Promise.reject(response.data)
|
||||
}
|
||||
return response.data
|
||||
},
|
||||
(error) => {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera
|
||||
const isMobile = /iPad|iPhone|iPod|Android/.test(userAgent)
|
||||
if (isMobile) {
|
||||
vant.Toast(error.message)
|
||||
} else {
|
||||
ELEMENT.Message.error(error.message)
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
return axiosService
|
||||
},
|
||||
//权限认证
|
||||
authService() {
|
||||
function authPermission(permission) {
|
||||
@@ -65,4 +106,55 @@ const commonUtil = {
|
||||
}
|
||||
}
|
||||
},
|
||||
//下载文件
|
||||
downLoadService: function (url, data) {
|
||||
const loading = ELEMENT.Loading.service({
|
||||
lock: true,
|
||||
text: "导出中,请耐心等待",
|
||||
spinner: "el-icon-loading",
|
||||
background: "rgba(0, 0, 0, 0.7)"
|
||||
})
|
||||
|
||||
Vue.prototype.$axios
|
||||
.post(url, data, { responseType: "blob" })
|
||||
.then((response) => {
|
||||
if (response.data.type === "application/json") {
|
||||
try {
|
||||
const reader = new FileReader()
|
||||
reader.onload = function () {
|
||||
// reader.result 包含了 Blob 的内容,转换为字符串
|
||||
const content = reader.result
|
||||
// 将字符串解析为 JSON 对象
|
||||
const jsonObject = JSON.parse(content)
|
||||
this.$message.error(jsonObject.msg)
|
||||
}
|
||||
reader.readAsText(response.data)
|
||||
} catch (err) {
|
||||
this.$message.error("下载文件出错")
|
||||
}
|
||||
return
|
||||
}
|
||||
//获取服务器返回的文件描述信息
|
||||
const contentDisposition = response.headers["content-disposition"]
|
||||
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
|
||||
const matches = filenameRegex.exec(contentDisposition)
|
||||
let filename = ""
|
||||
if (matches != null && matches[1]) {
|
||||
filename = matches[1].replace(/['"]/g, "")
|
||||
filename = decodeURIComponent(filename)
|
||||
}
|
||||
//执行下载文件
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]))
|
||||
const link = document.createElement("a")
|
||||
link.href = url
|
||||
link.setAttribute("download", filename) // 例如 'document.pdf'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
link.parentNode.removeChild(link)
|
||||
loading.close()
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,9 @@
|
||||
<script type="text/javascript" src="${base!}/assets/platform/plugins/wp-upload-vue/font/iconfont.js"></script>
|
||||
<script type="text/javascript" src="${base!}/assets/platform/plugins/wp-upload-vue/js/wpupload.js"></script>
|
||||
|
||||
<!--axios-->
|
||||
<script src="${base!}/assets/platform/plugins/axios/axios.js"></script>
|
||||
|
||||
<!-- import JavaScript -->
|
||||
<script src="${base!}/assets/platform/plugins/element-ui/lib/index.js"></script>
|
||||
<script src="${base!}/assets/platform/plugins/element-ui/lib/i18n/${lang,escape}.js"></script>
|
||||
@@ -146,6 +149,8 @@
|
||||
window.viewImage = viewImage;
|
||||
Vue.prototype.$viewImage = viewImage
|
||||
Vue.prototype.$auth = commonUtil.authService()
|
||||
Vue.prototype.$axios = commonUtil.axiosService()
|
||||
Vue.prototype.$downLoad = commonUtil.downLoadService
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const answer = {
|
||||
/*language=HTML*/
|
||||
template: `
|
||||
<el-dialog title="查看答卷" :visible.sync="dialogVisible" width="70%" top="2%">
|
||||
<el-dialog title="查看答卷" :visible.sync="dialogVisible" width="80%">
|
||||
<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>
|
||||
@@ -14,8 +14,10 @@ const answer = {
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-dialog>
|
||||
`,
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
@@ -28,14 +30,16 @@ const answer = {
|
||||
onOpen(activityId) {
|
||||
this.activityId = activityId
|
||||
this.dialogVisible = true
|
||||
this.list()
|
||||
this.pageData()
|
||||
},
|
||||
|
||||
list() {
|
||||
$.post("/platform/qsv/survey/userAnswer", { activityId: this.activityId }).then((res) => {
|
||||
pageData() {
|
||||
this.pageForm.activityId = this.activityId
|
||||
$.post("/platform/qsv/survey/userAnswer", this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.tableColumns = res.data.tableColumns
|
||||
this.tableData = res.data.tableData
|
||||
this.tableData = res.data.tableData.list
|
||||
this.pageForm.totalCount = res.data.tableData.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -2,6 +2,9 @@ const report = {
|
||||
/*language=HTML*/
|
||||
template: `
|
||||
<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="exportReportXlsx">导出xlsx</el-button>
|
||||
</el-row>
|
||||
<el-collapse v-model="activeName" accordion>
|
||||
<el-collapse-item :name="subjectIndex + 1" v-for="(subject,subjectIndex) in subjects">
|
||||
<template slot="title">
|
||||
@@ -116,6 +119,9 @@ const report = {
|
||||
this.optionUsers = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
exportReportXlsx(){
|
||||
this.$downLoad("/platform/qsv/survey/exportReportXlsx", { activityId: this.activityId })
|
||||
}
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
|
||||
Reference in New Issue
Block a user