修复导出报告和用户档案字段内容

This commit is contained in:
xiao12feng 2025-11-21 13:39:28 +08:00
parent 23fe845e7d
commit 30f5a56876
19 changed files with 772 additions and 357 deletions

View File

@ -83,6 +83,9 @@ public class PsyAssessmentReportController extends BaseController
@Autowired @Autowired
private ISasReportService sasReportService; private ISasReportService sasReportService;
@Autowired
private com.ddnai.system.service.psychology.IPsyUserProfileService profileService;
/** /**
* 获取报告列表包含测评报告和问卷报告 * 获取报告列表包含测评报告和问卷报告
*/ */
@ -125,6 +128,17 @@ public class PsyAssessmentReportController extends BaseController
vo.setIsGenerated(ar.getIsGenerated()); vo.setIsGenerated(ar.getIsGenerated());
vo.setGenerateTime(ar.getGenerateTime()); vo.setGenerateTime(ar.getGenerateTime());
vo.setCreateTime(ar.getCreateTime()); vo.setCreateTime(ar.getCreateTime());
// 获取用户信息
PsyAssessment assessment = assessmentService.selectAssessmentById(ar.getAssessmentId());
if (assessment != null) {
vo.setUserId(assessment.getUserId());
// 获取用户档案信息编号
com.ddnai.system.domain.psychology.PsyUserProfile profile = profileService.selectProfileByUserId(assessment.getUserId());
if (profile != null) {
vo.setInfoNumber(profile.getInfoNumber());
}
}
allReports.add(vo); allReports.add(vo);
} }
@ -141,6 +155,17 @@ public class PsyAssessmentReportController extends BaseController
vo.setIsGenerated(qr.getIsGenerated()); vo.setIsGenerated(qr.getIsGenerated());
vo.setGenerateTime(qr.getGenerateTime()); vo.setGenerateTime(qr.getGenerateTime());
vo.setCreateTime(qr.getCreateTime()); vo.setCreateTime(qr.getCreateTime());
// 获取用户信息
com.ddnai.system.domain.psychology.PsyQuestionnaireAnswer answer = questionnaireAnswerService.selectAnswerById(qr.getAnswerId());
if (answer != null) {
vo.setUserId(answer.getUserId());
// 获取用户档案信息编号
com.ddnai.system.domain.psychology.PsyUserProfile profile = profileService.selectProfileByUserId(answer.getUserId());
if (profile != null) {
vo.setInfoNumber(profile.getInfoNumber());
}
}
allReports.add(vo); allReports.add(vo);
System.out.println("添加问卷报告: reportId=" + qr.getReportId() + ", answerId=" + qr.getAnswerId() + ", title=" + qr.getReportTitle()); System.out.println("添加问卷报告: reportId=" + qr.getReportId() + ", answerId=" + qr.getAnswerId() + ", title=" + qr.getReportTitle());
} }
@ -184,6 +209,8 @@ public class PsyAssessmentReportController extends BaseController
private Long reportId; private Long reportId;
private String sourceType; // "assessment" "questionnaire" private String sourceType; // "assessment" "questionnaire"
private Long sourceId; // assessmentId answerId private Long sourceId; // assessmentId answerId
private Long userId; // 用户ID
private String infoNumber; // 信息编号
private String reportTitle; private String reportTitle;
private String reportType; private String reportType;
private String reportContent; private String reportContent;
@ -199,6 +226,10 @@ public class PsyAssessmentReportController extends BaseController
public void setSourceType(String sourceType) { this.sourceType = sourceType; } public void setSourceType(String sourceType) { this.sourceType = sourceType; }
public Long getSourceId() { return sourceId; } public Long getSourceId() { return sourceId; }
public void setSourceId(Long sourceId) { this.sourceId = sourceId; } public void setSourceId(Long sourceId) { this.sourceId = sourceId; }
public Long getUserId() { return userId; }
public void setUserId(Long userId) { this.userId = userId; }
public String getInfoNumber() { return infoNumber; }
public void setInfoNumber(String infoNumber) { this.infoNumber = infoNumber; }
public String getReportTitle() { return reportTitle; } public String getReportTitle() { return reportTitle; }
public void setReportTitle(String reportTitle) { this.reportTitle = reportTitle; } public void setReportTitle(String reportTitle) { this.reportTitle = reportTitle; }
public String getReportType() { return reportType; } public String getReportType() { return reportType; }

View File

