2025年11月12日
This commit is contained in:
parent
6805ed2981
commit
60f2ab49c8
|
|
@ -67,3 +67,30 @@ export function getQuestionnaireRankList(questionnaireId) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询待评分的主观题列表
|
||||||
|
export function getPendingScoringList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/psychology/questionnaire/answer/scoring/pending',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交主观题评分
|
||||||
|
export function submitScoring(data) {
|
||||||
|
return request({
|
||||||
|
url: '/psychology/questionnaire/answer/scoring/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量提交主观题评分
|
||||||
|
export function batchSubmitScoring(data) {
|
||||||
|
return request({
|
||||||
|
url: '/psychology/questionnaire/answer/scoring/batch',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,14 +44,41 @@ export function updateReport(data) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除报告
|
// 修改报告(支持传递sourceType)
|
||||||
export function delReport(reportIds) {
|
export function updateReportWithType(reportId, sourceType, data) {
|
||||||
|
const updateData = {
|
||||||
|
reportId: reportId,
|
||||||
|
sourceType: sourceType,
|
||||||
|
...data
|
||||||
|
}
|
||||||
return request({
|
return request({
|
||||||
url: '/psychology/report/' + reportIds,
|
url: '/psychology/report',
|
||||||
|
method: 'put',
|
||||||
|
data: updateData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除报告(支持传递sourceType)
|
||||||
|
export function delReport(reportIds, sourceType) {
|
||||||
|
let url = '/psychology/report/' + reportIds;
|
||||||
|
if (sourceType) {
|
||||||
|
url += '?sourceType=' + sourceType;
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: url,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量删除报告(支持传递sourceType映射)
|
||||||
|
export function delReports(reportData) {
|
||||||
|
return request({
|
||||||
|
url: '/psychology/report/batch',
|
||||||
|
method: 'delete',
|
||||||
|
data: reportData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 生成报告
|
// 生成报告
|
||||||
export function generateReport(assessmentId) {
|
export function generateReport(assessmentId) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,17 @@ export const dynamicRoutes = [
|
||||||
title: '问卷题目管理',
|
title: '问卷题目管理',
|
||||||
roles: ['admin']
|
roles: ['admin']
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// 主观题评分
|
||||||
|
{
|
||||||
|
path: 'questionnaire/scoring',
|
||||||
|
name: 'QuestionnaireScoring',
|
||||||
|
component: () => import('@/views/psychology/questionnaire/scoring'),
|
||||||
|
meta: {
|
||||||
|
title: '主观题评分',
|
||||||
|
icon: 'edit',
|
||||||
|
roles: ['admin']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -298,10 +298,12 @@ export default {
|
||||||
this.getList();
|
this.getList();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 加载量表列表 */
|
/** 加载量表列表(只显示量表,不包含问卷) */
|
||||||
loadScaleList() {
|
loadScaleList() {
|
||||||
listScale({ status: '0', pageNum: 1, pageSize: 1000 }).then(response => {
|
listScale({ status: '0', pageNum: 1, pageSize: 1000, includeQuestionnaire: false }).then(response => {
|
||||||
this.scaleList = response.rows || [];
|
// 再次过滤,确保只显示量表
|
||||||
|
this.scaleList = (response.rows || [])
|
||||||
|
.filter(scale => !scale.sourceType || scale.sourceType === 'scale');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载因子列表(用于搜索) */
|
/** 加载因子列表(用于搜索) */
|
||||||
|
|
|
||||||
|
|
@ -209,10 +209,12 @@ export default {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载量表列表 */
|
/** 加载量表列表(只显示量表,不包含问卷) */
|
||||||
loadScales() {
|
loadScales() {
|
||||||
listScale({ status: '0' }).then(response => {
|
listScale({ status: '0', includeQuestionnaire: false }).then(response => {
|
||||||
this.scaleList = response.rows || [];
|
// 过滤掉问卷,只保留量表
|
||||||
|
this.scaleList = (response.rows || [])
|
||||||
|
.filter(scale => !scale.sourceType || scale.sourceType === 'scale');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载用户列表 */
|
/** 加载用户列表 */
|
||||||
|
|
|
||||||
|
|
@ -77,14 +77,17 @@ export default {
|
||||||
this.userName = response.data.userName;
|
this.userName = response.data.userName;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载量表列表 */
|
/** 加载量表列表(只显示量表,不包含问卷) */
|
||||||
loadScales() {
|
loadScales() {
|
||||||
listScale({ status: '0' }).then(response => {
|
listScale({ status: '0', includeQuestionnaire: false }).then(response => {
|
||||||
this.scaleList = (response.rows || []).map(scale => ({
|
// 过滤掉问卷,只保留量表
|
||||||
key: scale.scaleId,
|
this.scaleList = (response.rows || [])
|
||||||
label: scale.scaleName,
|
.filter(scale => !scale.sourceType || scale.sourceType === 'scale')
|
||||||
itemCount: scale.itemCount || 0
|
.map(scale => ({
|
||||||
}));
|
key: scale.scaleId,
|
||||||
|
label: scale.scaleName,
|
||||||
|
itemCount: scale.itemCount || 0
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载用户已有权限的量表 */
|
/** 加载用户已有权限的量表 */
|
||||||
|
|
|
||||||
|
|
@ -425,10 +425,12 @@ export default {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载量表列表 */
|
/** 加载量表列表(只显示量表,不包含问卷) */
|
||||||
loadScales() {
|
loadScales() {
|
||||||
listScale({ status: '0', pageNum: 1, pageSize: 1000 }).then(response => {
|
listScale({ status: '0', pageNum: 1, pageSize: 1000, includeQuestionnaire: false }).then(response => {
|
||||||
this.scaleList = response.rows || [];
|
// 再次过滤,确保只显示量表
|
||||||
|
this.scaleList = (response.rows || [])
|
||||||
|
.filter(scale => !scale.sourceType || scale.sourceType === 'scale');
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.scaleList = [];
|
this.scaleList = [];
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@
|
||||||
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="280">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="360">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
|
|
@ -120,6 +120,13 @@
|
||||||
@click="handleManageItems(scope.row)"
|
@click="handleManageItems(scope.row)"
|
||||||
v-hasPermi="['psychology:questionnaire:query']"
|
v-hasPermi="['psychology:questionnaire:query']"
|
||||||
>题目管理</el-button>
|
>题目管理</el-button>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-trophy"
|
||||||
|
@click="handleViewRank(scope.row)"
|
||||||
|
v-hasPermi="['psychology:questionnaire:query']"
|
||||||
|
>查看排名</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -232,11 +239,51 @@
|
||||||
<el-button @click="cancel">取 消</el-button>
|
<el-button @click="cancel">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 查看排名对话框 -->
|
||||||
|
<el-dialog title="问卷排名" :visible.sync="rankOpen" width="800px" append-to-body>
|
||||||
|
<div style="margin-bottom: 15px;">
|
||||||
|
<span style="font-size: 16px; font-weight: bold;">问卷名称:{{ currentQuestionnaireName }}</span>
|
||||||
|
</div>
|
||||||
|
<el-table v-loading="rankLoading" :data="rankList" border style="width: 100%">
|
||||||
|
<el-table-column type="index" label="排名" width="100" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag v-if="scope.$index + 1 === 1" type="danger" size="medium">第1名</el-tag>
|
||||||
|
<el-tag v-else-if="scope.$index + 1 === 2" type="warning" size="medium">第2名</el-tag>
|
||||||
|
<el-tag v-else-if="scope.$index + 1 === 3" type="success" size="medium">第3名</el-tag>
|
||||||
|
<span v-else style="font-size: 14px;">第{{ scope.$index + 1 }}名</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="respondentName" label="答题人" width="150" />
|
||||||
|
<el-table-column prop="totalScore" label="总分" width="120" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span style="font-weight: bold; color: #409EFF;">{{ scope.row.totalScore || 0 }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="rank" label="排名" width="100" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag v-if="scope.row.rank === 1" type="danger">第1名</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.rank === 2" type="warning">第2名</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.rank === 3" type="success">第3名</el-tag>
|
||||||
|
<span v-else>第{{ scope.row.rank }}名</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="submitTime" label="提交时间" width="180" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ parseTime(scope.row.submitTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="rankOpen = false">关 闭</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listQuestionnaire, getQuestionnaire, delQuestionnaire, addQuestionnaire, updateQuestionnaire } from "@/api/psychology/questionnaire"
|
import { listQuestionnaire, getQuestionnaire, delQuestionnaire, addQuestionnaire, updateQuestionnaire } from "@/api/psychology/questionnaire"
|
||||||
|
import { getQuestionnaireRankList } from "@/api/psychology/questionnaireAnswer"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PsyQuestionnaire",
|
name: "PsyQuestionnaire",
|
||||||
|
|
@ -272,6 +319,11 @@ export default {
|
||||||
},
|
},
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {},
|
form: {},
|
||||||
|
// 排名相关
|
||||||
|
rankOpen: false,
|
||||||
|
rankLoading: false,
|
||||||
|
rankList: [],
|
||||||
|
currentQuestionnaireName: "",
|
||||||
// 表单校验
|
// 表单校验
|
||||||
rules: {
|
rules: {
|
||||||
questionnaireCode: [
|
questionnaireCode: [
|
||||||
|
|
@ -393,6 +445,25 @@ export default {
|
||||||
this.getList()
|
this.getList()
|
||||||
this.$modal.msgSuccess("删除成功")
|
this.$modal.msgSuccess("删除成功")
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
/** 查看排名 */
|
||||||
|
handleViewRank(row) {
|
||||||
|
this.currentQuestionnaireName = row.questionnaireName || "";
|
||||||
|
this.rankOpen = true;
|
||||||
|
this.rankList = [];
|
||||||
|
this.rankLoading = true;
|
||||||
|
|
||||||
|
getQuestionnaireRankList(row.questionnaireId).then(response => {
|
||||||
|
this.rankList = response.data || [];
|
||||||
|
this.rankLoading = false;
|
||||||
|
if (this.rankList.length === 0) {
|
||||||
|
this.$modal.msgWarning("暂无排名数据");
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
this.rankLoading = false;
|
||||||
|
console.error('加载排名失败:', error);
|
||||||
|
this.$modal.msgError("加载排名失败");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
371
ruoyi-ui/src/views/psychology/questionnaire/scoring.vue
Normal file
371
ruoyi-ui/src/views/psychology/questionnaire/scoring.vue
Normal file
|
|
@ -0,0 +1,371 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
|
||||||
|
<el-form-item label="问卷名称" prop="questionnaireName">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.questionnaireName"
|
||||||
|
placeholder="请输入问卷名称"
|
||||||
|
clearable
|
||||||
|
@keyup.enter.native="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="答题人" prop="respondentName">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.respondentName"
|
||||||
|
placeholder="请输入答题人姓名"
|
||||||
|
clearable
|
||||||
|
@keyup.enter.native="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
icon="el-icon-check"
|
||||||
|
size="mini"
|
||||||
|
:disabled="multiple"
|
||||||
|
@click="handleBatchScore"
|
||||||
|
v-hasPermi="['psychology:questionnaire:score']"
|
||||||
|
>批量评分</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="scoringList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="序号" align="center" prop="detailId" width="80" />
|
||||||
|
<el-table-column label="问卷名称" align="center" prop="questionnaireName" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="答题人" align="center" prop="respondentName" width="120" />
|
||||||
|
<el-table-column label="题目序号" align="center" prop="itemNumber" width="100" />
|
||||||
|
<el-table-column label="题目类型" align="center" prop="itemType" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag v-if="scope.row.itemType === 'text'" type="info">简答题</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.itemType === 'textarea'" type="warning">问答题</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.itemType === 'essay'" type="danger">作文题</el-tag>
|
||||||
|
<span v-else>{{ scope.row.itemType }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="题目内容" align="left" prop="itemContent" :show-overflow-tooltip="true" min-width="200" />
|
||||||
|
<el-table-column label="题目分值" align="center" prop="itemScore" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.itemScore || 0 }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="答案内容" align="left" prop="answerText" :show-overflow-tooltip="true" min-width="200" />
|
||||||
|
<el-table-column label="当前得分" align="center" prop="answerScore" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.answerScore || 0 }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="提交时间" align="center" prop="submitTime" width="180">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ parseTime(scope.row.submitTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-edit"
|
||||||
|
@click="handleScore(scope.row)"
|
||||||
|
v-hasPermi="['psychology:questionnaire:score']"
|
||||||
|
>评分</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-show="total>0"
|
||||||
|
:total="total"
|
||||||
|
:page.sync="queryParams.pageNum"
|
||||||
|
:limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 评分对话框 -->
|
||||||
|
<el-dialog title="主观题评分" :visible.sync="scoreOpen" width="800px" append-to-body>
|
||||||
|
<el-form ref="scoreForm" :model="scoreForm" :rules="scoreRules" label-width="120px">
|
||||||
|
<el-form-item label="问卷名称">
|
||||||
|
<el-input v-model="scoreForm.questionnaireName" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="答题人">
|
||||||
|
<el-input v-model="scoreForm.respondentName" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="题目序号">
|
||||||
|
<el-input v-model="scoreForm.itemNumber" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="题目类型">
|
||||||
|
<el-input v-model="scoreForm.itemTypeName" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="题目内容">
|
||||||
|
<el-input v-model="scoreForm.itemContent" type="textarea" :rows="3" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="题目分值">
|
||||||
|
<el-input v-model="scoreForm.itemScore" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="答案内容">
|
||||||
|
<el-input v-model="scoreForm.answerText" type="textarea" :rows="6" :disabled="true" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="得分" prop="score">
|
||||||
|
<el-input-number
|
||||||
|
v-model="scoreForm.score"
|
||||||
|
:min="0"
|
||||||
|
:max="scoreForm.itemScore || 100"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.5"
|
||||||
|
placeholder="请输入得分"
|
||||||
|
style="width: 100%;"
|
||||||
|
/>
|
||||||
|
<div style="margin-top: 5px; color: #909399; font-size: 12px;">
|
||||||
|
满分:{{ scoreForm.itemScore || 0 }} 分
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="评语">
|
||||||
|
<el-input
|
||||||
|
v-model="scoreForm.comment"
|
||||||
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
placeholder="请输入评语(可选)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitScoreForm">确 定</el-button>
|
||||||
|
<el-button @click="cancelScore">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 批量评分对话框 -->
|
||||||
|
<el-dialog title="批量评分" :visible.sync="batchScoreOpen" width="900px" append-to-body>
|
||||||
|
<el-table :data="selectedRows" border max-height="400">
|
||||||
|
<el-table-column label="序号" align="center" width="60" type="index" />
|
||||||
|
<el-table-column label="问卷名称" prop="questionnaireName" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="答题人" prop="respondentName" width="100" />
|
||||||
|
<el-table-column label="题目序号" prop="itemNumber" width="80" />
|
||||||
|
<el-table-column label="题目分值" prop="itemScore" width="80" />
|
||||||
|
<el-table-column label="得分" width="150">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-input-number
|
||||||
|
v-model="scope.row.score"
|
||||||
|
:min="0"
|
||||||
|
:max="scope.row.itemScore || 100"
|
||||||
|
:precision="2"
|
||||||
|
:step="0.5"
|
||||||
|
size="small"
|
||||||
|
style="width: 100%;"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</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>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitBatchScore">确 定</el-button>
|
||||||
|
<el-button @click="cancelBatchScore">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getPendingScoringList, submitScoring, batchSubmitScoring } from "@/api/psychology/questionnaireAnswer";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "QuestionnaireScoring",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 遮罩层
|
||||||
|
loading: true,
|
||||||
|
// 选中数组
|
||||||
|
ids: [],
|
||||||
|
// 非单个禁用
|
||||||
|
single: true,
|
||||||
|
// 非多个禁用
|
||||||
|
multiple: true,
|
||||||
|
// 显示搜索条件
|
||||||
|
showSearch: true,
|
||||||
|
// 总条数
|
||||||
|
total: 0,
|
||||||
|
// 待评分列表数据
|
||||||
|
scoringList: [],
|
||||||
|
// 查询参数
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
questionnaireName: undefined,
|
||||||
|
respondentName: undefined
|
||||||
|
},
|
||||||
|
// 评分对话框
|
||||||
|
scoreOpen: false,
|
||||||
|
scoreForm: {},
|
||||||
|
scoreRules: {
|
||||||
|
score: [
|
||||||
|
{ required: true, message: "得分不能为空", trigger: "blur" },
|
||||||
|
{ type: 'number', min: 0, message: "得分不能小于0", trigger: "blur" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 批量评分对话框
|
||||||
|
batchScoreOpen: false,
|
||||||
|
selectedRows: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 查询待评分列表 */
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
getPendingScoringList(this.queryParams).then(response => {
|
||||||
|
this.scoringList = response.rows;
|
||||||
|
this.total = response.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNum = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
resetQuery() {
|
||||||
|
this.resetForm("queryForm");
|
||||||
|
this.handleQuery();
|
||||||
|
},
|
||||||
|
// 多选框选中数据
|
||||||
|
handleSelectionChange(selection) {
|
||||||
|
this.ids = selection.map(item => item.detailId);
|
||||||
|
this.single = selection.length != 1;
|
||||||
|
this.multiple = !selection.length;
|
||||||
|
this.selectedRows = selection;
|
||||||
|
},
|
||||||
|
/** 评分按钮操作 */
|
||||||
|
handleScore(row) {
|
||||||
|
const itemTypeMap = {
|
||||||
|
'text': '简答题',
|
||||||
|
'textarea': '问答题',
|
||||||
|
'essay': '作文题'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.scoreForm = {
|
||||||
|
detailId: row.detailId,
|
||||||
|
questionnaireName: row.questionnaireName,
|
||||||
|
respondentName: row.respondentName,
|
||||||
|
itemNumber: row.itemNumber,
|
||||||
|
itemTypeName: itemTypeMap[row.itemType] || row.itemType,
|
||||||
|
itemContent: row.itemContent,
|
||||||
|
itemScore: row.itemScore || 0,
|
||||||
|
answerText: row.answerText || '',
|
||||||
|
score: row.answerScore || 0,
|
||||||
|
comment: ''
|
||||||
|
};
|
||||||
|
this.scoreOpen = true;
|
||||||
|
},
|
||||||
|
/** 提交评分表单 */
|
||||||
|
submitScoreForm() {
|
||||||
|
this.$refs["scoreForm"].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
const data = {
|
||||||
|
detailId: this.scoreForm.detailId,
|
||||||
|
score: this.scoreForm.score,
|
||||||
|
comment: this.scoreForm.comment
|
||||||
|
};
|
||||||
|
|
||||||
|
submitScoring(data).then(response => {
|
||||||
|
this.$modal.msgSuccess("评分成功");
|
||||||
|
this.scoreOpen = false;
|
||||||
|
this.getList();
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('评分失败:', error);
|
||||||
|
this.$modal.msgError("评分失败");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 取消评分 */
|
||||||
|
cancelScore() {
|
||||||
|
this.scoreOpen = false;
|
||||||
|
this.resetScoreForm();
|
||||||
|
},
|
||||||
|
/** 重置评分表单 */
|
||||||
|
resetScoreForm() {
|
||||||
|
this.scoreForm = {
|
||||||
|
detailId: null,
|
||||||
|
questionnaireName: '',
|
||||||
|
respondentName: '',
|
||||||
|
itemNumber: null,
|
||||||
|
itemTypeName: '',
|
||||||
|
itemContent: '',
|
||||||
|
itemScore: 0,
|
||||||
|
answerText: '',
|
||||||
|
score: 0,
|
||||||
|
comment: ''
|
||||||
|
};
|
||||||
|
if (this.$refs["scoreForm"]) {
|
||||||
|
this.$refs["scoreForm"].resetFields();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 批量评分按钮操作 */
|
||||||
|
handleBatchScore() {
|
||||||
|
if (this.selectedRows.length === 0) {
|
||||||
|
this.$modal.msgWarning("请选择要评分的题目");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为每行添加score和comment字段
|
||||||
|
this.selectedRows = this.selectedRows.map(row => ({
|
||||||
|
...row,
|
||||||
|
score: row.answerScore || 0,
|
||||||
|
comment: ''
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.batchScoreOpen = true;
|
||||||
|
},
|
||||||
|
/** 提交批量评分 */
|
||||||
|
submitBatchScore() {
|
||||||
|
const scoringList = this.selectedRows.map(row => ({
|
||||||
|
detailId: row.detailId,
|
||||||
|
score: row.score || 0,
|
||||||
|
comment: row.comment || ''
|
||||||
|
}));
|
||||||
|
|
||||||
|
batchSubmitScoring(scoringList).then(response => {
|
||||||
|
this.$modal.msgSuccess(response.msg || "批量评分成功");
|
||||||
|
this.batchScoreOpen = false;
|
||||||
|
this.getList();
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('批量评分失败:', error);
|
||||||
|
this.$modal.msgError("批量评分失败");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 取消批量评分 */
|
||||||
|
cancelBatchScore() {
|
||||||
|
this.batchScoreOpen = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.app-container {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
@ -3,7 +3,16 @@
|
||||||
<el-card v-loading="loading">
|
<el-card v-loading="loading">
|
||||||
<div slot="header" class="clearfix">
|
<div slot="header" class="clearfix">
|
||||||
<span>测评报告详情</span>
|
<span>测评报告详情</span>
|
||||||
<el-button style="float: right; padding: 3px 0" type="text" @click="handleBack">返回</el-button>
|
<div style="float: right;">
|
||||||
|
<el-button
|
||||||
|
style="padding: 3px 0; margin-right: 10px;"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-edit"
|
||||||
|
@click="handleEdit"
|
||||||
|
v-hasPermi="['psychology:report:edit']"
|
||||||
|
>编辑</el-button>
|
||||||
|
<el-button style="padding: 3px 0" type="text" @click="handleBack">返回</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-descriptions title="基本信息" :column="2" border>
|
<el-descriptions title="基本信息" :column="2" border>
|
||||||
|
|
@ -64,11 +73,50 @@
|
||||||
<el-button type="primary" icon="el-icon-download" @click="handleDownloadPDF">下载PDF报告</el-button>
|
<el-button type="primary" icon="el-icon-download" @click="handleDownloadPDF">下载PDF报告</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 报告编辑对话框 -->
|
||||||
|
<el-dialog title="编辑报告" :visible.sync="editOpen" width="900px" append-to-body>
|
||||||
|
<el-form ref="editForm" :model="editForm" :rules="editRules" label-width="100px">
|
||||||
|
<el-form-item label="报告标题" prop="reportTitle">
|
||||||
|
<el-input v-model="editForm.reportTitle" placeholder="请输入报告标题" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="报告类型" prop="reportType">
|
||||||
|
<el-select v-model="editForm.reportType" placeholder="请选择报告类型">
|
||||||
|
<el-option label="标准报告" value="standard" />
|
||||||
|
<el-option label="详细报告" value="detailed" />
|
||||||
|
<el-option label="简要报告" value="brief" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="报告摘要" prop="summary">
|
||||||
|
<el-input
|
||||||
|
v-model="editForm.summary"
|
||||||
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
placeholder="请输入报告摘要"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="报告内容" prop="reportContent">
|
||||||
|
<el-input
|
||||||
|
v-model="editForm.reportContent"
|
||||||
|
type="textarea"
|
||||||
|
:rows="15"
|
||||||
|
placeholder="请输入报告内容(支持HTML格式)"
|
||||||
|
/>
|
||||||
|
<div style="margin-top: 10px; color: #909399; font-size: 12px;">
|
||||||
|
<i class="el-icon-info"></i> 提示:报告内容支持HTML格式,可以包含标题、段落、列表等格式
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitEditForm">确 定</el-button>
|
||||||
|
<el-button @click="cancelEdit">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getReport, getReportByAssessmentId } from "@/api/psychology/report";
|
import { getReport, getReportByAssessmentId, updateReportWithType } from "@/api/psychology/report";
|
||||||
import { getQuestionnaireRankList } from "@/api/psychology/questionnaireAnswer";
|
import { getQuestionnaireRankList } from "@/api/psychology/questionnaireAnswer";
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
|
@ -80,7 +128,18 @@ export default {
|
||||||
reportForm: {},
|
reportForm: {},
|
||||||
sourceType: null,
|
sourceType: null,
|
||||||
rankList: [],
|
rankList: [],
|
||||||
rankLoading: false
|
rankLoading: false,
|
||||||
|
// 编辑对话框
|
||||||
|
editOpen: false,
|
||||||
|
editForm: {},
|
||||||
|
editRules: {
|
||||||
|
reportTitle: [
|
||||||
|
{ required: true, message: "报告标题不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
|
reportType: [
|
||||||
|
{ required: true, message: "报告类型不能为空", trigger: "change" }
|
||||||
|
]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
@ -178,6 +237,60 @@ export default {
|
||||||
console.error('获取答题记录失败:', error);
|
console.error('获取答题记录失败:', error);
|
||||||
this.$modal.msgError("获取答题记录失败");
|
this.$modal.msgError("获取答题记录失败");
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
/** 编辑按钮操作 */
|
||||||
|
handleEdit() {
|
||||||
|
this.editForm = {
|
||||||
|
reportId: this.reportForm.reportId,
|
||||||
|
sourceType: this.sourceType,
|
||||||
|
reportTitle: this.reportForm.reportTitle || '',
|
||||||
|
reportType: this.reportForm.reportType || 'standard',
|
||||||
|
summary: this.reportForm.summary || '',
|
||||||
|
reportContent: this.reportForm.reportContent || ''
|
||||||
|
};
|
||||||
|
this.editOpen = true;
|
||||||
|
},
|
||||||
|
/** 提交编辑表单 */
|
||||||
|
submitEditForm() {
|
||||||
|
this.$refs["editForm"].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
const updateData = {
|
||||||
|
reportTitle: this.editForm.reportTitle,
|
||||||
|
reportType: this.editForm.reportType,
|
||||||
|
summary: this.editForm.summary,
|
||||||
|
reportContent: this.editForm.reportContent
|
||||||
|
};
|
||||||
|
|
||||||
|
updateReportWithType(this.editForm.reportId, this.editForm.sourceType, updateData).then(response => {
|
||||||
|
this.$modal.msgSuccess("修改成功");
|
||||||
|
this.editOpen = false;
|
||||||
|
// 重新加载报告数据
|
||||||
|
this.loadReport();
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('修改报告失败:', error);
|
||||||
|
this.$modal.msgError("修改失败");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 取消编辑 */
|
||||||
|
cancelEdit() {
|
||||||
|
this.editOpen = false;
|
||||||
|
this.resetEditForm();
|
||||||
|
},
|
||||||
|
/** 重置编辑表单 */
|
||||||
|
resetEditForm() {
|
||||||
|
this.editForm = {
|
||||||
|
reportId: null,
|
||||||
|
sourceType: null,
|
||||||
|
reportTitle: '',
|
||||||
|
reportType: 'standard',
|
||||||
|
summary: '',
|
||||||
|
reportContent: ''
|
||||||
|
};
|
||||||
|
if (this.$refs["editForm"]) {
|
||||||
|
this.$refs["editForm"].resetFields();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -121,11 +121,50 @@
|
||||||
:limit.sync="queryParams.pageSize"
|
:limit.sync="queryParams.pageSize"
|
||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 报告编辑对话框 -->
|
||||||
|
<el-dialog title="编辑报告" :visible.sync="editOpen" width="900px" append-to-body>
|
||||||
|
<el-form ref="editForm" :model="editForm" :rules="editRules" label-width="100px">
|
||||||
|
<el-form-item label="报告标题" prop="reportTitle">
|
||||||
|
<el-input v-model="editForm.reportTitle" placeholder="请输入报告标题" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="报告类型" prop="reportType">
|
||||||
|
<el-select v-model="editForm.reportType" placeholder="请选择报告类型">
|
||||||
|
<el-option label="标准报告" value="standard" />
|
||||||
|
<el-option label="详细报告" value="detailed" />
|
||||||
|
<el-option label="简要报告" value="brief" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="报告摘要" prop="summary">
|
||||||
|
<el-input
|
||||||
|
v-model="editForm.summary"
|
||||||
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
placeholder="请输入报告摘要"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="报告内容" prop="reportContent">
|
||||||
|
<el-input
|
||||||
|
v-model="editForm.reportContent"
|
||||||
|
type="textarea"
|
||||||
|
:rows="15"
|
||||||
|
placeholder="请输入报告内容(支持HTML格式)"
|
||||||
|
/>
|
||||||
|
<div style="margin-top: 10px; color: #909399; font-size: 12px;">
|
||||||
|
<i class="el-icon-info"></i> 提示:报告内容支持HTML格式,可以包含标题、段落、列表等格式
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitEditForm">确 定</el-button>
|
||||||
|
<el-button @click="cancelEdit">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listReport, getReport, delReport, exportReport } from "@/api/psychology/report";
|
import { listReport, getReport, delReport, exportReport, updateReportWithType } from "@/api/psychology/report";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Report",
|
name: "Report",
|
||||||
|
|
@ -135,6 +174,8 @@ export default {
|
||||||
loading: true,
|
loading: true,
|
||||||
// 选中数组
|
// 选中数组
|
||||||
ids: [],
|
ids: [],
|
||||||
|
// 选中的完整行数据(包含sourceType)
|
||||||
|
selectedRows: [],
|
||||||
// 非单个禁用
|
// 非单个禁用
|
||||||
single: true,
|
single: true,
|
||||||
// 非多个禁用
|
// 非多个禁用
|
||||||
|
|
@ -152,6 +193,17 @@ export default {
|
||||||
sourceType: undefined,
|
sourceType: undefined,
|
||||||
reportType: undefined,
|
reportType: undefined,
|
||||||
isGenerated: undefined
|
isGenerated: undefined
|
||||||
|
},
|
||||||
|
// 编辑对话框
|
||||||
|
editOpen: false,
|
||||||
|
editForm: {},
|
||||||
|
editRules: {
|
||||||
|
reportTitle: [
|
||||||
|
{ required: true, message: "报告标题不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
|
reportType: [
|
||||||
|
{ required: true, message: "报告类型不能为空", trigger: "change" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
@ -181,6 +233,7 @@ export default {
|
||||||
// 多选框选中数据
|
// 多选框选中数据
|
||||||
handleSelectionChange(selection) {
|
handleSelectionChange(selection) {
|
||||||
this.ids = selection.map(item => item.reportId);
|
this.ids = selection.map(item => item.reportId);
|
||||||
|
this.selectedRows = selection; // 保存选中的完整行数据,包含sourceType
|
||||||
this.single = selection.length != 1;
|
this.single = selection.length != 1;
|
||||||
this.multiple = !selection.length;
|
this.multiple = !selection.length;
|
||||||
},
|
},
|
||||||
|
|
@ -190,8 +243,66 @@ export default {
|
||||||
},
|
},
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
handleUpdate(row) {
|
handleUpdate(row) {
|
||||||
// TODO: 实现报告编辑功能
|
// 先获取完整的报告数据
|
||||||
this.$modal.msgInfo("报告编辑功能待实现");
|
getReport(row.reportId, row.sourceType).then(response => {
|
||||||
|
if (response.data) {
|
||||||
|
this.editForm = {
|
||||||
|
reportId: response.data.reportId,
|
||||||
|
sourceType: row.sourceType,
|
||||||
|
reportTitle: response.data.reportTitle || '',
|
||||||
|
reportType: response.data.reportType || 'standard',
|
||||||
|
summary: response.data.summary || '',
|
||||||
|
reportContent: response.data.reportContent || ''
|
||||||
|
};
|
||||||
|
this.editOpen = true;
|
||||||
|
} else {
|
||||||
|
this.$modal.msgError("获取报告数据失败");
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('获取报告数据失败:', error);
|
||||||
|
this.$modal.msgError("获取报告数据失败");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 提交编辑表单 */
|
||||||
|
submitEditForm() {
|
||||||
|
this.$refs["editForm"].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
const updateData = {
|
||||||
|
reportTitle: this.editForm.reportTitle,
|
||||||
|
reportType: this.editForm.reportType,
|
||||||
|
summary: this.editForm.summary,
|
||||||
|
reportContent: this.editForm.reportContent
|
||||||
|
};
|
||||||
|
|
||||||
|
updateReportWithType(this.editForm.reportId, this.editForm.sourceType, updateData).then(response => {
|
||||||
|
this.$modal.msgSuccess("修改成功");
|
||||||
|
this.editOpen = false;
|
||||||
|
this.getList();
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('修改报告失败:', error);
|
||||||
|
this.$modal.msgError("修改失败");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 取消编辑 */
|
||||||
|
cancelEdit() {
|
||||||
|
this.editOpen = false;
|
||||||
|
this.resetEditForm();
|
||||||
|
},
|
||||||
|
/** 重置编辑表单 */
|
||||||
|
resetEditForm() {
|
||||||
|
this.editForm = {
|
||||||
|
reportId: null,
|
||||||
|
sourceType: null,
|
||||||
|
reportTitle: '',
|
||||||
|
reportType: 'standard',
|
||||||
|
summary: '',
|
||||||
|
reportContent: ''
|
||||||
|
};
|
||||||
|
if (this.$refs["editForm"]) {
|
||||||
|
this.$refs["editForm"].resetFields();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
handleExport() {
|
handleExport() {
|
||||||
|
|
@ -241,13 +352,67 @@ export default {
|
||||||
},
|
},
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
handleDelete(row) {
|
handleDelete(row) {
|
||||||
const reportIds = row.reportId ? [row.reportId] : this.ids;
|
let reportIds;
|
||||||
|
let sourceType;
|
||||||
|
|
||||||
|
if (row && row.reportId) {
|
||||||
|
// 单个删除
|
||||||
|
reportIds = [row.reportId];
|
||||||
|
sourceType = row.sourceType;
|
||||||
|
} else {
|
||||||
|
// 批量删除
|
||||||
|
reportIds = this.ids;
|
||||||
|
// 检查选中的报告是否都是同一类型
|
||||||
|
if (this.selectedRows && this.selectedRows.length > 0) {
|
||||||
|
const types = [...new Set(this.selectedRows.map(r => r.sourceType))];
|
||||||
|
if (types.length === 1) {
|
||||||
|
sourceType = types[0];
|
||||||
|
} else {
|
||||||
|
// 混合类型,需要分别删除
|
||||||
|
this.$modal.confirm('选中的报告包含不同类型,将分别删除。是否确认删除?').then(() => {
|
||||||
|
this.deleteReportsByType();
|
||||||
|
}).catch(() => {});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.$modal.confirm('是否确认删除选中的报告?').then(() => {
|
this.$modal.confirm('是否确认删除选中的报告?').then(() => {
|
||||||
return delReport(reportIds);
|
return delReport(reportIds, sourceType);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.getList();
|
this.getList();
|
||||||
this.$modal.msgSuccess("删除成功");
|
this.$modal.msgSuccess("删除成功");
|
||||||
}).catch(() => {});
|
}).catch((error) => {
|
||||||
|
console.error('删除失败:', error);
|
||||||
|
const errorMsg = error.msg || error.message || "删除失败";
|
||||||
|
this.$modal.msgError(errorMsg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 按类型分别删除报告 */
|
||||||
|
deleteReportsByType() {
|
||||||
|
// 按sourceType分组
|
||||||
|
const grouped = {};
|
||||||
|
this.selectedRows.forEach(row => {
|
||||||
|
const type = row.sourceType || 'assessment';
|
||||||
|
if (!grouped[type]) {
|
||||||
|
grouped[type] = [];
|
||||||
|
}
|
||||||
|
grouped[type].push(row.reportId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 分别删除每组
|
||||||
|
const deletePromises = Object.keys(grouped).map(type => {
|
||||||
|
return delReport(grouped[type], type);
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.all(deletePromises).then(() => {
|
||||||
|
this.getList();
|
||||||
|
this.$modal.msgSuccess("删除成功");
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('删除失败:', error);
|
||||||
|
const errorMsg = error.msg || error.message || "删除失败";
|
||||||
|
this.$modal.msgError(errorMsg);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -314,11 +314,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 加载量表列表 */
|
/** 加载量表列表(只显示量表,不包含问卷) */
|
||||||
loadScaleList() {
|
loadScaleList() {
|
||||||
this.scaleLoading = true;
|
this.scaleLoading = true;
|
||||||
listScale(this.scaleQuery).then(response => {
|
// 确保不包含问卷
|
||||||
this.scaleList = response.rows || [];
|
const query = { ...this.scaleQuery, includeQuestionnaire: false };
|
||||||
|
listScale(query).then(response => {
|
||||||
|
// 再次过滤,确保只显示量表
|
||||||
|
this.scaleList = (response.rows || [])
|
||||||
|
.filter(scale => !scale.sourceType || scale.sourceType === 'scale');
|
||||||
this.scaleLoading = false;
|
this.scaleLoading = false;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.scaleLoading = false;
|
this.scaleLoading = false;
|
||||||
|
|
|
||||||
|
|
@ -910,7 +910,7 @@ export default {
|
||||||
handleQuestionnaireDetail(row) {
|
handleQuestionnaireDetail(row) {
|
||||||
const questionnaireId = row.originalId || Math.abs(row.scaleId)
|
const questionnaireId = row.originalId || Math.abs(row.scaleId)
|
||||||
getQuestionnaire(questionnaireId).then(response => {
|
getQuestionnaire(questionnaireId).then(response => {
|
||||||
this.$modal.msgInfo("问卷详情:" + JSON.stringify(response.data, null, 2))
|
this.$modal.msg("问卷详情:" + JSON.stringify(response.data, null, 2))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/** 问卷修改按钮操作 */
|
/** 问卷修改按钮操作 */
|
||||||
|
|
|
||||||
|
|
@ -268,11 +268,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 加载量表列表 */
|
/** 加载量表列表(只显示量表,不包含问卷) */
|
||||||
loadScales() {
|
loadScales() {
|
||||||
this.scaleLoading = true;
|
this.scaleLoading = true;
|
||||||
listScale(this.scaleQuery).then(response => {
|
// 确保不包含问卷
|
||||||
this.scaleList = response.rows || [];
|
const query = { ...this.scaleQuery, includeQuestionnaire: false };
|
||||||
|
listScale(query).then(response => {
|
||||||
|
// 再次过滤,确保只显示量表
|
||||||
|
this.scaleList = (response.rows || [])
|
||||||
|
.filter(scale => !scale.sourceType || scale.sourceType === 'scale');
|
||||||
this.scaleLoading = false;
|
this.scaleLoading = false;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.scaleLoading = false;
|
this.scaleLoading = false;
|
||||||
|
|
|
||||||
|
|
@ -307,10 +307,12 @@ export default {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载量表列表 */
|
/** 加载量表列表(只显示量表,不包含问卷) */
|
||||||
loadScales() {
|
loadScales() {
|
||||||
listScale({ status: '0', pageNum: 1, pageSize: 1000 }).then(response => {
|
listScale({ status: '0', pageNum: 1, pageSize: 1000, includeQuestionnaire: false }).then(response => {
|
||||||
this.scaleList = response.rows || [];
|
// 再次过滤,确保只显示量表
|
||||||
|
this.scaleList = (response.rows || [])
|
||||||
|
.filter(scale => !scale.sourceType || scale.sourceType === 'scale');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 加载因子列表 */
|
/** 加载因子列表 */
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ public class PsyAssessmentReportController extends BaseController
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PsyQuestionnaireReportMapper questionnaireReportMapper;
|
private PsyQuestionnaireReportMapper questionnaireReportMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private com.ddnai.system.service.psychology.IPsyQuestionnaireAnswerService questionnaireAnswerService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取报告列表(包含测评报告和问卷报告)
|
* 获取报告列表(包含测评报告和问卷报告)
|
||||||
|
|
@ -233,26 +236,176 @@ public class PsyAssessmentReportController extends BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改报告
|
* 修改报告(支持测评报告和问卷报告)
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('psychology:report:edit')")
|
@PreAuthorize("@ss.hasPermi('psychology:report:edit')")
|
||||||
@Log(title = "测评报告", businessType = BusinessType.UPDATE)
|
@Log(title = "测评报告", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@RequestBody PsyAssessmentReport report)
|
public AjaxResult edit(@RequestBody java.util.Map<String, Object> params)
|
||||||
{
|
{
|
||||||
report.setUpdateBy(getUsername());
|
String sourceType = (String) params.get("sourceType");
|
||||||
return toAjax(reportService.updateReport(report));
|
Long reportId = Long.valueOf(params.get("reportId").toString());
|
||||||
|
|
||||||
|
if ("questionnaire".equals(sourceType)) {
|
||||||
|
// 更新问卷报告
|
||||||
|
PsyQuestionnaireReport report = questionnaireReportMapper.selectReportById(reportId);
|
||||||
|
if (report == null) {
|
||||||
|
return error("报告不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.containsKey("reportTitle")) {
|
||||||
|
report.setReportTitle((String) params.get("reportTitle"));
|
||||||
|
}
|
||||||
|
if (params.containsKey("reportContent")) {
|
||||||
|
report.setReportContent((String) params.get("reportContent"));
|
||||||
|
}
|
||||||
|
if (params.containsKey("summary")) {
|
||||||
|
report.setSummary((String) params.get("summary"));
|
||||||
|
}
|
||||||
|
if (params.containsKey("reportType")) {
|
||||||
|
report.setReportType((String) params.get("reportType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
report.setUpdateBy(getUsername());
|
||||||
|
int result = questionnaireReportMapper.updateReport(report);
|
||||||
|
return toAjax(result);
|
||||||
|
} else {
|
||||||
|
// 更新测评报告
|
||||||
|
PsyAssessmentReport report = reportService.selectReportById(reportId);
|
||||||
|
if (report == null) {
|
||||||
|
return error("报告不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.containsKey("reportTitle")) {
|
||||||
|
report.setReportTitle((String) params.get("reportTitle"));
|
||||||
|
}
|
||||||
|
if (params.containsKey("reportContent")) {
|
||||||
|
report.setReportContent((String) params.get("reportContent"));
|
||||||
|
}
|
||||||
|
if (params.containsKey("summary")) {
|
||||||
|
report.setSummary((String) params.get("summary"));
|
||||||
|
}
|
||||||
|
if (params.containsKey("reportType")) {
|
||||||
|
report.setReportType((String) params.get("reportType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
report.setUpdateBy(getUsername());
|
||||||
|
return toAjax(reportService.updateReport(report));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除报告
|
* 删除报告(支持测评报告和问卷报告)
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('psychology:report:remove')")
|
@PreAuthorize("@ss.hasPermi('psychology:report:remove')")
|
||||||
@Log(title = "测评报告", businessType = BusinessType.DELETE)
|
@Log(title = "测评报告", businessType = BusinessType.DELETE)
|
||||||
@DeleteMapping("/{reportIds}")
|
@DeleteMapping("/{reportIds}")
|
||||||
public AjaxResult remove(@PathVariable Long[] reportIds)
|
public AjaxResult remove(@PathVariable Long[] reportIds, @RequestParam(required = false) String sourceType)
|
||||||
{
|
{
|
||||||
return toAjax(reportService.deleteReportByIds(reportIds));
|
try {
|
||||||
|
int totalDeleted = 0;
|
||||||
|
|
||||||
|
if ("questionnaire".equals(sourceType)) {
|
||||||
|
// 删除问卷报告,同时删除对应的答题记录
|
||||||
|
for (Long reportId : reportIds) {
|
||||||
|
// 先查询报告,获取answerId
|
||||||
|
PsyQuestionnaireReport report = questionnaireReportMapper.selectReportById(reportId);
|
||||||
|
if (report != null) {
|
||||||
|
Long answerId = report.getAnswerId();
|
||||||
|
// 删除报告
|
||||||
|
int result = questionnaireReportMapper.deleteReportById(reportId);
|
||||||
|
if (result > 0) {
|
||||||
|
totalDeleted++;
|
||||||
|
System.out.println("删除问卷报告成功,reportId: " + reportId + ", answerId: " + answerId);
|
||||||
|
|
||||||
|
// 删除对应的答题记录(会级联删除答案详情)
|
||||||
|
try {
|
||||||
|
// 先获取答题记录,以便重新计算排名
|
||||||
|
com.ddnai.system.domain.psychology.PsyQuestionnaireAnswer answer =
|
||||||
|
questionnaireAnswerService.selectAnswerById(answerId);
|
||||||
|
Long questionnaireId = null;
|
||||||
|
if (answer != null) {
|
||||||
|
questionnaireId = answer.getQuestionnaireId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除答题记录(会级联删除答案详情)
|
||||||
|
int deleteResult = questionnaireAnswerService.deleteAnswerByIds(new Long[]{answerId});
|
||||||
|
System.out.println("删除答题记录结果: " + deleteResult + ", answerId: " + answerId);
|
||||||
|
|
||||||
|
// 重新计算排名
|
||||||
|
if (questionnaireId != null) {
|
||||||
|
// 通过查询所有答题记录来重新计算排名
|
||||||
|
com.ddnai.system.domain.psychology.PsyQuestionnaireAnswer query =
|
||||||
|
new com.ddnai.system.domain.psychology.PsyQuestionnaireAnswer();
|
||||||
|
query.setQuestionnaireId(questionnaireId);
|
||||||
|
query.setStatus("1");
|
||||||
|
java.util.List<com.ddnai.system.domain.psychology.PsyQuestionnaireAnswer> allAnswers =
|
||||||
|
questionnaireAnswerService.selectAnswerList(query);
|
||||||
|
|
||||||
|
// 按总分降序排序
|
||||||
|
allAnswers.sort((a, b) -> {
|
||||||
|
if (a.getTotalScore() == null && b.getTotalScore() == null) return 0;
|
||||||
|
if (a.getTotalScore() == null) return 1;
|
||||||
|
if (b.getTotalScore() == null) return -1;
|
||||||
|
int compare = b.getTotalScore().compareTo(a.getTotalScore());
|
||||||
|
if (compare != 0) return compare;
|
||||||
|
if (a.getSubmitTime() != null && b.getSubmitTime() != null) {
|
||||||
|
return a.getSubmitTime().compareTo(b.getSubmitTime());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新排名
|
||||||
|
int rank = 1;
|
||||||
|
for (com.ddnai.system.domain.psychology.PsyQuestionnaireAnswer a : allAnswers) {
|
||||||
|
a.setRank(rank++);
|
||||||
|
questionnaireAnswerService.updateAnswer(a);
|
||||||
|
}
|
||||||
|
System.out.println("重新计算排名成功,questionnaireId: " + questionnaireId);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("删除答题记录失败,answerId: " + answerId + ", 错误: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("删除问卷报告失败,reportId: " + reportId + "(可能不存在)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("问卷报告不存在,reportId: " + reportId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 默认删除测评报告,如果不存在则尝试删除问卷报告
|
||||||
|
for (Long reportId : reportIds) {
|
||||||
|
// 先尝试删除测评报告(使用单个ID的数组)
|
||||||
|
Long[] singleIdArray = new Long[]{reportId};
|
||||||
|
int result = reportService.deleteReportByIds(singleIdArray);
|
||||||
|
if (result > 0) {
|
||||||
|
totalDeleted++;
|
||||||
|
System.out.println("删除测评报告成功,reportId: " + reportId);
|
||||||
|
} else {
|
||||||
|
// 如果测评报告不存在,尝试删除问卷报告
|
||||||
|
System.out.println("测评报告不存在,尝试删除问卷报告,reportId: " + reportId);
|
||||||
|
int qResult = questionnaireReportMapper.deleteReportById(reportId);
|
||||||
|
if (qResult > 0) {
|
||||||
|
totalDeleted++;
|
||||||
|
System.out.println("删除问卷报告成功,reportId: " + reportId);
|
||||||
|
} else {
|
||||||
|
System.err.println("删除报告失败,reportId: " + reportId + "(测评报告和问卷报告都不存在)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalDeleted > 0) {
|
||||||
|
return success("成功删除 " + totalDeleted + " 个报告");
|
||||||
|
} else {
|
||||||
|
return error("删除失败,报告不存在或已被删除");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("删除报告失败", e);
|
||||||
|
return error("删除报告失败:" + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.ddnai.web.controller.psychology;
|
package com.ddnai.web.controller.psychology;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
@ -45,6 +46,9 @@ public class PsyQuestionnaireAnswerController extends BaseController
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPsyQuestionnaireAnswerService answerService;
|
private IPsyQuestionnaireAnswerService answerService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private com.ddnai.system.mapper.psychology.PsyQuestionnaireReportMapper questionnaireReportMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取问卷答题列表
|
* 获取问卷答题列表
|
||||||
|
|
@ -179,18 +183,45 @@ public class PsyQuestionnaireAnswerController extends BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取问卷成绩排名列表
|
* 获取问卷成绩排名列表(只返回报告管理中存在的报告对应的答题记录)
|
||||||
*/
|
*/
|
||||||
@GetMapping("/rank/{questionnaireId}")
|
@GetMapping("/rank/{questionnaireId}")
|
||||||
public AjaxResult getRankList(@PathVariable Long questionnaireId)
|
public AjaxResult getRankList(@PathVariable Long questionnaireId)
|
||||||
{
|
{
|
||||||
|
// 先查询报告管理中的所有问卷报告(使用与报告管理相同的查询逻辑)
|
||||||
|
com.ddnai.system.domain.psychology.PsyQuestionnaireReport reportQuery =
|
||||||
|
new com.ddnai.system.domain.psychology.PsyQuestionnaireReport();
|
||||||
|
List<com.ddnai.system.domain.psychology.PsyQuestionnaireReport> allReports =
|
||||||
|
questionnaireReportMapper.selectReportList(reportQuery);
|
||||||
|
|
||||||
|
// 收集所有报告的answerId(这些是报告管理中可见的报告)
|
||||||
|
java.util.Set<Long> validAnswerIds = new java.util.HashSet<>();
|
||||||
|
for (com.ddnai.system.domain.psychology.PsyQuestionnaireReport report : allReports) {
|
||||||
|
if (report.getAnswerId() != null) {
|
||||||
|
// 只包含指定问卷的报告
|
||||||
|
PsyQuestionnaireAnswer answer = answerService.selectAnswerById(report.getAnswerId());
|
||||||
|
if (answer != null && answer.getQuestionnaireId().equals(questionnaireId)) {
|
||||||
|
validAnswerIds.add(report.getAnswerId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询该问卷的所有答题记录
|
||||||
PsyQuestionnaireAnswer query = new PsyQuestionnaireAnswer();
|
PsyQuestionnaireAnswer query = new PsyQuestionnaireAnswer();
|
||||||
query.setQuestionnaireId(questionnaireId);
|
query.setQuestionnaireId(questionnaireId);
|
||||||
query.setStatus("1"); // 只查询已完成的
|
query.setStatus("1"); // 只查询已完成的
|
||||||
List<PsyQuestionnaireAnswer> list = answerService.selectAnswerList(query);
|
List<PsyQuestionnaireAnswer> list = answerService.selectAnswerList(query);
|
||||||
|
|
||||||
|
// 只保留报告管理中存在的答题记录
|
||||||
|
List<PsyQuestionnaireAnswer> filteredList = new ArrayList<>();
|
||||||
|
for (PsyQuestionnaireAnswer answer : list) {
|
||||||
|
if (validAnswerIds.contains(answer.getAnswerId())) {
|
||||||
|
filteredList.add(answer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 按总分降序排序,总分相同按提交时间升序
|
// 按总分降序排序,总分相同按提交时间升序
|
||||||
list.sort((a, b) -> {
|
filteredList.sort((a, b) -> {
|
||||||
if (a.getTotalScore() == null && b.getTotalScore() == null) return 0;
|
if (a.getTotalScore() == null && b.getTotalScore() == null) return 0;
|
||||||
if (a.getTotalScore() == null) return 1;
|
if (a.getTotalScore() == null) return 1;
|
||||||
if (b.getTotalScore() == null) return -1;
|
if (b.getTotalScore() == null) return -1;
|
||||||
|
|
@ -203,7 +234,7 @@ public class PsyQuestionnaireAnswerController extends BaseController
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return success(list);
|
return success(filteredList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -225,5 +256,75 @@ public class PsyQuestionnaireAnswerController extends BaseController
|
||||||
return error("报告生成失败:" + e.getMessage());
|
return error("报告生成失败:" + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询待评分的主观题列表
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('psychology:questionnaire:score')")
|
||||||
|
@GetMapping("/scoring/pending")
|
||||||
|
public TableDataInfo getPendingScoringList(PsyQuestionnaireAnswerDetail detail)
|
||||||
|
{
|
||||||
|
startPage();
|
||||||
|
List<Map<String, Object>> list = answerService.selectPendingScoringList(detail);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交主观题评分
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('psychology:questionnaire:score')")
|
||||||
|
@Log(title = "主观题评分", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/scoring/submit")
|
||||||
|
public AjaxResult submitScoring(@RequestBody Map<String, Object> params)
|
||||||
|
{
|
||||||
|
Long detailId = Long.valueOf(params.get("detailId").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);
|
||||||
|
if (result > 0)
|
||||||
|
{
|
||||||
|
return success("评分成功");
|
||||||
|
}
|
||||||
|
return error("评分失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量提交主观题评分
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('psychology:questionnaire:score')")
|
||||||
|
@Log(title = "主观题批量评分", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/scoring/batch")
|
||||||
|
public AjaxResult batchSubmitScoring(@RequestBody List<Map<String, Object>> scoringList)
|
||||||
|
{
|
||||||
|
int successCount = 0;
|
||||||
|
int failCount = 0;
|
||||||
|
|
||||||
|
for (Map<String, Object> params : scoringList)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Long detailId = Long.valueOf(params.get("detailId").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);
|
||||||
|
if (result > 0)
|
||||||
|
{
|
||||||
|
successCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success("批量评分完成:成功 " + successCount + " 条,失败 " + failCount + " 条");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,17 @@ public class PsyQuestionnaireController extends BaseController
|
||||||
@DeleteMapping("/{questionnaireIds}")
|
@DeleteMapping("/{questionnaireIds}")
|
||||||
public AjaxResult remove(@PathVariable Long[] questionnaireIds)
|
public AjaxResult remove(@PathVariable Long[] questionnaireIds)
|
||||||
{
|
{
|
||||||
return toAjax(questionnaireService.deleteQuestionnaireByIds(questionnaireIds));
|
try {
|
||||||
|
int result = questionnaireService.deleteQuestionnaireByIds(questionnaireIds);
|
||||||
|
if (result > 0) {
|
||||||
|
return success("删除问卷成功");
|
||||||
|
} else {
|
||||||
|
return error("删除问卷失败,可能问卷不存在或已被删除");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("删除问卷失败", e);
|
||||||
|
return error("删除问卷失败:" + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,21 @@ public class PsyScalePermissionController extends BaseController
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public AjaxResult add(@Validated @RequestBody PsyScalePermission permission)
|
public AjaxResult add(@Validated @RequestBody PsyScalePermission permission)
|
||||||
{
|
{
|
||||||
permission.setCreateBy(getUsername());
|
try {
|
||||||
return toAjax(permissionService.insertPermission(permission));
|
permission.setCreateBy(getUsername());
|
||||||
|
int result = permissionService.insertPermission(permission);
|
||||||
|
if (result > 0) {
|
||||||
|
return success("添加权限成功");
|
||||||
|
} else {
|
||||||
|
return error("添加权限失败");
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.error("添加权限失败", e);
|
||||||
|
return error(e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("添加权限失败", e);
|
||||||
|
return error("添加权限失败:" + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -94,8 +107,21 @@ public class PsyScalePermissionController extends BaseController
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@Validated @RequestBody PsyScalePermission permission)
|
public AjaxResult edit(@Validated @RequestBody PsyScalePermission permission)
|
||||||
{
|
{
|
||||||
permission.setUpdateBy(getUsername());
|
try {
|
||||||
return toAjax(permissionService.updatePermission(permission));
|
permission.setUpdateBy(getUsername());
|
||||||
|
int result = permissionService.updatePermission(permission);
|
||||||
|
if (result > 0) {
|
||||||
|
return success("修改权限成功");
|
||||||
|
} else {
|
||||||
|
return error("修改权限失败");
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.error("修改权限失败", e);
|
||||||
|
return error(e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("修改权限失败", e);
|
||||||
|
return error("修改权限失败:" + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -117,11 +143,21 @@ public class PsyScalePermissionController extends BaseController
|
||||||
@PostMapping("/assign")
|
@PostMapping("/assign")
|
||||||
public AjaxResult assignUserScales(@RequestBody java.util.Map<String, Object> params)
|
public AjaxResult assignUserScales(@RequestBody java.util.Map<String, Object> params)
|
||||||
{
|
{
|
||||||
Long userId = Long.valueOf(params.get("userId").toString());
|
try {
|
||||||
@SuppressWarnings("unchecked")
|
Long userId = Long.valueOf(params.get("userId").toString());
|
||||||
List<Long> scaleIdList = (List<Long>) params.get("scaleIds");
|
@SuppressWarnings("unchecked")
|
||||||
Long[] scaleIds = scaleIdList != null ? scaleIdList.toArray(new Long[0]) : new Long[0];
|
List<Long> scaleIdList = (List<Long>) params.get("scaleIds");
|
||||||
return toAjax(permissionService.batchAssignUserScalePermission(userId, scaleIds));
|
Long[] scaleIds = scaleIdList != null ? scaleIdList.toArray(new Long[0]) : new Long[0];
|
||||||
|
int result = permissionService.batchAssignUserScalePermission(userId, scaleIds);
|
||||||
|
if (result > 0) {
|
||||||
|
return success("分配权限成功,共分配 " + result + " 个权限");
|
||||||
|
} else {
|
||||||
|
return error("分配权限失败,可能所有量表都不存在");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("分配权限失败", e);
|
||||||
|
return error("分配权限失败:" + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ spring:
|
||||||
druid:
|
druid:
|
||||||
# 主库数据源
|
# 主库数据源
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://localhost:3306/ry_news?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
url: jdbc:mysql://1.15.149.240:3306/ry_news?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||||
username: root
|
username: root
|
||||||
password: root
|
password: 9daafa7710f5198f
|
||||||
# 从库数据源
|
# 从库数据源
|
||||||
slave:
|
slave:
|
||||||
# 从数据源开关/默认关闭
|
# 从数据源开关/默认关闭
|
||||||
|
|
|
||||||
|
|
@ -67,5 +67,21 @@ public interface PsyQuestionnaireAnswerDetailMapper
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public int deleteDetailByIds(Long[] detailIds);
|
public int deleteDetailByIds(Long[] detailIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据答题ID批量删除答案详情
|
||||||
|
*
|
||||||
|
* @param answerIds 答题ID数组
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteDetailByAnswerIds(Long[] answerIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询待评分的主观题列表(关联题目和答题记录信息)
|
||||||
|
*
|
||||||
|
* @param detail 查询条件
|
||||||
|
* @return 待评分题目列表
|
||||||
|
*/
|
||||||
|
public List<java.util.Map<String, Object>> selectPendingScoringList(PsyQuestionnaireAnswerDetail detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,8 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
|
||||||
{
|
{
|
||||||
// 主观题标记为待评分
|
// 主观题标记为待评分
|
||||||
detail.setIsScored("0");
|
detail.setIsScored("0");
|
||||||
|
// 主观题的answerScore保持为null,不设置,避免覆盖
|
||||||
|
// detail.setAnswerScore(null); // 不要设置,保持原值
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新答案详情
|
// 更新答案详情
|
||||||
|
|
@ -270,7 +272,7 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取所有答案详情
|
// 获取所有答案详情(重新从数据库获取,确保获取最新数据)
|
||||||
List<PsyQuestionnaireAnswerDetail> details = detailMapper.selectDetailListByAnswerId(answerId);
|
List<PsyQuestionnaireAnswerDetail> details = detailMapper.selectDetailListByAnswerId(answerId);
|
||||||
if (details == null || details.isEmpty()) {
|
if (details == null || details.isEmpty()) {
|
||||||
System.err.println("答案详情为空,answerId: " + answerId);
|
System.err.println("答案详情为空,answerId: " + answerId);
|
||||||
|
|
@ -279,6 +281,19 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
|
||||||
|
|
||||||
System.out.println("获取到 " + details.size() + " 条答案详情");
|
System.out.println("获取到 " + details.size() + " 条答案详情");
|
||||||
|
|
||||||
|
// 为了确保获取最新数据,重新查询每个detail(避免MyBatis一级缓存问题)
|
||||||
|
for (int i = 0; i < details.size(); i++) {
|
||||||
|
PsyQuestionnaireAnswerDetail detail = details.get(i);
|
||||||
|
PsyQuestionnaireAnswerDetail latestDetail = detailMapper.selectDetailById(detail.getDetailId());
|
||||||
|
if (latestDetail != null) {
|
||||||
|
// 使用最新的数据
|
||||||
|
details.set(i, latestDetail);
|
||||||
|
System.out.println("刷新detail - detailId: " + latestDetail.getDetailId() +
|
||||||
|
", isScored: " + latestDetail.getIsScored() +
|
||||||
|
", answerScore: " + latestDetail.getAnswerScore());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 生成报告内容
|
// 生成报告内容
|
||||||
StringBuilder reportContent = new StringBuilder();
|
StringBuilder reportContent = new StringBuilder();
|
||||||
reportContent.append("<div class='report-container'>");
|
reportContent.append("<div class='report-container'>");
|
||||||
|
|
@ -313,6 +328,24 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保主观题标识正确(从题目类型判断)
|
||||||
|
boolean isSubjective = isSubjectiveType(item.getItemType());
|
||||||
|
String isSubjectiveStr = isSubjective ? "1" : "0";
|
||||||
|
// 如果数据库中的isSubjective字段为空或不正确,使用题目类型判断的结果
|
||||||
|
if (detail.getIsSubjective() == null || detail.getIsSubjective().isEmpty()) {
|
||||||
|
detail.setIsSubjective(isSubjectiveStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调试日志:输出每个题目的评分状态
|
||||||
|
System.out.println("报告生成 - 题目ID: " + detail.getItemId() +
|
||||||
|
", detailId: " + detail.getDetailId() +
|
||||||
|
", isScored: " + detail.getIsScored() +
|
||||||
|
", isSubjective: " + detail.getIsSubjective() +
|
||||||
|
", answerScore: " + detail.getAnswerScore() +
|
||||||
|
", answerScore类型: " + (detail.getAnswerScore() != null ? detail.getAnswerScore().getClass().getName() : "null") +
|
||||||
|
", itemType: " + item.getItemType());
|
||||||
|
|
||||||
reportContent.append("<tr>");
|
reportContent.append("<tr>");
|
||||||
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd;'>").append(item.getItemNumber() != null ? item.getItemNumber() : "").append("</td>");
|
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd;'>").append(item.getItemNumber() != null ? item.getItemNumber() : "").append("</td>");
|
||||||
// HTML转义题目内容,防止XSS攻击
|
// HTML转义题目内容,防止XSS攻击
|
||||||
|
|
@ -320,7 +353,25 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
|
||||||
itemContent = itemContent.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """).replace("'", "'");
|
itemContent = itemContent.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """).replace("'", "'");
|
||||||
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd;'>").append(itemContent).append("</td>");
|
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd;'>").append(itemContent).append("</td>");
|
||||||
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd; text-align: center;'>").append(detail.getAnswerScore() != null ? detail.getAnswerScore() : BigDecimal.ZERO).append("</td>");
|
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd; text-align: center;'>").append(detail.getAnswerScore() != null ? detail.getAnswerScore() : BigDecimal.ZERO).append("</td>");
|
||||||
String statusText = "1".equals(detail.getIsScored()) ? "已评分" : ("1".equals(detail.getIsSubjective()) ? "待评分" : "未评分");
|
|
||||||
|
// 判断状态:优先检查isScored,如果已评分则显示"已评分",否则根据是否为主观题显示"待评分"或"未评分"
|
||||||
|
String statusText;
|
||||||
|
String isScoredValue = detail.getIsScored();
|
||||||
|
String isSubjectiveValue = detail.getIsSubjective();
|
||||||
|
|
||||||
|
// 调试日志
|
||||||
|
System.out.println("状态判断 - isScored: [" + isScoredValue + "], isSubjective: [" + isSubjectiveValue + "], isSubjective(计算): " + isSubjective);
|
||||||
|
|
||||||
|
if ("1".equals(isScoredValue)) {
|
||||||
|
statusText = "已评分";
|
||||||
|
System.out.println("状态结果: 已评分");
|
||||||
|
} else if ("1".equals(isSubjectiveValue) || isSubjective) {
|
||||||
|
statusText = "待评分";
|
||||||
|
System.out.println("状态结果: 待评分");
|
||||||
|
} else {
|
||||||
|
statusText = "未评分";
|
||||||
|
System.out.println("状态结果: 未评分");
|
||||||
|
}
|
||||||
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd;'>").append(statusText).append("</td>");
|
reportContent.append("<td style='padding: 10px; border: 1px solid #ddd;'>").append(statusText).append("</td>");
|
||||||
reportContent.append("</tr>");
|
reportContent.append("</tr>");
|
||||||
}
|
}
|
||||||
|
|
@ -813,5 +864,188 @@ public class PsyQuestionnaireAnswerServiceImpl implements IPsyQuestionnaireAnswe
|
||||||
answerMapper.updateAnswer(answer);
|
answerMapper.updateAnswer(answer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询待评分的主观题列表
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<java.util.Map<String, Object>> selectPendingScoringList(PsyQuestionnaireAnswerDetail detail)
|
||||||
|
{
|
||||||
|
return detailMapper.selectPendingScoringList(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交主观题评分
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public int submitScoring(Long detailId, BigDecimal score, String comment)
|
||||||
|
{
|
||||||
|
// 获取答案详情
|
||||||
|
PsyQuestionnaireAnswerDetail detail = detailMapper.selectDetailById(detailId);
|
||||||
|
if (detail == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取题目信息,判断是否为主观题
|
||||||
|
PsyQuestionnaireItem item = itemMapper.selectItemById(detail.getItemId());
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为主观题(优先使用数据库字段,如果为空则根据题目类型判断)
|
||||||
|
boolean isSubjective = "1".equals(detail.getIsSubjective());
|
||||||
|
if (detail.getIsSubjective() == null || detail.getIsSubjective().isEmpty())
|
||||||
|
{
|
||||||
|
isSubjective = isSubjectiveType(item.getItemType());
|
||||||
|
// 更新数据库字段
|
||||||
|
detail.setIsSubjective(isSubjective ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证是否为主观题
|
||||||
|
if (!isSubjective)
|
||||||
|
{
|
||||||
|
System.err.println("提交评分失败:不是主观题,detailId: " + detailId + ", itemType: " + item.getItemType());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 允许重新评分(如果已评分,允许修改)
|
||||||
|
// 注释掉这个检查,允许重新评分
|
||||||
|
// if ("1".equals(detail.getIsScored()))
|
||||||
|
// {
|
||||||
|
// System.err.println("提交评分失败:已评分,detailId: " + detailId);
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 验证分数是否超过题目分值
|
||||||
|
if (item.getScore() != null)
|
||||||
|
{
|
||||||
|
if (score.compareTo(item.getScore()) > 0)
|
||||||
|
{
|
||||||
|
score = item.getScore(); // 超过题目分值,设置为题目分值
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新答案详情
|
||||||
|
// 确保score不为null,并且使用正确的精度
|
||||||
|
BigDecimal finalScore = score != null ? score : BigDecimal.ZERO;
|
||||||
|
detail.setAnswerScore(finalScore);
|
||||||
|
detail.setIsScored("1");
|
||||||
|
detail.setScoredBy(SecurityUtils.getUsername());
|
||||||
|
detail.setScoredTime(DateUtils.getNowDate());
|
||||||
|
|
||||||
|
// 确保isSubjective字段已设置
|
||||||
|
if (detail.getIsSubjective() == null || detail.getIsSubjective().isEmpty()) {
|
||||||
|
detail.setIsSubjective(isSubjective ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("========== 提交评分开始 ==========");
|
||||||
|
System.out.println("detailId: " + detailId);
|
||||||
|
System.out.println("answerId: " + detail.getAnswerId());
|
||||||
|
System.out.println("score(参数): " + score);
|
||||||
|
System.out.println("finalScore(设置值): " + finalScore);
|
||||||
|
System.out.println("answerScore(对象设置前): " + detail.getAnswerScore());
|
||||||
|
System.out.println("isScored(设置前): " + detail.getIsScored());
|
||||||
|
System.out.println("isSubjective: " + detail.getIsSubjective());
|
||||||
|
|
||||||
|
// 再次确认设置
|
||||||
|
detail.setAnswerScore(finalScore);
|
||||||
|
detail.setIsScored("1");
|
||||||
|
|
||||||
|
System.out.println("answerScore(对象设置后): " + detail.getAnswerScore());
|
||||||
|
System.out.println("isScored(设置后): " + detail.getIsScored());
|
||||||
|
System.out.println("准备调用 updateDetail...");
|
||||||
|
|
||||||
|
int result = detailMapper.updateDetail(detail);
|
||||||
|
|
||||||
|
System.out.println("updateDetail 返回结果: " + result);
|
||||||
|
System.out.println("========== 提交评分结束 ==========");
|
||||||
|
|
||||||
|
// 立即验证更新是否成功(重新查询数据库)
|
||||||
|
if (result > 0) {
|
||||||
|
PsyQuestionnaireAnswerDetail verifyDetail = detailMapper.selectDetailById(detailId);
|
||||||
|
if (verifyDetail != null) {
|
||||||
|
System.out.println("验证更新结果 - detailId: " + detailId +
|
||||||
|
", answerScore(数据库): " + verifyDetail.getAnswerScore() +
|
||||||
|
", isScored(数据库): " + verifyDetail.getIsScored());
|
||||||
|
|
||||||
|
// 如果数据库中的分数不正确,记录警告
|
||||||
|
if (verifyDetail.getAnswerScore() == null || verifyDetail.getAnswerScore().compareTo(score) != 0) {
|
||||||
|
System.err.println("警告:数据库中的分数与设置的分数不一致!设置的分数: " + score +
|
||||||
|
", 数据库中的分数: " + verifyDetail.getAnswerScore());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("警告:更新后无法查询到detail,detailId: " + detailId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果评分成功,更新答题记录的总分
|
||||||
|
if (result > 0)
|
||||||
|
{
|
||||||
|
// 重新计算总分(重新从数据库获取最新数据)
|
||||||
|
List<PsyQuestionnaireAnswerDetail> allDetails = detailMapper.selectDetailListByAnswerId(detail.getAnswerId());
|
||||||
|
BigDecimal totalScore = BigDecimal.ZERO;
|
||||||
|
for (PsyQuestionnaireAnswerDetail d : allDetails)
|
||||||
|
{
|
||||||
|
if (d.getAnswerScore() != null)
|
||||||
|
{
|
||||||
|
totalScore = totalScore.add(d.getAnswerScore());
|
||||||
|
}
|
||||||
|
System.out.println("计算总分 - detailId: " + d.getDetailId() +
|
||||||
|
", answerScore: " + d.getAnswerScore() +
|
||||||
|
", isScored: " + d.getIsScored());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("计算出的总分: " + totalScore);
|
||||||
|
|
||||||
|
// 更新答题记录
|
||||||
|
PsyQuestionnaireAnswer answer = answerMapper.selectAnswerById(detail.getAnswerId());
|
||||||
|
if (answer != null)
|
||||||
|
{
|
||||||
|
answer.setTotalScore(totalScore);
|
||||||
|
answer.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
answerMapper.updateAnswer(answer);
|
||||||
|
|
||||||
|
// 重新计算排名
|
||||||
|
updateRank(answer.getQuestionnaireId());
|
||||||
|
|
||||||
|
// 重新生成报告,以反映最新的评分
|
||||||
|
// 注意:由于在同一个事务中,MyBatis一级缓存可能返回旧数据
|
||||||
|
// 这里先刷新一下,确保获取最新数据
|
||||||
|
try {
|
||||||
|
// 强制刷新:重新获取一次最新的detail数据,确保isScored和answerScore已更新
|
||||||
|
// 清除MyBatis一级缓存,强制从数据库查询
|
||||||
|
PsyQuestionnaireAnswerDetail latestDetail = detailMapper.selectDetailById(detailId);
|
||||||
|
if (latestDetail != null) {
|
||||||
|
System.out.println("重新获取detail - detailId: " + detailId +
|
||||||
|
", isScored: " + latestDetail.getIsScored() +
|
||||||
|
", answerScore: " + latestDetail.getAnswerScore() +
|
||||||
|
", answerScore类型: " + (latestDetail.getAnswerScore() != null ? latestDetail.getAnswerScore().getClass().getName() : "null"));
|
||||||
|
|
||||||
|
// 如果获取的数据不正确,记录警告
|
||||||
|
if (latestDetail.getAnswerScore() == null || latestDetail.getAnswerScore().compareTo(score) != 0) {
|
||||||
|
System.err.println("严重警告:重新获取的detail分数不正确!期望分数: " + score +
|
||||||
|
", 实际分数: " + latestDetail.getAnswerScore());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.err.println("警告:无法重新获取detail,detailId: " + detailId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成报告(会重新从数据库获取所有数据)
|
||||||
|
generateQuestionnaireReport(detail.getAnswerId());
|
||||||
|
System.out.println("评分后重新生成报告成功,answerId: " + detail.getAnswerId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 报告生成失败不影响评分,但记录错误
|
||||||
|
System.err.println("评分后重新生成报告失败,answerId: " + detail.getAnswerId());
|
||||||
|
System.err.println("错误信息: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,13 @@ package com.ddnai.system.service.impl.psychology;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
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 com.ddnai.system.domain.psychology.PsyQuestionnaire;
|
import com.ddnai.system.domain.psychology.PsyQuestionnaire;
|
||||||
|
import com.ddnai.system.domain.psychology.PsyQuestionnaireAnswer;
|
||||||
import com.ddnai.system.mapper.psychology.PsyQuestionnaireMapper;
|
import com.ddnai.system.mapper.psychology.PsyQuestionnaireMapper;
|
||||||
|
import com.ddnai.system.mapper.psychology.PsyQuestionnaireAnswerMapper;
|
||||||
|
import com.ddnai.system.mapper.psychology.PsyQuestionnaireAnswerDetailMapper;
|
||||||
|
import com.ddnai.system.mapper.psychology.PsyQuestionnaireReportMapper;
|
||||||
import com.ddnai.system.service.psychology.IPsyQuestionnaireService;
|
import com.ddnai.system.service.psychology.IPsyQuestionnaireService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,6 +22,15 @@ public class PsyQuestionnaireServiceImpl implements IPsyQuestionnaireService
|
||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
private PsyQuestionnaireMapper questionnaireMapper;
|
private PsyQuestionnaireMapper questionnaireMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PsyQuestionnaireAnswerMapper answerMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PsyQuestionnaireAnswerDetailMapper detailMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PsyQuestionnaireReportMapper reportMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询问卷信息
|
* 查询问卷信息
|
||||||
|
|
@ -73,9 +87,92 @@ public class PsyQuestionnaireServiceImpl implements IPsyQuestionnaireService
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int deleteQuestionnaireByIds(Long[] questionnaireIds)
|
public int deleteQuestionnaireByIds(Long[] questionnaireIds)
|
||||||
{
|
{
|
||||||
return questionnaireMapper.deleteQuestionnaireByIds(questionnaireIds);
|
try {
|
||||||
|
System.out.println("开始删除问卷,问卷ID数量: " + questionnaireIds.length);
|
||||||
|
|
||||||
|
// 在删除问卷前,先删除相关的答题记录、答案详情和报告
|
||||||
|
for (Long questionnaireId : questionnaireIds)
|
||||||
|
{
|
||||||
|
System.out.println("处理问卷ID: " + questionnaireId);
|
||||||
|
|
||||||
|
// 1. 查询该问卷的所有答题记录
|
||||||
|
PsyQuestionnaireAnswer query = new PsyQuestionnaireAnswer();
|
||||||
|
query.setQuestionnaireId(questionnaireId);
|
||||||
|
List<PsyQuestionnaireAnswer> answers = answerMapper.selectAnswerList(query);
|
||||||
|
|
||||||
|
System.out.println("查询到答题记录数量: " + (answers != null ? answers.size() : 0));
|
||||||
|
|
||||||
|
if (answers != null && !answers.isEmpty())
|
||||||
|
{
|
||||||
|
Long[] answerIds = answers.stream()
|
||||||
|
.map(PsyQuestionnaireAnswer::getAnswerId)
|
||||||
|
.toArray(Long[]::new);
|
||||||
|
|
||||||
|
System.out.println("准备删除答题记录,数量: " + answerIds.length);
|
||||||
|
|
||||||
|
// 2. 删除每个答题记录对应的报告
|
||||||
|
int reportCount = 0;
|
||||||
|
for (PsyQuestionnaireAnswer answer : answers)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
com.ddnai.system.domain.psychology.PsyQuestionnaireReport report =
|
||||||
|
reportMapper.selectReportByAnswerId(answer.getAnswerId());
|
||||||
|
if (report != null)
|
||||||
|
{
|
||||||
|
int deleteResult = reportMapper.deleteReportById(report.getReportId());
|
||||||
|
if (deleteResult > 0) {
|
||||||
|
reportCount++;
|
||||||
|
System.out.println("删除报告成功,reportId: " + report.getReportId());
|
||||||
|
} else {
|
||||||
|
System.err.println("删除报告失败,reportId: " + report.getReportId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("删除报告时发生异常,answerId: " + answer.getAnswerId());
|
||||||
|
System.err.println("异常信息: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("删除问卷报告失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("共删除报告数量: " + reportCount);
|
||||||
|
|
||||||
|
// 3. 删除答案详情(必须先删除,因为有外键约束)
|
||||||
|
try {
|
||||||
|
int detailResult = detailMapper.deleteDetailByAnswerIds(answerIds);
|
||||||
|
System.out.println("删除答案详情结果: " + detailResult);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("删除答案详情时发生异常");
|
||||||
|
System.err.println("异常信息: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("删除答案详情失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 删除答题记录
|
||||||
|
try {
|
||||||
|
int answerResult = answerMapper.deleteAnswerByIds(answerIds);
|
||||||
|
System.out.println("删除答题记录结果: " + answerResult);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("删除答题记录时发生异常");
|
||||||
|
System.err.println("异常信息: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("删除答题记录失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 最后删除问卷本身
|
||||||
|
int result = questionnaireMapper.deleteQuestionnaireByIds(questionnaireIds);
|
||||||
|
System.out.println("删除问卷结果: " + result);
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("删除问卷时发生异常");
|
||||||
|
System.err.println("异常信息: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("删除问卷失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import com.ddnai.common.utils.SecurityUtils;
|
||||||
import com.ddnai.system.domain.psychology.PsyScalePermission;
|
import com.ddnai.system.domain.psychology.PsyScalePermission;
|
||||||
import com.ddnai.system.mapper.psychology.PsyScalePermissionMapper;
|
import com.ddnai.system.mapper.psychology.PsyScalePermissionMapper;
|
||||||
import com.ddnai.system.service.psychology.IPsyScalePermissionService;
|
import com.ddnai.system.service.psychology.IPsyScalePermissionService;
|
||||||
|
import com.ddnai.system.service.psychology.IPsyScaleService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 量表权限 服务层实现
|
* 量表权限 服务层实现
|
||||||
|
|
@ -19,6 +20,9 @@ public class PsyScalePermissionServiceImpl implements IPsyScalePermissionService
|
||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
private PsyScalePermissionMapper permissionMapper;
|
private PsyScalePermissionMapper permissionMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPsyScaleService scaleService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询量表权限信息
|
* 查询量表权限信息
|
||||||
|
|
@ -84,6 +88,16 @@ public class PsyScalePermissionServiceImpl implements IPsyScalePermissionService
|
||||||
@Override
|
@Override
|
||||||
public int insertPermission(PsyScalePermission permission)
|
public int insertPermission(PsyScalePermission permission)
|
||||||
{
|
{
|
||||||
|
// 验证 scale_id 是否存在
|
||||||
|
if (permission.getScaleId() != null)
|
||||||
|
{
|
||||||
|
com.ddnai.system.domain.psychology.PsyScale scale = scaleService.selectScaleById(permission.getScaleId());
|
||||||
|
if (scale == null)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("量表不存在,scaleId: " + permission.getScaleId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (permission.getStatus() == null)
|
if (permission.getStatus() == null)
|
||||||
{
|
{
|
||||||
permission.setStatus("0");
|
permission.setStatus("0");
|
||||||
|
|
@ -100,6 +114,16 @@ public class PsyScalePermissionServiceImpl implements IPsyScalePermissionService
|
||||||
@Override
|
@Override
|
||||||
public int updatePermission(PsyScalePermission permission)
|
public int updatePermission(PsyScalePermission permission)
|
||||||
{
|
{
|
||||||
|
// 验证 scale_id 是否存在
|
||||||
|
if (permission.getScaleId() != null)
|
||||||
|
{
|
||||||
|
com.ddnai.system.domain.psychology.PsyScale scale = scaleService.selectScaleById(permission.getScaleId());
|
||||||
|
if (scale == null)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("量表不存在,scaleId: " + permission.getScaleId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return permissionMapper.updatePermission(permission);
|
return permissionMapper.updatePermission(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,6 +184,14 @@ public class PsyScalePermissionServiceImpl implements IPsyScalePermissionService
|
||||||
String username = SecurityUtils.getUsername();
|
String username = SecurityUtils.getUsername();
|
||||||
for (Long scaleId : scaleIds)
|
for (Long scaleId : scaleIds)
|
||||||
{
|
{
|
||||||
|
// 验证 scale_id 是否存在
|
||||||
|
com.ddnai.system.domain.psychology.PsyScale scale = scaleService.selectScaleById(scaleId);
|
||||||
|
if (scale == null)
|
||||||
|
{
|
||||||
|
System.err.println("警告:量表不存在,跳过该权限分配,scaleId: " + scaleId);
|
||||||
|
continue; // 跳过不存在的量表
|
||||||
|
}
|
||||||
|
|
||||||
PsyScalePermission permission = new PsyScalePermission();
|
PsyScalePermission permission = new PsyScalePermission();
|
||||||
permission.setUserId(userId);
|
permission.setUserId(userId);
|
||||||
permission.setScaleId(scaleId);
|
permission.setScaleId(scaleId);
|
||||||
|
|
|
||||||
|
|
@ -81,5 +81,23 @@ public interface IPsyQuestionnaireAnswerService
|
||||||
* @param answerId 答题ID
|
* @param answerId 答题ID
|
||||||
*/
|
*/
|
||||||
public void generateReport(Long answerId);
|
public void generateReport(Long answerId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询待评分的主观题列表
|
||||||
|
*
|
||||||
|
* @param detail 查询条件
|
||||||
|
* @return 待评分题目列表(包含题目信息、答案信息等)
|
||||||
|
*/
|
||||||
|
public List<java.util.Map<String, Object>> selectPendingScoringList(PsyQuestionnaireAnswerDetail detail);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交主观题评分
|
||||||
|
*
|
||||||
|
* @param detailId 答案详情ID
|
||||||
|
* @param score 得分
|
||||||
|
* @param comment 评语(可选)
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int submitScoring(Long detailId, java.math.BigDecimal score, String comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="optionId != null">option_id = #{optionId}, </if>
|
<if test="optionId != null">option_id = #{optionId}, </if>
|
||||||
<if test="optionIds != null">option_ids = #{optionIds}, </if>
|
<if test="optionIds != null">option_ids = #{optionIds}, </if>
|
||||||
<if test="answerText != null">answer_text = #{answerText}, </if>
|
<if test="answerText != null">answer_text = #{answerText}, </if>
|
||||||
<if test="answerScore != null">answer_score = #{answerScore}, </if>
|
<!-- 对于answerScore,使用choose确保即使为0或小数也能更新,但null时不更新 -->
|
||||||
|
<choose>
|
||||||
|
<when test="answerScore != null">
|
||||||
|
answer_score = #{answerScore,jdbcType=DECIMAL},
|
||||||
|
</when>
|
||||||
|
</choose>
|
||||||
<if test="isSubjective != null and isSubjective != ''">is_subjective = #{isSubjective}, </if>
|
<if test="isSubjective != null and isSubjective != ''">is_subjective = #{isSubjective}, </if>
|
||||||
<if test="isScored != null and isScored != ''">is_scored = #{isScored}, </if>
|
<if test="isScored != null and isScored != ''">is_scored = #{isScored}, </if>
|
||||||
<if test="scoredBy != null and scoredBy != ''">scored_by = #{scoredBy}, </if>
|
<if test="scoredBy != null and scoredBy != ''">scored_by = #{scoredBy}, </if>
|
||||||
|
|
@ -92,6 +97,46 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
#{detailId}
|
#{detailId}
|
||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteDetailByAnswerIds" parameterType="String">
|
||||||
|
delete from psy_questionnaire_answer_detail where answer_id in
|
||||||
|
<foreach item="answerId" collection="array" open="(" separator="," close=")">
|
||||||
|
#{answerId}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<!-- 查询待评分的主观题列表(关联题目、答题记录、问卷信息) -->
|
||||||
|
<select id="selectPendingScoringList" parameterType="com.ddnai.system.domain.psychology.PsyQuestionnaireAnswerDetail" resultType="java.util.Map">
|
||||||
|
select
|
||||||
|
d.detail_id as detailId,
|
||||||
|
d.answer_id as answerId,
|
||||||
|
d.item_id as itemId,
|
||||||
|
d.answer_text as answerText,
|
||||||
|
d.answer_score as answerScore,
|
||||||
|
d.is_scored as isScored,
|
||||||
|
d.scored_by as scoredBy,
|
||||||
|
d.scored_time as scoredTime,
|
||||||
|
i.item_number as itemNumber,
|
||||||
|
i.item_content as itemContent,
|
||||||
|
i.item_type as itemType,
|
||||||
|
i.score as itemScore,
|
||||||
|
a.questionnaire_id as questionnaireId,
|
||||||
|
a.respondent_name as respondentName,
|
||||||
|
a.submit_time as submitTime,
|
||||||
|
q.questionnaire_name as questionnaireName
|
||||||
|
from psy_questionnaire_answer_detail d
|
||||||
|
inner join psy_questionnaire_item i on d.item_id = i.item_id
|
||||||
|
inner join psy_questionnaire_answer a on d.answer_id = a.answer_id
|
||||||
|
inner join psy_questionnaire q on a.questionnaire_id = q.questionnaire_id
|
||||||
|
where d.is_subjective = '1' and d.is_scored = '0'
|
||||||
|
<if test="answerId != null">
|
||||||
|
and d.answer_id = #{answerId}
|
||||||
|
</if>
|
||||||
|
<if test="itemId != null">
|
||||||
|
and d.item_id = #{itemId}
|
||||||
|
</if>
|
||||||
|
order by a.submit_time desc, i.item_number asc
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
149
sql/添加主观题评分菜单.sql
Normal file
149
sql/添加主观题评分菜单.sql
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
-- 添加主观题评分菜单
|
||||||
|
-- 菜单类型:C(菜单)
|
||||||
|
-- 父菜单ID:2009(心理测评管理)
|
||||||
|
-- 排序:在问卷管理(2041,order_num=8)之后,设置为13(在量表权限管理之后)
|
||||||
|
|
||||||
|
-- 设置字符集(确保中文正确显示)
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!50503 SET NAMES utf8mb4 */;
|
||||||
|
|
||||||
|
-- 添加主观题评分菜单(菜单项)
|
||||||
|
-- 注意:menu_id需要根据实际情况调整,这里使用AUTO_INCREMENT自动生成
|
||||||
|
INSERT INTO `sys_menu` (
|
||||||
|
`menu_name`,
|
||||||
|
`parent_id`,
|
||||||
|
`order_num`,
|
||||||
|
`path`,
|
||||||
|
`component`,
|
||||||
|
`query`,
|
||||||
|
`route_name`,
|
||||||
|
`is_frame`,
|
||||||
|
`is_cache`,
|
||||||
|
`menu_type`,
|
||||||
|
`visible`,
|
||||||
|
`status`,
|
||||||
|
`perms`,
|
||||||
|
`icon`,
|
||||||
|
`create_by`,
|
||||||
|
`create_time`,
|
||||||
|
`remark`
|
||||||
|
) VALUES (
|
||||||
|
'主观题评分', -- 菜单名称
|
||||||
|
2009, -- 父菜单ID(心理测评管理)
|
||||||
|
13, -- 显示顺序(在量表权限管理order_num=12之后)
|
||||||
|
'questionnaire/scoring', -- 路由地址
|
||||||
|
'psychology/questionnaire/scoring', -- 组件路径
|
||||||
|
NULL, -- 路由参数
|
||||||
|
'QuestionnaireScoring', -- 路由名称
|
||||||
|
1, -- 是否为外链(1否)
|
||||||
|
0, -- 是否缓存(0缓存)
|
||||||
|
'C', -- 菜单类型(C菜单)
|
||||||
|
'0', -- 菜单状态(0显示)
|
||||||
|
'0', -- 菜单状态(0正常)
|
||||||
|
'psychology:questionnaire:score', -- 权限标识
|
||||||
|
'edit', -- 菜单图标
|
||||||
|
'admin', -- 创建者
|
||||||
|
NOW(), -- 创建时间
|
||||||
|
'主观题评分菜单' -- 备注
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 添加主观题评分的按钮权限
|
||||||
|
-- 评分查询(使用子查询获取刚插入的菜单ID)
|
||||||
|
INSERT INTO `sys_menu` (
|
||||||
|
`menu_name`,
|
||||||
|
`parent_id`,
|
||||||
|
`order_num`,
|
||||||
|
`path`,
|
||||||
|
`component`,
|
||||||
|
`query`,
|
||||||
|
`route_name`,
|
||||||
|
`is_frame`,
|
||||||
|
`is_cache`,
|
||||||
|
`menu_type`,
|
||||||
|
`visible`,
|
||||||
|
`status`,
|
||||||
|
`perms`,
|
||||||
|
`icon`,
|
||||||
|
`create_by`,
|
||||||
|
`create_time`,
|
||||||
|
`remark`
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'评分查询',
|
||||||
|
menu_id,
|
||||||
|
1,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
NULL,
|
||||||
|
'',
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
'F',
|
||||||
|
'0',
|
||||||
|
'0',
|
||||||
|
'psychology:questionnaire:score:query',
|
||||||
|
'#',
|
||||||
|
'admin',
|
||||||
|
NOW(),
|
||||||
|
''
|
||||||
|
FROM sys_menu
|
||||||
|
WHERE menu_name = '主观题评分' AND parent_id = 2009
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- 评分操作
|
||||||
|
INSERT INTO `sys_menu` (
|
||||||
|
`menu_name`,
|
||||||
|
`parent_id`,
|
||||||
|
`order_num`,
|
||||||
|
`path`,
|
||||||
|
`component`,
|
||||||
|
`query`,
|
||||||
|
`route_name`,
|
||||||
|
`is_frame`,
|
||||||
|
`is_cache`,
|
||||||
|
`menu_type`,
|
||||||
|
`visible`,
|
||||||
|
`status`,
|
||||||
|
`perms`,
|
||||||
|
`icon`,
|
||||||
|
`create_by`,
|
||||||
|
`create_time`,
|
||||||
|
`remark`
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'评分操作',
|
||||||
|
menu_id,
|
||||||
|
2,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
NULL,
|
||||||
|
'',
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
'F',
|
||||||
|
'0',
|
||||||
|
'0',
|
||||||
|
'psychology:questionnaire:score',
|
||||||
|
'#',
|
||||||
|
'admin',
|
||||||
|
NOW(),
|
||||||
|
''
|
||||||
|
FROM sys_menu
|
||||||
|
WHERE menu_name = '主观题评分' AND parent_id = 2009
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- 为管理员角色(role_id=1)添加菜单权限
|
||||||
|
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
|
||||||
|
SELECT 1, menu_id FROM sys_menu WHERE menu_name = '主观题评分' AND parent_id = 2009
|
||||||
|
ON DUPLICATE KEY UPDATE role_id = role_id;
|
||||||
|
|
||||||
|
-- 为管理员角色添加按钮权限
|
||||||
|
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
|
||||||
|
SELECT 1, m2.menu_id
|
||||||
|
FROM sys_menu m1
|
||||||
|
INNER JOIN sys_menu m2 ON m2.parent_id = m1.menu_id
|
||||||
|
WHERE m1.menu_name = '主观题评分' AND m1.parent_id = 2009
|
||||||
|
ON DUPLICATE KEY UPDATE role_id = role_id;
|
||||||
|
|
||||||
Binary file not shown.
BIN
z_Project change/心理需求.docx
Normal file
BIN
z_Project change/心理需求.docx
Normal file
Binary file not shown.
BIN
z_Project change/量表项目.pdf
Normal file
BIN
z_Project change/量表项目.pdf
Normal file
Binary file not shown.
139
主观题评分功能使用说明.md
Normal file
139
主观题评分功能使用说明.md
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
# 主观题评分功能使用说明
|
||||||
|
|
||||||
|
## 功能说明
|
||||||
|
|
||||||
|
主观题评分功能允许管理员对问卷中的主观题(简答题、问答题、作文题)进行手动评分。
|
||||||
|
|
||||||
|
## 添加菜单方法
|
||||||
|
|
||||||
|
### 方法一:执行SQL脚本(推荐)
|
||||||
|
|
||||||
|
1. 打开数据库管理工具(如Navicat、MySQL Workbench等)
|
||||||
|
2. 连接到数据库
|
||||||
|
3. 执行 `sql/添加主观题评分菜单.sql` 文件中的SQL语句
|
||||||
|
4. 刷新浏览器页面,菜单应该会出现在"心理测评管理"下
|
||||||
|
|
||||||
|
### 方法二:通过菜单管理页面手动添加
|
||||||
|
|
||||||
|
1. 登录系统,进入 **系统管理** -> **菜单管理**
|
||||||
|
2. 找到 **心理测评管理**(菜单ID:2009)
|
||||||
|
3. 点击 **新增** 按钮
|
||||||
|
4. 填写以下信息:
|
||||||
|
- **菜单名称**:主观题评分
|
||||||
|
- **父菜单**:心理测评管理
|
||||||
|
- **显示顺序**:13
|
||||||
|
- **路由地址**:questionnaire/scoring
|
||||||
|
- **组件路径**:psychology/questionnaire/scoring
|
||||||
|
- **路由名称**:QuestionnaireScoring
|
||||||
|
- **菜单类型**:菜单
|
||||||
|
- **菜单图标**:edit
|
||||||
|
- **权限标识**:psychology:questionnaire:score
|
||||||
|
- **是否显示**:显示
|
||||||
|
- **状态**:正常
|
||||||
|
5. 点击 **确定** 保存
|
||||||
|
|
||||||
|
6. 添加按钮权限(可选):
|
||||||
|
- 在菜单管理中找到刚创建的"主观题评分"菜单
|
||||||
|
- 点击 **新增** 添加按钮权限:
|
||||||
|
- **菜单名称**:评分查询
|
||||||
|
- **权限标识**:psychology:questionnaire:score:query
|
||||||
|
- **菜单类型**:按钮
|
||||||
|
|
||||||
|
- 再添加一个:
|
||||||
|
- **菜单名称**:评分操作
|
||||||
|
- **权限标识**:psychology:questionnaire:score
|
||||||
|
- **菜单类型**:按钮
|
||||||
|
|
||||||
|
7. 分配菜单权限:
|
||||||
|
- 进入 **系统管理** -> **角色管理**
|
||||||
|
- 找到 **管理员** 角色,点击 **修改**
|
||||||
|
- 在 **菜单权限** 中勾选 **主观题评分** 及其按钮权限
|
||||||
|
- 点击 **确定** 保存
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 访问主观题评分页面
|
||||||
|
|
||||||
|
- 方法一:在左侧菜单中找到 **心理测评管理** -> **主观题评分**
|
||||||
|
- 方法二:直接访问URL:`/psychology/questionnaire/scoring`
|
||||||
|
|
||||||
|
### 2. 查看待评分题目
|
||||||
|
|
||||||
|
页面会自动显示所有待评分的主观题,包括:
|
||||||
|
- 问卷名称
|
||||||
|
- 答题人
|
||||||
|
- 题目序号和内容
|
||||||
|
- 题目类型(简答题/问答题/作文题)
|
||||||
|
- 题目分值
|
||||||
|
- 答案内容
|
||||||
|
- 提交时间
|
||||||
|
|
||||||
|
### 3. 单个评分
|
||||||
|
|
||||||
|
1. 在列表中点击 **评分** 按钮
|
||||||
|
2. 在弹出的对话框中:
|
||||||
|
- 查看题目内容和答案内容
|
||||||
|
- 输入得分(不能超过题目分值)
|
||||||
|
- 可选:输入评语
|
||||||
|
3. 点击 **确定** 保存评分
|
||||||
|
|
||||||
|
### 4. 批量评分
|
||||||
|
|
||||||
|
1. 在列表中勾选多个待评分的题目
|
||||||
|
2. 点击 **批量评分** 按钮
|
||||||
|
3. 在批量评分对话框中为每个题目输入得分和评语
|
||||||
|
4. 点击 **确定** 批量保存
|
||||||
|
|
||||||
|
### 5. 搜索和筛选
|
||||||
|
|
||||||
|
- 可以通过 **问卷名称** 搜索
|
||||||
|
- 可以通过 **答题人** 搜索
|
||||||
|
|
||||||
|
## 功能特点
|
||||||
|
|
||||||
|
1. **自动识别主观题**:系统自动识别简答题(text)、问答题(textarea)、作文题(essay)三种类型
|
||||||
|
2. **分数验证**:评分不能超过题目分值,系统会自动限制
|
||||||
|
3. **自动更新总分**:评分后自动重新计算答题记录的总分
|
||||||
|
4. **自动更新排名**:评分后自动重新计算该问卷的排名
|
||||||
|
5. **批量评分**:支持同时为多个题目评分,提高效率
|
||||||
|
6. **评语功能**:可以为每个答案添加评语(可选)
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 只有已提交的问卷中的主观题才会出现在待评分列表中
|
||||||
|
2. 已经评分的题目不会出现在待评分列表中
|
||||||
|
3. 评分后,用户查看报告时会看到更新后的成绩
|
||||||
|
4. 如果评分失败,请检查:
|
||||||
|
- 是否有评分权限(`psychology:questionnaire:score`)
|
||||||
|
- 题目是否为主观题且未评分
|
||||||
|
- 得分是否超过题目分值
|
||||||
|
|
||||||
|
## 权限配置
|
||||||
|
|
||||||
|
需要的权限标识:
|
||||||
|
- `psychology:questionnaire:score` - 评分操作权限
|
||||||
|
- `psychology:questionnaire:score:query` - 查询权限(可选)
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q: 菜单中没有显示"主观题评分"?
|
||||||
|
A: 需要执行SQL脚本或通过菜单管理页面手动添加菜单,并确保已分配菜单权限给当前角色。
|
||||||
|
|
||||||
|
### Q: 点击菜单后页面空白?
|
||||||
|
A: 检查:
|
||||||
|
1. 路由配置是否正确(`ruoyi-ui/src/router/index.js`)
|
||||||
|
2. 页面文件是否存在(`ruoyi-ui/src/views/psychology/questionnaire/scoring.vue`)
|
||||||
|
3. 浏览器控制台是否有错误信息
|
||||||
|
|
||||||
|
### Q: 没有待评分的数据?
|
||||||
|
A: 检查:
|
||||||
|
1. 是否有已提交的问卷答题记录
|
||||||
|
2. 问卷中是否包含主观题(text、textarea、essay类型)
|
||||||
|
3. 主观题是否已经被评分过(已评分的不会显示)
|
||||||
|
|
||||||
|
### Q: 评分后总分没有更新?
|
||||||
|
A: 系统会自动更新,如果未更新,请:
|
||||||
|
1. 刷新页面查看
|
||||||
|
2. 检查后端日志是否有错误
|
||||||
|
3. 确认评分是否成功(查看操作日志)
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user