260 lines
6.5 KiB
Vue
260 lines
6.5 KiB
Vue
<template>
|
|
<div>
|
|
<Transition name="fade">
|
|
<p
|
|
v-if="intMessage"
|
|
class="message"
|
|
>
|
|
{{ intMessage }}
|
|
</p>
|
|
</Transition>
|
|
<VueSelect
|
|
:id="intName"
|
|
ref="select"
|
|
:loading="intLoading"
|
|
v-model="intModelRelated"
|
|
:clearable="false"
|
|
:label="intLabel"
|
|
:options="intData"
|
|
@search="search"
|
|
:filterable="true"
|
|
:disabled="intReadonly || intDisabled"
|
|
:searchable="true"
|
|
:placeholder="intPlaceholder"
|
|
>
|
|
<template #list-footer>
|
|
<li class="pagination">
|
|
<button
|
|
@click="
|
|
$event.preventDefault();
|
|
intPage -= 1;
|
|
"
|
|
:disabled="!intHasPrevPage"
|
|
class="btn btn-sm btn-primary mt-2 mb-2 ms-2 me-2"
|
|
>
|
|
{{ __("Précédent") }}
|
|
</button>
|
|
<button
|
|
@click="
|
|
$event.preventDefault();
|
|
intPage += 1;
|
|
"
|
|
:disabled="!intHasNextPage"
|
|
class="btn btn-sm btn-primary mt-2 mb-2"
|
|
>
|
|
{{ __("Suivant") }}
|
|
</button>
|
|
</li>
|
|
</template>
|
|
</VueSelect>
|
|
<input
|
|
type="hidden"
|
|
v-model="intModelRelated.value"
|
|
:name="intName"
|
|
>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import type { PropType } from "vue";
|
|
import { defineComponent } from "vue";
|
|
import VueSelect from "vue-select";
|
|
import route from "./../../modules/route";
|
|
import trans from "./../../modules/trans";
|
|
|
|
export default defineComponent({
|
|
components: {
|
|
VueSelect,
|
|
},
|
|
mixins: [route, trans],
|
|
props: {
|
|
label: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
name: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
targetmodel: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
routename: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
modelrelated: {
|
|
type: Object as PropType<VselectOption>,
|
|
default: null
|
|
},
|
|
modelselected: {
|
|
type: Object as PropType<VselectOption>,
|
|
default: null
|
|
},
|
|
readonly: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
helper: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
required: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
searchlabel: {
|
|
type: String,
|
|
default: "name",
|
|
}
|
|
},
|
|
data(): {
|
|
intName: string;
|
|
intRouteName: string;
|
|
intTargetModel: string;
|
|
intPlaceholder: string;
|
|
intDisabled: boolean;
|
|
intReadonly: boolean;
|
|
intModelRelated: VselectOption;
|
|
intLoading: boolean;
|
|
intSearchText: string;
|
|
intData: LaravelModelList;
|
|
intPage: number;
|
|
intPerPage: number;
|
|
intHasNextPage: boolean;
|
|
intHasPrevPage: boolean;
|
|
intMessage: string | null;
|
|
intLabel: string;
|
|
} {
|
|
return {
|
|
intName: "",
|
|
intRouteName: "",
|
|
intTargetModel: "",
|
|
intPlaceholder: "",
|
|
intDisabled: false,
|
|
intReadonly: false,
|
|
intModelRelated: {
|
|
id: 0,
|
|
name: "",
|
|
value: 0,
|
|
},
|
|
intLoading: false,
|
|
intSearchText: "",
|
|
intData: [],
|
|
intPage: 1,
|
|
intPerPage: 12,
|
|
intHasNextPage: true,
|
|
intHasPrevPage: false,
|
|
intMessage: null,
|
|
intLabel: "name",
|
|
};
|
|
},
|
|
mounted() {
|
|
const json = String(this.$attrs.json ?? "{}"),
|
|
data = JSON.parse(json);
|
|
this.intName = (this.name) ? this.name : data.name;
|
|
this.intRouteName = (this.routename) ? this.routename : data.routeName;
|
|
this.intTargetModel = (this.targetmodel) ? this.targetmodel : data.targetModel;
|
|
this.intPlaceholder = (this.placeholder) ? this.placeholder : data.placeholder;
|
|
this.intDisabled = (this.disabled) ? this.disabled : !!data.disabled;
|
|
this.intReadonly = (this.readonly) ? this.readonly : !!data.readonly;
|
|
if ((this.modelselected && this.modelselected.value !== null) || data.modelSelected) {
|
|
this.intModelRelated = (this.modelselected) ? this.modelselected : data.modelSelected;
|
|
} else if ((this.modelrelated && this.modelrelated.value !== null) || data.modelRelated) {
|
|
this.intModelRelated = (this.modelrelated) ? this.modelrelated : data.modelRelated;
|
|
} else {
|
|
this.intModelRelated = {
|
|
id: 0,
|
|
name: "",
|
|
value: 0,
|
|
};
|
|
}
|
|
this.intLabel = (this.searchlabel) ? this.searchlabel : data.searchlabel ?? "name";
|
|
this.search(false);
|
|
},
|
|
watch: {
|
|
intPage() {
|
|
if (this.intPage < 1) {
|
|
this.intPage = 1;
|
|
}
|
|
if (this.intPage > 1) {
|
|
this.intHasPrevPage = true;
|
|
} else {
|
|
this.intHasPrevPage = false;
|
|
}
|
|
this.search();
|
|
},
|
|
intData() {
|
|
if (this.intData.length == this.intPerPage) {
|
|
this.intHasNextPage = true;
|
|
} else {
|
|
this.intHasNextPage = false;
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
search(search: false | null | string = null): void {
|
|
if (search !== false && search !== null) {
|
|
this.intSearchText = search;
|
|
}
|
|
let init = search === false ? true : false,
|
|
routeUrl = this.route(this.intRouteName);
|
|
|
|
if (!routeUrl) {
|
|
throw new Error("undefined route " + this.intRouteName);
|
|
}
|
|
if (this.intPage) {
|
|
routeUrl += "?targetModel=" + this.intTargetModel + "&page=" + this.intPage;
|
|
}
|
|
if (this.intSearchText) {
|
|
routeUrl += "&search=" + this.intSearchText;
|
|
}
|
|
|
|
this.intLoading = true;
|
|
|
|
window.axios
|
|
.get(routeUrl)
|
|
.then((response) => {
|
|
this.intData = response.data.data as LaravelModelList;
|
|
if (init && this.intData.length && this.intModelRelated.value === null) {
|
|
this.intModelRelated = this.intData[0] as VselectOption;
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
this.intMessage =
|
|
"Erreur lors de l'opération, merci d'actualiser la page.";
|
|
if (e.response?.status === 422) {
|
|
const errors = e.response?.data?.errors;
|
|
if (errors instanceof String) {
|
|
this.intMessage = errors as string;
|
|
}
|
|
if (errors instanceof Object) {
|
|
this.intMessage = Object.values(errors).reduce(function (
|
|
previous,
|
|
current
|
|
) {
|
|
return String(previous) + String(current);
|
|
}) as string;
|
|
}
|
|
console.warn(errors);
|
|
}
|
|
})
|
|
.then(() => {
|
|
this.intLoading = false;
|
|
});
|
|
},
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import "vue-select/dist/vue-select.css";
|
|
:root {
|
|
--vs-dropdown-max-height: 15rem;
|
|
}
|
|
</style>
|