|
- "use server";
-
- // import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
- // import { BASE_API_URL } from "@/config/api";
- import {
- serverFetch,
- serverFetchJson,
- serverFetchWithNoContent,
- ServerFetchError,
- } from "../../utils/fetchUtil";
- import { BASE_API_URL } from "../../../config/api";
- import { revalidateTag } from "next/cache";
- import { cache } from "react";
-
-
- export interface ShopAndTruck{
- id: number;
- name: String;
- code: String;
- addr1: String;
- addr2: String;
- addr3: String;
- contactNo: number;
- type: String;
- contactEmail: String;
- contactName: String;
- truckLanceCode: String;
- DepartureTime: String;
- LoadingSequence?: number | null;
- districtReference: string | null;
- Store_id: Number;
- remark?: String | null;
- truckId?: number;
- }
-
- export interface Shop{
- id: number;
- name: String;
- code: String;
- addr3: String;
- }
-
- export interface Truck{
- id?: number;
- truckLanceCode: String;
- departureTime: String | number[];
- loadingSequence: number;
- districtReference: string | null;
- storeId: Number | String;
- remark?: String | null;
- shopName?: String | null;
- shopCode?: String | null;
- }
-
- export interface SaveTruckLane {
- id: number;
- truckLanceCode: string;
- departureTime: string;
- loadingSequence: number;
- districtReference: string | null;
- storeId: string;
- remark?: string | null;
- logisticId?: number | null;
- /** When true, set truck.logistic to logisticId (null clears). When false/omit, do not change logistic. */
- updateLogistic?: boolean;
- }
-
- /** POST /truck/updateLaneLogistic — 同線桶內 truck 列一次更新 logistic(單一 transaction) */
- export interface UpdateLaneLogisticRequest {
- truckLanceCode: string;
- remark?: string | null;
- logisticId?: number | null;
- }
-
- export interface DeleteTruckLane {
- id: number;
- }
-
- export interface UpdateTruckShopDetailsRequest {
- id: number;
- shopId?: number | null;
- shopName: string | null;
- shopCode: string | null;
- loadingSequence: number;
- remark?: string | null;
- }
-
- export interface SaveTruckRequest {
- id?: number | null;
- store_id: string;
- truckLanceCode: string;
- departureTime: string;
- shopId: number;
- shopName: string;
- shopCode: string;
- loadingSequence: number;
- districtReference?: string | null;
- remark?: string | null;
- logisticId?: number | null;
- }
-
- export interface CreateTruckWithoutShopRequest {
- store_id: string;
- truckLanceCode: string;
- departureTime: string;
- loadingSequence?: number;
- districtReference?: string | null;
- logisticId?: number | null;
- remark?: string | null;
- }
-
- export interface MessageResponse {
- id: number | null;
- name: string | null;
- code: string | null;
- type: string;
- message: string;
- errorPosition: string | null;
- entity: Truck | null;
- }
-
- export const fetchAllShopsAction = cache(async (params?: Record<string, string | number | null>) => {
- const endpoint = `${BASE_API_URL}/shop/combo/allShop`;
- const qs = params
- ? Object.entries(params)
- .filter(([, v]) => v !== null && v !== undefined && String(v).trim() !== "")
- .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
- .join("&")
- : "";
-
- const url = qs ? `${endpoint}?${qs}` : endpoint;
-
- return serverFetchJson<ShopAndTruck[]>(url, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const findTruckLaneByShopIdAction = cache(async (shopId: number | string) => {
- const endpoint = `${BASE_API_URL}/truck/findTruckLane/${shopId}`;
-
- return serverFetchJson<Truck[]>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const updateTruckLaneAction = async (data: SaveTruckLane) => {
- const endpoint = `${BASE_API_URL}/truck/updateTruckLane`;
-
- return serverFetchJson<MessageResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const updateLaneLogisticAction = async (
- data: UpdateLaneLogisticRequest,
- ): Promise<MessageResponse> => {
- const endpoint = `${BASE_API_URL}/truck/updateLaneLogistic`;
- return serverFetchJson<MessageResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const deleteTruckLaneAction = async (data: DeleteTruckLane) => {
- const endpoint = `${BASE_API_URL}/truck/deleteTruckLane`;
-
- return serverFetchJson<MessageResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const createTruckAction = async (data: SaveTruckRequest) => {
- const endpoint = `${BASE_API_URL}/truck/createTruckInShop`;
-
- return serverFetchJson<MessageResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const findAllUniqueTruckLaneCombinationsAction = cache(async () => {
- const endpoint = `${BASE_API_URL}/truck/findAllUniqueTruckLanceCodeAndRemarkCombinations`;
-
- return serverFetchJson<Truck[]>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- /** O(1) 取整個 RouteBoard 所需 truck rows;前端自行按 (truckLanceCode, remark) 分桶。 */
- export const findAllForRouteBoardAction = cache(async () => {
- const endpoint = `${BASE_API_URL}/truck/findAllForRouteBoard`;
- return serverFetchJson<Truck[]>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const findAllShopsByTruckLanceCodeAndRemarkAction = cache(async (truckLanceCode: string, remark: string) => {
- const endpoint = `${BASE_API_URL}/truck/findAllFromShopAndTruckByTruckLanceCodeAndRemarkAndDeletedFalse`;
- const url = `${endpoint}?truckLanceCode=${encodeURIComponent(truckLanceCode)}&remark=${encodeURIComponent(remark)}`;
-
- return serverFetchJson<ShopAndTruck[]>(url, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const findAllShopsByTruckLanceCodeAction = cache(async (truckLanceCode: string) => {
- const endpoint = `${BASE_API_URL}/truck/findAllFromShopAndTruckByTruckLanceCodeAndDeletedFalse`;
- const url = `${endpoint}?truckLanceCode=${encodeURIComponent(truckLanceCode)}`;
-
- return serverFetchJson<ShopAndTruck[]>(url, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const findAllByTruckLanceCodeAndDeletedFalseAction = cache(async (truckLanceCode: string) => {
- const endpoint = `${BASE_API_URL}/truck/findAllByTruckLanceCodeAndDeletedFalse`;
- const url = `${endpoint}?truckLanceCode=${encodeURIComponent(truckLanceCode)}`;
-
- return serverFetchJson<Truck[]>(url, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- /** 與 `findAllUniqueTruckLanceCodeAndRemarkCombinations` 同一 (code, remark) 桶;remark 空則不帶參數。 */
- export const findAllByTruckLanceCodeAndRemarkAndDeletedFalseAction = cache(
- async (truckLanceCode: string, remark: string | null | undefined) => {
- const endpoint = `${BASE_API_URL}/truck/findAllByTruckLanceCodeAndRemarkAndDeletedFalse`;
- const params = new URLSearchParams();
- params.set("truckLanceCode", truckLanceCode);
- const r = remark != null && String(remark).trim() !== "" ? String(remark).trim() : "";
- if (r !== "") params.set("remark", r);
- const url = `${endpoint}?${params.toString()}`;
- return serverFetchJson<Truck[]>(url, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- },
- );
-
- export const updateTruckShopDetailsAction = async (data: UpdateTruckShopDetailsRequest) => {
- const endpoint = `${BASE_API_URL}/truck/updateTruckShopDetails`;
-
- return serverFetchJson<MessageResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const createTruckWithoutShopAction = async (data: CreateTruckWithoutShopRequest) => {
- const endpoint = `${BASE_API_URL}/truck/createTruckWithoutShop`;
-
- return serverFetchJson<MessageResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- /** PDF 圖1:每車線一個 worksheet(MTMS_ROUTE_V1)。回傳 base64 方便 client 下載。 */
- export const exportRouteLanesExcelAction = async (
- laneIds: string[],
- ): Promise<{ base64: string; filename: string }> => {
- const response = await serverFetch(`${BASE_API_URL}/truck/exportRouteLanesExcel`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Accept:
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- },
- body: JSON.stringify({ laneIds }),
- });
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Export failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- const cd = response.headers.get("content-disposition") ?? "";
- let filename = `MTMS_車線_${Date.now()}.xlsx`;
- const quoted = /filename="([^"]+)"/i.exec(cd);
- const star = /filename\*=UTF-8''([^;\s]+)/i.exec(cd);
- const raw = (star?.[1] || quoted?.[1])?.trim();
- if (raw) {
- try {
- filename = decodeURIComponent(raw);
- } catch {
- filename = raw;
- }
- }
- const buf = await response.arrayBuffer();
- return {
- base64: Buffer.from(buf).toString("base64"),
- filename,
- };
- };
-
- /** 圖2:車線 Report(單一 sheet;每間物流公司一個水平區塊)。 */
- export const exportRouteReportExcelAction = async (
- laneIds: string[],
- ): Promise<{ base64: string; filename: string }> => {
- const response = await serverFetch(`${BASE_API_URL}/truck/exportRouteReportExcel`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Accept:
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- },
- body: JSON.stringify({ laneIds }),
- });
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Export failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- const cd = response.headers.get("content-disposition") ?? "";
- let filename = `車線Report_${Date.now()}.xlsx`;
- const quoted = /filename="([^"]+)"/i.exec(cd);
- const star = /filename\*=UTF-8''([^;\s]+)/i.exec(cd);
- const raw = (star?.[1] || quoted?.[1])?.trim();
- if (raw) {
- try {
- filename = decodeURIComponent(raw);
- } catch {
- filename = raw;
- }
- }
- const buf = await response.arrayBuffer();
- return {
- base64: Buffer.from(buf).toString("base64"),
- filename,
- };
- };
-
- export const exportTruckLaneVersionReportExcelAction = async (
- fromVersionId: number,
- toVersionId: number,
- ): Promise<{ base64: string; filename: string }> => {
- const response = await serverFetch(
- `${BASE_API_URL}/truck/exportTruckLaneVersionReportExcel`,
- {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Accept:
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- },
- body: JSON.stringify({ fromVersionId, toVersionId }),
- },
- );
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Export failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- const cd = response.headers.get("content-disposition") ?? "";
- let filename = `車線版本報告_${Date.now()}.xlsx`;
- const quoted = /filename="([^"]+)"/i.exec(cd);
- const star = /filename\*=UTF-8''([^;\s]+)/i.exec(cd);
- const raw = (star?.[1] || quoted?.[1])?.trim();
- if (raw) {
- try {
- filename = decodeURIComponent(raw);
- } catch {
- filename = raw;
- }
- }
- const buf = await response.arrayBuffer();
- return {
- base64: Buffer.from(buf).toString("base64"),
- filename,
- };
- };
-
- export const importRouteLanesExcelAction = async (
- formData: FormData,
- ): Promise<MessageResponse> => {
- const response = await serverFetch(`${BASE_API_URL}/truck/importRouteLanesExcel`, {
- method: "POST",
- body: formData,
- });
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Import failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- return (await response.json()) as MessageResponse;
- };
-
- export type RouteLaneImportPreviewRow = {
- truckRowId: number | null;
- truckLanceCode: string;
- remark: string | null;
- storeId: string;
- departureTime: string;
- shopId: number;
- shopName: string;
- shopCode: string;
- loadingSequence: number;
- districtReference: string | null;
- logisticId: number | null;
- };
-
- export type ParseRouteLanesExcelResponse = {
- sheetCount: number;
- rowCount: number;
- rows: RouteLaneImportPreviewRow[];
- };
-
- export const parseRouteLanesExcelAction = async (
- formData: FormData,
- ): Promise<ParseRouteLanesExcelResponse> => {
- const response = await serverFetch(`${BASE_API_URL}/truck/parseRouteLanesExcel`, {
- method: "POST",
- body: formData,
- });
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Parse import failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- return (await response.json()) as ParseRouteLanesExcelResponse;
- };
-
- export const findAllUniqueShopNamesAndCodesFromTrucksAction = cache(async () => {
- const endpoint = `${BASE_API_URL}/truck/findAllUniqueShopNamesAndCodesFromTrucks`;
-
- return serverFetchJson<Array<{ name: string; code: string }>>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const findAllUniqueRemarksFromTrucksAction = cache(async () => {
- const endpoint = `${BASE_API_URL}/truck/findAllUniqueRemarksFromTrucks`;
-
- return serverFetchJson<string[]>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const findAllUniqueShopCodesFromTrucksAction = cache(async () => {
- const endpoint = `${BASE_API_URL}/truck/findAllUniqueShopCodesFromTrucks`;
-
- return serverFetchJson<string[]>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const findAllUniqueShopNamesFromTrucksAction = cache(async () => {
- const endpoint = `${BASE_API_URL}/truck/findAllUniqueShopNamesFromTrucks`;
-
- return serverFetchJson<string[]>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- // ---- Truck lane version snapshot (DB snapshot) ----
-
- export interface CreateTruckLaneSnapshotRequest {
- truckLanceCode?: string | null;
- note?: string | null;
- }
-
- export interface TruckLaneVersionResponse {
- id: number;
- truckLanceCode: string;
- note: string | null;
- created: string | null;
- createdBy?: string | null;
- /** truck_lane_version.modifiedBy(BaseEntity) */
- modifiedBy?: string | null;
- }
-
- export interface TruckLaneVersionLineResponse {
- truckRowId: number;
- truckLanceCode: string | null;
- shopCode: string | null;
- branchName: string | null;
- districtReference: string | null;
- loadingSequence: number | null;
- departureTime: string | null;
- storeId: string;
- remark: string | null;
- logisticId: number | null;
- }
-
- export type DiffFieldChange = {
- field: string;
- from: string | null;
- to: string | null;
- };
-
- export type TruckLaneVersionDiffLine = {
- truckRowId: number;
- shopCode: string | null;
- changes: DiffFieldChange[];
- /** 快照車線(僅欄位異動時 changes 不含 truckLanceCode/remark) */
- truckLanceCode?: string | null;
- remark?: string | null;
- };
-
- export type LogisticMasterDiffLine = {
- logisticId: number;
- type: string;
- logisticName: string;
- carPlate: string;
- changeText: string;
- };
-
- export type TruckLaneVersionDiffResponse = {
- fromVersionId: number;
- toVersionId: number;
- changed: TruckLaneVersionDiffLine[];
- logisticMasterChanges?: LogisticMasterDiffLine[];
- };
-
- export const createTruckLaneSnapshotAction = async (data: CreateTruckLaneSnapshotRequest) => {
- const endpoint = `${BASE_API_URL}/truckLaneVersion/snapshot`;
- return serverFetchJson<TruckLaneVersionResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const listTruckLaneVersionsAction = cache(async (truckLanceCode?: string | null) => {
- const endpoint = `${BASE_API_URL}/truckLaneVersion`;
- const url =
- truckLanceCode != null && String(truckLanceCode).trim() !== ""
- ? `${endpoint}?truckLanceCode=${encodeURIComponent(String(truckLanceCode))}`
- : endpoint;
- return serverFetchJson<TruckLaneVersionResponse[]>(url, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const getTruckLaneVersionLinesAction = cache(async (versionId: number) => {
- const endpoint = `${BASE_API_URL}/truckLaneVersion/${versionId}/lines`;
- return serverFetchJson<TruckLaneVersionLineResponse[]>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- });
-
- export const diffTruckLaneVersionsAction = async (
- fromVersionId: number,
- toVersionId: number,
- ) => {
- const endpoint = `${BASE_API_URL}/truckLaneVersion/diff`;
- const url = `${endpoint}?fromVersionId=${encodeURIComponent(String(fromVersionId))}&toVersionId=${encodeURIComponent(String(toVersionId))}`;
- return serverFetchJson<TruckLaneVersionDiffResponse>(url, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const restoreTruckLaneVersionAction = async (versionId: number) => {
- const endpoint = `${BASE_API_URL}/truckLaneVersion/${versionId}/restore`;
- return serverFetchJson<MessageResponse>(endpoint, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export type UpdateTruckLaneVersionNoteRequest = {
- note: string | null;
- };
-
- export const updateTruckLaneVersionNoteAction = async (
- versionId: number,
- data: UpdateTruckLaneVersionNoteRequest,
- ) => {
- const endpoint = `${BASE_API_URL}/truckLaneVersion/${versionId}/note`;
- return serverFetchJson<TruckLaneVersionResponse>(endpoint, {
- method: "PATCH",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- // ---- Truck lane schedule (server-side apply) ----
-
- export type TruckLaneScheduleLineAction =
- | "MOVE"
- | "CREATE"
- | "DELETE"
- | "ENSURE_LANE";
-
- export type TruckLaneMoveTargetRequest = {
- truckRowId: number;
- toTruckLanceCode: string;
- toRemark?: string | null;
- toStoreId: string;
- toLoadingSequence: number;
- toDistrictReference?: string | null;
- departureTime?: string | null;
- };
-
- export type TruckLaneScheduleLineRequest = {
- action: TruckLaneScheduleLineAction;
- truckRowId?: number | null;
- toTruckLanceCode: string;
- toRemark?: string | null;
- toStoreId: string;
- toLoadingSequence?: number | null;
- toDistrictReference?: string | null;
- shopId?: number | null;
- shopCode?: string | null;
- shopName?: string | null;
- departureTime?: string | null;
- logisticId?: number | null;
- };
-
- export type CreateTruckLaneScheduleRequest = {
- executeAt: string;
- note?: string | null;
- lines?: TruckLaneScheduleLineRequest[] | null;
- moves?: TruckLaneMoveTargetRequest[] | null;
- };
-
- export type TruckLaneScheduleLineResponse = {
- id: number;
- action: TruckLaneScheduleLineAction;
- truckRowId: number | null;
- shopCode: string | null;
- shopName: string | null;
- fromTruckLanceCode: string | null;
- fromRemark: string | null;
- fromStoreId: string | null;
- fromLoadingSequence?: number | null;
- fromDistrictReference?: string | null;
- fromDepartureTime?: string | null;
- toTruckLanceCode: string;
- toRemark: string | null;
- toStoreId: string;
- toDistrictReference?: string | null;
- toLoadingSequence?: number | null;
- departureTime?: string | null;
- lineStatus: string;
- errorMessage: string | null;
- appliedAt: string | null;
- };
-
- export type RouteExcelSchedulePlanPreviewRow = {
- action: TruckLaneScheduleLineAction;
- truckRowId: number | null;
- shopCode: string | null;
- shopName: string | null;
- toTruckLanceCode: string;
- toRemark: string | null;
- toStoreId: string;
- toLoadingSequence: number | null;
- };
-
- export type RouteExcelSchedulePlanError = {
- shopCode: string;
- shopName: string;
- message: string;
- };
-
- export type RouteExcelSchedulePlanCounts = {
- moves: number;
- creates: number;
- deletes: number;
- ensureLanes: number;
- };
-
- export type RouteExcelSchedulePlanResponse = {
- sheetCount: number;
- rowCount: number;
- lines: TruckLaneScheduleLineRequest[];
- previews: RouteExcelSchedulePlanPreviewRow[];
- errors: RouteExcelSchedulePlanError[];
- counts: RouteExcelSchedulePlanCounts;
- };
-
- export type TruckLaneScheduleResponse = {
- id: number;
- executeAt: string;
- status: string;
- source: string;
- note: string | null;
- appliedAt: string | null;
- errorMessage: string | null;
- snapshotVersionId: number | null;
- preApplySnapshotVersionId?: number | null;
- created: string | null;
- createdBy?: string | null;
- modifiedBy: string | null;
- lines?: TruckLaneScheduleLineResponse[] | null;
- lineCounts?: {
- total: number;
- applied: number;
- failed: number;
- pending: number;
- } | null;
- };
-
- export type PendingTruckRowIdsResponse = {
- /** 所有開放排程(PENDING/APPLYING)涉及的 truck rows(標記、排程驗證用) */
- truckRowIds: number[];
- /** 已進入鎖定時間窗(或 APPLYING)的 truck rows,看板不可手改 */
- lockedTruckRowIds?: number[];
- };
-
- export type TruckLaneScheduleExcelPreviewRow = {
- rowIndex: number;
- shopCode: string;
- toTruckLanceCode: string;
- toRemark: string | null;
- toStoreId: string;
- executeAt: string | null;
- truckRowId: number | null;
- };
-
- export type TruckLaneScheduleExcelRowError = {
- rowIndex: number;
- message: string;
- };
-
- export type ParseTruckLaneScheduleExcelResponse = {
- rowCount: number;
- validCount: number;
- errorCount: number;
- rows: TruckLaneScheduleExcelPreviewRow[];
- errors: TruckLaneScheduleExcelRowError[];
- };
-
- export const createTruckLaneScheduleAction = async (
- data: CreateTruckLaneScheduleRequest,
- ): Promise<TruckLaneScheduleResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule`;
- return serverFetchJson<TruckLaneScheduleResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const planTruckLaneScheduleFromRouteExcelAction = async (
- formData: FormData,
- ): Promise<RouteExcelSchedulePlanResponse> => {
- const response = await serverFetch(
- `${BASE_API_URL}/truckLaneSchedule/planFromRouteExcel`,
- {
- method: "POST",
- body: formData,
- },
- );
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Plan import failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- return (await response.json()) as RouteExcelSchedulePlanResponse;
- };
-
- export const listTruckLaneSchedulesAction = async (
- status?: string[],
- limit: number = 200,
- ): Promise<TruckLaneScheduleResponse[]> => {
- const params = new URLSearchParams();
- for (const s of status ?? []) {
- params.append("status", s);
- }
- params.set("limit", String(limit));
- const qs = params.toString();
- const base = `${BASE_API_URL}/truckLaneSchedule`;
- return serverFetchJson<TruckLaneScheduleResponse[]>(
- `${base}${qs ? `?${qs}` : ""}`,
- {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- },
- );
- };
-
- export const getTruckLaneScheduleAction = async (
- id: number,
- ): Promise<TruckLaneScheduleResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}`;
- return serverFetchJson<TruckLaneScheduleResponse>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const pendingTruckLaneScheduleShopIdsAction =
- async (): Promise<PendingTruckRowIdsResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule/pendingShopIds`;
- return serverFetchJson<PendingTruckRowIdsResponse>(endpoint, {
- method: "GET",
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const cancelTruckLaneScheduleAction = async (
- id: number,
- ): Promise<TruckLaneScheduleResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/cancel`;
- return serverFetchJson<TruckLaneScheduleResponse>(endpoint, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const applyNowTruckLaneScheduleAction = async (
- id: number,
- ): Promise<TruckLaneScheduleResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/applyNow`;
- return serverFetchJson<TruckLaneScheduleResponse>(endpoint, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export type RetryFailedTruckLaneScheduleRequest = {
- executeAt?: string | null;
- };
-
- export const retryFailedTruckLaneScheduleAction = async (
- id: number,
- body?: RetryFailedTruckLaneScheduleRequest,
- ): Promise<TruckLaneScheduleResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/retry-failed`;
- return serverFetchJson<TruckLaneScheduleResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(body ?? {}),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const reactivateCancelledTruckLaneScheduleAction = async (
- id: number,
- body?: RetryFailedTruckLaneScheduleRequest,
- ): Promise<TruckLaneScheduleResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/reactivate`;
- return serverFetchJson<TruckLaneScheduleResponse>(endpoint, {
- method: "POST",
- body: JSON.stringify(body ?? {}),
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const ignoreTruckLaneScheduleAction = async (
- id: number,
- ): Promise<TruckLaneScheduleResponse> => {
- const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/ignore`;
- return serverFetchJson<TruckLaneScheduleResponse>(endpoint, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- });
- };
-
- export const parseTruckLaneScheduleExcelAction = async (
- formData: FormData,
- defaultExecuteAt?: string | null,
- ): Promise<ParseTruckLaneScheduleExcelResponse> => {
- const qs =
- defaultExecuteAt != null && defaultExecuteAt !== ""
- ? `?defaultExecuteAt=${encodeURIComponent(defaultExecuteAt)}`
- : "";
- const response = await serverFetch(
- `${BASE_API_URL}/truckLaneSchedule/parseExcel${qs}`,
- { method: "POST", body: formData },
- );
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Parse schedule Excel failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- return (await response.json()) as ParseTruckLaneScheduleExcelResponse;
- };
-
- export const importTruckLaneScheduleExcelAction = async (
- formData: FormData,
- defaultExecuteAt?: string | null,
- note?: string | null,
- ): Promise<TruckLaneScheduleResponse[]> => {
- const params = new URLSearchParams();
- if (defaultExecuteAt) params.set("defaultExecuteAt", defaultExecuteAt);
- if (note) params.set("note", note);
- const qs = params.toString() ? `?${params.toString()}` : "";
- const response = await serverFetch(
- `${BASE_API_URL}/truckLaneSchedule/importExcel${qs}`,
- { method: "POST", body: formData },
- );
- if (!response.ok) {
- const text = await response.text().catch(() => "");
- throw new ServerFetchError(
- `Import schedule Excel failed: ${response.status} ${text}`.trim(),
- response,
- );
- }
- return (await response.json()) as TruckLaneScheduleResponse[];
- };
|