You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
394 lines
9.3 KiB
394 lines
9.3 KiB
import axios from "axios";
|
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
import { STATUSES } from "./config";
|
|
import { usePointSelection } from "./stores/usePointSelection";
|
|
import { RANGE_FILTERS_KEYS, usePendingPointsFilters } from "./stores/usePendingPointsFilters";
|
|
import { appendFiltersInUse } from "./utils.js";
|
|
import { useMode } from "./stores/useMode.js";
|
|
import { useMemo } from "react";
|
|
import { useUpdateLayerCounter } from "./stores/useUpdateLayerCounter.js";
|
|
import { keycloak } from "./keycloak.js";
|
|
import { useKeycloak } from "@react-keycloak/web";
|
|
|
|
export const BASE_URL = import.meta.env.VITE_API_URL;
|
|
|
|
export const api = axios.create({
|
|
baseURL:
|
|
import.meta.env.MODE === "development"
|
|
? "http://localhost:5173/"
|
|
: BASE_URL,
|
|
});
|
|
|
|
api.interceptors.request.use(async function (config) {
|
|
const token = keycloak.token;
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${ token }`;
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
export const useDbTableName = () => {
|
|
const {isImportMode} = useMode();
|
|
if (isImportMode) return "pre_placement_points";
|
|
return "placement_points";
|
|
}
|
|
|
|
export const useSourceLayerName = () => {
|
|
const {isImportMode} = useMode();
|
|
if (isImportMode) return "public.prepoints_with_dist";
|
|
return "public.points_with_dist";
|
|
}
|
|
|
|
const enrichParamsWithRegionFilter = (params, region) => {
|
|
const resultParams = params ? params : new URLSearchParams();
|
|
|
|
if (region) {
|
|
if (region.type === "ao") {
|
|
resultParams.append("district[]", region.id);
|
|
}
|
|
|
|
if (region.type === "rayon") {
|
|
resultParams.append("area[]", region.id);
|
|
}
|
|
}
|
|
|
|
return resultParams;
|
|
};
|
|
|
|
export const getPoints = async (params, region, dbTable = "placement_points", signal) => {
|
|
const resultParams = enrichParamsWithRegionFilter(params, region);
|
|
|
|
const { data } = await api.get(
|
|
`/api/${dbTable}/?${resultParams.toString()}`, {signal}
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const exportPoints = async (params, region, dbTable = "placement_points") => {
|
|
const resultParams = enrichParamsWithRegionFilter(params, region);
|
|
|
|
const { data } = await api.get(
|
|
`/api/${dbTable}/to_excel/?${resultParams.toString()}`,
|
|
{ responseType: "arraybuffer" }
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const downloadImportTemplate = async () => {
|
|
const { data } = await api.get(
|
|
'/api/pre_placement_points/download_template/',
|
|
{ responseType: "arraybuffer" }
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const uploadPointsFile = async (file, config) => {
|
|
const formData = new FormData();
|
|
formData.append("file", file);
|
|
const { data } = await api.post(
|
|
`/api/pre_placement_points/load_matching_file/`,
|
|
formData,
|
|
config
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const importPoints = async (id) => {
|
|
const formData = new FormData();
|
|
formData.append("id", id);
|
|
const { data } = await api.post(
|
|
`/api/pre_placement_points/start_matching/`,
|
|
formData
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const getImportStatus = async () => {
|
|
const { data } = await api.get(
|
|
`/api/pre_placement_points/import_status/`
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const useGetTotalInitialPointsCount = () => {
|
|
const dbTable = useDbTableName();
|
|
const { updateCounter } = useUpdateLayerCounter();
|
|
return useQuery(
|
|
["all-initial-count", dbTable, updateCounter],
|
|
async ({signal}) => {
|
|
const params = new URLSearchParams({
|
|
page: 1,
|
|
page_size: 1,
|
|
});
|
|
params.append("status[]", [STATUSES.pending, STATUSES.cancelled]);
|
|
|
|
return await getPoints(params, null, dbTable, signal);
|
|
},
|
|
{
|
|
select: (data) => data.count,
|
|
refetchOnWindowFocus: false
|
|
}
|
|
);
|
|
};
|
|
|
|
export const useGetFilteredPendingPointsCount = (isMerge) => {
|
|
const { filters, ranges } = usePendingPointsFilters();
|
|
const { updateCounter } = useUpdateLayerCounter();
|
|
const {
|
|
categories,
|
|
region,
|
|
} = filters;
|
|
const {
|
|
selection: { included },
|
|
} = usePointSelection();
|
|
|
|
const includedIds = [...included];
|
|
const getParams = () => {
|
|
const params = new URLSearchParams({
|
|
page: 1,
|
|
page_size: 1,
|
|
"categories[]": categories,
|
|
"included[]": includedIds,
|
|
});
|
|
params.append("status[]", STATUSES.pending);
|
|
|
|
appendFiltersInUse(params, filters, ranges);
|
|
|
|
return params;
|
|
}
|
|
|
|
const getMergeParams = () => {
|
|
return new URLSearchParams({
|
|
"matching_status": "New",
|
|
});
|
|
}
|
|
|
|
const dbTable = useDbTableName();
|
|
|
|
return useQuery(
|
|
["filtered-points", filters, dbTable, includedIds, updateCounter],
|
|
async ({signal}) => {
|
|
const params = isMerge ? getMergeParams() : getParams();
|
|
|
|
return await getPoints(params, region, dbTable, signal);
|
|
},
|
|
{
|
|
select: (data) => data.count,
|
|
keepPreviousData: true,
|
|
refetchOnWindowFocus: false
|
|
}
|
|
);
|
|
};
|
|
|
|
export const useGetPointsToMergeCount = () => {
|
|
const getMergeParams = () => {
|
|
return new URLSearchParams({
|
|
"matching_status": "New",
|
|
});
|
|
}
|
|
|
|
const dbTable = useDbTableName();
|
|
|
|
return useQuery(
|
|
["filtered-points", dbTable],
|
|
async () => {
|
|
const params = getMergeParams();
|
|
|
|
return await getPoints(params, null, dbTable);
|
|
},
|
|
{ select: (data) => data.count, keepPreviousData: true }
|
|
);
|
|
};
|
|
|
|
export const useMergePointsToDb = () => {
|
|
return useMutation({
|
|
mutationFn: () => {
|
|
return api.post(
|
|
`/api/pre_placement_points/move_points/`
|
|
);
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useGetPermissions = () => {
|
|
const {setImportMode} = useMode();
|
|
return useQuery(["permissions"], async () => {
|
|
const { data } = await api.get("/api/me/");
|
|
|
|
if (data?.groups?.includes("postnet_editor")) {
|
|
return "editor";
|
|
}
|
|
|
|
setImportMode(false);
|
|
return "viewer";
|
|
});
|
|
};
|
|
|
|
const TASK_STATUSES = {
|
|
finished: "Перерасчет ML завершен"
|
|
}
|
|
export const useCanEdit = () => {
|
|
const { keycloak } = useKeycloak();
|
|
const { data: statusData } = useLastMLRun();
|
|
|
|
const hasFinishedUpdate = useMemo(() => {
|
|
return statusData?.task_status === TASK_STATUSES.finished
|
|
}, [statusData]);
|
|
|
|
return keycloak.hasResourceRole("postnet_editor", "postnet") && hasFinishedUpdate;
|
|
};
|
|
|
|
export const useUpdatePostamatId = () => {
|
|
return useMutation({
|
|
mutationFn: (params) => {
|
|
return api.put(
|
|
`/api/placement_points/update_postamat_id/?${params.toString()}`
|
|
);
|
|
},
|
|
});
|
|
};
|
|
|
|
export const getLastMLRun = async () => {
|
|
const { data } = await api.get(
|
|
`/api/placement_points/last_time_ml_run/`
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const startML = async () => {
|
|
const { data } = await api.get(
|
|
`/api/placement_points/start/`
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const getPostamatesAndPvzGroups = async () => {
|
|
const { data } = await api.get(
|
|
`/api/postamate_and_pvz_groups/`
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const usePostamatesAndPvzGroups = () => {
|
|
return useQuery(
|
|
['groups'],
|
|
async () => {
|
|
return await getPostamatesAndPvzGroups();
|
|
},
|
|
);
|
|
};
|
|
|
|
export const getOtherGroups = async () => {
|
|
const { data } = await api.get(
|
|
`/api/other_object_groups/`
|
|
);
|
|
|
|
return data;
|
|
};
|
|
|
|
export const useOtherGroups = () => {
|
|
return useQuery(
|
|
['other_groups'],
|
|
async () => {
|
|
return await getOtherGroups();
|
|
},
|
|
);
|
|
};
|
|
|
|
export const useLastMLRun = () => {
|
|
return useQuery(
|
|
['last_time'],
|
|
async () => {
|
|
return await getLastMLRun();
|
|
},
|
|
{
|
|
refetchInterval: 5000,
|
|
}
|
|
);
|
|
}
|
|
|
|
export const useGetPendingPointsRange = (dbTable) => {
|
|
const { isImportMode } = useMode();
|
|
const statusFilter = isImportMode ? '' : `?status[]=${STATUSES.pending}`;
|
|
|
|
return useQuery(
|
|
["prediction-max-min", dbTable],
|
|
async () => {
|
|
const { data, isInitialLoading, isFetching } = await api.get(
|
|
`/api/${dbTable}/filters/${statusFilter}`
|
|
);
|
|
return {data, isLoading: isInitialLoading || isFetching};
|
|
},
|
|
{
|
|
select: ({data, isLoading}) => {
|
|
const distToGroupsArr = data.dist_to_groups.map((groupRange) => {
|
|
return {
|
|
[`d${groupRange.group_id}`]: [Math.floor(groupRange.dist[0]), Math.min(Math.ceil(groupRange.dist[1]), 4000)],
|
|
}
|
|
});
|
|
const distToGroups = Object.assign({}, ...distToGroupsArr);
|
|
const rangesArr = RANGE_FILTERS_KEYS.map((key) => {
|
|
if ((/d[0-9]/.test(key))) return;
|
|
return {
|
|
[key]: [Math.floor(data[key][0]), Math.ceil(data[key][1])]
|
|
}
|
|
}).filter(item => !!item);
|
|
const ranges = Object.assign({}, ...rangesArr);
|
|
return {
|
|
fullRange: {
|
|
prediction: data.prediction_current,
|
|
...ranges,
|
|
...distToGroups
|
|
},
|
|
isLoading: isLoading
|
|
};
|
|
},
|
|
}
|
|
);
|
|
};
|
|
|
|
export const useGetPopupPoints = (features) => {
|
|
const pointsIds = features.map(f => f.properties.id);
|
|
const dbTable = useDbTableName();
|
|
|
|
const { data, isInitialLoading, isFetching } = useQuery(
|
|
["popup_data", features],
|
|
async () => {
|
|
const params = new URLSearchParams({
|
|
"location_ids[]": pointsIds,
|
|
});
|
|
|
|
const { data } = await api.get(
|
|
`/api/${dbTable}/?${params.toString()}`
|
|
);
|
|
|
|
return data.results;
|
|
},
|
|
{
|
|
refetchOnWindowFocus: false,
|
|
refetchOnMount: false
|
|
}
|
|
);
|
|
|
|
return { data, isLoading: isInitialLoading || isFetching };
|
|
};
|
|
|
|
export const deletePoint = async (id) => {
|
|
const formData = new FormData();
|
|
formData.append("ids", id);
|
|
await api.delete(
|
|
`/api/pre_placement_points/delete_points/`,
|
|
{ data: formData }
|
|
)
|
|
}
|