Implemented teacher view for competencies
This commit is contained in:
parent
456e9b503e
commit
96caeb895a
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 ) {
|
||||
options.defaultAggregation = "core";
|
||||
}
|
||||
if ( !options.editMode ) {
|
||||
options.editMode = false;
|
||||
}
|
||||
} else {
|
||||
options = { defaultAggregation: "core"};
|
||||
options = { defaultAggregation: "core", editMode: false};
|
||||
}
|
||||
|
||||
const in_systemcontext = (contextid <= 1);
|
||||
|
||||
// Setup the initial Vue app for this page
|
||||
let app = new Vue({
|
||||
el: '#root',
|
||||
|
@ -100,6 +101,7 @@ export function init(contextid,categoryid,options) {
|
|||
courses: [],
|
||||
text: strings.studyplan,
|
||||
usedcontexts: [],
|
||||
initialEditMode: !!options.editMode,
|
||||
},
|
||||
created() {
|
||||
this.$root.$on('studyplanRemoved',(studyplan)=>{
|
||||
|
|
|
@ -16,8 +16,8 @@ import {svgarcpath} from './util/svgarc';
|
|||
import Debugger from './util/debugger';
|
||||
import Config from 'core/config';
|
||||
import {ProcessStudyplan, ProcessStudyplanPage, objCopy} from './studyplan-processor';
|
||||
|
||||
import TSComponents from './treestudyplan-components';
|
||||
import {eventTypes as editSwEventTypes} from 'core/edit_switch';
|
||||
|
||||
// Make π available as a constant
|
||||
const π = Math.PI;
|
||||
|
@ -180,6 +180,13 @@ export default {
|
|||
// Create new eventbus for interaction between item components
|
||||
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',{
|
||||
props: {
|
||||
value: {
|
||||
|
@ -1606,11 +1613,15 @@ export default {
|
|||
</tr>
|
||||
<template v-else>
|
||||
<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>
|
||||
</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 class='details' >
|
||||
<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 :colspan="(c.required)?1:2">
|
||||
<span :class="'r-completion-'+completion_tag(c)">
|
||||
|
@ -1630,9 +1641,6 @@ export default {
|
|||
</template>
|
||||
</span>
|
||||
</td>
|
||||
<td v-if="c.required">
|
||||
<span class="text-danger" v-if="c.required">{{ text.required }}</span>
|
||||
</td>
|
||||
<td v-if="c.feedback">
|
||||
<a v-b-modal="'r-competency-feedback-'+c.id"
|
||||
href="#"
|
||||
|
@ -1675,17 +1683,22 @@ export default {
|
|||
<th colspan="3">{{text.results}}</th>
|
||||
</tr>
|
||||
<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>
|
||||
</td>
|
||||
<td class='details' v-if="cc.details">
|
||||
<a :href='competencyurl(c)' target="_blank"><span v-html='cc.details'></span></a>
|
||||
<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><span :class="'r-completion-'+completion_tag(cc)"
|
||||
><i :class="'fa fa-'+completion_icon(cc)" :title="text['completion_'+completion_tag(cc)]"></i>
|
||||
{{ (cc.proficient === null)?text.unrated:cc.grade }}</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">
|
||||
<a v-b-modal="'r-competency-feedback-'+cc.id"
|
||||
href="#"
|
||||
|
@ -1782,10 +1795,10 @@ export default {
|
|||
ungraded: 0,
|
||||
};
|
||||
|
||||
if(this.value.course.completion){
|
||||
for(const cond of this.value.course.completion.conditions){
|
||||
for(const itm of cond.items){
|
||||
if(itm.progress){
|
||||
if(this.value.course.completion) {
|
||||
for(const cond of this.value.course.completion.conditions) {
|
||||
for(const itm of cond.items) {
|
||||
if(itm.progress) {
|
||||
status.students += itm.progress.students;
|
||||
status.completed += itm.progress.completed;
|
||||
status.completed_pass += itm.progress.completed_pass;
|
||||
|
@ -1794,10 +1807,12 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (this.value.course.grades){
|
||||
for( const g of this.value.course.grades){
|
||||
if(g.grading){
|
||||
} else if (this.value.course.competency) {
|
||||
status.students = this.value.course.competency.total;
|
||||
status.completed = this.value.course.competency.proficient;
|
||||
} else if (this.value.course.grades) {
|
||||
for( const g of this.value.course.grades) {
|
||||
if(g.grading) {
|
||||
status.students += g.grading.students;
|
||||
status.completed += g.grading.completed;
|
||||
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',{
|
||||
props: {
|
||||
value : {
|
||||
|
@ -2313,23 +2328,30 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
completion_icon(completion) {
|
||||
switch(completion){
|
||||
case "progress":
|
||||
return "exclamation-circle";
|
||||
case "complete":
|
||||
return "check-circle";
|
||||
case "complete-pass":
|
||||
return "check-circle";
|
||||
case "complete-fail":
|
||||
return "times-circle";
|
||||
default: // case "incomplete"
|
||||
return "circle-o";
|
||||
completion_icon(competency) {
|
||||
if (competency.proficient && competency.courseproficient) {
|
||||
return "check-circle";
|
||||
} else if (competency.proficient) {
|
||||
return "check";
|
||||
} else if (competency.proficient === false) {
|
||||
return "times-circle";
|
||||
} else {
|
||||
return "circle-o";
|
||||
}
|
||||
},
|
||||
|
||||
completion_tag(cgroup){
|
||||
return cgroup.completion?'completed':'incomplete';
|
||||
completion_tag(competency){
|
||||
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) {
|
||||
|
@ -2342,48 +2364,55 @@ export default {
|
|||
}
|
||||
let url;
|
||||
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 {
|
||||
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;
|
||||
},
|
||||
requiredChanged(newValue,c){
|
||||
call([{
|
||||
methodname: 'local_treestudyplan_require_competency',
|
||||
args: { 'competency_id': c.id,
|
||||
'item_id': this.item.id,
|
||||
'required': newValue,
|
||||
}
|
||||
}])[0].fail(notification.exception);
|
||||
},
|
||||
competencyurl(c) {
|
||||
return `/admin/tool/lp/user_competency_in_course.php?courseid=${this.item.course.id}&competencyid=${c.id}`;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<table class="t-item-course-competency-list">
|
||||
<table class="r-item-course-competency-list">
|
||||
<tr v-if="value.competencies.length == 0">
|
||||
<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>
|
||||
</td>
|
||||
</tr>
|
||||
<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'>
|
||||
<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>
|
||||
<b-form-checkbox inline
|
||||
@change="requiredChanged($event,c)"
|
||||
v-model="c.required"
|
||||
>{{ text.required }}</b-form-checkbox>
|
||||
<a href="#" v-b-modal="'modal-competency-id-'+c.id"><span v-html='c.title'></span></a>
|
||||
</td>
|
||||
<td class='details'>
|
||||
<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>
|
||||
<b-modal :id="'modal-competency-id-'+c.id"
|
||||
size="lg"
|
||||
|
@ -2404,17 +2433,41 @@ export default {
|
|||
|
||||
<template v-if="c.rule && c.children">
|
||||
<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'>
|
||||
<th>{{text.heading}}</th>
|
||||
<th></th>
|
||||
<th>{{text.required}}</th>
|
||||
<th colspan="2">{{text.heading}}</th>
|
||||
<th colspan="3">{{text.results}}</th>
|
||||
</tr>
|
||||
<tr v-for="cc in c.children">
|
||||
<td :colspan="(c.details)?1:2" ><span v-html='cc.title'></span></td>
|
||||
<td class='details' v-if="cc.details"><span v-html='cc.details'></span></td>
|
||||
<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-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>
|
||||
</table>
|
||||
</template>
|
||||
|
@ -2426,7 +2479,6 @@ export default {
|
|||
});
|
||||
|
||||
|
||||
|
||||
Vue.component('r-grading-bar',{
|
||||
props: {
|
||||
value : {
|
||||
|
|
|
@ -16,6 +16,7 @@ import {objCopy,transportItem} from './studyplan-processor';
|
|||
import Debugger from './util/debugger';
|
||||
import {download,upload} from './downloader';
|
||||
import {ProcessStudyplan, ProcessStudyplanPage} from './studyplan-processor';
|
||||
import {eventTypes as editSwEventTypes} from 'core/edit_switch';
|
||||
|
||||
import TSComponents from './treestudyplan-components';
|
||||
import mFormComponents from "./util/mform-helper";
|
||||
|
@ -42,7 +43,6 @@ export default {
|
|||
Vue.use(TSComponents);
|
||||
Vue.use(mFormComponents);
|
||||
let debug = new Debugger("treestudyplan-editor");
|
||||
|
||||
/************************************
|
||||
* *
|
||||
* Treestudyplan Editor components *
|
||||
|
@ -58,10 +58,15 @@ export default {
|
|||
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
|
||||
}
|
||||
|
||||
|
||||
// Create new eventbus for interaction between item components
|
||||
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({
|
||||
conditions: [
|
||||
{ value: 'ALL', textkey: 'condition_all'},
|
||||
|
@ -249,10 +254,8 @@ export default {
|
|||
dateexpire: "dateexpire",
|
||||
badgeinfo: "badgeinfo",
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* T-STUDYPLAN-ADVANCED
|
||||
*/
|
||||
|
@ -282,7 +285,6 @@ export default {
|
|||
mounted() {
|
||||
},
|
||||
updated() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
scales(){
|
||||
|
@ -1184,7 +1186,7 @@ export default {
|
|||
* T-STUDYPLAN
|
||||
*/
|
||||
Vue.component('t-studyplan', {
|
||||
props: [ 'value', 'index', ],
|
||||
props: [ 'value', 'index', 'initeditmode'],
|
||||
data() {
|
||||
return {
|
||||
config: {
|
||||
|
@ -1257,13 +1259,16 @@ export default {
|
|||
};
|
||||
},
|
||||
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() {
|
||||
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
|
||||
this.edit.studyline.editmode = true;
|
||||
}
|
||||
}*/
|
||||
this.edit.studyline.editmode = this.initeditmode;
|
||||
this.$root.$emit('redrawLines');
|
||||
},
|
||||
updated() {
|
||||
|
@ -1276,6 +1281,9 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
onMoodleEditModeChanged(mode){
|
||||
this.edit.studyline.editmode = mode;
|
||||
},
|
||||
columns(page) {
|
||||
return 1+ (page.periods * 2);
|
||||
},
|
||||
|
@ -1522,11 +1530,11 @@ export default {
|
|||
selectedpageChanged(newTabIndex,prevTabIndex) {
|
||||
const page = this.value.pages[newTabIndex];
|
||||
|
||||
/*
|
||||
if (page.studylines.length == 0) {
|
||||
this.edit.studyline.editmode = true;
|
||||
} else {
|
||||
this.edit.studyline.editmode = false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
,
|
||||
|
|
|
@ -186,6 +186,23 @@ abstract class aggregator {
|
|||
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 string Configuration string
|
||||
|
@ -201,6 +218,8 @@ abstract class aggregator {
|
|||
*/
|
||||
public static function basic_structure($value = VALUE_REQUIRED) : \external_description {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -210,6 +229,8 @@ abstract class aggregator {
|
|||
*/
|
||||
public function basic_model() {
|
||||
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\competency_rule_points;
|
||||
use core_competency\evidence;
|
||||
use core_competency\user_competency;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
|
@ -63,6 +64,29 @@ class coursecompetencyinfo {
|
|||
$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
|
||||
|
@ -85,8 +109,8 @@ class coursecompetencyinfo {
|
|||
"coursegrade" => new \external_value(PARAM_TEXT, 'course competency grade', VALUE_OPTIONAL),
|
||||
"proficient" => new \external_value(PARAM_BOOL, '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),
|
||||
"ncourseproficient" => new \external_value(PARAM_INT, 'number of students with course proficiency',VALUE_OPTIONAL),
|
||||
"needreview" => new \external_value(PARAM_BOOL, 'waiting for review or review in progress',VALUE_OPTIONAL),
|
||||
"completionstats" => static::completionstats_structure(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),
|
||||
"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 {
|
||||
return new \external_single_structure([
|
||||
"competencies" => new \external_multiple_structure(self::competencyinfo_structure(), 'competencies'),
|
||||
"fproficient" => new \external_value(PARAM_FLOAT, 'fraction of completion for total course proficiency ',VALUE_OPTIONAL),
|
||||
"fcourseproficient" => new \external_value(PARAM_FLOAT, 'fraction of completion for total course proficienct',VALUE_OPTIONAL),
|
||||
"proficient" => new \external_value(PARAM_INT, 'number of proficient user/competencys ',VALUE_OPTIONAL),
|
||||
"total" => new \external_value(PARAM_INT, 'total number of gradable user/competencies',VALUE_OPTIONAL),
|
||||
], 'course completion info', $value);
|
||||
}
|
||||
|
||||
|
@ -195,19 +219,19 @@ class coursecompetencyinfo {
|
|||
|
||||
$count = 0;
|
||||
$nproficient = 0;
|
||||
$ncourseproficient = 0;
|
||||
|
||||
foreach($coursecompetencies as $c) {
|
||||
$ci = $this->competencyinfo_model($c);
|
||||
if(!empty($studentslist)){
|
||||
if(!empty($studentlist)){
|
||||
$stats = $this->proficiency_stats($c,$studentlist);
|
||||
$count += $stats->count;
|
||||
$nproficient += $stats->nproficient;
|
||||
$ncourseproficient += $stats->ncourseproficient;
|
||||
// Copy proficiency stats to model.
|
||||
foreach ((array)$stats as $key => $value) {
|
||||
$ci[$key] = $value;
|
||||
}
|
||||
$ci['completionstats'] = self::completionstats($stats);
|
||||
|
||||
}
|
||||
$ci['required'] = $this->is_required($c);
|
||||
|
||||
|
@ -249,6 +273,10 @@ class coursecompetencyinfo {
|
|||
foreach($dids as $did) {
|
||||
$cc = new competency($did);
|
||||
$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(array_key_exists($did,$crlist)) {
|
||||
$cr = $crlist[$did];
|
||||
|
@ -267,9 +295,9 @@ class coursecompetencyinfo {
|
|||
$info = [
|
||||
"competencies" => $cis,
|
||||
];
|
||||
if(!empty($studentslist)){
|
||||
$info["fproficient"] = (float)($nproficient)/(float)($count);
|
||||
$info["fcourseproficient"] = (float)($ncourseproficient)/(float)($count);
|
||||
if(!empty($studentlist)){
|
||||
$info["proficient"] = $nproficient;
|
||||
$info["total"] = $count;
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
@ -413,12 +441,16 @@ class coursecompetencyinfo {
|
|||
$r->count = 0;
|
||||
$r->nproficient = 0;
|
||||
$r->ncourseproficient = 0;
|
||||
$r->nneedreview = 0;
|
||||
$r->nfailed = 0;
|
||||
|
||||
foreach ($studentlist as $sid) {
|
||||
$p = $this->proficiency($competency,$sid);
|
||||
$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->nneedreview += ($p->needreview)?1:0;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
@ -438,8 +470,11 @@ class coursecompetencyinfo {
|
|||
$r = new \stdClass();
|
||||
|
||||
$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->needreview = (!($r->proficient) && ($uc->get('status') > user_competency::STATUS_IDLE));
|
||||
$r->failed = $proficiency === false;
|
||||
try {
|
||||
// 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);
|
||||
|
@ -449,7 +484,6 @@ class coursecompetencyinfo {
|
|||
return $r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve course proficiency and overall proficiency for a competency and user
|
||||
*
|
||||
|
|
|
@ -138,6 +138,14 @@ class bistate_aggregator extends \local_treestudyplan\aggregator {
|
|||
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
|
||||
* @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, [
|
||||
"defaultAggregation" => get_config("local_treestudyplan","aggregation_mode"),
|
||||
"editMode" => $PAGE->user_is_editing()
|
||||
]]);
|
||||
|
||||
$catlist = courseservice::list_accessible_categories_with_usage("edit");
|
||||
|
@ -150,6 +151,7 @@ print $OUTPUT->header();
|
|||
v-model='activestudyplan'
|
||||
@moved="movedStudyplan"
|
||||
@toggletoolbox="toggletoolbox"
|
||||
:initeditmode="initialEditMode"
|
||||
></t-studyplan>
|
||||
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
|
||||
<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) {
|
||||
print " <r-report type='teaching' teachermode ></r-report>";
|
||||
} else {
|
||||
print " <r-report type='own' ></r-report>";
|
||||
print " <r-report type='own' :userid='userid'></r-report>";
|
||||
|
||||
}
|
||||
print " </div>";
|
||||
|
|
|
@ -80,6 +80,8 @@ if ($CFG->debugdeveloper) {
|
|||
}
|
||||
$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
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue
Block a user