Implemented teacher view for competencies
This commit is contained in:
parent
456e9b503e
commit
96caeb895a
16 changed files with 233 additions and 181 deletions
2
amd/build/page-edit-plan.min.js
vendored
2
amd/build/page-edit-plan.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/report-viewer-components.min.js
vendored
2
amd/build/report-viewer-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/studyplan-editor-components.min.js
vendored
2
amd/build/studyplan-editor-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -64,12 +64,13 @@ export function init(contextid,categoryid,options) {
|
||||||
if ( !options.defaultAggregation ) {
|
if ( !options.defaultAggregation ) {
|
||||||
options.defaultAggregation = "core";
|
options.defaultAggregation = "core";
|
||||||
}
|
}
|
||||||
|
if ( !options.editMode ) {
|
||||||
|
options.editMode = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
options = { defaultAggregation: "core"};
|
options = { defaultAggregation: "core", editMode: false};
|
||||||
}
|
}
|
||||||
|
|
||||||
const in_systemcontext = (contextid <= 1);
|
|
||||||
|
|
||||||
// Setup the initial Vue app for this page
|
// Setup the initial Vue app for this page
|
||||||
let app = new Vue({
|
let app = new Vue({
|
||||||
el: '#root',
|
el: '#root',
|
||||||
|
@ -100,6 +101,7 @@ export function init(contextid,categoryid,options) {
|
||||||
courses: [],
|
courses: [],
|
||||||
text: strings.studyplan,
|
text: strings.studyplan,
|
||||||
usedcontexts: [],
|
usedcontexts: [],
|
||||||
|
initialEditMode: !!options.editMode,
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.$root.$on('studyplanRemoved',(studyplan)=>{
|
this.$root.$on('studyplanRemoved',(studyplan)=>{
|
||||||
|
|
|
@ -16,8 +16,8 @@ import {svgarcpath} from './util/svgarc';
|
||||||
import Debugger from './util/debugger';
|
import Debugger from './util/debugger';
|
||||||
import Config from 'core/config';
|
import Config from 'core/config';
|
||||||
import {ProcessStudyplan, ProcessStudyplanPage, objCopy} from './studyplan-processor';
|
import {ProcessStudyplan, ProcessStudyplanPage, objCopy} from './studyplan-processor';
|
||||||
|
|
||||||
import TSComponents from './treestudyplan-components';
|
import TSComponents from './treestudyplan-components';
|
||||||
|
import {eventTypes as editSwEventTypes} from 'core/edit_switch';
|
||||||
|
|
||||||
// Make π available as a constant
|
// Make π available as a constant
|
||||||
const π = Math.PI;
|
const π = Math.PI;
|
||||||
|
@ -180,6 +180,13 @@ export default {
|
||||||
// Create new eventbus for interaction between item components
|
// Create new eventbus for interaction between item components
|
||||||
const ItemEventBus = new Vue();
|
const ItemEventBus = new Vue();
|
||||||
|
|
||||||
|
// Add event listener for the edit mode event so we can react to it, or at the very least ignore it
|
||||||
|
document.addEventListener(editSwEventTypes.editModeSet,(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
ItemEventBus.$emit('editModeSet',e.detail.editMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
Vue.component('r-progress-circle',{
|
Vue.component('r-progress-circle',{
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
|
@ -1606,11 +1613,15 @@ export default {
|
||||||
</tr>
|
</tr>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<tr v-for='c in value.competencies'>
|
<tr v-for='c in value.competencies'>
|
||||||
<td :colspan="(c.details)?1:2">
|
<td>
|
||||||
<a href="#" v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.title'></span></a>
|
<a href="#" v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.title'></span></a>
|
||||||
</td>
|
</td>
|
||||||
<td class='details' v-if="c.details">
|
<td class='details' >
|
||||||
<a href="#" v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.details'></span></a>
|
<a v-if="c.details" href="#" v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.details'></span></a>
|
||||||
|
<abbr v-if="c.required" :title="text.required"
|
||||||
|
:class="'s-required ' + + completion_tag(c)"
|
||||||
|
><i class='fa fa-asterisk' ></i
|
||||||
|
></abbr>
|
||||||
</td>
|
</td>
|
||||||
<td :colspan="(c.required)?1:2">
|
<td :colspan="(c.required)?1:2">
|
||||||
<span :class="'r-completion-'+completion_tag(c)">
|
<span :class="'r-completion-'+completion_tag(c)">
|
||||||
|
@ -1630,9 +1641,6 @@ export default {
|
||||||
</template>
|
</template>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="c.required">
|
|
||||||
<span class="text-danger" v-if="c.required">{{ text.required }}</span>
|
|
||||||
</td>
|
|
||||||
<td v-if="c.feedback">
|
<td v-if="c.feedback">
|
||||||
<a v-b-modal="'r-competency-feedback-'+c.id"
|
<a v-b-modal="'r-competency-feedback-'+c.id"
|
||||||
href="#"
|
href="#"
|
||||||
|
@ -1675,17 +1683,22 @@ export default {
|
||||||
<th colspan="3">{{text.results}}</th>
|
<th colspan="3">{{text.results}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="cc in c.children">
|
<tr v-for="cc in c.children">
|
||||||
<td :colspan="(c.details)?1:2" >
|
<td >
|
||||||
<a :href='competencyurl(c)' target="_blank"><span v-html='cc.title'></span></a>
|
<a :href='competencyurl(c)' target="_blank"><span v-html='cc.title'></span></a>
|
||||||
</td>
|
</td>
|
||||||
<td class='details' v-if="cc.details">
|
<td class='details'>
|
||||||
<a :href='competencyurl(c)' target="_blank"><span v-html='cc.details'></span></a>
|
<a v-if="cc.details" :href='competencyurl(c)' target="_blank"><span v-html='cc.details'></span></a>
|
||||||
|
<abbr v-if="c.required" :title="text.required"
|
||||||
|
:class="'s-required ' + + completion_tag(cc)"
|
||||||
|
><i class='fa fa-asterisk' ></i
|
||||||
|
></abbr>
|
||||||
</td>
|
</td>
|
||||||
<td><span :class="'r-completion-'+completion_tag(cc)"
|
<td><span :class="'r-completion-'+completion_tag(cc)"
|
||||||
><i :class="'fa fa-'+completion_icon(cc)" :title="text['completion_'+completion_tag(cc)]"></i>
|
><i :class="'fa fa-'+completion_icon(cc)" :title="text['completion_'+completion_tag(cc)]"></i>
|
||||||
{{ (cc.proficient === null)?text.unrated:cc.grade }}</span></td>
|
{{ (cc.proficient === null)?text.unrated:cc.grade }}</span></td>
|
||||||
<td><span class="text-info">{{ cc.points }} {{ text.points }}</span></td>
|
<td><span class="text-info">{{ cc.points }} {{ text.points }}</span></td>
|
||||||
<td><span class="text-danger" v-if='cc.required'>{{ text.required }}</span></td>
|
<td>
|
||||||
|
</td>
|
||||||
<td v-if="cc.feedback">
|
<td v-if="cc.feedback">
|
||||||
<a v-b-modal="'r-competency-feedback-'+cc.id"
|
<a v-b-modal="'r-competency-feedback-'+cc.id"
|
||||||
href="#"
|
href="#"
|
||||||
|
@ -1782,10 +1795,10 @@ export default {
|
||||||
ungraded: 0,
|
ungraded: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if(this.value.course.completion){
|
if(this.value.course.completion) {
|
||||||
for(const cond of this.value.course.completion.conditions){
|
for(const cond of this.value.course.completion.conditions) {
|
||||||
for(const itm of cond.items){
|
for(const itm of cond.items) {
|
||||||
if(itm.progress){
|
if(itm.progress) {
|
||||||
status.students += itm.progress.students;
|
status.students += itm.progress.students;
|
||||||
status.completed += itm.progress.completed;
|
status.completed += itm.progress.completed;
|
||||||
status.completed_pass += itm.progress.completed_pass;
|
status.completed_pass += itm.progress.completed_pass;
|
||||||
|
@ -1794,10 +1807,12 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (this.value.course.competency) {
|
||||||
} else if (this.value.course.grades){
|
status.students = this.value.course.competency.total;
|
||||||
for( const g of this.value.course.grades){
|
status.completed = this.value.course.competency.proficient;
|
||||||
if(g.grading){
|
} else if (this.value.course.grades) {
|
||||||
|
for( const g of this.value.course.grades) {
|
||||||
|
if(g.grading) {
|
||||||
status.students += g.grading.students;
|
status.students += g.grading.students;
|
||||||
status.completed += g.grading.completed;
|
status.completed += g.grading.completed;
|
||||||
status.completed_pass += g.grading.completed_pass;
|
status.completed_pass += g.grading.completed_pass;
|
||||||
|
@ -2276,7 +2291,7 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
//TAG: Course competency
|
//TAG: Teacher Course competency
|
||||||
Vue.component('r-item-teacher-course-competency',{
|
Vue.component('r-item-teacher-course-competency',{
|
||||||
props: {
|
props: {
|
||||||
value : {
|
value : {
|
||||||
|
@ -2313,23 +2328,30 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
completion_icon(completion) {
|
completion_icon(competency) {
|
||||||
switch(completion){
|
if (competency.proficient && competency.courseproficient) {
|
||||||
case "progress":
|
return "check-circle";
|
||||||
return "exclamation-circle";
|
} else if (competency.proficient) {
|
||||||
case "complete":
|
return "check";
|
||||||
return "check-circle";
|
} else if (competency.proficient === false) {
|
||||||
case "complete-pass":
|
return "times-circle";
|
||||||
return "check-circle";
|
} else {
|
||||||
case "complete-fail":
|
return "circle-o";
|
||||||
return "times-circle";
|
|
||||||
default: // case "incomplete"
|
|
||||||
return "circle-o";
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
completion_tag(cgroup){
|
completion_tag(competency){
|
||||||
return cgroup.completion?'completed':'incomplete';
|
if (competency.proficient && competency.courseproficient) {
|
||||||
|
return "completed";
|
||||||
|
} else if (competency.proficient) {
|
||||||
|
return "completed";
|
||||||
|
} else if (competency.proficient === false) {
|
||||||
|
return "failed";
|
||||||
|
} else if (competency.progress) {
|
||||||
|
return "progress";
|
||||||
|
} else {
|
||||||
|
return "incomplete";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
pathtags(competency) {
|
pathtags(competency) {
|
||||||
|
@ -2342,48 +2364,55 @@ export default {
|
||||||
}
|
}
|
||||||
let url;
|
let url;
|
||||||
if (p.type =='competency') {
|
if (p.type =='competency') {
|
||||||
url = `/admin/tool/lp/competencies.php?competencyid=${p.id}`;
|
url = `/admin/tool/lp/user_competency_in_course.php?courseid=${this.item.course.id}&competencyid=${p.id}`;
|
||||||
} else {
|
} else {
|
||||||
url = `/admin/tool/lp/competencies.php?competencyframeworkid=${p.id}&pagecontextid=${p.contextid}`;
|
url = this.competencyurl(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
s += `<a href="${url}">${p.title}</a>`;
|
s += `<a href="${url}" target="_blank">${p.title}</a>`;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
},
|
},
|
||||||
requiredChanged(newValue,c){
|
competencyurl(c) {
|
||||||
call([{
|
return `/admin/tool/lp/user_competency_in_course.php?courseid=${this.item.course.id}&competencyid=${c.id}`;
|
||||||
methodname: 'local_treestudyplan_require_competency',
|
}
|
||||||
args: { 'competency_id': c.id,
|
|
||||||
'item_id': this.item.id,
|
|
||||||
'required': newValue,
|
|
||||||
}
|
|
||||||
}])[0].fail(notification.exception);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<table class="t-item-course-competency-list">
|
<table class="r-item-course-competency-list">
|
||||||
<tr v-if="value.competencies.length == 0">
|
<tr v-if="value.competencies.length == 0">
|
||||||
<td colspan='2'>{{text.competencies_not_configured}}!
|
<td colspan='2'>{{text.competencies_not_configured}}!
|
||||||
<br><a :href="'/admin/tool/lp/coursecompetencies.php?courseid='+item.course.id" target='_blank'>{{text.configure_competencies}}</a>
|
<br><a :href="'/admin/tool/lp/coursecompetencies.php?courseid='+item.course.id" target='_blank'>{{text.configure_competencies}}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<tr class='t-item-course-competency-headers'>
|
|
||||||
<th>{{text.heading}}</th>
|
|
||||||
<th></th>
|
|
||||||
<th>{{text.required}}</th>
|
|
||||||
</tr>
|
|
||||||
<tr v-for='c in value.competencies'>
|
<tr v-for='c in value.competencies'>
|
||||||
<td :colspan="(c.details)?1:2"><a href='#' v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.title'></span></a></td>
|
|
||||||
<td class='details' v-if="c.details">
|
|
||||||
<a href='#' v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.details'></span></a>
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<b-form-checkbox inline
|
<a href="#" v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.title'></span></a>
|
||||||
@change="requiredChanged($event,c)"
|
</td>
|
||||||
v-model="c.required"
|
<td class='details'>
|
||||||
>{{ text.required }}</b-form-checkbox>
|
<a v-if="c.details" href="#" v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.details'></span></a>
|
||||||
|
<abbr v-if="c.required" :title="text.required"
|
||||||
|
:class="'s-required ' + + completion_tag(c)"
|
||||||
|
><i class='fa fa-asterisk' ></i
|
||||||
|
></abbr>
|
||||||
|
</td>
|
||||||
|
<td><r-completion-bar v-model="c.completionstats" :width="150" :height="15"></td>
|
||||||
|
<td v-if="c.feedback">
|
||||||
|
<a v-b-modal="'r-competency-feedback-'+c.id"
|
||||||
|
href="#"
|
||||||
|
>{{ text["view_feedback"]}}</a>
|
||||||
|
<b-modal
|
||||||
|
:id="'r-competency-feedback-'+c.id"
|
||||||
|
size="sm"
|
||||||
|
ok-only
|
||||||
|
centered
|
||||||
|
scrollable
|
||||||
|
>
|
||||||
|
<template #modal-header>
|
||||||
|
<h2><i class="fa fa-puzzle-piece"></i>{{ c.title }}</h2><br>
|
||||||
|
</template>
|
||||||
|
<span v-html="c.feedback"></span>
|
||||||
|
</b-modal>
|
||||||
</td>
|
</td>
|
||||||
<b-modal :id="'modal-competency-id-'+c.id"
|
<b-modal :id="'modal-competency-id-'+c.id"
|
||||||
size="lg"
|
size="lg"
|
||||||
|
@ -2404,17 +2433,41 @@ export default {
|
||||||
|
|
||||||
<template v-if="c.rule && c.children">
|
<template v-if="c.rule && c.children">
|
||||||
<div>{{ c.ruleoutcome }} {{ text.when}} <span v-html="c.rule.toLocaleLowerCase()"></span></div>
|
<div>{{ c.ruleoutcome }} {{ text.when}} <span v-html="c.rule.toLocaleLowerCase()"></span></div>
|
||||||
<table v-if="c.children" class='t-item-course-competency-list'>
|
<table v-if="c.children" class='r-item-course-competency-list'>
|
||||||
<tr class='t-item-course-competency-headers'>
|
<tr class='t-item-course-competency-headers'>
|
||||||
<th>{{text.heading}}</th>
|
<th colspan="2">{{text.heading}}</th>
|
||||||
<th></th>
|
<th colspan="3">{{text.results}}</th>
|
||||||
<th>{{text.required}}</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="cc in c.children">
|
<tr v-for="cc in c.children">
|
||||||
<td :colspan="(c.details)?1:2" ><span v-html='cc.title'></span></td>
|
<td>
|
||||||
<td class='details' v-if="cc.details"><span v-html='cc.details'></span></td>
|
<a :href='competencyurl(c)' target="_blank"><span v-html='cc.title'></span></a>
|
||||||
|
</td>
|
||||||
|
<td class='details'>
|
||||||
|
<a v-if="cc.details" :href='competencyurl(c)' target="_blank"><span v-html='cc.details'></span></a>
|
||||||
|
<abbr v-if="c.required" :title="text.required"
|
||||||
|
:class="'s-required ' + completion_tag(cc)"
|
||||||
|
><i class='fa fa-asterisk' ></i
|
||||||
|
></abbr>
|
||||||
|
</td>
|
||||||
|
<td><r-completion-bar v-model="cc.completionstats" :width="150" :height="15"></r-completion-bar></td>
|
||||||
<td><span class="text-info">{{ cc.points }} {{ text.points }}</span></td>
|
<td><span class="text-info">{{ cc.points }} {{ text.points }}</span></td>
|
||||||
<td><span class="text-danger" v-if='cc.required'>{{ text.required }}</span></td>
|
<td v-if="cc.feedback">
|
||||||
|
<a v-b-modal="'r-competency-feedback-'+cc.id"
|
||||||
|
href="#"
|
||||||
|
>{{ text["view_feedback"]}}</a>
|
||||||
|
<b-modal
|
||||||
|
:id="'r-competency-feedback-'+cc.id"
|
||||||
|
size="sm"
|
||||||
|
ok-only
|
||||||
|
centered
|
||||||
|
scrollable
|
||||||
|
>
|
||||||
|
<template #modal-header>
|
||||||
|
<h2><i class="fa fa-puzzle-piece"></i>{{ cc.title }}</h2><br>
|
||||||
|
</template>
|
||||||
|
<span v-html="cc.feedback"></span>
|
||||||
|
</b-modal>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2426,7 +2479,6 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Vue.component('r-grading-bar',{
|
Vue.component('r-grading-bar',{
|
||||||
props: {
|
props: {
|
||||||
value : {
|
value : {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {objCopy,transportItem} from './studyplan-processor';
|
||||||
import Debugger from './util/debugger';
|
import Debugger from './util/debugger';
|
||||||
import {download,upload} from './downloader';
|
import {download,upload} from './downloader';
|
||||||
import {ProcessStudyplan, ProcessStudyplanPage} from './studyplan-processor';
|
import {ProcessStudyplan, ProcessStudyplanPage} from './studyplan-processor';
|
||||||
|
import {eventTypes as editSwEventTypes} from 'core/edit_switch';
|
||||||
|
|
||||||
import TSComponents from './treestudyplan-components';
|
import TSComponents from './treestudyplan-components';
|
||||||
import mFormComponents from "./util/mform-helper";
|
import mFormComponents from "./util/mform-helper";
|
||||||
|
@ -42,7 +43,6 @@ export default {
|
||||||
Vue.use(TSComponents);
|
Vue.use(TSComponents);
|
||||||
Vue.use(mFormComponents);
|
Vue.use(mFormComponents);
|
||||||
let debug = new Debugger("treestudyplan-editor");
|
let debug = new Debugger("treestudyplan-editor");
|
||||||
|
|
||||||
/************************************
|
/************************************
|
||||||
* *
|
* *
|
||||||
* Treestudyplan Editor components *
|
* Treestudyplan Editor components *
|
||||||
|
@ -58,10 +58,15 @@ export default {
|
||||||
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
|
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Create new eventbus for interaction between item components
|
// Create new eventbus for interaction between item components
|
||||||
const ItemEventBus = new Vue();
|
const ItemEventBus = new Vue();
|
||||||
|
|
||||||
|
// Add event listener for the edit mode event so we can react to it, or at the very least ignore it
|
||||||
|
document.addEventListener(editSwEventTypes.editModeSet,(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
ItemEventBus.$emit('editModeSet', e.detail.editMode);
|
||||||
|
});
|
||||||
|
|
||||||
let string_keys = load_stringkeys({
|
let string_keys = load_stringkeys({
|
||||||
conditions: [
|
conditions: [
|
||||||
{ value: 'ALL', textkey: 'condition_all'},
|
{ value: 'ALL', textkey: 'condition_all'},
|
||||||
|
@ -249,10 +254,8 @@ export default {
|
||||||
dateexpire: "dateexpire",
|
dateexpire: "dateexpire",
|
||||||
badgeinfo: "badgeinfo",
|
badgeinfo: "badgeinfo",
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* T-STUDYPLAN-ADVANCED
|
* T-STUDYPLAN-ADVANCED
|
||||||
*/
|
*/
|
||||||
|
@ -282,7 +285,6 @@ export default {
|
||||||
mounted() {
|
mounted() {
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
scales(){
|
scales(){
|
||||||
|
@ -1184,7 +1186,7 @@ export default {
|
||||||
* T-STUDYPLAN
|
* T-STUDYPLAN
|
||||||
*/
|
*/
|
||||||
Vue.component('t-studyplan', {
|
Vue.component('t-studyplan', {
|
||||||
props: [ 'value', 'index', ],
|
props: [ 'value', 'index', 'initeditmode'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
config: {
|
config: {
|
||||||
|
@ -1257,13 +1259,16 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
// Listener for the signal that a new connection was made and needs to be drawn
|
||||||
|
// Sent by the incoming item - By convention, outgoing items are responsible for drawing the lines
|
||||||
|
ItemEventBus.$on('editModeSet', this.onMoodleEditModeChanged);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if(this.value.pages[0].studylines.length == 0){
|
/*if(this.value.pages[0].studylines.length == 0){
|
||||||
// start in editmode if studylines on first page are empty
|
// start in editmode if studylines on first page are empty
|
||||||
this.edit.studyline.editmode = true;
|
this.edit.studyline.editmode = true;
|
||||||
}
|
}*/
|
||||||
|
this.edit.studyline.editmode = this.initeditmode;
|
||||||
this.$root.$emit('redrawLines');
|
this.$root.$emit('redrawLines');
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
|
@ -1276,6 +1281,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
onMoodleEditModeChanged(mode){
|
||||||
|
this.edit.studyline.editmode = mode;
|
||||||
|
},
|
||||||
columns(page) {
|
columns(page) {
|
||||||
return 1+ (page.periods * 2);
|
return 1+ (page.periods * 2);
|
||||||
},
|
},
|
||||||
|
@ -1522,11 +1530,11 @@ export default {
|
||||||
selectedpageChanged(newTabIndex,prevTabIndex) {
|
selectedpageChanged(newTabIndex,prevTabIndex) {
|
||||||
const page = this.value.pages[newTabIndex];
|
const page = this.value.pages[newTabIndex];
|
||||||
|
|
||||||
|
/*
|
||||||
if (page.studylines.length == 0) {
|
if (page.studylines.length == 0) {
|
||||||
this.edit.studyline.editmode = true;
|
this.edit.studyline.editmode = true;
|
||||||
} else {
|
|
||||||
this.edit.studyline.editmode = false;
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
|
|
@ -186,6 +186,23 @@ abstract class aggregator {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if Aggregation method makes use of "required grades" in a course/module.
|
||||||
|
* @return bool True if Aggregation method makes use of "required grades" in a course/module.
|
||||||
|
*/
|
||||||
|
public function use_required_grades(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if aggregation method makes use of item conditions
|
||||||
|
* @return bool True if aggregation method makes use of
|
||||||
|
*/
|
||||||
|
public function use_item_conditions(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the current configuration string.
|
* Return the current configuration string.
|
||||||
* @return string Configuration string
|
* @return string Configuration string
|
||||||
|
@ -201,6 +218,8 @@ abstract class aggregator {
|
||||||
*/
|
*/
|
||||||
public static function basic_structure($value = VALUE_REQUIRED) : \external_description {
|
public static function basic_structure($value = VALUE_REQUIRED) : \external_description {
|
||||||
return new \external_single_structure([
|
return new \external_single_structure([
|
||||||
|
"useRequiredGrades" => new \external_value(PARAM_BOOL, 'id of studyplan'),
|
||||||
|
"useItemConditions" => new \external_value(PARAM_BOOL, 'name of studyplan'),
|
||||||
], "Aggregator requirements", $value);
|
], "Aggregator requirements", $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +229,8 @@ abstract class aggregator {
|
||||||
*/
|
*/
|
||||||
public function basic_model() {
|
public function basic_model() {
|
||||||
return [
|
return [
|
||||||
|
"useRequiredGrades" => $this->use_required_grades(),
|
||||||
|
"useItemConditions" => $this->use_item_conditions(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ use core_competency\competency;
|
||||||
use core_competency\api as c_api;
|
use core_competency\api as c_api;
|
||||||
use core_competency\competency_rule_points;
|
use core_competency\competency_rule_points;
|
||||||
use core_competency\evidence;
|
use core_competency\evidence;
|
||||||
|
use core_competency\user_competency;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,6 +64,29 @@ class coursecompetencyinfo {
|
||||||
$this->modinfo = get_fast_modinfo($this->course);
|
$this->modinfo = get_fast_modinfo($this->course);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webservice structure for completion stats
|
||||||
|
* @param int $value Webservice requirement constant
|
||||||
|
*/
|
||||||
|
public static function completionstats_structure($value = VALUE_OPTIONAL) : \external_description {
|
||||||
|
return new \external_single_structure([
|
||||||
|
"ungraded" => new \external_value(PARAM_INT, 'number of ungraded submissions'),
|
||||||
|
"completed" => new \external_value(PARAM_INT, 'number of completed students'),
|
||||||
|
"students" => new \external_value(PARAM_INT, 'number of students that should submit'),
|
||||||
|
"completed_pass" => new \external_value(PARAM_INT, 'number of completed-pass students'),
|
||||||
|
"completed_fail" => new \external_value(PARAM_INT, 'number of completed-fail students'),
|
||||||
|
], "details about gradable submissions", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function completionstats($stats){
|
||||||
|
return [
|
||||||
|
"students" => $stats->count,
|
||||||
|
"completed" => 0,
|
||||||
|
"ungraded" => $stats->nneedreview,
|
||||||
|
"completed_pass" => $stats->nproficient,
|
||||||
|
"completed_fail" => $stats->nfailed,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic competency info structure for individual competency stats
|
* Generic competency info structure for individual competency stats
|
||||||
|
@ -85,8 +109,8 @@ class coursecompetencyinfo {
|
||||||
"coursegrade" => new \external_value(PARAM_TEXT, 'course competency grade', VALUE_OPTIONAL),
|
"coursegrade" => new \external_value(PARAM_TEXT, 'course competency grade', VALUE_OPTIONAL),
|
||||||
"proficient" => new \external_value(PARAM_BOOL, 'competency proficiency',VALUE_OPTIONAL),
|
"proficient" => new \external_value(PARAM_BOOL, 'competency proficiency',VALUE_OPTIONAL),
|
||||||
"courseproficient" => new \external_value(PARAM_BOOL, 'course competency proficiency',VALUE_OPTIONAL),
|
"courseproficient" => new \external_value(PARAM_BOOL, 'course competency proficiency',VALUE_OPTIONAL),
|
||||||
"nproficient" => new \external_value(PARAM_INT, 'number of students with proficiency',VALUE_OPTIONAL),
|
"needreview" => new \external_value(PARAM_BOOL, 'waiting for review or review in progress',VALUE_OPTIONAL),
|
||||||
"ncourseproficient" => new \external_value(PARAM_INT, 'number of students with course proficiency',VALUE_OPTIONAL),
|
"completionstats" => static::completionstats_structure(VALUE_OPTIONAL),
|
||||||
"count" => new \external_value(PARAM_INT, 'number of students in stats',VALUE_OPTIONAL),
|
"count" => new \external_value(PARAM_INT, 'number of students in stats',VALUE_OPTIONAL),
|
||||||
"required" => new \external_value(PARAM_BOOL, 'if required in parent competency rule',VALUE_OPTIONAL),
|
"required" => new \external_value(PARAM_BOOL, 'if required in parent competency rule',VALUE_OPTIONAL),
|
||||||
"points" => new \external_value(PARAM_INT, 'number of points in parent competency rule',VALUE_OPTIONAL),
|
"points" => new \external_value(PARAM_INT, 'number of points in parent competency rule',VALUE_OPTIONAL),
|
||||||
|
@ -107,8 +131,8 @@ class coursecompetencyinfo {
|
||||||
public static function editor_structure($value = VALUE_REQUIRED) : \external_description {
|
public static function editor_structure($value = VALUE_REQUIRED) : \external_description {
|
||||||
return new \external_single_structure([
|
return new \external_single_structure([
|
||||||
"competencies" => new \external_multiple_structure(self::competencyinfo_structure(), 'competencies'),
|
"competencies" => new \external_multiple_structure(self::competencyinfo_structure(), 'competencies'),
|
||||||
"fproficient" => new \external_value(PARAM_FLOAT, 'fraction of completion for total course proficiency ',VALUE_OPTIONAL),
|
"proficient" => new \external_value(PARAM_INT, 'number of proficient user/competencys ',VALUE_OPTIONAL),
|
||||||
"fcourseproficient" => new \external_value(PARAM_FLOAT, 'fraction of completion for total course proficienct',VALUE_OPTIONAL),
|
"total" => new \external_value(PARAM_INT, 'total number of gradable user/competencies',VALUE_OPTIONAL),
|
||||||
], 'course completion info', $value);
|
], 'course completion info', $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,19 +219,19 @@ class coursecompetencyinfo {
|
||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$nproficient = 0;
|
$nproficient = 0;
|
||||||
$ncourseproficient = 0;
|
|
||||||
|
|
||||||
foreach($coursecompetencies as $c) {
|
foreach($coursecompetencies as $c) {
|
||||||
$ci = $this->competencyinfo_model($c);
|
$ci = $this->competencyinfo_model($c);
|
||||||
if(!empty($studentslist)){
|
if(!empty($studentlist)){
|
||||||
$stats = $this->proficiency_stats($c,$studentlist);
|
$stats = $this->proficiency_stats($c,$studentlist);
|
||||||
$count += $stats->count;
|
$count += $stats->count;
|
||||||
$nproficient += $stats->nproficient;
|
$nproficient += $stats->nproficient;
|
||||||
$ncourseproficient += $stats->ncourseproficient;
|
|
||||||
// Copy proficiency stats to model.
|
// Copy proficiency stats to model.
|
||||||
foreach ((array)$stats as $key => $value) {
|
foreach ((array)$stats as $key => $value) {
|
||||||
$ci[$key] = $value;
|
$ci[$key] = $value;
|
||||||
}
|
}
|
||||||
|
$ci['completionstats'] = self::completionstats($stats);
|
||||||
|
|
||||||
}
|
}
|
||||||
$ci['required'] = $this->is_required($c);
|
$ci['required'] = $this->is_required($c);
|
||||||
|
|
||||||
|
@ -249,6 +273,10 @@ class coursecompetencyinfo {
|
||||||
foreach($dids as $did) {
|
foreach($dids as $did) {
|
||||||
$cc = new competency($did);
|
$cc = new competency($did);
|
||||||
$cci = $this->competencyinfo_model($cc);
|
$cci = $this->competencyinfo_model($cc);
|
||||||
|
if(!empty($studentlist)){
|
||||||
|
$stats = $this->proficiency_stats($cc,$studentlist);
|
||||||
|
$cci['completionstats'] = self::completionstats($stats);
|
||||||
|
}
|
||||||
if($rule instanceof competency_rule_points) {
|
if($rule instanceof competency_rule_points) {
|
||||||
if(array_key_exists($did,$crlist)) {
|
if(array_key_exists($did,$crlist)) {
|
||||||
$cr = $crlist[$did];
|
$cr = $crlist[$did];
|
||||||
|
@ -267,9 +295,9 @@ class coursecompetencyinfo {
|
||||||
$info = [
|
$info = [
|
||||||
"competencies" => $cis,
|
"competencies" => $cis,
|
||||||
];
|
];
|
||||||
if(!empty($studentslist)){
|
if(!empty($studentlist)){
|
||||||
$info["fproficient"] = (float)($nproficient)/(float)($count);
|
$info["proficient"] = $nproficient;
|
||||||
$info["fcourseproficient"] = (float)($ncourseproficient)/(float)($count);
|
$info["total"] = $count;
|
||||||
}
|
}
|
||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
@ -413,12 +441,16 @@ class coursecompetencyinfo {
|
||||||
$r->count = 0;
|
$r->count = 0;
|
||||||
$r->nproficient = 0;
|
$r->nproficient = 0;
|
||||||
$r->ncourseproficient = 0;
|
$r->ncourseproficient = 0;
|
||||||
|
$r->nneedreview = 0;
|
||||||
|
$r->nfailed = 0;
|
||||||
|
|
||||||
foreach ($studentlist as $sid) {
|
foreach ($studentlist as $sid) {
|
||||||
$p = $this->proficiency($competency,$sid);
|
$p = $this->proficiency($competency,$sid);
|
||||||
$r->count += 1;
|
$r->count += 1;
|
||||||
$r->nproficient += ($p->proficient)?1:0;
|
$r->nproficient += ($p->proficient === true)?1:0;
|
||||||
|
$r->nfailed += ($p->proficient === false)?1:0;
|
||||||
$r->ncourseproficient += ($p->courseproficient)?1:0;
|
$r->ncourseproficient += ($p->courseproficient)?1:0;
|
||||||
|
$r->nneedreview += ($p->needreview)?1:0;
|
||||||
}
|
}
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
@ -438,8 +470,11 @@ class coursecompetencyinfo {
|
||||||
$r = new \stdClass();
|
$r = new \stdClass();
|
||||||
|
|
||||||
$uc = c_api::get_user_competency($userid, $competencyid);
|
$uc = c_api::get_user_competency($userid, $competencyid);
|
||||||
$r->proficient = $uc->get('proficiency');
|
$proficiency = $uc->get('proficiency');
|
||||||
|
$r->proficient = $proficiency;
|
||||||
$r->grade = $scale->get_nearest_item($uc->get('grade'));
|
$r->grade = $scale->get_nearest_item($uc->get('grade'));
|
||||||
|
$r->needreview = (!($r->proficient) && ($uc->get('status') > user_competency::STATUS_IDLE));
|
||||||
|
$r->failed = $proficiency === false;
|
||||||
try {
|
try {
|
||||||
// Only add course grade and proficiency if the competency is included in the course.
|
// Only add course grade and proficiency if the competency is included in the course.
|
||||||
$ucc = c_api::get_user_competency_in_course($this->course->id,$userid,$competencyid);
|
$ucc = c_api::get_user_competency_in_course($this->course->id,$userid,$competencyid);
|
||||||
|
@ -449,7 +484,6 @@ class coursecompetencyinfo {
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve course proficiency and overall proficiency for a competency and user
|
* Retrieve course proficiency and overall proficiency for a competency and user
|
||||||
*
|
*
|
||||||
|
|
|
@ -138,6 +138,14 @@ class bistate_aggregator extends \local_treestudyplan\aggregator {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if Aggregation method makes use of "required grades" in a course/module.
|
||||||
|
* @return bool True if Aggregation method makes use of "required grades" in a course/module.
|
||||||
|
*/
|
||||||
|
public function use_required_grades(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregate completed/failed goals into one outcome
|
* Aggregate completed/failed goals into one outcome
|
||||||
* @param int[] $completions List of completions (completion class constants)
|
* @param int[] $completions List of completions (completion class constants)
|
||||||
|
|
|
@ -82,6 +82,7 @@ if ($CFG->debugdeveloper) {
|
||||||
}
|
}
|
||||||
$PAGE->requires->js_call_amd('local_treestudyplan/page-edit-plan', 'init', [$studyplancontext->id, $categoryid, [
|
$PAGE->requires->js_call_amd('local_treestudyplan/page-edit-plan', 'init', [$studyplancontext->id, $categoryid, [
|
||||||
"defaultAggregation" => get_config("local_treestudyplan","aggregation_mode"),
|
"defaultAggregation" => get_config("local_treestudyplan","aggregation_mode"),
|
||||||
|
"editMode" => $PAGE->user_is_editing()
|
||||||
]]);
|
]]);
|
||||||
|
|
||||||
$catlist = courseservice::list_accessible_categories_with_usage("edit");
|
$catlist = courseservice::list_accessible_categories_with_usage("edit");
|
||||||
|
@ -150,6 +151,7 @@ print $OUTPUT->header();
|
||||||
v-model='activestudyplan'
|
v-model='activestudyplan'
|
||||||
@moved="movedStudyplan"
|
@moved="movedStudyplan"
|
||||||
@toggletoolbox="toggletoolbox"
|
@toggletoolbox="toggletoolbox"
|
||||||
|
:initeditmode="initialEditMode"
|
||||||
></t-studyplan>
|
></t-studyplan>
|
||||||
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
|
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
|
||||||
<span class="sr-only">Loading...</span>
|
<span class="sr-only">Loading...</span>
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
<?php
|
|
||||||
// This file is part of the Studyplan plugin for Moodle
|
|
||||||
//
|
|
||||||
// Moodle is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Moodle is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
/**
|
|
||||||
* Entry point for other moodle modules to embed the user's report in a view
|
|
||||||
* @package local_treestudyplan
|
|
||||||
* @copyright 2023 P.M. Kuipers
|
|
||||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once("../../config.php");
|
|
||||||
|
|
||||||
require_once($CFG->libdir.'/weblib.php');
|
|
||||||
|
|
||||||
use local_treestudyplan;
|
|
||||||
|
|
||||||
$systemcontext = context_system::instance();
|
|
||||||
|
|
||||||
$PAGE->set_url("/local/treestudyplan/myreport.php", array());
|
|
||||||
require_login();
|
|
||||||
|
|
||||||
$PAGE->set_pagelayout('embedded');
|
|
||||||
$PAGE->set_context($systemcontext);
|
|
||||||
$PAGE->set_title(get_string('report_invited', 'local_treestudyplan', "{$USER->firstname} {$USER->lastname}"));
|
|
||||||
$PAGE->set_heading(get_string('report_invited', 'local_treestudyplan', "{$USER->firstname} {$USER->lastname}"));
|
|
||||||
|
|
||||||
// Load javascripts and specific css.
|
|
||||||
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue/bootstrap-vue.css'));
|
|
||||||
if ($CFG->debugdeveloper) {
|
|
||||||
$PAGE->requires->css(new moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
|
|
||||||
}
|
|
||||||
$PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut function to provide translations
|
|
||||||
*
|
|
||||||
* @param mixed $str Translation key
|
|
||||||
* @param null|string[] $param Parameters to pass to translation
|
|
||||||
* @param string $plugin Location to search for translation strings
|
|
||||||
* @return string Translation of key
|
|
||||||
*/
|
|
||||||
function t($str, $param = null, $plugin = 'local_treestudyplan') {
|
|
||||||
print get_string($str, $plugin, $param);
|
|
||||||
}
|
|
||||||
|
|
||||||
print $OUTPUT->header();
|
|
||||||
?>
|
|
||||||
<div class="m-buttonbar" style="margin-bottom: 1em; text-align: right;">
|
|
||||||
<a class="btn btn-primary" href="invitations.php" id="manage_invites"><i class="fa fa-share"></i> <?php t('manage_invites'); ?></a>
|
|
||||||
</div>
|
|
||||||
<div id='root'>
|
|
||||||
<div class='vue-loader' v-show='false'>
|
|
||||||
<div class="spinner-border text-primary" role="status">
|
|
||||||
<span class="sr-only">Loading...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-cloak>
|
|
||||||
<r-report v-model="studyplans"></r-report>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
|
|
||||||
print $OUTPUT->footer();
|
|
|
@ -87,7 +87,7 @@ print " <div v-cloak>";
|
||||||
if ($am_teaching) {
|
if ($am_teaching) {
|
||||||
print " <r-report type='teaching' teachermode ></r-report>";
|
print " <r-report type='teaching' teachermode ></r-report>";
|
||||||
} else {
|
} else {
|
||||||
print " <r-report type='own' ></r-report>";
|
print " <r-report type='own' :userid='userid'></r-report>";
|
||||||
|
|
||||||
}
|
}
|
||||||
print " </div>";
|
print " </div>";
|
||||||
|
|
|
@ -80,6 +80,8 @@ if ($CFG->debugdeveloper) {
|
||||||
}
|
}
|
||||||
$PAGE->requires->js_call_amd('local_treestudyplan/page-view-plan', 'init', [$studyplancontext->id, $categoryid]);
|
$PAGE->requires->js_call_amd('local_treestudyplan/page-view-plan', 'init', [$studyplancontext->id, $categoryid]);
|
||||||
|
|
||||||
|
// Disable edit switch.
|
||||||
|
$PAGE->theme->haseditswitch = false;
|
||||||
/**
|
/**
|
||||||
* Shortcut function to provide translations
|
* Shortcut function to provide translations
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue