Browse Source

feat: 暂存

lihao
nili 4 months ago
parent
commit
305ad8fa5b
  1. 9
      config/routes.ts
  2. 64
      src/pages/App/AppManagement.tsx
  3. 201
      src/pages/App/CashConfigForm.tsx
  4. 117
      src/pages/App/NormalAppManagement.tsx
  5. 2
      src/services/matrix/admin.ts
  6. 18
      src/services/matrix/citrusAppController.ts
  7. 10
      src/services/matrix/index.ts
  8. 38
      src/services/matrix/matrixAppController.ts
  9. 36
      src/services/matrix/openController.ts
  10. 105
      src/services/matrix/typings.d.ts
  11. 46
      src/services/matrix/userController.ts

9
config/routes.ts

@ -1,5 +1,4 @@
 /**
/**
* @name umi * @name umi
* @description path,component,routes,redirect,wrappers,name,icon * @description path,component,routes,redirect,wrappers,name,icon
* @param path path 第一种是动态参数 :id * * @param path path 第一种是动态参数 :id *
@ -54,19 +53,19 @@ export default [
path: '/adminList', path: '/adminList',
name: '人员管理', name: '人员管理',
access: 'canAdmin', access: 'canAdmin',
component: './AdminManagement' component: './AdminManagement',
}, },
{ {
path: '/bind', path: '/bind',
name: '绑定设备', name: '绑定设备',
access: 'canDeviceOwner', access: 'canDeviceOwner',
component: './Bind' component: './Bind',
}, },
{ {
path: '/appList', path: '/appList',
name: '应用管理', name: '应用管理',
access: 'canAdmin', access: 'canAdmin',
component: './AppManagement' component: './App/AppManagement',
}, },
{ {
path: '/', path: '/',

64
src/pages/AppManagement.tsx → src/pages/App/AppManagement.tsx

@ -4,6 +4,7 @@ import { Button, Form, Input, Modal, Popover, QRCode, Select, Tag } from 'antd';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { appList, saveApp } from '@/services/matrix/admin'; import { appList, saveApp } from '@/services/matrix/admin';
import NormalAppManagement from './NormalAppManagement';
const AppManagement = () => { const AppManagement = () => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
@ -13,15 +14,15 @@ const AppManagement = () => {
const [filteredAppArr, setFilteredAppArr] = useState<API.MatrixApp[]>([]); const [filteredAppArr, setFilteredAppArr] = useState<API.MatrixApp[]>([]);
const { initialState } = useModel('@@initialState'); const { initialState } = useModel('@@initialState');
const currentUser = initialState?.currentUser; const currentUser = initialState?.currentUser;
const canUpdate = currentUser && currentUser.role && currentUser.role < 2; const superAdmin = currentUser && currentUser.role && currentUser.role < 2;
const handleEdit = (record: API.MatrixApp) => { const handleEdit = (record: API.MatrixAppBo) => {
form.setFieldsValue(record); form.setFieldsValue(record);
setVisible(true); setVisible(true);
setEditing(true); setEditing(true);
}; };
const columns: ProColumns<API.MatrixApp>[] = [ const columns: ProColumns<API.MatrixAppBo>[] = [
{ {
title: '应用名', title: '应用名',
dataIndex: 'name', dataIndex: 'name',
@ -56,8 +57,53 @@ const AppManagement = () => {
}, },
]; ];
const columnsWithOperation: ProColumns<API.MatrixApp>[] = [ const superAdminColumns: ProColumns<API.MatrixAppBo>[] = [
...columns, {
title: '应用名',
dataIndex: 'name',
copyable: true,
hideInSearch: true,
},
{
title: '应用图片',
dataIndex: 'img',
hideInSearch: true,
renderText: (img: string) => <img style={{ width: '40px' }} src={img} />,
},
{
title: 'code',
dataIndex: 'code',
copyable: true,
hideInSearch: true,
},
{
title: '下载地址',
dataIndex: 'url',
width: 200,
hideInSearch: true,
renderText: (url: string) => (
<Popover
overlayInnerStyle={{ padding: 0 }}
content={<QRCode value={url || ''} bordered={false} />}
>
<a style={{ wordBreak: 'break-word' }}>{url}</a>
</Popover>
),
},
{
title: '操作',
width: 80,
hideInSearch: true,
renderText: (r: API.MatrixAppBo) => {
if (r.enableCash) {
return (
<a key="edit" onClick={() => handleEdit(r)}>
</a>
);
}
},
},
{ {
title: 'secret', title: 'secret',
dataIndex: 'secret', dataIndex: 'secret',
@ -95,7 +141,7 @@ const AppManagement = () => {
title: '操作', title: '操作',
width: 80, width: 80,
hideInSearch: true, hideInSearch: true,
renderText: (record: API.MatrixApp) => ( renderText: (record: API.MatrixAppBo) => (
<a key="edit" onClick={() => handleEdit(record)}> <a key="edit" onClick={() => handleEdit(record)}>
</a> </a>
@ -143,6 +189,10 @@ const AppManagement = () => {
setFilteredAppArr(filtered); setFilteredAppArr(filtered);
}; };
if (!superAdmin) {
return <NormalAppManagement />;
}
return ( return (
<PageContainer> <PageContainer>
{currentUser && currentUser.role && currentUser.role < 2 && ( {currentUser && currentUser.role && currentUser.role < 2 && (
@ -165,7 +215,7 @@ const AppManagement = () => {
onReset={() => { onReset={() => {
setFilteredAppArr(appArr); setFilteredAppArr(appArr);
}} }}
columns={canUpdate ? columnsWithOperation : columns} columns={superAdmin ? superAdminColumns : columns}
dataSource={filteredAppArr} dataSource={filteredAppArr}
/> />

201
src/pages/App/CashConfigForm.tsx

@ -0,0 +1,201 @@
import { getAppNormalConfig, saveNormalConfig } from '@/services/matrix/matrixAppController';
import { InfoCircleOutlined, MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Col, Form, Input, InputNumber, Modal, Row, Tooltip } from 'antd';
import React, { useEffect } from 'react';
export type CashConfigFormProps = {
onCancel: () => void;
onSubmit: () => void;
updateModalOpen: boolean;
appCode: string;
};
const CashConfigForm: React.FC<CashConfigFormProps> = (props) => {
const [form] = Form.useForm();
const handleOk = () => {
form.submit();
};
const handleCancel = () => {
props.onCancel();
};
const fetchConfig = async (appCode: string) => {
const data = await getAppNormalConfig({ appCode });
form.setFieldsValue(data.data);
};
useEffect(() => {
fetchConfig(props.appCode);
}, [props.appCode]);
const handleSaveApp = async (values: API.AppNormalConfig) => {
try {
await saveNormalConfig({ appCode: props.appCode }, values);
} catch (e) {
return;
}
props.onSubmit();
};
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 },
},
};
const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 20, offset: 6 },
},
};
return (
<Modal title="编辑" visible={props.updateModalOpen} onOk={handleOk} onCancel={handleCancel}>
<Form form={form} onFinish={handleSaveApp}>
<Form.List name="moneyLadder">
{(fields, { add, remove }) => (
<>
{fields.map((field, index) => (
<Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
label={index === 0 ? '提现梯度' : ''}
required={false}
key={field.key}
>
<Form.Item
{...field}
validateTrigger={['onChange', 'onBlur']}
rules={[
{
required: true,
whitespace: true,
message: '请输入金额或者删除本行',
},
]}
noStyle
>
<InputNumber placeholder="金额,单位分" style={{ width: '60%' }} />
</Form.Item>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
/>
) : null}
</Form.Item>
))}
<Form.Item {...formItemLayoutWithOutLabel}>
<Button
type="dashed"
onClick={() => add()}
style={{ width: '60%' }}
icon={<PlusOutlined />}
>
</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item
name="noAuditMoney"
label={
<>
<span style={{ marginLeft: 4 }}>
<Tooltip title="低于此金额的提现申请将会自动审核通过">
<InfoCircleOutlined />
</Tooltip>
</span>
</>
}
>
<InputNumber placeholder="单位分" style={{ width: '60%' }} />
</Form.Item>
<Form.Item name="qqUrl" label="QQ群链接">
<Input />
</Form.Item>
<Form.Item
name="dayLimit"
label={
<>
<span style={{ marginLeft: 4 }}>
<Tooltip title="同个账号或同个支付宝每日最多提现的次数">
<InfoCircleOutlined />
</Tooltip>
</span>
</>
}
>
<InputNumber style={{ width: '60%' }} />
</Form.Item>
<Form.Item
name="maxIncomeEachVideo"
label={
<>
<span style={{ marginLeft: 4 }}>
<Tooltip title="看一条视频最多能获得的钱,单位分">
<InfoCircleOutlined />
</Tooltip>
</span>
</>
}
>
<InputNumber style={{ width: '60%' }} />
</Form.Item>
<Form.Item name="defaultRate" label={<></>}>
<InputNumber style={{ width: '60%' }} />
</Form.Item>
<Form.List name="dayRates">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name }, index) => (
<>
<Form.Item
{...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
label={index === 0 ? '特殊日分成比例' : ''}
required={false}
key={key}
>
<Row key={key} align="stretch" gutter={16}>
<Col span={8}>
<Form.Item name={[name, 'day']} rules={[{ required: true }]}>
<Input placeholder="Day" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name={[name, 'rate']} rules={[{ required: true }]}>
<Input placeholder="Rate" />
</Form.Item>
</Col>
<Col>
<MinusCircleOutlined onClick={() => remove(name)} />
</Col>
</Row>
</Form.Item>
</>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} block>
Add Field
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form>
</Modal>
);
};
export default CashConfigForm;

117
src/pages/App/NormalAppManagement.tsx

@ -0,0 +1,117 @@
import { appList } from '@/services/matrix/admin';
import { PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { Input, Popover, QRCode } from 'antd';
import { useEffect, useState } from 'react';
import CashConfigForm from './CashConfigForm';
const NormalAppManagement = () => {
const [visible, setVisible] = useState(false);
const [appArr, setAppArr] = useState<API.MatrixApp[]>([]);
const [filteredAppArr, setFilteredAppArr] = useState<API.MatrixApp[]>([]);
const [appCode, setAppCode] = useState<string>();
const columns: ProColumns<API.MatrixAppBo>[] = [
{
title: '应用名',
dataIndex: 'name',
copyable: true,
hideInSearch: true,
},
{
title: '应用图片',
dataIndex: 'img',
hideInSearch: true,
renderText: (img: string) => <img style={{ width: '40px' }} src={img} />,
},
{
title: 'code',
dataIndex: 'code',
copyable: true,
hideInSearch: true,
},
{
title: '下载地址',
dataIndex: 'url',
width: 200,
hideInSearch: true,
renderText: (url: string) => (
<Popover
overlayInnerStyle={{ padding: 0 }}
content={<QRCode value={url || ''} bordered={false} />}
>
<a style={{ wordBreak: 'break-word' }}>{url}</a>
</Popover>
),
},
{
title: '操作',
width: 80,
hideInSearch: true,
renderText: (r: API.MatrixAppBo) => {
if (r.enableCash) {
return (
<a
key="edit"
onClick={() => {
setAppCode(r.code);
setVisible(true);
}}
>
</a>
);
}
},
},
];
const fetchApp = async () => {
const res = await appList();
if (res.data) {
setAppArr(res.data);
setFilteredAppArr(res.data);
}
};
useEffect(() => {
fetchApp();
}, []);
return (
<PageContainer>
<ProTable
search={{
defaultCollapsed: false, // 默认展开搜索框
optionRender: () => [
// 自定义搜索框
<Input
key="name"
placeholder="请输入应用名"
onChange={(e) => handleSearch(e.target.value)}
/>,
],
}}
onReset={() => {
setFilteredAppArr(appArr);
}}
columns={columns}
dataSource={filteredAppArr}
/>
{appCode && (
<CashConfigForm
updateModalOpen={visible}
appCode={appCode || ''}
onCancel={() => setVisible(false)}
onSubmit={() => {
setVisible(false);
}}
/>
)}
</PageContainer>
);
};
export default NormalAppManagement;

2
src/services/matrix/admin.ts

@ -51,7 +51,7 @@ export async function advList(body: API.AdvRecordQuery, options?: { [key: string
/** 此处后端没有提供注释 GET /api/admin/appList */ /** 此处后端没有提供注释 GET /api/admin/appList */
export async function appList(options?: { [key: string]: any }) { export async function appList(options?: { [key: string]: any }) {
return request<API.RListMatrixApp>('/api/admin/appList', { return request<API.RListMatrixAppBo>('/api/admin/appList', {
method: 'GET', method: 'GET',
...(options || {}), ...(options || {}),
}); });

18
src/services/matrix/citrusAppController.ts

@ -0,0 +1,18 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 此处后端没有提供注释 GET /api/citrus/app/getDetail */
export async function getAppDetail(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getAppDetailParams,
options?: { [key: string]: any },
) {
return request<API.RAppCashConfig>('/api/citrus/app/getDetail', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}

10
src/services/matrix/index.ts

@ -4,15 +4,21 @@
// API 唯一标识: // API 唯一标识:
import * as admin from './admin'; import * as admin from './admin';
import * as appController from './appController'; import * as appController from './appController';
import * as citrusAppController from './citrusAppController';
import * as device from './device'; import * as device from './device';
import * as loginController from './loginController'; import * as loginController from './loginController';
import * as matrixAppController from './matrixAppController';
import * as matrixController from './matrixController'; import * as matrixController from './matrixController';
import * as registerController from './registerController'; import * as openController from './openController';
import * as userController from './userController';
export default { export default {
matrixAppController,
matrixController, matrixController,
loginController, loginController,
registerController, userController,
openController,
admin, admin,
device, device,
appController, appController,
citrusAppController,
}; };

38
src/services/matrix/matrixAppController.ts

@ -0,0 +1,38 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 此处后端没有提供注释 GET /api/matrix/app/normalConfig */
export async function getAppNormalConfig(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getAppNormalConfigParams,
options?: { [key: string]: any },
) {
return request<API.RAppNormalConfig>('/api/matrix/app/normalConfig', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /api/matrix/app/normalConfig */
export async function saveNormalConfig(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.saveNormalConfigParams,
body: API.AppNormalConfig,
options?: { [key: string]: any },
) {
return request<API.RVoid>('/api/matrix/app/normalConfig', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
params: {
...params,
},
data: body,
...(options || {}),
});
}

36
src/services/matrix/registerController.ts → src/services/matrix/openController.ts

@ -2,6 +2,42 @@
/* eslint-disable */ /* eslint-disable */
import { request } from '@umijs/max'; import { request } from '@umijs/max';
/** 此处后端没有提供注释 POST /api/citrus/loginByCode */
export async function loginByCode(body: API.LoginReq, options?: { [key: string]: any }) {
return request<API.RString>('/api/citrus/loginByCode', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /api/citrus/loginByPwd */
export async function loginByPwd(body: API.LoginReq, options?: { [key: string]: any }) {
return request<API.RString>('/api/citrus/loginByPwd', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /api/citrus/loginByToken */
export async function loginByToken(body: API.LoginReq, options?: { [key: string]: any }) {
return request<API.RString>('/api/citrus/loginByToken', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 GET /api/citrus/register/getApp */ /** 此处后端没有提供注释 GET /api/citrus/register/getApp */
export async function getApp( export async function getApp(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象) // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)

105
src/services/matrix/typings.d.ts

@ -31,6 +31,13 @@ declare namespace API {
adminId?: number; adminId?: number;
}; };
type AppCashConfig = {
moneyLadder?: number[];
noAuditMoney?: number;
qqUrl?: string;
dayLimit?: number;
};
type AppInfo = { type AppInfo = {
name?: string; name?: string;
icon?: string; icon?: string;
@ -39,6 +46,20 @@ declare namespace API {
recommend?: AppInfo[]; recommend?: AppInfo[];
}; };
type applyCashParams = {
money: number;
};
type AppNormalConfig = {
moneyLadder?: number[];
noAuditMoney?: number;
qqUrl?: string;
dayLimit?: number;
maxIncomeEachVideo?: number;
dayRates?: DayRate[];
defaultRate?: number;
};
type bindDeviceParams = { type bindDeviceParams = {
deviceId: string; deviceId: string;
appCode: string; appCode: string;
@ -49,6 +70,12 @@ declare namespace API {
date: number; date: number;
}; };
type CashRecord = {
cent?: number;
createTime?: number;
status?: number;
};
type CurrentUser = { type CurrentUser = {
avatarUrl?: string; avatarUrl?: string;
nickName?: string; nickName?: string;
@ -61,6 +88,11 @@ declare namespace API {
income?: number; income?: number;
}; };
type DayRate = {
day?: number;
rate?: number;
};
type deleteWhiteListParams = { type deleteWhiteListParams = {
deviceId: string; deviceId: string;
}; };
@ -74,12 +106,21 @@ declare namespace API {
deviceId: string; deviceId: string;
}; };
type getAppDetailParams = {
appCode: string;
};
type getAppInfoParams = { type getAppInfoParams = {
appId?: string; appId?: string;
}; };
type getAppNormalConfigParams = {
appCode: string;
};
type getAppParams = { type getAppParams = {
inviteCode: string; inviteCode?: string;
appCode?: string;
}; };
type grantAppParams = { type grantAppParams = {
@ -209,6 +250,16 @@ declare namespace API {
channel?: string; channel?: string;
hide?: number; hide?: number;
secret?: string; secret?: string;
umeng?: string;
aliPay?: string;
wx?: string;
moneyLadder?: string;
noAuditMoney?: number;
qqUrl?: string;
dayLimit?: number;
maxIncomeEachVideo?: number;
dayRates?: string;
defaultRate?: number;
}; };
type MatrixAppBo = { type MatrixAppBo = {
@ -216,6 +267,11 @@ declare namespace API {
code?: string; code?: string;
img?: string; img?: string;
url?: string; url?: string;
channel?: string;
hide?: number;
secret?: string;
enableCash?: boolean;
config?: AppCashConfig;
}; };
type MatrixMockSchedule = { type MatrixMockSchedule = {
@ -271,12 +327,24 @@ declare namespace API {
size: number; size: number;
}; };
type RAppCashConfig = {
code?: number;
message?: string;
data?: AppCashConfig;
};
type RAppInfo = { type RAppInfo = {
code?: number; code?: number;
message?: string; message?: string;
data?: AppInfo; data?: AppInfo;
}; };
type RAppNormalConfig = {
code?: number;
message?: string;
data?: AppNormalConfig;
};
type RBoolean = { type RBoolean = {
code?: number; code?: number;
message?: string; message?: string;
@ -302,6 +370,12 @@ declare namespace API {
data?: InviteInfo; data?: InviteInfo;
}; };
type RListCashRecord = {
code?: number;
message?: string;
data?: CashRecord[];
};
type RListDateIncome = { type RListDateIncome = {
code?: number; code?: number;
message?: string; message?: string;
@ -326,10 +400,10 @@ declare namespace API {
data?: MatrixAdvRecordSimple[]; data?: MatrixAdvRecordSimple[];
}; };
type RListMatrixApp = { type RListMatrixAppBo = {
code?: number; code?: number;
message?: string; message?: string;
data?: MatrixApp[]; data?: MatrixAppBo[];
}; };
type RListMatrixMockSchedule = { type RListMatrixMockSchedule = {
@ -392,14 +466,25 @@ declare namespace API {
data?: STSInfo; data?: STSInfo;
}; };
type RUserBo = {
code?: number;
message?: string;
data?: UserBo;
};
type RVoid = { type RVoid = {
code?: number; code?: number;
message?: string; message?: string;
data?: Record<string, any>; data?: Record<string, any>;
}; };
type saveNormalConfigParams = {
appCode: string;
};
type sendCodeParams = { type sendCodeParams = {
mobile: string; mobile: string;
scene: string;
}; };
type STSInfo = { type STSInfo = {
@ -421,6 +506,20 @@ declare namespace API {
signature: string; signature: string;
}; };
type UserBo = {
id?: number;
mobile?: string;
name?: string;
nickname?: string;
avatar?: string;
money?: number;
aliPayAccount?: string;
income?: number;
goldCoin?: number;
inviteCode?: string;
inviteUrl?: string;
};
type UserInfo = { type UserInfo = {
avatarUrl?: string; avatarUrl?: string;
nickName?: string; nickName?: string;

46
src/services/matrix/userController.ts

@ -0,0 +1,46 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 此处后端没有提供注释 POST /api/citrus/user/applyCash */
export async function applyCash(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.applyCashParams,
options?: { [key: string]: any },
) {
return request<API.RVoid>('/api/citrus/user/applyCash', {
method: 'POST',
params: {
...params,
},
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /api/citrus/user/bindAliPay */
export async function bindAliPay(body: API.UserBo, options?: { [key: string]: any }) {
return request<API.RVoid>('/api/citrus/user/bindAliPay', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 此处后端没有提供注释 GET /api/citrus/user/cashRecords */
export async function getCashRecord(options?: { [key: string]: any }) {
return request<API.RListCashRecord>('/api/citrus/user/cashRecords', {
method: 'GET',
...(options || {}),
});
}
/** 此处后端没有提供注释 GET /api/citrus/user/current */
export async function currentUser1(options?: { [key: string]: any }) {
return request<API.RUserBo>('/api/citrus/user/current', {
method: 'GET',
...(options || {}),
});
}
Loading…
Cancel
Save