4043-form_data #25
|
@ -61,7 +61,7 @@ function responseError(error) {
|
||||||
router.push({ path: '/login' });
|
router.push({ path: '/login' });
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.interceptors.response.use((response) => {
|
axios.interceptors.response.use((response) => {
|
||||||
|
|
|
@ -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(
|
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
|
||||||
{
|
{
|
||||||
type: 'negative',
|
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(
|
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
|
||||||
{
|
{
|
||||||
type: 'negative',
|
type: 'negative',
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<script setup>
|
||||||
|
import { h, onMounted } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
autoLoad: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
sortBy: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({ fetch });
|
||||||
|
const emit = defineEmits(['onFetch']);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if ($props.autoLoad) {
|
||||||
|
await fetch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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 },
|
||||||
|
});
|
||||||
|
|
||||||
|
emit('onFetch', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
return h('div', []);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<render />
|
||||||
|
</template>
|
|
@ -0,0 +1,118 @@
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, onUnmounted, computed, ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
import SkeletonForm from 'src/components/SkeletonForm.vue';
|
||||||
|
|
||||||
|
const quasar = useQuasar();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const state = useState();
|
||||||
|
const { validate } = useValidator();
|
||||||
|
|
||||||
|
const $props = defineProps({
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['onFetch']);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => await fetch());
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
state.unset($props.model);
|
||||||
|
});
|
||||||
|
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const hasChanges = ref(false);
|
||||||
|
const formData = computed(() => state.get($props.model));
|
||||||
|
const originalData = ref();
|
||||||
|
|
||||||
|
async function fetch() {
|
||||||
|
const { data } = await axios.get($props.url, {
|
||||||
|
params: { filter: $props.filter },
|
||||||
|
});
|
||||||
|
|
||||||
|
state.set($props.model, data);
|
||||||
|
originalData.value = Object.assign({}, data);
|
||||||
|
|
||||||
|
watch(formData.value, () => (hasChanges.value = true));
|
||||||
|
|
||||||
|
emit('onFetch', state.get($props.model));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function save() {
|
||||||
|
if (!hasChanges.value) {
|
||||||
|
return quasar.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: t('globals.noChanges'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
isLoading.value = true;
|
||||||
|
await axios.patch($props.url, formData.value);
|
||||||
|
|
||||||
|
originalData.value = formData.value;
|
||||||
|
hasChanges.value = false;
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
state.set($props.model, originalData.value);
|
||||||
|
hasChanges.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter(value, update, filterOptions) {
|
||||||
|
update(
|
||||||
|
() => {
|
||||||
|
const { options, filterFn } = filterOptions;
|
||||||
|
|
||||||
|
options.value = filterFn(options, value);
|
||||||
|
},
|
||||||
|
(ref) => {
|
||||||
|
ref.setOptionIndex(-1);
|
||||||
|
ref.moveOptionSelection(1, true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<q-banner v-if="hasChanges" class="text-white bg-warning">
|
||||||
|
<q-icon name="warning" size="md" class="q-mr-md" />
|
||||||
|
<span>{{ t('globals.changesToSave') }}</span>
|
||||||
|
</q-banner>
|
||||||
|
<q-form v-if="formData" @submit="save" @reset="reset" class="q-pa-md">
|
||||||
|
<slot name="form" :data="formData" :validate="validate" :filter="filter"></slot>
|
||||||
|
<div class="q-mt-lg">
|
||||||
|
<slot name="actions">
|
||||||
|
<q-btn :label="t('globals.save')" type="submit" color="primary" />
|
||||||
|
<q-btn
|
||||||
|
:label="t('globals.reset')"
|
||||||
|
type="reset"
|
||||||
|
class="q-ml-sm"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
:disable="!hasChanges"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</q-form>
|
||||||
|
<skeleton-form v-if="!formData" />
|
||||||
|
<q-inner-loading :showing="isLoading" :label="t('globals.pleaseWait')" color="primary" />
|
||||||
|
</template>
|
|
@ -1,27 +1,39 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
autoLoad: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
url: {
|
url: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
filter: {
|
filter: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
autoLoad: {
|
where: {
|
||||||
type: Boolean,
|
type: Object,
|
||||||
default: false,
|
default: null,
|
||||||
},
|
},
|
||||||
sortBy: {
|
sortBy: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
limit: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
rowsPerPage: {
|
rowsPerPage: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 10,
|
default: 10,
|
||||||
|
@ -33,7 +45,18 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
defineEmits(['onNavigate']);
|
defineEmits(['onNavigate']);
|
||||||
defineExpose({ fetch });
|
defineExpose({ refresh });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if ($props.autoLoad) paginate();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => $props.data,
|
||||||
|
() => {
|
||||||
|
rows.value = $props.data;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const hasMoreData = ref(false);
|
const hasMoreData = ref(false);
|
||||||
|
@ -42,18 +65,12 @@ const pagination = ref({
|
||||||
rowsPerPage: $props.rowsPerPage,
|
rowsPerPage: $props.rowsPerPage,
|
||||||
page: 1,
|
page: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rows = ref(null);
|
const rows = ref(null);
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if ($props.autoLoad) fetch();
|
|
||||||
else rows.value = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
const { page, rowsPerPage, sortBy, descending } = pagination.value;
|
const { page, rowsPerPage, sortBy } = pagination.value;
|
||||||
|
|
||||||
isLoading.value = true;
|
if (!$props.url) return;
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
limit: rowsPerPage,
|
limit: rowsPerPage,
|
||||||
|
@ -62,12 +79,26 @@ async function fetch() {
|
||||||
|
|
||||||
Object.assign(filter, $props.filter);
|
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;
|
if (sortBy) filter.order = sortBy;
|
||||||
|
|
||||||
const { data } = await axios.get($props.url, {
|
const { data } = await axios.get($props.url, {
|
||||||
params: { filter },
|
params: { filter },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
isLoading.value = false;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function paginate() {
|
||||||
|
const { page, rowsPerPage, sortBy, descending } = pagination.value;
|
||||||
|
|
||||||
|
const data = await fetch();
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
return;
|
return;
|
||||||
|
@ -87,13 +118,31 @@ async function fetch() {
|
||||||
isLoading.value = false;
|
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) {
|
async function onLoad(...params) {
|
||||||
const done = params[1];
|
const done = params[1];
|
||||||
if (!rows.value || rows.value.length === 0) return done(false);
|
if (!rows.value || rows.value.length === 0 || !$props.url) return done(false);
|
||||||
|
|
||||||
pagination.value.page = pagination.value.page + 1;
|
pagination.value.page = pagination.value.page + 1;
|
||||||
|
|
||||||
await fetch();
|
await paginate();
|
||||||
|
|
||||||
const endOfPages = !hasMoreData.value;
|
const endOfPages = !hasMoreData.value;
|
||||||
done(endOfPages);
|
done(endOfPages);
|
||||||
|
@ -103,34 +152,7 @@ async function onLoad(...params) {
|
||||||
<template>
|
<template>
|
||||||
<q-infinite-scroll @load="onLoad" :offset="offset" class="column items-center">
|
<q-infinite-scroll @load="onLoad" :offset="offset" class="column items-center">
|
||||||
<div v-if="rows" class="card-list q-gutter-y-md">
|
<div v-if="rows" class="card-list q-gutter-y-md">
|
||||||
<q-card class="card" v-for="row of rows" :key="row.id">
|
<slot name="body" :rows="rows"></slot>
|
||||||
<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>
|
|
||||||
<div v-if="!rows.length && !isLoading" class="info-row q-pa-md text-center">
|
<div v-if="!rows.length && !isLoading" class="info-row q-pa-md text-center">
|
||||||
<h5>
|
<h5>
|
||||||
{{ t('components.smartCard.noData') }}
|
{{ t('components.smartCard.noData') }}
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div class="q-pa-md">
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-skeleton type="QInput" square />
|
<q-skeleton type="QInput" square />
|
||||||
|
@ -27,4 +28,5 @@
|
||||||
<q-skeleton type="QBtn" />
|
<q-skeleton type="QBtn" />
|
||||||
<q-skeleton type="QBtn" />
|
<q-skeleton type="QBtn" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
||||||
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
|
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
|
||||||
import SmartCard from '../SmartCard.vue';
|
import Paginate from '../Paginate.vue';
|
||||||
|
|
||||||
const mockPush = jest.fn();
|
const mockPush = jest.fn();
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ jest.mock('vue-router', () => ({
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('SmartCard', () => {
|
describe('Paginate', () => {
|
||||||
const expectedUrl = '/api/customers';
|
const expectedUrl = '/api/customers';
|
||||||
let vm;
|
let vm;
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
@ -22,7 +22,7 @@ describe('SmartCard', () => {
|
||||||
rowsPerPage: 3
|
rowsPerPage: 3
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
vm = createWrapper(SmartCard, options).vm;
|
vm = createWrapper(Paginate, options).vm;
|
||||||
|
|
||||||
jest.spyOn(axios, 'get').mockResolvedValue({
|
jest.spyOn(axios, 'get').mockResolvedValue({
|
||||||
data: [
|
data: [
|
||||||
|
@ -39,8 +39,8 @@ describe('SmartCard', () => {
|
||||||
vm.hasMoreData = true;
|
vm.hasMoreData = true;
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('fetch()', () => {
|
describe('paginate()', () => {
|
||||||
it('should call to the fetch() method and set the data on the rows property', async () => {
|
it('should call to the paginate() method and set the data on the rows property', async () => {
|
||||||
const expectedOptions = {
|
const expectedOptions = {
|
||||||
params: {
|
params: {
|
||||||
filter: {
|
filter: {
|
||||||
|
@ -51,13 +51,13 @@ describe('SmartCard', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await vm.fetch();
|
await vm.paginate();
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptions);
|
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptions);
|
||||||
expect(vm.rows.length).toEqual(3);
|
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 = {
|
const expectedOptions = {
|
||||||
params: {
|
params: {
|
||||||
filter: {
|
filter: {
|
||||||
|
@ -68,7 +68,7 @@ describe('SmartCard', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await vm.fetch();
|
await vm.paginate();
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptions);
|
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptions);
|
||||||
expect(vm.rows.length).toEqual(3);
|
expect(vm.rows.length).toEqual(3);
|
||||||
|
@ -85,7 +85,7 @@ describe('SmartCard', () => {
|
||||||
|
|
||||||
vm.pagination.page = 2;
|
vm.pagination.page = 2;
|
||||||
|
|
||||||
await vm.fetch();
|
await vm.paginate();
|
||||||
|
|
||||||
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptionsPaginated);
|
expect(axios.get).toHaveBeenCalledWith(expectedUrl, expectedOptionsPaginated);
|
||||||
expect(vm.rows.length).toEqual(6);
|
expect(vm.rows.length).toEqual(6);
|
|
@ -1,5 +1,7 @@
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
|
||||||
|
const state = ref({});
|
||||||
|
|
||||||
const user = ref({
|
const user = ref({
|
||||||
id: 0,
|
id: 0,
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -44,11 +46,27 @@ export function useState() {
|
||||||
roles.value = data;
|
roles.value = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set(name, data) {
|
||||||
|
state.value[name] = ref(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(name) {
|
||||||
|
return state.value[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
function unset(name) {
|
||||||
|
delete state.value[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getUser,
|
getUser,
|
||||||
setUser,
|
setUser,
|
||||||
getRoles,
|
getRoles,
|
||||||
setRoles,
|
setRoles,
|
||||||
|
set,
|
||||||
|
get,
|
||||||
|
unset,
|
||||||
drawer
|
drawer
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,6 @@ export function useValidator() {
|
||||||
return validations(validation)[validation.validation];
|
return validations(validation)[validation.validation];
|
||||||
});
|
});
|
||||||
|
|
||||||
if (property === 'socialName') {
|
|
||||||
console.log(modelValidations[property])
|
|
||||||
}
|
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,11 @@ export default {
|
||||||
yes: 'Yes',
|
yes: 'Yes',
|
||||||
no: 'No',
|
no: 'No',
|
||||||
noChanges: 'No changes to save',
|
noChanges: 'No changes to save',
|
||||||
|
changesToSave: 'You have changes pending to save',
|
||||||
confirmRemove: 'You are about to delete this row. Are you sure?',
|
confirmRemove: 'You are about to delete this row. Are you sure?',
|
||||||
rowAdded: 'Row added',
|
rowAdded: 'Row added',
|
||||||
rowRemoved: 'Row removed'
|
rowRemoved: 'Row removed',
|
||||||
|
pleaseWait: 'Please wait...'
|
||||||
},
|
},
|
||||||
moduleIndex: {
|
moduleIndex: {
|
||||||
allModules: 'All modules'
|
allModules: 'All modules'
|
||||||
|
@ -150,7 +152,8 @@ export default {
|
||||||
list: 'List',
|
list: 'List',
|
||||||
createTicket: 'Create ticket',
|
createTicket: 'Create ticket',
|
||||||
summary: 'Summary',
|
summary: 'Summary',
|
||||||
basicData: 'Basic Data'
|
basicData: 'Basic Data',
|
||||||
|
boxing: 'Boxing'
|
||||||
},
|
},
|
||||||
list: {
|
list: {
|
||||||
nickname: 'Nickname',
|
nickname: 'Nickname',
|
||||||
|
@ -197,8 +200,7 @@ export default {
|
||||||
state: 'State'
|
state: 'State'
|
||||||
},
|
},
|
||||||
rmaList: {
|
rmaList: {
|
||||||
code: 'Code',
|
code: 'Code'
|
||||||
newRma: 'New RMA...'
|
|
||||||
},
|
},
|
||||||
rma: {
|
rma: {
|
||||||
user: 'User',
|
user: 'User',
|
||||||
|
|
|
@ -21,9 +21,11 @@ export default {
|
||||||
yes: 'Si',
|
yes: 'Si',
|
||||||
no: 'No',
|
no: 'No',
|
||||||
noChanges: 'Sin cambios que guardar',
|
noChanges: 'Sin cambios que guardar',
|
||||||
|
changesToSave: 'Tienes cambios pendientes de guardar',
|
||||||
confirmRemove: 'Vas a eliminar este registro. ¿Continuar?',
|
confirmRemove: 'Vas a eliminar este registro. ¿Continuar?',
|
||||||
rowAdded: 'Fila añadida',
|
rowAdded: 'Fila añadida',
|
||||||
rowRemoved: 'Fila eliminada'
|
rowRemoved: 'Fila eliminada',
|
||||||
|
pleaseWait: 'Por favor, espera...'
|
||||||
},
|
},
|
||||||
moduleIndex: {
|
moduleIndex: {
|
||||||
allModules: 'Todos los módulos'
|
allModules: 'Todos los módulos'
|
||||||
|
@ -149,7 +151,8 @@ export default {
|
||||||
list: 'Listado',
|
list: 'Listado',
|
||||||
createTicket: 'Crear ticket',
|
createTicket: 'Crear ticket',
|
||||||
summary: 'Resumen',
|
summary: 'Resumen',
|
||||||
basicData: 'Datos básicos'
|
basicData: 'Datos básicos',
|
||||||
|
boxing: 'Encajado'
|
||||||
},
|
},
|
||||||
list: {
|
list: {
|
||||||
nickname: 'Alias',
|
nickname: 'Alias',
|
||||||
|
@ -196,8 +199,7 @@ export default {
|
||||||
state: 'Estado'
|
state: 'Estado'
|
||||||
},
|
},
|
||||||
rmaList: {
|
rmaList: {
|
||||||
code: 'Código',
|
code: 'Código'
|
||||||
newRma: 'Nuevo RMA...'
|
|
||||||
},
|
},
|
||||||
rma: {
|
rma: {
|
||||||
user: 'Usuario',
|
user: 'Usuario',
|
||||||
|
|
|
@ -1,33 +1,18 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { useSession } from 'src/composables/useSession';
|
|
||||||
import { useValidator } from 'src/composables/useValidator';
|
|
||||||
import SkeletonForm from 'src/components/SkeletonForm.vue';
|
|
||||||
|
|
||||||
onMounted(() => {
|
import { useSession } from 'src/composables/useSession';
|
||||||
fetch();
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
fetchWorkers();
|
import FormModel from 'src/components/FormModel.vue';
|
||||||
fetchClaimStates();
|
|
||||||
});
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const quasar = useQuasar();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { validate } = useValidator();
|
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const token = session.getToken();
|
const token = session.getToken();
|
||||||
|
|
||||||
const claim = ref(null);
|
const claimFilter = {
|
||||||
const claimCopy = ref(null);
|
|
||||||
const hasChanges = ref(false);
|
|
||||||
|
|
||||||
function fetch() {
|
|
||||||
const id = route.params.id;
|
|
||||||
const filter = {
|
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
relation: 'client',
|
relation: 'client',
|
||||||
|
@ -37,116 +22,79 @@ function fetch() {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
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 workers = ref([]);
|
const workers = ref([]);
|
||||||
const workersCopy = ref([]);
|
const workersCopy = ref([]);
|
||||||
function fetchWorkers() {
|
|
||||||
const filter = {
|
|
||||||
where: {
|
|
||||||
role: 'salesPerson',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const options = { params: { filter } };
|
|
||||||
axios.get(`Workers/activeWithRole`, options).then(({ data }) => {
|
|
||||||
workers.value = data;
|
|
||||||
workersCopy.value = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const claimStates = ref([]);
|
const claimStates = ref([]);
|
||||||
const claimStatesCopy = ref([]);
|
const claimStatesCopy = ref([]);
|
||||||
function fetchClaimStates() {
|
|
||||||
axios.get(`ClaimStates`).then(({ data }) => {
|
function setWorkers(data) {
|
||||||
|
workers.value = data;
|
||||||
|
workersCopy.value = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setClaimStates(data) {
|
||||||
claimStates.value = data;
|
claimStates.value = data;
|
||||||
claimStatesCopy.value = data;
|
claimStatesCopy.value = data;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter(value, update, options, originalOptions, filter) {
|
const workerFilter = {
|
||||||
update(
|
options: workers,
|
||||||
() => {
|
filterFn: (options, value) => {
|
||||||
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();
|
const search = value.toLowerCase();
|
||||||
|
|
||||||
filter(value, update, workers, workersCopy, (row) => {
|
if (value === '') return workersCopy.value;
|
||||||
|
|
||||||
|
return options.value.filter((row) => {
|
||||||
const id = row.id;
|
const id = row.id;
|
||||||
const name = row.name.toLowerCase();
|
const name = row.name.toLowerCase();
|
||||||
|
|
||||||
const idMatch = id == search;
|
const idMatches = id == search;
|
||||||
const nameMatch = name.indexOf(search) > -1;
|
const nameMatches = name.indexOf(search) > -1;
|
||||||
|
|
||||||
return idMatch || nameMatch;
|
return idMatches || nameMatches;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
};
|
||||||
|
|
||||||
function filterStates(value, update) {
|
const statesFilter = {
|
||||||
|
options: claimStates,
|
||||||
|
filterFn: (options, value) => {
|
||||||
const search = value.toLowerCase();
|
const search = value.toLowerCase();
|
||||||
|
|
||||||
filter(value, update, claimStates, claimStatesCopy, (row) => {
|
if (value === '') return claimStatesCopy.value;
|
||||||
|
|
||||||
|
return options.value.filter((row) => {
|
||||||
const description = row.description.toLowerCase();
|
const description = row.description.toLowerCase();
|
||||||
|
|
||||||
return description.indexOf(search) > -1;
|
return description.indexOf(search) > -1;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
};
|
||||||
function save() {
|
|
||||||
const id = route.params.id;
|
|
||||||
const formData = claim.value;
|
|
||||||
|
|
||||||
if (!hasChanges.value) {
|
|
||||||
return quasar.notify({
|
|
||||||
type: 'negative',
|
|
||||||
message: t('globals.noChanges'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.patch(`Claims/${id}`, formData).then((hasChanges.value = false));
|
|
||||||
}
|
|
||||||
|
|
||||||
function onReset() {
|
|
||||||
claim.value = claimCopy.value;
|
|
||||||
hasChanges.value = false;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
<fetch-data
|
||||||
|
url="Workers/activeWithInheritedRole"
|
||||||
|
:filter="{ where: { role: 'salesPerson' } }"
|
||||||
|
@on-fetch="setWorkers"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<fetch-data url="ClaimStates" @on-fetch="setClaimStates" auto-load />
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<q-card class="q-pa-md">
|
<q-card>
|
||||||
<skeleton-form v-if="!claim" />
|
<form-model :url="`Claims/${route.params.id}`" :filter="claimFilter" model="claim">
|
||||||
<q-form v-if="claim" @submit="save" @reset="onReset" greedy>
|
<template #form="{ data, validate, filter }">
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input v-model="claim.client.name" :label="t('claim.basicData.customer')" disable />
|
<q-input v-model="data.client.name" :label="t('claim.basicData.customer')" disable />
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input v-model="claim.created" mask="####-##-##" fill-mask="_" autofocus>
|
<q-input v-model="data.created" mask="####-##-##" fill-mask="_" autofocus>
|
||||||
<template #append>
|
<template #append>
|
||||||
<q-icon name="event" class="cursor-pointer">
|
<q-icon name="event" class="cursor-pointer">
|
||||||
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
|
||||||
<q-date v-model="claim.created" mask="YYYY-MM-DD">
|
<q-date v-model="data.created" mask="YYYY-MM-DD">
|
||||||
<div class="row items-center justify-end">
|
<div class="row items-center justify-end">
|
||||||
<q-btn v-close-popup label="Close" color="primary" flat />
|
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||||
</div>
|
</div>
|
||||||
|
@ -160,7 +108,7 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="claim.workerFk"
|
v-model="data.workerFk"
|
||||||
:options="workers"
|
:options="workers"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
|
@ -168,15 +116,15 @@ function onReset() {
|
||||||
:label="t('claim.basicData.assignedTo')"
|
:label="t('claim.basicData.assignedTo')"
|
||||||
map-options
|
map-options
|
||||||
use-input
|
use-input
|
||||||
@filter="filterWorkers"
|
@filter="(value, update) => filter(value, update, workerFilter)"
|
||||||
:rules="validate('claim.claimStateFk')"
|
:rules="validate('claim.claimStateFk')"
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
>
|
>
|
||||||
<template #before>
|
<template #before>
|
||||||
<q-avatar color="orange">
|
<q-avatar color="orange">
|
||||||
<q-img
|
<q-img
|
||||||
v-if="claim.workerFk"
|
v-if="data.workerFk"
|
||||||
:src="`/api/Images/user/160x160/${claim.workerFk}/download?access_token=${token}`"
|
:src="`/api/Images/user/160x160/${data.workerFk}/download?access_token=${token}`"
|
||||||
spinner-color="white"
|
spinner-color="white"
|
||||||
/>
|
/>
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
|
@ -185,7 +133,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="claim.claimStateFk"
|
v-model="data.claimStateFk"
|
||||||
:options="claimStates"
|
:options="claimStates"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="description"
|
option-label="description"
|
||||||
|
@ -193,7 +141,7 @@ function onReset() {
|
||||||
:label="t('claim.basicData.state')"
|
:label="t('claim.basicData.state')"
|
||||||
map-options
|
map-options
|
||||||
use-input
|
use-input
|
||||||
@filter="filterStates"
|
@filter="(value, update) => filter(value, update, statesFilter)"
|
||||||
:rules="validate('claim.claimStateFk')"
|
:rules="validate('claim.claimStateFk')"
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
>
|
>
|
||||||
|
@ -203,14 +151,14 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="claim.packages"
|
v-model="data.packages"
|
||||||
:label="t('claim.basicData.packages')"
|
:label="t('claim.basicData.packages')"
|
||||||
:rules="validate('claim.packages')"
|
:rules="validate('claim.packages')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="claim.rma"
|
v-model="data.rma"
|
||||||
:label="t('claim.basicData.returnOfMaterial')"
|
:label="t('claim.basicData.returnOfMaterial')"
|
||||||
:rules="validate('claim.rma')"
|
:rules="validate('claim.rma')"
|
||||||
/>
|
/>
|
||||||
|
@ -218,17 +166,13 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-checkbox v-model="claim.hasToPickUp" :label="t('claim.basicData.picked')" />
|
<q-checkbox v-model="data.hasToPickUp" :label="t('claim.basicData.picked')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</template>
|
||||||
<q-btn :label="t('globals.save')" type="submit" color="primary" />
|
</form-model>
|
||||||
<q-btn :label="t('globals.reset')" type="reset" class="q-ml-sm" color="primary" flat />
|
|
||||||
</div>
|
|
||||||
</q-form>
|
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -163,7 +163,9 @@ function stateColor(code) {
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
<router-view v-if="claim.id" :claim="claim"></router-view>
|
<q-page class="q-pa-md">
|
||||||
|
<router-view></router-view>
|
||||||
|
</q-page>
|
||||||
</q-page-container>
|
</q-page-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
import axios from 'axios';
|
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';
|
import { toDate } from 'src/filters';
|
||||||
|
|
||||||
onMounted(() => fetch());
|
|
||||||
|
|
||||||
const $props = defineProps({
|
|
||||||
claim: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const claim = ref([]);
|
||||||
|
const fetcher = ref();
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
|
include: {
|
||||||
|
relation: 'rmas',
|
||||||
|
scope: {
|
||||||
include: {
|
include: {
|
||||||
relation: 'worker',
|
relation: 'worker',
|
||||||
scope: {
|
scope: {
|
||||||
|
@ -27,27 +27,24 @@ const filter = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
where: {
|
order: 'created DESC',
|
||||||
code: $props.claim.rma,
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function fetch() {
|
async function addRow() {
|
||||||
//console.log($props.claim);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addRow() {
|
|
||||||
const formData = {
|
const formData = {
|
||||||
code: $props.claim.rma,
|
code: claim.value.rma,
|
||||||
};
|
};
|
||||||
|
|
||||||
axios.post(`ClaimRmas`, formData).then(() => {
|
await axios.post(`ClaimRmas`, formData);
|
||||||
|
await fetcher.value.fetch();
|
||||||
|
|
||||||
quasar.notify({
|
quasar.notify({
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
message: t('globals.rowAdded'),
|
message: t('globals.rowAdded'),
|
||||||
icon: 'check',
|
icon: 'check',
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmShown = ref(false);
|
const confirmShown = ref(false);
|
||||||
|
@ -57,9 +54,11 @@ function confirmRemove(id) {
|
||||||
rmaId.value = id;
|
rmaId.value = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove() {
|
async function remove() {
|
||||||
const id = rmaId.value;
|
const id = rmaId.value;
|
||||||
axios.delete(`ClaimRmas/${id}`).then(() => {
|
|
||||||
|
await axios.delete(`ClaimRmas/${id}`);
|
||||||
|
await fetcher.value.fetch();
|
||||||
confirmShown.value = false;
|
confirmShown.value = false;
|
||||||
|
|
||||||
quasar.notify({
|
quasar.notify({
|
||||||
|
@ -67,7 +66,6 @@ function remove() {
|
||||||
message: t('globals.rowRemoved'),
|
message: t('globals.rowRemoved'),
|
||||||
icon: 'check',
|
icon: 'check',
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
|
@ -75,7 +73,14 @@ function hide() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md sticky">
|
<fetch-data
|
||||||
|
ref="fetcher"
|
||||||
|
:url="`Claims/${route.params.id}`"
|
||||||
|
:filter="filter"
|
||||||
|
@on-fetch="($data) => (claim = $data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<div class="sticky-page">
|
||||||
<q-page-sticky expand position="top">
|
<q-page-sticky expand position="top">
|
||||||
<q-toolbar class="bg-grey-9">
|
<q-toolbar class="bg-grey-9">
|
||||||
<q-space />
|
<q-space />
|
||||||
|
@ -85,28 +90,41 @@ function hide() {
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
</q-page-sticky>
|
</q-page-sticky>
|
||||||
|
|
||||||
<smart-card ref="card" url="/ClaimRmas" :filter="filter" sort-by="id DESC" auto-load>
|
<paginate :data="claim.rmas">
|
||||||
<template #header="{ row }">
|
<template #body="{ rows }">
|
||||||
<q-item-label caption>{{ t('claim.rma.user') }}</q-item-label>
|
<q-card class="card">
|
||||||
<q-item-label>{{ row.worker.user.name }}</q-item-label>
|
<template v-for="row of rows" :key="row.id">
|
||||||
</template>
|
<q-item class="q-pa-none items-start">
|
||||||
<template #labels="{ row }">
|
<q-item-section class="q-pa-md">
|
||||||
<q-list>
|
<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 class="q-pa-none">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('claim.rma.created') }}</q-item-label>
|
<q-item-label caption>{{ t('claim.rma.created') }}</q-item-label>
|
||||||
<q-item-label>{{ toDate(row.created, { timeStyle: 'medium' }) }}</q-item-label>
|
<q-item-label>
|
||||||
|
{{ toDate(row.created, { timeStyle: 'medium' }) }}
|
||||||
|
</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</template>
|
</q-item-section>
|
||||||
<template #actions="{ row }">
|
<q-card-actions vertical class="justify-between">
|
||||||
<q-btn flat round color="orange" icon="vn:bin" @click="confirmRemove(row.id)">
|
<q-btn flat round color="orange" icon="vn:bin" @click="confirmRemove(row.id)">
|
||||||
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
|
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-item>
|
||||||
|
<q-separator />
|
||||||
</template>
|
</template>
|
||||||
</smart-card>
|
</q-card>
|
||||||
</q-page>
|
</template>
|
||||||
|
</paginate>
|
||||||
|
</div>
|
||||||
<q-dialog v-model="confirmShown" persistent @hide="hide">
|
<q-dialog v-model="confirmShown" persistent @hide="hide">
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section class="row items-center">
|
<q-card-section class="row items-center">
|
||||||
|
@ -126,7 +144,7 @@ function hide() {
|
||||||
.q-toolbar {
|
.q-toolbar {
|
||||||
background-color: $grey-9;
|
background-color: $grey-9;
|
||||||
}
|
}
|
||||||
.sticky {
|
.sticky-page {
|
||||||
padding-top: 66px;
|
padding-top: 66px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,6 @@ function stateColor(code) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
|
||||||
<div class="summary container">
|
<div class="summary container">
|
||||||
<q-card>
|
<q-card>
|
||||||
<skeleton-summary v-if="!claim" />
|
<skeleton-summary v-if="!claim" />
|
||||||
|
@ -158,7 +157,6 @@ function stateColor(code) {
|
||||||
</template>
|
</template>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -194,4 +192,8 @@ function stateColor(code) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.q-dialog .summary {
|
||||||
|
max-width: 1200px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { reactive, watch } from 'vue'
|
|
||||||
|
|
||||||
const customer = reactive({
|
|
||||||
name: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(() => customer.name, () => {
|
|
||||||
console.log('customer.name changed');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<q-page class="q-pa-md">
|
|
||||||
<q-card class="q-pa-md">
|
|
||||||
<q-form @submit="onSubmit" @reset="onReset" class="q-gutter-md">
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
v-model="customer.name"
|
|
||||||
label="Your name *"
|
|
||||||
hint="Name and surname"
|
|
||||||
lazy-rules
|
|
||||||
:rules="[val => val && val.length > 0 || 'Please type something']"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
type="number"
|
|
||||||
v-model="age"
|
|
||||||
label="Your age *"
|
|
||||||
lazy-rules
|
|
||||||
:rules="[
|
|
||||||
val => val !== null && val !== '' || 'Please type your age',
|
|
||||||
val => val > 0 && val < 100 || 'Please type a real age'
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<q-btn label="Submit" type="submit" color="primary" />
|
|
||||||
<q-btn label="Reset" type="reset" color="primary" flat class="q-ml-sm" />
|
|
||||||
</div>
|
|
||||||
</q-form>
|
|
||||||
</q-card>
|
|
||||||
</q-page>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.card {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 60em;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
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 { toDate } from 'src/filters/index';
|
||||||
import ClaimSummary from './Card/ClaimSummary.vue';
|
import ClaimSummary from './Card/ClaimSummary.vue';
|
||||||
|
|
||||||
|
@ -50,8 +50,13 @@ function showPreview(id) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
<q-page class="q-pa-md">
|
||||||
<smart-card url="/Claims" :filter="filter" sort-by="id DESC" @on-navigate="navigate" auto-load>
|
<paginate url="/Claims" :filter="filter" sort-by="id DESC" auto-load>
|
||||||
<template #labels="{ row }">
|
<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-list>
|
||||||
<q-item class="q-pa-none">
|
<q-item class="q-pa-none">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
|
@ -78,8 +83,9 @@ function showPreview(id) {
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</template>
|
</q-item-section>
|
||||||
<template #actions="{ row }">
|
<q-separator vertical />
|
||||||
|
<q-card-actions vertical class="justify-between">
|
||||||
<q-btn color="grey-7" round flat icon="more_vert">
|
<q-btn color="grey-7" round flat icon="more_vert">
|
||||||
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
|
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
|
||||||
<q-menu cover auto-close>
|
<q-menu cover auto-close>
|
||||||
|
@ -106,8 +112,11 @@ function showPreview(id) {
|
||||||
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
|
<q-btn flat round color="grey-7" icon="preview" @click="showPreview(row.id)">
|
||||||
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
|
<q-tooltip>{{ t('components.smartCard.openSummary') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-item>
|
||||||
|
</q-card>
|
||||||
</template>
|
</template>
|
||||||
</smart-card>
|
</paginate>
|
||||||
</q-page>
|
</q-page>
|
||||||
<q-dialog v-model="preview.shown">
|
<q-dialog v-model="preview.shown">
|
||||||
<claim-summary :claim-id="preview.data.claimId" />
|
<claim-summary :claim-id="preview.data.claimId" />
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import SmartCard from 'src/components/SmartCard.vue';
|
import Paginate from 'src/components/Paginate.vue';
|
||||||
|
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -26,7 +26,7 @@ function submit() {
|
||||||
crated: new Date(),
|
crated: new Date(),
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.then(() => card.value.fetch());
|
.then(() => card.value.refresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmShown = ref(false);
|
const confirmShown = ref(false);
|
||||||
|
@ -38,7 +38,9 @@ function confirm(id) {
|
||||||
|
|
||||||
function remove() {
|
function remove() {
|
||||||
const id = rmaId.value;
|
const id = rmaId.value;
|
||||||
axios.delete(`ClaimRmas/${id}`).then(() => {
|
axios
|
||||||
|
.delete(`ClaimRmas/${id}`)
|
||||||
|
.then(() => {
|
||||||
confirmShown.value = false;
|
confirmShown.value = false;
|
||||||
|
|
||||||
quasar.notify({
|
quasar.notify({
|
||||||
|
@ -46,7 +48,8 @@ function remove() {
|
||||||
message: 'Entry deleted',
|
message: 'Entry deleted',
|
||||||
icon: 'check',
|
icon: 'check',
|
||||||
});
|
});
|
||||||
});
|
})
|
||||||
|
.then(() => card.value.refresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
|
@ -59,14 +62,18 @@ function hide() {
|
||||||
<q-page-sticky expand position="top" :offset="[16, 16]">
|
<q-page-sticky expand position="top" :offset="[16, 16]">
|
||||||
<q-card class="card q-pa-md">
|
<q-card class="card q-pa-md">
|
||||||
<q-form @submit="submit">
|
<q-form @submit="submit">
|
||||||
<q-input v-model="newRma.code" :label="t('claim.rmaList.newRma')" class="q-mb-md" />
|
<q-input v-model="newRma.code" :label="t('claim.rmaList.code')" class="q-mb-md" autofocus />
|
||||||
<div class="text-caption">$(0) entries</div>
|
<!-- <div class="text-caption">$(0) entries</div> -->
|
||||||
</q-form>
|
</q-form>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-page-sticky>
|
</q-page-sticky>
|
||||||
|
|
||||||
<smart-card ref="card" url="/ClaimRmas" sort-by="id DESC" auto-load>
|
<paginate ref="card" url="/ClaimRmas" sort-by="id DESC" auto-load>
|
||||||
<template #labels="{ row }">
|
<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-list>
|
||||||
<q-item class="q-pa-none">
|
<q-item class="q-pa-none">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
|
@ -75,13 +82,18 @@ function hide() {
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</template>
|
</q-item-section>
|
||||||
<template #actions="{ row }">
|
<q-card-actions vertical class="justify-between">
|
||||||
<q-btn flat round color="primary" icon="vn:bin" @click="confirm(row.id)">
|
<q-btn flat round color="primary" icon="vn:bin" @click="confirm(row.id)">
|
||||||
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
|
<q-tooltip>{{ t('globals.remove') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-item>
|
||||||
|
<q-separator />
|
||||||
</template>
|
</template>
|
||||||
</smart-card>
|
</q-card>
|
||||||
|
</template>
|
||||||
|
</paginate>
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
<q-dialog v-model="confirmShown" persistent @hide="hide">
|
<q-dialog v-model="confirmShown" persistent @hide="hide">
|
||||||
|
|
|
@ -1,135 +1,64 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { useSession } from 'src/composables/useSession';
|
|
||||||
import { useValidator } from 'src/composables/useValidator';
|
|
||||||
import SkeletonForm from 'src/components/SkeletonForm.vue';
|
|
||||||
|
|
||||||
onMounted(() => {
|
import { useSession } from 'src/composables/useSession';
|
||||||
fetch();
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
fetchWorkers();
|
import FormModel from 'src/components/FormModel.vue';
|
||||||
fetchBusinessTypes();
|
|
||||||
fetchContactChannels();
|
|
||||||
});
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const quasar = useQuasar();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { validate } = useValidator();
|
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const token = session.getToken();
|
const token = session.getToken();
|
||||||
|
|
||||||
const customer = ref(null);
|
|
||||||
const customerCopy = ref(null);
|
|
||||||
const hasChanges = ref(false);
|
|
||||||
|
|
||||||
function fetch() {
|
|
||||||
const id = route.params.id;
|
|
||||||
const filter = {
|
|
||||||
include: [],
|
|
||||||
};
|
|
||||||
const options = { params: { filter } };
|
|
||||||
axios.get(`Clients/${id}`, options).then(({ data }) => {
|
|
||||||
customer.value = data;
|
|
||||||
customerCopy.value = Object.assign({}, data);
|
|
||||||
|
|
||||||
watch(customer.value, () => (hasChanges.value = true));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const businessTypes = ref([]);
|
|
||||||
function fetchBusinessTypes() {
|
|
||||||
axios.get(`BusinessTypes`).then(({ data }) => {
|
|
||||||
businessTypes.value = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const contactChannels = ref([]);
|
|
||||||
function fetchContactChannels() {
|
|
||||||
axios.get(`ContactChannels`).then(({ data }) => {
|
|
||||||
contactChannels.value = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const workers = ref([]);
|
const workers = ref([]);
|
||||||
const workersCopy = ref([]);
|
const workersCopy = ref([]);
|
||||||
function fetchWorkers() {
|
const businessTypes = ref([]);
|
||||||
const filter = {
|
const contactChannels = ref([]);
|
||||||
where: {
|
|
||||||
role: 'salesPerson',
|
function setWorkers(data) {
|
||||||
},
|
|
||||||
};
|
|
||||||
const options = { params: { filter } };
|
|
||||||
axios.get(`Workers/activeWithRole`, options).then(({ data }) => {
|
|
||||||
workers.value = data;
|
workers.value = data;
|
||||||
workersCopy.value = data;
|
workersCopy.value = data;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter(value, update, options, originalOptions, filter) {
|
const filterOptions = {
|
||||||
update(
|
options: workers,
|
||||||
() => {
|
filterFn: (options, value) => {
|
||||||
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();
|
const search = value.toLowerCase();
|
||||||
|
|
||||||
filter(value, update, workers, workersCopy, (row) => {
|
if (value === '') return workersCopy.value;
|
||||||
|
|
||||||
|
return options.value.filter((row) => {
|
||||||
const id = row.id;
|
const id = row.id;
|
||||||
const name = row.name.toLowerCase();
|
const name = row.name.toLowerCase();
|
||||||
|
|
||||||
const idMatch = id == search;
|
const idMatches = id == search;
|
||||||
const nameMatch = name.indexOf(search) > -1;
|
const nameMatches = name.indexOf(search) > -1;
|
||||||
|
|
||||||
return idMatch || nameMatch;
|
return idMatches || nameMatches;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
};
|
||||||
function save() {
|
|
||||||
const id = route.params.id;
|
|
||||||
const formData = customer.value;
|
|
||||||
|
|
||||||
if (!hasChanges.value) {
|
|
||||||
return quasar.notify({
|
|
||||||
type: 'negative',
|
|
||||||
message: t('globals.noChanges'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.patch(`Clients/${id}`, formData).then((hasChanges.value = false));
|
|
||||||
}
|
|
||||||
|
|
||||||
function onReset() {
|
|
||||||
customer.value = customerCopy.value;
|
|
||||||
hasChanges.value = false;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
<fetch-data
|
||||||
|
url="Workers/activeWithInheritedRole"
|
||||||
|
:filter="{ where: { role: 'salesPerson' } }"
|
||||||
|
@on-fetch="setWorkers"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<fetch-data url="ContactChannels" @on-fetch="($data) => (contactChannels = $data)" auto-load />
|
||||||
|
<fetch-data url="BusinessTypes" @on-fetch="($data) => (businessTypes = $data)" auto-load />
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<q-card class="q-pa-md">
|
<q-card>
|
||||||
<skeleton-form v-if="!customer" />
|
<form-model :url="`Clients/${route.params.id}`" model="customer">
|
||||||
<q-form v-if="customer" @submit="save" @reset="onReset" greedy>
|
<template #form="{ data, validate, filter }">
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.socialName"
|
v-model="data.socialName"
|
||||||
:label="t('customer.basicData.socialName')"
|
:label="t('customer.basicData.socialName')"
|
||||||
:rules="validate('client.socialName')"
|
:rules="validate('client.socialName')"
|
||||||
autofocus
|
autofocus
|
||||||
|
@ -137,7 +66,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="customer.businessTypeFk"
|
v-model="data.businessTypeFk"
|
||||||
:options="businessTypes"
|
:options="businessTypes"
|
||||||
option-value="code"
|
option-value="code"
|
||||||
option-label="description"
|
option-label="description"
|
||||||
|
@ -152,7 +81,7 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.contact"
|
v-model="data.contact"
|
||||||
:label="t('customer.basicData.contact')"
|
:label="t('customer.basicData.contact')"
|
||||||
:rules="validate('client.contact')"
|
:rules="validate('client.contact')"
|
||||||
clearable
|
clearable
|
||||||
|
@ -160,7 +89,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.email"
|
v-model="data.email"
|
||||||
type="email"
|
type="email"
|
||||||
:label="t('customer.basicData.email')"
|
:label="t('customer.basicData.email')"
|
||||||
:rules="validate('client.email')"
|
:rules="validate('client.email')"
|
||||||
|
@ -171,7 +100,7 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.phone"
|
v-model="data.phone"
|
||||||
:label="t('customer.basicData.phone')"
|
:label="t('customer.basicData.phone')"
|
||||||
:rules="validate('client.phone')"
|
:rules="validate('client.phone')"
|
||||||
clearable
|
clearable
|
||||||
|
@ -179,7 +108,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-input
|
<q-input
|
||||||
v-model="customer.mobile"
|
v-model="data.mobile"
|
||||||
:label="t('customer.basicData.mobile')"
|
:label="t('customer.basicData.mobile')"
|
||||||
:rules="validate('client.mobile')"
|
:rules="validate('client.mobile')"
|
||||||
clearable
|
clearable
|
||||||
|
@ -189,7 +118,7 @@ function onReset() {
|
||||||
<div class="row q-gutter-md q-mb-md">
|
<div class="row q-gutter-md q-mb-md">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="customer.salesPersonFk"
|
v-model="data.salesPersonFk"
|
||||||
:options="workers"
|
:options="workers"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
|
@ -197,15 +126,15 @@ function onReset() {
|
||||||
:label="t('customer.basicData.salesPerson')"
|
:label="t('customer.basicData.salesPerson')"
|
||||||
map-options
|
map-options
|
||||||
use-input
|
use-input
|
||||||
@filter="filterWorkers"
|
@filter="(value, update) => filter(value, update, filterOptions)"
|
||||||
:rules="validate('client.salesPersonFk')"
|
:rules="validate('client.salesPersonFk')"
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
>
|
>
|
||||||
<template #before>
|
<template #before>
|
||||||
<q-avatar color="orange">
|
<q-avatar color="orange">
|
||||||
<q-img
|
<q-img
|
||||||
v-if="customer.salesPersonFk"
|
v-if="data.salesPersonFk"
|
||||||
:src="`/api/Images/user/160x160/${customer.salesPersonFk}/download?access_token=${token}`"
|
:src="`/api/Images/user/160x160/${data.salesPersonFk}/download?access_token=${token}`"
|
||||||
spinner-color="white"
|
spinner-color="white"
|
||||||
/>
|
/>
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
|
@ -214,7 +143,7 @@ function onReset() {
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-select
|
<q-select
|
||||||
v-model="customer.contactChannelFk"
|
v-model="data.contactChannelFk"
|
||||||
:options="contactChannels"
|
:options="contactChannels"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
|
@ -226,14 +155,10 @@ function onReset() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</template>
|
||||||
<q-btn :label="t('globals.save')" type="submit" color="primary" />
|
</form-model>
|
||||||
<q-btn :label="t('globals.reset')" type="reset" class="q-ml-sm" color="primary" flat />
|
|
||||||
</div>
|
|
||||||
</q-form>
|
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -174,7 +174,9 @@ async function fetch() {
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
|
<q-page class="q-pa-md">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
|
</q-page>
|
||||||
</q-page-container>
|
</q-page-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,7 @@ function fetch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const balanceDue = computed(() => {
|
const balanceDue = computed(() => {
|
||||||
const [defaulter] = customer.value.defaulters;
|
return customer.value.defaulters.length && customer.value.defaulters[0].amount;
|
||||||
|
|
||||||
return defaulter.amount;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const balanceDueWarning = computed(() => (balanceDue.value ? 'negative' : ''));
|
const balanceDueWarning = computed(() => (balanceDue.value ? 'negative' : ''));
|
||||||
|
@ -64,7 +62,6 @@ const creditWarning = computed(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
|
||||||
<div class="summary container">
|
<div class="summary container">
|
||||||
<q-card>
|
<q-card>
|
||||||
<skeleton-summary v-if="!customer" />
|
<skeleton-summary v-if="!customer" />
|
||||||
|
@ -75,7 +72,10 @@ const creditWarning = computed(() => {
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item-label header class="text-h6">
|
<q-item-label header class="text-h6">
|
||||||
{{ t('customer.summary.basicData') }}
|
{{ t('customer.summary.basicData') }}
|
||||||
<router-link :to="{ name: 'CustomerBasicData' }">
|
<router-link
|
||||||
|
:to="{ name: 'CustomerBasicData', params: { id: entityId } }"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<q-icon name="open_in_new" />
|
<q-icon name="open_in_new" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
|
@ -98,7 +98,7 @@ const creditWarning = computed(() => {
|
||||||
<q-item-label>{{ customer.contact }}</q-item-label>
|
<q-item-label>{{ customer.contact }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.salesPersonUser">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.salesPerson') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.salesPerson') }}</q-item-label>
|
||||||
<q-item-label>{{ customer.salesPersonUser.name }}</q-item-label>
|
<q-item-label>{{ customer.salesPersonUser.name }}</q-item-label>
|
||||||
|
@ -122,7 +122,7 @@ const creditWarning = computed(() => {
|
||||||
<q-item-label>{{ customer.email }}</q-item-label>
|
<q-item-label>{{ customer.email }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.contactChannel">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.contactChannel') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.contactChannel') }}</q-item-label>
|
||||||
<q-item-label>{{ customer.contactChannel.name }}</q-item-label>
|
<q-item-label>{{ customer.contactChannel.name }}</q-item-label>
|
||||||
|
@ -153,13 +153,13 @@ const creditWarning = computed(() => {
|
||||||
<q-item-label>{{ customer.postcode }}</q-item-label>
|
<q-item-label>{{ customer.postcode }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.province">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.province') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.province') }}</q-item-label>
|
||||||
<q-item-label>{{ customer.province.name }}</q-item-label>
|
<q-item-label>{{ customer.province.name }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.country">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.country') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.country') }}</q-item-label>
|
||||||
<q-item-label>{{ customer.country.country }}</q-item-label>
|
<q-item-label>{{ customer.country.country }}</q-item-label>
|
||||||
|
@ -249,11 +249,7 @@ const creditWarning = computed(() => {
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item dense>
|
<q-item dense>
|
||||||
<q-checkbox
|
<q-checkbox v-model="customer.hasLcr" :label="t('customer.summary.hasLcr')" disable />
|
||||||
v-model="customer.hasLcr"
|
|
||||||
:label="t('customer.summary.hasLcr')"
|
|
||||||
disable
|
|
||||||
/>
|
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item dense>
|
<q-item dense>
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
|
@ -271,7 +267,7 @@ const creditWarning = computed(() => {
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col" v-if="customer.defaultAddress">
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item-label header class="text-h6">
|
<q-item-label header class="text-h6">
|
||||||
{{ t('customer.summary.consignee') }}
|
{{ t('customer.summary.consignee') }}
|
||||||
|
@ -296,7 +292,7 @@ const creditWarning = computed(() => {
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col" v-if="customer.account">
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item-label header class="text-h6">
|
<q-item-label header class="text-h6">
|
||||||
{{ t('customer.summary.webAccess') }}
|
{{ t('customer.summary.webAccess') }}
|
||||||
|
@ -333,11 +329,11 @@ const creditWarning = computed(() => {
|
||||||
<q-item-label>{{ toCurrency(customer.mana.mana) }}</q-item-label>
|
<q-item-label>{{ toCurrency(customer.mana.mana) }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.claimsRatio">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{
|
<q-item-label caption>
|
||||||
t('customer.summary.priceIncreasingRate')
|
{{ t('customer.summary.priceIncreasingRate') }}
|
||||||
}}</q-item-label>
|
</q-item-label>
|
||||||
<q-item-label>{{ toPercentage(priceIncreasingRate) }}</q-item-label>
|
<q-item-label>{{ toPercentage(priceIncreasingRate) }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
@ -347,7 +343,7 @@ const creditWarning = computed(() => {
|
||||||
<q-item-label>{{ toCurrency(customer.averageInvoiced.invoiced) }}</q-item-label>
|
<q-item-label>{{ toCurrency(customer.averageInvoiced.invoiced) }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.claimsRatio">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.claimRate') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.claimRate') }}</q-item-label>
|
||||||
<q-item-label>{{ toPercentage(claimRate) }}</q-item-label>
|
<q-item-label>{{ toPercentage(claimRate) }}</q-item-label>
|
||||||
|
@ -360,7 +356,7 @@ const creditWarning = computed(() => {
|
||||||
<q-item-label header class="text-h6">
|
<q-item-label header class="text-h6">
|
||||||
{{ t('customer.summary.financialData') }}
|
{{ t('customer.summary.financialData') }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
<q-item>
|
<q-item v-if="customer.debt">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.risk') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.risk') }}</q-item-label>
|
||||||
<q-item-label :class="debtWarning">
|
<q-item-label :class="debtWarning">
|
||||||
|
@ -386,7 +382,7 @@ const creditWarning = computed(() => {
|
||||||
</q-icon>
|
</q-icon>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.creditInsurance">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.securedCredit') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.securedCredit') }}</q-item-label>
|
||||||
<q-item-label>{{ toCurrency(customer.creditInsurance) }}</q-item-label>
|
<q-item-label>{{ toCurrency(customer.creditInsurance) }}</q-item-label>
|
||||||
|
@ -408,7 +404,7 @@ const creditWarning = computed(() => {
|
||||||
</q-icon>
|
</q-icon>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-if="customer.defaulters">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label caption>{{ t('customer.summary.balanceDue') }}</q-item-label>
|
<q-item-label caption>{{ t('customer.summary.balanceDue') }}</q-item-label>
|
||||||
<q-item-label :class="balanceDueWarning">
|
<q-item-label :class="balanceDueWarning">
|
||||||
|
@ -433,9 +429,7 @@ const creditWarning = computed(() => {
|
||||||
</template>
|
</template>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -491,4 +485,8 @@ const creditWarning = computed(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.q-dialog .summary {
|
||||||
|
max-width: 1200px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
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';
|
import CustomerSummary from './Card/CustomerSummary.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -26,8 +26,13 @@ function showPreview(id) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
<q-page class="q-pa-md">
|
||||||
<smart-card url="/Clients" sort-by="id DESC" @on-navigate="navigate" auto-load>
|
<paginate url="/Clients" sort-by="id DESC" auto-load>
|
||||||
<template #labels="{ row }">
|
<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-list>
|
||||||
<q-item class="q-pa-none">
|
<q-item class="q-pa-none">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
|
@ -42,8 +47,9 @@ function showPreview(id) {
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</template>
|
</q-item-section>
|
||||||
<template #actions="{ row }">
|
<q-separator vertical />
|
||||||
|
<q-card-actions vertical class="justify-between">
|
||||||
<q-btn color="grey-7" round flat icon="more_vert">
|
<q-btn color="grey-7" round flat icon="more_vert">
|
||||||
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
|
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
|
||||||
<q-menu cover auto-close>
|
<q-menu cover auto-close>
|
||||||
|
@ -73,8 +79,11 @@ function showPreview(id) {
|
||||||
<q-btn flat round color="grey-7" icon="vn:ticket">
|
<q-btn flat round color="grey-7" icon="vn:ticket">
|
||||||
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
|
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-item>
|
||||||
|
</q-card>
|
||||||
</template>
|
</template>
|
||||||
</smart-card>
|
</paginate>
|
||||||
</q-page>
|
</q-page>
|
||||||
<q-dialog v-model="preview.shown">
|
<q-dialog v-model="preview.shown">
|
||||||
<customer-summary :customer-id="preview.data.customerId" />
|
<customer-summary :customer-id="preview.data.customerId" />
|
||||||
|
|
|
@ -79,8 +79,7 @@ async function getVideoList(expeditionId, timed) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-layout view="hhh lpr ffr" class="fit">
|
<q-drawer show-if-above side="right">
|
||||||
<q-drawer show-if-above side="right" bordered>
|
|
||||||
<q-scroll-area class="fit">
|
<q-scroll-area class="fit">
|
||||||
<q-list bordered separator style="max-width: 318px">
|
<q-list bordered separator style="max-width: 318px">
|
||||||
<q-item v-if="lastExpedition && videoList.length">
|
<q-item v-if="lastExpedition && videoList.length">
|
||||||
|
@ -144,8 +143,6 @@ async function getVideoList(expeditionId, timed) {
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
|
|
||||||
<q-page-container>
|
|
||||||
<q-page>
|
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-carousel animated v-model="slide" height="max-content">
|
<q-carousel animated v-model="slide" height="max-content">
|
||||||
<q-carousel-slide v-for="video in videoList" :key="video.value" :name="video.value">
|
<q-carousel-slide v-for="video in videoList" :key="video.value" :name="video.value">
|
||||||
|
@ -153,7 +150,4 @@ async function getVideoList(expeditionId, timed) {
|
||||||
</q-carousel-slide>
|
</q-carousel-slide>
|
||||||
</q-carousel>
|
</q-carousel>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-page>
|
|
||||||
</q-page-container>
|
|
||||||
</q-layout>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -147,17 +147,19 @@ function stateColor(state) {
|
||||||
<q-separator />
|
<q-separator />
|
||||||
|
|
||||||
<q-list>
|
<q-list>
|
||||||
<!-- <q-item :to="{ name: 'TicketBasicData' }" clickable v-ripple>
|
<q-item :to="{ name: 'TicketBoxing' }" clickable v-ripple>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon name="vn:settings" />
|
<q-icon name="vn:package" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>{{ t('ticket.pageTitles.basicData') }}</q-item-section>
|
<q-item-section>{{ t('ticket.pageTitles.boxing') }}</q-item-section>
|
||||||
</q-item> -->
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-scroll-area> </q-drawer
|
</q-scroll-area>
|
||||||
>-->
|
</q-drawer>
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
|
<q-page class="q-pa-md">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
|
</q-page>
|
||||||
</q-page-container>
|
</q-page-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
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 { toDate, toCurrency } from 'src/filters/index';
|
||||||
// import CustomerSummary from './Card/CustomerSummary.vue';
|
// import TicketSummary from './Card/TicketSummary.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -62,8 +62,13 @@ function showPreview(id) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
<q-page class="q-pa-md">
|
||||||
<smart-card url="/Tickets" :filter="filter" sort-by="id DESC" @on-navigate="navigate" auto-load>
|
<paginate url="/Tickets" :filter="filter" sort-by="id DESC" auto-load>
|
||||||
<template #labels="{ row }">
|
<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-list>
|
||||||
<q-item class="q-pa-none">
|
<q-item class="q-pa-none">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
|
@ -100,8 +105,9 @@ function showPreview(id) {
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</template>
|
</q-item-section>
|
||||||
<template #actions="{ row }">
|
<q-separator vertical />
|
||||||
|
<q-card-actions vertical class="justify-between">
|
||||||
<q-btn color="grey-7" round flat icon="more_vert">
|
<q-btn color="grey-7" round flat icon="more_vert">
|
||||||
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
|
<q-tooltip>{{ t('customer.list.moreOptions') }}</q-tooltip>
|
||||||
<q-menu cover auto-close>
|
<q-menu cover auto-close>
|
||||||
|
@ -131,8 +137,11 @@ function showPreview(id) {
|
||||||
<q-btn flat round color="grey-7" icon="vn:ticket">
|
<q-btn flat round color="grey-7" icon="vn:ticket">
|
||||||
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
|
<q-tooltip>{{ t('customer.list.customerOrders') }}</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-item>
|
||||||
|
</q-card>
|
||||||
</template>
|
</template>
|
||||||
</smart-card>
|
</paginate>
|
||||||
</q-page>
|
</q-page>
|
||||||
<!-- <q-dialog v-model="preview.shown">
|
<!-- <q-dialog v-model="preview.shown">
|
||||||
<customer-summary :customer-id="preview.data.customerId" />
|
<customer-summary :customer-id="preview.data.customerId" />
|
||||||
|
|
|
@ -34,15 +34,6 @@ export default {
|
||||||
roles: ['claimManager']
|
roles: ['claimManager']
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Claim/ClaimRmaList.vue'),
|
component: () => import('src/pages/Claim/ClaimRmaList.vue'),
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ClaimCreate',
|
|
||||||
path: 'create',
|
|
||||||
meta: {
|
|
||||||
title: 'createClaim',
|
|
||||||
icon: 'vn:addperson',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Claim/ClaimCreate.vue'),
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -76,8 +67,7 @@ export default {
|
||||||
title: 'rma',
|
title: 'rma',
|
||||||
roles: ['claimManager']
|
roles: ['claimManager']
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Claim/Card/ClaimRma.vue'),
|
component: () => import('src/pages/Claim/Card/ClaimRma.vue')
|
||||||
props: { claim: true }
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue