初步完成人工充值页面;完成数据统计页面

This commit is contained in:
yezian 2024-01-04 14:40:05 +08:00
parent fce15a60d7
commit 99c6f600a8
4 changed files with 171 additions and 43 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";
import { Form, Input, Table, Image, Space, Button, Modal, Radio } from "antd";
import baseRequest from "../../utils/baseRequest";
import { generateSignature } from "../../utils/crypto";
const ManualRechargeAndWithdrawalContent = (props) => {
const { TextArea } = Input;
@ -134,10 +133,7 @@ const ManualRechargeAndWithdrawalContent = (props) => {
const modalSearch = async (value) => {
try {
const base = baseRequest();
const signature = generateSignature();
const response = await fetch(
`/op/account/list_by_user_id?signature=${signature}`,
{
const response = await fetch(`/op/account/list_by_user_id`, {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -146,8 +142,7 @@ const ManualRechargeAndWithdrawalContent = (props) => {
user_id: parseInt(value.userId, 10),
...base,
}),
}
);
});
const data = await response.json();
if (data.ret === -1) {
alert(data.msg);
@ -177,15 +172,7 @@ const ManualRechargeAndWithdrawalContent = (props) => {
try {
const base = baseRequest();
const signature = generateSignature({
mid: selectedUser,
coins: parseInt(value.num, 10),
operator: base.b_mid.toString(),
...base,
});
const response = await fetch(
`/op/vas/create_order?signature=${signature}`,
{
const response = await fetch(`/op/vas/create_order`, {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -193,18 +180,15 @@ const ManualRechargeAndWithdrawalContent = (props) => {
body: JSON.stringify({
mid: selectedUser,
coins: parseInt(value.num, 10),
operator: base.b_mid.toString(),
operator: value.password,
...base,
}),
}
);
});
const data = await response.json();
console.log(data);
if (data.ret === -1) {
alert(data.msg);
return;
}
setUserInfo(data.data.account);
} catch (error) {
console.error(error);
}
@ -342,6 +326,19 @@ const ManualRechargeAndWithdrawalContent = (props) => {
>
<Input className="w-32" type="number" min={0} max={10000} />
</Form.Item>
<Form.Item
label="支付密码"
name="password"
rules={[
{
required: true,
message: "未填写",
},
]}
style={{ margin: 0 }}
>
<Input className="w-32" type="password" min={0} max={10000} />
</Form.Item>
<Button className="ml-8" type="primary" htmlType="submit">
确认
</Button>

133
src/pages/Op/data.jsx Normal file
View File

@ -0,0 +1,133 @@
import React, { useState, useEffect } from "react";
import baseRequest from "../../utils/baseRequest";
import { DatePicker, Table } from "antd";
export default function Data() {
const { RangePicker } = DatePicker;
const [data, setData] = useState();
//
const currentTimestamp = Date.now();
// 2
const oneHourAgoTimestamp = currentTimestamp - 7200000; // 1 = 60 * 60 * 1000
const [selectTime, setSelectTime] = useState({
ct_lower_bound: oneHourAgoTimestamp,
ct_upper_bound: currentTimestamp,
});
useEffect(() => {
const getData = async () => {
try {
const base = baseRequest();
const response = await fetch(`/op/daily_statement/list`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
ct_lower_bound: Math.floor(selectTime.ct_lower_bound / 1000),
ct_upper_bound: Math.floor(selectTime.ct_upper_bound / 1000),
offset: 0,
limit: 100,
...base,
}),
});
const _data = await response.json();
const structedData = _data.data.list.map((item, index) => {
return {
key: index,
time: {
start: new Date(item.start_time * 1000).toLocaleString(),
end: new Date(item.end_time * 1000).toLocaleString(),
},
h5_call_count: item.h5_call_count,
registered_user_count: item.registered_user_count,
order_created_count: item.order_created_count,
order_finished_count: item.order_finished_count,
};
});
setData(structedData);
if (_data.ret === -1) {
alert(_data.msg);
return;
}
} catch (error) {
console.error(error);
}
};
getData();
}, [selectTime]);
const onOk = (value) => {
const startTimeStamp = value[0] && value[0].valueOf() - 60000; //
const endTimeStamp = value[1] && value[1].valueOf() + 60000; //
setSelectTime({
ct_lower_bound: startTimeStamp,
ct_upper_bound: endTimeStamp,
});
};
//
const columns = [
{
title: "时段",
dataIndex: "time",
key: "time",
render: (data) => {
return (
<div>
<p>
<span className="text-green-400">开始时间</span>
{data.start}
</p>
<p>
<span className="text-red-400">结束时间</span>
{data.end}
</p>
</div>
);
},
},
{
title: "当日页面访问",
dataIndex: "h5_call_count",
key: "h5_call_count",
},
{
title: "总注册",
dataIndex: "registered_user_count",
key: "registered_user_count",
},
{
title: "总订单创建",
dataIndex: "order_created_count",
key: "order_created_count",
},
{
title: "总订单完成",
dataIndex: "order_finished_count",
key: "order_finished_count",
},
];
return (
<div className="px-4">
<h1>数据统计</h1>
<p>请选择时段</p>
<RangePicker
showTime={{
format: "HH:mm",
}}
showNow
format="YYYY-MM-DD HH:mm"
onOk={onOk}
/>
<Table
columns={columns}
dataSource={data}
pagination={{ pageSize: 20 }}
scroll={{ y: window.innerHeight - 300 }}
/>
</div>
);
}

View File

@ -16,6 +16,7 @@ import {
import { Menu, Layout } from "antd";
import { Outlet, useNavigate, useLocation } from "react-router-dom";
import { checkAuth, signOut } from "../../utils/auth";
import Data from "./data";
export default function Op() {
const { Content, Sider } = Layout;
@ -92,11 +93,8 @@ export default function Op() {
zIndex: 999,
}}
>
<div className="op-logo">
<img
src="https://s2.loli.net/2023/08/03/mu51haYNUOPXkqR.png"
alt=""
/>
<div onClick={() => navigate("/")} className="op-logo">
<img src="/images/icon_border.png" alt="" />
<h2>铁粉空间运营</h2>
</div>
<Menu
@ -118,7 +116,7 @@ export default function Op() {
overflow: "initial",
}}
>
{location.pathname === "/" && <h1>好兄弟辛苦了加油奥利给</h1>}
{location.pathname === "/" && <Data />}
<Outlet />
</Content>
</Layout>