salix-front/src/composables/useArrayData.js

157 lines
3.9 KiB
JavaScript

import { onMounted, ref, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import axios from 'axios';
import { useArrayDataStore } from 'stores/useArrayDataStore';
const arrayDataStore = useArrayDataStore();
export function useArrayData(key, userOptions) {
if (!key) throw new Error('ArrayData: A key is required to use this composable');
if (!arrayDataStore.get(key)) {
arrayDataStore.set(key);
}
const store = arrayDataStore.get(key);
const hasMoreData = ref(false);
const router = useRouter();
const route = useRoute();
let canceller = null;
const page = ref(1);
onMounted(() => {
setOptions()
const query = route.query;
if (query.params) {
store.userParams = JSON.parse(query.params);
}
});
function setOptions() {
if (typeof userOptions === 'object') {
for (const option in userOptions) {
if (userOptions[option] == null) continue
if (Object.prototype.hasOwnProperty.call(store, option)) {
store[option] = userOptions[option];
}
}
}
}
async function fetch({ append = false }) {
if (!store.url) return;
cancelRequest();
canceller = new AbortController();
const filter = {
order: store.order,
limit: store.limit,
skip: store.skip,
};
Object.assign(filter, store.userFilter);
Object.assign(store.filter, filter);
const params = {
filter: JSON.stringify(store.filter),
};
Object.assign(params, store.userParams);
const response = await axios.get(store.url, {
signal: canceller.signal,
params,
});
const { limit } = filter;
hasMoreData.value = response.data.length === limit;
if (append === true) {
if (!store.data) store.data = [];
for (const row of response.data) store.data.push(row);
}
if (append === false) {
store.data = response.data;
updateStateParams();
}
canceller = null;
}
function destroy() {
if (arrayDataStore.get(key)) {
arrayDataStore.clear(key);
}
}
function cancelRequest() {
if (canceller) {
canceller.abort();
canceller = null;
}
}
async function applyFilter({ filter, params }) {
if (filter) store.userFilter = filter;
if (params) store.userParams = Object.assign({}, params);
await fetch({ append: false });
}
async function addFilter({ filter, params }) {
if (filter) store.userFilter = Object.assign(store.userFilter, filter);
if (params) store.userParams = Object.assign(store.userParams, params);
await fetch({ append: false });
}
async function loadMore() {
if (!hasMoreData.value) return;
store.skip = store.limit * page.value;
page.value += 1;
await fetch({ append: true });
}
async function refresh() {
await fetch({ append: false });
}
function updateStateParams() {
const query = {};
if (store.order) query.order = store.order;
if (store.limit) query.limit = store.limit;
if (store.skip) query.skip = store.skip;
if (store.userParams && Object.keys(store.userParams).length !== 0)
query.params = JSON.stringify(store.userParams);
router.replace({
path: route.path,
query: query,
});
}
const totalRows = computed(() => store.data && store.data.length | 0);
return {
fetch,
applyFilter,
addFilter,
refresh,
destroy,
loadMore,
store,
hasMoreData,
totalRows,
updateStateParams,
};
}