Added Automatic HistoryItems to Events,Customers,Vendors
This commit is contained in:
@@ -50,6 +50,8 @@ const historyItems = computed(() => {
|
|||||||
items = dataStore.historyItems.filter(i => i.profile === elementId)
|
items = dataStore.historyItems.filter(i => i.profile === elementId)
|
||||||
} else if(type === "absencerequest") {
|
} else if(type === "absencerequest") {
|
||||||
items = dataStore.historyItems.filter(i => i.absenceRequest === elementId)
|
items = dataStore.historyItems.filter(i => i.absenceRequest === elementId)
|
||||||
|
} else if(type === "event") {
|
||||||
|
items = dataStore.historyItems.filter(i => i.event === elementId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
@@ -87,6 +89,8 @@ const addHistoryItem = async () => {
|
|||||||
addHistoryItemData.value.profile = elementId
|
addHistoryItemData.value.profile = elementId
|
||||||
} else if(type === "absencerequest") {
|
} else if(type === "absencerequest") {
|
||||||
addHistoryItemData.value.absenceRequest = elementId
|
addHistoryItemData.value.absenceRequest = elementId
|
||||||
|
} else if(type === "event") {
|
||||||
|
addHistoryItemData.value.event = elementId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -176,15 +180,15 @@ const renderText = (text) => {
|
|||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<UAvatar
|
<UAvatar
|
||||||
v-if="!item.user"
|
v-if="!item.createdBy"
|
||||||
:src="colorMode.value === 'light' ? '/Logo.png' : '/Logo_Dark.png' "
|
:src="colorMode.value === 'light' ? '/Logo.png' : '/Logo_Dark.png' "
|
||||||
/>
|
/>
|
||||||
<UAvatar
|
<UAvatar
|
||||||
:alt="dataStore.profiles.find(profile => profile.id === item.user).fullName"
|
:alt="dataStore.getProfileById(item.createdBy).fullName"
|
||||||
v-else
|
v-else
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h3 v-if="item.user">{{dataStore.getProfileById(item.user) ? dataStore.getProfileById(item.user).fullName : ""}}</h3>
|
<h3 v-if="item.createdBy">{{dataStore.getProfileById(item.createdBy) ? dataStore.getProfileById(item.createdBy).fullName : ""}}</h3>
|
||||||
<h3 v-else>Spaces Bot</h3>
|
<h3 v-else>Spaces Bot</h3>
|
||||||
<span v-html="renderText(item.text)"/><br>
|
<span v-html="renderText(item.text)"/><br>
|
||||||
<span class="text-gray-500">{{dayjs(item.created_at).format("DD.MM.YY HH:mm")}}</span>
|
<span class="text-gray-500">{{dayjs(item.created_at).format("DD.MM.YY HH:mm")}}</span>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const itemInfo = ref({
|
|||||||
active: true,
|
active: true,
|
||||||
isCompany: true
|
isCompany: true
|
||||||
})
|
})
|
||||||
|
const oldItemInfo = ref({})
|
||||||
|
|
||||||
//Functions
|
//Functions
|
||||||
const setupPage = async () => {
|
const setupPage = async () => {
|
||||||
@@ -31,6 +32,7 @@ const setupPage = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(mode.value === "edit") itemInfo.value = currentItem.value
|
if(mode.value === "edit") itemInfo.value = currentItem.value
|
||||||
|
if(currentItem.value.id) oldItemInfo.value = JSON.parse(JSON.stringify(currentItem.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
const editItem = async () => {
|
const editItem = async () => {
|
||||||
@@ -54,7 +56,7 @@ setupPage()
|
|||||||
<template #right>
|
<template #right>
|
||||||
<UButton
|
<UButton
|
||||||
v-if="mode === 'edit'"
|
v-if="mode === 'edit'"
|
||||||
@click="dataStore.updateItem('customers',itemInfo)"
|
@click="dataStore.updateItem('customers',itemInfo,oldItemInfo)"
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</UButton>
|
</UButton>
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ const mode = ref(route.params.mode || "show")
|
|||||||
const itemInfo = ref({
|
const itemInfo = ref({
|
||||||
resources: []
|
resources: []
|
||||||
})
|
})
|
||||||
|
const oldItemInfo = ref({})
|
||||||
|
|
||||||
const resourceToAdd = ref(dataStore.activeProfile.id)
|
const resourceToAdd = ref(dataStore.activeProfile.id)
|
||||||
const mapResources = () => {
|
/*const mapResources = () => {
|
||||||
console.log(itemInfo.value.resources)
|
console.log(itemInfo.value.resources)
|
||||||
itemInfo.value.resources.map(resource => {
|
itemInfo.value.resources.map(resource => {
|
||||||
console.log(resource)
|
console.log(resource)
|
||||||
@@ -22,7 +23,7 @@ const mapResources = () => {
|
|||||||
type: resource.type
|
type: resource.type
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
const setupPage = () => {
|
const setupPage = () => {
|
||||||
@@ -39,6 +40,7 @@ const setupPage = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
if(route.query.project) itemInfo.value.project = route.query.project
|
if(route.query.project) itemInfo.value.project = route.query.project
|
||||||
|
if(itemInfo.value.id) oldItemInfo.value = JSON.parse(JSON.stringify(itemInfo.value))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ setupPage()
|
|||||||
Erstellen
|
Erstellen
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
@click="dataStore.updateItem('events',itemInfo)"
|
@click="dataStore.updateItem('events',itemInfo,oldItemInfo)"
|
||||||
v-else-if="mode === 'edit' && route.params.id"
|
v-else-if="mode === 'edit' && route.params.id"
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
@@ -92,7 +94,11 @@ setupPage()
|
|||||||
{{itemInfo}}
|
{{itemInfo}}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.label === 'Logbuch'">
|
<div v-if="item.label === 'Logbuch'">
|
||||||
|
<HistoryDisplay
|
||||||
|
type="event"
|
||||||
|
v-if="itemInfo"
|
||||||
|
:element-id="itemInfo.id"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
5
pages/vendors/[mode]/[[id]].vue
vendored
5
pages/vendors/[mode]/[[id]].vue
vendored
@@ -19,6 +19,7 @@ const mode = ref(route.params.mode || "show")
|
|||||||
const itemInfo = ref({
|
const itemInfo = ref({
|
||||||
infoData: {}
|
infoData: {}
|
||||||
})
|
})
|
||||||
|
const oldItemInfo = ref({})
|
||||||
|
|
||||||
//Functions
|
//Functions
|
||||||
const setupPage = () => {
|
const setupPage = () => {
|
||||||
@@ -27,6 +28,8 @@ const setupPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode.value === "edit") itemInfo.value = currentItem.value
|
if (mode.value === "edit") itemInfo.value = currentItem.value
|
||||||
|
if(currentItem.value.id) oldItemInfo.value = JSON.parse(JSON.stringify(currentItem.value))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const editItem = async () => {
|
const editItem = async () => {
|
||||||
@@ -49,7 +52,7 @@ setupPage()
|
|||||||
<template #right>
|
<template #right>
|
||||||
<UButton
|
<UButton
|
||||||
v-if="mode === 'edit'"
|
v-if="mode === 'edit'"
|
||||||
@click="dataStore.updateItem('vendors',itemInfo)"
|
@click="dataStore.updateItem('vendors',itemInfo,oldItemInfo)"
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</UButton>
|
</UButton>
|
||||||
|
|||||||
264
stores/data.js
264
stores/data.js
@@ -17,13 +17,15 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
tasks: {
|
tasks: {
|
||||||
label: "Aufgaben",
|
label: "Aufgaben",
|
||||||
labelSingle: "Aufgabe",
|
labelSingle: "Aufgabe",
|
||||||
redirect: true
|
redirect: true,
|
||||||
|
historyItemHolder: "task"
|
||||||
},
|
},
|
||||||
customers: {
|
customers: {
|
||||||
label: "Kunden",
|
label: "Kunden",
|
||||||
labelSingle: "Kunde",
|
labelSingle: "Kunde",
|
||||||
redirect:true,
|
redirect:true,
|
||||||
numberRangeHolder: "customerNumber"
|
numberRangeHolder: "customerNumber",
|
||||||
|
historyItemHolder: "customer"
|
||||||
},
|
},
|
||||||
contacts: {
|
contacts: {
|
||||||
label: "Kontakte",
|
label: "Kontakte",
|
||||||
@@ -100,7 +102,9 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
label: "Termine",
|
label: "Termine",
|
||||||
labelSingle: "Termin"
|
labelSingle: "Termin",
|
||||||
|
historyItemHolder: "event",
|
||||||
|
redirect: true
|
||||||
},
|
},
|
||||||
profiles: {
|
profiles: {
|
||||||
label: "Mitarbeiter",
|
label: "Mitarbeiter",
|
||||||
@@ -400,6 +404,250 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var deepDiffMapper = function () {
|
||||||
|
return {
|
||||||
|
VALUE_CREATED: 'created',
|
||||||
|
VALUE_UPDATED: 'updated',
|
||||||
|
VALUE_DELETED: 'deleted',
|
||||||
|
VALUE_UNCHANGED: 'unchanged',
|
||||||
|
map: function(obj1, obj2) {
|
||||||
|
if (this.isFunction(obj1) || this.isFunction(obj2)) {
|
||||||
|
throw 'Invalid argument. Function given, object expected.';
|
||||||
|
}
|
||||||
|
if (this.isValue(obj1) || this.isValue(obj2)) {
|
||||||
|
return {
|
||||||
|
type: this.compareValues(obj1, obj2),
|
||||||
|
data: {o: obj1, n: obj2}//obj1 === undefined ? obj2 : obj1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var diff = {};
|
||||||
|
for (var key in obj1) {
|
||||||
|
if (this.isFunction(obj1[key])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value2 = undefined;
|
||||||
|
if (obj2[key] !== undefined) {
|
||||||
|
value2 = obj2[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
diff[key] = this.map(obj1[key], value2);
|
||||||
|
}
|
||||||
|
for (var key in obj2) {
|
||||||
|
if (this.isFunction(obj2[key]) || diff[key] !== undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff[key] = this.map(undefined, obj2[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
|
||||||
|
},
|
||||||
|
compareValues: function (value1, value2) {
|
||||||
|
if (value1 === value2) {
|
||||||
|
return this.VALUE_UNCHANGED;
|
||||||
|
}
|
||||||
|
if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
|
||||||
|
return this.VALUE_UNCHANGED;
|
||||||
|
}
|
||||||
|
if (value1 === undefined) {
|
||||||
|
return this.VALUE_CREATED;
|
||||||
|
}
|
||||||
|
if (value2 === undefined) {
|
||||||
|
return this.VALUE_DELETED;
|
||||||
|
}
|
||||||
|
return this.VALUE_UPDATED;
|
||||||
|
},
|
||||||
|
isFunction: function (x) {
|
||||||
|
return Object.prototype.toString.call(x) === '[object Function]';
|
||||||
|
},
|
||||||
|
isArray: function (x) {
|
||||||
|
return Object.prototype.toString.call(x) === '[object Array]';
|
||||||
|
},
|
||||||
|
isDate: function (x) {
|
||||||
|
return Object.prototype.toString.call(x) === '[object Date]';
|
||||||
|
},
|
||||||
|
isObject: function (x) {
|
||||||
|
return Object.prototype.toString.call(x) === '[object Object]';
|
||||||
|
},
|
||||||
|
isValue: function (x) {
|
||||||
|
return !this.isObject(x) && !this.isArray(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const generateHistoryItems = async (dataType,newData, oldData=null) => {
|
||||||
|
//console.log(oldData)
|
||||||
|
//console.log(newData)
|
||||||
|
|
||||||
|
let itemsToCreate = []
|
||||||
|
|
||||||
|
const checkPropState = (key,propContent) => {
|
||||||
|
//console.log(propContent)
|
||||||
|
if(propContent.type && propContent.data){
|
||||||
|
if(propContent.type === "updated" ||propContent.type === "created"){
|
||||||
|
createHistoryItem(key,propContent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let prop in propContent) {
|
||||||
|
checkPropState(prop,propContent[prop])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createHistoryItem = (key,prop) => {
|
||||||
|
|
||||||
|
console.log("OLD: " + prop.data.o)
|
||||||
|
console.log("NEW: " + prop.data.n)
|
||||||
|
|
||||||
|
let name = "" || key
|
||||||
|
let oldVal = prop.data.o || "-"
|
||||||
|
let newVal = prop.data.n || "-"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(key === "project") {
|
||||||
|
name = "Projekt"
|
||||||
|
oldVal = projects.value.find(i => i.id === prop.data.o).name
|
||||||
|
newVal = projects.value.find(i => i.id === prop.data.n).name
|
||||||
|
} else if (key === "title") {
|
||||||
|
name = "Titel"
|
||||||
|
} else if(key === "type") {
|
||||||
|
name = "Typ"
|
||||||
|
} else if(key === "notes") {
|
||||||
|
name = "Notizen"
|
||||||
|
} else if(key === "link") {
|
||||||
|
name = "Link"
|
||||||
|
} else if(key === "start") {
|
||||||
|
name = "Start"
|
||||||
|
oldVal = dayjs(prop.data.o).format("DD.MM.YY HH:mm")
|
||||||
|
newVal = dayjs(prop.data.n).format("DD.MM.YY HH:mm")
|
||||||
|
} else if(key === "end") {
|
||||||
|
name = "Ende"
|
||||||
|
oldVal = dayjs(prop.data.o).format("DD.MM.YY HH:mm")
|
||||||
|
newVal = dayjs(prop.data.n).format("DD.MM.YY HH:mm")
|
||||||
|
} else if(key === "resources") {
|
||||||
|
name = "Resourcen"
|
||||||
|
oldVal = prop.data.o.map(i => i.title).join(", ")
|
||||||
|
newVal = prop.data.n.map(i => i.title).join(", ")
|
||||||
|
} else if(key === "customerNumber") {
|
||||||
|
name = "Kundennummer"
|
||||||
|
} else if(key === "active") {
|
||||||
|
name = "Aktiv"
|
||||||
|
if(oldVal === true){
|
||||||
|
oldVal = "Aktiv"
|
||||||
|
newVal = "Gesperrt"
|
||||||
|
} else if(oldVal === "-") {
|
||||||
|
oldVal = "Gesperrt"
|
||||||
|
newVal = "Aktiv"
|
||||||
|
}
|
||||||
|
} else if(key === "isCompany") {
|
||||||
|
name = "Firmenkunde"
|
||||||
|
if(oldVal === true){
|
||||||
|
oldVal = "Firma"
|
||||||
|
newVal = "Privatkunde"
|
||||||
|
} else if(oldVal === "-") {
|
||||||
|
oldVal = "Privatkunde"
|
||||||
|
newVal = "Firma"
|
||||||
|
}
|
||||||
|
} else if(key === "special") {
|
||||||
|
name = "Adresszusatz"
|
||||||
|
} else if(key === "street") {
|
||||||
|
name = "Straße & Hausnummer"
|
||||||
|
} else if(key === "city") {
|
||||||
|
name = "Ort"
|
||||||
|
} else if(key === "zip") {
|
||||||
|
name = "Postleitzahl"
|
||||||
|
} else if(key === "country") {
|
||||||
|
name = "Land"
|
||||||
|
} else if(key === "web") {
|
||||||
|
name = "Webseite"
|
||||||
|
} else if(key === "email") {
|
||||||
|
name = "E-Mail"
|
||||||
|
} else if(key === "tel") {
|
||||||
|
name = "Telefon"
|
||||||
|
} else if(key === "ustid") {
|
||||||
|
name = "USt-ID"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let text = ""
|
||||||
|
if(prop.type === "updated" && newVal !== "-" && oldVal !== "-") {
|
||||||
|
text = `Verändert: ${name} von "${oldVal}" zu "${newVal}"`
|
||||||
|
} else if(prop.type === "updated" && newVal !== "-" && oldVal === "-") {
|
||||||
|
text = `Hinzugefügt: ${name} "${newVal}"`
|
||||||
|
} else if(prop.type === "created") {
|
||||||
|
text = `Hinzugefügt: ${name} "${newVal}"`
|
||||||
|
} else if(prop.type === "updated" && newVal === "-" && oldVal !== "-") {
|
||||||
|
text = `Entfernt: ${name} "${oldVal}"`
|
||||||
|
}
|
||||||
|
|
||||||
|
let historyItem = {
|
||||||
|
text: text,
|
||||||
|
createdBy: activeProfile.value.id,
|
||||||
|
oldVal: prop.data.o,
|
||||||
|
newVal: prop.data.n,
|
||||||
|
tenant: currentTenant.value
|
||||||
|
}
|
||||||
|
|
||||||
|
historyItem[dataTypes[dataType].historyItemHolder] = newData.id
|
||||||
|
|
||||||
|
console.log(historyItem)
|
||||||
|
itemsToCreate.push(historyItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oldData) {
|
||||||
|
let result = deepDiffMapper.map(oldData,newData)
|
||||||
|
|
||||||
|
console.log(result)
|
||||||
|
|
||||||
|
for (let prop in result) {
|
||||||
|
//console.log(prop)
|
||||||
|
checkPropState(prop,result[prop])
|
||||||
|
|
||||||
|
|
||||||
|
//console.log(prop)
|
||||||
|
//console.log(result[prop])
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let historyItem = {
|
||||||
|
text: `${dataTypes[dataType].labelSingle} erstellt`,
|
||||||
|
createdBy: activeProfile.value.id,
|
||||||
|
tenant: currentTenant.value
|
||||||
|
}
|
||||||
|
|
||||||
|
historyItem[dataTypes[dataType].historyItemHolder] = newData.id
|
||||||
|
|
||||||
|
console.log(historyItem)
|
||||||
|
itemsToCreate.push(historyItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*const {data,error} = await supabase.from("historyitems").insert(itemsToCreate)
|
||||||
|
|
||||||
|
if(error) {
|
||||||
|
console.log(error)
|
||||||
|
} else {
|
||||||
|
fetchHistoryItems()
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Realtime Update
|
//Realtime Update
|
||||||
const channelA = supabase
|
const channelA = supabase
|
||||||
@@ -454,6 +702,8 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const {data:supabaseData,error:supabaseError} = await supabase
|
const {data:supabaseData,error:supabaseError} = await supabase
|
||||||
.from(dataType)
|
.from(dataType)
|
||||||
.insert(data)
|
.insert(data)
|
||||||
@@ -463,6 +713,8 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
console.log(supabaseError)
|
console.log(supabaseError)
|
||||||
toast.add({title: "Es ist ein Fehler bei der Erstellung aufgetreten", color: "rose"})
|
toast.add({title: "Es ist ein Fehler bei der Erstellung aufgetreten", color: "rose"})
|
||||||
} else if (supabaseData) {
|
} else if (supabaseData) {
|
||||||
|
console.log(supabaseData)
|
||||||
|
await generateHistoryItems(dataType, supabaseData[0])
|
||||||
await eval( dataType + '.value.push(' + JSON.stringify(...supabaseData) + ')')
|
await eval( dataType + '.value.push(' + JSON.stringify(...supabaseData) + ')')
|
||||||
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
|
toast.add({title: `${dataTypes[dataType].labelSingle} hinzugefügt`})
|
||||||
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
|
if(dataTypes[dataType].redirect) await router.push(`/${dataType}/show/${supabaseData[0].id}`)
|
||||||
@@ -470,12 +722,11 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateItem (dataType, data) {
|
async function updateItem (dataType, data, oldData = null) {
|
||||||
|
|
||||||
const {tenants, ...newData} = data
|
const {tenants, ...newData} = data
|
||||||
|
|
||||||
|
await generateHistoryItems(dataType,data,oldData)
|
||||||
|
|
||||||
|
|
||||||
const {data:supabaseData,error: supabaseError} = await supabase
|
const {data:supabaseData,error: supabaseError} = await supabase
|
||||||
.from(dataType)
|
.from(dataType)
|
||||||
@@ -1164,6 +1415,7 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
changeProfile,
|
changeProfile,
|
||||||
uploadFiles,
|
uploadFiles,
|
||||||
hasRight,
|
hasRight,
|
||||||
|
generateHistoryItems,
|
||||||
|
|
||||||
//Data
|
//Data
|
||||||
profiles,
|
profiles,
|
||||||
|
|||||||
Reference in New Issue
Block a user