added input masks to EmployeeDetails, started implementing Employees/Index. Updated to Vue 3.2.21
This commit is contained in:
890
package-lock.json
generated
890
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
|
"build-test": "vite build",
|
||||||
"serve": "vite preview"
|
"serve": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -18,7 +19,8 @@
|
|||||||
"pinia": "^2.0.0-rc.13",
|
"pinia": "^2.0.0-rc.13",
|
||||||
"pinia-plugin-persist": "^0.0.92",
|
"pinia-plugin-persist": "^0.0.92",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"vue": "^3.2.20",
|
"vue": "^3.2.21",
|
||||||
|
"vue-imask": "^6.2.2",
|
||||||
"vue-router": "^4.0.12",
|
"vue-router": "^4.0.12",
|
||||||
"vue-tsc": "^0.3.0"
|
"vue-tsc": "^0.3.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
|
|
||||||
AddEmployeeModal(
|
AddEmployeeModal(
|
||||||
:searchData="employees"
|
:searchData="rows"
|
||||||
:searchFields="['name']"
|
:searchFields="['first_name', 'last_name']"
|
||||||
:searchRow="addEmployeeRow"
|
:searchRow="addEmployeeRow"
|
||||||
:modalId="modalId"
|
:modalId="modalId"
|
||||||
@emitResult="addEmployee($event)"
|
@emitResult="addEmployee($event)"
|
||||||
@@ -144,7 +144,7 @@ AddEmployeeModal(
|
|||||||
const addEmployeeRow : Ref<number> = ref(-1)
|
const addEmployeeRow : Ref<number> = ref(-1)
|
||||||
const addEmployeeMonth : Ref<number> = ref(-1)
|
const addEmployeeMonth : Ref<number> = ref(-1)
|
||||||
const scheduleData : Ref<ScheduleData> = ref(getScheduleData())
|
const scheduleData : Ref<ScheduleData> = ref(getScheduleData())
|
||||||
const { employees } = storeToRefs(store)
|
const { rows } = storeToRefs(store)
|
||||||
|
|
||||||
const selected : Ref<string[]> = ref([])
|
const selected : Ref<string[]> = ref([])
|
||||||
const shiftAnchor : Ref<Coordinates | undefined> = ref(undefined)
|
const shiftAnchor : Ref<Coordinates | undefined> = ref(undefined)
|
||||||
|
|||||||
@@ -16,18 +16,19 @@ async function onLogout() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav class="nav justify-content-center border-bottom mb-4 pb-2 d-flex">
|
<nav class="nav justify-content-center border-bottom mb-4 pb-2 d-flex">
|
||||||
<router-link class="nav-link" to="/">Home</router-link>
|
<router-link class="nav-link" :to="{name: 'Home'}">Home</router-link>
|
||||||
|
<router-link v-if="userStore.isAdmin" :to="{name: 'Employees/Index'}" class="nav-link">Mitarbeiter</router-link>
|
||||||
<div class="ms-auto"></div>
|
<div class="ms-auto"></div>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="userStore.isLoggedIn"
|
v-if="userStore.isLoggedIn"
|
||||||
class="nav-link"
|
class="nav-link"
|
||||||
to="/employees/me"
|
:to="{name: 'Employees/Details', params: {id: 'me'}}"
|
||||||
>
|
>
|
||||||
Profile
|
Profil
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<a v-if="userStore.isLoggedIn" href="#" @click="onLogout()" class="nav-link">Logout</a>
|
<a v-if="userStore.isLoggedIn" href="#" @click="onLogout()" class="nav-link">Logout</a>
|
||||||
<router-link v-else to="Login" class="nav-link">Login</router-link>
|
<router-link v-else :to="{name: 'Login'}" class="nav-link">Login</router-link>
|
||||||
</nav>
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function onCancel() {
|
|||||||
Mitarbeiter bearbeiten
|
Mitarbeiter bearbeiten
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button v-if="isActive" type="button" @click="onSave" class="btn btn-success ms-auto">
|
<button v-if="isActive" type="submit" @click.prevent="onSave" class="btn btn-success ms-auto">
|
||||||
<i class="bi bi-save"></i>
|
<i class="bi bi-save"></i>
|
||||||
Mitarbeiter speichern
|
Mitarbeiter speichern
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -21,10 +21,19 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
requiresAdmin: false
|
requiresAdmin: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/employees',
|
||||||
|
name: 'Employees/Index',
|
||||||
|
component: () => import('@/views/Employees/Index.vue'),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: true,
|
||||||
|
requiresAdmin: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/employees/:id',
|
path: '/employees/:id',
|
||||||
name: 'EmployeesDetails',
|
name: 'Employees/Details',
|
||||||
component: () => import('@/views/EmployeesDetails.vue'),
|
component: () => import('@/views/Employees/Details.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
requiresAdmin: false
|
requiresAdmin: false
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ type ResultData = {
|
|||||||
phone: string | undefined,
|
phone: string | undefined,
|
||||||
mobile: string | undefined,
|
mobile: string | undefined,
|
||||||
email: string | undefined,
|
email: string | undefined,
|
||||||
contractHours: number | undefined,
|
contractHours: number,
|
||||||
isActive: boolean,
|
isActive: boolean,
|
||||||
username: string | undefined,
|
username: string | undefined,
|
||||||
role: string
|
role: string
|
||||||
@@ -34,7 +34,7 @@ export const useEmployee = defineStore({
|
|||||||
phone: '',
|
phone: '',
|
||||||
mobile: '',
|
mobile: '',
|
||||||
email: '',
|
email: '',
|
||||||
contractHours: NaN,
|
contractHours: 0,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
@@ -50,7 +50,7 @@ export const useEmployee = defineStore({
|
|||||||
phone: '',
|
phone: '',
|
||||||
mobile: '',
|
mobile: '',
|
||||||
email: '',
|
email: '',
|
||||||
contractHours: NaN,
|
contractHours: 0,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
@@ -60,15 +60,24 @@ export const useEmployee = defineStore({
|
|||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
assignTruthyValues(target: Object, source: Object) {
|
||||||
|
for (const key in source) {
|
||||||
|
if (source[key]) {
|
||||||
|
target[key] = source[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async fetchFromApi(id: string | string[]) {
|
async fetchFromApi(id: string | string[]) {
|
||||||
|
this.$reset()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data : ResultData = await <ResultData>(await axios.get('employees/'+id, {
|
const data : ResultData = await <ResultData>(await axios.get('employees/'+id, {
|
||||||
headers: user.header
|
headers: user.header
|
||||||
})).data
|
})).data
|
||||||
|
|
||||||
Object.assign(this.clean.employee, data)
|
this.assignTruthyValues(this.employee, data)
|
||||||
Object.assign(this.employee, data)
|
this.assignTruthyValues(this.clean.employee, data)
|
||||||
}
|
}
|
||||||
catch(err){
|
catch(err){
|
||||||
if(err instanceof Error) notifications.add('danger', err.message, -1)
|
if(err instanceof Error) notifications.add('danger', err.message, -1)
|
||||||
@@ -99,8 +108,6 @@ export const useEmployee = defineStore({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(result)
|
|
||||||
|
|
||||||
this.employee.password = ''
|
this.employee.password = ''
|
||||||
this.employee.passwordConfirm = ''
|
this.employee.passwordConfirm = ''
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,68 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { useUser } from '@/stores/user'
|
||||||
|
import axios from '@/axios'
|
||||||
|
|
||||||
import emplJSON from '../sample-data/employees.json'
|
import emplJSON from '../sample-data/employees.json'
|
||||||
|
|
||||||
|
const user = useUser()
|
||||||
|
|
||||||
export const useEmployees = defineStore('employees', {
|
export const useEmployees = defineStore('employees', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
/** @type {{id: number, name: string, handle: string, contractHours: number }[]} */
|
/**
|
||||||
employees: emplJSON
|
* @type {}[]
|
||||||
|
*/
|
||||||
|
rows: Array<Object>(),
|
||||||
|
|
||||||
|
meta: {
|
||||||
|
current_page: NaN,
|
||||||
|
first_page: NaN,
|
||||||
|
last_page: NaN,
|
||||||
|
per_page: NaN,
|
||||||
|
total: NaN
|
||||||
|
},
|
||||||
|
|
||||||
|
columns: Array<string>()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
/**
|
||||||
|
* @param: {number} limit - QueryString: limit=20 etc.
|
||||||
|
* @param: {number} page - QueryString: page=1 etc.
|
||||||
|
* @param: {string} sortBy - QueryString: sort_by=asc(col1),desc(col2),...
|
||||||
|
* @param: {string} simpleSearch - QueryString: simple_search=query(col1,col2,...)
|
||||||
|
**/
|
||||||
|
async fetchFromApi(limit?: number, page?:number, sort_by?: string, simple_search?: string) {
|
||||||
|
try {
|
||||||
|
const data : any= (await axios.get(
|
||||||
|
'/employees',
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
limit,
|
||||||
|
page,
|
||||||
|
sort_by,
|
||||||
|
simple_search
|
||||||
|
},
|
||||||
|
headers: user.header
|
||||||
|
}
|
||||||
|
)).data
|
||||||
|
|
||||||
|
Object.assign(this.meta, data?.meta)
|
||||||
|
Object.assign(this.rows, data?.data)
|
||||||
|
|
||||||
|
this.columns = this.fetchColumns()
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchColumns() : string[] {
|
||||||
|
if(this.rows[0]){
|
||||||
|
return Object.keys(this.rows[0])
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<VProfileControls class="mb-5" :isActive="editEmployee || createUser" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
|
<form class="text-start">
|
||||||
|
<VProfileControls class="mb-5" :isActive="editEmployee || createUser" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
|
||||||
|
|
||||||
<form @keydown.enter="onEnter" class="text-start">
|
|
||||||
<div class="row mb-5">
|
<div class="row mb-5">
|
||||||
<div class="col pe-5">
|
<div class="col pe-5">
|
||||||
<h4 class="">Persönliche Informationen</h4>
|
<h4 class="">Persönliche Informationen</h4>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<label for="first-name" class="form-label">Vorname:</label>
|
<label for="first-name" class="form-label">Vorname:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-model.trim="state.employee.firstName"
|
v-model.trim="employee.firstName"
|
||||||
id="first-name"
|
id="first-name"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="classIsInvalid(v$.firstName)"
|
:class="classIsInvalid(v$.firstName)"
|
||||||
@@ -24,31 +24,49 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="last-name" class="form-label">Nachname:</label>
|
<label for="last-name" class="form-label">Nachname:</label>
|
||||||
<input type="text" v-model.trim="state.employee.lastName" id="last-name" class="form-control" :disabled="!editEmployee">
|
<input type="text" v-model.trim="employee.lastName" id="last-name" class="form-control" :disabled="!editEmployee">
|
||||||
|
|
||||||
<label for="shorthand" class="form-label">Kürzel:</label>
|
<label for="shorthand" class="form-label">Kürzel:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-model.trim="state.employee.shorthand"
|
v-model.trim="employee.shorthand"
|
||||||
id="shorthand"
|
id="shorthand"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="classIsInvalid(v$.shorthand)"
|
:class="classIsInvalid(v$.shorthand)"
|
||||||
:disabled="!editEmployee"
|
:disabled="!editEmployee"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div v-for="(error) in v$.shorthand.$errors" class="invalid-feedback" id="shorthandFeedback">
|
<div v-for="(error) in v$.shorthand.$errors" class="invalid-feedback" id="shorthandFeedback">
|
||||||
{{ error.$message }}
|
{{ error.$message }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col ps-5 border-start">
|
<div class="col ps-5 border-start">
|
||||||
|
|
||||||
<h4 class="">Kontaktdaten</h4>
|
<h4 class="">Kontaktdaten</h4>
|
||||||
<label for="phone" class="form-label">Telefonnummer:</label>
|
<label for="phone" class="form-label">Telefonnummer:</label>
|
||||||
<input type="phone" v-model.trim="state.employee.phone" id="phone" class="form-control" :disabled="!editEmployee">
|
<MaskInput
|
||||||
|
type="tel"
|
||||||
|
id="phone"
|
||||||
|
v-model="employee.phone"
|
||||||
|
:mask="'000[00]{ / }0000 [0000]'"
|
||||||
|
class="form-control"
|
||||||
|
:disabled="!editEmployee"
|
||||||
|
placeholder="_____ / ____ ____"
|
||||||
|
/>
|
||||||
<label for="mobile" class="form-label">Handynummer:</label>
|
<label for="mobile" class="form-label">Handynummer:</label>
|
||||||
<input type="mobile" v-model.trim="state.employee.mobile" id="mobile" class="form-control" :disabled="!editEmployee">
|
<MaskInput
|
||||||
|
type="tel"
|
||||||
|
v-model="employee.mobile"
|
||||||
|
:mask="'000[00]{ / }[0000] [0000]'"
|
||||||
|
id="mobile"
|
||||||
|
class="form-control"
|
||||||
|
:disabled="!editEmployee"
|
||||||
|
placeholder="_____ / ____ ____"
|
||||||
|
/>
|
||||||
<label for="email" class="form-label">E-Mail-Adresse:</label>
|
<label for="email" class="form-label">E-Mail-Adresse:</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
v-model.trim="state.employee.email"
|
v-model.trim="employee.email"
|
||||||
id="email"
|
id="email"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="classIsInvalid(v$.email)"
|
:class="classIsInvalid(v$.email)"
|
||||||
@@ -63,15 +81,21 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col pe-5">
|
<div class="col pe-5">
|
||||||
<h4 class="">Vertragsinformationen:</h4>
|
<h4 class="">Vertragsinformationen:</h4>
|
||||||
<label for="contract-hours" class="form-label">Wochenstunden:</label>
|
<label for="contract-hours" min="0" max="40" class="form-label">Wochenstunden:</label>
|
||||||
<input
|
|
||||||
type="number"
|
<MaskInput
|
||||||
v-model.number="state.employee.contractHours"
|
v-model:typed="employee.contractHours"
|
||||||
|
v-model="strContractHours"
|
||||||
|
:mask="Number"
|
||||||
|
:signed="false"
|
||||||
|
@click="$event.target.select()"
|
||||||
|
|
||||||
id="contract-hours"
|
id="contract-hours"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="classIsInvalid(v$.contractHours)"
|
:class="classIsInvalid(v$.contractHours)"
|
||||||
:disabled="!editEmployee"
|
:disabled="!editEmployee"
|
||||||
>
|
/>
|
||||||
|
|
||||||
<div v-for="(error) in v$.contractHours.$errors" class="invalid-feedback" id="contractHoursFeedback">
|
<div v-for="(error) in v$.contractHours.$errors" class="invalid-feedback" id="contractHoursFeedback">
|
||||||
{{error.$message}}
|
{{error.$message}}
|
||||||
</div>
|
</div>
|
||||||
@@ -93,7 +117,7 @@
|
|||||||
<label for="username" class="form-label">Benutzername:</label>
|
<label for="username" class="form-label">Benutzername:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-model.trim="state.employee.username"
|
v-model.trim="employee.username"
|
||||||
id="username"
|
id="username"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="classIsInvalid(v$.username)"
|
:class="classIsInvalid(v$.username)"
|
||||||
@@ -105,7 +129,7 @@
|
|||||||
<label for="password" class="form-label">Neues Passwort:</label>
|
<label for="password" class="form-label">Neues Passwort:</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
v-model="state.employee.password"
|
v-model="employee.password"
|
||||||
id="password"
|
id="password"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:class="classIsInvalid(v$.password)"
|
:class="classIsInvalid(v$.password)"
|
||||||
@@ -117,7 +141,7 @@
|
|||||||
<label for="password-repeat" class="form-label">Neues Passwort wiederholen:</label>
|
<label for="password-repeat" class="form-label">Neues Passwort wiederholen:</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
v-model="state.employee.passwordConfirm"
|
v-model="employee.passwordConfirm"
|
||||||
id="password-repeat"
|
id="password-repeat"
|
||||||
class="form-control mb-3"
|
class="form-control mb-3"
|
||||||
:class="classIsInvalid(v$.passwordConfirm)"
|
:class="classIsInvalid(v$.passwordConfirm)"
|
||||||
@@ -130,10 +154,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<VProfileControls class="mt-5" :isActive="editEmployee || createUser" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<VProfileControls class="mt-5" :isActive="editEmployee || createUser" @save="onUpdateEmployee" @toggleEdit="onToggleEdit" />
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -143,13 +166,18 @@ import VProfileControls from '@/components/VProfileControls.vue';
|
|||||||
import { onMounted, computed, ref, watch } from 'vue'
|
import { onMounted, computed, ref, watch } from 'vue'
|
||||||
import { useEmployee } from '@/stores/employee'
|
import { useEmployee } from '@/stores/employee'
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
import { required, email, between, decimal, sameAs, helpers, requiredIf } from '@vuelidate/validators'
|
import { required, email, between, decimal, sameAs, requiredIf } from '@vuelidate/validators'
|
||||||
|
import { IMaskComponent as MaskInput } from 'vue-imask'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const state = useEmployee()
|
const state = useEmployee()
|
||||||
|
|
||||||
|
const { employee } = storeToRefs(state)
|
||||||
|
|
||||||
const editEmployee = ref(false)
|
const editEmployee = ref(false)
|
||||||
|
const strContractHours = ref('')
|
||||||
|
|
||||||
const rules = computed(() => ({
|
const rules = computed(() => ({
|
||||||
firstName: {
|
firstName: {
|
||||||
@@ -172,12 +200,12 @@ const rules = computed(() => ({
|
|||||||
requiredIf: requiredIf(() => createUser.value)
|
requiredIf: requiredIf(() => createUser.value)
|
||||||
},
|
},
|
||||||
passwordConfirm: {
|
passwordConfirm: {
|
||||||
sameAs: sameAs(state.employee.password)
|
sameAs: sameAs(employee.value.password)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
const v$ = useVuelidate(rules, state.employee)
|
const v$ = useVuelidate(rules, employee)
|
||||||
|
|
||||||
const createUser = ref(false)
|
const createUser = ref(false)
|
||||||
|
|
||||||
@@ -186,11 +214,7 @@ async function onUpdateEmployee() {
|
|||||||
await state.persist()
|
await state.persist()
|
||||||
onToggleEdit()
|
onToggleEdit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEnter() {
|
|
||||||
onUpdateEmployee
|
|
||||||
}
|
|
||||||
|
|
||||||
function onToggleCreateUser() {
|
function onToggleCreateUser() {
|
||||||
createUser.value = !createUser.value
|
createUser.value = !createUser.value
|
||||||
@@ -219,7 +243,7 @@ function classIsInvalid(object : any) : string {
|
|||||||
return object.$dirty && object.$invalid ? 'is-invalid' : ''
|
return object.$dirty && object.$invalid ? 'is-invalid' : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(() => {
|
||||||
state.fetchFromApi(route.params.id)
|
state.fetchFromApi(route.params.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
84
src/views/Employees/Index.vue
Normal file
84
src/views/Employees/Index.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
v-for="col in columns"
|
||||||
|
@click="onSortBy(col)"
|
||||||
|
>
|
||||||
|
{{col}}
|
||||||
|
<i :style="{visibility: colIsSelected(col) ? 'visible' : 'hidden'}" class="bi" :class="iconSort"></i>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="employee in rows" @click="router.push({name: 'Employees/Details', params: {id: employee.id}})">
|
||||||
|
<td v-for="col in columns">
|
||||||
|
{{ employee[col] }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import { onMounted, reactive, watch, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useEmployees } from '@/stores/employees'
|
||||||
|
|
||||||
|
const store = useEmployees()
|
||||||
|
const router = useRouter()
|
||||||
|
const { rows, meta, columns } = storeToRefs(store)
|
||||||
|
|
||||||
|
const sort_by = reactive({
|
||||||
|
asc: true,
|
||||||
|
column: 'id'
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(sort_by, () => {
|
||||||
|
store.fetchFromApi(undefined, undefined, (sort_by.asc ? "asc(" : "desc(")+sort_by.column+")")
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
store.fetchFromApi(undefined, undefined, (sort_by.asc ? "asc(" : "desc(")+sort_by.column+")")
|
||||||
|
})
|
||||||
|
|
||||||
|
function colIsSelected(col : string) {
|
||||||
|
return col === sort_by.column
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSortBy(col : string) {
|
||||||
|
if(col !== sort_by.column) sort_by.asc = true
|
||||||
|
else sort_by.asc = !sort_by.asc
|
||||||
|
|
||||||
|
sort_by.column = col
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconSort = computed(() => {
|
||||||
|
return 'bi-sort-' + (sort_by.asc ? 'down' : 'up')+'-alt'
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
table th {
|
||||||
|
-ms-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user