From 9950691ce49ae0a1f3f1bcbadd68dbc79282b953 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Mon, 19 Jun 2023 14:34:44 +0900 Subject: [PATCH] =?UTF-8?q?=E5=88=A9=E7=94=A8=E5=AE=9F=E7=B8=BE=E4=B8=80?= =?UTF-8?q?=E8=A6=A7=E3=80=80=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/custom/hello-techno/use-summary.ts | 65 ++++ src/api/index.ts | 7 + src/api/url.ts | 4 + src/codes/page.ts | 3 + src/contexts/SearchConditionContext.tsx | 6 +- src/layouts/dashbord/navigator.tsx | 11 + .../custom/hello-techno/detail.tsx | 72 +++++ .../use-summary/custom/hello-techno/list.tsx | 278 ++++++++++++++++++ src/routes/auth.ts | 10 + src/routes/index.tsx | 16 + src/routes/path.ts | 6 + src/utils/datetime.ts | 10 +- 12 files changed, 482 insertions(+), 6 deletions(-) create mode 100644 src/api/custom/hello-techno/use-summary.ts create mode 100644 src/pages/dashboard/use-summary/custom/hello-techno/detail.tsx create mode 100644 src/pages/dashboard/use-summary/custom/hello-techno/list.tsx diff --git a/src/api/custom/hello-techno/use-summary.ts b/src/api/custom/hello-techno/use-summary.ts new file mode 100644 index 0000000..2cb985f --- /dev/null +++ b/src/api/custom/hello-techno/use-summary.ts @@ -0,0 +1,65 @@ +import { + APICommonResponse, + ApiId, + HttpMethod, + ListRequest, + request, +} from "../.."; +import { getUrl } from "../../url"; + +export type UseSummary = { + id: string; + + summary_yyyymm: string; + summary_key1: string; + summary_key2?: string; + + customer_name: string; + parking_name?: string; + + receipt_order_count: string; + sms_send_count: string; + sms_send_cost: string; + + is_fixed: boolean; + + updated_at: string; +}; + +// 利用実績一覧取得 ----------------------- +export type UseSummariesRequest = { + summary_yyyymm: string; +} & ListRequest; + +export type UseSummariesResponse = { + data: { + records: UseSummary[]; + }; +} & APICommonResponse; + +export const getUseSummaries = async (data: UseSummariesRequest) => { + const res = await request({ + url: getUrl(ApiId.HT_CUSTOM_USE_SUMMARIES), + method: HttpMethod.GET, + data: new URLSearchParams(data), + }); + return res; +}; + +// 利用実績年月取得 ----------------------- +export type UseSummaryYYYYMMsRequest = {}; + +export type UseSummaryYYYYMMsResponse = { + data: { + records: string[]; + }; +} & APICommonResponse; + +export const getUseSummaryYYYYMMs = async (data: UseSummaryYYYYMMsRequest) => { + const res = await request({ + url: getUrl(ApiId.USE_SUMMARY_YYYYMM), + method: HttpMethod.GET, + data: new URLSearchParams(data), + }); + return res; +}; diff --git a/src/api/index.ts b/src/api/index.ts index f3052d5..d8331c7 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -29,6 +29,8 @@ export const ApiId = { CONTRACTS: id++, + USE_SUMMARY_YYYYMM: id++, + LOGIN_USERS: id++, LOGIN_USER_CREATE: id++, LOGIN_USER_CHANGE_PASSWORD: id++, @@ -39,6 +41,7 @@ export const ApiId = { HT_CUSTOM_ADJUST_DATA: id++, HT_CUSTOM_RECEIPT_ISSUING_ORDERS: id++, HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE: id++, + HT_CUSTOM_USE_SUMMARIES: id++, } as const; export type ApiId = (typeof ApiId)[keyof typeof ApiId]; @@ -59,6 +62,10 @@ export type ResultCode = (typeof ResultCode)[keyof typeof ResultCode]; export interface TimestampRequest { timestamp: string; } +export type ListRequest = { + sort?: string; + order?: string; +}; export interface APICommonResponse { result: ResultCode; diff --git a/src/api/url.ts b/src/api/url.ts index 3a5410d..2a9a358 100644 --- a/src/api/url.ts +++ b/src/api/url.ts @@ -19,6 +19,9 @@ const urls = { [A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders", [A.CONTRACTS]: "contracts", + + [A.USE_SUMMARY_YYYYMM]: "use-summary/yyyymm", + [A.LOGIN_USERS]: "users", [A.LOGIN_USER_CREATE]: "user/create", [A.LOGIN_USER_CHANGE_PASSWORD]: "user/change-password", @@ -31,6 +34,7 @@ const urls = { "custom/hello-techno/receipt-issuing-orders", [A.HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE]: "custom/hello-techno/receipt-issuing-order/create", + [A.HT_CUSTOM_USE_SUMMARIES]: "custom/hello-techno/use-summaries", }; const prefixs = { diff --git a/src/codes/page.ts b/src/codes/page.ts index c6eb24d..232ed69 100644 --- a/src/codes/page.ts +++ b/src/codes/page.ts @@ -18,6 +18,9 @@ export const PageID = { DASHBOARD_RECEIPT_ISSUING_ORDER_LIST_CUSTOM_HELLO_TECHNO: id++, DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO: id++, + DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO: id++, + DASHBOARD_USE_SUMMARY_DETAIL_CUSTOM_HELLO_TECHNO: id++, + DASHBOARD_LOGIN_USER_LIST: id++, DASHBOARD_LOGIN_USER_CREATE: id++, DASHBOARD_LOGIN_USER_CHANGE_PASSWORD: id++, diff --git a/src/contexts/SearchConditionContext.tsx b/src/contexts/SearchConditionContext.tsx index 409696d..98a96bb 100644 --- a/src/contexts/SearchConditionContext.tsx +++ b/src/contexts/SearchConditionContext.tsx @@ -12,7 +12,7 @@ const _condition: Dictionary = {}; const initialState = { initialized: false, condition: _condition, - get: (key: string): string => "", + get: (key: string, defaultValue?: string): string => "", initializeCondition: () => {}, addCondition: (condition: Dictionary) => { console.log("not init SearchConditionContext"); @@ -52,8 +52,8 @@ export function SearchConditionContextProvider({ children }: Props) { setInitialized(true); }; - const get = (key: string) => { - return condition[key] ?? ""; + const get = (key: string, defaultValue?: string) => { + return condition[key] ?? defaultValue ?? ""; }; const getCondition = useMemo(() => { diff --git a/src/layouts/dashbord/navigator.tsx b/src/layouts/dashbord/navigator.tsx index 1c26580..092f416 100644 --- a/src/layouts/dashbord/navigator.tsx +++ b/src/layouts/dashbord/navigator.tsx @@ -4,6 +4,7 @@ import PeopleIcon from "@mui/icons-material/People"; import ArticleIcon from "@mui/icons-material/Article"; import SettingsIcon from "@mui/icons-material/Settings"; import AccountBoxIcon from "@mui/icons-material/AccountBox"; +import AccountBalanceIcon from "@mui/icons-material/AccountBalance"; import { Collapse } from "@mui/material"; import Box from "@mui/material/Box"; import Divider from "@mui/material/Divider"; @@ -93,6 +94,16 @@ export default function Navigator(props: DrawerProps) { }, ], }, + { + label: "利用実績", + icon: , + children: [ + { + id: PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO, + label: "一覧", + }, + ], + }, { label: "ユーザ管理", icon: , diff --git a/src/pages/dashboard/use-summary/custom/hello-techno/detail.tsx b/src/pages/dashboard/use-summary/custom/hello-techno/detail.tsx new file mode 100644 index 0000000..7bef8e5 --- /dev/null +++ b/src/pages/dashboard/use-summary/custom/hello-techno/detail.tsx @@ -0,0 +1,72 @@ +import { + Box, + Button, + Grid, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, + Typography, +} from "@mui/material"; +import { PageID, TabID } from "codes/page"; +import { RHFTextField } from "components/hook-form"; +import useDashboard from "hooks/useDashBoard"; +import { useEffect } from "react"; + +export default function UseSummaryList() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.DASHBOARD_USE_SUMMARY_DETAIL_CUSTOM_HELLO_TECHNO, + TabID.NONE + ); + + useEffect(() => { + setHeaderTitle("利用実績詳細"); + setTabs(null); + }, []); + return ( + <> + + + + 運営会社 + 京都 + + + 対象月 + 2023/05 + + + + + + + + + + + 駐車場名 + 領収証発行件数 + + + + A駐車場 + 1件 + + + B駐車場 + 3件 + + +
+
+ + ); +} diff --git a/src/pages/dashboard/use-summary/custom/hello-techno/list.tsx b/src/pages/dashboard/use-summary/custom/hello-techno/list.tsx new file mode 100644 index 0000000..06f0ae3 --- /dev/null +++ b/src/pages/dashboard/use-summary/custom/hello-techno/list.tsx @@ -0,0 +1,278 @@ +import { + Box, + Grid, + Stack, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TablePagination, + TableRow, + TextField, + Typography, +} from "@mui/material"; +import { Dictionary } from "@types"; +import { + UseSummary, + getUseSummaries, + getUseSummaryYYYYMMs, +} from "api/custom/hello-techno/use-summary"; +import { PageID, TabID } from "codes/page"; +import { FormProvider, RHFTextField } from "components/hook-form"; +import RHFSelect, { SelectOptionProps } from "components/hook-form/RHFSelect"; +import { TableHeadCustom } from "components/table"; +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 { useEffect, useMemo, useState } from "react"; +import { useForm } from "react-hook-form"; +import { getPath } from "routes/path"; +import { sprintf } from "sprintf-js"; +import { formatYYYYMMStr, now } from "utils/datetime"; + +export default function UseSummaryList() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO, + TabID.NONE + ); + + const { navigateWhenChanged } = useNavigateCustom(); + + useEffect(() => { + setHeaderTitle("利用実績一覧"); + setTabs(null); + }, []); + + return ( + + + + ); +} + +function Page() { + const table = useTable(); + return ( + + + + + ); +} + +type FormProps = { + summary_yyyymm: string; +}; + +type CommonProps = { + table: UseTableReturn; +}; +function SearchBox({ table }: CommonProps) { + const { + condition, + initialized, + get, + addCondition: add, + } = useSearchConditionContext(); + + const form = useForm({ + defaultValues: { + summary_yyyymm: "", + }, + }); + + const selectedYYYYMM = form.watch("summary_yyyymm"); + + const [yyyymm, setYYYYMM] = useState(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 { callAPI: callGetUseSummaryYYYYMMs } = useAPICall({ + apiMethod: getUseSummaryYYYYMMs, + onSuccess: ({ data: { records } }) => { + setYYYYMM(records); + }, + }); + + const { + callAPI: callGetContracts, + makeSendData, + sending, + } = useAPICall({ + apiMethod: getUseSummaries, + backDrop: true, + onSuccess: ({ data }) => { + table.setRowData(data.records); + }, + }); + + const handleSubmit = async (data: FormProps) => { + addCondition(data); + }; + + const addCondition = (data: FormProps) => { + add({ + ...data, + }); + }; + const handleBlur = () => { + addCondition(form.getValues()); + }; + + const fetch = async () => { + const sendData = { + ...form.getValues(), + }; + + if (sendData.summary_yyyymm) { + callGetContracts(sendData); + } + }; + + // 初期値設定 + useEffect(() => { + if (initialized && yyyymm !== null) { + form.setValue( + "summary_yyyymm", + get("summary_yyyymm", yyyymm.find(() => true) ?? "") + ); + addCondition(form.getValues()); + } + }, [initialized, condition, yyyymm]); + + // Fetchアクション + useEffect(() => { + if (initialized) { + fetch(); + } + }, [condition, initialized, selectedYYYYMM]); + + useEffect(() => { + callGetUseSummaryYYYYMMs({}); + }, []); + + return ( + + + + + 年月 + {/* */} + + + + + + ); +} + +function TableBox({ table }: CommonProps) { + const TABLE_HEAD = [ + { id: "customer_name", label: "運営会社名", align: "left" }, + { id: "parking_name", label: "駐車場名", align: "left" }, + { id: "receipt_order_count", label: "領収証発行件数", align: "left" }, + // { id: "", label: "郵送件数", align: "left" }, + { id: "sms_send_count", label: "SMS送信件数", align: "left" }, + ]; + const { + order, + page, + sort, + rowsPerPage, + fetched, + fillteredRow, + isNotFound, + dataLength, + // + onSort, + onChangePage, + onChangeRowsPerPage, + // + setRowData, + // + ROWS_PER_PAGES, + } = table; + + return ( + <> + + + + + + {fillteredRow.map((row, index) => ( + + ))} + +
+
+ + + + + + ); +} + +type RowProps = { + data: UseSummary; +}; +function Row({ data }: RowProps) { + const { navigateWhenChanged } = useNavigateCustom(); + + const handleClick = () => { + // navigateWhenChanged(getPath(PageID.DASHBOARD_CONTRACT_DETAIL), { + // id: data.id, + // }); + }; + + return ( + + {data.customer_name} + {data.parking_name} + {data.receipt_order_count}件 + {/* {data.parking_name} */} + {data.sms_send_count}件 + + ); +} diff --git a/src/routes/auth.ts b/src/routes/auth.ts index 599b995..df676bb 100644 --- a/src/routes/auth.ts +++ b/src/routes/auth.ts @@ -32,6 +32,16 @@ export const AUTH = { R.NORMAL_ADMIN, [C.HELLO_TECHNO] ), + [P.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO]: setAuth( + "ge", + R.NORMAL_ADMIN, + [C.HELLO_TECHNO] + ), + [P.DASHBOARD_USE_SUMMARY_DETAIL_CUSTOM_HELLO_TECHNO]: setAuth( + "ge", + R.NORMAL_ADMIN, + [C.HELLO_TECHNO] + ), [P.DASHBOARD_LOGIN_USER_LIST]: setAuth("ge", R.CONTRACT_ADMIN), [P.DASHBOARD_LOGIN_USER_CREATE]: setAuth("ge", R.CONTRACT_ADMIN), [P.DASHBOARD_LOGIN_USER_CHANGE_PASSWORD]: setAuth("ge", R.NORMAL_ADMIN), diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 42fe350..76203c9 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -81,6 +81,14 @@ const DashboardRoutes = (): RouteObject => { pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO, element: , }, + { + pageId: PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO, + element: , + }, + { + pageId: PageID.DASHBOARD_USE_SUMMARY_DETAIL_CUSTOM_HELLO_TECHNO, + element: , + }, { pageId: PageID.DASHBOARD_LOGIN_USER_LIST, element: , @@ -169,6 +177,14 @@ const ReceiptIssuingOrderDetailHelloTechno = Loadable( ) ); +// 利用実績関連 +const UseSummaryListHelloTechno = Loadable( + lazy(() => import("pages/dashboard/use-summary/custom/hello-techno/list")) +); +const UseSummaryDetailHelloTechno = Loadable( + lazy(() => import("pages/dashboard/use-summary/custom/hello-techno/detail")) +); + // ログインユーザー管理 const LoginUserList = Loadable( lazy(() => import("pages/dashboard/login-user/list")) diff --git a/src/routes/path.ts b/src/routes/path.ts index 79946db..2728b51 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -61,6 +61,12 @@ const PATHS = { PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO )]: "/dashboard/receipt-issusing-order/detail/:id", + // 利用実績関連 + [makePathKey(PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO)]: + "/dashboard/use-summary/hello-techno/list", + [makePathKey(PageID.DASHBOARD_USE_SUMMARY_DETAIL_CUSTOM_HELLO_TECHNO)]: + "/dashboard/use-summary/hello-techno/detail", + // ログインユーザ管理 [makePathKey(PageID.DASHBOARD_LOGIN_USER_LIST)]: "/dashboard/login-user/list/:page", diff --git a/src/utils/datetime.ts b/src/utils/datetime.ts index 71a2ddc..f3e243a 100644 --- a/src/utils/datetime.ts +++ b/src/utils/datetime.ts @@ -1,7 +1,8 @@ import { format, isValid, parse, parseISO } from "date-fns"; export const DEFAULT_DATE_FORMAT = "yyyy/MM/dd"; -export const DEFAULT_DATET_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss"; +export const DEFAULT_DATE_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss"; +export const DEFAULT_YYYYMM_FORMAT = "yyyyMM"; type Input = Date | string | null | undefined; @@ -10,7 +11,10 @@ export const formatDateStr = (source: Input) => { }; export const formatDateTimeStr = (source: Date | string | null | undefined) => { - return formatToStr(source, DEFAULT_DATET_TIME_FORMAT); + return formatToStr(source, DEFAULT_DATE_TIME_FORMAT); +}; +export const formatYYYYMMStr = (source: Date | string | null | undefined) => { + return formatToStr(source, DEFAULT_YYYYMM_FORMAT); }; const formatToStr = (source: Input, formatStr: string) => { @@ -31,7 +35,7 @@ export const dateParse = (source: Input): Date | null => { }; export const dateTimeParse = (source: Input): Date | null => { - return parseFromFormat(source, DEFAULT_DATET_TIME_FORMAT); + return parseFromFormat(source, DEFAULT_DATE_TIME_FORMAT); }; const parseFromFormat = (source: Input, format: string): Date | null => {