@ -61,7 +61,6 @@ public class PsyQuestionnaireAnswerController extends BaseController
/** /**
* 获取问卷答题列表 * 获取问卷答题列表
*/ */
@PreAuthorize("@ss.hasPermi('psychology:questionnaire:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(PsyQuestionnaireAnswer answer) public TableDataInfo list(PsyQuestionnaireAnswer answer)
{ {
@ -88,9 +87,12 @@ public class PsyQuestionnaireAnswerController extends BaseController
Long questionnaireId = Long.valueOf(params.get("questionnaireId").toString()); Long questionnaireId = Long.valueOf(params.get("questionnaireId").toString());
String respondentName = params.get("respondentName") != null ? params.get("respondentName").toString() : null; String respondentName = params.get("respondentName") != null ? params.get("respondentName").toString() : null;
// 获取被测试用户ID如果前端传递了userId管理员代测则使用传递的userId否则使用当前登录用户ID
Long userId = params.get("userId") != null ? Long.valueOf(params.get("userId").toString()) : SecurityUtils.getUserId();
PsyQuestionnaireAnswer answer = new PsyQuestionnaireAnswer(); PsyQuestionnaireAnswer answer = new PsyQuestionnaireAnswer();
answer.setQuestionnaireId(questionnaireId); answer.setQuestionnaireId(questionnaireId);
answer.setUserId(SecurityUtils.getUserId()); answer.setUserId(userId); // 使用被测试用户ID
answer.setRespondentName(respondentName); answer.setRespondentName(respondentName);
answer.setStatus("0"); // 进行中 answer.setStatus("0"); // 进行中
answer.setStartTime(new Date()); answer.setStartTime(new Date());
@ -164,28 +166,39 @@ public class PsyQuestionnaireAnswerController extends BaseController
{ {
try try
{ {
System.out.println("开始提交问卷answerId: " + answerId + ", 用户: " + SecurityUtils.getUsername());
PsyQuestionnaireAnswer answer = answerService.selectAnswerById(answerId); PsyQuestionnaireAnswer answer = answerService.selectAnswerById(answerId);
if (answer == null) if (answer == null)
{ {
System.err.println("答题记录不存在answerId: " + answerId);
return error("答题记录不存在"); return error("答题记录不存在");
} }
if (!"0".equals(answer.getStatus())) if (!"0".equals(answer.getStatus()))
{ {
System.err.println("问卷状态异常answerId: " + answerId + ", status: " + answer.getStatus());
return error("问卷已完成或已作废"); return error("问卷已完成或已作废");
} }
// 自动评分并提交 // 自动评分并提交
long startTime = System.currentTimeMillis();
int result = answerService.submitAnswer(answerId); int result = answerService.submitAnswer(answerId);
long endTime = System.currentTimeMillis();
System.out.println("问卷提交完成answerId: " + answerId + ", 耗时: " + (endTime - startTime) + "ms, 结果: " + result);
if (result > 0) if (result > 0)
{ {
return success("提交成功"); return success("提交成功");
} }
System.err.println("提交失败answerId: " + answerId + ", result: " + result);
return error("提交失败"); return error("提交失败");
} }
catch (Exception e) catch (Exception e)
{ {
System.err.println("提交问卷异常answerId: " + answerId + ", 错误: " + e.getMessage());
e.printStackTrace();
return error("提交失败:" + e.getMessage()); return error("提交失败:" + e.getMessage());
} }
} }
@ -290,9 +303,8 @@ public class PsyQuestionnaireAnswerController extends BaseController
{ {
Long detailId = Long.valueOf(params.get("detailId").toString()); Long detailId = Long.valueOf(params.get("detailId").toString());
java.math.BigDecimal score = new java.math.BigDecimal(params.get("score").toString()); java.math.BigDecimal score = new java.math.BigDecimal(params.get("score").toString());
String comment = params.get("comment") != null ? params.get("comment").toString() : null;
int result = answerService.submitScoring(detailId, score, comment); int result = answerService.submitScoring(detailId, score, null);
if (result > 0) if (result > 0)
{ {
return success("评分成功"); return success("评分成功");
@ -317,9 +329,8 @@ public class PsyQuestionnaireAnswerController extends BaseController
{ {
Long detailId = Long.valueOf(params.get("detailId").toString()); Long detailId = Long.valueOf(params.get("detailId").toString());
java.math.BigDecimal score = new java.math.BigDecimal(params.get("score").toString()); java.math.BigDecimal score = new java.math.BigDecimal(params.get("score").toString());
String comment = params.get("comment") != null ? params.get("comment").toString() : null;
int result = answerService.submitScoring(detailId, score, comment); int result = answerService.submitScoring(detailId, score, null);
if (result > 0) if (result > 0)
{ {
successCount++; successCount++;

View File

@ -34,9 +34,8 @@ public class PsyQuestionnaireController extends BaseController
private IPsyQuestionnaireService questionnaireService; private IPsyQuestionnaireService questionnaireService;
/** /**
* 获取问卷列表 * 获取问卷列表答题用户可访问
*/ */
@PreAuthorize("@ss.hasPermi('psychology:questionnaire:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(PsyQuestionnaire questionnaire) public TableDataInfo list(PsyQuestionnaire questionnaire)
{ {
@ -46,9 +45,8 @@ public class PsyQuestionnaireController extends BaseController
} }
/** /**
* 根据问卷ID获取详细信息 * 根据问卷ID获取详细信息答题用户可访问
*/ */
@PreAuthorize("@ss.hasPermi('psychology:questionnaire:query')")
@GetMapping(value = "/{questionnaireId}") @GetMapping(value = "/{questionnaireId}")
public AjaxResult getInfo(@PathVariable Long questionnaireId) public AjaxResult getInfo(@PathVariable Long questionnaireId)
{ {

View File

@ -17,17 +17,17 @@ spring:
username: username:
password: password:
# 初始连接数 # 初始连接数
initialSize: 5 initialSize: 10
# 最小连接池数量 # 最小连接池数量
minIdle: 10 minIdle: 20
# 最大连接池数量 # 最大连接池数量
maxActive: 20 maxActive: 100
# 配置获取连接等待超时的时间 # 配置获取连接等待超时的时间减少到20秒快速失败
maxWait: 60000 maxWait: 20000
# 配置连接超时时间 # 配置连接超时时间
connectTimeout: 30000 connectTimeout: 10000
# 配置网络超时时间 # 配置网络超时时间
socketTimeout: 60000 socketTimeout: 30000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000 timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒 # 配置一个连接在池中最小生存的时间,单位是毫秒

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

View File

@ -48,28 +48,48 @@ public class PsyUserProfile extends BaseEntity
@Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd")
private java.util.Date birthday; private java.util.Date birthday;
/** 学历 */ /** 监狱 */
@Excel(name = "学历") @Excel(name = "监狱")
private String education; private String prison;
/** 职业 */ /** 监区 */
@Excel(name = "职业") @Excel(name = "监区")
private String occupation; private String prisonArea;
/** 地址 */ /** 性别 */
@Excel(name = "地址") @Excel(name = "性别", readConverterExp = "0=男,1=女,2=未知")
private String address; private String gender;
/** 紧急联系人 */ /** 民族 */
@Excel(name = "紧急联系人") @Excel(name = "民族")
private String emergencyContact; private String nation;
/** 紧急联系电话 */ /** 文化程度 */
@Excel(name = "紧急联系电话") @Excel(name = "文化程度")
private String emergencyPhone; private String educationLevel;
/** 病史 */ /** 罪名 */
private String medicalHistory; @Excel(name = "罪名")
private String crimeName;
/** 刑期 */
@Excel(name = "刑期")
private String sentenceTerm;
/** 刑期起日 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "刑期起日", width = 30, dateFormat = "yyyy-MM-dd")
private java.util.Date sentenceStartDate;
/** 刑期止日 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "刑期止日", width = 30, dateFormat = "yyyy-MM-dd")
private java.util.Date sentenceEndDate;
/** 入监时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "入监时间", width = 30, dateFormat = "yyyy-MM-dd")
private java.util.Date entryDate;
/** 用户状态0正常 1停用 */ /** 用户状态0正常 1停用 */
private String status; private String status;
@ -154,64 +174,104 @@ public class PsyUserProfile extends BaseEntity
this.birthday = birthday; this.birthday = birthday;
} }
public String getEducation() public String getPrison()
{ {
return education; return prison;
} }
public void setEducation(String education) public void setPrison(String prison)
{ {
this.education = education; this.prison = prison;
} }
public String getOccupation() public String getPrisonArea()
{ {
return occupation; return prisonArea;
} }
public void setOccupation(String occupation) public void setPrisonArea(String prisonArea)
{ {
this.occupation = occupation; this.prisonArea = prisonArea;
} }
public String getAddress() public String getGender()
{ {
return address; return gender;
} }
public void setAddress(String address) public void setGender(String gender)
{ {
this.address = address; this.gender = gender;
} }
public String getEmergencyContact() public String getNation()
{ {
return emergencyContact; return nation;
} }
public void setEmergencyContact(String emergencyContact) public void setNation(String nation)
{ {
this.emergencyContact = emergencyContact; this.nation = nation;
} }
public String getEmergencyPhone() public String getEducationLevel()
{ {
return emergencyPhone; return educationLevel;
} }
public void setEmergencyPhone(String emergencyPhone) public void setEducationLevel(String educationLevel)
{ {
this.emergencyPhone = emergencyPhone; this.educationLevel = educationLevel;
} }
public String getMedicalHistory() public String getCrimeName()
{ {
return medicalHistory; return crimeName;
} }
public void setMedicalHistory(String medicalHistory) public void setCrimeName(String crimeName)
{ {
this.medicalHistory = medicalHistory; this.crimeName = crimeName;
}
public String getSentenceTerm()
{
return sentenceTerm;
}
public void setSentenceTerm(String sentenceTerm)
{
this.sentenceTerm = sentenceTerm;
}
public java.util.Date getSentenceStartDate()
{
return sentenceStartDate;
}
public void setSentenceStartDate(java.util.Date sentenceStartDate)
{
this.sentenceStartDate = sentenceStartDate;
}
public java.util.Date getSentenceEndDate()
{
return sentenceEndDate;
}
public void setSentenceEndDate(java.util.Date sentenceEndDate)
{
this.sentenceEndDate = sentenceEndDate;
}
public java.util.Date getEntryDate()
{
return entryDate;
}
public void setEntryDate(java.util.Date entryDate)
{
this.entryDate = entryDate;
} }
public String getUserName() public String getUserName()
@ -274,74 +334,6 @@ public class PsyUserProfile extends BaseEntity
this.infoNumber = infoNumber; this.infoNumber = infoNumber;
} }
// 以下方法用于兼容现有代码这些字段可能存储在 profileData JSON
// 如果需要可以从 profileData 中解析这些字段
public String getPrisonerName()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getPrisonName()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getPrisonAreaName()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getCustodyStatus()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getNation()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getEducationLevel()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getCrimeName()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getSentenceTerm()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getSentenceStartDate()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getSentenceEndDate()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
public String getEntryDate()
{
// 可以从 profileData JSON 中解析暂时返回 null
return null;
}
@Override @Override
public String toString() { public String toString() {
@ -354,11 +346,16 @@ public class PsyUserProfile extends BaseEntity
.append("userName", getUserName()) .append("userName", getUserName())
.append("phone", getPhone()) .append("phone", getPhone())
.append("birthday", getBirthday()) .append("birthday", getBirthday())
.append("education", getEducation()) .append("prison", getPrison())
.append("occupation", getOccupation()) .append("prisonArea", getPrisonArea())
.append("address", getAddress()) .append("gender", getGender())
.append("emergencyContact", getEmergencyContact()) .append("nation", getNation())
.append("emergencyPhone", getEmergencyPhone()) .append("educationLevel", getEducationLevel())
.append("crimeName", getCrimeName())
.append("sentenceTerm", getSentenceTerm())
.append("sentenceStartDate", getSentenceStartDate())
.append("sentenceEndDate", getSentenceEndDate())
.append("entryDate", getEntryDate())
.append("infoNumber", getInfoNumber()) .append("infoNumber", getInfoNumber())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())

View File

@ -156,22 +156,30 @@ public class PsyAssessmentServiceImpl implements IPsyAssessmentService
PsyUserProfile profile = userProfileService.selectProfileByUserId(userId); PsyUserProfile profile = userProfileService.selectProfileByUserId(userId);
if (profile != null) if (profile != null)
{ {
if (StringUtils.isNotEmpty(profile.getPrisonerName())) if (StringUtils.isNotEmpty(profile.getUserName()))
{ {
summaryVO.setUserName(profile.getPrisonerName()); summaryVO.setUserName(profile.getUserName());
summaryVO.setNickName(profile.getPrisonerName()); summaryVO.setNickName(profile.getUserName());
} }
summaryVO.setInfoNumber(profile.getInfoNumber()); summaryVO.setInfoNumber(profile.getInfoNumber());
summaryVO.setPrisonName(profile.getPrisonName()); summaryVO.setPrisonName(profile.getPrison());
summaryVO.setPrisonAreaName(profile.getPrisonAreaName()); summaryVO.setPrisonAreaName(profile.getPrisonArea());
summaryVO.setCustodyStatus(profile.getCustodyStatus()); // 监管状态字段已删除可以根据需要设置默认值或删除此行
// summaryVO.setCustodyStatus(profile.getCustodyStatus());
summaryVO.setNation(profile.getNation()); summaryVO.setNation(profile.getNation());
summaryVO.setEducationLevel(profile.getEducationLevel()); summaryVO.setEducationLevel(profile.getEducationLevel());
summaryVO.setCrimeName(profile.getCrimeName()); summaryVO.setCrimeName(profile.getCrimeName());
summaryVO.setSentenceTerm(profile.getSentenceTerm()); summaryVO.setSentenceTerm(profile.getSentenceTerm());
summaryVO.setSentenceStartDate(profile.getSentenceStartDate()); // 日期字段需要转换为字符串格式
summaryVO.setSentenceEndDate(profile.getSentenceEndDate()); if (profile.getSentenceStartDate() != null) {
summaryVO.setEntryDate(profile.getEntryDate()); summaryVO.setSentenceStartDate(new java.text.SimpleDateFormat("yyyy-MM-dd").format(profile.getSentenceStartDate()));
}
if (profile.getSentenceEndDate() != null) {
summaryVO.setSentenceEndDate(new java.text.SimpleDateFormat("yyyy-MM-dd").format(profile.getSentenceEndDate()));
}
if (profile.getEntryDate() != null) {
summaryVO.setEntryDate(new java.text.SimpleDateFormat("yyyy-MM-dd").format(profile.getEntryDate()));
}
} }
List<PsyAssessment> assessments = assessmentMapper.selectAssessmentListByUserId(userId); List<PsyAssessment> assessments = assessmentMapper.selectAssessmentListByUserId(userId);

View File

@ -3,6 +3,7 @@ package com.ddnai.system.service.impl.psychology;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -217,25 +218,37 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
// 判断是否及格需要从问卷表获取及格分数 // 判断是否及格需要从问卷表获取及格分数
// 这里暂时不判断后续可以完善 // 这里暂时不判断后续可以完善
// 更新排名需要重新计算所有答题记录的排名
updateRank(answer.getQuestionnaireId());
int result = answerMapper.updateAnswer(answer); int result = answerMapper.updateAnswer(answer);
// 生成问卷报告 // 异步更新排名避免阻塞提交流程
if (result > 0) { final Long questionnaireIdForRank = answer.getQuestionnaireId();
CompletableFuture.runAsync(() -> {
try { try {
generateQuestionnaireReport(answerId); // 延迟50ms确保事务提交完成
System.out.println("问卷报告生成完成answerId: " + answerId); Thread.sleep(50);
updateRank(questionnaireIdForRank);
System.out.println("异步排名更新完成questionnaireId: " + questionnaireIdForRank);
} catch (Exception e) { } catch (Exception e) {
// 报告生成失败不影响提交但记录详细错误 System.err.println("异步更新排名失败questionnaireId: " + questionnaireIdForRank);
System.err.println("生成问卷报告失败answerId: " + answerId);
System.err.println("错误信息: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
// 不抛出异常让提交流程继续
} }
} else { });
System.err.println("更新答题记录失败无法生成报告answerId: " + answerId);
// 异步生成问卷报告避免阻塞提交流程
if (result > 0) {
// 使用异步任务生成报告不阻塞当前事务
CompletableFuture.runAsync(() -> {
try {
// 延迟100ms确保事务提交完成
Thread.sleep(100);
generateQuestionnaireReport(answerId);
System.out.println("异步问卷报告生成完成answerId: " + answerId);
} catch (Exception e) {
System.err.println("异步生成问卷报告失败answerId: " + answerId);
System.err.println("错误信息: " + e.getMessage());
e.printStackTrace();
}
});
} }
return result; return result;
@ -379,10 +392,35 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
reportContent.append("</tbody></table>"); reportContent.append("</tbody></table>");
reportContent.append("</div>"); reportContent.append("</div>");
// 检查是否有未评分的主观题
boolean hasUnscoredSubjective = false;
int unscoredCount = 0;
for (PsyQuestionnaireAnswerDetail detail : details) {
PsyQuestionnaireItem item = itemMapper.selectItemById(detail.getItemId());
if (item != null) {
boolean isSubjective = isSubjectiveType(item.getItemType());
String isScored = detail.getIsScored();
// 如果是主观题且未评分
if (isSubjective && !"1".equals(isScored)) {
hasUnscoredSubjective = true;
unscoredCount++;
}
}
}
System.out.println("评分检查结果 - 总题目数: " + details.size() +
", 未评分主观题数: " + unscoredCount +
", 是否有未评分主观题: " + hasUnscoredSubjective);
// 生成报告摘要 // 生成报告摘要
String summary = String.format("本次答题共完成%d道题目总得分%.2f分", String summary = String.format("本次答题共完成%d道题目总得分%.2f分%s",
details.size(), details.size(),
answer.getTotalScore() != null ? answer.getTotalScore().doubleValue() : 0.0); answer.getTotalScore() != null ? answer.getTotalScore().doubleValue() : 0.0,
hasUnscoredSubjective ? "(有" + unscoredCount + "道主观题待评分)" : "");
// 根据是否有未评分的主观题决定报告状态
String isGenerated = hasUnscoredSubjective ? "0" : "1";
// 保存报告到数据库 // 保存报告到数据库
PsyQuestionnaireReport existingReport = reportMapper.selectReportByAnswerId(answerId); PsyQuestionnaireReport existingReport = reportMapper.selectReportByAnswerId(answerId);
@ -394,13 +432,13 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
if (existingReport != null) { if (existingReport != null) {
// 更新现有报告 // 更新现有报告
System.out.println("更新已存在的报告reportId: " + existingReport.getReportId()); System.out.println("更新已存在的报告reportId: " + existingReport.getReportId() + ", 报告状态: " + isGenerated);
report = existingReport; report = existingReport;
report.setReportType("standard"); report.setReportType("standard");
report.setReportTitle(reportTitle); report.setReportTitle(reportTitle);
report.setReportContent(reportContent.toString()); report.setReportContent(reportContent.toString());
report.setSummary(summary); report.setSummary(summary);
report.setIsGenerated("1"); report.setIsGenerated(isGenerated); // 根据评分状态设置
report.setGenerateTime(DateUtils.getNowDate()); report.setGenerateTime(DateUtils.getNowDate());
report.setUpdateBy(SecurityUtils.getUsername()); report.setUpdateBy(SecurityUtils.getUsername());
report.setUpdateTime(DateUtils.getNowDate()); report.setUpdateTime(DateUtils.getNowDate());
@ -414,12 +452,12 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
report.setReportTitle(reportTitle); report.setReportTitle(reportTitle);
report.setReportContent(reportContent.toString()); report.setReportContent(reportContent.toString());
report.setSummary(summary); report.setSummary(summary);
report.setIsGenerated("1"); report.setIsGenerated(isGenerated); // 根据评分状态设置
report.setGenerateTime(DateUtils.getNowDate()); report.setGenerateTime(DateUtils.getNowDate());
report.setCreateBy(SecurityUtils.getUsername()); report.setCreateBy(SecurityUtils.getUsername());
report.setCreateTime(DateUtils.getNowDate()); report.setCreateTime(DateUtils.getNowDate());
int insertResult = reportMapper.insertReport(report); int insertResult = reportMapper.insertReport(report);
System.out.println("创建新报告结果: " + insertResult + ", reportId: " + report.getReportId()); System.out.println("创建新报告结果: " + insertResult + ", reportId: " + report.getReportId() + ", 报告状态: " + isGenerated);
if (insertResult <= 0) { if (insertResult <= 0) {
System.err.println("警告报告插入失败insertResult: " + insertResult); System.err.println("警告报告插入失败insertResult: " + insertResult);
} }
@ -1008,8 +1046,18 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
answer.setUpdateBy(SecurityUtils.getUsername()); answer.setUpdateBy(SecurityUtils.getUsername());
answerMapper.updateAnswer(answer); answerMapper.updateAnswer(answer);
// 重新计算排名 // 异步重新计算排名
updateRank(answer.getQuestionnaireId()); final Long questionnaireIdForRank = answer.getQuestionnaireId();
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(50);
updateRank(questionnaireIdForRank);
System.out.println("评分后异步排名更新完成questionnaireId: " + questionnaireIdForRank);
} catch (Exception e) {
System.err.println("评分后异步更新排名失败questionnaireId: " + questionnaireIdForRank);
e.printStackTrace();
}
});
// 重新生成报告以反映最新的评分 // 重新生成报告以反映最新的评分
// 注意由于在同一个事务中MyBatis一级缓存可能返回旧数据 // 注意由于在同一个事务中MyBatis一级缓存可能返回旧数据

View File

@ -92,7 +92,8 @@ public class SasReportServiceImpl implements ISasReportService
info.setUnitName(firstNonBlank(summary.getPrisonName(), summary.getDeptName(), resolveDefaultUnitName())); info.setUnitName(firstNonBlank(summary.getPrisonName(), summary.getDeptName(), resolveDefaultUnitName()));
info.setPrisonAreaName(summary.getPrisonAreaName()); info.setPrisonAreaName(summary.getPrisonAreaName());
info.setDeptName(summary.getDeptName()); info.setDeptName(summary.getDeptName());
info.setCustodyStatus(summary.getCustodyStatus()); // 监管状态字段已删除可以根据需要设置默认值或删除此行
// info.setCustodyStatus(summary.getCustodyStatus());
} }
else else
{ {
@ -181,10 +182,11 @@ public class SasReportServiceImpl implements ISasReportService
} }
if (data.getUserInfo() != null) if (data.getUserInfo() != null)
{ {
if (StringUtils.isNotBlank(data.getUserInfo().getCustodyStatus())) // 监管状态字段已删除
{ // if (StringUtils.isNotBlank(data.getUserInfo().getCustodyStatus()))
keywords.add(data.getUserInfo().getCustodyStatus()); // {
} // keywords.add(data.getUserInfo().getCustodyStatus());
// }
if (StringUtils.isNotBlank(data.getUserInfo().getPrisonAreaName())) if (StringUtils.isNotBlank(data.getUserInfo().getPrisonAreaName()))
{ {
keywords.add(data.getUserInfo().getPrisonAreaName()); keywords.add(data.getUserInfo().getPrisonAreaName());

View File

@ -25,31 +25,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectQuestionnaireVo"> <sql id="selectQuestionnaireVo">
select questionnaire_id, questionnaire_code, questionnaire_name, questionnaire_type, paper_type, select q.questionnaire_id, q.questionnaire_code, q.questionnaire_name, q.questionnaire_type, q.paper_type,
item_count, total_score, pass_score, estimated_time, description, status, sort_order, COALESCE(COUNT(i.item_id), 0) as item_count, q.total_score, q.pass_score, q.estimated_time, q.description, q.status, q.sort_order,
create_by, create_time, update_by, update_time, remark q.create_by, q.create_time, q.update_by, q.update_time, q.remark
from psy_questionnaire from psy_questionnaire q
left join psy_questionnaire_item i on q.questionnaire_id = i.questionnaire_id
</sql> </sql>
<select id="selectQuestionnaireById" parameterType="Long" resultMap="PsyQuestionnaireResult"> <select id="selectQuestionnaireById" parameterType="Long" resultMap="PsyQuestionnaireResult">
<include refid="selectQuestionnaireVo"/> <include refid="selectQuestionnaireVo"/>
where questionnaire_id = #{questionnaireId} where q.questionnaire_id = #{questionnaireId}
group by q.questionnaire_id
</select> </select>
<select id="selectQuestionnaireByCode" parameterType="String" resultMap="PsyQuestionnaireResult"> <select id="selectQuestionnaireByCode" parameterType="String" resultMap="PsyQuestionnaireResult">
<include refid="selectQuestionnaireVo"/> <include refid="selectQuestionnaireVo"/>
where questionnaire_code = #{questionnaireCode} where q.questionnaire_code = #{questionnaireCode}
group by q.questionnaire_id
</select> </select>
<select id="selectQuestionnaireList" parameterType="com.ddnai.system.domain.psychology.PsyQuestionnaire" resultMap="PsyQuestionnaireResult"> <select id="selectQuestionnaireList" parameterType="com.ddnai.system.domain.psychology.PsyQuestionnaire" resultMap="PsyQuestionnaireResult">
<include refid="selectQuestionnaireVo"/> <include refid="selectQuestionnaireVo"/>
<where> <where>
<if test="questionnaireCode != null and questionnaireCode != ''"> and questionnaire_code = #{questionnaireCode}</if> <if test="questionnaireCode != null and questionnaireCode != ''"> and q.questionnaire_code = #{questionnaireCode}</if>
<if test="questionnaireName != null and questionnaireName != ''"> and questionnaire_name like concat('%', #{questionnaireName}, '%')</if> <if test="questionnaireName != null and questionnaireName != ''"> and q.questionnaire_name like concat('%', #{questionnaireName}, '%')</if>
<if test="questionnaireType != null and questionnaireType != ''"> and questionnaire_type = #{questionnaireType}</if> <if test="questionnaireType != null and questionnaireType != ''"> and q.questionnaire_type = #{questionnaireType}</if>
<if test="status != null and status != ''"> and status = #{status}</if> <if test="status != null and status != ''"> and q.status = #{status}</if>
</where> </where>
order by sort_order, create_time desc group by q.questionnaire_id
order by q.sort_order, q.create_time desc
</select> </select>
<insert id="insertQuestionnaire" parameterType="com.ddnai.system.domain.psychology.PsyQuestionnaire" useGeneratedKeys="true" keyProperty="questionnaireId"> <insert id="insertQuestionnaire" parameterType="com.ddnai.system.domain.psychology.PsyQuestionnaire" useGeneratedKeys="true" keyProperty="questionnaireId">

View File

@ -14,12 +14,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="userName" column="user_name" /> <result property="userName" column="user_name" />
<result property="phone" column="phone" /> <result property="phone" column="phone" />
<result property="birthday" column="birthday" /> <result property="birthday" column="birthday" />
<result property="education" column="education" /> <result property="prison" column="prison" />
<result property="occupation" column="occupation" /> <result property="prisonArea" column="prison_area" />
<result property="address" column="address" /> <result property="gender" column="gender" />
<result property="emergencyContact" column="emergency_contact" /> <result property="nation" column="nation" />
<result property="emergencyPhone" column="emergency_phone" /> <result property="educationLevel" column="education_level" />
<result property="medicalHistory" column="medical_history" /> <result property="crimeName" column="crime_name" />
<result property="sentenceTerm" column="sentence_term" />
<result property="sentenceStartDate" column="sentence_start_date" />
<result property="sentenceEndDate" column="sentence_end_date" />
<result property="entryDate" column="entry_date" />
<result property="status" column="status" /> <result property="status" column="status" />
<result property="deptId" column="dept_id" /> <result property="deptId" column="dept_id" />
<result property="deptName" column="dept_name" /> <result property="deptName" column="dept_name" />
@ -33,8 +37,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<sql id="selectProfileVo"> <sql id="selectProfileVo">
select p.profile_id, p.user_id, p.profile_type, p.profile_data, p.avatar, p.id_card, p.birthday, select p.profile_id, p.user_id, p.profile_type, p.profile_data, p.avatar, p.id_card, p.birthday,
p.education, p.occupation, p.address, p.emergency_contact, p.emergency_phone, p.prison, p.prison_area, p.gender, p.nation, p.education_level, p.crime_name,
p.medical_history, p.info_number, p.create_by, p.create_time, p.update_by, p.update_time, p.remark, p.sentence_term, p.sentence_start_date, p.sentence_end_date, p.entry_date,
p.info_number, p.create_by, p.create_time, p.update_by, p.update_time, p.remark,
u.user_name, u.phonenumber as phone, u.nick_name, u.email, u.sex, u.status, u.dept_id, u.create_time as user_create_time u.user_name, u.phonenumber as phone, u.nick_name, u.email, u.sex, u.status, u.dept_id, u.create_time as user_create_time
</sql> </sql>
@ -64,8 +69,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar as user_avatar, u.phonenumber as phone, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by as user_create_by, u.create_time as user_create_time, u.remark as user_remark, select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar as user_avatar, u.phonenumber as phone, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by as user_create_by, u.create_time as user_create_time, u.remark as user_remark,
d.dept_name, d.leader, d.dept_name, d.leader,
p.profile_id, p.profile_type, p.profile_data, p.avatar, p.id_card, p.birthday, p.profile_id, p.profile_type, p.profile_data, p.avatar, p.id_card, p.birthday,
p.education, p.occupation, p.address, p.emergency_contact, p.emergency_phone, p.prison, p.prison_area, p.gender, p.nation, p.education_level, p.crime_name,
p.medical_history, p.info_number, p.create_by, p.create_time, p.update_by, p.update_time, p.remark p.sentence_term, p.sentence_start_date, p.sentence_end_date, p.entry_date,
p.info_number, p.create_by, p.create_time, p.update_by, p.update_time, p.remark
from sys_user u from sys_user u
left join sys_dept d on u.dept_id = d.dept_id left join sys_dept d on u.dept_id = d.dept_id
left join psy_user_profile p on u.user_id = p.user_id left join psy_user_profile p on u.user_id = p.user_id
@ -113,12 +119,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="avatar != null">avatar, </if> <if test="avatar != null">avatar, </if>
<if test="idCard != null">id_card, </if> <if test="idCard != null">id_card, </if>
<if test="birthday != null">birthday, </if> <if test="birthday != null">birthday, </if>
<if test="education != null">education, </if> <if test="prison != null">prison, </if>
<if test="occupation != null">occupation, </if> <if test="prisonArea != null">prison_area, </if>
<if test="address != null">address, </if> <if test="gender != null">gender, </if>
<if test="emergencyContact != null">emergency_contact, </if> <if test="nation != null">nation, </if>
<if test="emergencyPhone != null">emergency_phone, </if> <if test="educationLevel != null">education_level, </if>
<if test="medicalHistory != null">medical_history, </if> <if test="crimeName != null">crime_name, </if>
<if test="sentenceTerm != null">sentence_term, </if>
<if test="sentenceStartDate != null">sentence_start_date, </if>
<if test="sentenceEndDate != null">sentence_end_date, </if>
<if test="entryDate != null">entry_date, </if>
<if test="infoNumber != null">info_number, </if> <if test="infoNumber != null">info_number, </if>
<if test="createBy != null">create_by, </if> <if test="createBy != null">create_by, </if>
<if test="remark != null">remark, </if> <if test="remark != null">remark, </if>
@ -130,12 +140,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="avatar != null">#{avatar}, </if> <if test="avatar != null">#{avatar}, </if>
<if test="idCard != null">#{idCard}, </if> <if test="idCard != null">#{idCard}, </if>
<if test="birthday != null">#{birthday}, </if> <if test="birthday != null">#{birthday}, </if>
<if test="education != null">#{education}, </if> <if test="prison != null">#{prison}, </if>
<if test="occupation != null">#{occupation}, </if> <if test="prisonArea != null">#{prisonArea}, </if>
<if test="address != null">#{address}, </if> <if test="gender != null">#{gender}, </if>
<if test="emergencyContact != null">#{emergencyContact}, </if> <if test="nation != null">#{nation}, </if>
<if test="emergencyPhone != null">#{emergencyPhone}, </if> <if test="educationLevel != null">#{educationLevel}, </if>
<if test="medicalHistory != null">#{medicalHistory}, </if> <if test="crimeName != null">#{crimeName}, </if>
<if test="sentenceTerm != null">#{sentenceTerm}, </if>
<if test="sentenceStartDate != null">#{sentenceStartDate}, </if>
<if test="sentenceEndDate != null">#{sentenceEndDate}, </if>
<if test="entryDate != null">#{entryDate}, </if>
<if test="infoNumber != null">#{infoNumber}, </if> <if test="infoNumber != null">#{infoNumber}, </if>
<if test="createBy != null">#{createBy}, </if> <if test="createBy != null">#{createBy}, </if>
<if test="remark != null">#{remark}, </if> <if test="remark != null">#{remark}, </if>
@ -151,12 +165,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="avatar != null">avatar = #{avatar}, </if> <if test="avatar != null">avatar = #{avatar}, </if>
<if test="idCard != null">id_card = #{idCard}, </if> <if test="idCard != null">id_card = #{idCard}, </if>
<if test="birthday != null">birthday = #{birthday}, </if> <if test="birthday != null">birthday = #{birthday}, </if>
<if test="education != null">education = #{education}, </if> <if test="prison != null">prison = #{prison}, </if>
<if test="occupation != null">occupation = #{occupation}, </if> <if test="prisonArea != null">prison_area = #{prisonArea}, </if>
<if test="address != null">address = #{address}, </if> <if test="gender != null">gender = #{gender}, </if>
<if test="emergencyContact != null">emergency_contact = #{emergencyContact}, </if> <if test="nation != null">nation = #{nation}, </if>
<if test="emergencyPhone != null">emergency_phone = #{emergencyPhone}, </if> <if test="educationLevel != null">education_level = #{educationLevel}, </if>
<if test="medicalHistory != null">medical_history = #{medicalHistory}, </if> <if test="crimeName != null">crime_name = #{crimeName}, </if>
<if test="sentenceTerm != null">sentence_term = #{sentenceTerm}, </if>
<if test="sentenceStartDate != null">sentence_start_date = #{sentenceStartDate}, </if>
<if test="sentenceEndDate != null">sentence_end_date = #{sentenceEndDate}, </if>
<if test="entryDate != null">entry_date = #{entryDate}, </if>
<if test="infoNumber != null">info_number = #{infoNumber}, </if> <if test="infoNumber != null">info_number = #{infoNumber}, </if>
<if test="updateBy != null">update_by = #{updateBy}, </if> <if test="updateBy != null">update_by = #{updateBy}, </if>
<if test="remark != null">remark = #{remark}, </if> <if test="remark != null">remark = #{remark}, </if>

View File

@ -45,39 +45,97 @@ function buildKeywordAnalysis(reportData, severityMeta) {
} }
export function buildChartOption(reportData) { export function buildChartOption(reportData) {
const chartData = reportData.chartData || {} try {
const score = safeScore(reportData.calculatedResults?.rawScore) const chartData = reportData.chartData || {}
const xAxis = chartData.xAxis || [reportData.testRecord?.projectDate || '当前'] const score = safeScore(reportData.calculatedResults?.rawScore)
const seriesData = chartData.series || [{ name: '总分', value: reportData.calculatedResults?.rawScore || 0 }] const rawScoreValue = reportData.calculatedResults?.rawScore || 0
return {
title: { // 构建X轴数据
text: chartData.title || 'SAS总分趋势', let xAxis = []
left: 'center' if (chartData.xAxis && Array.isArray(chartData.xAxis) && chartData.xAxis.length > 0) {
}, xAxis = chartData.xAxis
tooltip: { trigger: 'axis' }, } else if (reportData.testRecord?.projectDate) {
xAxis: { xAxis = [formatDateLabel(reportData.testRecord.projectDate)]
type: 'category', } else {
data: xAxis xAxis = ['当前']
},
yAxis: { type: 'value' },
series: [
{
name: '总分',
type: 'line',
smooth: true,
areaStyle: { opacity: 0.15 },
data: seriesData.map(item => item.value)
}
],
graphic: {
type: 'text',
left: 'center',
top: '10%',
style: {
text: `当前得分:${score}`,
fontSize: 14
}
} }
// 构建系列数据
let seriesDataValues = []
if (chartData.series && Array.isArray(chartData.series) && chartData.series.length > 0) {
seriesDataValues = chartData.series.map(item => {
const val = item.value !== undefined ? item.value : rawScoreValue
return typeof val === 'number' ? val : parseFloat(val) || 0
})
} else {
seriesDataValues = [typeof rawScoreValue === 'number' ? rawScoreValue : parseFloat(rawScoreValue) || 0]
}
return {
title: {
text: chartData.title || '测评分数趋势',
left: 'center',
top: 10,
textStyle: {
fontSize: 16,
fontWeight: 'normal'
}
},
tooltip: {
trigger: 'axis',
formatter: '{b}: {c}分'
},
grid: {
left: '10%',
right: '10%',
bottom: '15%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
data: xAxis,
axisLine: {
lineStyle: { color: '#999' }
}
},
yAxis: {
type: 'value',
name: '分数',
axisLine: {
lineStyle: { color: '#999' }
}
},
series: [
{
name: '总分',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#409EFF'
},
lineStyle: {
width: 2,
color: '#409EFF'
},
areaStyle: {
opacity: 0.2,
color: '#409EFF'
},
data: seriesDataValues,
label: {
show: true,
position: 'top',
formatter: '{c}分'
}
}
]
}
} catch (error) {
console.error('构建图表配置失败:', error)
throw new Error('图表配置构建失败: ' + error.message)
} }
} }

View File

@ -3,10 +3,8 @@ import { buildChartOption, formatDateLabel } from './DynamicContentService'
class SASReportGenerator { class SASReportGenerator {
async buildHtml(reportData, includeChart = true) { async buildHtml(reportData, includeChart = true) {
// 不再使用图表功能
let chartImage = '' let chartImage = ''
if (includeChart) {
chartImage = await this.renderChartImage(buildChartOption(reportData))
}
const recommendations = (reportData.calculatedResults.recommendations || []).map(item => `<li>${item}</li>`).join('') const recommendations = (reportData.calculatedResults.recommendations || []).map(item => `<li>${item}</li>`).join('')
const keywords = (reportData.keywordAnalysis || reportData.keywords || []).map(item => `<span class="tag">${item}</span>`).join('') const keywords = (reportData.keywordAnalysis || reportData.keywords || []).map(item => `<span class="tag">${item}</span>`).join('')
const printScopes = (reportData.printScopes || []).map(scope => ` const printScopes = (reportData.printScopes || []).map(scope => `
@ -43,7 +41,7 @@ class SASReportGenerator {
<div class="section-title">基本信息</div> <div class="section-title">基本信息</div>
<table> <table>
<tr><th>编码</th><td>${reportData.userInfo.infoNumber || reportData.testRecord.assessmentId || '-'}</td> <tr><th>编码</th><td>${reportData.userInfo.infoNumber || reportData.testRecord.assessmentId || '-'}</td>
<th>样本</th><td>${reportData.userInfo.name || '-'}</td></tr> <th>姓名</th><td>${reportData.userInfo.name || '-'}</td></tr>
<tr><th>测试单位</th><td>${reportData.userInfo.unitName || '-'}</td> <tr><th>测试单位</th><td>${reportData.userInfo.unitName || '-'}</td>
<th>性别</th><td>${reportData.userInfo.gender || '-'}</td></tr> <th>性别</th><td>${reportData.userInfo.gender || '-'}</td></tr>
<tr><th>所属科室/监区</th><td>${reportData.userInfo.prisonAreaName || reportData.userInfo.deptName || '-'}</td> <tr><th>所属科室/监区</th><td>${reportData.userInfo.prisonAreaName || reportData.userInfo.deptName || '-'}</td>
@ -58,7 +56,6 @@ class SASReportGenerator {
<tr><th>原始分数</th><td class="highlight">${reportData.calculatedResults.rawScore}</td></tr> <tr><th>原始分数</th><td class="highlight">${reportData.calculatedResults.rawScore}</td></tr>
<tr><th>功能评级</th><td>${reportData.calculatedResults.functionalRating}</td></tr> <tr><th>功能评级</th><td>${reportData.calculatedResults.functionalRating}</td></tr>
</table> </table>
${chartImage ? `<div class="chart"><img src="${chartImage}" alt="chart" style="max-width: 600px" /></div>` : ''}
</div> </div>
<div class="section"> <div class="section">
@ -106,18 +103,58 @@ class SASReportGenerator {
} }
async renderChartImage(option) { async renderChartImage(option) {
const container = document.createElement('div') let container = null
container.style.width = '640px' let chart = null
container.style.height = '320px' try {
container.style.position = 'fixed' console.log('开始渲染图表,配置:', option)
container.style.left = '-9999px'
document.body.appendChild(container) // 创建容器
const chart = echarts.init(container) container = document.createElement('div')
chart.setOption(option) container.style.width = '640px'
const dataUrl = chart.getDataURL({ pixelRatio: 2, backgroundColor: '#fff' }) container.style.height = '320px'
chart.dispose() container.style.position = 'fixed'
document.body.removeChild(container) container.style.left = '-9999px'
return dataUrl container.style.top = '0'
document.body.appendChild(container)
// 初始化echarts
chart = echarts.init(container)
if (!chart) {
throw new Error('echarts初始化失败')
}
// 设置图表选项
chart.setOption(option)
// 等待渲染完成
await new Promise(resolve => setTimeout(resolve, 100))
// 获取图表图像
const dataUrl = chart.getDataURL({
type: 'png',
pixelRatio: 2,
backgroundColor: '#fff'
})
console.log('图表渲染成功,图像长度:', dataUrl?.length || 0)
return dataUrl
} catch (error) {
console.error('图表渲染失败:', error)
throw error
} finally {
// 清理资源
try {
if (chart) {
chart.dispose()
}
if (container && container.parentNode) {
document.body.removeChild(container)
}
} catch (cleanupError) {
console.warn('清理图表资源时出错:', cleanupError)
}
}
} }
resolveReportTitle(reportData) { resolveReportTitle(reportData) {

View File

@ -16,8 +16,8 @@ axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
const service = axios.create({ const service = axios.create({
// axios中请求配置有baseURL选项表示请求URL公共部分 // axios中请求配置有baseURL选项表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API, baseURL: process.env.VUE_APP_BASE_API,
// 超时 // 超时增加到30秒以支持连续测评操作
timeout: 10000 timeout: 30000
}) })
// request拦截器 // request拦截器

View File

@ -95,6 +95,7 @@ export default {
scaleList: [], scaleList: [],
profileList: [], profileList: [],
pausedList: [], pausedList: [],
targetUserId: null, // IDURL
form: { form: {
scaleId: undefined, scaleId: undefined,
profileId: undefined profileId: undefined
@ -110,11 +111,23 @@ export default {
}; };
}, },
created() { created() {
// URLscaleId // URLscaleIdprofileId/userId
const scaleId = this.$route.query.scaleId; const scaleId = this.$route.query.scaleId;
const profileId = this.$route.query.profileId;
const userId = this.$route.query.userId;
if (scaleId) { if (scaleId) {
this.form.scaleId = parseInt(scaleId); this.form.scaleId = parseInt(scaleId);
} }
if (profileId) {
this.form.profileId = parseInt(profileId);
}
// userId
if (userId) {
this.targetUserId = parseInt(userId);
}
this.loadScales(); this.loadScales();
this.loadProfiles(); this.loadProfiles();
this.loadPaused(); this.loadPaused();
@ -140,9 +153,17 @@ export default {
if (selectedScale && selectedScale.sourceType === 'questionnaire') { if (selectedScale && selectedScale.sourceType === 'questionnaire') {
// //
const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId); const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId);
const queryParams = { questionnaireId: questionnaireId };
// URLuserId
const urlUserId = this.$route.query.userId;
if (urlUserId) {
queryParams.userId = urlUserId;
}
this.$router.replace({ this.$router.replace({
path: '/psychology/questionnaire/start', path: '/psychology/questionnaire/start',
query: { questionnaireId: questionnaireId } query: queryParams
}); });
} }
} }
@ -164,9 +185,17 @@ export default {
if (selectedScale && selectedScale.sourceType === 'questionnaire') { if (selectedScale && selectedScale.sourceType === 'questionnaire') {
// //
const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId); const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId);
const queryParams = { questionnaireId: questionnaireId };
// URLuserId
const urlUserId = this.$route.query.userId;
if (urlUserId) {
queryParams.userId = urlUserId;
}
this.$router.replace({ this.$router.replace({
path: '/psychology/questionnaire/start', path: '/psychology/questionnaire/start',
query: { questionnaireId: questionnaireId } query: queryParams
}); });
} }
} }
@ -197,9 +226,17 @@ export default {
if (selectedScale && selectedScale.sourceType === 'questionnaire') { if (selectedScale && selectedScale.sourceType === 'questionnaire') {
// //
const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId); const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId);
const queryParams = { questionnaireId: questionnaireId };
// URLuserId
const urlUserId = this.$route.query.userId;
if (urlUserId) {
queryParams.userId = urlUserId;
}
this.$router.replace({ this.$router.replace({
path: '/psychology/questionnaire/start', path: '/psychology/questionnaire/start',
query: { questionnaireId: questionnaireId } query: queryParams
}); });
} }
} }
@ -269,13 +306,29 @@ export default {
return; return;
} }
// //
if (selectedScale.sourceType === 'questionnaire') { if (selectedScale.sourceType === 'questionnaire') {
const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId); const questionnaireId = selectedScale.originalId || Math.abs(selectedScale.scaleId);
//
//
const queryParams = { questionnaireId: questionnaireId };
// 使targetUserIdURL使
if (this.targetUserId) {
queryParams.userId = this.targetUserId;
console.log('使用URL参数的userId:', this.targetUserId);
} else if (this.form.profileId) {
const selectedProfile = this.profileList.find(p => p.profileId === this.form.profileId);
if (selectedProfile && selectedProfile.userId) {
queryParams.userId = selectedProfile.userId;
console.log('管理员代测传递userId:', selectedProfile.userId);
}
}
//
this.$router.push({ this.$router.push({
path: '/psychology/questionnaire/start', path: '/psychology/questionnaire/start',
query: { questionnaireId: questionnaireId } query: queryParams
}); });
return; return;
} }

View File

@ -122,10 +122,25 @@
<span>{{ parseTime(scope.row.birthday, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.birthday, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="学历" align="center" prop="education" width="100" /> <el-table-column label="监狱" align="center" prop="prison" width="120" />
<el-table-column label="职业" align="center" prop="occupation" width="120" /> <el-table-column label="监区" align="center" prop="prisonArea" width="100" />
<el-table-column label="紧急联系人" align="center" prop="emergencyContact" width="120" /> <el-table-column label="性别" align="center" prop="gender" width="80">
<el-table-column label="紧急电话" align="center" prop="emergencyPhone" width="130" /> <template slot-scope="scope">
<span v-if="scope.row.gender === '0'"></span>
<span v-else-if="scope.row.gender === '1'"></span>
<span v-else-if="scope.row.gender === '2'">未知</span>
<span v-else>{{ scope.row.gender }}</span>
</template>
</el-table-column>
<el-table-column label="民族" align="center" prop="nation" width="80" />
<el-table-column label="文化程度" align="center" prop="educationLevel" width="100" />
<el-table-column label="罪名" align="center" prop="crimeName" width="120" />
<el-table-column label="刑期" align="center" prop="sentenceTerm" width="100" />
<el-table-column label="入监时间" align="center" prop="entryDate" width="120">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.entryDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
@ -226,34 +241,99 @@
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="学历" prop="education"> <el-form-item label="监狱" prop="prison">
<el-input v-model="form.education" placeholder="请输入学历" /> <el-input v-model="form.prison" placeholder="请输入监狱名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="职业" prop="occupation"> <el-form-item label="监区" prop="prisonArea">
<el-input v-model="form.occupation" placeholder="请输入职业" /> <el-input v-model="form.prisonArea" placeholder="请输入监区" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="性别" prop="gender">
<el-select v-model="form.gender" placeholder="请选择性别">
<el-option label="男" value="0" />
<el-option label="女" value="1" />
<el-option label="未知" value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="民族" prop="nation">
<el-input v-model="form.nation" placeholder="请输入民族" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="文化程度" prop="educationLevel">
<el-select v-model="form.educationLevel" placeholder="请选择文化程度">
<el-option label="小学" value="小学" />
<el-option label="初中" value="初中" />
<el-option label="高中" value="高中" />
<el-option label="中专" value="中专" />
<el-option label="大专" value="大专" />
<el-option label="本科" value="本科" />
<el-option label="硕士" value="硕士" />
<el-option label="博士" value="博士" />
<el-option label="其他" value="其他" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="罪名" prop="crimeName">
<el-input v-model="form.crimeName" placeholder="请输入罪名" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="刑期" prop="sentenceTerm">
<el-input v-model="form.sentenceTerm" placeholder="请输入刑期3年6个月" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="刑期起日" prop="sentenceStartDate">
<el-date-picker
v-model="form.sentenceStartDate"
type="date"
placeholder="选择刑期起日"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="刑期止日" prop="sentenceEndDate">
<el-date-picker
v-model="form.sentenceEndDate"
type="date"
placeholder="选择刑期止日"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入监时间" prop="entryDate">
<el-date-picker
v-model="form.entryDate"
type="date"
placeholder="选择入监时间"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="头像"> <el-form-item label="头像">
<el-input v-model="form.avatar" placeholder="请输入头像URL" /> <el-input v-model="form.avatar" placeholder="请输入头像URL" />
</el-form-item> </el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="form.address" type="textarea" :rows="2" placeholder="请输入地址" />
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="紧急联系人" prop="emergencyContact">
<el-input v-model="form.emergencyContact" placeholder="请输入紧急联系人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="紧急联系电话" prop="emergencyPhone">
<el-input v-model="form.emergencyPhone" placeholder="请输入紧急联系电话" maxlength="11" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注"> <el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" /> <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
</el-form-item> </el-form-item>
@ -542,11 +622,16 @@ export default {
userName: undefined, userName: undefined,
phone: undefined, phone: undefined,
birthday: undefined, birthday: undefined,
education: undefined, prison: undefined,
occupation: undefined, prisonArea: undefined,
address: undefined, gender: undefined,
emergencyContact: undefined, nation: undefined,
emergencyPhone: undefined, educationLevel: undefined,
crimeName: undefined,
sentenceTerm: undefined,
sentenceStartDate: undefined,
sentenceEndDate: undefined,
entryDate: undefined,
remark: undefined remark: undefined
} }
this.resetForm("form") this.resetForm("form")

View File

@ -128,14 +128,6 @@
满分{{ scoreForm.itemScore || 0 }} 满分{{ scoreForm.itemScore || 0 }}
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="评语">
<el-input
v-model="scoreForm.comment"
type="textarea"
:rows="4"
placeholder="请输入评语(可选)"
/>
</el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitScoreForm"> </el-button> <el-button type="primary" @click="submitScoreForm"> </el-button>
@ -164,17 +156,6 @@
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="评语" min-width="200">
<template slot-scope="scope">
<el-input
v-model="scope.row.comment"
type="textarea"
:rows="2"
placeholder="评语(可选)"
size="small"
/>
</template>
</el-table-column>
</el-table> </el-table>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitBatchScore"> </el-button> <el-button type="primary" @click="submitBatchScore"> </el-button>
@ -273,8 +254,7 @@ export default {
itemContent: row.itemContent, itemContent: row.itemContent,
itemScore: row.itemScore || 0, itemScore: row.itemScore || 0,
answerText: row.answerText || '', answerText: row.answerText || '',
score: row.answerScore || 0, score: row.answerScore || 0
comment: ''
}; };
this.scoreOpen = true; this.scoreOpen = true;
}, },
@ -284,8 +264,7 @@ export default {
if (valid) { if (valid) {
const data = { const data = {
detailId: this.scoreForm.detailId, detailId: this.scoreForm.detailId,
score: this.scoreForm.score, score: this.scoreForm.score
comment: this.scoreForm.comment
}; };
submitScoring(data).then(response => { submitScoring(data).then(response => {
@ -315,8 +294,7 @@ export default {
itemContent: '', itemContent: '',
itemScore: 0, itemScore: 0,
answerText: '', answerText: '',
score: 0, score: 0
comment: ''
}; };
if (this.$refs["scoreForm"]) { if (this.$refs["scoreForm"]) {
this.$refs["scoreForm"].resetFields(); this.$refs["scoreForm"].resetFields();
@ -329,11 +307,10 @@ export default {
return; return;
} }
// scorecomment // score
this.selectedRows = this.selectedRows.map(row => ({ this.selectedRows = this.selectedRows.map(row => ({
...row, ...row,
score: row.answerScore || 0, score: row.answerScore || 0
comment: ''
})); }));
this.batchScoreOpen = true; this.batchScoreOpen = true;
@ -342,8 +319,7 @@ export default {
submitBatchScore() { submitBatchScore() {
const scoringList = this.selectedRows.map(row => ({ const scoringList = this.selectedRows.map(row => ({
detailId: row.detailId, detailId: row.detailId,
score: row.score || 0, score: row.score || 0
comment: row.comment || ''
})); }));
batchSubmitScoring(scoringList).then(response => { batchSubmitScoring(scoringList).then(response => {

View File

@ -43,6 +43,7 @@ export default {
return { return {
loading: false, loading: false,
questionnaireList: [], questionnaireList: [],
selectedUserId: null, // ID
form: { form: {
questionnaireId: undefined, questionnaireId: undefined,
respondentName: undefined respondentName: undefined
@ -55,10 +56,16 @@ export default {
}; };
}, },
created() { created() {
// URLquestionnaireId // URLquestionnaireIduserId
const questionnaireId = this.$route.query.questionnaireId; const questionnaireId = this.$route.query.questionnaireId;
const userId = this.$route.query.userId;
if (questionnaireId) { if (questionnaireId) {
this.form.questionnaireId = parseInt(questionnaireId); this.form.questionnaireId = parseInt(questionnaireId);
// userId
if (userId) {
this.selectedUserId = parseInt(userId);
}
// //
this.$nextTick(() => { this.$nextTick(() => {
this.startAnswerDirectly(); this.startAnswerDirectly();
@ -87,6 +94,11 @@ export default {
respondentName: this.form.respondentName || null respondentName: this.form.respondentName || null
}; };
// userId
if (this.selectedUserId) {
data.userId = this.selectedUserId;
}
startQuestionnaireAnswer(data).then(response => { startQuestionnaireAnswer(data).then(response => {
if (response.code === 200) { if (response.code === 200) {
this.$modal.msgSuccess("答题已开始"); this.$modal.msgSuccess("答题已开始");
@ -119,6 +131,11 @@ export default {
respondentName: null // respondentName: null //
}; };
// userId
if (this.selectedUserId) {
data.userId = this.selectedUserId;
}
startQuestionnaireAnswer(data).then(response => { startQuestionnaireAnswer(data).then(response => {
if (response.code === 200) { if (response.code === 200) {
this.$modal.msgSuccess("答题已开始"); this.$modal.msgSuccess("答题已开始");

View File

@ -44,8 +44,8 @@
plain plain
icon="el-icon-printer" icon="el-icon-printer"
size="mini" size="mini"
:disabled="!isAssessmentSelection" :disabled="multiple"
@click="openSasDialog" @click="openExportDialog"
v-hasPermi="['psychology:report:export']" v-hasPermi="['psychology:report:export']"
>导出报告</el-button> >导出报告</el-button>
</el-col> </el-col>
@ -72,7 +72,11 @@
<el-tag v-else type="primary">量表</el-tag> <el-tag v-else type="primary">量表</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="来源ID" align="center" prop="sourceId" width="100" /> <el-table-column label="信息编号" align="center" prop="infoNumber" width="120">
<template slot-scope="scope">
<span>{{ scope.row.infoNumber || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="报告标题" align="center" prop="reportTitle" :show-overflow-tooltip="true" /> <el-table-column label="报告标题" align="center" prop="reportTitle" :show-overflow-tooltip="true" />
<el-table-column label="报告类型" align="center" prop="reportType" width="120"> <el-table-column label="报告类型" align="center" prop="reportType" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
@ -160,7 +164,7 @@
</el-dialog> </el-dialog>
<!-- SAS 报告导出设置 --> <!-- SAS 报告导出设置 -->
<el-dialog title="SAS报告导出" :visible.sync="sasExportDialog" width="420px" append-to-body @close="resetSasDialog"> <el-dialog title="报告导出" :visible.sync="sasExportDialog" width="420px" append-to-body @close="resetSasDialog">
<el-form :model="sasExportForm" label-width="90px"> <el-form :model="sasExportForm" label-width="90px">
<el-form-item label="导出格式"> <el-form-item label="导出格式">
<el-radio-group v-model="sasExportForm.format"> <el-radio-group v-model="sasExportForm.format">
@ -168,9 +172,6 @@
<el-radio label="print">打印/PDF</el-radio> <el-radio label="print">打印/PDF</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="包含图表">
<el-switch v-model="sasExportForm.includeChart"></el-switch>
</el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click="sasExportDialog = false"> </el-button> <el-button @click="sasExportDialog = false"> </el-button>
@ -229,20 +230,13 @@ export default {
}, },
sasExportDialog: false, sasExportDialog: false,
sasExportForm: { sasExportForm: {
format: "word", format: "word"
includeChart: true
}, },
sasExportLoading: false, sasExportLoading: false,
sasTarget: null sasTarget: null
}; };
}, },
computed: { computed: {
isAssessmentSelection() {
const row = this.getActiveRow();
if (!row) return false;
if (!row.sourceType) return true;
return row.sourceType === 'assessment';
}
}, },
created() { created() {
this.getList(); this.getList();
@ -403,20 +397,36 @@ export default {
} }
return null; return null;
}, },
async openSasDialog(row) { async openExportDialog() {
const target = row || this.getActiveRow(); //
const target = this.getActiveRow();
if (!target) { if (!target) {
this.$message.warning("请先选择一条量表报告"); this.$message.warning("请先选择一条报告");
return; return;
} }
if (target.sourceType && target.sourceType !== 'assessment') {
this.$message.warning("仅支持量表测评报告生成模板"); console.log('选中的报告对象:', target);
console.log('报告类型:', target.sourceType);
// sourceType
if (!target.sourceType) {
this.$modal.msgError("报告缺少类型信息,请刷新页面后重试");
return; return;
} }
//
if (target.sourceType === 'questionnaire') {
this.sasTarget = { ...target, sourceType: 'questionnaire' };
this.sasExportForm = { format: "word" };
this.sasExportDialog = true;
return;
}
// 使SAS
try { try {
const resolved = await this.ensureAssessmentInfo(target); const resolved = await this.ensureAssessmentInfo(target);
this.sasTarget = resolved; this.sasTarget = { ...resolved, sourceType: 'assessment' };
this.sasExportForm = { format: "word", includeChart: true }; this.sasExportForm = { format: "word" };
this.sasExportDialog = true; this.sasExportDialog = true;
} catch (error) { } catch (error) {
this.$modal.msgError(error.message || "无法定位测评ID"); this.$modal.msgError(error.message || "无法定位测评ID");
@ -445,35 +455,97 @@ export default {
this.sasExportDialog = false; this.sasExportDialog = false;
this.sasExportLoading = false; this.sasExportLoading = false;
this.sasTarget = null; this.sasTarget = null;
this.sasExportForm = { format: "word", includeChart: true }; this.sasExportForm = { format: "word" };
}, },
async confirmSasExport() { async confirmSasExport() {
if (!this.sasTarget) { if (!this.sasTarget) {
this.$message.warning("未选择报告"); this.$message.warning("未选择报告");
return; return;
} }
const assessmentId = this.sasTarget.sourceId || this.sasTarget.assessmentId;
if (!assessmentId) {
this.$modal.msgError("无法定位测评ID");
return;
}
this.sasExportLoading = true; this.sasExportLoading = true;
try { try {
const reportData = await loadSasReportData(assessmentId); //
if (this.sasExportForm.format === 'word') { if (this.sasTarget.sourceType === 'questionnaire') {
await SASReportGenerator.exportWord(reportData, this.sasExportForm.includeChart); //
await this.exportQuestionnaireReport();
} else { } else {
await SASReportGenerator.print(reportData, this.sasExportForm.includeChart); //
await this.exportAssessmentReport();
} }
this.$modal.msgSuccess("SAS报告已生成"); this.$modal.msgSuccess("报告已生成");
this.resetSasDialog(); this.resetSasDialog();
} catch (error) { } catch (error) {
console.error("生成SAS报告失败:", error); console.error("生成报告失败:", error);
this.$modal.msgError("生成失败:" + (error.message || "未知错误")); this.$modal.msgError("生成失败:" + (error.message || "未知错误"));
} finally { } finally {
this.sasExportLoading = false; this.sasExportLoading = false;
} }
}, },
async exportAssessmentReport() {
const assessmentId = this.sasTarget.sourceId || this.sasTarget.assessmentId;
if (!assessmentId) {
throw new Error("无法定位测评ID");
}
const reportData = await loadSasReportData(assessmentId);
if (this.sasExportForm.format === 'word') {
await SASReportGenerator.exportWord(reportData, false);
} else {
await SASReportGenerator.print(reportData, false);
}
},
async exportQuestionnaireReport() {
// HTML
const response = await getReport(this.sasTarget.reportId, 'questionnaire');
if (!response || !response.data) {
throw new Error("获取报告内容失败");
}
const report = response.data;
console.log('问卷报告数据:', report);
// 使
const reportHtml = `
<html>
<head>
<meta charset="UTF-8" />
<title>${report.reportTitle || '问卷报告'}</title>
<style>
body { font-family: 'Microsoft Yahei', sans-serif; padding: 32px; color: #303133; }
h1, h2 { text-align: center; margin: 16px 0; }
.section { margin-top: 24px; }
.report-info { margin: 5px 0; color: #606266; }
table.score-table { width: 100%; border-collapse: collapse; margin: 20px 0; }
table.score-table td, table.score-table th { border: 1px solid #ddd; padding: 10px; font-size: 14px; }
table.score-table th { background-color: #f5f7fa; font-weight: bold; }
.content { margin-top: 24px; line-height: 1.8; }
</style>
</head>
<body>
${report.reportContent || '暂无报告内容'}
</body>
</html>
`;
if (this.sasExportForm.format === 'word') {
// Word
const blob = new Blob(['\ufeff', reportHtml], { type: 'application/msword' });
const filename = `${report.reportTitle || '问卷报告'}_${Date.now()}.doc`;
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
//
const printWindow = window.open('', '_blank');
printWindow.document.write(reportHtml);
printWindow.document.close();
printWindow.focus();
printWindow.print();
}
},
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
let reportIds; let reportIds;