Ver código fonte

利用集計対応 HT

SATE_RECEIPT-16 0630_打ち合わせメモ
develop
sosuke.iwabuchi 2 anos atrás
pai
commit
2ec0b3d91a
9 arquivos alterados com 166 adições e 120 exclusões
  1. +5
    -12
      src/api/custom/hello-techno/use-summary.ts
  2. +1
    -0
      src/api/index.ts
  3. +2
    -0
      src/api/url.ts
  4. +25
    -14
      src/components/table/TableHeadCustom.tsx
  5. +1
    -1
      src/hooks/useTable.ts
  6. +2
    -1
      src/pages/dashboard/contract/list.tsx
  7. +2
    -1
      src/pages/dashboard/login-user/list.tsx
  8. +46
    -19
      src/pages/dashboard/receipt-issuing-order/custom/hello-techno/list.tsx
  9. +82
    -72
      src/pages/dashboard/use-summary/custom/hello-techno/list.tsx

+ 5
- 12
src/api/custom/hello-techno/use-summary.ts Ver arquivo

@@ -8,28 +8,21 @@ import {
import { getUrl } from "../../url";

export type UseSummary = {
id: string;

summary_yyyymm: string;
summary_key1: string;
summary_key2?: string;
date_from: string;
date_to: string;

customer_code: string;
customer_name: string;
parking_name?: string;

receipt_order_count: string;
mail_order_count: string;
sms_send_count: string;
sms_send_cost: string;

is_fixed: boolean;

updated_at: string;
};

// 利用実績一覧取得 -----------------------
export type UseSummariesRequest = {
summary_yyyymm: string;
date_from: string;
date_to: string;
} & ListRequest;

export type UseSummariesResponse = {


+ 1
- 0
src/api/index.ts Ver arquivo

@@ -47,6 +47,7 @@ export const ApiId = {
HT_CUSTOM_RECEIPT_ISSUING_ORDERS: id++,
HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE: id++,
HT_CUSTOM_USE_SUMMARIES: id++,
HT_CUSTOM_USE_SUMMARY_DOWNLOAD_CSV: id++,
} as const;
export type ApiId = (typeof ApiId)[keyof typeof ApiId];



+ 2
- 0
src/api/url.ts Ver arquivo

@@ -40,12 +40,14 @@ const urls = {
[A.HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE]:
"custom/hello-techno/receipt-issuing-order/create",
[A.HT_CUSTOM_USE_SUMMARIES]: "custom/hello-techno/use-summaries",
[A.HT_CUSTOM_USE_SUMMARY_DOWNLOAD_CSV]: "custom/hello-techno/use-summary/csv",
};

const prefixs = {
[A.CSRF_TOKEN]: "",
[A.DOWNLOAD_RECEIPT]: "",
[A.DOWNLOAD_RECEIPT_LETTER]: "",
[A.HT_CUSTOM_USE_SUMMARY_DOWNLOAD_CSV]: "",
};
const DEFAULT_API_URL_PREFIX = "api";



+ 25
- 14
src/components/table/TableHeadCustom.tsx Ver arquivo

@@ -1,5 +1,5 @@
// @mui
import { Theme } from '@mui/material/styles';
import { Theme } from "@mui/material/styles";
import {
Box,
SxProps,
@@ -8,7 +8,7 @@ import {
TableCell,
TableHead,
TableSortLabel,
} from '@mui/material';
} from "@mui/material";

// ----------------------------------------------------------------------

@@ -16,20 +16,29 @@ const visuallyHidden = {
border: 0,
margin: -1,
padding: 0,
width: '1px',
height: '1px',
overflow: 'hidden',
position: 'absolute',
whiteSpace: 'nowrap',
clip: 'rect(0 0 0 0)',
width: "1px",
height: "1px",
overflow: "hidden",
position: "absolute",
whiteSpace: "nowrap",
clip: "rect(0 0 0 0)",
} as const;

// ----------------------------------------------------------------------
export type HeadLabelProps = {
id: string;
label?: string;
align?: "inherit" | "left" | "center" | "right" | "justify";
width?: number | string;
minWidth?: number | string;
needSort?: boolean;
// { id: "customer_name", label: "運営会社名", align: "left" },
};

type Props = {
order?: 'asc' | 'desc';
order?: "asc" | "desc";
orderBy?: string;
headLabel: any[];
headLabel: HeadLabelProps[];
rowCount?: number;
numSelected?: number;
onSort?: (id: string) => void;
@@ -65,7 +74,7 @@ export default function TableHeadCustom({
{headLabel.map((headCell) => (
<TableCell
key={headCell.id}
align={headCell.align || 'left'}
align={headCell.align || "left"}
sortDirection={orderBy === headCell.id ? order : false}
sx={{ width: headCell.width, minWidth: headCell.minWidth }}
>
@@ -73,15 +82,17 @@ export default function TableHeadCustom({
<TableSortLabel
hideSortIcon
active={orderBy === headCell.id}
direction={orderBy === headCell.id ? order : 'asc'}
direction={orderBy === headCell.id ? order : "asc"}
onClick={() => onSort(headCell.id)}
sx={{ textTransform: 'capitalize' }}
sx={{ textTransform: "capitalize" }}
>
{headCell.label}

{orderBy === headCell.id ? (
<Box sx={{ ...visuallyHidden }}>
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
{order === "desc"
? "sorted descending"
: "sorted ascending"}
</Box>
) : null}
</TableSortLabel>


+ 1
- 1
src/hooks/useTable.ts Ver arquivo

@@ -30,7 +30,7 @@ export type UseTableReturn<T extends object> = {
};

export default function useTable<T extends object>(): UseTableReturn<T> {
const ROWS_PER_PAGES = [20, 50, 100];
const ROWS_PER_PAGES = [50, 100, 500];

const ORDER = "order";
const SORT = "sort";


+ 2
- 1
src/pages/dashboard/contract/list.tsx Ver arquivo

@@ -16,6 +16,7 @@ import { Contract, getContracts } from "api/contract";
import { PageID, TabID } from "codes/page";
import { FormProvider, RHFTextField } from "components/hook-form";
import { TableHeadCustom } from "components/table";
import { HeadLabelProps } from "components/table/TableHeadCustom";
import { SearchConditionContextProvider } from "contexts/SearchConditionContext";
import useAPICall from "hooks/useAPICall";
import useAuth from "hooks/useAuth";
@@ -155,7 +156,7 @@ function SearchBox({ table }: CommonProps) {
}

function TableBox({ table }: CommonProps) {
const TABLE_HEAD = [
const TABLE_HEAD: HeadLabelProps[] = [
{ id: "id", label: "ID", align: "left" },
{ id: "name", label: "名前", align: "left" },
];


+ 2
- 1
src/pages/dashboard/login-user/list.tsx Ver arquivo

@@ -50,6 +50,7 @@ import RHFDatePicker from "components/hook-form/RHFDatePicker";
import { dateParse, formatDateStr } from "utils/datetime";
import { Clear } from "@mui/icons-material";
import { LoginUser, getLoginUsers } from "api/login-user";
import { HeadLabelProps } from "components/table/TableHeadCustom";

export default function LoginUserList() {
const { setHeaderTitle, setTabs } = useDashboard(
@@ -217,7 +218,7 @@ function SearchBox({ table }: CommonProps) {
}

function TableBox({ table }: CommonProps) {
const TABLE_HEAD = [
const TABLE_HEAD: HeadLabelProps[] = [
{ id: "name", label: "名前", align: "left" },
{ id: "email", label: "Email", align: "left" },
];


+ 46
- 19
src/pages/dashboard/receipt-issuing-order/custom/hello-techno/list.tsx Ver arquivo

@@ -30,6 +30,7 @@ import { PageID, TabID } from "codes/page";
import { FormProvider, RHFCheckbox, RHFTextField } from "components/hook-form";
import RHFDatePicker from "components/hook-form/RHFDatePicker";
import { TableHeadCustom } from "components/table";
import { HeadLabelProps } from "components/table/TableHeadCustom";
import { SearchConditionContextProvider } from "contexts/SearchConditionContext";
import useAPICall from "hooks/useAPICall";
import useAuth from "hooks/useAuth";
@@ -43,6 +44,19 @@ import { useForm } from "react-hook-form";
import { getPath } from "routes/path";
import { dateParse, formatDateStr } from "utils/datetime";

export const SearchParam = {
CUSTOMER_NAME: "customer_name",
PARKING_NAME: "parking_name",
INCLUDE_DONE: "include_done",
STATUS: "status",
SMS_PHONE_NUMBER: "sms_phone_number",
HANDLER_NAME: "handler_name",
ORDER_DATE_FROM: "order_date_from",
ORDER_DATE_TO: "order_date_to",
RECEIPT_NO: "receipt_no",
} as const;
export type SearchParam = (typeof SearchParam)[keyof typeof SearchParam];

export default function ReceiptIssuingOrderList() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO,
@@ -73,15 +87,15 @@ function Page() {
}

type FormProps = {
customer_name: string;
parking_name: string;
include_done: boolean;
status: string;
sms_phone_number: string;
handler_name: string;
order_date_from: Date | null;
order_date_to: Date | null;
receipt_no: string;
[SearchParam.CUSTOMER_NAME]: string;
[SearchParam.PARKING_NAME]: string;
[SearchParam.INCLUDE_DONE]: boolean;
[SearchParam.STATUS]: string;
[SearchParam.SMS_PHONE_NUMBER]: string;
[SearchParam.HANDLER_NAME]: string;
[SearchParam.ORDER_DATE_FROM]: Date | null;
[SearchParam.ORDER_DATE_TO]: Date | null;
[SearchParam.RECEIPT_NO]: string;
};
type CommonProps = {
table: UseTableReturn<ReceiptIssuingOrderHTCustom>;
@@ -215,7 +229,7 @@ function SearchBox({ table }: CommonProps) {
<Typography>担当者</Typography>
<Stack direction="row">
<RHFTextField
name="handler_name"
name={SearchParam.HANDLER_NAME}
fullWidth={false}
onBlur={handleBlur}
/>
@@ -232,13 +246,17 @@ function SearchBox({ table }: CommonProps) {
<Grid item xs={3} lg={2}>
<Stack>
<Typography>ステータス</Typography>
<RHFTextField name="status" onBlur={handleBlur} />
<RHFTextField name={SearchParam.STATUS} onBlur={handleBlur} />
</Stack>
</Grid>
<Grid item>
<Stack>
<Typography>完了を含む</Typography>
<RHFCheckbox name="include_done" label="" sx={{ mx: "auto" }} />
<RHFCheckbox
name={SearchParam.INCLUDE_DONE}
label=""
sx={{ mx: "auto" }}
/>
</Stack>
</Grid>
</Grid>
@@ -246,22 +264,31 @@ function SearchBox({ table }: CommonProps) {
<Grid item xs={3} lg={2}>
<Stack>
<Typography>運営会社</Typography>
<RHFTextField name="customer_name" onBlur={handleBlur} />
<RHFTextField
name={SearchParam.CUSTOMER_NAME}
onBlur={handleBlur}
/>
</Stack>
</Grid>
<Grid item xs={3} lg={2}>
<Stack>
<Typography>駐車場名</Typography>
<RHFTextField name="parking_name" onBlur={handleBlur} />
<RHFTextField
name={SearchParam.PARKING_NAME}
onBlur={handleBlur}
/>
</Stack>
</Grid>
<Grid item xs={3} lg={2}>
<Typography>電話番号</Typography>
<RHFTextField name="sms_phone_number" onBlur={handleBlur} />
<RHFTextField
name={SearchParam.SMS_PHONE_NUMBER}
onBlur={handleBlur}
/>
</Grid>
<Grid item xs={3} lg={2}>
<Typography>領収証番号</Typography>
<RHFTextField name="receipt_no" onBlur={handleBlur} />
<RHFTextField name={SearchParam.RECEIPT_NO} onBlur={handleBlur} />
</Grid>
<Grid item xs={3} lg={2}>
<Typography>受付時刻</Typography>
@@ -309,7 +336,7 @@ function SearchBox({ table }: CommonProps) {
<Stack direction="row" spacing={2}>
<Box>
<Typography>From</Typography>
<RHFDatePicker name="order_date_from" />
<RHFDatePicker name={SearchParam.ORDER_DATE_FROM} />
</Box>
<Box>
<Typography>&nbsp;</Typography>
@@ -317,7 +344,7 @@ function SearchBox({ table }: CommonProps) {
</Box>
<Box>
<Typography>To</Typography>
<RHFDatePicker name="order_date_to" />
<RHFDatePicker name={SearchParam.ORDER_DATE_TO} />
</Box>
</Stack>
</DialogContent>
@@ -336,7 +363,7 @@ function SearchBox({ table }: CommonProps) {
}

function TableBox({ table }: CommonProps) {
const TABLE_HEAD = [
const TABLE_HEAD: HeadLabelProps[] = [
{ id: "order_datetime", label: "受付時刻", align: "left" },
{ id: "customer_name", label: "運営会社名", align: "left" },
{ id: "parking_name", label: "駐車場名", align: "left" },


+ 82
- 72
src/pages/dashboard/use-summary/custom/hello-techno/list.tsx Ver arquivo

@@ -2,6 +2,7 @@ import {
Box,
Button,
Grid,
Stack,
Table,
TableBody,
TableCell,
@@ -10,24 +11,31 @@ import {
TableRow,
Typography,
} from "@mui/material";
import { ApiId } from "api";
import {
UseSummary,
getUseSummaries,
getUseSummaryYYYYMMs,
} from "api/custom/hello-techno/use-summary";
import { getFullUrl } from "api/url";
import { PageID, TabID } from "codes/page";
import { FormProvider } from "components/hook-form";
import RHFDatePicker from "components/hook-form/RHFDatePicker";
import RHFSelect, { SelectOptionProps } from "components/hook-form/RHFSelect";
import { TableHeadCustom } from "components/table";
import { HeadLabelProps } from "components/table/TableHeadCustom";
import { SearchConditionContextProvider } from "contexts/SearchConditionContext";
import useAPICall from "hooks/useAPICall";
import useDashboard from "hooks/useDashBoard";
import useNavigateCustom from "hooks/useNavigateCustom";
import useSearchConditionContext from "hooks/useSearchConditionContext";
import useTable, { UseTableReturn } from "hooks/useTable";
import { SearchParam } from "pages/dashboard/receipt-issuing-order/custom/hello-techno/list";
import { useEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { getPath } from "routes/path";
import { sprintf } from "sprintf-js";
import { dateParse, formatDateStr } from "utils/datetime";

export default function UseSummaryList() {
const { setHeaderTitle, setTabs } = useDashboard(
@@ -60,7 +68,8 @@ function Page() {
}

type FormProps = {
summary_yyyymm: string;
date_from: Date | null;
date_to: Date | null;
};

type CommonProps = {
@@ -76,50 +85,15 @@ function SearchBox({ table }: CommonProps) {

const form = useForm<FormProps>({
defaultValues: {
summary_yyyymm: "",
date_from: null,
date_to: null,
},
});

const selectedYYYYMM = form.watch("summary_yyyymm");
const dateFrom = form.watch("date_from");
const dateTo = form.watch("date_to");

const [yyyymm, setYYYYMM] = useState<string[] | null>(null);

const yyyymmOptions: SelectOptionProps[] = useMemo(() => {
if (yyyymm === null) return [];
return yyyymm.map((ele) => {
return {
value: ele,
label: sprintf("%s/%s", ele.substring(0, 4), ele.substring(4, 6)),
};
});
}, [yyyymm]);

const downloadCsvUrl = useMemo(() => {
if (!selectedYYYYMM) return "";
const param = new URLSearchParams({
summary_yyyymm: selectedYYYYMM,
});

return (
process.env.REACT_APP_HOST_API_KEY +
"/custom/hello-techno/use-summary/csv?" +
param.toString()
);
}, [selectedYYYYMM]);

const { callAPI: callGetUseSummaryYYYYMMs } = useAPICall({
apiMethod: getUseSummaryYYYYMMs,
backDrop: true,
onSuccess: ({ data: { records } }) => {
setYYYYMM(records);
},
});

const {
callAPI: callGetContracts,
makeSendData,
sending,
} = useAPICall({
const { callAPI: callGetContracts } = useAPICall({
apiMethod: getUseSummaries,
backDrop: true,
onSuccess: ({ data }) => {
@@ -134,61 +108,59 @@ function SearchBox({ table }: CommonProps) {
const addCondition = (data: FormProps) => {
add({
...data,
date_from: formatDateStr(data.date_from),
date_to: formatDateStr(data.date_to),
});
};

const fetch = async () => {
const dateFrom = form.getValues("date_from");
const dateTo = form.getValues("date_to");
if (!dateFrom || !dateTo) return;
const sendData = {
...condition,
...form.getValues(),
date_from: formatDateStr(dateFrom),
date_to: formatDateStr(dateTo),
};

if (sendData.summary_yyyymm) {
callGetContracts(sendData);
}
callGetContracts(sendData);
};

// 初期値設定
useEffect(() => {
if (initialized && yyyymm !== null) {
form.setValue(
"summary_yyyymm",
get("summary_yyyymm", yyyymm.find(() => true) ?? "")
);
addCondition(form.getValues());
if (initialized) {
form.setValue("date_from", dateParse(get("date_from")));
form.setValue("date_to", dateParse(get("date_to")));
}
}, [initialized, condition, yyyymm]);
}, [initialized]);

// Fetchアクション
useEffect(() => {
if (initialized) {
fetch();
}
}, [condition, initialized, selectedYYYYMM]);
}, [condition, initialized]);

useEffect(() => {
callGetUseSummaryYYYYMMs({});
}, []);
addCondition(form.getValues());
}, [dateFrom, dateTo]);

return (
<FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}>
<Box sx={{ p: 1, m: 1 }}>
<Grid container spacing={2}>
<Grid item xs={3} lg={2}>
<Typography>年月</Typography>
<RHFSelect
options={yyyymmOptions}
name="summary_yyyymm"
<Typography>開始年月日</Typography>
<RHFDatePicker
name="date_from"
size="small"
onChange={() => {
console.log("ge");
}}
/>
</Grid>
{!!selectedYYYYMM && (
<Grid item xs={3} lg={2}>
<Typography>CSV</Typography>
<Button variant="contained" color="info" href={downloadCsvUrl}>
ダウンロード
</Button>
</Grid>
)}
<Grid item xs={3} lg={2}>
<Typography>終了年月日</Typography>
<RHFDatePicker name="date_to" size="small" />
</Grid>
</Grid>
</Box>
</FormProvider>
@@ -196,12 +168,12 @@ function SearchBox({ table }: CommonProps) {
}

function TableBox({ table }: CommonProps) {
const TABLE_HEAD = [
const TABLE_HEAD: HeadLabelProps[] = [
{ id: "customer_name", label: "運営会社名", align: "left" },
{ id: "parking_name", label: "駐車場名", align: "left" },
{ id: "receipt_order_count", label: "領収証発行件数", align: "left" },
{ id: "mail_order_count", label: "郵送依頼件数", align: "left" },
{ id: "sms_send_count", label: "SMS送信件数", align: "left" },
{ id: "actions", label: "アクション", align: "left", needSort: false },
];
const {
order,
@@ -267,13 +239,51 @@ type RowProps = {
data: UseSummary;
};
function Row({ data }: RowProps) {
const { navigateWhenChanged } = useNavigateCustom();

const handleClickDetail = () => {
const param = new URLSearchParams({
[SearchParam.CUSTOMER_NAME]: data.customer_name,
[SearchParam.ORDER_DATE_FROM]: data.date_from,
[SearchParam.ORDER_DATE_TO]: data.date_to,
[SearchParam.INCLUDE_DONE]: "1",
});
navigateWhenChanged(
getPath(PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO),
param
);
};

const downloadCsvUrl = useMemo(() => {
const param = new URLSearchParams({
date_from: data.date_from,
date_to: data.date_to,
customer_code: data.customer_code,
});

return (
getFullUrl(ApiId.HT_CUSTOM_USE_SUMMARY_DOWNLOAD_CSV) +
"?" +
param.toString()
);
}, [data]);

return (
<TableRow>
<TableCell>{data.customer_name}</TableCell>
<TableCell>{data.parking_name}</TableCell>
<TableCell>{data.receipt_order_count}件</TableCell>
<TableCell>{data.mail_order_count}件</TableCell>
<TableCell>{data.sms_send_count}件</TableCell>
<TableCell>
<Stack direction="row" spacing={2}>
<Button variant="contained" onClick={handleClickDetail}>
詳細
</Button>
<Button variant="contained" href={downloadCsvUrl}>
CSV
</Button>
</Stack>
</TableCell>
</TableRow>
);
}

Carregando…
Cancelar
Salvar