Explorar el Código

利用実績一覧 追加

develop
sosuke.iwabuchi hace 2 años
padre
commit
9950691ce4
Se han modificado 12 ficheros con 482 adiciones y 6 borrados
  1. +65
    -0
      src/api/custom/hello-techno/use-summary.ts
  2. +7
    -0
      src/api/index.ts
  3. +4
    -0
      src/api/url.ts
  4. +3
    -0
      src/codes/page.ts
  5. +3
    -3
      src/contexts/SearchConditionContext.tsx
  6. +11
    -0
      src/layouts/dashbord/navigator.tsx
  7. +72
    -0
      src/pages/dashboard/use-summary/custom/hello-techno/detail.tsx
  8. +278
    -0
      src/pages/dashboard/use-summary/custom/hello-techno/list.tsx
  9. +10
    -0
      src/routes/auth.ts
  10. +16
    -0
      src/routes/index.tsx
  11. +6
    -0
      src/routes/path.ts
  12. +7
    -3
      src/utils/datetime.ts

+ 65
- 0
src/api/custom/hello-techno/use-summary.ts Ver fichero

@@ -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<UseSummariesResponse>({
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<UseSummaryYYYYMMsResponse>({
url: getUrl(ApiId.USE_SUMMARY_YYYYMM),
method: HttpMethod.GET,
data: new URLSearchParams(data),
});
return res;
};

+ 7
- 0
src/api/index.ts Ver fichero

@@ -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;


+ 4
- 0
src/api/url.ts Ver fichero

@@ -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 = {


+ 3
- 0
src/codes/page.ts Ver fichero

@@ -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++,


+ 3
- 3
src/contexts/SearchConditionContext.tsx Ver fichero

@@ -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(() => {


+ 11
- 0
src/layouts/dashbord/navigator.tsx Ver fichero

@@ -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: <AccountBalanceIcon />,
children: [
{
id: PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO,
label: "一覧",
},
],
},
{
label: "ユーザ管理",
icon: <PeopleIcon />,


+ 72
- 0
src/pages/dashboard/use-summary/custom/hello-techno/detail.tsx Ver fichero

@@ -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 (
<>
<Box sx={{ p: 1, m: 1 }}>
<Grid container spacing={2}>
<Grid item>
<Typography>運営会社</Typography>
<Typography>京都</Typography>
</Grid>
<Grid item>
<Typography>対象月</Typography>
<Typography>2023/05</Typography>
</Grid>
<Grid item xs />
<Grid item>
<Button variant="contained">CSVダウンロード</Button>
</Grid>
</Grid>
</Box>
<TableContainer
sx={{
// minWidth: 800,
position: "relative",
}}
>
<Table size="small">
<TableHead>
<TableCell>駐車場名</TableCell>
<TableCell>領収証発行件数</TableCell>
</TableHead>
<TableBody>
<TableRow>
<TableCell>A駐車場</TableCell>
<TableCell>1件</TableCell>
</TableRow>
<TableRow>
<TableCell>B駐車場</TableCell>
<TableCell>3件</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</>
);
}

+ 278
- 0
src/pages/dashboard/use-summary/custom/hello-techno/list.tsx Ver fichero

@@ -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 (
<SearchConditionContextProvider>
<Page />
</SearchConditionContextProvider>
);
}

function Page() {
const table = useTable<UseSummary>();
return (
<Box>
<SearchBox table={table} />
<TableBox table={table} />
</Box>
);
}

type FormProps = {
summary_yyyymm: string;
};

type CommonProps = {
table: UseTableReturn<UseSummary>;
};
function SearchBox({ table }: CommonProps) {
const {
condition,
initialized,
get,
addCondition: add,
} = useSearchConditionContext();

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

const selectedYYYYMM = form.watch("summary_yyyymm");

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 { 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 (
<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>
{/* <RHFTextField
name="summary_yyyymm"
placeholder="YYYYMM"
onBlur={handleBlur}
/> */}
<RHFSelect
options={yyyymmOptions}
name="summary_yyyymm"
size="small"
/>
</Grid>
</Grid>
</Box>
</FormProvider>
);
}

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 (
<>
<TableContainer
sx={{
// minWidth: 800,
position: "relative",
}}
>
<Table size="small">
<TableHeadCustom
order={order}
orderBy={sort}
headLabel={TABLE_HEAD}
rowCount={1}
numSelected={0}
onSort={onSort}
/>

<TableBody>
{fillteredRow.map((row, index) => (
<Row data={row} key={index} />
))}
</TableBody>
</Table>
</TableContainer>

<Box sx={{ position: "relative" }}>
<TablePagination
rowsPerPageOptions={ROWS_PER_PAGES}
component="div"
count={dataLength}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={onChangePage}
onRowsPerPageChange={onChangeRowsPerPage}
/>
</Box>
</>
);
}

type RowProps = {
data: UseSummary;
};
function Row({ data }: RowProps) {
const { navigateWhenChanged } = useNavigateCustom();

const handleClick = () => {
// navigateWhenChanged(getPath(PageID.DASHBOARD_CONTRACT_DETAIL), {
// id: data.id,
// });
};

return (
<TableRow hover sx={{ cursor: "pointer" }} onClick={handleClick}>
<TableCell>{data.customer_name}</TableCell>
<TableCell>{data.parking_name}</TableCell>
<TableCell>{data.receipt_order_count}件</TableCell>
{/* <TableCell>{data.parking_name}</TableCell> */}
<TableCell>{data.sms_send_count}件</TableCell>
</TableRow>
);
}

+ 10
- 0
src/routes/auth.ts Ver fichero

@@ -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),


+ 16
- 0
src/routes/index.tsx Ver fichero

@@ -81,6 +81,14 @@ const DashboardRoutes = (): RouteObject => {
pageId: PageID.DASHBOARD_RECEIPT_ISSUING_ORDER_DETAIL_CUSTOM_HELLO_TECHNO,
element: <ReceiptIssuingOrderDetailHelloTechno />,
},
{
pageId: PageID.DASHBOARD_USE_SUMMARY_LIST_CUSTOM_HELLO_TECHNO,
element: <UseSummaryListHelloTechno />,
},
{
pageId: PageID.DASHBOARD_USE_SUMMARY_DETAIL_CUSTOM_HELLO_TECHNO,
element: <UseSummaryDetailHelloTechno />,
},
{
pageId: PageID.DASHBOARD_LOGIN_USER_LIST,
element: <LoginUserList />,
@@ -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"))


+ 6
- 0
src/routes/path.ts Ver fichero

@@ -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",


+ 7
- 3
src/utils/datetime.ts Ver fichero

@@ -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 => {


Cargando…
Cancelar
Guardar