update some code.
This commit is contained in:
@@ -0,0 +1,637 @@
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function () {
|
||||
'use strict';
|
||||
return String.prototype.indexOf.apply(this, arguments) !== -1;
|
||||
};
|
||||
}
|
||||
//extend FileReader
|
||||
if (!FileReader.prototype.readAsBinaryString) {
|
||||
FileReader.prototype.readAsBinaryString = function (fileData) {
|
||||
var binary = "";
|
||||
var pt = this;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
var bytes = new Uint8Array(reader.result);
|
||||
var length = bytes.byteLength;
|
||||
for (var i = 0; i < length; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
//pt.result - readonly so assign binary
|
||||
pt.content = binary;
|
||||
$(pt).trigger('onload');
|
||||
}
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
}
|
||||
|
||||
//localStorage persistence
|
||||
var SHIFT_STORAGE_KEY = "dienstplan_chrosey";
|
||||
var RULE_STORAGE_KEY = "regeln_chrosey";
|
||||
var shiftStorage = {
|
||||
fetch: function () {
|
||||
'use strict';
|
||||
var parsed = JSON.parse(localStorage.getItem(SHIFT_STORAGE_KEY) || '[]'),
|
||||
shifts = [];
|
||||
parsed.forEach(function (el, index) {
|
||||
var shift = Shift.thaw(el);
|
||||
shift.id = index;
|
||||
shifts.push(shift);
|
||||
});
|
||||
shiftStorage.uid = shifts.length;
|
||||
return shifts;
|
||||
},
|
||||
save : function (shifts) {
|
||||
'use strict';
|
||||
var json = JSON.stringify(shifts)
|
||||
localStorage.setItem(SHIFT_STORAGE_KEY, json);
|
||||
},
|
||||
count: function () {
|
||||
return JSON.parse(localStorage.getItem(SHIFT_STORAGE_KEY) || '[]').length;
|
||||
}
|
||||
};
|
||||
var ruleStorage = {
|
||||
fetch: function () {
|
||||
'use strict';
|
||||
var parsed = JSON.parse(localStorage.getItem(RULE_STORAGE_KEY)) | [];
|
||||
var rules = parsed.length > 0 ?
|
||||
parsed.map((e, i) => {
|
||||
var r = Rule.thaw(e);
|
||||
r.id = i;
|
||||
return r;
|
||||
}) :
|
||||
Rule.defaults();
|
||||
ruleStorage.uid = rules.length;
|
||||
return rules;
|
||||
},
|
||||
save : function (rules) {
|
||||
'use strict';
|
||||
var json = JSON.stringify(rules);
|
||||
localStorage.setItem(RULE_STORAGE_KEY, json);
|
||||
}
|
||||
};
|
||||
|
||||
Vue.component('ask-format-modal', {
|
||||
template: `
|
||||
<div id="ask-format-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Dienstplanformat</h4>
|
||||
<p>Welches Format soll eingelesen werden?</p>
|
||||
<label v-for="option in options" >
|
||||
<input name="dpFormat" type="radio" :value="option" v-model="picked"/>
|
||||
<span>{{ option }}</span>
|
||||
</label>
|
||||
<p>Ausgewählt: {{ picked }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-close waves-effect waves-green btn-flat" @click.stop="submitPick">Bastätigen</a>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
picked: null
|
||||
}
|
||||
},
|
||||
props : ["options"],
|
||||
methods: {
|
||||
submitPick() {
|
||||
this.$emit('picked-format', this.picked);
|
||||
$('#ask-format-modal').modal('close');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Vue.component('chip-input', {
|
||||
template: `
|
||||
<div class="chips no-autoinit" :id="name"></div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
instance: null,
|
||||
chips : []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
chipsData() {
|
||||
return this.instance.chipsData;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
initData: {
|
||||
deep: true,
|
||||
handler(n, o) {
|
||||
if (n !== o) {
|
||||
this.initialize();
|
||||
this.$emit('init');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
name : String,
|
||||
initData: Array
|
||||
},
|
||||
|
||||
methods: {
|
||||
initialize() {
|
||||
this.chips = this.initData.map(e => e);
|
||||
var el = $('#' + this.name)[0];
|
||||
this.instance = M.Chips.init(el, {
|
||||
data : this.chips,
|
||||
onChipAdd : () => {
|
||||
this.$emit("change", this.chipsData);
|
||||
},
|
||||
onChipDelete: () => {
|
||||
this.$emit("change", this.chipsData);
|
||||
},
|
||||
placeholder: "ist",
|
||||
secondaryPlaceholder: "oder ..."
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.initialize();
|
||||
}
|
||||
});
|
||||
|
||||
var app = new Vue({
|
||||
el : '#app',
|
||||
data : {
|
||||
shifts : shiftStorage.fetch(),
|
||||
rules : ruleStorage.fetch(),
|
||||
icsFile : null,
|
||||
blob : null,
|
||||
dp_sheet : '',
|
||||
deletedShift : '',
|
||||
format : '',
|
||||
remaining : shiftStorage.count(),
|
||||
selectedShift : new Shift({}),
|
||||
selectedShiftIndex: -1,
|
||||
selectedRule : new Rule({}),
|
||||
selectedRuleIndex : -1,
|
||||
saveto : 'dienstplan.ics',
|
||||
uploadFileName : "",
|
||||
availableFormats : ["Erfurt", "Stuttgart", "X"],
|
||||
stepper : null,
|
||||
timepickers : null,
|
||||
|
||||
config: {
|
||||
moment : {
|
||||
parse_formats : [
|
||||
"ddd, DD/ MMM. 'YY HH:mm",
|
||||
"ddd, DD/ MMM. YYYY HH:mm"
|
||||
],
|
||||
parse_language : 'en',
|
||||
display_language: 'de'
|
||||
},
|
||||
stepper : {
|
||||
firstActive: 0,
|
||||
},
|
||||
toast : {
|
||||
displayLength: 3000
|
||||
},
|
||||
timepicker: {
|
||||
twelveHour: false,
|
||||
container: '#app'
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
shifts: {
|
||||
handler: function (shifts) {
|
||||
'use strict';
|
||||
shiftStorage.save(shifts);
|
||||
this.remaining = shifts.length;
|
||||
this.icsFile = null;
|
||||
this.blob = null;
|
||||
this.makeToast("Änderungen gespeichert.");
|
||||
},
|
||||
deep : true
|
||||
},
|
||||
rules : {
|
||||
handler: function (rules) {
|
||||
'use strict';
|
||||
ruleStorage.save(rules);
|
||||
this.makeToast("Änderungen gespeichert.");
|
||||
},
|
||||
deep : true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
groupedTermine() {
|
||||
return _.chain(this.shifts).sortBy(e => e.Datum).groupBy(e => e.Datum).value();
|
||||
}
|
||||
},
|
||||
|
||||
methods : {
|
||||
updateArten(value) {
|
||||
this.selectedRule.Arten = value;
|
||||
},
|
||||
|
||||
updateTitel(value) {
|
||||
this.selectedRule.Titel = value;
|
||||
},
|
||||
|
||||
makeToast(message) {
|
||||
var toastOptions = this.config.toast;
|
||||
toastOptions.html = message;
|
||||
M.toast(toastOptions);
|
||||
},
|
||||
|
||||
openModal(elementID) {
|
||||
var element = document.getElementById(elementID);
|
||||
var modal = M.Modal.getInstance(element);
|
||||
modal.open();
|
||||
},
|
||||
|
||||
closeModal(elementID) {
|
||||
var element = document.getElementById(elementID);
|
||||
var modal = M.Modal.getInstance(element);
|
||||
modal.close();
|
||||
},
|
||||
|
||||
|
||||
onFileChange: function (event) {
|
||||
var files = event.target.files || event.dataTransfer.files;
|
||||
this.handleInputFile(files[0]);
|
||||
this.uploadFileName = files[0].name + " [" + Math.round(files[0].size / 1024) + " kB]";
|
||||
this.makeToast(this.uploadFileName + " ausgewählt");
|
||||
},
|
||||
|
||||
handleInputFile: function (file) {
|
||||
var reader = new FileReader();
|
||||
var vm = this;
|
||||
reader.onload = (e) => {
|
||||
var data = !e ? reader.content : e.target.result;
|
||||
var workbook = XLSX.read(data, {
|
||||
type : 'binary',
|
||||
cellDates: true,
|
||||
});
|
||||
var isErfurterDienstplan = workbook.SheetNames.indexOf("Dienstplan") > -1;
|
||||
|
||||
if (isErfurterDienstplan) {
|
||||
vm.parseForErfurt(workbook.Sheets["Dienstplan"]);
|
||||
} else {
|
||||
this.workbook = workbook;
|
||||
this.askForDienstplanFormat();
|
||||
}
|
||||
};
|
||||
reader.readAsBinaryString(file);
|
||||
},
|
||||
|
||||
askForDienstplanFormat: function () {
|
||||
this.makeToast("Dienstplanformat nicht erkannt.");
|
||||
this.openModal('ask-format-modal');
|
||||
},
|
||||
|
||||
parseForErfurt: function (dp) {
|
||||
var arr = XLSX.utils.sheet_to_row_object_array(dp, {
|
||||
range: 1
|
||||
});
|
||||
this.format = "Erfurt";
|
||||
var vm = this;
|
||||
var day;
|
||||
|
||||
this.makeToast("Erfurter Dienstplan erkannt.");
|
||||
|
||||
arr.forEach(element => {
|
||||
moment.locale(vm.config.moment.parse_language);
|
||||
if (element.hasOwnProperty('Datum')) {
|
||||
day = moment(element.Datum);
|
||||
console.debug(element);
|
||||
}
|
||||
|
||||
if (element.hasOwnProperty('Bemerkung')) {
|
||||
if (element.Bemerkung.toString().search(/\d\d:\d\d\s/) >= 0) {
|
||||
// prüfe ob eine Uhrzeit drinnen steht
|
||||
let sonderzeit = moment(element.Bemerkung, 'HH:mm');
|
||||
let name = element.Bemerkung.toString().replace(/\d\d:\d\d\s/, '').trim();
|
||||
let splittedName = name.split(' ');
|
||||
|
||||
let terminArt = '';
|
||||
splittedName.forEach(function (item) {
|
||||
vm.rules.forEach(function (rule) {
|
||||
rule.Arten.forEach(function (art) {
|
||||
if (art.tag == item) {
|
||||
terminArt = art.tag;
|
||||
name.replace(art.tag, '');
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
let termin = {
|
||||
datum : day.clone().hour(sonderzeit.hour()).minute(sonderzeit.minute()),
|
||||
art : terminArt,
|
||||
beschreibung: '',
|
||||
name : name.trim()
|
||||
}
|
||||
vm.addShift(new Shift(termin));
|
||||
beschreibung = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (element.hasOwnProperty('Dienst')) {
|
||||
|
||||
let times = [];
|
||||
let art, beschreibung, name = "";
|
||||
if (element.Zeit.toString().indexOf(' + ') > 0) {
|
||||
// in der Zeitspalte stehen mehrere Uhrzeiten.
|
||||
let tempTimes = element.Zeit.toString().split(' + ');
|
||||
tempTimes.forEach(function (time) {
|
||||
let mom = moment(time, 'HH:mm');
|
||||
times.push([mom.hour(), mom.minute()]);
|
||||
})
|
||||
} else if (element.Zeit.toString().indexOf(' - ') > 0) {
|
||||
// in der Zeitspalte stehen mehrere Uhrzeiten als Zeitspanne
|
||||
let tempTimes = element.Zeit.toString().split(' - ');
|
||||
|
||||
let mom = moment(tempTimes[0], 'HH:mm');
|
||||
let momEnd = moment(tempTimes[1], 'HH:mm');
|
||||
times.push([mom.hour(), mom.minute(), momEnd.hour(), momEnd.minute()]);
|
||||
} else {
|
||||
if (element.Zeit) {
|
||||
let mom = moment(element.Zeit);
|
||||
times.push([mom.hour(), mom.minute()]);
|
||||
} else {
|
||||
times.push([0, 0]);
|
||||
}
|
||||
}
|
||||
|
||||
art = element.Dienst.trim();
|
||||
|
||||
if (element.hasOwnProperty('__EMPTY')) {
|
||||
name = element.__EMPTY.trim();
|
||||
}
|
||||
|
||||
if (element.hasOwnProperty('Bemerkung')
|
||||
&& element.Bemerkung.toString().search(/\d\d:\d\d\s/) == -1) {
|
||||
beschreibung = element.Bemerkung;
|
||||
}
|
||||
|
||||
times.forEach(time => {
|
||||
var termin = {
|
||||
datum : day.clone().hour(time[0]).minute(time[1]),
|
||||
art : art,
|
||||
beschreibung: beschreibung,
|
||||
name : name
|
||||
}
|
||||
if (time.length === 4) {
|
||||
// Wenn die Zeit mehr Werte hat, dann behandle die nächsten 2 als ende
|
||||
termin.end = day.clone().hour(time[2]).minute(time[3]);
|
||||
termin.dontSetDurationFromRules = true;
|
||||
}
|
||||
vm.addShift(new Shift(termin));
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
changeTime: function (hours) {
|
||||
let temp = this.shifts;
|
||||
this.shifts = [];
|
||||
temp.forEach(shift => {
|
||||
shift.updateBeginn(hours);
|
||||
this.addShift(shift);
|
||||
});
|
||||
},
|
||||
|
||||
updateBeginn: function (shift, hours) {
|
||||
shift.updateBeginn(hours);
|
||||
this.shifts.splice(this.shifts.indexOf(shift), 1, shift);
|
||||
},
|
||||
|
||||
parseForStuttgart: function (dp) {
|
||||
var arr = XLSX.utils.sheet_to_json(dp, {
|
||||
header : "A",
|
||||
blankrows: false,
|
||||
});
|
||||
var vm = this;
|
||||
var day;
|
||||
|
||||
this.makeToast("Stuttgarter Dienstplan erkannt.");
|
||||
|
||||
arr.forEach(element => {
|
||||
moment.locale(vm.config.moment.parse_language);
|
||||
if (element.hasOwnProperty('C')) {
|
||||
day = moment(element.C);
|
||||
}
|
||||
if (element.hasOwnProperty('D') && moment(element.D, "HH:mm").isValid()) {
|
||||
var termin = {
|
||||
ort : element.H ? element.H.trim() : "",
|
||||
art : element.E ? element.E.trim() : "",
|
||||
beschreibung: element.H ? element.H.trim() : "",
|
||||
name : element.F ? element.F.trim() : ""
|
||||
}
|
||||
var time = day.clone();
|
||||
if (typeof (element.D) === "object") {
|
||||
time = moment(element.D);
|
||||
termin.datum = day.clone().hour(time.hour()).minute(time.minute());
|
||||
} else if (element.D.indexOf("-") > -1) {
|
||||
var tArray = element.D.split(" - ");
|
||||
time = moment(tArray[0], "HH:mm");
|
||||
termin.datum = day.clone().hour(time.hour()).minute(time.minute());
|
||||
termin.ende = moment(tArray[1], "HH:mm").format("HH:mm");
|
||||
}
|
||||
vm.addShift(new Shift(termin));
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
parseForX: function (dp, sheetName) {
|
||||
moment.locale(this.config.moment.parse_language);
|
||||
var arr = XLSX.utils.sheet_to_json(dp, {
|
||||
header : "A",
|
||||
blankrows: false,
|
||||
});
|
||||
var vm = this;
|
||||
var month = moment(sheetName.substr(sheetName.indexOf(" ") + 1), "MMMM YYYY", "de");
|
||||
var day;
|
||||
|
||||
arr.forEach(element => {
|
||||
var art, name, beschreibung = null;
|
||||
var time = moment().hour(0).minute(0);
|
||||
try {
|
||||
if (element.hasOwnProperty('A')) {
|
||||
day = moment(element.A, "D.", "de");
|
||||
day = Number(element.A);
|
||||
}
|
||||
if ((!element.F && !element.H && !element.J) || element.I == "Spielort/ Extras" || element.J == "Spielort/Extras") {
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if (element.hasOwnProperty("D") && element.hasOwnProperty("E")) {
|
||||
// Probe
|
||||
time = moment(element.D);
|
||||
art = element.E.trim();
|
||||
name = element.F ? element.F.trim() : "";
|
||||
beschreibung = typeof (element.I) != 'undefined' ? element.I.trim() :
|
||||
typeof (element.J) != 'undefined' ? element.J.trim() :
|
||||
"";
|
||||
} else if (element.hasOwnProperty("G") && element.hasOwnProperty("H")) {
|
||||
// Vorstellung
|
||||
time = moment(element.G);
|
||||
art = "VS";
|
||||
name = element.H.trim();
|
||||
beschreibung = typeof (element.I) != 'undefined' ? element.I.trim() :
|
||||
typeof (element.J) != 'undefined' ? element.J.trim() :
|
||||
"";
|
||||
} else if (element.hasOwnProperty("I")) {
|
||||
// Spielort/Extras
|
||||
beschreibung = element.I.trim();
|
||||
name = name ? name : "Spielort/Extras";
|
||||
} else if (element.hasOwnProperty("J")) {
|
||||
// Spielort/Extras Fallback
|
||||
beschreibung = element.J.trim();
|
||||
name = name ? name : "Spielort/Extras";
|
||||
}
|
||||
|
||||
var datumStr = day + '.' + month.clone().format("MM.YY") + time.format(" HH:mm");
|
||||
var termin = {
|
||||
ort : "",
|
||||
art : art,
|
||||
beschreibung: beschreibung,
|
||||
name : name,
|
||||
datum : moment(datumStr, "D.MM.YY HH:mm")
|
||||
}
|
||||
vm.addShift(new Shift(termin));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Parsen", element, error);
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
parsePickedFormat: function (format) {
|
||||
this.makeToast(`Versuche ${format} zu lesen.`);
|
||||
switch (format) {
|
||||
case "Erfurt":
|
||||
this.parseForErfurt(this.workbook.Sheets["Dienstplan"]);
|
||||
break;
|
||||
case "Stuttgart":
|
||||
var sheetName = this.workbook.SheetNames[0];
|
||||
this.parseForStuttgart(this.workbook.Sheets[sheetName]);
|
||||
break;
|
||||
case "X":
|
||||
var sheetName = this.workbook.SheetNames[0];
|
||||
this.parseForX(this.workbook.Sheets[sheetName], sheetName);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.workbook = null;
|
||||
},
|
||||
|
||||
addShift: function (shift) {
|
||||
this.shifts.push(shift);
|
||||
},
|
||||
|
||||
removeShift: function (shift) {
|
||||
this.shifts.splice(this.shifts.indexOf(shift), 1);
|
||||
this.makeToast(shift.VEventTitle + " gelöscht");
|
||||
},
|
||||
|
||||
cleanStorage: function () {
|
||||
this.shifts = [];
|
||||
this.makeToast("Alle Einträge gelöscht");
|
||||
},
|
||||
|
||||
createDownloadFile: function () {
|
||||
var vCal = new VCalendar("Dienstplan Kalender");
|
||||
this.shifts.forEach(function (shift) {
|
||||
vCal.add(shift.toVEvent());
|
||||
});
|
||||
var calString = vCal.toString();
|
||||
this.blob = new Blob([calString], {
|
||||
type: 'text/plain'
|
||||
});
|
||||
|
||||
if (this.icsFile !== null) {
|
||||
window.URL.revokeObjectURL(this.icsFile);
|
||||
}
|
||||
|
||||
this.icsFile = window.URL.createObjectURL(this.blob);
|
||||
this.makeToast(this.saveto + " erstellt.");
|
||||
},
|
||||
|
||||
downloadFile: function () {
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
window.navigator.msSaveOrOpenBlob(this.blob, this.saveto);
|
||||
}
|
||||
},
|
||||
|
||||
selectShift: function (shift) {
|
||||
this.selectedShift = Shift.thaw(shift);
|
||||
|
||||
this.keepShift = shift;
|
||||
M.updateTextFields();
|
||||
this.openModal('shiftModal');
|
||||
},
|
||||
|
||||
saveChanges: function (changedShift) {
|
||||
this.shifts.splice(this.shifts.indexOf(this.keepShift), 1, changedShift);
|
||||
|
||||
this.closeModal('shiftModal');
|
||||
this.keepShift = '';
|
||||
this.selectedShift = '';
|
||||
},
|
||||
|
||||
discardChanges: function (changedShift) {
|
||||
this.closeModal('shiftModal');
|
||||
this.keepShift = '';
|
||||
this.selectedShift = '';
|
||||
},
|
||||
|
||||
editRule: function (rule) {
|
||||
this.selectedRule = Rule.thaw(rule);
|
||||
this.selectedRuleIndex = this.rules.indexOf(rule);
|
||||
this.openModal('ruleModal');
|
||||
},
|
||||
|
||||
saveRule: function () {
|
||||
this.rules[this.selectedRuleIndex] = this.selectedRule;
|
||||
|
||||
this.closeModal('ruleModal');
|
||||
this.selectedRule = new Rule();
|
||||
},
|
||||
|
||||
discardRule: function () {
|
||||
this.closeModal('ruleModal');
|
||||
|
||||
this.selectedRule = new Rule();
|
||||
},
|
||||
|
||||
applyRules: function () {
|
||||
var shifts = this.shifts;
|
||||
shifts.forEach(function (shift) {
|
||||
Shift.setDurationFromRules(shift, this.rules);
|
||||
});
|
||||
this.shifts = shifts;
|
||||
}
|
||||
|
||||
},
|
||||
directives: {
|
||||
'edit-focus': function (el, value) {
|
||||
if (value) {
|
||||
el.focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted : function () {
|
||||
M.AutoInit();
|
||||
var els = document.querySelectorAll('.timepicker');
|
||||
this.timepickers = M.Timepicker.init(els, this.config.timepicker);
|
||||
var el = document.querySelector(".stepper");
|
||||
this.stepper = new MStepper(el, this.config.stepper);
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user