yujialong 4 weeks ago
parent da0efc51bc
commit 1b70f00dbc
  1. 15
      src/pages/achievement/info/project.vue
  2. 2
      src/pages/achievement/list/project.vue
  3. 27
      src/pages/assessment/add/index.vue
  4. 158
      src/pages/match/manage/theoryReport.vue

@ -277,7 +277,7 @@ export default {
this.errorAnalysis = res.errorAnalysis || {} this.errorAnalysis = res.errorAnalysis || {}
this.max = res.highestErrorRate || {} this.max = res.highestErrorRate || {}
this.min = res.minimumErrorRate || {} this.min = res.minimumErrorRate || {}
this.scores = res.getFractionalSegmentNum this.scores = res.calculateRangeCounts
this.getChart() this.getChart()
this.errorChart() this.errorChart()
} catch (e) { } catch (e) {
@ -309,7 +309,7 @@ export default {
// //
show (row) { show (row) {
this.$store.commit('achievement/setRow', null) this.$store.commit('achievement/setRow', null)
this.$router.push(`show?reportId=${row.reportId}`) this.$router.push(`${row.paperId ? '/match/theoryReport' : 'show'}?reportId=${row.reportId}`)
}, },
// () // ()
exportData () { exportData () {
@ -347,7 +347,7 @@ export default {
mallId: this.mallId, mallId: this.mallId,
reportIds reportIds
} }
data[this.permissions ? 'assessmentId' : 'projectId'] = this.id data[this.permissions ? 'assessmentId' : this.paperId ? 'paperId' : 'projectId'] = this.id || this.paperId
const res = await axios.post(this.api.batchExportReportsAsZip, data, { const res = await axios.post(this.api.batchExportReportsAsZip, data, {
headers: { headers: {
token: this.token token: this.token
@ -446,10 +446,7 @@ export default {
util.downloadFileDirect(`活跃度.xls`, new Blob([res.data])) util.downloadFileDirect(`活跃度.xls`, new Blob([res.data]))
}, },
getChart () { // 线 getChart () { // 线
const data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] const data = this.scores
for (const i in this.scores) {
data[+(i.replace('num', '')) - 1] = this.scores[i]
}
let myChart = echarts.init(document.getElementById("chart")); let myChart = echarts.init(document.getElementById("chart"));
myChart.setOption({ myChart.setOption({
title: { text: "实验分数分布图" }, title: { text: "实验分数分布图" },
@ -462,7 +459,7 @@ export default {
// axisLabel: { // axisLabel: {
// interval: 9, // interval: 9,
// }, // },
data: ["0-10", "10-20", "20-30", "30-40", "40-50", "50-60", "60-70", "70-80", "80-90", "90-100"] data: data.map(e => e.range)
}, },
yAxis: { yAxis: {
name: this.permissions ? "人数" : '成绩报告数量', name: this.permissions ? "人数" : '成绩报告数量',
@ -470,7 +467,7 @@ export default {
minInterval: 5, minInterval: 5,
}, },
series: [{ series: [{
data, data: data.map(e => e.count),
type: "line", type: "line",
areaStyle: {}, areaStyle: {},
label: { label: {

@ -251,7 +251,7 @@ export default {
// //
entry (row) { entry (row) {
this.$store.commit('achievement/setReferrer', `${this.$route.path}?${qs.stringify(this.form)}&page=${this.page}`) this.$store.commit('achievement/setReferrer', `${this.$route.path}?${qs.stringify(this.form)}&page=${this.page}`)
this.$router.push(`project?id=${row.assessmentId || row.projectId || ''}&paperId=${row.paperId || ''}&projectName=${row.projectName}&permissions=${row.permissions || 0}&mallId=${this.form.mallId}&classId=${row.classId || ''}`) this.$router.push(`project?id=${row.assessmentId || row.projectId || ''}&paperId=${row.paperId || ''}&projectName=${row.projectName}&permissions=${this.form.permissions}&mallId=${this.form.mallId}&classId=${row.classId || ''}`)
}, },
handleDelete (row) { // handleDelete (row) { //
this.$confirm("该项目下的所有成绩报告将会删除,是否继续?", "提示", { this.$confirm("该项目下的所有成绩报告将会删除,是否继续?", "提示", {

@ -3,7 +3,7 @@
<el-form :disabled="isDetail"> <el-form :disabled="isDetail">
<el-card shadow="hover" class="m-b-20"> <el-card shadow="hover" class="m-b-20">
<div class="flex-between"> <div class="flex-between">
<el-page-header @back="goBack" :content="isDetail ? '查看' : (form.id ? '更新' : '创建') + '教学实验'"></el-page-header> <el-page-header @back="goBack" :content="isDetail ? '查看' : (form.id ? '更新' : '创建') + '考核'"></el-page-header>
<div> <div>
<el-button type="primary" @click="save(0)" v-show="!isDetail">{{ form.id ? "更新" : "创建" }}</el-button> <el-button type="primary" @click="save(0)" v-show="!isDetail">{{ form.id ? "更新" : "创建" }}</el-button>
</div> </div>
@ -30,10 +30,10 @@
<!-- 根据发布方式判断时间的显示 --> <!-- 根据发布方式判断时间的显示 -->
<el-card shadow="hover" class="m-b-20"> <el-card shadow="hover" class="m-b-20">
<div> <div>
<p class="m-b-20">实验时间</p> <p class="m-b-20">考核时间</p>
<!-- 手动发布显示 --> <!-- 手动发布显示 -->
<div class="date-inputs" v-if="form.type == 1"> <div class="date-inputs" v-if="form.type == 1">
实验时长 考核时长
<el-input type="number" min="0" v-model.trim="duration.day" placeholder></el-input> <el-input type="number" min="0" v-model.trim="duration.day" placeholder></el-input>
<el-input type="number" min="0" v-model.trim="duration.hour" placeholder></el-input> <el-input type="number" min="0" v-model.trim="duration.hour" placeholder></el-input>
@ -72,7 +72,7 @@
<!-- 实训项目模块 --> <!-- 实训项目模块 -->
<el-card shadow="hover" class="m-b-20"> <el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-20"> <div class="flex-between m-b-20">
<span>实训项目</span> <span>考核项目</span>
<div style="display: inline-flex;"> <div style="display: inline-flex;">
<div> <div>
<el-input placeholder="请输入项目名称" prefix-icon="el-icon-search" v-model.trim="keyword" clearable></el-input> <el-input placeholder="请输入项目名称" prefix-icon="el-icon-search" v-model.trim="keyword" clearable></el-input>
@ -379,7 +379,6 @@ export default {
}, },
getProjectData () { getProjectData () {
const curItem = this.curriculumList.find(e => e.mallId === this.form.mallId) const curItem = this.curriculumList.find(e => e.mallId === this.form.mallId)
console.log("🚀 ~ file: index.vue:471 ~ getProjectData ~ curItem:", curItem)
let data = { let data = {
pageNum: this.page, pageNum: this.page,
pageSize: this.pageSize, pageSize: this.pageSize,
@ -419,18 +418,18 @@ export default {
let day = hour * 24; let day = hour * 24;
this.form.experimentDuration = `${Math.floor(timestamp / day)}d${Math.floor(timestamp % day / hour)}h${Math.floor(timestamp % day % hour / minute)}m`; this.form.experimentDuration = `${Math.floor(timestamp / day)}d${Math.floor(timestamp % day / hour)}h${Math.floor(timestamp % day % hour / minute)}m`;
} }
if (this.form.type == 1 && this.form.experimentDuration == "0d0h0m") return util.warningMsg("请填写实验时长"); if (this.form.type == 1 && this.form.experimentDuration == "0d0h0m") return util.warningMsg("请填写考核时长");
if (this.form.type == 2 && this.startTime == "0000-00-00 00:00:00") return util.warningMsg("请填写实验时间"); if (this.form.type == 2 && this.startTime == "0000-00-00 00:00:00") return util.warningMsg("请填写考核时间");
if (this.form.type == 1) { if (this.form.type == 1) {
const { day, hour, minute } = this.duration const { day, hour, minute } = this.duration
if (String(day).includes('.')) return util.warningMsg('实验天数请填写整数') if (String(day).includes('.')) return util.warningMsg('考核天数请填写整数')
if (day < 0) return util.warningMsg('实验天数请勿填写负数') if (day < 0) return util.warningMsg('考核天数请勿填写负数')
if (String(hour).includes('.')) return util.warningMsg('实验小时请填写整数') if (String(hour).includes('.')) return util.warningMsg('考核小时请填写整数')
if (hour < 0) return util.warningMsg('实验小时请勿填写负数') if (hour < 0) return util.warningMsg('考核小时请勿填写负数')
if (String(minute).includes('.')) return util.warningMsg('实验分钟请填写整数') if (String(minute).includes('.')) return util.warningMsg('考核分钟请填写整数')
if (minute < 0) return util.warningMsg('实验分钟请勿填写负数') if (minute < 0) return util.warningMsg('考核分钟请勿填写负数')
} }
if (!form.uuid) return util.warningMsg("请选择实训项目"); if (!form.uuid) return util.warningMsg("请选择考核项目");
const item = this.projectData.find(e => form.uuid === e.projectId || form.uuid === e.paperId) const item = this.projectData.find(e => form.uuid === e.projectId || form.uuid === e.paperId)
if (item) form[item.projectId ? 'projectId' : 'paperId'] = form.uuid if (item) form[item.projectId ? 'projectId' : 'paperId'] = form.uuid
if (this.form.isSpecify == 0 && this.form.isEnableCode == 1) { if (this.form.isSpecify == 0 && this.form.isEnableCode == 1) {

@ -64,7 +64,7 @@
<div v-else class="score-wrap"> <div v-else class="score-wrap">
<em>{{ info.score }}</em> <em>{{ info.score }}</em>
<img src="@/assets/img/point.png" alt=""> <img src="@/assets/img/point.png" alt="">
<p v-if="essayExist" class="exist">部分试题待判分成绩待定</p> <p v-if="notReview" class="exist">部分试题待判分成绩待定</p>
</div> </div>
</li> </li>
<li> <li>
@ -96,14 +96,16 @@
</el-table-column> </el-table-column>
<el-table-column prop="userTotalScore" label="得分" align="center"> <el-table-column prop="userTotalScore" label="得分" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<p v-if="scope.row.questionType === 'essay'" class="text-red">待评分</p> <p v-if="scope.row.questionType === 'essay' && scope.row.scoringStatus === '未判分'" class="text-red">待评分
<p v-else-if="essayExist && !scope.row.paperId" class="text-red">{{ scope.row.userTotalScore </p>
<p v-else-if="notReview && !scope.row.paperId" class="text-red">{{ scope.row.userTotalScore
}}部分试题待判分成绩待定</p> }}部分试题待判分成绩待定</p>
<p v-else>{{ scope.row.userTotalScore }}</p> <p v-else>{{ scope.row.userTotalScore }}</p>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="scoreRatePercentage" label="得分率" align="center"> <el-table-column prop="scoreRatePercentage" label="得分率" align="center">
<template slot-scope="scope">{{ scope.row.questionType === 'essay' ? '-' : scope.row.scoreRatePercentage <template slot-scope="scope">{{ scope.row.questionType === 'essay' && scope.row.scoringStatus === '未判分'
? '-' : scope.row.scoreRatePercentage
}}</template> }}</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -127,16 +129,18 @@
<el-tag class="m-r-5" :type="ques.difficultTheme">{{ ques.difficult }}</el-tag> <el-tag class="m-r-5" :type="ques.difficultTheme">{{ ques.difficult }}</el-tag>
<div class="stem html-parse" :id="'stem' + ques.id" v-html="ques.stem"></div> <div class="stem html-parse" :id="'stem' + ques.id" v-html="ques.stem"></div>
<p>{{ ques.questionScore }}</p> <p v-if="!ques.notScored">{{ ques.questionScore }}</p>
</div> </div>
<div <div
v-if="item.questionType !== 'fill_blank' && item.questionType !== 'essay' && ques.questionAnswerVersionsList" v-if="item.questionType !== 'fill_blank' && item.questionType !== 'essay' && ques.questionAnswerVersionsList"
class="m-b-10"> class="m-b-10">
<div v-for="(opt, j) in ques.questionAnswerVersionsList" :key="j" class="opt"> <div v-for="(opt, j) in ques.questionAnswerVersionsList" :key="j" class="opt">
<img v-if="opt.optCorrect === 1" src="@/assets/img/right.svg" alt="" class="icon"> <template v-if="!ques.notScored">
<img v-else-if="!opt.optCorrect" src="@/assets/img/wrong.svg" alt="" class="icon"> <img v-if="opt.optCorrect === 1" src="@/assets/img/right.svg" alt="" class="icon">
<span v-else class="icon not-ans"></span> <img v-else-if="!opt.optCorrect" src="@/assets/img/wrong.svg" alt="" class="icon">
<span v-else class="icon not-ans"></span>
</template>
<span>{{ numToLetter(j) }}.&nbsp;</span> <span>{{ numToLetter(j) }}.&nbsp;</span>
<div class="text html-parse" v-html="opt.optionText"></div> <div class="text html-parse" v-html="opt.optionText"></div>
@ -156,37 +160,46 @@
</template> </template>
<div v-if="ques.knowledgePointList && ques.knowledgePointList.length" class="m-b-10"> <div v-if="ques.knowledgePointList && ques.knowledgePointList.length" class="m-b-10">
<span>知识点</span> <span class="line-label">知识点</span>
<el-tag v-for="(kp, k) in ques.knowledgePointList" :key="k" class="m-r-5" type="info">{{ kp.name <el-tag v-for="(kp, k) in ques.knowledgePointList" :key="k" class="m-r-5" type="info">{{ kp.name
}}</el-tag> }}</el-tag>
</div> </div>
<div class="flex m-b-10"> <div class="flex m-b-10">
<span>解析</span> <span class="line-label">解析</span>
<div <div
v-if="ques.questionAnswerVersionsList.length && ques.questionAnswerVersionsList[0].answerAnalysis" v-if="ques.questionAnswerVersionsList.length && ques.questionAnswerVersionsList[0].answerAnalysis"
v-html="ques.questionAnswerVersionsList[0].answerAnalysis" class="html-parse"></div> v-html="ques.questionAnswerVersionsList[0].answerAnalysis" class="html-parse"></div>
<div v-else>暂无解析</div> <div v-else>暂无解析</div>
</div> </div>
<div :class="['ques-info', { essay: item.questionType === 'essay' }]"> <div
:class="['ques-info', { essay: item.questionType === 'essay' && ques.scoringStatus === '未判分' && !ques.notScored }]">
<!-- 主观题 -->
<template v-if="item.questionType === 'essay'"> <template v-if="item.questionType === 'essay'">
<div class="line"> <div class="line">
<span class="line-label">参考答案</span> <span class="line-label">参考答案</span>
<div v-html="ques.questionAnswerVersionsList[0].referenceAnswer" class="html-parse"></div> <div v-if="ques.questionAnswerVersionsList[0].referenceAnswer"
v-html="ques.questionAnswerVersionsList[0].referenceAnswer" class="html-parse"></div>
<span v-else>暂无参考答案</span>
</div> </div>
<div class="line"> <div class="line">
<span class="line-label">考生答案</span> <span class="line-label">考生答案</span>
<div v-if="ques.answerContent" v-html="ques.answerContent" class="html-parse"></div> <p v-if="!ques.richTextStatus">无需作答</p>
<div v-else>未作答</div> <div v-else-if="ques.answerContent" v-html="ques.answerContent" class="html-parse"></div>
<p v-else>未作答</p>
</div> </div>
<div v-if="ques.attachmentUrl" class="line"> <div v-if="ques.allowAttachment" class="line">
<span class="line-label">考生上传附件</span> <span class="line-label">考生上传附件</span>
<el-link class="m-r-10" type="primary" @click="preview(ques.attachmentUrl)">{{ <template v-if="ques.attachmentUrl">
ques.attachmentName }}</el-link> <el-link class="m-r-10" type="primary" @click="preview(ques.attachmentUrl)">{{
<el-button type="primary" size="mini" round ques.attachmentName }}</el-link>
@click="download(ques.attachmentName, ques.attachmentUrl)">下载</el-button> <el-button type="primary" size="mini" round
@click="download(ques.attachmentName, ques.attachmentUrl)">下载</el-button>
</template>
<span v-else>未上传</span>
</div> </div>
</template> </template>
<!-- 客观题 -->
<template v-else> <template v-else>
<div class="line">正确答案{{ ques.quesAnswer }}</div> <div class="line">正确答案{{ ques.quesAnswer }}</div>
<div class="line"> <div class="line">
@ -195,16 +208,26 @@
<div v-else-if="ques.userAnswerFill" class="fill-answers"> <div v-else-if="ques.userAnswerFill" class="fill-answers">
<p v-for="(ans, j) in ques.userAnswerFill" :key="j" class="fill-answer"> <p v-for="(ans, j) in ques.userAnswerFill" :key="j" class="fill-answer">
填空{{ j + 1 }}{{ ans.studentAnswer || '未作答' }} 填空{{ j + 1 }}{{ ans.studentAnswer || '未作答' }}
<img v-if="ans.correct" src="@/assets/img/right.svg" alt="" class="icon"> <template v-if="!ques.notScored">
<img v-else src="@/assets/img/wrong.svg" alt="" class="icon"> <img v-if="ans.correct" src="@/assets/img/right.svg" alt="" class="icon">
<img v-else src="@/assets/img/wrong.svg" alt="" class="icon">
</template>
</p> </p>
</div> </div>
<span v-else>未作答</span>
</div> </div>
</template> </template>
<div class="line">题目分值{{ ques.questionScore }}</div> <div class="line">题目分值{{ ques.notScored ? '不计分' : ques.questionScore + '分' }}</div>
<div class="line">考生得分<el-input class="score-input" size="small" :value="ques.userScore" <div class="line">考生得分<template v-if="ques.notScored">不计分</template>
disabled /> <template v-else>
<el-input class="score-input" size="small" :value="ques.userScore" disabled />
</template>
</div>
<div v-for="(coment, k) in ques.comment" :key="k" class="line">
<span class="line-label">评语{{ k + 1 }}</span>
<div v-html="coment" class="html-parse"></div>
</div> </div>
</div> </div>
</div> </div>
@ -280,10 +303,15 @@ export default {
id: 4, id: 4,
name: '待判分' name: '待判分'
}, },
{
id: 5,
name: '不计分'
},
], ],
outlines: [], outlines: [],
paper: [], paper: [],
essayExist: 0, essayExist: 0,
notReview: 0,
previewImgVisible: false, previewImgVisible: false,
previewImg: '', previewImg: '',
pdfVisible: false, pdfVisible: false,
@ -305,8 +333,12 @@ export default {
const { questionTypes: types, difficults } = QuesConst const { questionTypes: types, difficults } = QuesConst
const { numToLetter } = Util const { numToLetter } = Util
let essayExist = 0 let essayExist = 0
let notReview = 0
outline.map(e => { outline.map(e => {
if (e.questionType === 'essay') essayExist = 1 if (e.questionType === 'essay') {
essayExist = 1
if (e.scoringStatus === '未判分') notReview = 1
}
e.shrink = false e.shrink = false
const type = e.questionType const type = e.questionType
e.questionTypeName = types.find(n => n.id === type).name e.questionTypeName = types.find(n => n.id === type).name
@ -319,10 +351,12 @@ export default {
} }
} }
n.notScored = n.questionScore === 0 // =0
if (n.notScored) n.userScore = '-'
const opts = n.questionAnswerVersionsList const opts = n.questionAnswerVersionsList
if (type !== 'fill_blank' && type !== 'essay') { // if (type !== 'fill_blank' && type !== 'essay') { //
if (!n.userScore) n.userScore = 0 if (!n.userScore) n.userScore = 0
n.isCorrect = n.userScore && n.userScore === n.questionScore ? 1 : 2 this.handleIsCorrect(n)
// //
let { userAnswer } = n let { userAnswer } = n
@ -367,14 +401,15 @@ export default {
// //
let rightLen = 0 let rightLen = 0
if (n.userAnswerFill) rightLen = n.userAnswerFill.filter(m => m.correct).length // if (n.userAnswerFill) rightLen = n.userAnswerFill.filter(m => m.correct).length //
n.isCorrect = n.userScore && n.questionScore === n.userScore ? 1 : (rightLen ? 3 : 2) n.isCorrect = n.notScored ? 5 : (n.userScore && n.questionScore === n.userScore ? 1 : (rightLen ? 3 : 2))
} else if (type === 'essay') { // } else if (type === 'essay') { //
n.isCorrect = 4 // this.handleIsCorrect(n)
} }
}) })
}) })
this.essayExist = essayExist // this.essayExist = essayExist //
this.notReview = notReview //
this.paper = outline this.paper = outline
this.outlines = [ this.outlines = [
...outline, ...outline,
@ -402,6 +437,10 @@ export default {
this.loading = false this.loading = false
} }
}, },
//
handleIsCorrect (n) {
n.isCorrect = n.notScored ? 5 : (n.userScore === undefined ? 4 : (n.userScore === n.questionScore ? 1 : n.userScore ? 3 : 2)) // reviewScore 0
},
scrollToSmooth (position, duration) { scrollToSmooth (position, duration) {
let startTime = Date.now() let startTime = Date.now()
@ -464,10 +503,44 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.wrap {
padding: 10px;
}
.text-right {
text-align: right;
}
.text-red { .text-red {
color: #f00; color: #f00;
} }
code,
kbd,
samp {
font-family: 'PingFang SC', 'Helvetica Neue', Helvetica, 'microsoft yahei', arial, STHeiTi, sans-serif;
word-wrap: break-word;
white-space: pre-wrap;
}
/deep/ pre {
white-space: pre-wrap;
/* css-3 */
white-space: -moz-pre-wrap;
/* Mozilla, since 1999 */
white-space: pre-wrap;
/* Opera 4-6 */
white-space: -o-pre-wrap;
/* Opera 7 */
word-wrap: break-word;
/* Internet Explorer 5.5+ */
word-break: break-all;
overflow: hidden;
font-size: 12px;
font-weight: 400;
font-family: 'PingFang SC', 'Helvetica Neue', Helvetica, 'microsoft yahei', arial, STHeiTi, sans-serif;
}
/deep/.report { /deep/.report {
display: flex; display: flex;
@ -582,7 +655,7 @@ export default {
} }
.left { .left {
width: 290px; width: 320px;
margin-right: 15px; margin-right: 15px;
background-color: #fff; background-color: #fff;
@ -621,7 +694,7 @@ export default {
li { li {
position: relative; position: relative;
width: 30px; min-width: 30px;
margin: 7px 9px; margin: 7px 9px;
font-size: 13px; font-size: 13px;
text-align: center; text-align: center;
@ -662,8 +735,15 @@ export default {
border-color: #fe9f0a; border-color: #fe9f0a;
} }
.status5 .serial {
color: #fff;
background-color: #d1d1d1;
border-color: #d1d1d1;
}
.score { .score {
height: 22px; height: 22px;
padding: 0 2px;
border: 1px solid #d3d3d3; border: 1px solid #d3d3d3;
border-top: 0; border-top: 0;
line-height: 22px; line-height: 22px;
@ -673,7 +753,7 @@ export default {
.status-filter { .status-filter {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
padding: 10px; padding: 10px 0;
border-top: 1px solid #e5e5e5; border-top: 1px solid #e5e5e5;
li { li {
@ -683,6 +763,7 @@ export default {
font-size: 12px; font-size: 12px;
color: #333; color: #333;
cursor: pointer; cursor: pointer;
white-space: nowrap;
border: 1px solid transparent; border: 1px solid transparent;
&:before { &:before {
@ -726,7 +807,7 @@ export default {
} }
} }
&:last-child { &:nth-child(4) {
&.active { &.active {
color: #fe9f0a; color: #fe9f0a;
border-color: #fe9f0a; border-color: #fe9f0a;
@ -737,6 +818,17 @@ export default {
} }
} }
&:last-child {
&.active {
color: #d1d1d1;
border-color: #d1d1d1;
}
&:before {
background-color: #d1d1d1;
}
}
&.active { &.active {
font-weight: 600; font-weight: 600;
} }
@ -745,7 +837,7 @@ export default {
} }
.right { .right {
width: calc(100% - 305px); width: calc(100% - 355px);
height: calc(100vh - 287px); height: calc(100vh - 287px);
padding: 10px; padding: 10px;
background-color: #fff; background-color: #fff;

Loading…
Cancel
Save