Replaced student email by last course access time
This commit is contained in:
parent
6b616c0a6a
commit
8f2673c4a4
2
amd/build/studyplan-report-components.min.js
vendored
2
amd/build/studyplan-report-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/util/date-helper.min.js
vendored
2
amd/build/util/date-helper.min.js
vendored
|
@ -1,3 +1,3 @@
|
||||||
define("local_treestudyplan/util/date-helper",["exports"],(function(_exports){function format_date(d,short){d instanceof Date||(d=new Date(d));let monthformat="short";return!0===short?monthformat="numeric":!1===short&&(monthformat="long"),d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})}function studyplanDates(plan){let earliestStart=null,latestEnd=null,openEnded=!1;for(const ix in plan.pages){const page=plan.pages[ix],s=new Date(page.startdate);if(page.enddate||(openEnded=!0),(!earliestStart||s<earliestStart)&&(earliestStart=s),page.enddate){const e=new Date(page.enddate);(!latestEnd||e>latestEnd)&&(latestEnd=e)}}return{start:earliestStart,end:openEnded?null:latestEnd}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.add_days=function(datestr,days){const date=new Date(datestr);return function(date){const d=new Date(date);let month=""+(d.getMonth()+1),day=""+d.getDate();const year=d.getFullYear();month.length<2&&(month="0"+month);day.length<2&&(day="0"+day);return[year,month,day].join("-")}(new Date(date.getTime()+864e5*days))},_exports.datespaninfo=function(first,last){first instanceof Date||(first=new Date(first));last instanceof Date||(last=new Date(last));first.setHours(0),first.setMinutes(0),first.setSeconds(0),first.setMilliseconds(0),last.setHours(23),last.setMinutes(59),last.setSeconds(59),last.setMilliseconds(999);const dayspan=Math.round((last-first+1)/864e5),years=Math.floor(dayspan/365),ydaysleft=dayspan%365,weeks=Math.floor(ydaysleft/7);return{first:first,last:last,totaldays:dayspan,years:years,weeks:weeks,days:ydaysleft%7,formatted:{first:format_date(first),last:format_date(last)}}},_exports.format_date=format_date,_exports.studyplanDates=studyplanDates,_exports.studyplanPageTiming=function(page){const now=(new Date).getTime(),start=new Date(page.startdate),end=page.enddate?new Date(page.enddate):null;return start<now?end&&now>end?"past":"present":"future"},_exports.studyplanTiming=function(plan){const now=(new Date).getTime(),dates=studyplanDates(plan);return dates.start<now?dates.end&&now>dates.end?"past":"present":"future"}}));
|
define("local_treestudyplan/util/date-helper",["exports"],(function(_exports){function format_date(d,short){d instanceof Date||(d=new Date(d));let monthformat="short";return!0===short?monthformat="numeric":!1===short&&(monthformat="long"),d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})}function studyplanDates(plan){let earliestStart=null,latestEnd=null,openEnded=!1;for(const ix in plan.pages){const page=plan.pages[ix],s=new Date(page.startdate);if(page.enddate||(openEnded=!0),(!earliestStart||s<earliestStart)&&(earliestStart=s),page.enddate){const e=new Date(page.enddate);(!latestEnd||e>latestEnd)&&(latestEnd=e)}}return{start:earliestStart,end:openEnded?null:latestEnd}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.add_days=function(datestr,days){const date=new Date(datestr);return function(date){const d=new Date(date);let month=""+(d.getMonth()+1),day=""+d.getDate();const year=d.getFullYear();month.length<2&&(month="0"+month);day.length<2&&(day="0"+day);return[year,month,day].join("-")}(new Date(date.getTime()+864e5*days))},_exports.datespaninfo=function(first,last){first instanceof Date||(first=new Date(first));last instanceof Date||(last=new Date(last));first.setHours(0),first.setMinutes(0),first.setSeconds(0),first.setMilliseconds(0),last.setHours(23),last.setMinutes(59),last.setSeconds(59),last.setMilliseconds(999);const dayspan=Math.round((last-first+1)/864e5),years=Math.floor(dayspan/365),ydaysleft=dayspan%365,weeks=Math.floor(ydaysleft/7);return{first:first,last:last,totaldays:dayspan,years:years,weeks:weeks,days:ydaysleft%7,formatted:{first:format_date(first),last:format_date(last)}}},_exports.format_date=format_date,_exports.format_datetime=function(d,short){d instanceof Date||(d=new Date(d));let monthformat="short";!0===short?monthformat="numeric":!1===short&&(monthformat="long");return d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})+" "+d.toLocaleTimeString(document.documentElement.lang,{timeStyle:"short"})},_exports.studyplanDates=studyplanDates,_exports.studyplanPageTiming=function(page){const now=(new Date).getTime(),start=new Date(page.startdate),end=page.enddate?new Date(page.enddate):null;return start<now?end&&now>end?"past":"present":"future"},_exports.studyplanTiming=function(plan){const now=(new Date).getTime(),dates=studyplanDates(plan);return dates.start<now?dates.end&&now>dates.end?"past":"present":"future"}}));
|
||||||
|
|
||||||
//# sourceMappingURL=date-helper.min.js.map
|
//# sourceMappingURL=date-helper.min.js.map
|
File diff suppressed because one or more lines are too long
|
@ -13,6 +13,7 @@ import Debugger from './util/debugger';
|
||||||
import Config from 'core/config';
|
import Config from 'core/config';
|
||||||
import TSComponents from './treestudyplan-components';
|
import TSComponents from './treestudyplan-components';
|
||||||
import FitTextVue from './util/fittext-vue';
|
import FitTextVue from './util/fittext-vue';
|
||||||
|
import {format_datetime} from "./util/date-helper";
|
||||||
|
|
||||||
const debug = new Debugger("treestudyplan-viewer");
|
const debug = new Debugger("treestudyplan-viewer");
|
||||||
|
|
||||||
|
@ -121,7 +122,8 @@ export default {
|
||||||
students: 'students@core',
|
students: 'students@core',
|
||||||
firstname: 'firstname@core',
|
firstname: 'firstname@core',
|
||||||
lastname: 'lastname@core',
|
lastname: 'lastname@core',
|
||||||
email: 'email@core'
|
email: 'email@core',
|
||||||
|
lastaccess: 'lastaccess@core',
|
||||||
},
|
},
|
||||||
studentresults: {
|
studentresults: {
|
||||||
completion_incomplete: "completion_incomplete",
|
completion_incomplete: "completion_incomplete",
|
||||||
|
@ -132,6 +134,7 @@ export default {
|
||||||
completion_good: "completion_good",
|
completion_good: "completion_good",
|
||||||
completion_excellent: "completion_excellent",
|
completion_excellent: "completion_excellent",
|
||||||
student_not_tracked: "student_not_tracked",
|
student_not_tracked: "student_not_tracked",
|
||||||
|
never: "never@core",
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -166,12 +169,13 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.loadStudents();
|
|
||||||
},
|
},
|
||||||
watch:{
|
watch:{
|
||||||
structure: {
|
structure: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler (structure) {
|
handler (structure) {
|
||||||
|
this.loadStudents(); // reload the student list
|
||||||
|
|
||||||
// (Re)build expansion info structure
|
// (Re)build expansion info structure
|
||||||
let firstperiod = true;
|
let firstperiod = true;
|
||||||
for (const period of structure.periods) {
|
for (const period of structure.periods) {
|
||||||
|
@ -224,7 +228,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
sortedstudents(){
|
sortedstudents(){
|
||||||
const self=this;
|
const self=this;
|
||||||
// Probably should make a deep copy for purity's sake, but this works just as well.
|
// Probably could make a deep copy for purity's sake, but this works just as well and is probably more efficient.
|
||||||
const students = this.students;
|
const students = this.students;
|
||||||
for (const group of this.students) {
|
for (const group of this.students) {
|
||||||
group.users.sort((a,b) => {
|
group.users.sort((a,b) => {
|
||||||
|
@ -234,7 +238,13 @@ export default {
|
||||||
d = b;
|
d = b;
|
||||||
e = a;
|
e = a;
|
||||||
}
|
}
|
||||||
|
if (this.sorting.header == "lastaccess") {
|
||||||
|
const dvalue = (d[this.sorting.header]?d[this.sorting.header]:0);
|
||||||
|
const evalue = (e[this.sorting.header]?e[this.sorting.header]:0);
|
||||||
|
return dvalue - evalue;
|
||||||
|
} else {
|
||||||
return String(d[this.sorting.header]).localeCompare(String(e[this.sorting.header]));
|
return String(d[this.sorting.header]).localeCompare(String(e[this.sorting.header]));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +352,7 @@ export default {
|
||||||
:style="'--resultColCount: '+resultColCount+';'">
|
:style="'--resultColCount: '+resultColCount+';'">
|
||||||
<colgroup class="q-col-studentinfo">
|
<colgroup class="q-col-studentinfo">
|
||||||
<col class="q-name"></col>
|
<col class="q-name"></col>
|
||||||
<col class="q-email"></col>
|
<col class="q-lastaccess"></col>
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<colgroup class="q-col-resultinfo">
|
<colgroup class="q-col-resultinfo">
|
||||||
<col v-for="n in resultColCount"></col>
|
<col v-for="n in resultColCount"></col>
|
||||||
|
@ -475,11 +485,11 @@ export default {
|
||||||
template: `
|
template: `
|
||||||
<thead class='q-header'>
|
<thead class='q-header'>
|
||||||
<tr> <!-- period heading -->
|
<tr> <!-- period heading -->
|
||||||
<th rowspan='3' colspan='2' class='q-studentinfo q-generic'><span>{{text.students}}</span></th>
|
<th rowspan='4' colspan='2' class='q-studentinfo q-generic'><span>{{text.students}}</span></th>
|
||||||
<th v-for="p in structure.periods"
|
<th v-for="p in structure.periods"
|
||||||
:class="'q-period-heading '+ ((expansion.periods[p.period.id].expanded)?'expanded':'collapsed')"
|
:class="'q-period-heading '+ ((expansion.periods[p.period.id].expanded)?'expanded':'collapsed')"
|
||||||
:colspan='colspanPeriod(p)'
|
:colspan='colspanPeriod(p)'
|
||||||
:rowspan='(expansion.periods[p.period.id].expanded && p.lines.length > 0)?1:4'
|
:rowspan='(expansion.periods[p.period.id].expanded && p.lines.length > 0)?1:5'
|
||||||
><span class="q-wrap"><a v-if='(p.lines.length > 0)' href='#' @click.prevent="togglePeriod(p.period)"
|
><span class="q-wrap"><a v-if='(p.lines.length > 0)' href='#' @click.prevent="togglePeriod(p.period)"
|
||||||
><i v-if="expansion.periods[p.period.id].expanded"
|
><i v-if="expansion.periods[p.period.id].expanded"
|
||||||
class='q-chevron fa fa-minus'></i
|
class='q-chevron fa fa-minus'></i
|
||||||
|
@ -494,7 +504,7 @@ export default {
|
||||||
<th v-for="l in p.lines"
|
<th v-for="l in p.lines"
|
||||||
:class="'q-line-heading ' + ((expansion.lines[p.period.id][l.line.id].expanded)?'expanded':'collapsed')"
|
:class="'q-line-heading ' + ((expansion.lines[p.period.id][l.line.id].expanded)?'expanded':'collapsed')"
|
||||||
:colspan="colspanLine(p,l)"
|
:colspan="colspanLine(p,l)"
|
||||||
:rowspan='(expansion.lines[p.period.id][l.line.id].expanded)?1:3'
|
:rowspan='(expansion.lines[p.period.id][l.line.id].expanded)?1:4'
|
||||||
><span class="q-wrap"><fittext vertical maxsize="18pt"
|
><span class="q-wrap"><fittext vertical maxsize="18pt"
|
||||||
><span class='q-label'
|
><span class='q-label'
|
||||||
:title="l.line.shortname"
|
:title="l.line.shortname"
|
||||||
|
@ -513,7 +523,7 @@ export default {
|
||||||
<th v-for="item in l.items"
|
<th v-for="item in l.items"
|
||||||
:class="'q-item-heading ' + ((expansion.items[item.id].expanded)?'expanded':'collapsed')"
|
:class="'q-item-heading ' + ((expansion.items[item.id].expanded)?'expanded':'collapsed')"
|
||||||
:colspan="colspanItem(item)"
|
:colspan="colspanItem(item)"
|
||||||
:rowspan='(expansion.items[item.id].expanded)?1:2'
|
:rowspan='(expansion.items[item.id].expanded)?1:3'
|
||||||
><span class="q-wrap"><a href='#'
|
><span class="q-wrap"><a href='#'
|
||||||
@click.prevent="toggleItem(item)"
|
@click.prevent="toggleItem(item)"
|
||||||
><i v-if="expansion.items[item.id].expanded"
|
><i v-if="expansion.items[item.id].expanded"
|
||||||
|
@ -537,32 +547,16 @@ export default {
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
<tr> <!-- condition heading -->
|
<tr> <!-- condition heading -->
|
||||||
<th class="q-studentinfo q-name">
|
|
||||||
<fittext maxsize="12pt"
|
|
||||||
><a href="#" @click.prevent="toggleSort('firstname')">{{text.firstname}}</a
|
|
||||||
><i v-if="sorting.header=='firstname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
|
|
||||||
><i v-else-if="sorting.header=='firstname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i>
|
|
||||||
/ <a href="#" @click.prevent="toggleSort('lastname')">{{text.lastname}}</a
|
|
||||||
><i v-if="sorting.header=='lastname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
|
|
||||||
><i v-else-if="sorting.header=='lastname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
|
|
||||||
></fittext>
|
|
||||||
</th>
|
|
||||||
<th class="q-studentinfo q-email">
|
|
||||||
<fittext maxsize="12pt"
|
|
||||||
><a href="#" @click.prevent="toggleSort('email')">{{text.email}}</a
|
|
||||||
><i v-if="sorting.header=='email' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
|
|
||||||
><i v-else-if="sorting.header=='email' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
|
|
||||||
></fittext>
|
|
||||||
</th>
|
|
||||||
<template v-for="p in structure.periods">
|
<template v-for="p in structure.periods">
|
||||||
<template v-if="expansion.periods[p.period.id].expanded">
|
<template v-if="expansion.periods[p.period.id].expanded">
|
||||||
<template v-for="l in p.lines">
|
<template v-for="l in p.lines">
|
||||||
<template v-if="expansion.lines[p.period.id][l.line.id].expanded">
|
<template v-if="expansion.lines[p.period.id][l.line.id].expanded">
|
||||||
<template v-for="item in l.items">
|
<template v-for="item in l.items">
|
||||||
<template v-if="expansion.items[item.id].expanded">
|
<template v-if="expansion.items[item.id].expanded">
|
||||||
<th class='q-condition-heading overall'
|
<th class='q-condition-heading overall' rowspan="2"
|
||||||
><span class='q-wrap'>{{ text.overall }}</span></th>
|
><span class='q-wrap'>{{ text.overall }}</span></th>
|
||||||
<th v-for="c in conditions(item)"
|
<th v-for="c in conditions(item)"
|
||||||
|
rowspan="2"
|
||||||
class='q-condition-heading'
|
class='q-condition-heading'
|
||||||
><span class="q-wrap"><fittext vertical maxsize="14pt"><a class='q-label q-condition-label'
|
><span class="q-wrap"><fittext vertical maxsize="14pt"><a class='q-label q-condition-label'
|
||||||
:title="c.tooltip" href="#" @click.prevent
|
:title="c.tooltip" href="#" @click.prevent
|
||||||
|
@ -577,6 +571,25 @@ export default {
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr> <!-- student info heading -->
|
||||||
|
<th class="q-studentinfo q-name">
|
||||||
|
<fittext maxsize="12pt"
|
||||||
|
><a href="#" @click.prevent="toggleSort('firstname')">{{text.firstname}}</a
|
||||||
|
><i v-if="sorting.header=='firstname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
|
||||||
|
><i v-else-if="sorting.header=='firstname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i>
|
||||||
|
/ <a href="#" @click.prevent="toggleSort('lastname')">{{text.lastname}}</a
|
||||||
|
><i v-if="sorting.header=='lastname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
|
||||||
|
><i v-else-if="sorting.header=='lastname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
|
||||||
|
></fittext>
|
||||||
|
</th>
|
||||||
|
<th class="q-studentinfo q-email">
|
||||||
|
<fittext maxsize="12pt"
|
||||||
|
><a href="#" @click.prevent="toggleSort('lastaccess')">{{text.lastaccess}}</a
|
||||||
|
><i v-if="sorting.header=='lastaccess' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
|
||||||
|
><i v-else-if="sorting.header=='lastaccess' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
|
||||||
|
></fittext>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
|
@ -678,6 +691,13 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
lastaccess() {
|
||||||
|
if (this.student.lastaccess) {
|
||||||
|
return format_datetime(this.student.lastaccess*1000); // Takes date in milliseconds
|
||||||
|
} else {
|
||||||
|
return this.text.never;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
useritems(line) {
|
useritems(line) {
|
||||||
|
@ -705,7 +725,7 @@ export default {
|
||||||
template: `
|
template: `
|
||||||
<tr :class="'q-student-results userrow ' + (even?'even':'odd')">
|
<tr :class="'q-student-results userrow ' + (even?'even':'odd')">
|
||||||
<td class='q-studentinfo q-name'><fittext maxsize="12pt">{{student.firstname}} {{student.lastname}}</fittext></td>
|
<td class='q-studentinfo q-name'><fittext maxsize="12pt">{{student.firstname}} {{student.lastname}}</fittext></td>
|
||||||
<td class='q-studentinfo q-email'><fittext maxsize="12pt">{{student.email}}</fittext></td>
|
<td class='q-studentinfo q-email'><fittext maxsize="12pt">{{lastaccess}}</fittext></td>
|
||||||
<template v-for="p in structure.periods">
|
<template v-for="p in structure.periods">
|
||||||
<template v-if="expansion.periods[p.period.id].expanded && p.lines.length > 0">
|
<template v-if="expansion.periods[p.period.id].expanded && p.lines.length > 0">
|
||||||
<template v-for="l in p.lines">
|
<template v-for="l in p.lines">
|
||||||
|
|
|
@ -20,6 +20,30 @@ export function format_date(d,short){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a date according to localized custom
|
||||||
|
* @param {Date|string} d The date to convert
|
||||||
|
* @param {boolean} short Short format (default false)
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function format_datetime(d,short){
|
||||||
|
if(!(d instanceof Date)){
|
||||||
|
d = new Date(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
let monthformat = "short";
|
||||||
|
if(short === true){
|
||||||
|
monthformat = "numeric";
|
||||||
|
} else if (short === false) {
|
||||||
|
monthformat = "long";
|
||||||
|
}
|
||||||
|
return d.toLocaleDateString(document.documentElement.lang,{
|
||||||
|
year: 'numeric', month: monthformat, day: 'numeric'
|
||||||
|
})+" "+d.toLocaleTimeString(document.documentElement.lang,{
|
||||||
|
timeStyle: "short",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides standardized information about the period between two dates
|
* Provides standardized information about the period between two dates
|
||||||
* As
|
* As
|
||||||
|
|
|
@ -53,6 +53,7 @@ class associationservice extends \external_api {
|
||||||
"lastname" => new \external_value(PARAM_TEXT, 'last name'),
|
"lastname" => new \external_value(PARAM_TEXT, 'last name'),
|
||||||
"idnumber" => new \external_value(PARAM_TEXT, 'id number'),
|
"idnumber" => new \external_value(PARAM_TEXT, 'id number'),
|
||||||
"email" => new \external_value(PARAM_TEXT, 'email address'),
|
"email" => new \external_value(PARAM_TEXT, 'email address'),
|
||||||
|
"lastaccess" => new \external_value(PARAM_INT, 'id of last access this user had to any course in the studyplan', VALUE_OPTIONAL),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +126,28 @@ class associationservice extends \external_api {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function user_lastaccess($userid,$studyplanid=null) {
|
||||||
|
global $DB;
|
||||||
|
if (!empty($studyplanid)) {
|
||||||
|
$lasql = "SELECT MAX(a.timeaccess) FROM {user_lastaccess} a
|
||||||
|
INNER JOIN {local_treestudyplan_item} i ON i.course_id = a.courseid
|
||||||
|
INNER JOIN {local_treestudyplan_line} l ON l.id = i.line_id
|
||||||
|
INNER JOIN {local_treestudyplan_page} p ON l.page_id = p.id
|
||||||
|
WHERE a.userid = :userid AND p.studyplan_id = :studyplanid";
|
||||||
|
$lastaccess = $DB->get_field_sql($lasql,["userid" => $userid, "studyplanid" => $studyplanid]);
|
||||||
|
debug::write("Got lastaccess '{$lastaccess}' for user {$userid} in plan {$studyplanid}");
|
||||||
|
} else {
|
||||||
|
$lasql = "SELECT MAX(a.timeaccess) FROM {user_lastaccess} a
|
||||||
|
WHERE a.userid = :userid";
|
||||||
|
$lastaccess = $DB->get_field_sql($lasql,["userid" => $userid]);
|
||||||
|
debug::write("Got lastaccess '{$lastaccess}' for user {$userid} in any course");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $lastaccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter description for webservice function list_cohort
|
* Parameter description for webservice function list_cohort
|
||||||
*/
|
*/
|
||||||
|
@ -454,9 +477,17 @@ class associationservice extends \external_api {
|
||||||
ORDER BY u.lastname, u.firstname";
|
ORDER BY u.lastname, u.firstname";
|
||||||
$rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]);
|
$rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
ID: 30
|
||||||
|
page: 33
|
||||||
|
plan: 28
|
||||||
|
*/
|
||||||
$users = [];
|
$users = [];
|
||||||
foreach ($rs as $u) {
|
foreach ($rs as $u) {
|
||||||
$users[] = self::make_user_model($u);
|
$user = self::make_user_model($u);
|
||||||
|
$user["lastaccess"] = self::user_lastaccess($u->id,$studyplanid);
|
||||||
|
$users[] = $user;
|
||||||
|
|
||||||
}
|
}
|
||||||
$rs->close();
|
$rs->close();
|
||||||
self::sortusermodels($users);
|
self::sortusermodels($users);
|
||||||
|
@ -601,7 +632,9 @@ class associationservice extends \external_api {
|
||||||
$rs = $DB->get_recordset_sql($sql, ["cohortid" => $c->id]);
|
$rs = $DB->get_recordset_sql($sql, ["cohortid" => $c->id]);
|
||||||
|
|
||||||
foreach ($rs as $u) {
|
foreach ($rs as $u) {
|
||||||
$users[] = self::make_user_model($u);
|
$user = self::make_user_model($u);
|
||||||
|
$user["lastaccess"] = self::user_lastaccess($u->id,$studyplanid);
|
||||||
|
$users[] = $user;
|
||||||
}
|
}
|
||||||
$rs->close();
|
$rs->close();
|
||||||
|
|
||||||
|
|
|
@ -1586,8 +1586,11 @@ body.path-local-treestudyplan .editmode-switch-form > * {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
width: calc(24rem + var(--resultColCount) * 4rem);
|
width: calc(24rem + var(--resultColCount) * 4rem);
|
||||||
}
|
}
|
||||||
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-studentinfo col {
|
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-studentinfo col.q-name {
|
||||||
width: 12rem;
|
width: 14rem;
|
||||||
|
}
|
||||||
|
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-studentinfo col.q-lastaccess {
|
||||||
|
width: 10rem;
|
||||||
}
|
}
|
||||||
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-resultinfo col {
|
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-resultinfo col {
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
|
|
|
@ -9,8 +9,11 @@
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
width: calc((2 * 12rem) + (var(--resultColCount) * 4rem));
|
width: calc((2 * 12rem) + (var(--resultColCount) * 4rem));
|
||||||
colgroup.q-col-studentinfo {
|
colgroup.q-col-studentinfo {
|
||||||
col {
|
col.q-name {
|
||||||
width: 12rem;
|
width: 14rem;
|
||||||
|
}
|
||||||
|
col.q-lastaccess {
|
||||||
|
width: 10rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
colgroup.q-col-resultinfo {
|
colgroup.q-col-resultinfo {
|
||||||
|
|
|
@ -1586,8 +1586,11 @@ body.path-local-treestudyplan .editmode-switch-form > * {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
width: calc(24rem + var(--resultColCount) * 4rem);
|
width: calc(24rem + var(--resultColCount) * 4rem);
|
||||||
}
|
}
|
||||||
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-studentinfo col {
|
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-studentinfo col.q-name {
|
||||||
width: 12rem;
|
width: 14rem;
|
||||||
|
}
|
||||||
|
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-studentinfo col.q-lastaccess {
|
||||||
|
width: 10rem;
|
||||||
}
|
}
|
||||||
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-resultinfo col {
|
.path-local-treestudyplan table.q-studyplanreport colgroup.q-col-resultinfo col {
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user