Merge pull request 'Zone Calendar' (!411) from hyervoni/salix-front-mindshore:feature/ZoneCalendar into dev
gitea/salix-front/pipeline/head This commit looks good
Details
gitea/salix-front/pipeline/head This commit looks good
Details
Reviewed-on: #411 Reviewed-by: Javier Segarra <jsegarra@verdnatura.es> Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
commit
b54cb73c91
|
@ -74,7 +74,7 @@ const closeForm = () => {
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
/>
|
/>
|
||||||
<slot name="customButtons" />
|
<slot name="custom-buttons" />
|
||||||
</div>
|
</div>
|
||||||
</QCard>
|
</QCard>
|
||||||
</QForm>
|
</QForm>
|
||||||
|
|
|
@ -22,6 +22,7 @@ const props = defineProps({
|
||||||
searchbarInfo: { type: String, default: '' },
|
searchbarInfo: { type: String, default: '' },
|
||||||
searchCustomRouteRedirect: { type: String, default: undefined },
|
searchCustomRouteRedirect: { type: String, default: undefined },
|
||||||
searchRedirect: { type: Boolean, default: true },
|
searchRedirect: { type: Boolean, default: true },
|
||||||
|
searchMakeFetch: { type: Boolean, default: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
wdays: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:wdays']);
|
||||||
|
|
||||||
|
const weekdayStore = useWeekdayStore();
|
||||||
|
|
||||||
|
const selectedWDays = computed({
|
||||||
|
get: () => props.wdays,
|
||||||
|
set: (value) => emit('update:wdays', value),
|
||||||
|
});
|
||||||
|
|
||||||
|
const toggleDay = (index) => (selectedWDays.value[index] = !selectedWDays.value[index]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="q-gutter-x-sm" style="width: max-content">
|
||||||
|
<QBtn
|
||||||
|
v-for="(weekday, index) in weekdayStore.getLocalesMap"
|
||||||
|
:key="index"
|
||||||
|
:label="weekday.localeChar"
|
||||||
|
rounded
|
||||||
|
style="max-width: 36px"
|
||||||
|
:color="selectedWDays[weekday.index] ? 'primary' : ''"
|
||||||
|
@click="toggleDay(weekday.index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -147,7 +147,7 @@ const containerClasses = computed(() => {
|
||||||
.q-calendar-month__head--workweek,
|
.q-calendar-month__head--workweek,
|
||||||
.q-calendar-month__head--weekday.q-calendar__center.q-calendar__ellipsis {
|
.q-calendar-month__head--weekday.q-calendar__center.q-calendar__ellipsis {
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
color: var(---color-font-secondary);
|
color: $color-font-secondary;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -67,6 +67,10 @@ const props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
makeFetch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let arrayData = useArrayData(props.dataKey, { ...props });
|
let arrayData = useArrayData(props.dataKey, { ...props });
|
||||||
|
@ -94,12 +98,14 @@ async function search() {
|
||||||
([key, value]) => value && (props.staticParams || []).includes(key)
|
([key, value]) => value && (props.staticParams || []).includes(key)
|
||||||
);
|
);
|
||||||
store.skip = 0;
|
store.skip = 0;
|
||||||
await arrayData.applyFilter({
|
|
||||||
params: {
|
if (props.makeFetch)
|
||||||
...Object.fromEntries(staticParams),
|
await arrayData.applyFilter({
|
||||||
search: searchText.value,
|
params: {
|
||||||
},
|
...Object.fromEntries(staticParams),
|
||||||
});
|
search: searchText.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!props.redirect) return;
|
if (!props.redirect) return;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { buildFilter } from 'filters/filterPanel';
|
||||||
|
|
||||||
const arrayDataStore = useArrayDataStore();
|
const arrayDataStore = useArrayDataStore();
|
||||||
|
|
||||||
export function useArrayData(key, userOptions) {
|
export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
|
||||||
if (!key) throw new Error('ArrayData: A key is required to use this composable');
|
if (!key) throw new Error('ArrayData: A key is required to use this composable');
|
||||||
|
|
||||||
if (!arrayDataStore.get(key)) arrayDataStore.set(key);
|
if (!arrayDataStore.get(key)) arrayDataStore.set(key);
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import toCurrency from './toCurrency';
|
||||||
|
|
||||||
|
export default function (value) {
|
||||||
|
if (value == null || value === '') return () => '-';
|
||||||
|
return () => toCurrency(value);
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import toLowerCamel from './toLowerCamel';
|
||||||
import dashIfEmpty from './dashIfEmpty';
|
import dashIfEmpty from './dashIfEmpty';
|
||||||
import dateRange from './dateRange';
|
import dateRange from './dateRange';
|
||||||
import toHour from './toHour';
|
import toHour from './toHour';
|
||||||
|
import dashOrCurrency from './dashOrCurrency';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
toLowerCase,
|
toLowerCase,
|
||||||
|
@ -17,6 +18,7 @@ export {
|
||||||
toDate,
|
toDate,
|
||||||
toHour,
|
toHour,
|
||||||
toDateString,
|
toDateString,
|
||||||
|
dashOrCurrency,
|
||||||
toDateHourMin,
|
toDateHourMin,
|
||||||
toDateHourMinSec,
|
toDateHourMinSec,
|
||||||
toRelativeDate,
|
toRelativeDate,
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import { toDate } from 'filters/index';
|
import { toDate } from 'filters/index';
|
||||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
|
@ -14,7 +13,6 @@ import ClaimSummary from './Card/ClaimSummary.vue';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
|
|
|
@ -19,7 +19,7 @@ const { t } = useI18n();
|
||||||
const dms = ref({});
|
const dms = ref({});
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const editDownloadDisabled = ref(false);
|
const editDownloadDisabled = ref(false);
|
||||||
const invoiceIn = computed(() => useArrayData(route.meta.moduleName).store.data);
|
const invoiceIn = computed(() => useArrayData().store.data);
|
||||||
const userConfig = ref(null);
|
const userConfig = ref(null);
|
||||||
const invoiceId = computed(() => +route.params.id);
|
const invoiceId = computed(() => +route.params.id);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { toCurrency } from 'src/filters';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const arrayData = useArrayData(route.meta.moduleName);
|
const arrayData = useArrayData();
|
||||||
const invoiceIn = computed(() => arrayData.store.data);
|
const invoiceIn = computed(() => arrayData.store.data);
|
||||||
|
|
||||||
const rowsSelected = ref([]);
|
const rowsSelected = ref([]);
|
||||||
|
|
|
@ -11,9 +11,7 @@ import { useArrayData } from 'src/composables/useArrayData';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const currency = computed(
|
const currency = computed(() => useArrayData().store.data?.currency?.code);
|
||||||
() => useArrayData(route.meta.moduleName).store.data?.currency?.code
|
|
||||||
);
|
|
||||||
const invoceInIntrastat = ref([]);
|
const invoceInIntrastat = ref([]);
|
||||||
const rowsSelected = ref([]);
|
const rowsSelected = ref([]);
|
||||||
const countries = ref([]);
|
const countries = ref([]);
|
||||||
|
|
|
@ -16,7 +16,7 @@ const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const entityId = computed(() => props.id || +route.params.id);
|
const entityId = computed(() => props.id || +route.params.id);
|
||||||
const invoiceIn = computed(() => useArrayData(route.meta.moduleName).store.data);
|
const invoiceIn = computed(() => useArrayData().store.data);
|
||||||
const currency = computed(() => invoiceIn.value?.currency?.code);
|
const currency = computed(() => invoiceIn.value?.currency?.code);
|
||||||
const invoiceInUrl = ref();
|
const invoiceInUrl = ref();
|
||||||
const amountsNotMatch = ref(null);
|
const amountsNotMatch = ref(null);
|
||||||
|
|
|
@ -11,13 +11,12 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import CrudModel from 'src/components/CrudModel.vue';
|
import CrudModel from 'src/components/CrudModel.vue';
|
||||||
import VnCurrency from 'src/components/common/VnCurrency.vue';
|
import VnCurrency from 'src/components/common/VnCurrency.vue';
|
||||||
|
|
||||||
const router = useRoute();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
|
||||||
const arrayData = useArrayData(router.meta.moduleName);
|
const arrayData = useArrayData();
|
||||||
const invoiceIn = computed(() => arrayData.store.data);
|
const invoiceIn = computed(() => arrayData.store.data);
|
||||||
const invoiceId = +router.params.id;
|
const invoiceId = +useRoute().params.id;
|
||||||
const currency = computed(() => invoiceIn.value?.currency?.code);
|
const currency = computed(() => invoiceIn.value?.currency?.code);
|
||||||
const expenses = ref([]);
|
const expenses = ref([]);
|
||||||
const sageTaxTypes = ref([]);
|
const sageTaxTypes = ref([]);
|
||||||
|
|
|
@ -10,7 +10,7 @@ const { t } = useI18n();
|
||||||
|
|
||||||
defineExpose({ checkToBook });
|
defineExpose({ checkToBook });
|
||||||
|
|
||||||
const { store } = useArrayData(useRoute().meta.moduleName);
|
const { store } = useArrayData();
|
||||||
|
|
||||||
async function checkToBook(id) {
|
async function checkToBook(id) {
|
||||||
let directBooking = true;
|
let directBooking = true;
|
||||||
|
|
|
@ -11,13 +11,10 @@ import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import VnInputTime from 'components/common/VnInputTime.vue';
|
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||||
import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const stateStore = useStateStore();
|
|
||||||
const shelvingId = ref(route.params?.id || null);
|
const shelvingId = ref(route.params?.id || null);
|
||||||
const isNew = Boolean(!shelvingId.value);
|
const isNew = Boolean(!shelvingId.value);
|
||||||
const defaultInitialData = {
|
const defaultInitialData = {
|
||||||
|
|
|
@ -15,14 +15,11 @@ import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import { openBuscaman } from 'src/utils/buscaman';
|
import { openBuscaman } from 'src/utils/buscaman';
|
||||||
import SendSmsDialog from 'components/common/SendSmsDialog.vue';
|
import SendSmsDialog from 'components/common/SendSmsDialog.vue';
|
||||||
import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const selectedRows = ref([]);
|
const selectedRows = ref([]);
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
|
|
|
@ -136,13 +136,6 @@ const getEventByTimestamp = ({ year, month, day }) => {
|
||||||
return props.events[stamp] || null;
|
return props.events[stamp] || null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isFestive = (timestamp) => {
|
|
||||||
const event = getEventByTimestamp(timestamp);
|
|
||||||
if (!event) return false;
|
|
||||||
|
|
||||||
const { isFestive } = event;
|
|
||||||
return isFestive;
|
|
||||||
};
|
|
||||||
const getEventAttrs = (timestamp) => {
|
const getEventAttrs = (timestamp) => {
|
||||||
const event = getEventByTimestamp(timestamp);
|
const event = getEventByTimestamp(timestamp);
|
||||||
if (!event) return {};
|
if (!event) return {};
|
||||||
|
|
|
@ -14,10 +14,12 @@ const customRouteRedirectName = computed(() => {
|
||||||
if (routeName.value === 'ZoneLocations') return null;
|
if (routeName.value === 'ZoneLocations') return null;
|
||||||
return routeName.value;
|
return routeName.value;
|
||||||
});
|
});
|
||||||
|
const searchbarMakeFetch = computed(() => routeName.value !== 'ZoneEvents');
|
||||||
const searchBarDataKeys = {
|
const searchBarDataKeys = {
|
||||||
ZoneWarehouses: 'ZoneWarehouses',
|
ZoneWarehouses: 'ZoneWarehouses',
|
||||||
ZoneSummary: 'ZoneSummary',
|
ZoneSummary: 'ZoneSummary',
|
||||||
ZoneLocations: 'ZoneLocations',
|
ZoneLocations: 'ZoneLocations',
|
||||||
|
ZoneEvents: 'ZoneEvents',
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -27,6 +29,7 @@ const searchBarDataKeys = {
|
||||||
:search-data-key="searchBarDataKeys[routeName]"
|
:search-data-key="searchBarDataKeys[routeName]"
|
||||||
:search-custom-route-redirect="customRouteRedirectName"
|
:search-custom-route-redirect="customRouteRedirectName"
|
||||||
:search-redirect="!!customRouteRedirectName"
|
:search-redirect="!!customRouteRedirectName"
|
||||||
|
:search-make-fetch="searchbarMakeFetch"
|
||||||
:searchbar-label="t('list.searchZone')"
|
:searchbar-label="t('list.searchZone')"
|
||||||
:searchbar-info="t('list.searchInfo')"
|
:searchbar-info="t('list.searchInfo')"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import FormPopup from 'components/FormPopup.vue';
|
||||||
|
import ZoneLocationsTree from './ZoneLocationsTree.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
date: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
isNewMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
eventType: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
geoIds: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['onSubmit', 'closeForm']);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
|
|
||||||
|
const isNew = computed(() => props.isNewMode);
|
||||||
|
const dated = ref(null);
|
||||||
|
const tickedNodes = ref();
|
||||||
|
|
||||||
|
const _excludeType = ref('all');
|
||||||
|
const excludeType = computed({
|
||||||
|
get: () => _excludeType.value,
|
||||||
|
set: (val) => {
|
||||||
|
_excludeType.value = val;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const arrayData = useArrayData('ZoneEvents');
|
||||||
|
|
||||||
|
const exclusionGeoCreate = async () => {
|
||||||
|
try {
|
||||||
|
if (isNew.value) {
|
||||||
|
const params = {
|
||||||
|
zoneFk: parseInt(route.params.id),
|
||||||
|
date: dated.value,
|
||||||
|
geoIds: tickedNodes.value,
|
||||||
|
};
|
||||||
|
await axios.post('Zones/exclusionGeo', params);
|
||||||
|
} else {
|
||||||
|
const params = {
|
||||||
|
zoneExclusionFk: props.event?.zoneExclusionFk,
|
||||||
|
geoIds: tickedNodes.value,
|
||||||
|
};
|
||||||
|
await axios.post('Zones/updateExclusionGeo', params);
|
||||||
|
}
|
||||||
|
await refetchEvents();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error creating exclusion geo: ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const exclusionCreate = async () => {
|
||||||
|
try {
|
||||||
|
if (isNew.value)
|
||||||
|
await axios.post(`Zones/${route.params.id}/exclusions`, [
|
||||||
|
{ dated: dated.value },
|
||||||
|
]);
|
||||||
|
else
|
||||||
|
await axios.put(`Zones/${route.params.id}/exclusions/${props.event?.id}`, {
|
||||||
|
dated: dated.value,
|
||||||
|
});
|
||||||
|
|
||||||
|
await refetchEvents();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error creating exclusion: ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
if (excludeType.value === 'all') exclusionCreate();
|
||||||
|
else exclusionGeoCreate();
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteEvent = async () => {
|
||||||
|
try {
|
||||||
|
if (!props.event) return;
|
||||||
|
const exclusionId = props.event?.zoneExclusionFk || props.event?.id;
|
||||||
|
await axios.delete(`Zones/${route.params.id}/exclusions/${exclusionId}`);
|
||||||
|
await refetchEvents();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error deleting event: ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeForm = () => emit('closeForm');
|
||||||
|
|
||||||
|
const refetchEvents = async () => {
|
||||||
|
await arrayData.refresh({ append: false });
|
||||||
|
closeForm();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.event) {
|
||||||
|
dated.value = props.event?.dated;
|
||||||
|
excludeType.value =
|
||||||
|
props.eventType === 'geoExclusion' ? 'specificLocations' : 'all';
|
||||||
|
tickedNodes.value = props.geoIds || [];
|
||||||
|
} else if (props.date) dated.value = props.date;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormPopup
|
||||||
|
:title="
|
||||||
|
isNew
|
||||||
|
? t('eventsExclusionForm.addExclusion')
|
||||||
|
: t('eventsExclusionForm.editExclusion')
|
||||||
|
"
|
||||||
|
@on-submit="onSubmit()"
|
||||||
|
:default-cancel-button="false"
|
||||||
|
:default-submit-button="false"
|
||||||
|
>
|
||||||
|
<template #form-inputs>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-lg">
|
||||||
|
<VnInputDate :label="t('eventsInclusionForm.day')" v-model="dated" />
|
||||||
|
</VnRow>
|
||||||
|
<div class="column q-gutter-y-sm q-mb-md">
|
||||||
|
<QRadio
|
||||||
|
v-model="excludeType"
|
||||||
|
dense
|
||||||
|
val="all"
|
||||||
|
:label="t('eventsExclusionForm.all')"
|
||||||
|
/>
|
||||||
|
<QRadio
|
||||||
|
v-model="excludeType"
|
||||||
|
dense
|
||||||
|
val="specificLocations"
|
||||||
|
:label="t('eventsExclusionForm.specificLocations')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="excludeType === 'specificLocations'"
|
||||||
|
style="min-height: 60vh; overflow-y: scroll"
|
||||||
|
>
|
||||||
|
<ZoneLocationsTree
|
||||||
|
:root-label="t('eventsExclusionForm.rootTreeLabel')"
|
||||||
|
v-model:tickedNodes="tickedNodes"
|
||||||
|
show-search-bar
|
||||||
|
show-default-checkboxes
|
||||||
|
>
|
||||||
|
<template #content="{ node }">
|
||||||
|
<span>{{ node.name }}</span>
|
||||||
|
</template>
|
||||||
|
</ZoneLocationsTree>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #custom-buttons>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
class="q-mr-sm"
|
||||||
|
v-close-popup
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
v-if="
|
||||||
|
!isNew && (eventType === 'exclusion' || eventType === 'geoExclusion')
|
||||||
|
"
|
||||||
|
:label="t('globals.delete')"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
class="q-mr-sm"
|
||||||
|
@click="
|
||||||
|
openConfirmationModal(
|
||||||
|
t('eventsPanel.deleteTitle'),
|
||||||
|
t('eventsPanel.deleteSubtitle'),
|
||||||
|
() => deleteEvent()
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:label="isNew ? t('globals.add') : t('globals.save')"
|
||||||
|
type="submit"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</FormPopup>
|
||||||
|
</template>
|
|
@ -0,0 +1,240 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import FormPopup from 'components/FormPopup.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
import VnWeekdayPicker from 'src/components/common/VnWeekdayPicker.vue';
|
||||||
|
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
||||||
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
date: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
event: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
isNewMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
eventType: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['onSubmit', 'closeForm']);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const weekdayStore = useWeekdayStore();
|
||||||
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
|
|
||||||
|
const isNew = computed(() => props.isNewMode);
|
||||||
|
const eventInclusionFormData = ref({ wdays: [] });
|
||||||
|
|
||||||
|
const _inclusionType = ref('indefinitely');
|
||||||
|
const inclusionType = computed({
|
||||||
|
get: () => _inclusionType.value,
|
||||||
|
set: (val) => {
|
||||||
|
_inclusionType.value = val;
|
||||||
|
eventInclusionFormData.value.type = val;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const arrayData = useArrayData('ZoneEvents');
|
||||||
|
|
||||||
|
const createEvent = async () => {
|
||||||
|
try {
|
||||||
|
eventInclusionFormData.value.weekDays = weekdayStore.toSet(
|
||||||
|
eventInclusionFormData.value.wdays
|
||||||
|
);
|
||||||
|
|
||||||
|
if (inclusionType.value == 'day') eventInclusionFormData.value.weekDays = '';
|
||||||
|
else eventInclusionFormData.value.dated = null;
|
||||||
|
|
||||||
|
if (inclusionType.value != 'range') {
|
||||||
|
eventInclusionFormData.value.started = null;
|
||||||
|
eventInclusionFormData.value.ended = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNew.value)
|
||||||
|
await axios.post(
|
||||||
|
`Zones/${route.params.id}/events`,
|
||||||
|
eventInclusionFormData.value
|
||||||
|
);
|
||||||
|
else
|
||||||
|
await axios.put(
|
||||||
|
`Zones/${route.params.id}/events/${props.event?.id}`,
|
||||||
|
eventInclusionFormData.value
|
||||||
|
);
|
||||||
|
|
||||||
|
await refetchEvents();
|
||||||
|
emit('onSubmit');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error creating event', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteEvent = async () => {
|
||||||
|
try {
|
||||||
|
if (!props.event) return;
|
||||||
|
await axios.delete(`Zones/${route.params.id}/events/${props.event?.id}`);
|
||||||
|
await refetchEvents();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error deleting event: ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeForm = () => {
|
||||||
|
emit('closeForm');
|
||||||
|
};
|
||||||
|
|
||||||
|
const refetchEvents = async () => {
|
||||||
|
await arrayData.refresh({ append: false });
|
||||||
|
closeForm();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.event) {
|
||||||
|
eventInclusionFormData.value = { ...props.event };
|
||||||
|
inclusionType.value = props.event?.type || 'day';
|
||||||
|
} else if (props.date) {
|
||||||
|
eventInclusionFormData.value.dated = props.date;
|
||||||
|
inclusionType.value = 'day';
|
||||||
|
} else inclusionType.value = 'indefinitely';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormPopup
|
||||||
|
:title="
|
||||||
|
isNew ? t('eventsInclusionForm.addEvent') : t('eventsInclusionForm.editEvent')
|
||||||
|
"
|
||||||
|
@on-submit="createEvent()"
|
||||||
|
:default-cancel-button="false"
|
||||||
|
:default-submit-button="false"
|
||||||
|
>
|
||||||
|
<template #form-inputs>
|
||||||
|
<div class="column q-gutter-y-sm q-mb-md">
|
||||||
|
<QRadio
|
||||||
|
v-model="inclusionType"
|
||||||
|
dense
|
||||||
|
val="day"
|
||||||
|
:label="t('eventsInclusionForm.oneDay')"
|
||||||
|
/>
|
||||||
|
<QRadio
|
||||||
|
v-model="inclusionType"
|
||||||
|
dense
|
||||||
|
val="indefinitely"
|
||||||
|
:label="t('eventsInclusionForm.indefinitely')"
|
||||||
|
/>
|
||||||
|
<QRadio
|
||||||
|
v-model="inclusionType"
|
||||||
|
dense
|
||||||
|
val="range"
|
||||||
|
:label="t('eventsInclusionForm.rangeOfDates')"
|
||||||
|
class="q-mb-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<div class="col flex justify-center">
|
||||||
|
<VnInputDate
|
||||||
|
v-if="inclusionType === 'day'"
|
||||||
|
:label="t('eventsInclusionForm.day')"
|
||||||
|
v-model="eventInclusionFormData.dated"
|
||||||
|
class="full-width"
|
||||||
|
/>
|
||||||
|
<VnWeekdayPicker
|
||||||
|
v-else
|
||||||
|
v-model:wdays="eventInclusionFormData.wdays"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow v-if="inclusionType === 'range'" class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInputDate
|
||||||
|
:label="t('eventsInclusionForm.from')"
|
||||||
|
v-model="eventInclusionFormData.started"
|
||||||
|
/>
|
||||||
|
<VnInputDate
|
||||||
|
:label="t('eventsInclusionForm.to')"
|
||||||
|
v-model="eventInclusionFormData.ended"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInputTime
|
||||||
|
v-model="eventInclusionFormData.hour"
|
||||||
|
:label="t('eventsInclusionForm.closing')"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
v-model="eventInclusionFormData.travelingDays"
|
||||||
|
:label="t('eventsInclusionForm.travelingDays')"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInput
|
||||||
|
v-model="eventInclusionFormData.price"
|
||||||
|
:label="t('eventsInclusionForm.price')"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
<VnInput
|
||||||
|
v-model="eventInclusionFormData.bonus"
|
||||||
|
:label="t('eventsInclusionForm.bonus')"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInput
|
||||||
|
v-model="eventInclusionFormData.m3Max"
|
||||||
|
:label="t('eventsInclusionForm.m3Max')"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
<template #custom-buttons>
|
||||||
|
<QBtn
|
||||||
|
:label="t('globals.cancel')"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
class="q-mr-sm"
|
||||||
|
v-close-popup
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
v-if="!isNew && eventType === 'event'"
|
||||||
|
:label="t('globals.delete')"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
class="q-mr-sm"
|
||||||
|
@click="
|
||||||
|
openConfirmationModal(
|
||||||
|
t('eventsPanel.deleteTitle'),
|
||||||
|
t('eventsPanel.deleteSubtitle'),
|
||||||
|
() => deleteEvent()
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<QBtn
|
||||||
|
:label="isNew ? t('globals.save') : t('globals.add')"
|
||||||
|
type="submit"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</FormPopup>
|
||||||
|
</template>
|
|
@ -0,0 +1,111 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, onUnmounted } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import ZoneEventsPanel from './ZoneEventsPanel.vue';
|
||||||
|
import ZoneCalendarGrid from '../ZoneCalendarGrid.vue';
|
||||||
|
import ZoneEventInclusionForm from './ZoneEventInclusionForm.vue';
|
||||||
|
import ZoneEventExclusionForm from './ZoneEventExclusionForm.vue';
|
||||||
|
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
|
||||||
|
const firstDay = ref(null);
|
||||||
|
const lastDay = ref(null);
|
||||||
|
|
||||||
|
const events = ref([]);
|
||||||
|
const formModeName = ref('include');
|
||||||
|
const showZoneEventForm = ref(false);
|
||||||
|
const zoneEventsFormProps = reactive({
|
||||||
|
isNewMode: true,
|
||||||
|
date: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const openForm = (data) => {
|
||||||
|
const { date = null, isNewMode, event, eventType, geoIds = [] } = data;
|
||||||
|
zoneEventsFormProps.date = date;
|
||||||
|
zoneEventsFormProps.isNewMode = isNewMode;
|
||||||
|
zoneEventsFormProps.event = event;
|
||||||
|
zoneEventsFormProps.eventType = eventType;
|
||||||
|
if (geoIds.length) zoneEventsFormProps.geoIds = geoIds;
|
||||||
|
|
||||||
|
showZoneEventForm.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onZoneEventFormClose = () => {
|
||||||
|
showZoneEventForm.value = false;
|
||||||
|
zoneEventsFormProps.value = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<template v-if="stateStore.isHeaderMounted()">
|
||||||
|
<Teleport to="#actions-append">
|
||||||
|
<div class="row q-gutter-x-sm">
|
||||||
|
<QBtn
|
||||||
|
flat
|
||||||
|
@click="stateStore.toggleRightDrawer()"
|
||||||
|
round
|
||||||
|
dense
|
||||||
|
icon="menu"
|
||||||
|
>
|
||||||
|
<QTooltip bottom anchor="bottom right">
|
||||||
|
{{ t('globals.collapseMenu') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||||
|
<QScrollArea class="fit text-grey-8">
|
||||||
|
<ZoneEventsPanel
|
||||||
|
:first-day="firstDay"
|
||||||
|
:last-day="lastDay"
|
||||||
|
:events="events"
|
||||||
|
v-model:formModeName="formModeName"
|
||||||
|
@open-zone-form="openForm"
|
||||||
|
/>
|
||||||
|
</QScrollArea>
|
||||||
|
</QDrawer>
|
||||||
|
<QPage class="q-pa-md flex justify-center">
|
||||||
|
<ZoneCalendarGrid
|
||||||
|
v-model:events="events"
|
||||||
|
v-model:firstDay="firstDay"
|
||||||
|
v-model:lastDay="lastDay"
|
||||||
|
data-key="ZoneEvents"
|
||||||
|
@on-date-selected="openForm"
|
||||||
|
/>
|
||||||
|
<QDialog v-model="showZoneEventForm" @hide="onZoneEventFormClose()">
|
||||||
|
<ZoneEventInclusionForm
|
||||||
|
v-if="formModeName === 'include'"
|
||||||
|
v-bind="zoneEventsFormProps"
|
||||||
|
@close-form="onZoneEventFormClose()"
|
||||||
|
/>
|
||||||
|
<ZoneEventExclusionForm
|
||||||
|
v-else
|
||||||
|
v-bind="zoneEventsFormProps"
|
||||||
|
@close-form="onZoneEventFormClose()"
|
||||||
|
/>
|
||||||
|
</QDialog>
|
||||||
|
<QPageSticky :offset="[20, 20]">
|
||||||
|
<QBtn
|
||||||
|
@click="
|
||||||
|
openForm({
|
||||||
|
isNewMode: true,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
color="primary"
|
||||||
|
fab
|
||||||
|
icon="add"
|
||||||
|
/>
|
||||||
|
<QTooltip class="text-no-wrap">
|
||||||
|
{{ t('eventsInclusionForm.addEvent') }}
|
||||||
|
</QTooltip>
|
||||||
|
</QPageSticky>
|
||||||
|
</QPage>
|
||||||
|
</template>
|
|
@ -0,0 +1,221 @@
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, watch, computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { toDateFormat, toTimeFormat } from 'src/filters/date.js';
|
||||||
|
import { dashOrCurrency, toCurrency } from 'filters/index';
|
||||||
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
||||||
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
firstDay: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
lastDay: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
formModeName: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
default: 'include',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['openZoneForm', 'update:formModeName']);
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const weekdayStore = useWeekdayStore();
|
||||||
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
|
|
||||||
|
const formName = computed({
|
||||||
|
get: () => props.formModeName,
|
||||||
|
set: (value) => emit('update:formModeName', value),
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = computed(() => ({
|
||||||
|
zoneFk: route.params.id,
|
||||||
|
started: props.firstDay,
|
||||||
|
ended: props.lastDay,
|
||||||
|
}));
|
||||||
|
const arrayData = useArrayData('ZoneEvents', {
|
||||||
|
params: params,
|
||||||
|
url: `Zones/getEventsFiltered`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
if (!params.value.zoneFk || !params.value.started || !params.value.ended) return;
|
||||||
|
|
||||||
|
await arrayData.applyFilter({
|
||||||
|
params: params.value,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching events: ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
params,
|
||||||
|
async () => {
|
||||||
|
await fetchData();
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const formatWdays = (event) => {
|
||||||
|
if (!event.weekDays) return;
|
||||||
|
|
||||||
|
let abrWdays = event.weekDays
|
||||||
|
.split(',')
|
||||||
|
.map((wday) => weekdayStore.getLocalesMap[wday].localeAbr);
|
||||||
|
|
||||||
|
return abrWdays.length < 7 ? abrWdays.join(', ') : t('eventsPanel.everyday');
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteEvent = async (id) => {
|
||||||
|
try {
|
||||||
|
if (!id) return;
|
||||||
|
await axios.delete(`Zones/${route.params.id}/events/${id}`);
|
||||||
|
await fetchData();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error deleting event: ', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const openInclusionForm = (event) => {
|
||||||
|
formName.value = 'include';
|
||||||
|
emit('openZoneForm', {
|
||||||
|
date: event.dated,
|
||||||
|
event,
|
||||||
|
isNewMode: false,
|
||||||
|
eventType: 'event',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
weekdayStore.initStore();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QForm @submit="onSubmit()">
|
||||||
|
<div class="column q-pa-md q-gutter-y-sm">
|
||||||
|
<span class="color-vn-label text-subtitle1">{{
|
||||||
|
t('eventsPanel.editMode')
|
||||||
|
}}</span>
|
||||||
|
<QRadio
|
||||||
|
v-model="formName"
|
||||||
|
dense
|
||||||
|
val="include"
|
||||||
|
:label="t('eventsPanel.include')"
|
||||||
|
/>
|
||||||
|
<QRadio
|
||||||
|
v-model="formName"
|
||||||
|
dense
|
||||||
|
val="exclude"
|
||||||
|
:label="t('eventsPanel.exclude')"
|
||||||
|
class="q-mb-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="color-vn-label text-subtitle1 q-px-md">{{
|
||||||
|
t('eventsPanel.events')
|
||||||
|
}}</span>
|
||||||
|
<QList>
|
||||||
|
<QItem v-for="(event, index) in events" :key="index" class="event-card">
|
||||||
|
<QItemSection left @click="openInclusionForm(event)">
|
||||||
|
<div v-if="event.type == 'day'" class="q-mb-xs">
|
||||||
|
{{ toDateFormat(event.dated) }}
|
||||||
|
</div>
|
||||||
|
<div v-if="event.type != 'day'" class="q-mb-xs">
|
||||||
|
<span v-if="event.weekDays">
|
||||||
|
{{ formatWdays(event) }}
|
||||||
|
</span>
|
||||||
|
<span v-if="event.type == 'range'">
|
||||||
|
({{ toDateFormat(event.started) }} -
|
||||||
|
{{ toDateFormat(event.ended) }})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="color-vn-label">
|
||||||
|
{{ t('eventsPanel.closing') }}:
|
||||||
|
<span class="color-vn-text q-ml-xs">
|
||||||
|
{{ dashIfEmpty(toTimeFormat(event.hour)) }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="color-vn-label">
|
||||||
|
{{ t('eventsPanel.travelingDays') }}:
|
||||||
|
<span class="color-vn-text">
|
||||||
|
{{ dashIfEmpty(event.travelingDays) }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="color-vn-label">
|
||||||
|
{{ t('eventsPanel.price') }}:
|
||||||
|
<span class="color-vn-text">
|
||||||
|
{{ dashOrCurrency(event.price)() }}</span
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<span class="color-vn-label">
|
||||||
|
{{ t('eventsPanel.bonus') }}:
|
||||||
|
<span class="color-vn-text">
|
||||||
|
{{ dashOrCurrency(event.bonus)() }}</span
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<span class="color-vn-label">
|
||||||
|
{{ t('eventsPanel.m3Max') }}:
|
||||||
|
<span class="color-vn-text"> {{ dashIfEmpty(event.m3Max) }}</span>
|
||||||
|
</span>
|
||||||
|
</QItemSection>
|
||||||
|
<QItemSection side @click="openInclusionForm(event)">
|
||||||
|
<QBtn
|
||||||
|
icon="delete"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
size="md"
|
||||||
|
color="primary"
|
||||||
|
@click.stop="
|
||||||
|
openConfirmationModal(
|
||||||
|
t('eventsPanel.deleteTitle'),
|
||||||
|
t('eventsPanel.deleteSubtitle'),
|
||||||
|
() => deleteEvent(event.id)
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('eventsPanel.delete') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<span
|
||||||
|
v-if="!events.length"
|
||||||
|
class="flex justify-center text-h5 color-vn-label"
|
||||||
|
>
|
||||||
|
{{ t('globals.noResults') }}
|
||||||
|
</span>
|
||||||
|
</QList>
|
||||||
|
</QForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.event-card {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: $border-thin-light;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--vn-accent-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -24,7 +24,8 @@ const onSelected = async (val, node) => {
|
||||||
<QPage class="column items-center q-pa-md">
|
<QPage class="column items-center q-pa-md">
|
||||||
<QCard class="full-width q-pa-md" style="max-width: 800px">
|
<QCard class="full-width q-pa-md" style="max-width: 800px">
|
||||||
<ZoneLocationsTree :root-label="t('zoneLocations.locations')">
|
<ZoneLocationsTree :root-label="t('zoneLocations.locations')">
|
||||||
<template #checkbox="{ node }">
|
<template #content="{ node }">
|
||||||
|
<span v-if="!node.id">{{ node.name }}</span>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
v-if="node.id"
|
v-if="node.id"
|
||||||
v-model="node.selected"
|
v-model="node.selected"
|
||||||
|
|
|
@ -1,12 +1,34 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, computed, watch } from 'vue';
|
import { onMounted, ref, computed, watch, onUnmounted } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
import { onUnmounted } from 'vue';
|
|
||||||
|
const props = defineProps({
|
||||||
|
rootLabel: {
|
||||||
|
type: String,
|
||||||
|
default: 'Locations',
|
||||||
|
},
|
||||||
|
tickedNodes: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
showSearchBar: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
showDefaultCheckboxes: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:tickedNodes']);
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -22,9 +44,21 @@ const { store } = arrayData;
|
||||||
const storeData = computed(() => store.data);
|
const storeData = computed(() => store.data);
|
||||||
|
|
||||||
const nodes = ref([
|
const nodes = ref([
|
||||||
{ id: null, name: t('zoneLocations.locations'), sons: true, childs: [{}] },
|
{
|
||||||
|
id: null,
|
||||||
|
name: props.rootLabel,
|
||||||
|
sons: true,
|
||||||
|
tickable: false,
|
||||||
|
noTick: true,
|
||||||
|
children: [{}],
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const _tickedNodes = computed({
|
||||||
|
get: () => props.tickedNodes,
|
||||||
|
set: (value) => emit('update:tickedNodes', value),
|
||||||
|
});
|
||||||
|
|
||||||
const previousExpandedNodes = ref(new Set());
|
const previousExpandedNodes = ref(new Set());
|
||||||
|
|
||||||
const onNodeExpanded = async (nodeKeysArray) => {
|
const onNodeExpanded = async (nodeKeysArray) => {
|
||||||
|
@ -107,17 +141,19 @@ watch(storeData, async (val) => {
|
||||||
formatNodeSelected(n);
|
formatNodeSelected(n);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
for (let n of state.get('Tree')) {
|
for (let n of state.get('Tree')) await fetchNodeLeaves(n);
|
||||||
await fetchNodeLeaves(n);
|
|
||||||
}
|
|
||||||
expanded.value = [null, ...fetchedNodeKeys];
|
expanded.value = [null, ...fetchedNodeKeys];
|
||||||
}
|
}
|
||||||
previousExpandedNodes.value = new Set(expanded.value);
|
previousExpandedNodes.value = new Set(expanded.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const reFetch = async () => {
|
||||||
|
await arrayData.fetch({ append: false });
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (store.userParams?.search) {
|
if (store.userParams?.search && !props.showSearchBar) {
|
||||||
await arrayData.fetch({ append: false });
|
await reFetch();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const stateTree = state.get('Tree');
|
const stateTree = state.get('Tree');
|
||||||
|
@ -140,6 +176,7 @@ onMounted(async () => {
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
expanded.value.unshift(null);
|
||||||
previousExpandedNodes.value = new Set(expanded.value);
|
previousExpandedNodes.value = new Set(expanded.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -149,14 +186,26 @@ onUnmounted(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<VnInput
|
||||||
|
v-if="showSearchBar"
|
||||||
|
v-model="store.userParams.search"
|
||||||
|
:placeholder="t('globals.search')"
|
||||||
|
@keydown.enter.prevent="reFetch()"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<QIcon class="cursor-pointer" name="search" />
|
||||||
|
</template>
|
||||||
|
</VnInput>
|
||||||
<QTree
|
<QTree
|
||||||
ref="treeRef"
|
ref="treeRef"
|
||||||
:nodes="nodes"
|
:nodes="nodes"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
label-key="name"
|
label-key="name"
|
||||||
children-key="childs"
|
children-key="childs"
|
||||||
|
:tick-strategy="props.showDefaultCheckboxes ? 'strict' : 'none'"
|
||||||
v-model:expanded="expanded"
|
v-model:expanded="expanded"
|
||||||
@update:expanded="onNodeExpanded($event)"
|
@update:expanded="onNodeExpanded($event)"
|
||||||
|
v-model:ticked="_tickedNodes"
|
||||||
:default-expand-all="true"
|
:default-expand-all="true"
|
||||||
>
|
>
|
||||||
<template #default-header="{ node }">
|
<template #default-header="{ node }">
|
||||||
|
@ -164,8 +213,7 @@ onUnmounted(() => {
|
||||||
:id="node.id"
|
:id="node.id"
|
||||||
class="qtr row justify-between full-width q-pr-md cursor-pointer"
|
class="qtr row justify-between full-width q-pr-md cursor-pointer"
|
||||||
>
|
>
|
||||||
<span v-if="!node.id">{{ node.name }}</span>
|
<slot name="content" :node="node" />
|
||||||
<slot name="checkbox" :node="node" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</QTree>
|
</QTree>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import ZoneClosingTable from './ZoneClosingTable.vue';
|
import ZoneClosingTable from './ZoneClosingTable.vue';
|
||||||
import QCalendarMonthWrapper from 'src/components/ui/QCalendarMonthWrapper.vue';
|
import QCalendarMonthWrapper from 'src/components/ui/QCalendarMonthWrapper.vue';
|
||||||
|
@ -38,7 +39,10 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['onDateSelected']);
|
||||||
|
|
||||||
const { locale } = useI18n();
|
const { locale } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
const calendarRef = ref(null);
|
const calendarRef = ref(null);
|
||||||
const weekdayStore = useWeekdayStore();
|
const weekdayStore = useWeekdayStore();
|
||||||
|
@ -52,7 +56,11 @@ const todayTimestamp = computed(() => {
|
||||||
});
|
});
|
||||||
const _monthDate = computed(() => date.formatDate(props.monthDate, 'YYYY-MM-DD'));
|
const _monthDate = computed(() => date.formatDate(props.monthDate, 'YYYY-MM-DD'));
|
||||||
|
|
||||||
|
const isZoneDeliveryView = computed(() => route.name === 'ZoneDeliveryDays');
|
||||||
|
|
||||||
const onEventSelection = async ({ year, month, day }) => {
|
const onEventSelection = async ({ year, month, day }) => {
|
||||||
|
if (!isZoneDeliveryView.value) return;
|
||||||
|
|
||||||
const date = new Date(year, month - 1, day);
|
const date = new Date(year, month - 1, day);
|
||||||
const stamp = date.getTime();
|
const stamp = date.getTime();
|
||||||
const events = props.daysMap[stamp];
|
const events = props.daysMap[stamp];
|
||||||
|
@ -81,6 +89,13 @@ const getEventByTimestamp = ({ year, month, day }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getEventType = ({ year, month, day }) => {
|
||||||
|
const stamp = new Date(year, month - 1, day).getTime();
|
||||||
|
if (props.exclusions[stamp]) return 'exclusion';
|
||||||
|
if (props.geoExclusions[stamp]) return 'geoExclusion';
|
||||||
|
return 'event';
|
||||||
|
};
|
||||||
|
|
||||||
const getEventAttrs = ({ year, month, day }) => {
|
const getEventAttrs = ({ year, month, day }) => {
|
||||||
const stamp = new Date(year, month - 1, day).getTime();
|
const stamp = new Date(year, month - 1, day).getTime();
|
||||||
|
|
||||||
|
@ -104,6 +119,28 @@ const isToday = (timestamp) => {
|
||||||
const calendarHeaderTitle = computed(() => {
|
const calendarHeaderTitle = computed(() => {
|
||||||
return `${weekdayStore.getLocaleMonths[props.month - 1].locale} ${props.year}`;
|
return `${weekdayStore.getLocaleMonths[props.month - 1].locale} ${props.year}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleDateClick = (timestamp) => {
|
||||||
|
if (isZoneDeliveryView.value) return;
|
||||||
|
|
||||||
|
const event = getEventByTimestamp(timestamp);
|
||||||
|
const { year, month, day } = timestamp;
|
||||||
|
const date = new Date(year, month - 1, day);
|
||||||
|
const stamp = date.getTime();
|
||||||
|
const eventType = getEventType(timestamp);
|
||||||
|
|
||||||
|
let geoIds = [];
|
||||||
|
if (eventType === 'geoExclusion')
|
||||||
|
geoIds = props.geoExclusions[stamp].map((geoExclusion) => geoExclusion.geoFk);
|
||||||
|
|
||||||
|
emit('onDateSelected', {
|
||||||
|
date,
|
||||||
|
isNewMode: !event,
|
||||||
|
event: event && event.length > 0 ? event[0] : null,
|
||||||
|
eventType,
|
||||||
|
geoIds,
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -128,6 +165,7 @@ const calendarHeaderTitle = computed(() => {
|
||||||
short-weekday-label
|
short-weekday-label
|
||||||
:locale="locale"
|
:locale="locale"
|
||||||
:now="today"
|
:now="today"
|
||||||
|
@click-date="handleDateClick($event.scope.timestamp)"
|
||||||
mini-mode
|
mini-mode
|
||||||
>
|
>
|
||||||
<template #day="{ scope: { timestamp } }">
|
<template #day="{ scope: { timestamp } }">
|
||||||
|
@ -135,7 +173,11 @@ const calendarHeaderTitle = computed(() => {
|
||||||
<QBtn
|
<QBtn
|
||||||
v-if="getEventByTimestamp(timestamp)"
|
v-if="getEventByTimestamp(timestamp)"
|
||||||
v-bind="{ ...getEventAttrs(timestamp) }"
|
v-bind="{ ...getEventAttrs(timestamp) }"
|
||||||
@click="onEventSelection(timestamp)"
|
@click="
|
||||||
|
isZoneDeliveryView
|
||||||
|
? onEventSelection(timestamp)
|
||||||
|
: handleDateClick(timestamp)
|
||||||
|
"
|
||||||
rounded
|
rounded
|
||||||
dense
|
dense
|
||||||
flat
|
flat
|
||||||
|
@ -144,7 +186,7 @@ const calendarHeaderTitle = computed(() => {
|
||||||
'--today': isToday(timestamp),
|
'--today': isToday(timestamp),
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<QPopupProxy>
|
<QPopupProxy v-if="isZoneDeliveryView">
|
||||||
<ZoneClosingTable
|
<ZoneClosingTable
|
||||||
v-if="zoneClosingData && zoneClosingData.length"
|
v-if="zoneClosingData && zoneClosingData.length"
|
||||||
:rows="zoneClosingData"
|
:rows="zoneClosingData"
|
|
@ -0,0 +1,250 @@
|
||||||
|
<script setup>
|
||||||
|
import { computed, onMounted, ref, watch, onUnmounted, nextTick } from 'vue';
|
||||||
|
|
||||||
|
import ZoneCalendar from './ZoneCalendar.vue';
|
||||||
|
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
dataKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'update:firstDay',
|
||||||
|
'update:lastDay',
|
||||||
|
'update:events',
|
||||||
|
'onDateSelected',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const weekdayStore = useWeekdayStore();
|
||||||
|
|
||||||
|
const nMonths = ref(4);
|
||||||
|
const _date = ref(Date.vnNew());
|
||||||
|
const _data = ref(null);
|
||||||
|
const firstDay = ref(null);
|
||||||
|
const lastDay = ref(null);
|
||||||
|
const months = ref([]);
|
||||||
|
const days = ref({});
|
||||||
|
const exclusions = ref({});
|
||||||
|
const geoExclusions = ref({});
|
||||||
|
const events = ref([]);
|
||||||
|
|
||||||
|
const arrayData = useArrayData(props.dataKey);
|
||||||
|
const { store } = arrayData;
|
||||||
|
|
||||||
|
const refreshEvents = () => {
|
||||||
|
days.value = {};
|
||||||
|
if (!data.value) return;
|
||||||
|
|
||||||
|
let day = new Date(firstDay.value.getTime());
|
||||||
|
|
||||||
|
while (day <= lastDay.value) {
|
||||||
|
let stamp = day.getTime();
|
||||||
|
let wday = day.getDay();
|
||||||
|
let dayEvents = [];
|
||||||
|
let _exclusions = exclusions.value[stamp] || [];
|
||||||
|
|
||||||
|
if (events.value) {
|
||||||
|
for (let event of events.value) {
|
||||||
|
let match;
|
||||||
|
switch (event.type) {
|
||||||
|
case 'day':
|
||||||
|
match = event.dated == stamp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
match =
|
||||||
|
event.wdays[wday] &&
|
||||||
|
(!event.started || stamp >= event.started) &&
|
||||||
|
(!event.ended || stamp <= event.ended);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (match && !_exclusions.find((e) => e.zoneFk == event.zoneFk)) {
|
||||||
|
dayEvents.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dayEvents.length) days.value[stamp] = dayEvents;
|
||||||
|
|
||||||
|
day.setDate(day.getDate() + 1);
|
||||||
|
}
|
||||||
|
emit('update:events', events.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const date = computed({
|
||||||
|
get: () => _date.value,
|
||||||
|
set: (value) => {
|
||||||
|
_date.value = value;
|
||||||
|
let stamp = value.getTime();
|
||||||
|
|
||||||
|
firstDay.value = new Date(stamp);
|
||||||
|
firstDay.value.setDate(1);
|
||||||
|
|
||||||
|
lastDay.value = new Date(stamp);
|
||||||
|
lastDay.value.setMonth(lastDay.value.getMonth() + nMonths.value);
|
||||||
|
lastDay.value.setDate(0);
|
||||||
|
|
||||||
|
months.value = [];
|
||||||
|
for (let i = 0; i < nMonths.value; i++) {
|
||||||
|
let monthDate = new Date(stamp);
|
||||||
|
monthDate.setMonth(value.getMonth() + i);
|
||||||
|
months.value.push(monthDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('update:firstDay', firstDay.value);
|
||||||
|
emit('update:lastDay', lastDay.value);
|
||||||
|
refreshEvents();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => {
|
||||||
|
return _data.value;
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
_data.value = value;
|
||||||
|
|
||||||
|
value = value || {};
|
||||||
|
|
||||||
|
events.value = value.events;
|
||||||
|
function toStamp(date) {
|
||||||
|
return date && new Date(date).setHours(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
exclusions.value = {};
|
||||||
|
let _exclusions = value.exclusions;
|
||||||
|
|
||||||
|
if (_exclusions) {
|
||||||
|
for (let exclusion of _exclusions) {
|
||||||
|
let stamp = toStamp(exclusion.dated);
|
||||||
|
if (!exclusions[stamp]) exclusions.value[stamp] = [];
|
||||||
|
exclusions.value[stamp].push(exclusion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geoExclusions.value = {};
|
||||||
|
let _geoExclusions = value.geoExclusions;
|
||||||
|
if (_geoExclusions) {
|
||||||
|
for (let geoExclusion of _geoExclusions) {
|
||||||
|
let stamp = toStamp(geoExclusion.dated);
|
||||||
|
if (!geoExclusions.value[stamp]) geoExclusions.value[stamp] = [];
|
||||||
|
geoExclusions.value[stamp].push(geoExclusion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _events = value.events;
|
||||||
|
if (_events) {
|
||||||
|
for (let event of _events) {
|
||||||
|
event.dated = toStamp(event.dated);
|
||||||
|
event.ended = toStamp(event.ended);
|
||||||
|
event.started = toStamp(event.started);
|
||||||
|
event.wdays = weekdayStore.fromSet(event.weekDays || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshEvents();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.data,
|
||||||
|
(value) => {
|
||||||
|
data.value = value;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const getMonthNameAndYear = (date) => {
|
||||||
|
const monthName = weekdayStore.getLocaleMonths[date.getMonth()].locale;
|
||||||
|
const year = date.getFullYear();
|
||||||
|
return `${monthName} ${year}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const headerTitle = computed(() => {
|
||||||
|
if (!months.value?.length) return;
|
||||||
|
|
||||||
|
const firstMonth = getMonthNameAndYear(months.value[0]);
|
||||||
|
const lastMonth = getMonthNameAndYear(months.value[months.value.length - 1]);
|
||||||
|
|
||||||
|
return `${firstMonth} - ${lastMonth}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const step = (direction) => {
|
||||||
|
const _date = new Date(date.value);
|
||||||
|
_date.setMonth(_date.getMonth() + nMonths.value * direction);
|
||||||
|
date.value = _date;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDateSelected = (data) => emit('onDateSelected', data);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
let initialDate = Date.vnNew();
|
||||||
|
initialDate.setDate(1);
|
||||||
|
initialDate.setHours(0, 0, 0, 0);
|
||||||
|
date.value = initialDate;
|
||||||
|
weekdayStore.initStore();
|
||||||
|
await nextTick();
|
||||||
|
stateStore.rightDrawer = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => arrayData.destroy());
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<QCard style="height: max-content">
|
||||||
|
<div class="calendars-header">
|
||||||
|
<QBtn
|
||||||
|
icon="arrow_left"
|
||||||
|
size="sm"
|
||||||
|
flat
|
||||||
|
class="full-height"
|
||||||
|
@click="step(-1)"
|
||||||
|
/>
|
||||||
|
<span>{{ headerTitle }}</span>
|
||||||
|
<QBtn
|
||||||
|
icon="arrow_right"
|
||||||
|
size="sm"
|
||||||
|
flat
|
||||||
|
class="full-height"
|
||||||
|
@click="step(1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="calendars-container">
|
||||||
|
<ZoneCalendar
|
||||||
|
v-for="(month, index) in months"
|
||||||
|
:key="index"
|
||||||
|
:month="month.getMonth() + 1"
|
||||||
|
:year="month.getFullYear()"
|
||||||
|
:month-date="month"
|
||||||
|
:geo-exclusions="geoExclusions"
|
||||||
|
:exclusions="exclusions"
|
||||||
|
:days-map="days"
|
||||||
|
@on-date-selected="onDateSelected"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.calendars-header {
|
||||||
|
height: 45px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: $primary;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendars-container {
|
||||||
|
max-width: 800px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,181 +1,12 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, ref, watch, onUnmounted } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
import ZoneDeliveryPanel from './ZoneDeliveryPanel.vue';
|
import ZoneDeliveryPanel from './ZoneDeliveryPanel.vue';
|
||||||
import ZoneDeliveryCalendar from './ZoneDeliveryCalendar.vue';
|
import ZoneCalendarGrid from './ZoneCalendarGrid.vue';
|
||||||
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
const weekdayStore = useWeekdayStore();
|
|
||||||
|
|
||||||
const nMonths = ref(4);
|
|
||||||
const _date = ref(Date.vnNew());
|
|
||||||
const _data = ref(null);
|
|
||||||
const firstDay = ref(null);
|
const firstDay = ref(null);
|
||||||
const lastDay = ref(null);
|
const lastDay = ref(null);
|
||||||
const months = ref([]);
|
|
||||||
const days = ref({});
|
|
||||||
const exclusions = ref({});
|
|
||||||
const geoExclusions = ref({});
|
|
||||||
const events = ref([]);
|
const events = ref([]);
|
||||||
const arrayData = useArrayData('ZoneDeliveryDays', {
|
|
||||||
url: 'Zones/getEvents',
|
|
||||||
});
|
|
||||||
const { store } = arrayData;
|
|
||||||
|
|
||||||
const refreshEvents = () => {
|
|
||||||
days.value = {};
|
|
||||||
if (!data.value) return;
|
|
||||||
|
|
||||||
let day = new Date(firstDay.value.getTime());
|
|
||||||
|
|
||||||
while (day <= lastDay.value) {
|
|
||||||
let stamp = day.getTime();
|
|
||||||
let wday = day.getDay();
|
|
||||||
let dayEvents = [];
|
|
||||||
let _exclusions = exclusions.value[stamp] || [];
|
|
||||||
|
|
||||||
if (events.value) {
|
|
||||||
for (let event of events.value) {
|
|
||||||
let match;
|
|
||||||
switch (event.type) {
|
|
||||||
case 'day':
|
|
||||||
match = event.dated == stamp;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
match =
|
|
||||||
event.wdays[wday] &&
|
|
||||||
(!event.started || stamp >= event.started) &&
|
|
||||||
(!event.ended || stamp <= event.ended);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (match && !_exclusions.find((e) => e.zoneFk == event.zoneFk)) {
|
|
||||||
dayEvents.push(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dayEvents.length) days.value[stamp] = dayEvents;
|
|
||||||
|
|
||||||
day.setDate(day.getDate() + 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const date = computed({
|
|
||||||
get: () => _date.value,
|
|
||||||
set: (value) => {
|
|
||||||
_date.value = value;
|
|
||||||
let stamp = value.getTime();
|
|
||||||
|
|
||||||
firstDay.value = new Date(stamp);
|
|
||||||
firstDay.value.setDate(1);
|
|
||||||
|
|
||||||
lastDay.value = new Date(stamp);
|
|
||||||
lastDay.value.setMonth(lastDay.value.getMonth() + nMonths.value);
|
|
||||||
lastDay.value.setDate(0);
|
|
||||||
|
|
||||||
months.value = [];
|
|
||||||
for (let i = 0; i < nMonths.value; i++) {
|
|
||||||
let monthDate = new Date(stamp);
|
|
||||||
monthDate.setMonth(value.getMonth() + i);
|
|
||||||
months.value.push(monthDate);
|
|
||||||
}
|
|
||||||
refreshEvents();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = computed({
|
|
||||||
get: () => {
|
|
||||||
return _data.value;
|
|
||||||
},
|
|
||||||
set: (value) => {
|
|
||||||
_data.value = value;
|
|
||||||
|
|
||||||
value = value || {};
|
|
||||||
|
|
||||||
events.value = value.events;
|
|
||||||
function toStamp(date) {
|
|
||||||
return date && new Date(date).setHours(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
exclusions.value = {};
|
|
||||||
let _exclusions = value.exclusions;
|
|
||||||
|
|
||||||
if (_exclusions) {
|
|
||||||
for (let exclusion of _exclusions) {
|
|
||||||
let stamp = toStamp(exclusion.dated);
|
|
||||||
if (!exclusions[stamp]) exclusions.value[stamp] = [];
|
|
||||||
exclusions.value[stamp].push(exclusion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
geoExclusions.value = {};
|
|
||||||
let _geoExclusions = value.geoExclusions;
|
|
||||||
|
|
||||||
if (_geoExclusions) {
|
|
||||||
for (let geoExclusion of _geoExclusions) {
|
|
||||||
let stamp = toStamp(geoExclusion.dated);
|
|
||||||
if (!geoExclusions[stamp]) geoExclusions.value[stamp] = [];
|
|
||||||
geoExclusions.value[stamp].push(geoExclusion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let _events = value.events;
|
|
||||||
if (_events) {
|
|
||||||
for (let event of _events) {
|
|
||||||
event.dated = toStamp(event.dated);
|
|
||||||
event.ended = toStamp(event.ended);
|
|
||||||
event.started = toStamp(event.started);
|
|
||||||
event.wdays = weekdayStore.fromSet(event.weekDays || '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshEvents();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => store.data,
|
|
||||||
(value) => {
|
|
||||||
data.value = value;
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const getMonthNameAndYear = (date) => {
|
|
||||||
const monthName = weekdayStore.getLocaleMonths[date.getMonth()].locale;
|
|
||||||
const year = date.getFullYear();
|
|
||||||
return `${monthName} ${year}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const headerTitle = computed(() => {
|
|
||||||
if (!months.value?.length) return;
|
|
||||||
|
|
||||||
const firstMonth = getMonthNameAndYear(months.value[0]);
|
|
||||||
const lastMonth = getMonthNameAndYear(months.value[months.value.length - 1]);
|
|
||||||
|
|
||||||
return `${firstMonth} - ${lastMonth}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
const step = (direction) => {
|
|
||||||
const _date = new Date(date.value);
|
|
||||||
_date.setMonth(_date.getMonth() + nMonths.value * direction);
|
|
||||||
date.value = _date;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
stateStore.rightDrawer = true;
|
|
||||||
let initialDate = Date.vnNew();
|
|
||||||
initialDate.setDate(1);
|
|
||||||
initialDate.setHours(0, 0, 0, 0);
|
|
||||||
date.value = initialDate;
|
|
||||||
weekdayStore.initStore();
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => arrayData.destroy());
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -185,55 +16,11 @@ onUnmounted(() => arrayData.destroy());
|
||||||
</template>
|
</template>
|
||||||
</RightMenu>
|
</RightMenu>
|
||||||
<QPage class="q-pa-md flex justify-center">
|
<QPage class="q-pa-md flex justify-center">
|
||||||
<QCard style="height: max-content">
|
<ZoneCalendarGrid
|
||||||
<div class="calendars-header">
|
v-model:events="events"
|
||||||
<QBtn
|
v-model:firstDay="firstDay"
|
||||||
icon="arrow_left"
|
v-model:lastDay="lastDay"
|
||||||
size="sm"
|
data-key="ZoneDeliveryDays"
|
||||||
flat
|
/>
|
||||||
class="full-height"
|
|
||||||
@click="step(-1)"
|
|
||||||
/>
|
|
||||||
<span>{{ headerTitle }}</span>
|
|
||||||
<QBtn
|
|
||||||
icon="arrow_right"
|
|
||||||
size="sm"
|
|
||||||
flat
|
|
||||||
class="full-height"
|
|
||||||
@click="step(1)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="calendars-container">
|
|
||||||
<ZoneDeliveryCalendar
|
|
||||||
v-for="(month, index) in months"
|
|
||||||
:key="index"
|
|
||||||
:month="month.getMonth() + 1"
|
|
||||||
:year="month.getFullYear()"
|
|
||||||
:month-date="month"
|
|
||||||
:geo-exclusions="geoExclusions"
|
|
||||||
:exclusions="exclusions"
|
|
||||||
:days-map="days"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</QCard>
|
|
||||||
</QPage>
|
</QPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.calendars-header {
|
|
||||||
height: 45px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
background-color: $primary;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendars-container {
|
|
||||||
max-width: 800px;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { onMounted, ref, reactive } from 'vue';
|
import { onMounted, ref, reactive } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
|
|
@ -7,6 +7,7 @@ zone:
|
||||||
deliveryDays: Delivery days
|
deliveryDays: Delivery days
|
||||||
upcomingDeliveries: Upcoming deliveries
|
upcomingDeliveries: Upcoming deliveries
|
||||||
warehouses: Warehouses
|
warehouses: Warehouses
|
||||||
|
calendar: Calendar
|
||||||
list:
|
list:
|
||||||
clone: Clone
|
clone: Clone
|
||||||
id: Id
|
id: Id
|
||||||
|
@ -66,6 +67,41 @@ warehouses:
|
||||||
deleteSubtitle: Are you sure you want to continue?
|
deleteSubtitle: Are you sure you want to continue?
|
||||||
warehouse: Warehouse
|
warehouse: Warehouse
|
||||||
add: Add
|
add: Add
|
||||||
|
eventsPanel:
|
||||||
|
editMode: Edit mode
|
||||||
|
include: Include
|
||||||
|
exclude: Exclude
|
||||||
|
events: Events
|
||||||
|
closing: Closing
|
||||||
|
travelingDays: Traveling days
|
||||||
|
price: Price
|
||||||
|
bonus: Bonus
|
||||||
|
m3Max: Max m³
|
||||||
|
everyday: Everyday
|
||||||
|
delete: Delete
|
||||||
|
deleteTitle: This item will be deleted
|
||||||
|
deleteSubtitle: Are you sure you want to continue?
|
||||||
|
eventsExclusionForm:
|
||||||
|
addExclusion: Add exclusion
|
||||||
|
editExclusion: Edit exclusion
|
||||||
|
day: Day
|
||||||
|
all: All
|
||||||
|
specificLocations: Specific locations
|
||||||
|
rootTreeLabel: Locations where it is not distributed
|
||||||
|
eventsInclusionForm:
|
||||||
|
addEvent: Add event
|
||||||
|
editEvent: Edit event
|
||||||
|
oneDay: One day
|
||||||
|
indefinitely: Indefinitely
|
||||||
|
rangeOfDates: Range of dates
|
||||||
|
day: Day
|
||||||
|
closing: Closing
|
||||||
|
travelingDays: Traveling days
|
||||||
|
price: Price
|
||||||
|
bonus: Bonus
|
||||||
|
m3Max: Max m³
|
||||||
|
from: From
|
||||||
|
to: To
|
||||||
upcomingDeliveries:
|
upcomingDeliveries:
|
||||||
province: Province
|
province: Province
|
||||||
closing: Closing
|
closing: Closing
|
||||||
|
|
|
@ -7,6 +7,7 @@ zone:
|
||||||
deliveryDays: Días de entrega
|
deliveryDays: Días de entrega
|
||||||
upcomingDeliveries: Próximos repartos
|
upcomingDeliveries: Próximos repartos
|
||||||
warehouses: Almacenes
|
warehouses: Almacenes
|
||||||
|
calendar: Calendario
|
||||||
list:
|
list:
|
||||||
clone: Clonar
|
clone: Clonar
|
||||||
id: Id
|
id: Id
|
||||||
|
@ -68,6 +69,41 @@ warehouses:
|
||||||
deleteSubtitle: ¿Seguro que quieres continuar?
|
deleteSubtitle: ¿Seguro que quieres continuar?
|
||||||
warehouse: Almacén
|
warehouse: Almacén
|
||||||
add: Añadir
|
add: Añadir
|
||||||
|
eventsPanel:
|
||||||
|
editMode: Modo edición
|
||||||
|
include: Incluir
|
||||||
|
exclude: Excluir
|
||||||
|
events: Eventos
|
||||||
|
closing: Cierre
|
||||||
|
travelingDays: Días de viaje
|
||||||
|
price: Precio
|
||||||
|
bonus: Bonificación
|
||||||
|
m3Max: Meidida máxima
|
||||||
|
everyday: Todos los días
|
||||||
|
delete: Eliminar
|
||||||
|
deleteTitle: Este elemento será eliminado
|
||||||
|
deleteSubtitle: ¿Seguro que quieres continuar?
|
||||||
|
eventsExclusionForm:
|
||||||
|
addExclusion: Añadir exclusión
|
||||||
|
editExclusion: Editar exclusión
|
||||||
|
day: Día
|
||||||
|
all: Todo
|
||||||
|
specificLocations: Localizaciones concretas
|
||||||
|
rootTreeLabel: Localizaciones en las que no se reparte
|
||||||
|
eventsInclusionForm:
|
||||||
|
addEvent: Añadir evento
|
||||||
|
editEvent: Editar evento
|
||||||
|
oneDay: Un día
|
||||||
|
indefinitely: Indefinido
|
||||||
|
rangeOfDates: Rango de fechas
|
||||||
|
day: Día
|
||||||
|
closing: Cierre
|
||||||
|
travelingDays: Días de viaje
|
||||||
|
price: Precio
|
||||||
|
bonus: Bonificación
|
||||||
|
m3Max: Medida máxima
|
||||||
|
from: Desde
|
||||||
|
to: Hasta
|
||||||
upcomingDeliveries:
|
upcomingDeliveries:
|
||||||
province: Provincia
|
province: Provincia
|
||||||
closing: Cierre
|
closing: Cierre
|
||||||
|
|
|
@ -39,146 +39,6 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Account/Role/AccountRoles.vue'),
|
component: () => import('src/pages/Account/Role/AccountRoles.vue'),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'alias',
|
|
||||||
name: 'AccountAlias',
|
|
||||||
meta: {
|
|
||||||
title: 'alias',
|
|
||||||
icon: 'email',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/AccountAlias.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'accounts',
|
|
||||||
name: 'AccountAccounts',
|
|
||||||
meta: {
|
|
||||||
title: 'accounts',
|
|
||||||
icon: 'accessibility',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/AccountAccounts.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'ldap',
|
|
||||||
name: 'AccountLdap',
|
|
||||||
meta: {
|
|
||||||
title: 'ldap',
|
|
||||||
icon: 'account_tree',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/AccountLdap.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'samba',
|
|
||||||
name: 'AccountSamba',
|
|
||||||
meta: {
|
|
||||||
title: 'samba',
|
|
||||||
icon: 'preview',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/AccountSamba.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'acls',
|
|
||||||
name: 'AccountAcls',
|
|
||||||
meta: {
|
|
||||||
title: 'acls',
|
|
||||||
icon: 'check',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/AccountAcls.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'connections',
|
|
||||||
name: 'AccountConnections',
|
|
||||||
meta: {
|
|
||||||
title: 'connections',
|
|
||||||
icon: 'check',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/AccountConnections.vue'),
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
path: 'create',
|
|
||||||
name: 'AccountCreate',
|
|
||||||
meta: {
|
|
||||||
title: 'accountCreate',
|
|
||||||
icon: 'add',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/AccountCreate.vue'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AccountCard',
|
|
||||||
path: ':id',
|
|
||||||
component: () => import('src/pages/Account/Card/AccountCard.vue'),
|
|
||||||
redirect: { name: 'AccountSummary' },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'AccountSummary',
|
|
||||||
path: 'summary',
|
|
||||||
meta: {
|
|
||||||
title: 'summary',
|
|
||||||
icon: 'launch',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/Card/AccountSummary.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AccountBasicData',
|
|
||||||
path: 'basic-data',
|
|
||||||
meta: {
|
|
||||||
title: 'basicData',
|
|
||||||
icon: 'vn:settings',
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import('src/pages/Account/Card/AccountBasicData.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AccountInheritedRoles',
|
|
||||||
path: 'inherited-oles',
|
|
||||||
meta: {
|
|
||||||
title: 'inheritedRoles',
|
|
||||||
icon: 'group',
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import('src/pages/Account/Card/AccountInheritedRoles.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AccountMailForwarding',
|
|
||||||
path: 'mail-forwarding',
|
|
||||||
meta: {
|
|
||||||
title: 'mailForwarding',
|
|
||||||
icon: 'forward',
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import('src/pages/Account/Card/AccountMailForwarding.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AccountMailAlias',
|
|
||||||
path: 'mail-alias',
|
|
||||||
meta: {
|
|
||||||
title: 'mailAlias',
|
|
||||||
icon: 'email',
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import('src/pages/Account/Card/AccountMailAlias.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AccountPrivileges',
|
|
||||||
path: 'privileges',
|
|
||||||
meta: {
|
|
||||||
title: 'privileges',
|
|
||||||
icon: 'badge',
|
|
||||||
},
|
|
||||||
component: () =>
|
|
||||||
import('src/pages/Account/Card/AccountPrivileges.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AccountLog',
|
|
||||||
path: 'log',
|
|
||||||
meta: {
|
|
||||||
title: 'log',
|
|
||||||
icon: 'history',
|
|
||||||
},
|
|
||||||
component: () => import('src/pages/Account/Card/AccountLog.vue'),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,8 +11,19 @@ export default {
|
||||||
component: RouterView,
|
component: RouterView,
|
||||||
redirect: { name: 'ZoneMain' },
|
redirect: { name: 'ZoneMain' },
|
||||||
menus: {
|
menus: {
|
||||||
main: ['ZoneList', 'ZoneDeliveryDays', 'ZoneUpcomingDeliveries'],
|
main: [
|
||||||
card: ['ZoneBasicData', 'ZoneWarehouses', 'ZoneHistory', 'ZoneLocations'],
|
'ZoneList',
|
||||||
|
'ZoneDeliveryDays',
|
||||||
|
'ZoneUpcomingList',
|
||||||
|
'ZoneUpcomingDeliveries',
|
||||||
|
],
|
||||||
|
card: [
|
||||||
|
'ZoneBasicData',
|
||||||
|
'ZoneWarehouses',
|
||||||
|
'ZoneHistory',
|
||||||
|
'ZoneLocations',
|
||||||
|
'ZoneEvents',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
@ -128,6 +139,15 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Zone/Card/ZoneLog.vue'),
|
component: () => import('src/pages/Zone/Card/ZoneLog.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'ZoneEvents',
|
||||||
|
path: 'events',
|
||||||
|
meta: {
|
||||||
|
title: 'calendar',
|
||||||
|
icon: 'vn:calendar',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Zone/Card/ZoneEvents.vue'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -73,6 +73,22 @@ export const useWeekdayStore = defineStore('weekdayStore', () => {
|
||||||
return locales;
|
return locales;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getLocalesMap = computed(() => {
|
||||||
|
const locales = {};
|
||||||
|
for (let code of localeOrder.es) {
|
||||||
|
const weekDay = weekdaysMap[code];
|
||||||
|
const locale = t(`weekdays.${weekdaysMap[code].code}`);
|
||||||
|
const obj = {
|
||||||
|
...weekDay,
|
||||||
|
locale,
|
||||||
|
localeChar: locale.substr(0, 1),
|
||||||
|
localeAbr: locale.substr(0, 3),
|
||||||
|
};
|
||||||
|
locales[weekDay.code] = obj;
|
||||||
|
}
|
||||||
|
return locales;
|
||||||
|
});
|
||||||
|
|
||||||
const getLocaleMonths = computed(() => {
|
const getLocaleMonths = computed(() => {
|
||||||
const locales = [];
|
const locales = [];
|
||||||
for (let code of monthCodes) {
|
for (let code of monthCodes) {
|
||||||
|
@ -106,6 +122,28 @@ export const useWeekdayStore = defineStore('weekdayStore', () => {
|
||||||
return wdays;
|
return wdays;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the inverse operation of fromSet() method. Transforms an
|
||||||
|
* array whose indexes are weekday index with selected days set to %true to
|
||||||
|
* weekday codes separated by commas.
|
||||||
|
*
|
||||||
|
* @param {Array<Boolean>} _weekDays Array with selected days set to %true
|
||||||
|
* @return {String} weekDays Weekday codes separated by commas
|
||||||
|
*/
|
||||||
|
const toSet = (_weekDays) => {
|
||||||
|
let wdays = [];
|
||||||
|
|
||||||
|
if (_weekDays) {
|
||||||
|
for (let i = 0; i < _weekDays.length; i++) {
|
||||||
|
if (!_weekDays[i]) continue;
|
||||||
|
let data = weekdays[i];
|
||||||
|
if (data) wdays.push(data.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wdays.join(',');
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
initStore,
|
initStore,
|
||||||
weekdaysMap,
|
weekdaysMap,
|
||||||
|
@ -115,5 +153,7 @@ export const useWeekdayStore = defineStore('weekdayStore', () => {
|
||||||
monthCodes,
|
monthCodes,
|
||||||
getLocaleMonths,
|
getLocaleMonths,
|
||||||
fromSet,
|
fromSet,
|
||||||
|
toSet,
|
||||||
|
getLocalesMap,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue