Forms refactor
gitea/salix-front/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2022-11-02 11:24:21 +01:00
parent bd908e5e93
commit a1fc7c6803
12 changed files with 354 additions and 346 deletions

View File

@ -52,8 +52,7 @@ describe('App', () => {
}
};
await vm.responseError(response);
expect(vm.responseError(response)).rejects.toEqual(expect.objectContaining(response));
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
{
type: 'negative',
@ -73,8 +72,7 @@ describe('App', () => {
}
};
await vm.responseError(response);
expect(vm.responseError(response)).rejects.toEqual(expect.objectContaining(response));
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
{
type: 'negative',

View File

@ -15,6 +15,18 @@ const $props = defineProps({
type: Object,
default: null,
},
where: {
type: Object,
default: null,
},
sortBy: {
type: String,
default: '',
},
limit: {
type: String,
default: '',
},
});
defineExpose({ fetch });
@ -27,8 +39,13 @@ onMounted(async () => {
});
async function fetch() {
const filter = Object.assign({}, $props.filter);
if ($props.where) filter.where = $props.where;
if ($props.sortBy) filter.order = $props.sortBy;
if ($props.limit) filter.limit = $props.limit;
const { data } = await axios.get($props.url, {
params: { filter: $props.filter },
params: { filter },
});
emit('onFetch', data);

View File

@ -6,6 +6,10 @@ import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const $props = defineProps({
autoLoad: {
type: Boolean,
default: false,
},
url: {
type: String,
default: '',
@ -18,14 +22,18 @@ const $props = defineProps({
type: Object,
default: null,
},
autoLoad: {
type: Boolean,
default: false,
where: {
type: Object,
default: null,
},
sortBy: {
type: String,
default: '',
},
limit: {
type: String,
default: '',
},
rowsPerPage: {
type: Number,
default: 10,
@ -37,10 +45,10 @@ const $props = defineProps({
});
defineEmits(['onNavigate']);
defineExpose({ fetch });
defineExpose({ refresh });
onMounted(() => {
if ($props.autoLoad) fetch();
if ($props.autoLoad) paginate();
});
watch(
@ -60,12 +68,10 @@ const pagination = ref({
const rows = ref(null);
async function fetch() {
const { page, rowsPerPage, sortBy, descending } = pagination.value;
const { page, rowsPerPage, sortBy } = pagination.value;
if (!$props.url) return;
isLoading.value = true;
const filter = {
limit: rowsPerPage,
skip: rowsPerPage * (page - 1),
@ -73,12 +79,26 @@ async function fetch() {
Object.assign(filter, $props.filter);
if ($props.where) filter.where = $props.where;
if ($props.sortBy) filter.order = $props.sortBy;
if ($props.limit) filter.limit = $props.limit;
if (sortBy) filter.order = sortBy;
const { data } = await axios.get($props.url, {
params: { filter },
});
isLoading.value = false;
return data;
}
async function paginate() {
const { page, rowsPerPage, sortBy, descending } = pagination.value;
const data = await fetch();
if (!data) {
isLoading.value = false;
return;
@ -98,13 +118,31 @@ async function fetch() {
isLoading.value = false;
}
async function refresh() {
const { rowsPerPage } = pagination.value;
const data = await fetch();
if (!data) {
isLoading.value = false;
return;
}
hasMoreData.value = data.length === rowsPerPage;
if (!rows.value) rows.value = [];
rows.value = data;
isLoading.value = false;
}
async function onLoad(...params) {
const done = params[1];
if (!rows.value || rows.value.length === 0 || !$props.url) return done(false);
pagination.value.page = pagination.value.page + 1;
await fetch();
await paginate();
const endOfPages = !hasMoreData.value;
done(endOfPages);
@ -114,34 +152,7 @@ async function onLoad(...params) {
<template>
<q-infinite-scroll @load="onLoad" :offset="offset" class="column items-center">
<div v-if="rows" class="card-list q-gutter-y-md">
<q-card class="card" v-for="row of rows" :key="row.id">
<q-item v-ripple class="q-pa-none items-start cursor-pointer q-hoverable">
<q-item-section class="q-pa-md" @click="$emit('onNavigate', row.id)">
<slot name="header" :row="row">
<div class="text-h6">{{ row.name }}</div>
<q-item-label caption>#{{ row.id }}</q-item-label>
</slot>
<slot name="labels" :row="row"></slot>
</q-item-section>
<q-separator vertical />
<q-card-actions vertical class="justify-between">
<slot name="actions" :row="row">
<q-btn
flat
round
color="orange"
icon="arrow_circle_right"
@click="$emit('onNavigate', row.id)"
>
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="preview">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
</slot>
</q-card-actions>
</q-item>
</q-card>
<slot name="body" :rows="rows"></slot>
<div v-if="!rows.length && !isLoading" class="info-row q-pa-md text-center">
<h5>
{{ t('components.smartCard.noData') }}

View File

@ -1,6 +1,6 @@
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
import SmartCard from '../SmartCard.vue';
import Paginate from '../Paginate.vue';
const mockPush = jest.fn();
@ -11,7 +11,7 @@ jest.mock('vue-router', () => ({
}),
}));
describe('SmartCard', () => {
describe('Paginate', () => {
const expectedUrl = '/api/customers';
let vm;
beforeAll(() => {
@ -22,7 +22,7 @@ describe('SmartCard', () => {
rowsPerPage: 3
}
};
vm = createWrapper(SmartCard, options).vm;
vm = createWrapper(Paginate, options).vm;
jest.spyOn(axios, 'get').mockResolvedValue({
data: [
@ -39,8 +39,8 @@ describe('SmartCard', () => {
vm.hasMoreData = true;
})
describe('fetch()', () => {
it('should call to the fetch() method and set the data on the rows property', async () => {
describe('paginate()', () => {
it('should call to the paginate() method and set the data on the rows property', async () => {
const expectedOptions = {
params: {
filter: {
@ -51,13 +51,13 @@ describe('SmartCard', () => {
}
};
await vm.fetch();
await vm.paginate();
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptions);
expect(vm.rows.length).toEqual(3);
});
it('should call to the fetch() method and then call it again to paginate', async () => {
it('should call to the paginate() method and then call it again to paginate', async () => {
const expectedOptions = {
params: {
filter: {
@ -68,7 +68,7 @@ describe('SmartCard', () => {
}
};
await vm.fetch();
await vm.paginate();
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptions);
expect(vm.rows.length).toEqual(3);
@ -85,7 +85,7 @@ describe('SmartCard', () => {
vm.pagination.page = 2;
await vm.fetch();
await vm.paginate();
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptionsPaginated);
expect(vm.rows.length).toEqual(6);

View File

@ -199,8 +199,7 @@ export default {
state: 'State'
},
rmaList: {
code: 'Code',
newRma: 'New RMA...'
code: 'Code'
},
rma: {
user: 'User',

View File

@ -198,8 +198,7 @@ export default {
state: 'Estado'
},
rmaList: {
code: 'Código',
newRma: 'Nuevo RMA...'
code: 'Código'
},
rma: {
user: 'Usuario',

View File

@ -12,31 +12,6 @@ const { t } = useI18n();
const session = useSession();
const token = session.getToken();
// const claim = ref(null);
// const claimCopy = ref(null);
// const hasChanges = ref(false);
// function fetch() {
// const id = route.params.id;
// const filter = {
// include: [
// {
// relation: 'client',
// scope: {
// fields: ['name'],
// },
// },
// ],
// };
// const options = { params: { filter } };
// axios.get(`Claims/${id}`, options).then(({ data }) => {
// claim.value = data;
// claimCopy.value = Object.assign({}, data);
// watch(claim.value, () => (hasChanges.value = true));
// });
// }
const claimFilter = {
include: [
{
@ -53,47 +28,6 @@ const workersCopy = ref([]);
const claimStates = ref([]);
const claimStatesCopy = ref([]);
// function filter(value, update, options, originalOptions, filter) {
// update(
// () => {
// if (value === '') {
// options.value = originalOptions.value;
// return;
// }
// options.value = options.value.filter(filter);
// },
// (ref) => {
// ref.setOptionIndex(-1);
// ref.moveOptionSelection(1, true);
// }
// );
// }
// function filterWorkers(value, update) {
// const search = value.toLowerCase();
// filter(value, update, workers, workersCopy, (row) => {
// const id = row.id;
// const name = row.name.toLowerCase();
// const idMatch = id == search;
// const nameMatch = name.indexOf(search) > -1;
// return idMatch || nameMatch;
// });
// }
// function filterStates(value, update) {
// const search = value.toLowerCase();
// filter(value, update, claimStates, claimStatesCopy, (row) => {
// const description = row.description.toLowerCase();
// return description.indexOf(search) > -1;
// });
// }
function setWorkers(data) {
workers.value = data;
workersCopy.value = data;

View File

@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import { useRoute } from 'vue-router';
import axios from 'axios';
import SmartCard from 'src/components/SmartCard.vue';
import Paginate from 'src/components/Paginate.vue';
import FetchData from 'src/components/FetchData.vue';
import { toDate } from 'src/filters';
@ -12,12 +12,9 @@ const quasar = useQuasar();
const route = useRoute();
const { t } = useI18n();
// const card = ref();
const claim = ref([]);
const fetcher = ref();
// const rma = computed(() => claim.value.rma);
const filter = {
include: {
relation: 'rmas',
@ -30,6 +27,7 @@ const filter = {
},
},
},
order: 'created DESC',
},
},
};
@ -92,27 +90,40 @@ function hide() {
</q-toolbar>
</q-page-sticky>
<smart-card :data="claim.rmas">
<template #header="{ row }">
<q-item-label caption>{{ t('claim.rma.user') }}</q-item-label>
<q-item-label>{{ row.worker.user.name }}</q-item-label>
<paginate :data="claim.rmas">
<template #body="{ rows }">
<q-card class="card">
<template v-for="row of rows" :key="row.id">
<q-item class="q-pa-none items-start">
<q-item-section class="q-pa-md">
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.rma.user') }}</q-item-label>
<q-item-label>{{ row.worker.user.name }}</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.rma.created') }}</q-item-label>
<q-item-label>
{{ toDate(row.created, { timeStyle: 'medium' }) }}
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-item-section>
<q-card-actions vertical class="justify-between">
<q-btn flat round color="orange" icon="vn:bin" @click="confirmRemove(row.id)">
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
</q-btn>
</q-card-actions>
</q-item>
<q-separator />
</template>
</q-card>
</template>
<template #labels="{ row }">
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.rma.created') }}</q-item-label>
<q-item-label>{{ toDate(row.created, { timeStyle: 'medium' }) }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</template>
<template #actions="{ row }">
<q-btn flat round color="orange" icon="vn:bin" @click="confirmRemove(row.id)">
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
</q-btn>
</template>
</smart-card>
</paginate>
</q-page>
<q-dialog v-model="confirmShown" persistent @hide="hide">
<q-card>

View File

@ -2,7 +2,7 @@
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import SmartCard from 'src/components/SmartCard.vue';
import Paginate from 'src/components/Paginate.vue';
import { toDate } from 'src/filters/index';
import ClaimSummary from './Card/ClaimSummary.vue';
@ -50,64 +50,73 @@ function showPreview(id) {
<template>
<q-page class="q-pa-md">
<smart-card url="/Claims" :filter="filter" sort-by="id DESC" @on-navigate="navigate" auto-load>
<template #labels="{ row }">
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.list.customer') }}</q-item-label>
<q-item-label>{{ row.client.name }}</q-item-label>
<paginate url="/Claims" :filter="filter" sort-by="id DESC" auto-load>
<template #body="{ rows }">
<q-card class="card" v-for="row of rows" :key="row.id">
<q-item class="q-pa-none items-start cursor-pointer q-hoverable" v-ripple clickable>
<q-item-section class="q-pa-md" @click="navigate(row.id)">
<div class="text-h6">{{ row.name }}</div>
<q-item-label caption>#{{ row.id }}</q-item-label>
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.list.customer') }}</q-item-label>
<q-item-label>{{ row.client.name }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('claim.list.assignedTo') }}</q-item-label>
<q-item-label>{{ row.worker.user.name }}</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.list.created') }}</q-item-label>
<q-item-label>{{ toDate(row.created) }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('claim.list.state') }}</q-item-label>
<q-item-label>
<q-chip :color="stateColor(row.claimState.code)" dense>
{{ row.claimState.description }}
</q-chip>
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('claim.list.assignedTo') }}</q-item-label>
<q-item-label>{{ row.worker.user.name }}</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.list.created') }}</q-item-label>
<q-item-label>{{ toDate(row.created) }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('claim.list.state') }}</q-item-label>
<q-item-label>
<q-chip :color="stateColor(row.claimState.code)" dense>
{{ row.claimState.description }}
</q-chip>
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</template>
<template #actions="{ row }">
<q-btn color="grey-7" round flat icon="more_vert">
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
<q-menu cover auto-close>
<q-list>
<q-item clickable>
<q-item-section avatar>
<q-icon name="add" />
</q-item-section>
<q-item-section>Add a note</q-item-section>
</q-item>
<q-item clickable>
<q-item-section avatar>
<q-icon name="logs" />
</q-item-section>
<q-item-section>Display claim logs</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-separator vertical />
<q-card-actions vertical class="justify-between">
<q-btn color="grey-7" round flat icon="more_vert">
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
<q-menu cover auto-close>
<q-list>
<q-item clickable>
<q-item-section avatar>
<q-icon name="add" />
</q-item-section>
<q-item-section>Add a note</q-item-section>
</q-item>
<q-item clickable>
<q-item-section avatar>
<q-icon name="logs" />
</q-item-section>
<q-item-section>Display claim logs</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn flat round color="orange" icon="arrow_circle_right" @click="navigate(row.id)">
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
<q-btn flat round color="orange" icon="arrow_circle_right" @click="navigate(row.id)">
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
</q-card-actions>
</q-item>
</q-card>
</template>
</smart-card>
</paginate>
</q-page>
<q-dialog v-model="preview.shown">
<claim-summary :claim-id="preview.data.claimId" />

View File

@ -3,7 +3,7 @@ import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import axios from 'axios';
import SmartCard from 'src/components/SmartCard.vue';
import Paginate from 'src/components/Paginate.vue';
const quasar = useQuasar();
const { t } = useI18n();
@ -26,7 +26,7 @@ function submit() {
crated: new Date(),
};
})
.then(() => card.value.fetch());
.then(() => card.value.refresh());
}
const confirmShown = ref(false);
@ -38,15 +38,18 @@ function confirm(id) {
function remove() {
const id = rmaId.value;
axios.delete(`ClaimRmas/${id}`).then(() => {
confirmShown.value = false;
axios
.delete(`ClaimRmas/${id}`)
.then(() => {
confirmShown.value = false;
quasar.notify({
type: 'positive',
message: 'Entry deleted',
icon: 'check',
});
});
quasar.notify({
type: 'positive',
message: 'Entry deleted',
icon: 'check',
});
})
.then(() => card.value.refresh());
}
function hide() {
@ -59,29 +62,38 @@ function hide() {
<q-page-sticky expand position="top" :offset="[16, 16]">
<q-card class="card q-pa-md">
<q-form @submit="submit">
<q-input v-model="newRma.code" :label="t('claim.rmaList.newRma')" class="q-mb-md" />
<div class="text-caption">$(0) entries</div>
<q-input v-model="newRma.code" :label="t('claim.rmaList.code')" class="q-mb-md" />
<!-- <div class="text-caption">$(0) entries</div> -->
</q-form>
</q-card>
</q-page-sticky>
<smart-card ref="card" url="/ClaimRmas" sort-by="id DESC" auto-load>
<template #labels="{ row }">
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.rmaList.code') }}</q-item-label>
<q-item-label>{{ row.code }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
<paginate ref="card" url="/ClaimRmas" sort-by="id DESC" auto-load>
<template #body="{ rows }">
<q-card class="card">
<template v-for="row of rows" :key="row.id">
<q-item class="q-pa-none items-start">
<q-item-section class="q-pa-md" @click="navigate(row.id)">
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('claim.rmaList.code') }}</q-item-label>
<q-item-label>{{ row.code }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-item-section>
<q-card-actions vertical class="justify-between">
<q-btn flat round color="primary" icon="vn:bin" @click="confirm(row.id)">
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
</q-btn>
</q-card-actions>
</q-item>
<q-separator />
</template>
</q-card>
</template>
<template #actions="{ row }">
<q-btn flat round color="primary" icon="vn:bin" @click="confirm(row.id)">
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
</q-btn>
</template>
</smart-card>
</paginate>
</q-page>
<q-dialog v-model="confirmShown" persistent @hide="hide">

View File

@ -2,7 +2,7 @@
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import SmartCard from 'src/components/SmartCard.vue';
import Paginate from 'src/components/Paginate.vue';
import CustomerSummary from './Card/CustomerSummary.vue';
const router = useRouter();
@ -26,55 +26,64 @@ function showPreview(id) {
<template>
<q-page class="q-pa-md">
<smart-card url="/Clients" sort-by="id DESC" @on-navigate="navigate" auto-load>
<template #labels="{ row }">
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('customer.list.email') }}</q-item-label>
<q-item-label>{{ row.email }}</q-item-label>
<paginate url="/Clients" sort-by="id DESC" auto-load>
<template #body="{ rows }">
<q-card class="card" v-for="row of rows" :key="row.id">
<q-item class="q-pa-none items-start cursor-pointer q-hoverable" v-ripple clickable>
<q-item-section class="q-pa-md" @click="navigate(row.id)">
<div class="text-h6">{{ row.name }}</div>
<q-item-label caption>#{{ row.id }}</q-item-label>
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('customer.list.email') }}</q-item-label>
<q-item-label>{{ row.email }}</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('customer.list.phone') }}</q-item-label>
<q-item-label>{{ row.phone }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('customer.list.phone') }}</q-item-label>
<q-item-label>{{ row.phone }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</template>
<template #actions="{ row }">
<q-btn color="grey-7" round flat icon="more_vert">
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
<q-menu cover auto-close>
<q-list>
<q-item clickable>
<q-item-section avatar>
<q-icon name="add" />
</q-item-section>
<q-item-section>Add a note</q-item-section>
</q-item>
<q-item clickable>
<q-item-section avatar>
<q-icon name="history" />
</q-item-section>
<q-item-section>Display customer history</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-separator vertical />
<q-card-actions vertical class="justify-between">
<q-btn color="grey-7" round flat icon="more_vert">
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
<q-menu cover auto-close>
<q-list>
<q-item clickable>
<q-item-section avatar>
<q-icon name="add" />
</q-item-section>
<q-item-section>Add a note</q-item-section>
</q-item>
<q-item clickable>
<q-item-section avatar>
<q-icon name="history" />
</q-item-section>
<q-item-section>Display customer history</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn flat round color="orange" icon="arrow_circle_right" @click="navigate(row.id)">
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="vn:ticket">
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
</q-btn>
<q-btn flat round color="orange" icon="arrow_circle_right" @click="navigate(row.id)">
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="vn:ticket">
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
</q-btn>
</q-card-actions>
</q-item>
</q-card>
</template>
</smart-card>
</paginate>
</q-page>
<q-dialog v-model="preview.shown">
<customer-summary :customer-id="preview.data.customerId" />

View File

@ -2,9 +2,9 @@
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import SmartCard from 'src/components/SmartCard.vue';
import Paginate from 'src/components/Paginate.vue';
import { toDate, toCurrency } from 'src/filters/index';
// import CustomerSummary from './Card/CustomerSummary.vue';
// import TicketSummary from './Card/TicketSummary.vue';
const router = useRouter();
const { t } = useI18n();
@ -62,77 +62,86 @@ function showPreview(id) {
<template>
<q-page class="q-pa-md">
<smart-card url="/Tickets" :filter="filter" sort-by="id DESC" @on-navigate="navigate" auto-load>
<template #labels="{ row }">
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('ticket.list.nickname') }}</q-item-label>
<q-item-label>{{ row.nickname }}</q-item-label>
<paginate url="/Tickets" :filter="filter" sort-by="id DESC" auto-load>
<template #body="{ rows }">
<q-card class="card" v-for="row of rows" :key="row.id">
<q-item class="q-pa-none items-start cursor-pointer q-hoverable" v-ripple clickable>
<q-item-section class="q-pa-md" @click="navigate(row.id)">
<div class="text-h6">{{ row.name }}</div>
<q-item-label caption>#{{ row.id }}</q-item-label>
<q-list>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('ticket.list.nickname') }}</q-item-label>
<q-item-label>{{ row.nickname }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.list.state') }}</q-item-label>
<q-item-label>
<q-chip :color="stateColor(row.ticketState)" dense>
{{ row.ticketState.state.name }}
</q-chip>
</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('ticket.list.shipped') }}</q-item-label>
<q-item-label>{{ toDate(row.shipped) }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.list.landed') }}</q-item-label>
<q-item-label>{{ toDate(row.landed) }}</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section v-if="row.client.salesPersonUser">
<q-item-label caption>{{ t('ticket.list.salesPerson') }}</q-item-label>
<q-item-label>{{ row.client.salesPersonUser.name }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.list.total') }}</q-item-label>
<q-item-label>{{ toCurrency(row.totalWithVat) }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.list.state') }}</q-item-label>
<q-item-label>
<q-chip :color="stateColor(row.ticketState)" dense>
{{ row.ticketState.state.name }}
</q-chip>
</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section>
<q-item-label caption>{{ t('ticket.list.shipped') }}</q-item-label>
<q-item-label>{{ toDate(row.shipped) }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.list.landed') }}</q-item-label>
<q-item-label>{{ toDate(row.landed) }}</q-item-label>
</q-item-section>
</q-item>
<q-item class="q-pa-none">
<q-item-section v-if="row.client.salesPersonUser">
<q-item-label caption>{{ t('ticket.list.salesPerson') }}</q-item-label>
<q-item-label>{{ row.client.salesPersonUser.name }}</q-item-label>
</q-item-section>
<q-item-section>
<q-item-label caption>{{ t('ticket.list.total') }}</q-item-label>
<q-item-label>{{ toCurrency(row.totalWithVat) }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</template>
<template #actions="{ row }">
<q-btn color="grey-7" round flat icon="more_vert">
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
<q-menu cover auto-close>
<q-list>
<q-item clickable>
<q-item-section avatar>
<q-icon name="add" />
</q-item-section>
<q-item-section>Add a note</q-item-section>
</q-item>
<q-item clickable>
<q-item-section avatar>
<q-icon name="history" />
</q-item-section>
<q-item-section>Display customer history</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-separator vertical />
<q-card-actions vertical class="justify-between">
<q-btn color="grey-7" round flat icon="more_vert">
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
<q-menu cover auto-close>
<q-list>
<q-item clickable>
<q-item-section avatar>
<q-icon name="add" />
</q-item-section>
<q-item-section>Add a note</q-item-section>
</q-item>
<q-item clickable>
<q-item-section avatar>
<q-icon name="history" />
</q-item-section>
<q-item-section>Display customer history</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn flat round color="orange" icon="arrow_circle_right" @click="navigate(row.id)">
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="vn:ticket">
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
</q-btn>
<q-btn flat round color="orange" icon="arrow_circle_right" @click="navigate(row.id)">
<q-tooltip>{{ t('components.smartCard.openCard') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
</q-btn>
<q-btn flat round color="grey-7" icon="vn:ticket">
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
</q-btn>
</q-card-actions>
</q-item>
</q-card>
</template>
</smart-card>
</paginate>
</q-page>
<!-- <q-dialog v-model="preview.shown">
<customer-summary :customer-id="preview.data.customerId" />