mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-02-13 03:45:31 +00:00
Fix, features et modifications UI
This commit is contained in:
@@ -63,7 +63,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { computed, ComputedRef, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
@@ -82,6 +82,7 @@ import {
|
||||
CONFIDENTIAL,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
|
||||
const store = useStore();
|
||||
@@ -103,6 +104,12 @@ const noResults = computed(() => {
|
||||
function getUrl(c: { id: number }): string {
|
||||
return `/fr/parcours/${c.id}`;
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyAccompanyingCourses,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
@@ -112,6 +112,7 @@ import {
|
||||
trans,
|
||||
} from "translator";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const evaluations: ComputedRef<
|
||||
PaginationResponse<AccompanyingPeriodWorkEvaluation>
|
||||
@@ -150,6 +151,12 @@ function getUrl(
|
||||
}
|
||||
return "";
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyEvaluations,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { computed, ComputedRef, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import { Notification } from "ChillPersonAssets/types";
|
||||
@@ -66,6 +66,7 @@ import {
|
||||
} from "translator";
|
||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
@@ -121,6 +122,12 @@ function getEntityUrl(n: Notification): string {
|
||||
throw "notification type unknown";
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyNotifications,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from "vue";
|
||||
import { computed, ComputedRef, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import TabTable from "./TabTable.vue";
|
||||
import {
|
||||
@@ -95,6 +95,7 @@ import {
|
||||
import { TasksState } from "./store/modules/homepage";
|
||||
import { Alert, Warning } from "ChillPersonAssets/types";
|
||||
import { localizeDateTimeFormat } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
@@ -123,6 +124,12 @@ const noResultsWarning = computed(() => {
|
||||
function getUrl(t: Warning | Alert): string {
|
||||
return `/fr/task/single-task/${t.id}/show`;
|
||||
}
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyTasks,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import MyWorkflowsTable from "./MyWorkflowsTable.vue";
|
||||
import {
|
||||
@@ -19,9 +19,16 @@ import {
|
||||
MY_WORKFLOWS_DESCRIPTION_CC,
|
||||
trans,
|
||||
} from "translator";
|
||||
import { HomepageTabs } from "ChillMainAssets/types";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const workflows = computed(() => store.state.homepage.workflows);
|
||||
const workflowsCc = computed(() => store.state.homepage.workflowsCc);
|
||||
onMounted(() => {
|
||||
store.dispatch("getByTab", {
|
||||
tab: HomepageTabs.MyWorkflows,
|
||||
param: "",
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
Center,
|
||||
DateTime,
|
||||
TranslatableString,
|
||||
User,
|
||||
@@ -148,8 +149,9 @@ export type TicketHistoryLine =
|
||||
| CallerStateEvent;
|
||||
|
||||
interface BaseTicket<
|
||||
T extends "ticket_ticket:simple" | "ticket_ticket:extended" =
|
||||
"ticket_ticket:simple",
|
||||
T extends
|
||||
| "ticket_ticket:simple"
|
||||
| "ticket_ticket:extended" = "ticket_ticket:simple",
|
||||
> {
|
||||
type_extended: T;
|
||||
type: "ticket_ticket";
|
||||
@@ -177,6 +179,7 @@ export interface Ticket extends BaseTicket<"ticket_ticket:extended"> {
|
||||
}
|
||||
|
||||
export interface TicketFilters {
|
||||
byPersonCenter: Center[];
|
||||
byPerson: Person[];
|
||||
byCreator: User[];
|
||||
byAddressee: UserGroupOrUser[];
|
||||
@@ -191,6 +194,7 @@ export interface TicketFilters {
|
||||
}
|
||||
|
||||
export interface TicketFilterParams {
|
||||
byPersonCenter?: number[];
|
||||
byPerson?: number[];
|
||||
byCreator?: number[];
|
||||
byAddressee?: number[];
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, defineProps, defineEmits, computed } from "vue";
|
||||
import { ref, watch, computed } from "vue";
|
||||
|
||||
// Components
|
||||
import PickEntity from "ChillMainAssets/vuejs/PickEntity/PickEntity.vue";
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
<!-- Sélection du motif -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{{
|
||||
trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE)
|
||||
}}</label>
|
||||
<label class="form-label">
|
||||
{{ trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE) }} *
|
||||
</label>
|
||||
<motive-selector-component
|
||||
v-model="ticketForm.motive"
|
||||
:motives="motives"
|
||||
@@ -49,9 +49,9 @@
|
||||
|
||||
<!-- Éditeur de commentaire -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label">{{
|
||||
trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE)
|
||||
}}</label>
|
||||
<label class="form-label">
|
||||
{{ trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE) }} *
|
||||
</label>
|
||||
<comment-editor-component
|
||||
v-model="ticketForm.content"
|
||||
:motive="ticketForm.motive ? ticketForm.motive : null"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { makeFetch } from "../../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
||||
import { Person } from "../../../../../../../../ChillPersonBundle/Resources/public/types";
|
||||
import { ApiException } from "../../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import {
|
||||
ApiException,
|
||||
Center,
|
||||
} from "../../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import { Module } from "vuex";
|
||||
import { RootState } from "..";
|
||||
import { Ticket } from ".././../../../types";
|
||||
@@ -8,21 +11,29 @@ import { Thirdparty } from "src/Bundle/ChillThirdPartyBundle/Resources/public/ty
|
||||
|
||||
export interface State {
|
||||
persons: Person[];
|
||||
centers: Center[];
|
||||
}
|
||||
|
||||
export const modulePersons: Module<State, RootState> = {
|
||||
state: () => ({
|
||||
persons: [] as Person[],
|
||||
centers: [] as Center[],
|
||||
}),
|
||||
getters: {
|
||||
getPersons(state) {
|
||||
return state.persons;
|
||||
},
|
||||
getCenters(state) {
|
||||
return state.centers;
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setPersons(state, persons: Person[]) {
|
||||
state.persons = persons;
|
||||
},
|
||||
setCenters(state, centers: Center[]) {
|
||||
state.centers = centers;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async setPersons({ commit, rootState }, persons: Person[]) {
|
||||
@@ -81,5 +92,15 @@ export const modulePersons: Module<State, RootState> = {
|
||||
throw error.name;
|
||||
}
|
||||
},
|
||||
async fetchCenters({ commit }) {
|
||||
try {
|
||||
const result: { showCenters: boolean; centers: Center[] } =
|
||||
await makeFetch("GET", "/api/1.0/person/creation/authorized-centers");
|
||||
commit("setCenters", result.showCenters ? result.centers : []);
|
||||
} catch (e: unknown) {
|
||||
const error = e as ApiException;
|
||||
throw error.name;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface State {
|
||||
ticket_list: TicketSimple[];
|
||||
pagination: Pagination;
|
||||
count: number;
|
||||
latest_update: Date | null;
|
||||
user: User;
|
||||
}
|
||||
|
||||
@@ -28,6 +29,7 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
next: null,
|
||||
previous: null,
|
||||
},
|
||||
latest_update: null,
|
||||
count: 0,
|
||||
user: {} as User,
|
||||
}),
|
||||
@@ -49,6 +51,9 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
getCount(state): number {
|
||||
return state.count;
|
||||
},
|
||||
getLatestUpdate(state): Date | null {
|
||||
return state.latest_update;
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setTicketList(state, ticketList: TicketSimple[]) {
|
||||
@@ -63,6 +68,9 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
setCount(state, count: number) {
|
||||
state.count = count;
|
||||
},
|
||||
setLatestUpdate(state, date: Date) {
|
||||
state.latest_update = date;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async fetchTicketList(
|
||||
@@ -95,6 +103,7 @@ export const moduleTicketList: Module<State, RootState> = {
|
||||
|
||||
commit("setTicketList", results);
|
||||
commit("setCount", count);
|
||||
commit("setLatestUpdate", new Date());
|
||||
commit("setPagination", pagination);
|
||||
} catch (e: unknown) {
|
||||
const error = e as ApiException;
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<ticket-filter-list-component
|
||||
:resultCount="resultCount"
|
||||
:available-centers="availableCenters"
|
||||
:latest-update="latestUpdate"
|
||||
:result-count="resultCount"
|
||||
:available-persons="availablePersons"
|
||||
:available-motives="availableMotives"
|
||||
:ticket-filter-params="ticketFilterParams"
|
||||
@@ -42,12 +44,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
import { ref, computed, onMounted, reactive } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// Types
|
||||
import { TicketSimple, Motive, TicketFilterParams } from "../../types";
|
||||
import type { Person } from "ChillPersonAssets/types";
|
||||
import { Center } from "ChillMainAssets/types";
|
||||
|
||||
// Components
|
||||
import TicketListComponent from "./components/TicketListComponent.vue";
|
||||
@@ -55,8 +59,13 @@ import TicketFilterListComponent from "./components/TicketFilterListComponent.vu
|
||||
import { Pagination } from "ChillMainAssets/lib/api/apiMethods";
|
||||
|
||||
// Translations
|
||||
import { trans, CHILL_TICKET_LIST_LOADING_TICKET } from "translator";
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_LIST_LOADING_TICKET,
|
||||
CHILL_TICKET_LIST_UPDATED,
|
||||
} from "translator";
|
||||
|
||||
const toast = useToast();
|
||||
const store = useStore();
|
||||
const ticketFilterParams = window.ticketFilterParams
|
||||
? window.ticketFilterParams
|
||||
@@ -67,14 +76,45 @@ const ticketList = computed(
|
||||
() => store.getters.getTicketList as TicketSimple[],
|
||||
);
|
||||
const resultCount = computed(() => store.getters.getCount as number);
|
||||
const latestUpdate = computed(
|
||||
() => store.getters.getLatestUpdate as Date | null,
|
||||
);
|
||||
const pagination = computed(() => store.getters.getPagination as Pagination);
|
||||
const availablePersons = ref<Person[]>([]);
|
||||
const availableMotives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const availableCenters = computed(() => store.getters.getCenters as Center[]);
|
||||
const filters: TicketFilterParams = reactive({
|
||||
byPersonCenter: ticketFilterParams?.byPersonCenter
|
||||
? ticketFilterParams.byPersonCenter.map((person) => person.id)
|
||||
: [],
|
||||
byPerson: ticketFilterParams?.byPerson
|
||||
? ticketFilterParams.byPerson.map((person) => person.id)
|
||||
: [],
|
||||
byCreator: ticketFilterParams?.byCreator
|
||||
? ticketFilterParams.byCreator.map((creator) => creator.id)
|
||||
: [],
|
||||
byAddressee: ticketFilterParams?.byAddressee
|
||||
? ticketFilterParams.byAddressee.map((addressee) => addressee.id)
|
||||
: [],
|
||||
byCurrentState: ticketFilterParams?.byCurrentState ?? ["open"],
|
||||
byCurrentStateEmergency: ticketFilterParams?.byCurrentStateEmergency ?? [],
|
||||
byMotives: ticketFilterParams?.byMotives
|
||||
? ticketFilterParams.byMotives.map((motive) => motive.id)
|
||||
: [],
|
||||
byCreatedAfter: ticketFilterParams?.byCreatedAfter ?? "",
|
||||
byCreatedBefore: ticketFilterParams?.byCreatedBefore ?? "",
|
||||
byResponseTimeExceeded: ticketFilterParams?.byResponseTimeExceeded
|
||||
? "true"
|
||||
: "",
|
||||
byAddresseeToMe: ticketFilterParams?.byAddresseeToMe ?? false,
|
||||
byTicketId: ticketFilterParams?.byTicketId ?? null,
|
||||
});
|
||||
|
||||
const handleFiltersChanged = async (filters: TicketFilterParams) => {
|
||||
const handleFiltersChanged = async (ticketFilterParams: TicketFilterParams) => {
|
||||
isLoading.value = true;
|
||||
Object.assign(filters, ticketFilterParams);
|
||||
try {
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
await store.dispatch("fetchTicketList", ticketFilterParams);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@@ -88,37 +128,21 @@ const fetchNextPage = async () => {
|
||||
|
||||
onMounted(async () => {
|
||||
isLoading.value = true;
|
||||
const filters: TicketFilterParams = {
|
||||
byPerson: ticketFilterParams?.byPerson
|
||||
? ticketFilterParams.byPerson.map((person) => person.id)
|
||||
: [],
|
||||
byCreator: ticketFilterParams?.byCreator
|
||||
? ticketFilterParams.byCreator.map((creator) => creator.id)
|
||||
: [],
|
||||
byAddressee: ticketFilterParams?.byAddressee
|
||||
? ticketFilterParams.byAddressee.map((addressee) => addressee.id)
|
||||
: [],
|
||||
byCurrentState: ticketFilterParams?.byCurrentState ?? ["open"],
|
||||
byCurrentStateEmergency: ticketFilterParams?.byCurrentStateEmergency ?? [],
|
||||
byMotives: ticketFilterParams?.byMotives
|
||||
? ticketFilterParams.byMotives.map((motive) => motive.id)
|
||||
: [],
|
||||
byCreatedAfter: ticketFilterParams?.byCreatedAfter ?? "",
|
||||
byCreatedBefore: ticketFilterParams?.byCreatedBefore ?? "",
|
||||
byResponseTimeExceeded: ticketFilterParams?.byResponseTimeExceeded
|
||||
? "true"
|
||||
: "",
|
||||
byAddresseeToMe: ticketFilterParams?.byAddresseeToMe ?? false,
|
||||
byTicketId: ticketFilterParams?.byTicketId ?? null,
|
||||
};
|
||||
|
||||
try {
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
store.dispatch("getCurrentUser");
|
||||
store.dispatch("fetchMotives");
|
||||
store.dispatch("fetchCenters");
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(async () => {
|
||||
await store.dispatch("fetchTicketList", filters);
|
||||
toast.success(trans(CHILL_TICKET_LIST_UPDATED));
|
||||
}, 60000);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="input-group mb-2">
|
||||
<vue-multiselect
|
||||
name="selectPersonCenter"
|
||||
id="selectPersonCenter"
|
||||
label="displayLabel"
|
||||
track-by="id"
|
||||
:custom-label="(value: Center) => value.name"
|
||||
:open-direction="openDirection"
|
||||
:multiple="true"
|
||||
:placeholder="trans(CHILL_TICKET_TICKET_SET_PERSON_CENTER_LABEL)"
|
||||
:options="centers"
|
||||
v-model="selectedCenter"
|
||||
class="form-control"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
import { Center } from "ChillMainAssets/types";
|
||||
import { trans, CHILL_TICKET_TICKET_SET_PERSON_CENTER_LABEL } from "translator";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object as () => Center[] | null,
|
||||
default: null,
|
||||
},
|
||||
centers: {
|
||||
type: Array as () => Center[],
|
||||
default: () => [],
|
||||
},
|
||||
openDirection: {
|
||||
type: String,
|
||||
default: "bottom",
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: Center[] | null) => void>();
|
||||
|
||||
const selectedCenter = computed<Center[] | null>({
|
||||
get() {
|
||||
return props.modelValue;
|
||||
},
|
||||
set(value: Center[] | null) {
|
||||
emit("update:modelValue", value);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-control {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
::v-deep .multiselect__tag {
|
||||
background: var(--bs-chill-green) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
@@ -52,38 +52,16 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<!-- Filtre par motifs -->
|
||||
<div class="row">
|
||||
<label class="form-label" for="motiveSelector">{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_BY_MOTIVES)
|
||||
}}</label>
|
||||
<motive-selector
|
||||
v-model="selectedMotive"
|
||||
:motives="availableMotives"
|
||||
:allow-parent-selection="true"
|
||||
@remove="(motive) => removeMotive(motive)"
|
||||
id="motiveSelector"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
<label class="form-label" for="personCenterSelector">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_BY_PERSON_CENTER) }}
|
||||
</label>
|
||||
<person-center-selector-component
|
||||
v-model="selectedPersonCenter"
|
||||
:centers="availableCenters"
|
||||
id="personCenterSelector"
|
||||
:disabled="ticketFilterParams?.byPersonCenter ? true : false"
|
||||
/>
|
||||
|
||||
<div class="mb-2" style="min-height: 2em">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span
|
||||
v-for="motive in filters.byMotives"
|
||||
:key="motive.id"
|
||||
class="badge bg-secondary d-flex align-items-center gap-1"
|
||||
>
|
||||
{{ getMotiveDisplayName(motive) }}
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close btn-close-white"
|
||||
:aria-label="trans(CHILL_TICKET_LIST_FILTER_REMOVE)"
|
||||
@click="removeMotive(motive)"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Filtre par état actuel -->
|
||||
<div class="d-flex gap-3">
|
||||
@@ -167,14 +145,50 @@
|
||||
</div>
|
||||
<!-- Filtre par numéro de ticket -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label pe-2" for="ticketSelector">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_BY_TICKET_ID) }}
|
||||
</label>
|
||||
<ticket-selector
|
||||
v-model="filters.byTicketId"
|
||||
id="ticketSelector"
|
||||
:disabled="ticketFilterParams?.byTicketId ? true : false"
|
||||
/>
|
||||
<div class="row">
|
||||
<label class="form-label pe-2" for="ticketSelector">
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_BY_TICKET_ID) }}
|
||||
</label>
|
||||
<ticket-selector
|
||||
v-model="filters.byTicketId"
|
||||
id="ticketSelector"
|
||||
:disabled="ticketFilterParams?.byTicketId ? true : false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Filtre par motifs -->
|
||||
<div class="row">
|
||||
<label class="form-label" for="motiveSelector">{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_BY_MOTIVES)
|
||||
}}</label>
|
||||
<motive-selector
|
||||
v-model="selectedMotive"
|
||||
:motives="availableMotives"
|
||||
:allow-parent-selection="true"
|
||||
@remove="(motive) => removeMotive(motive)"
|
||||
id="motiveSelector"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
/>
|
||||
|
||||
<div class="mb-2" style="min-height: 2em">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span
|
||||
v-for="motive in filters.byMotives"
|
||||
:key="motive.id"
|
||||
class="badge bg-secondary d-flex align-items-center gap-1"
|
||||
>
|
||||
{{ getMotiveDisplayName(motive) }}
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close btn-close-white"
|
||||
:aria-label="trans(CHILL_TICKET_LIST_FILTER_REMOVE)"
|
||||
@click="removeMotive(motive)"
|
||||
:disabled="ticketFilterParams?.byMotives ? true : false"
|
||||
></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -234,11 +248,27 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span
|
||||
class="col-12 d-flex align-items-end justify-content-end form-text text-muted mt-1"
|
||||
v-if="latestUpdate"
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
class="col-12 d-flex align-items-end justify-content-end form-text text-muted mt-1"
|
||||
>
|
||||
{{ resultCount !== 0 ? `${resultCount} ` : "" }}
|
||||
{{ trans(CHILL_TICKET_LIST_FILTER_RESULT, { count: resultCount }) }}
|
||||
<span v-if="latestUpdate">
|
||||
{{
|
||||
trans(CHILL_TICKET_LIST_FILTER_AT_TIME, {
|
||||
date: latestUpdate.toLocaleTimeString([], {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
}),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
@@ -248,6 +278,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Center } from "ChillMainAssets/types";
|
||||
import type { Person } from "ChillPersonAssets/types";
|
||||
import {
|
||||
type Motive,
|
||||
@@ -263,6 +294,7 @@ import {
|
||||
CHILL_TICKET_LIST_FILTER_BY_PERSON,
|
||||
CHILL_TICKET_LIST_FILTER_CREATORS,
|
||||
CHILL_TICKET_LIST_FILTER_BY_CREATOR,
|
||||
CHILL_TICKET_LIST_FILTER_BY_PERSON_CENTER,
|
||||
CHILL_TICKET_LIST_FILTER_ADDRESSEES,
|
||||
CHILL_TICKET_LIST_FILTER_BY_ADDRESSEES,
|
||||
CHILL_TICKET_LIST_FILTER_BY_MOTIVES,
|
||||
@@ -280,21 +312,26 @@ import {
|
||||
CHILL_TICKET_LIST_FILTER_APPLY,
|
||||
CHILL_TICKET_LIST_FILTER_RESULT,
|
||||
CHILL_TICKET_LIST_FILTER_CURRENT_STATE,
|
||||
CHILL_TICKET_LIST_FILTER_AT_TIME,
|
||||
} from "translator";
|
||||
|
||||
// Components
|
||||
import PersonsSelector from "../../TicketApp/components/Person/PersonsSelectorComponent.vue";
|
||||
import MotiveSelector from "../../TicketApp/components/Motive/MotiveSelectorComponent.vue";
|
||||
import AddresseeSelectorComponent from "../../TicketApp/components/Addressee/AddresseeSelectorComponent.vue";
|
||||
|
||||
import ToggleComponent from "./ToggleComponent.vue";
|
||||
import TicketSelector from "../../TicketApp/components/Ticket/TicketSelector.vue";
|
||||
import DateAndTimeSelectorComponent from "./DateAndTimeSelectorComponent.vue";
|
||||
import PersonCenterSelectorComponent from "./PersonCenterSelectorComponent.vue";
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
availableCenters: Center[];
|
||||
availablePersons?: Person[];
|
||||
availableMotives: Motive[];
|
||||
resultCount: number;
|
||||
latestUpdate: Date | null;
|
||||
ticketFilterParams: TicketFilters | null;
|
||||
}>();
|
||||
|
||||
@@ -304,6 +341,7 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const filtersInitValues: TicketFilters = {
|
||||
byPersonCenter: props.ticketFilterParams?.byPersonCenter ?? [],
|
||||
byPerson: props.ticketFilterParams?.byPerson ?? [],
|
||||
byCreator: props.ticketFilterParams?.byCreator ?? [],
|
||||
byAddressee: props.ticketFilterParams?.byAddressee ?? [],
|
||||
@@ -328,6 +366,13 @@ const isClosedToggled = ref(false);
|
||||
const isEmergencyToggled = ref(false);
|
||||
|
||||
const availablePersons = ref<Person[]>(props.availablePersons || []);
|
||||
|
||||
const selectedPersonCenter = ref<Center[] | null>(null);
|
||||
|
||||
watch(selectedPersonCenter, (newPersonCenter) => {
|
||||
filters.value.byPersonCenter = newPersonCenter ?? [];
|
||||
});
|
||||
|
||||
const selectedMotive = ref<Motive | null>();
|
||||
|
||||
watch(selectedMotive, (newMotive) => {
|
||||
@@ -363,6 +408,10 @@ const selectedMotiveIds = computed(() =>
|
||||
filters.value.byMotives.map((motive) => motive.id),
|
||||
);
|
||||
|
||||
const selectedPersonCenterIds = computed(() =>
|
||||
filters.value.byPersonCenter.map((center) => center.id),
|
||||
);
|
||||
|
||||
const handleStateToggle = (value: boolean) => {
|
||||
if (value) {
|
||||
filters.value.byCurrentState = ["closed"];
|
||||
@@ -433,6 +482,10 @@ const applyFilters = (): void => {
|
||||
apiFilters.byMotives = selectedMotiveIds.value;
|
||||
}
|
||||
|
||||
if (selectedPersonCenterIds.value.length > 0) {
|
||||
apiFilters.byPersonCenter = selectedPersonCenterIds.value;
|
||||
}
|
||||
|
||||
if (filters.value.byCreatedAfter) {
|
||||
apiFilters.byCreatedAfter = formatDateToISO(
|
||||
filters.value.byCreatedAfter,
|
||||
|
||||
@@ -43,26 +43,26 @@
|
||||
|
||||
<div class="card-body pt-0">
|
||||
<div class="row" v-if="ticket.currentAddressees.length">
|
||||
<div class="col-12 title text-start">
|
||||
<div class="col-md-3 col-12 title text-start" style="max-width: 215px">
|
||||
<h3>{{ trans(CHILL_TICKET_LIST_ADDRESSEES) }}</h3>
|
||||
</div>
|
||||
<div class="col-12 list">
|
||||
<div class="col-md-9 col-12 list">
|
||||
<addressee-component :addressees="ticket.currentAddressees" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="ticket.currentPersons.length">
|
||||
<div class="col-12 title text-start">
|
||||
<div class="col-md-3 col-12 title text-start" style="max-width: 215px">
|
||||
<h3>{{ trans(CHILL_TICKET_LIST_PERSONS) }}</h3>
|
||||
</div>
|
||||
<div class="col-12 list">
|
||||
<div class="col-md-9 col-12 list">
|
||||
<person-component :entities="ticket.currentPersons" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="ticket.caller">
|
||||
<div class="col-12 title text-start">
|
||||
<div class="col-md-3 col-12 title text-start" style="max-width: 215px">
|
||||
<h3>{{ trans(CHILL_TICKET_LIST_CALLERS) }}</h3>
|
||||
</div>
|
||||
<div class="col-12 list">
|
||||
<div class="col-md-9 col-12 list">
|
||||
<person-component
|
||||
:entities="
|
||||
ticket.caller ? ([ticket.caller] as Person[] | Thirdparty[]) : []
|
||||
|
||||
@@ -10,6 +10,7 @@ chill_ticket:
|
||||
loading_ticket: "Chargement des tickets..."
|
||||
loading_ticket_details: "Chargement de l'historique du ticket..."
|
||||
error_loading_ticket: "Erreur lors du chargement des ticket"
|
||||
updated: "Liste des tickets mise à jour"
|
||||
load_more: "Voir plus..."
|
||||
addressees: "Destinataires"
|
||||
persons: "Usager concernés"
|
||||
@@ -24,6 +25,7 @@ chill_ticket:
|
||||
by_person: "Par personne"
|
||||
creators: "Créateurs"
|
||||
by_creator: "Par créateur"
|
||||
by_person_center: "Par unité"
|
||||
addressees: "Par destinataire"
|
||||
by_addressees: "Par destinataire"
|
||||
by_motives: "Par motifs"
|
||||
@@ -42,7 +44,7 @@ chill_ticket:
|
||||
apply: "Appliquer les filtres"
|
||||
remove: "Supprimer"
|
||||
result: "{count, plural, =0 {Aucun résultat} =1 {resultat} other {resultats}}"
|
||||
|
||||
at_time: "à {date}"
|
||||
ticket:
|
||||
init_form:
|
||||
title: "Ajouter des informations sur le ticket"
|
||||
@@ -103,6 +105,8 @@ chill_ticket:
|
||||
caller_label: "Ajouter un appelant"
|
||||
success: "Appelants et usagers mis à jour"
|
||||
error: "Aucun usager sélectionné"
|
||||
set_person_center:
|
||||
label: "Choisir une unité"
|
||||
banner:
|
||||
person: "{count, plural, =0 {Aucun usager impliqué} =1 {Usager impliqué} other {Usagers impliqués}}"
|
||||
speaker: "{count, plural, =0 {Aucun destinataire} =1 {Destinataire} other {Destinataires}}"
|
||||
|
||||
Reference in New Issue
Block a user