182 lines
8.9 KiB
JavaScript
182 lines
8.9 KiB
JavaScript
Vue.component('tt-detail-table', {
|
|
//language=Vue
|
|
template: `
|
|
<table class="table table-sm table-striped view-table">
|
|
<tbody>
|
|
<tr v-for="(item, key) in detailItems" :key="key">
|
|
<td v-html="item.label.replaceAll('s', 's<wbr>') + ':'"></td>
|
|
<td>
|
|
<template v-if="item.hasOwnProperty('url')">
|
|
<a :href="item.url" target="_blank">{{item.value}}</a>
|
|
</template>
|
|
<template v-else>
|
|
{{item.value.includes('1970') ? '' : item.value}}
|
|
</template>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>`, props: ['detailItems'],
|
|
})
|
|
|
|
Vue.component('contract-journal', {
|
|
//language=Vue
|
|
template: `
|
|
<div>
|
|
<tt-card>
|
|
<template v-slot:header>
|
|
<h5 class="text-center">Journaleinträge</h5>
|
|
</template>
|
|
|
|
<div class="contract-journal-grid">
|
|
<template v-for="(entry, index) in journalEntries">
|
|
<!-- odd index should have class contract-journal-striped-background-->
|
|
<div :class="index % 2 === 0 ? 'contract-journal-striped-background' : ''" style="padding-right: 8px" class="text-monospace">{{entry.create}} ({{entry.creator}})</div>
|
|
<div :class="index % 2 === 0 ? 'contract-journal-striped-background' : ''"><i :class="entry.icon" :title="entry.iconTitle"></i></div>
|
|
|
|
<!-- if entry.text is longer than 180 characters add fa-caret in front of the text and use parseTextAddUrls to include html <a>-->
|
|
<template v-if="entry.text.length > 130">
|
|
<div
|
|
:class="index % 2 === 0 ? 'contract-journal-striped-background' : ''"
|
|
v-if="!expandedTexts.includes(index)"
|
|
@click="expandedTexts.push(index)" style="cursor: pointer;">
|
|
<div :class="entry.textClass" v-html="parseTextAddUrls(entry, 'fas fa-caret-down').substring(0, 130) + '...'"></div>
|
|
</div>
|
|
<div :class="index % 2 === 0 ? 'contract-journal-striped-background' : ''" v-if="expandedTexts.includes(index)" style="cursor: pointer;" @click="expandedTexts = expandedTexts.filter(i => i !== index)">
|
|
<div :class="entry.textClass" v-html="parseTextAddUrls(entry, 'fas fa-caret-up', true)"></div>
|
|
</div>
|
|
</template>
|
|
<template v-else>
|
|
<div :class="index % 2 === 0 ? 'contract-journal-striped-background' : ''"><div :class="entry.textClass" v-html="parseTextAddUrls(entry)"></div></div>
|
|
</template>
|
|
|
|
<hr style="grid-column: 1 / span 3; border-top: 1px solid #e9ecef; margin: 0;">
|
|
</template>
|
|
|
|
<div class="ml-3" style="grid-column: 1 / span 3">
|
|
<button type="button" class="btn btn-sm btn-info" @click="showNewJournal = !showNewJournal"
|
|
><i class="fas fa-plus"></i> Journaleintrag hinzufügen
|
|
</button>
|
|
</div>
|
|
<div class="card-body border-top mt-2" v-if="showNewJournal" id="new-journal" style="grid-column: 1 / span 3">
|
|
<form method="post" :action="window.TT_CONFIG['CONTRACT_NEW_JOURNAL_URL']" enctype="multipart/form-data">
|
|
<input type="hidden" name="contract_id" :value="contractId"/>
|
|
|
|
<label for="new_journal_type" class="form-label">Typ</label>
|
|
<select name="type" id="new_journal_type" class="form-control mb-2">
|
|
<option value="phone">Telefongespräch</option>
|
|
<option value="text">Kommentar</option>
|
|
<option value="file">Dateiupload</option>
|
|
</select>
|
|
|
|
<label for="new_journal_text" class="form-label">Text</label>
|
|
<textarea name="text" id="new_journal_text" class="form-control mb-2" style="height:120px;"></textarea>
|
|
|
|
<div id="new-journal-file-container" class="hidden">
|
|
<label for="new_journal_file" class="form-label">Dateianhang</label>
|
|
<input type="file" name="journal_file" id="new_journal_file" class="form-control mb-2"/>
|
|
</div>
|
|
|
|
<button class="btn btn-sm btn-primary" type="submit"><i class="fas fa-save mr-1"></i> Speichern</button>
|
|
</form>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</tt-card>
|
|
</div>
|
|
`, props: ['journalEntries', 'contractId'], data() {
|
|
return {
|
|
expandedTexts: [], showNewJournal: false, window: window
|
|
}
|
|
}, methods: {
|
|
parseTextAddUrls(entry, addIcon = null, replaceNewLines = false) {
|
|
let text = JSON.parse(JSON.stringify(entry)).text
|
|
if (replaceNewLines) {
|
|
text = text.replace(/(?:\r\n|\r|\n)/g, '<br>')
|
|
}
|
|
|
|
// if addIcon is set, add it to the beginning of the text
|
|
if (addIcon) {
|
|
text = `<i class="${addIcon} mr-1"></i> ${text}`
|
|
}
|
|
|
|
if (entry.url && entry["urlText"]) {
|
|
return text.replace('[URL]', `<a href="${entry.url}" target="_blank">${entry["urlText"]}</a>`)
|
|
}
|
|
return text
|
|
}
|
|
}
|
|
})
|
|
|
|
|
|
Vue.component('contract-view', {
|
|
//language=Vue
|
|
template: `
|
|
<div>
|
|
|
|
<tt-card>
|
|
<template v-slot:header>
|
|
<div class="contract-view-header">
|
|
<tt-button :href="window.TT_CONFIG['BACK_URL']" sm text="Zurück" icon="fas fa-arrow-left" additional-class="btn-primary"/>
|
|
|
|
<h2 class="text-center" :class="isPrivateProduct ? 'text-dark-red' : 'text-primary'">
|
|
{{window.TT_CONFIG.HEADER}}</h2>
|
|
|
|
<tt-button :href="window.TT_CONFIG['EDIT_URL']" sm text="Vertrag bearbeiten" icon="fas fa-edit" additional-class="btn-success"/>
|
|
</div>
|
|
<h3 class="text-center">{{subHeader}}</h3>
|
|
</template>
|
|
|
|
<div class="contract-view">
|
|
<tt-card no-body-padding-top class="contract-view-details-grid">
|
|
<h5 class="text-center">Vertragsdaten</h5>
|
|
<tt-detail-table :detail-items="contractDetails"/>
|
|
</tt-card>
|
|
|
|
<div class="contract-view-actions-grid">
|
|
<tt-card no-body-padding-top class="contract-view-actions">
|
|
<h5 class="text-center">Aktionen</h5>
|
|
<tt-button v-for="action in window.TT_CONFIG['CONTRACT_ACTIONS']" :href="action.url" sm :text="action.text" :icon="action.icon"
|
|
:additional-class="action.class" :confirm-text="action.confirmText" :key="action.text" class="mt-2"/>
|
|
</tt-card>
|
|
</div>
|
|
|
|
<contract-journal class="contract-view-journal-grid"
|
|
:journal-entries="window.TT_CONFIG['CONTRACT_JOURNAL']"
|
|
:contract-id="window.TT_CONFIG['CONTRACT_ID']"/>
|
|
|
|
<tt-card no-body-padding-top body-overflow-x-auto style="grid-column: 1" class="contract-view-links-grid">
|
|
<h5 class="text-center">Vertragslinks</h5>
|
|
<div v-html="contractLinkTableHTML"></div>
|
|
</tt-card>
|
|
|
|
</div>
|
|
|
|
|
|
</tt-card>
|
|
|
|
</div>
|
|
`, data() {
|
|
return {
|
|
window: window,
|
|
header: window.TT_CONFIG["HEADER"],
|
|
subHeader: window.TT_CONFIG["SUB_HEADER"],
|
|
contractDetails: window.TT_CONFIG["CONTRACT_DETAILS"],
|
|
contractLinkTableHTML: null,
|
|
}
|
|
}, computed: {
|
|
isPrivateProduct() {
|
|
return window.TT_CONFIG["HEADER"].includes('Privat')
|
|
}
|
|
},
|
|
async mounted() {
|
|
const response = await axios.get(window.TT_CONFIG["CONTRACT_LINK_TABLE_URL"])
|
|
this.contractLinkTableHTML = response.data
|
|
console.log(response.data)
|
|
}
|
|
})
|