feat:初始化
This commit is contained in:
parent
dbbfe346b3
commit
67fc8f005e
3
.eslintrc.js
Normal file
3
.eslintrc.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: require.resolve('@umijs/max/eslint'),
|
||||||
|
};
|
||||||
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/node_modules
|
||||||
|
/.env.local
|
||||||
|
/.umirc.local.ts
|
||||||
|
/config/config.local.ts
|
||||||
|
/src/.umi
|
||||||
|
/src/.umi-production
|
||||||
|
/src/.umi-test
|
||||||
|
/.umi
|
||||||
|
/.umi-production
|
||||||
|
/.umi-test
|
||||||
|
/dist
|
||||||
|
/.mfsu
|
||||||
|
.swc
|
||||||
17
.lintstagedrc
Normal file
17
.lintstagedrc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"*.{md,json}": [
|
||||||
|
"prettier --cache --write"
|
||||||
|
],
|
||||||
|
"*.{js,jsx}": [
|
||||||
|
"max lint --fix --eslint-only",
|
||||||
|
"prettier --cache --write"
|
||||||
|
],
|
||||||
|
"*.{css,less}": [
|
||||||
|
"max lint --fix --stylelint-only",
|
||||||
|
"prettier --cache --write"
|
||||||
|
],
|
||||||
|
"*.ts?(x)": [
|
||||||
|
"max lint --fix --eslint-only",
|
||||||
|
"prettier --cache --parser=typescript --write"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
.umi
|
||||||
|
.umi-production
|
||||||
8
.prettierrc
Normal file
8
.prettierrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"proseWrap": "never",
|
||||||
|
"overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
|
||||||
|
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"]
|
||||||
|
}
|
||||||
3
.stylelintrc.js
Normal file
3
.stylelintrc.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: require.resolve('@umijs/max/stylelint'),
|
||||||
|
};
|
||||||
23
.umirc.ts
Normal file
23
.umirc.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { defineConfig } from '@umijs/max';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
antd: {},
|
||||||
|
access: {},
|
||||||
|
model: {},
|
||||||
|
initialState: {},
|
||||||
|
request: {},
|
||||||
|
layout: {},
|
||||||
|
npmClient: 'npm',
|
||||||
|
define: {
|
||||||
|
'process.env.TOKEN_NAME': process.env.TOKEN_NAME,
|
||||||
|
'process.env.GUARD_NAME': process.env.GUARD_NAME,
|
||||||
|
},
|
||||||
|
proxy: {
|
||||||
|
'/api/': {
|
||||||
|
target: 'http://0.0.0.0:8000',
|
||||||
|
// target: 'https://loanos-test.nchl.net/',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: { '^': '' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
3
Dockerfile
Normal file
3
Dockerfile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FROM nexus.zzwb.cc:18444/nginx:1.21-alpine
|
||||||
|
COPY dist /usr/share/nginx/html
|
||||||
|
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
||||||
56
docker/nginx.conf
Executable file
56
docker/nginx.conf
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
# Generated by nginxconfig.io
|
||||||
|
# See nginxconfig.txt for the configuration share link
|
||||||
|
|
||||||
|
user nginx;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
worker_processes auto;
|
||||||
|
worker_rlimit_nofile 65535;
|
||||||
|
|
||||||
|
# Load modules
|
||||||
|
include /etc/nginx/modules-enabled/*.conf;
|
||||||
|
|
||||||
|
events {
|
||||||
|
multi_accept on;
|
||||||
|
worker_connections 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
charset utf-8;
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
server_tokens off;
|
||||||
|
log_not_found off;
|
||||||
|
types_hash_max_size 2048;
|
||||||
|
types_hash_bucket_size 64;
|
||||||
|
client_max_body_size 16M;
|
||||||
|
|
||||||
|
# MIME
|
||||||
|
include mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
access_log /dev/stdout;
|
||||||
|
error_log /dev/stderr warn;
|
||||||
|
|
||||||
|
# example.com
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name _;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html index.htm;
|
||||||
|
|
||||||
|
# index.html fallback
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# gzip
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
gencode.json
Normal file
4
gencode.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"url": "http://0.0.0.0:8000/api/docs/openapi",
|
||||||
|
"module": "Admin"
|
||||||
|
}
|
||||||
19173
package-lock.json
generated
Normal file
19173
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
35
package.json
Normal file
35
package.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"author": "helloworld <hello@world.com>",
|
||||||
|
"scripts": {
|
||||||
|
"build": "max build",
|
||||||
|
"dev": "max dev",
|
||||||
|
"format": "prettier --cache --write .",
|
||||||
|
"postinstall": "max setup",
|
||||||
|
"setup": "max setup",
|
||||||
|
"start": "npm run dev"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/icons": "^5.0.1",
|
||||||
|
"@ant-design/pro-components": "^2.4.4",
|
||||||
|
"@antv/s2": "^2.0.0-next.25",
|
||||||
|
"@antv/s2-react": "^2.0.0-next.24",
|
||||||
|
"@umijs/max": "^4.3.10",
|
||||||
|
"antd": "^5.4.0",
|
||||||
|
"axios": "^1.7.2",
|
||||||
|
"dayjs": "^1.11.12",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"react-use": "^17.5.1",
|
||||||
|
"valtio": "^1.13.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.0.33",
|
||||||
|
"@types/react-dom": "^18.0.11",
|
||||||
|
"gencode-ts-cli": "^0.0.1",
|
||||||
|
"lint-staged": "^13.2.0",
|
||||||
|
"prettier": "^2.8.7",
|
||||||
|
"prettier-plugin-organize-imports": "^3.2.2",
|
||||||
|
"prettier-plugin-packagejson": "^2.4.3",
|
||||||
|
"typescript": "^5.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
14149
pnpm-lock.yaml
generated
Normal file
14149
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
src/access.ts
Normal file
10
src/access.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export default (initialState: API.UserInfo) => {
|
||||||
|
// 在这里按照初始化数据定义项目中的权限,统一管理
|
||||||
|
// 参考文档 https://umijs.org/docs/max/access
|
||||||
|
const canSeeAdmin = !!(
|
||||||
|
initialState && initialState.name !== 'dontHaveAccess'
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
canSeeAdmin,
|
||||||
|
};
|
||||||
|
};
|
||||||
21
src/app.tsx
Normal file
21
src/app.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 运行时配置
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
LayoutConfig,
|
||||||
|
MyRootContainer,
|
||||||
|
requestConfig,
|
||||||
|
stateActions,
|
||||||
|
} from './common';
|
||||||
|
|
||||||
|
export const request = requestConfig;
|
||||||
|
|
||||||
|
export async function getInitialState(): Promise<any> {
|
||||||
|
return await stateActions.me();
|
||||||
|
}
|
||||||
|
|
||||||
|
export const layout = LayoutConfig;
|
||||||
|
|
||||||
|
export function rootContainer(container: React.ReactNode) {
|
||||||
|
return React.createElement(MyRootContainer, null, container);
|
||||||
|
}
|
||||||
0
src/assets/.gitkeep
Normal file
0
src/assets/.gitkeep
Normal file
BIN
src/assets/bitcoin.webp
Normal file
BIN
src/assets/bitcoin.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
13
src/common/components/MyAccess.tsx
Normal file
13
src/common/components/MyAccess.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Access, useAccess } from '@umijs/max';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
export default function MyAccess({
|
||||||
|
children,
|
||||||
|
theKey,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
theKey: string;
|
||||||
|
}) {
|
||||||
|
const access = useAccess();
|
||||||
|
return <Access accessible={access.canAccess(theKey)}>{children}</Access>;
|
||||||
|
}
|
||||||
138
src/common/components/MyButtons.tsx
Normal file
138
src/common/components/MyButtons.tsx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import {
|
||||||
|
DeleteOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
EyeOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
RollbackOutlined,
|
||||||
|
SaveFilled,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import { Button, ButtonProps, Dropdown, Popconfirm } from 'antd';
|
||||||
|
import { MyResponseType } from '..';
|
||||||
|
|
||||||
|
type MyButtonsType = { title?: string } & ButtonProps;
|
||||||
|
|
||||||
|
export const MyButtons = {
|
||||||
|
Create({ title, ...rest }: MyButtonsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Button type="primary" icon={<PlusOutlined />} {...rest}>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Default({
|
||||||
|
onConfirm,
|
||||||
|
isConfirm,
|
||||||
|
title,
|
||||||
|
description = '确定要取消?',
|
||||||
|
...rest
|
||||||
|
}: {
|
||||||
|
onConfirm?: () => void;
|
||||||
|
isConfirm?: boolean;
|
||||||
|
description?: string;
|
||||||
|
} & MyButtonsType): JSX.Element {
|
||||||
|
return isConfirm ? (
|
||||||
|
<Popconfirm
|
||||||
|
title="提示"
|
||||||
|
description={description}
|
||||||
|
okText="是"
|
||||||
|
cancelText="否"
|
||||||
|
onConfirm={onConfirm}
|
||||||
|
>
|
||||||
|
<Button size="small" {...rest}>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
) : (
|
||||||
|
<Button size="small" {...rest}>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
View({ title, ...rest }: MyButtonsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Button type="link" size="small" icon={<EyeOutlined />} {...rest}>
|
||||||
|
{title ?? '查看'}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Edit({ title = '编辑', ...rest }: MyButtonsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Button type="link" size="small" icon={<EditOutlined />} {...rest}>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Save({ title = '保存', ...rest }: MyButtonsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Button type="primary" icon={<SaveFilled />} {...rest}>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Delete({
|
||||||
|
onConfirm,
|
||||||
|
title = '删除',
|
||||||
|
...rest
|
||||||
|
}: { onConfirm: () => void } & MyButtonsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Popconfirm
|
||||||
|
title="删除提示"
|
||||||
|
description="确定要删除,将不可恢复?"
|
||||||
|
okText="是"
|
||||||
|
cancelText="否"
|
||||||
|
onConfirm={onConfirm}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
danger
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Export({
|
||||||
|
api,
|
||||||
|
params,
|
||||||
|
title,
|
||||||
|
...rest
|
||||||
|
}: {
|
||||||
|
api: (data: any) => Promise<MyResponseType>;
|
||||||
|
params?: Record<string, any>;
|
||||||
|
} & MyButtonsType): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
onClick: ({ item, key }: any) => {
|
||||||
|
console.log(item, key);
|
||||||
|
api?.({ ...params, ...{ download_type: key } });
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
// {
|
||||||
|
// key: 'page',
|
||||||
|
// label: '导出当前页',
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
key: 'query',
|
||||||
|
label: '按条件导出',
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// key: 'all',
|
||||||
|
// label: '导出全部',
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
placement="bottomLeft"
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<Button key="MyExportButton" icon={<RollbackOutlined />} {...rest}>
|
||||||
|
{title || '导出'}
|
||||||
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
SoftDelete() {},
|
||||||
|
};
|
||||||
37
src/common/components/MyIcons.tsx
Normal file
37
src/common/components/MyIcons.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {
|
||||||
|
AuditOutlined,
|
||||||
|
BankOutlined,
|
||||||
|
BarChartOutlined,
|
||||||
|
BarcodeOutlined,
|
||||||
|
ClusterOutlined,
|
||||||
|
ControlOutlined,
|
||||||
|
CreditCardOutlined,
|
||||||
|
SettingOutlined,
|
||||||
|
ShopOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
|
||||||
|
export type MyIconsType =
|
||||||
|
| 'BarcodeOutlined'
|
||||||
|
| 'AuditOutlined'
|
||||||
|
| 'ShopOutlined'
|
||||||
|
| 'BarChartOutlined'
|
||||||
|
| 'SettingOutlined'
|
||||||
|
| 'ControlOutlined'
|
||||||
|
| 'ClusterOutlined'
|
||||||
|
| 'BankOutlined'
|
||||||
|
| 'UserOutlined'
|
||||||
|
| 'CreditCardOutlined';
|
||||||
|
|
||||||
|
export const MyIcons = {
|
||||||
|
BarcodeOutlined: <BarcodeOutlined />,
|
||||||
|
AuditOutlined: <AuditOutlined />,
|
||||||
|
ShopOutlined: <ShopOutlined />,
|
||||||
|
BarChartOutlined: <BarChartOutlined />,
|
||||||
|
SettingOutlined: <SettingOutlined />,
|
||||||
|
ControlOutlined: <ControlOutlined />,
|
||||||
|
ClusterOutlined: <ClusterOutlined />,
|
||||||
|
BankOutlined: <BankOutlined />,
|
||||||
|
UserOutlined: <UserOutlined />,
|
||||||
|
CreditCardOutlined: <CreditCardOutlined />,
|
||||||
|
};
|
||||||
18
src/common/components/MyStatistics.tsx
Normal file
18
src/common/components/MyStatistics.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Flex, Statistic } from 'antd';
|
||||||
|
|
||||||
|
export function MyStatistics({ items = {} }: { items?: Record<string, any> }) {
|
||||||
|
return (
|
||||||
|
<Flex style={{ padding: '0px 20px 20px 20px' }}>
|
||||||
|
{Object.keys(items).map((key) => {
|
||||||
|
return (
|
||||||
|
<Statistic
|
||||||
|
key={key}
|
||||||
|
title={key}
|
||||||
|
value={items[key]}
|
||||||
|
style={{ marginRight: 50 }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
src/common/components/MyTag.tsx
Normal file
15
src/common/components/MyTag.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Tag } from 'antd';
|
||||||
|
import { MyProEnumItemProps } from '../typings';
|
||||||
|
|
||||||
|
export default function MyTag({
|
||||||
|
enums,
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
enums: MyProEnumItemProps;
|
||||||
|
value: string;
|
||||||
|
}) {
|
||||||
|
const item = enums[value] ?? undefined;
|
||||||
|
if (!item) return <>-</>;
|
||||||
|
console.log('item', value, item);
|
||||||
|
return <Tag color={item.color}>{item.text}</Tag>;
|
||||||
|
}
|
||||||
58
src/common/components/formFields/MyColorPicker.tsx
Normal file
58
src/common/components/formFields/MyColorPicker.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { ColorPicker } from 'antd';
|
||||||
|
|
||||||
|
export function MyColorPicker(props: any) {
|
||||||
|
return (
|
||||||
|
<ColorPicker
|
||||||
|
allowClear
|
||||||
|
arrow
|
||||||
|
showText
|
||||||
|
format="hex"
|
||||||
|
defaultValue={null}
|
||||||
|
presets={[
|
||||||
|
{
|
||||||
|
label: 'Recommended',
|
||||||
|
colors: [
|
||||||
|
'#000000',
|
||||||
|
'#000000E0',
|
||||||
|
'#000000A6',
|
||||||
|
'#00000073',
|
||||||
|
'#00000040',
|
||||||
|
'#00000026',
|
||||||
|
'#0000001A',
|
||||||
|
'#00000012',
|
||||||
|
'#0000000A',
|
||||||
|
'#00000005',
|
||||||
|
'#F5222D',
|
||||||
|
'#FA8C16',
|
||||||
|
'#FADB14',
|
||||||
|
'#8BBB11',
|
||||||
|
'#52C41A',
|
||||||
|
'#13A8A8',
|
||||||
|
'#1677FF',
|
||||||
|
'#2F54EB',
|
||||||
|
'#722ED1',
|
||||||
|
'#EB2F96',
|
||||||
|
'#F5222D4D',
|
||||||
|
'#FA8C164D',
|
||||||
|
'#FADB144D',
|
||||||
|
'#8BBB114D',
|
||||||
|
'#52C41A4D',
|
||||||
|
'#13A8A84D',
|
||||||
|
'#1677FF4D',
|
||||||
|
'#2F54EB4D',
|
||||||
|
'#722ED14D',
|
||||||
|
'#EB2F964D',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Recent',
|
||||||
|
colors: [],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
{...props}
|
||||||
|
onChange={(color) => {
|
||||||
|
props.onChange?.(color.toHexString());
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
21
src/common/components/formFields/MyEnumRadioGroup.tsx
Normal file
21
src/common/components/formFields/MyEnumRadioGroup.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { MyProEnumItemProps } from '@/common/typings';
|
||||||
|
import { Radio } from 'antd';
|
||||||
|
|
||||||
|
export default function MyEnumRadioGroup(props: {
|
||||||
|
enums: MyProEnumItemProps;
|
||||||
|
value: string | number | undefined;
|
||||||
|
onChange: (value: string | number | undefined) => void;
|
||||||
|
}) {
|
||||||
|
const options = Object.entries(props.enums).map(([, value]) => {
|
||||||
|
return { label: value.text, value: value.value };
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Radio.Group
|
||||||
|
options={options}
|
||||||
|
onChange={(e) => props?.onChange(e.target.value)}
|
||||||
|
value={props.value || options[0].value}
|
||||||
|
optionType="button"
|
||||||
|
buttonStyle="solid"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
src/common/components/formFields/MyIconSelect.tsx
Normal file
19
src/common/components/formFields/MyIconSelect.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Select, SelectProps, Space } from 'antd';
|
||||||
|
import { MyIcons } from '../MyIcons';
|
||||||
|
|
||||||
|
export function MyIconSelect(props: SelectProps) {
|
||||||
|
return (
|
||||||
|
<Select allowClear {...props}>
|
||||||
|
{Object?.entries(MyIcons).map(([key, Icon]) => {
|
||||||
|
return (
|
||||||
|
<Select.Option value={key} label={key} key={key}>
|
||||||
|
<Space>
|
||||||
|
{Icon}
|
||||||
|
{key}
|
||||||
|
</Space>
|
||||||
|
</Select.Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
12
src/common/components/formFields/MyMoneyInput.tsx
Normal file
12
src/common/components/formFields/MyMoneyInput.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { InputNumber } from 'antd';
|
||||||
|
|
||||||
|
export function MyMoneyInput(props: any) {
|
||||||
|
return (
|
||||||
|
<InputNumber
|
||||||
|
addonBefore="¥"
|
||||||
|
precision={2}
|
||||||
|
formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
src/common/components/formFields/MyPercentInput.tsx
Normal file
5
src/common/components/formFields/MyPercentInput.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { InputNumber } from 'antd';
|
||||||
|
|
||||||
|
export function MyPercentInput(props: any) {
|
||||||
|
return <InputNumber addonAfter="%" precision={2} {...props} />;
|
||||||
|
}
|
||||||
54
src/common/components/formFields/MyTreeCheckable.tsx
Normal file
54
src/common/components/formFields/MyTreeCheckable.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { Tree, TreeProps } from 'antd';
|
||||||
|
import { DataNode } from 'antd/es/tree';
|
||||||
|
import { Key, useEffect, useState } from 'react';
|
||||||
|
import { MyProFormFieldProps, MyResponseType } from '../../typings';
|
||||||
|
|
||||||
|
export function MyTreeCheckable(
|
||||||
|
props: {
|
||||||
|
api: (data?: any) => Promise<MyResponseType>;
|
||||||
|
} & TreeProps<DataNode> &
|
||||||
|
MyProFormFieldProps<Key[]>,
|
||||||
|
) {
|
||||||
|
const [treeData, setTreeData] = useState<DataNode[]>([]);
|
||||||
|
|
||||||
|
const processTree = (item: any): DataNode => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
key: item.id,
|
||||||
|
title: item.id + '_' + item.name,
|
||||||
|
children: item.children?.map(processTree),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
props.api?.({ guard_name: process.env.GUARD_NAME }).then((res: any) => {
|
||||||
|
const data = res.data?.map(processTree);
|
||||||
|
setTreeData(data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
|
||||||
|
console.log('onCheck', checkedKeys, info);
|
||||||
|
const ids: Key[] = [];
|
||||||
|
info.checkedNodes?.forEach((item) => {
|
||||||
|
if (item.children?.length === 0) {
|
||||||
|
ids.push(item.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('ids', ids);
|
||||||
|
props.onChange?.(ids);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (treeData?.length ?? 0) > 0 ? (
|
||||||
|
<Tree
|
||||||
|
checkable
|
||||||
|
defaultExpandAll
|
||||||
|
treeData={treeData}
|
||||||
|
onCheck={onCheck}
|
||||||
|
checkedKeys={props.value ?? []}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
|
}
|
||||||
137
src/common/components/formFields/MyUploadImages.tsx
Normal file
137
src/common/components/formFields/MyUploadImages.tsx
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import { MyProFormFieldProps } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { PlusOutlined, UploadOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Modal, Upload, UploadFile, UploadProps } from 'antd';
|
||||||
|
import { RcFile } from 'antd/es/upload';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useSetState } from 'react-use';
|
||||||
|
|
||||||
|
type MyType = {
|
||||||
|
uploadType?: 'image' | 'video' | 'audio' | 'file';
|
||||||
|
max?: number;
|
||||||
|
} & UploadProps<any> &
|
||||||
|
MyProFormFieldProps<UploadFile[]>;
|
||||||
|
|
||||||
|
const getBase64 = (file: RcFile): Promise<string> =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.onload = () => resolve(reader.result as string);
|
||||||
|
reader.onerror = (error) => reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
export function MyUploadImages({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
uploadType = 'image',
|
||||||
|
max = 1,
|
||||||
|
...rest
|
||||||
|
}: MyType) {
|
||||||
|
const [preview, setPreview] = useSetState<{
|
||||||
|
open: boolean;
|
||||||
|
image: string;
|
||||||
|
title: string;
|
||||||
|
}>({
|
||||||
|
open: false,
|
||||||
|
image: '',
|
||||||
|
title: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('MyUploadImages');
|
||||||
|
|
||||||
|
const handleCancel = () => setPreview({ open: false });
|
||||||
|
|
||||||
|
const handlePreview = async (file: UploadFile) => {
|
||||||
|
if (!file.url && !file.preview) {
|
||||||
|
file.preview = await getBase64(file.originFileObj as RcFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreview({
|
||||||
|
open: true,
|
||||||
|
image: file.url || file.preview,
|
||||||
|
title: file.name || file.url!.substring(file.url!.lastIndexOf('/') + 1),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
|
||||||
|
console.log('newFileList', newFileList);
|
||||||
|
const _newFileList: UploadFile<any>[] = newFileList.map((file) => {
|
||||||
|
if (!file.percent) return file;
|
||||||
|
return {
|
||||||
|
name: file.name,
|
||||||
|
status: file.status,
|
||||||
|
uid: file.uid,
|
||||||
|
url: file.response,
|
||||||
|
size: file.size ?? 0,
|
||||||
|
type: file.type ?? '',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
onChange?.(_newFileList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadButton =
|
||||||
|
uploadType === 'image' ? (
|
||||||
|
<div>
|
||||||
|
<PlusOutlined />
|
||||||
|
<div style={{ marginTop: 8 }}>Upload</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button icon={<UploadOutlined />}>Click to Upload</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const customRequest = ({ file, onError, onProgress, onSuccess }: any) => {
|
||||||
|
Apis.Auth.PreUpload({
|
||||||
|
filename: file.name,
|
||||||
|
}).then(async (res) => {
|
||||||
|
axios
|
||||||
|
.put(res.data.url, file, {
|
||||||
|
headers: res.data.headers,
|
||||||
|
onUploadProgress: ({ total, loaded }) => {
|
||||||
|
if (total)
|
||||||
|
onProgress(
|
||||||
|
{ percent: Math.round((loaded / total) * 100).toFixed(2) },
|
||||||
|
file,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(({ data: response }) => {
|
||||||
|
console.log('response', response);
|
||||||
|
if (response.errorMessage) {
|
||||||
|
onError(response, file);
|
||||||
|
} else {
|
||||||
|
onSuccess(res.data.url.split('?')[0], file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
abort() {
|
||||||
|
console.log('upload progress is aborted.');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Upload
|
||||||
|
accept={uploadType === 'image' ? 'image/*' : '*'}
|
||||||
|
fileList={value}
|
||||||
|
listType={uploadType === 'image' ? 'picture-card' : 'text'}
|
||||||
|
onPreview={handlePreview}
|
||||||
|
onChange={handleChange}
|
||||||
|
customRequest={customRequest}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{!value?.length || (value && value.length < max) ? uploadButton : null}
|
||||||
|
</Upload>
|
||||||
|
<Modal
|
||||||
|
open={preview.open}
|
||||||
|
title={preview.title}
|
||||||
|
footer={null}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
>
|
||||||
|
<img alt="preview" style={{ width: '100%' }} src={preview.image} />
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
94
src/common/components/layout/AvatarProps.tsx
Normal file
94
src/common/components/layout/AvatarProps.tsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { MyButtons } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import {
|
||||||
|
LogoutOutlined,
|
||||||
|
MenuFoldOutlined,
|
||||||
|
UnlockOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import { history } from '@umijs/max';
|
||||||
|
import { Avatar, Drawer, Dropdown, MenuProps, Space } from 'antd';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { stateActions } from '../../libs/valtio/actions';
|
||||||
|
import ChangePassword from './ChangePassword';
|
||||||
|
import MyTasks from './Tasks';
|
||||||
|
|
||||||
|
export default function AvatarProps({ user }: { user: any }) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [openDrawer, setOpenDrawer] = useState(false);
|
||||||
|
const showDrawer = () => {
|
||||||
|
setOpenDrawer(true);
|
||||||
|
};
|
||||||
|
const onClose = () => {
|
||||||
|
setOpenDrawer(false);
|
||||||
|
};
|
||||||
|
const items: MenuProps['items'] = [
|
||||||
|
{
|
||||||
|
key: 'changePassword',
|
||||||
|
label: (
|
||||||
|
<Space
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<UnlockOutlined />
|
||||||
|
修改密码
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'logout',
|
||||||
|
label: (
|
||||||
|
<Space
|
||||||
|
onClick={() => {
|
||||||
|
Apis.Auth.Logout().then(() => {
|
||||||
|
stateActions.setLogout();
|
||||||
|
history.push('/login');
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LogoutOutlined />
|
||||||
|
退出登录
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Space>
|
||||||
|
<MyButtons.Default
|
||||||
|
type="link"
|
||||||
|
icon={<MenuFoldOutlined />}
|
||||||
|
size="middle"
|
||||||
|
onClick={() => {
|
||||||
|
showDrawer();
|
||||||
|
}}
|
||||||
|
title="任务"
|
||||||
|
/>
|
||||||
|
<Dropdown menu={{ items }} placement="bottomRight">
|
||||||
|
<Space>
|
||||||
|
<Avatar
|
||||||
|
style={{ backgroundColor: '#87d068' }}
|
||||||
|
icon={<UserOutlined />}
|
||||||
|
size={28}
|
||||||
|
/>
|
||||||
|
<span>{user?.username}</span>
|
||||||
|
</Space>
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
<ChangePassword open={open} setOpen={setOpen} />
|
||||||
|
<Drawer
|
||||||
|
title="任务"
|
||||||
|
placement="right"
|
||||||
|
closable={false}
|
||||||
|
onClose={onClose}
|
||||||
|
open={openDrawer}
|
||||||
|
key="right"
|
||||||
|
width={500}
|
||||||
|
>
|
||||||
|
<MyTasks item={openDrawer} />
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
39
src/common/components/layout/ChangePassword.tsx
Normal file
39
src/common/components/layout/ChangePassword.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ModalForm, ProFormText } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function ChangePassword({
|
||||||
|
open,
|
||||||
|
setOpen,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (open: boolean) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<ModalForm<ApiTypes.Auth.ChangePassword>
|
||||||
|
open={open}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
title="修改密码"
|
||||||
|
onFinish={async (values) => {
|
||||||
|
return Apis.Auth.ChangePassword(values)
|
||||||
|
.then(() => {
|
||||||
|
message.success('修改密码成功');
|
||||||
|
setOpen(false);
|
||||||
|
})
|
||||||
|
.catch(() => false);
|
||||||
|
}}
|
||||||
|
modalProps={{
|
||||||
|
onCancel: () => setOpen(false),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ProFormText.Password name="old_password" label="原密码" required />
|
||||||
|
<ProFormText.Password name="new_password" label="新密码" required />
|
||||||
|
<ProFormText.Password
|
||||||
|
name="re_new_password"
|
||||||
|
label="重复新密码"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</ModalForm>
|
||||||
|
);
|
||||||
|
}
|
||||||
40
src/common/components/layout/MyCommonModal.tsx
Normal file
40
src/common/components/layout/MyCommonModal.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Button, Modal } from 'antd';
|
||||||
|
import { ReactNode, useState } from 'react';
|
||||||
|
|
||||||
|
export function MyCommonModal(props: {
|
||||||
|
title: string;
|
||||||
|
width: number;
|
||||||
|
button_text: string;
|
||||||
|
children: ReactNode;
|
||||||
|
}) {
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const showModal = () => {
|
||||||
|
setIsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOk = () => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button onClick={showModal} size="small">
|
||||||
|
{props.button_text}
|
||||||
|
</Button>
|
||||||
|
<Modal
|
||||||
|
title={props.title}
|
||||||
|
open={isModalOpen}
|
||||||
|
onOk={handleOk}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
width={props.width || 800}
|
||||||
|
destroyOnClose
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
104
src/common/components/layout/MyImportModal.tsx
Normal file
104
src/common/components/layout/MyImportModal.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { MyResponseType } from '@/common';
|
||||||
|
import { ImportOutlined, InboxOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Flex, Modal, Upload, message } from 'antd';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
type MyImportModalType = {
|
||||||
|
title?: string;
|
||||||
|
type?: any;
|
||||||
|
params?: Record<string, any>;
|
||||||
|
templateApi?: () => Promise<MyResponseType>;
|
||||||
|
importApi: (data: any) => Promise<MyResponseType>;
|
||||||
|
reload?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function MyImportModal(props: MyImportModalType) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [formData, setFormData] = useState<FormData | undefined>(undefined);
|
||||||
|
|
||||||
|
const { title = '批量导入', params = {}, type = 'primary' } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{type === 'danger' ? (
|
||||||
|
<Button onClick={() => setOpen(true)} type="primary" danger>
|
||||||
|
<ImportOutlined />
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button onClick={() => setOpen(true)} type="primary">
|
||||||
|
<ImportOutlined />
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title={title}
|
||||||
|
open={open}
|
||||||
|
onCancel={() => setOpen(false)}
|
||||||
|
onOk={() => {
|
||||||
|
if (!formData) return;
|
||||||
|
setLoading(true);
|
||||||
|
props
|
||||||
|
?.importApi(formData)
|
||||||
|
.then(() => {
|
||||||
|
message.success('导入操作成功');
|
||||||
|
setLoading(false);
|
||||||
|
setOpen(false);
|
||||||
|
props.reload?.();
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
confirmLoading={loading}
|
||||||
|
destroyOnClose={true}
|
||||||
|
maskClosable={false}
|
||||||
|
footer={(dom) => {
|
||||||
|
return (
|
||||||
|
<Flex style={{ width: '100%' }} justify="space-between">
|
||||||
|
<Button onClick={() => props?.templateApi?.()}>下载模板</Button>
|
||||||
|
<div>{dom}</div>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Upload.Dragger
|
||||||
|
accept=".xls,.xlsx,text/csv,.csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
|
maxCount={1}
|
||||||
|
beforeUpload={(file) => {
|
||||||
|
const isExcelFile =
|
||||||
|
file.type === 'application/vnd.ms-excel' ||
|
||||||
|
file.type ===
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||||
|
const isCSVFile = file.type === 'text/csv';
|
||||||
|
if (!isExcelFile && !isCSVFile) {
|
||||||
|
message.error(`${file.name} is not an Excel or CSV file`);
|
||||||
|
return Upload.LIST_IGNORE;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}}
|
||||||
|
customRequest={({ file }) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('upload_file', file);
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
formData.append(key, value);
|
||||||
|
});
|
||||||
|
setFormData(formData);
|
||||||
|
console.log('formData', formData, file);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className="ant-upload-drag-icon">
|
||||||
|
<InboxOutlined />
|
||||||
|
</p>
|
||||||
|
<p className="ant-upload-text">单击或拖动文件到此区域进行上传</p>
|
||||||
|
<p className="ant-upload-hint">
|
||||||
|
支持单次上传。严禁上传公司数据或其他被禁止的文件。
|
||||||
|
</p>
|
||||||
|
</Upload.Dragger>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
src/common/components/layout/MyLoading.tsx
Normal file
31
src/common/components/layout/MyLoading.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Spin } from 'antd';
|
||||||
|
import { useMyState } from '../..';
|
||||||
|
|
||||||
|
export function MyLoading() {
|
||||||
|
const { snap } = useMyState();
|
||||||
|
if (snap.session.loading === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
position: 'fixed',
|
||||||
|
zIndex: 9999,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Spin size="large">
|
||||||
|
<div style={{ paddingTop: '70px' }} />
|
||||||
|
Loading...
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
0
src/common/components/layout/MyLoginPage.tsx
Normal file
0
src/common/components/layout/MyLoginPage.tsx
Normal file
27
src/common/components/layout/MyPageContainer.tsx
Normal file
27
src/common/components/layout/MyPageContainer.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { PageContainer, PageContainerProps } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
|
||||||
|
export function MyPageContainer({
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
...rest
|
||||||
|
}: PageContainerProps) {
|
||||||
|
return (
|
||||||
|
<PageContainer
|
||||||
|
fixedHeader
|
||||||
|
header={{
|
||||||
|
title: title,
|
||||||
|
style: { backgroundColor: '#FFF' },
|
||||||
|
}}
|
||||||
|
token={{
|
||||||
|
paddingBlockPageContainerContent: 0,
|
||||||
|
paddingInlinePageContainerContent: 0,
|
||||||
|
}}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
|
||||||
|
{children}
|
||||||
|
</Space>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
21
src/common/components/layout/MyRootContainer.tsx
Normal file
21
src/common/components/layout/MyRootContainer.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { ConfigProvider } from 'antd';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { MyLoading } from './MyLoading';
|
||||||
|
|
||||||
|
export function MyRootContainer({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider
|
||||||
|
theme={{
|
||||||
|
token: {
|
||||||
|
fontSize: 14,
|
||||||
|
borderRadius: 1,
|
||||||
|
// colorPrimary: '#00928a',
|
||||||
|
// colorInfo: '#00928a',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MyLoading />
|
||||||
|
{children}
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
106
src/common/components/layout/Tasks.tsx
Normal file
106
src/common/components/layout/Tasks.tsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { MyButtons, renderTextHelper } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { SysTasksStatusEnum } from '@/gen/Enums';
|
||||||
|
import { UndoOutlined } from '@ant-design/icons';
|
||||||
|
import { Card, Descriptions, Pagination, Space } from 'antd';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export default function Tasks(props: any) {
|
||||||
|
const [option, setOption] = useState<any>({});
|
||||||
|
const getList = (page: number) => {
|
||||||
|
Apis.SysTasks.List({ perPage: 10, page: page })
|
||||||
|
.then((res) => {
|
||||||
|
setOption(res);
|
||||||
|
})
|
||||||
|
.catch(() => false);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props?.item) {
|
||||||
|
getList(1);
|
||||||
|
}
|
||||||
|
}, [props?.item]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }}>
|
||||||
|
{!option?.data?.length ? (
|
||||||
|
<div
|
||||||
|
style={{ color: '#999', textAlign: 'center', padding: '20px 0' }}
|
||||||
|
>
|
||||||
|
暂无任务数据
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
{option?.data?.map((res: any) => {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={res?.name}
|
||||||
|
key={res?.id}
|
||||||
|
extra={
|
||||||
|
<Space>
|
||||||
|
<MyButtons.Delete
|
||||||
|
size="middle"
|
||||||
|
type="default"
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.SysTasks.Delete({
|
||||||
|
id: res.id,
|
||||||
|
}).then(() => getList(1))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MyButtons.Default
|
||||||
|
icon={<UndoOutlined />}
|
||||||
|
size="middle"
|
||||||
|
onClick={() => getList(1)}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
<Descriptions column={1}>
|
||||||
|
<Descriptions.Item label="开始时间:">
|
||||||
|
{res?.start_at || '-'}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="成功数量:">
|
||||||
|
{res?.success_count || '-'}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="失败数量:">
|
||||||
|
{res?.fail_count || '-'}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="状态:">
|
||||||
|
<renderTextHelper.Tag
|
||||||
|
Enums={SysTasksStatusEnum}
|
||||||
|
value={res?.status}
|
||||||
|
key="status"
|
||||||
|
/>
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="结束时间:">
|
||||||
|
{res?.end_at || '-'}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="错误信息:">
|
||||||
|
{res?.error_message || '-'}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="失败的策路:">
|
||||||
|
<Space>
|
||||||
|
{res?.is_error_stop ? '失败后暂停' : '失败后续集执行'}
|
||||||
|
{res?.is_error_rollback ? '失败后全部回滚' : '失败后不回滚'}
|
||||||
|
</Space>
|
||||||
|
</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'end' }}>
|
||||||
|
<Pagination
|
||||||
|
defaultCurrent={option?.meta?.current_page}
|
||||||
|
total={option?.meta?.total}
|
||||||
|
onChange={(page) => {
|
||||||
|
getList(page);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
src/common/components/props/MyDrawerProps.ts
Normal file
11
src/common/components/props/MyDrawerProps.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { DrawerProps } from 'antd';
|
||||||
|
|
||||||
|
export const MyDrawerProps = {
|
||||||
|
props: {
|
||||||
|
footer: null,
|
||||||
|
maskClosable: false,
|
||||||
|
placement: 'bottom',
|
||||||
|
width: '80%',
|
||||||
|
height: 'calc(100% - 50px)',
|
||||||
|
} as DrawerProps,
|
||||||
|
};
|
||||||
13
src/common/components/props/MyModalFormProps.ts
Normal file
13
src/common/components/props/MyModalFormProps.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export const MyModalFormProps = {
|
||||||
|
props: {
|
||||||
|
layout: 'vertical',
|
||||||
|
labelAlign: 'left',
|
||||||
|
wrapperCol: { span: 20 },
|
||||||
|
style: { padding: '15px' },
|
||||||
|
layoutType: 'ModalForm',
|
||||||
|
grid: true,
|
||||||
|
modalProps: {
|
||||||
|
maskClosable: false,
|
||||||
|
},
|
||||||
|
} as any,
|
||||||
|
};
|
||||||
52
src/common/components/props/MyProTableProps.ts
Normal file
52
src/common/components/props/MyProTableProps.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { ParamsType, ProTableProps } from '@ant-design/pro-components';
|
||||||
|
import { SortOrder } from 'antd/es/table/interface';
|
||||||
|
|
||||||
|
export const MyProTableProps = {
|
||||||
|
props: {
|
||||||
|
scroll: { x: 'max-content', scrollToFirstRowOnChange: true },
|
||||||
|
bordered: true,
|
||||||
|
size: 'small',
|
||||||
|
rowKey: 'id',
|
||||||
|
pagination: {
|
||||||
|
showTotal: (total) => `总共${total}条`,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
defaultCollapsed: false,
|
||||||
|
},
|
||||||
|
} as ProTableProps<Record<string, any>, ParamsType, 'text'>,
|
||||||
|
|
||||||
|
request: async (
|
||||||
|
params: Record<string, any> & {
|
||||||
|
pageSize?: number;
|
||||||
|
current?: number;
|
||||||
|
keyword?: string;
|
||||||
|
},
|
||||||
|
sort: Record<string, SortOrder>,
|
||||||
|
api: (data?: any) => any,
|
||||||
|
setParams?: (params: any) => void,
|
||||||
|
setRes?: (res: any) => void,
|
||||||
|
defaultParams?: Record<string, any>,
|
||||||
|
) => {
|
||||||
|
const sortKeys = Object.keys(sort);
|
||||||
|
const sorter =
|
||||||
|
sortKeys.length > 0 ? [sortKeys[0], sort[sortKeys[0]]] : undefined;
|
||||||
|
const { current, pageSize, ...rest } = params;
|
||||||
|
const body = {
|
||||||
|
page: current,
|
||||||
|
perPage: pageSize,
|
||||||
|
...rest,
|
||||||
|
sorter: sorter,
|
||||||
|
...defaultParams,
|
||||||
|
};
|
||||||
|
setParams?.(body);
|
||||||
|
const data = await api(body);
|
||||||
|
setRes?.(data);
|
||||||
|
return {
|
||||||
|
data: data.data,
|
||||||
|
success: data.success,
|
||||||
|
total: data.meta?.total,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
214
src/common/components/schema/MyColumns.tsx
Normal file
214
src/common/components/schema/MyColumns.tsx
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import { MyResponseType, renderTextHelper } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProColumns } from '@ant-design/pro-components';
|
||||||
|
import { Popconfirm, Space, Tag } from 'antd';
|
||||||
|
|
||||||
|
type ReturnType = ProColumns<Record<string, any>, 'text'>;
|
||||||
|
|
||||||
|
export const MyColumns = {
|
||||||
|
ID(props?: ReturnType): ReturnType {
|
||||||
|
return { title: 'ID', dataIndex: 'id', hideInSearch: true, ...props };
|
||||||
|
},
|
||||||
|
DayStatus: (start: string, end: string) => {
|
||||||
|
const now = new Date();
|
||||||
|
const startDate = new Date(start);
|
||||||
|
const endDate = new Date(end);
|
||||||
|
// 判断当前时间与开始时间和结束时间的关系
|
||||||
|
if (now < startDate) {
|
||||||
|
return (
|
||||||
|
<Tag color="green" style={{ cursor: 'pointer' }}>
|
||||||
|
未开始
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
} else if (now > endDate) {
|
||||||
|
return (
|
||||||
|
<Tag color="default" style={{ cursor: 'pointer' }}>
|
||||||
|
已结束
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Tag color="#f50" style={{ cursor: 'pointer' }}>
|
||||||
|
进行中
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Images({ ...rest }: ReturnType): ReturnType {
|
||||||
|
return {
|
||||||
|
hideInSearch: true,
|
||||||
|
renderText: renderTextHelper.Images,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
SoftDelete({
|
||||||
|
onRestore,
|
||||||
|
onSoftDelete,
|
||||||
|
...rest
|
||||||
|
}: {
|
||||||
|
onRestore: (data: { id: number }) => Promise<MyResponseType>;
|
||||||
|
onSoftDelete: (data: { id: number }) => Promise<MyResponseType>;
|
||||||
|
} & ReturnType): ReturnType {
|
||||||
|
return {
|
||||||
|
title: '启/禁用',
|
||||||
|
render: (_, item, index, action) =>
|
||||||
|
item?.deleted_at ? (
|
||||||
|
<Popconfirm
|
||||||
|
title="启用"
|
||||||
|
description="您确认启用吗?"
|
||||||
|
onConfirm={() => {
|
||||||
|
onRestore?.({ id: item.id }).then(() => action?.reload());
|
||||||
|
}}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<Tag color="gray" style={{ cursor: 'pointer' }}>
|
||||||
|
已禁用
|
||||||
|
</Tag>
|
||||||
|
</Popconfirm>
|
||||||
|
) : (
|
||||||
|
<Popconfirm
|
||||||
|
title="禁用"
|
||||||
|
description="您确认禁用吗?"
|
||||||
|
onConfirm={() => {
|
||||||
|
onSoftDelete?.({ id: item.id }).then(() => action?.reload());
|
||||||
|
}}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<Tag color="green" style={{ cursor: 'pointer' }}>
|
||||||
|
已启用
|
||||||
|
</Tag>
|
||||||
|
</Popconfirm>
|
||||||
|
),
|
||||||
|
search: false,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
CreatedAt(props?: ReturnType): ReturnType {
|
||||||
|
return {
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
hideInSearch: true,
|
||||||
|
valueType: 'dateTime',
|
||||||
|
sorter: true,
|
||||||
|
align: 'right',
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
UpdatedAt(): ReturnType {
|
||||||
|
return {
|
||||||
|
title: '最近修改',
|
||||||
|
dataIndex: 'updated_at',
|
||||||
|
hideInSearch: true,
|
||||||
|
valueType: 'dateTime',
|
||||||
|
sorter: true,
|
||||||
|
align: 'right',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
FinishedAt(): ReturnType {
|
||||||
|
return {
|
||||||
|
title: '完成时间',
|
||||||
|
dataIndex: 'finished_at',
|
||||||
|
hideInSearch: true,
|
||||||
|
valueType: 'dateTime',
|
||||||
|
sorter: true,
|
||||||
|
align: 'right',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Boolean({ label, ...rest }: { label?: string[] } & ReturnType): ReturnType {
|
||||||
|
const option: { value: boolean; label: string; color: string }[] = [
|
||||||
|
{ value: false, label: label?.[0] ?? '否', color: 'gray' },
|
||||||
|
{ value: true, label: label?.[1] ?? '是', color: 'green' },
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
align: 'center',
|
||||||
|
request: async () => option,
|
||||||
|
renderText(text: boolean) {
|
||||||
|
const item = option.find((item) => item.value === Boolean(text));
|
||||||
|
return <Tag color={item?.color}>{item?.label}</Tag>;
|
||||||
|
},
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
YesOrNo({
|
||||||
|
yes = '已',
|
||||||
|
no = '未',
|
||||||
|
...rest
|
||||||
|
}: {
|
||||||
|
yes?: string;
|
||||||
|
no?: string;
|
||||||
|
} & ReturnType): ReturnType {
|
||||||
|
return {
|
||||||
|
align: 'center',
|
||||||
|
renderText(text) {
|
||||||
|
return (
|
||||||
|
<Tag bordered={false} color={text ? 'processing' : 'error'}>
|
||||||
|
{text ? yes : no}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
EnumTag({ ...rest }: ReturnType): ReturnType {
|
||||||
|
return {
|
||||||
|
align: 'center',
|
||||||
|
renderText(text: string | number) {
|
||||||
|
const _enum = rest.valueEnum ?? {};
|
||||||
|
if (!_enum) return <>-</>;
|
||||||
|
const item = _enum[text] ?? undefined;
|
||||||
|
if (!item) return <>-</>;
|
||||||
|
return <Tag color={item.color}>{item.text}</Tag>;
|
||||||
|
},
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Option({ ...rest }: ReturnType): ReturnType {
|
||||||
|
return {
|
||||||
|
title: '操作',
|
||||||
|
valueType: 'option',
|
||||||
|
align: 'right',
|
||||||
|
fixed: 'right',
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Network(props?: ReturnType): ReturnType {
|
||||||
|
return {
|
||||||
|
title: 'network',
|
||||||
|
...props,
|
||||||
|
render: (_: any, item: any) => {
|
||||||
|
const data = props?.dataIndex === 'network' ? item.network : item;
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
<img width={24} src={data.icon[0].url} />
|
||||||
|
<div>{data.name}</div>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
valueType: 'select',
|
||||||
|
key: 'networks_id',
|
||||||
|
fieldProps: {
|
||||||
|
fieldNames: { value: 'id', label: 'name' },
|
||||||
|
optionRender: (item: any) => {
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
<img width={24} src={item.data.icon[0].url} />
|
||||||
|
<div>{item.data.name}</div>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.Networks()).data,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Token({ ...rest }) {
|
||||||
|
return {
|
||||||
|
title: 'Token',
|
||||||
|
renderText(text: string) {
|
||||||
|
return <Tag color="blue">{text}</Tag>;
|
||||||
|
},
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
183
src/common/components/schema/MyFormItems.tsx
Normal file
183
src/common/components/schema/MyFormItems.tsx
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
import {
|
||||||
|
MyColorPicker,
|
||||||
|
MyIconSelect,
|
||||||
|
MyMoneyInput,
|
||||||
|
MyPercentInput,
|
||||||
|
MyUploadImages,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { ProFormColumnsType } from '@ant-design/pro-components';
|
||||||
|
// import { MyRichText } from '../components/FormFields/MyRichText';
|
||||||
|
|
||||||
|
type ReturnType = ProFormColumnsType<any, 'text'>;
|
||||||
|
type PropsType = { required?: boolean } & ReturnType;
|
||||||
|
|
||||||
|
export const MyFormItems = {
|
||||||
|
Text(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.text : {}),
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Integer(props: { min?: number } & PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'digit',
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.number : {}),
|
||||||
|
},
|
||||||
|
fieldProps: {
|
||||||
|
min: props.min ?? 1,
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Numeric(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'digit',
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.number : {}),
|
||||||
|
},
|
||||||
|
fieldProps: {
|
||||||
|
precision: 2,
|
||||||
|
min: 0,
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// RichText(props: PropsType): ReturnType {
|
||||||
|
// return {
|
||||||
|
// renderFormItem: () => <MyRichText />,
|
||||||
|
// formItemProps: {
|
||||||
|
// ...(props?.required ? rulesHelper.richtext : {}),
|
||||||
|
// },
|
||||||
|
// ...props,
|
||||||
|
// };
|
||||||
|
// },
|
||||||
|
UploadImages({
|
||||||
|
max = 1,
|
||||||
|
help,
|
||||||
|
...rest
|
||||||
|
}: { max?: number; help?: string } & PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
renderFormItem() {
|
||||||
|
return <MyUploadImages max={max} />;
|
||||||
|
},
|
||||||
|
formItemProps: {
|
||||||
|
help,
|
||||||
|
...(rest.required ?? false ? rulesHelper.upload({ max }) : {}),
|
||||||
|
},
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
EnumRadio(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'radioButton',
|
||||||
|
proFieldProps: {
|
||||||
|
placeholder: `请选择${props.title}`,
|
||||||
|
},
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.text : {}),
|
||||||
|
},
|
||||||
|
fieldProps: {
|
||||||
|
buttonStyle: 'solid',
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
EnumCheckbox(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'checkbox',
|
||||||
|
proFieldProps: {
|
||||||
|
placeholder: `请选择${props.title}`,
|
||||||
|
},
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.array : {}),
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
EnumSelect(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'select',
|
||||||
|
proFieldProps: {
|
||||||
|
placeholder: `请选择${props.title}`,
|
||||||
|
},
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.text : {}),
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Switch(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'switch',
|
||||||
|
initialValue: props.initialValue ?? false,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
DatePicker(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'date',
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.text : {}),
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Select(props: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
valueType: 'select',
|
||||||
|
proFieldProps: {
|
||||||
|
placeholder: `请选择${props.title}`,
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// EnumSelect(props: PropsType): ReturnType {
|
||||||
|
// const valueType = props.valueType ?? 'radioButton';
|
||||||
|
// const buttonStyle =
|
||||||
|
// valueType === 'radioButton'
|
||||||
|
// ? {
|
||||||
|
// buttonStyle: 'solid',
|
||||||
|
// }
|
||||||
|
// : {};
|
||||||
|
|
||||||
|
// },
|
||||||
|
IconSelect(props?: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
key: 'icon',
|
||||||
|
title: '图标',
|
||||||
|
renderFormItem: () => <MyIconSelect />,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
ColorPicker(props?: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
key: 'color',
|
||||||
|
dataIndex: 'color',
|
||||||
|
title: '颜色',
|
||||||
|
renderFormItem: () => <MyColorPicker />,
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Percent(props?: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
renderFormItem: () => <MyPercentInput />,
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.number : {}),
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Money(props?: PropsType): ReturnType {
|
||||||
|
return {
|
||||||
|
renderFormItem: () => <MyMoneyInput />,
|
||||||
|
formItemProps: {
|
||||||
|
...(props?.required ? rulesHelper.number : {}),
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
41
src/common/index.tsx
Normal file
41
src/common/index.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// components
|
||||||
|
export * from './components/formFields/MyColorPicker';
|
||||||
|
export * from './components/formFields/MyIconSelect';
|
||||||
|
export * from './components/formFields/MyMoneyInput';
|
||||||
|
export * from './components/formFields/MyPercentInput';
|
||||||
|
export * from './components/formFields/MyTreeCheckable';
|
||||||
|
export * from './components/formFields/MyUploadImages';
|
||||||
|
|
||||||
|
export * from './components/layout/MyCommonModal';
|
||||||
|
export * from './components/layout/MyImportModal';
|
||||||
|
export * from './components/layout/MyPageContainer';
|
||||||
|
export * from './components/layout/MyRootContainer';
|
||||||
|
|
||||||
|
export * from './components/props/MyDrawerProps';
|
||||||
|
export * from './components/props/MyModalFormProps';
|
||||||
|
export * from './components/props/MyProTableProps';
|
||||||
|
|
||||||
|
export * from './components/schema/MyColumns';
|
||||||
|
export * from './components/schema/MyFormItems';
|
||||||
|
|
||||||
|
export * from './components/MyButtons';
|
||||||
|
export * from './components/MyIcons';
|
||||||
|
export * from './components/MyStatistics';
|
||||||
|
|
||||||
|
// libs
|
||||||
|
export * from './libs/umi/layoutConfig';
|
||||||
|
export * from './libs/umi/requestConfig';
|
||||||
|
|
||||||
|
export * from './libs/valtio/actions';
|
||||||
|
export * from './libs/valtio/state';
|
||||||
|
|
||||||
|
// pages
|
||||||
|
export * from './pages/MyLoginPage1';
|
||||||
|
export * from './pages/NewMyS2Table';
|
||||||
|
|
||||||
|
// utils
|
||||||
|
export * from './utils/renderTextHelper';
|
||||||
|
export * from './utils/rulesHelper';
|
||||||
|
|
||||||
|
// typings
|
||||||
|
export * from './typings.d';
|
||||||
5
src/common/libs/umi/access.tsx
Normal file
5
src/common/libs/umi/access.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
export default function MyAccess({ children }: { children: ReactNode }) {
|
||||||
|
return <div>MyAccess</div>;
|
||||||
|
}
|
||||||
77
src/common/libs/umi/layoutConfig.tsx
Normal file
77
src/common/libs/umi/layoutConfig.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import Logo from '@/assets/bitcoin.webp';
|
||||||
|
import { MyIcons, MyIconsType, PermissionsType, useMyState } from '@/common';
|
||||||
|
import { Link, RuntimeConfig, history } from '@umijs/max';
|
||||||
|
import AvatarProps from '../../components/layout/AvatarProps';
|
||||||
|
|
||||||
|
const loopMenu = (permissions: PermissionsType[] | undefined) => {
|
||||||
|
let tree: PermissionsType[] = [];
|
||||||
|
let map: Record<number, PermissionsType> = {};
|
||||||
|
permissions?.forEach((permission) => {
|
||||||
|
map[permission.id] = {
|
||||||
|
path: permission.type === 'Button' ? 'null' : permission.path,
|
||||||
|
name: permission.name,
|
||||||
|
icon: permission.icon && MyIcons[permission.icon as MyIconsType],
|
||||||
|
children: [],
|
||||||
|
hideInMenu: permission.type === 'Button',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
permissions?.forEach((permission) => {
|
||||||
|
let node = map[permission.id];
|
||||||
|
if (permission.parent_id !== null) {
|
||||||
|
map[permission.parent_id].children.push(node);
|
||||||
|
} else {
|
||||||
|
tree.push(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return tree?.[0]?.children;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LayoutConfig: RuntimeConfig['layout'] = () => {
|
||||||
|
const { snap } = useMyState();
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: snap.session.campus?.name ?? '总后台',
|
||||||
|
logo: <img src={Logo} style={{ height: '30px' }} />,
|
||||||
|
layout: 'mix',
|
||||||
|
colorPrimary: '#1890ff',
|
||||||
|
siderWidth: 220,
|
||||||
|
pure: history.location.pathname === '/login',
|
||||||
|
avatarProps: {
|
||||||
|
render: () => <AvatarProps user={snap.session.user} />,
|
||||||
|
},
|
||||||
|
waterMarkProps: {
|
||||||
|
content: snap.session.user?.username,
|
||||||
|
},
|
||||||
|
collapsedButtonRender: false,
|
||||||
|
token: {
|
||||||
|
bgLayout: '#eef0f3',
|
||||||
|
header: {
|
||||||
|
colorBgHeader: '#001529',
|
||||||
|
colorHeaderTitle: '#FFF',
|
||||||
|
colorTextRightActionsItem: '#FFF',
|
||||||
|
heightLayoutHeader: 50,
|
||||||
|
},
|
||||||
|
sider: {
|
||||||
|
colorMenuBackground: '#FFF',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
menuItemRender: (item, dom) => <Link to={item.path || '/'}>{dom}</Link>,
|
||||||
|
menu: {
|
||||||
|
params: snap.session.permissions,
|
||||||
|
request: async () => {
|
||||||
|
let objjs: any = [];
|
||||||
|
snap.session.permissions?.forEach((res: any) => {
|
||||||
|
objjs.push(res);
|
||||||
|
});
|
||||||
|
let data = objjs.sort((a: any, b: any) => {
|
||||||
|
return a._lft - b._lft;
|
||||||
|
});
|
||||||
|
const menus = loopMenu(data);
|
||||||
|
return Promise.resolve(menus);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
unAccessible: <div>unAccessible</div>,
|
||||||
|
};
|
||||||
|
};
|
||||||
87
src/common/libs/umi/requestConfig.ts
Normal file
87
src/common/libs/umi/requestConfig.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import type { RequestConfig } from '@umijs/max';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { history } from 'umi';
|
||||||
|
import { stateActions } from '../valtio/actions';
|
||||||
|
import { state } from '../valtio/state';
|
||||||
|
|
||||||
|
const downloadFile = (disposition: string, data: any) => {
|
||||||
|
const blob = new Blob([data]);
|
||||||
|
const start = "filename*=utf-8''";
|
||||||
|
let fileName = '';
|
||||||
|
let dis = disposition.replace('UTF-8', 'utf-8');
|
||||||
|
// console.log(dis, 'dis');
|
||||||
|
if (dis.includes(start)) {
|
||||||
|
fileName = dis.substr(dis.indexOf(start) + start.length);
|
||||||
|
fileName = decodeURI(fileName);
|
||||||
|
}
|
||||||
|
if ('download' in document.createElement('a')) {
|
||||||
|
// 非IE下载
|
||||||
|
const elink: any = document.createElement('a');
|
||||||
|
elink.download = fileName;
|
||||||
|
elink.style.display = 'none';
|
||||||
|
elink.href = URL.createObjectURL(blob);
|
||||||
|
document.body.appendChild(elink);
|
||||||
|
elink.click();
|
||||||
|
URL.revokeObjectURL(elink.href); // 释放URL 对象
|
||||||
|
document.body.removeChild(elink);
|
||||||
|
} else {
|
||||||
|
// IE10+下载
|
||||||
|
// navigator.msSaveBlob(blob, fileName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const requestConfig: RequestConfig = {
|
||||||
|
baseURL: '/api/',
|
||||||
|
timeout: 1000 * 60,
|
||||||
|
method: 'POST',
|
||||||
|
errorConfig: {
|
||||||
|
errorThrower: (res) => {
|
||||||
|
console.log('errorThrower', res);
|
||||||
|
},
|
||||||
|
// 错误接收及处理
|
||||||
|
errorHandler: (error: any) => {
|
||||||
|
if (error) {
|
||||||
|
message.error(error.errorMessage);
|
||||||
|
switch (error.errorCode) {
|
||||||
|
case 10000:
|
||||||
|
if (history.location.pathname !== '/login') history.push('/login');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// 请求拦截器
|
||||||
|
requestInterceptors: [
|
||||||
|
(url: string, options: any) => {
|
||||||
|
stateActions.addLoading();
|
||||||
|
return {
|
||||||
|
url: url,
|
||||||
|
options: {
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
authorization: 'Bearer ' + state.storage.access_token,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
responseInterceptors: [
|
||||||
|
(response: any) => {
|
||||||
|
stateActions.subLoading();
|
||||||
|
const { headers } = response;
|
||||||
|
// console.log(headers['content-disposition'], 'response');
|
||||||
|
if (headers['content-disposition']) {
|
||||||
|
downloadFile(headers['content-disposition'], response.data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const { data = {} as any } = response;
|
||||||
|
if (!data.success && data.type !== 'application/vnd.ms-excel') {
|
||||||
|
return Promise.reject(response.data);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
50
src/common/libs/valtio/actions.ts
Normal file
50
src/common/libs/valtio/actions.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { MyResponseType } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { state } from './state';
|
||||||
|
|
||||||
|
export const stateActions = {
|
||||||
|
addLoading() {
|
||||||
|
state.session.loading++;
|
||||||
|
},
|
||||||
|
subLoading() {
|
||||||
|
state.session.loading--;
|
||||||
|
},
|
||||||
|
setReady(val: boolean) {
|
||||||
|
state.session.ready = val;
|
||||||
|
},
|
||||||
|
setLogin(res: MyResponseType) {
|
||||||
|
state.session.user = res.data.user;
|
||||||
|
state.session.campus = res.data.campus;
|
||||||
|
state.session.permissions = res.data.permissions;
|
||||||
|
if (res.data?.token?.access_token)
|
||||||
|
state.storage.access_token = res.data?.token?.access_token;
|
||||||
|
// 解析apis
|
||||||
|
const apiKeys: string[] = [];
|
||||||
|
res.data.permissions.forEach((permission: any) => {
|
||||||
|
if (permission.key) {
|
||||||
|
apiKeys.push(permission.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// console.log('apis', apis);
|
||||||
|
state.session.apiKeys = apiKeys;
|
||||||
|
},
|
||||||
|
setLogout() {
|
||||||
|
state.session.user = undefined;
|
||||||
|
state.session.campus = undefined;
|
||||||
|
state.session.permissions = undefined;
|
||||||
|
state.storage.access_token = undefined;
|
||||||
|
},
|
||||||
|
me: async () => {
|
||||||
|
const res = await Apis.Auth.Me();
|
||||||
|
if (res.success) {
|
||||||
|
stateActions.setLogin(res);
|
||||||
|
return {
|
||||||
|
name: state.session.user.username,
|
||||||
|
apiKeys: state.session.apiKeys,
|
||||||
|
// permissions: res.data.permissions,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return { name: '未登录', apiKeys: [] };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
60
src/common/libs/valtio/state.ts
Normal file
60
src/common/libs/valtio/state.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
import { proxy, snapshot, subscribe, useSnapshot } from 'valtio';
|
||||||
|
|
||||||
|
function proxyWithPersistant<V>(
|
||||||
|
val: V,
|
||||||
|
opts: {
|
||||||
|
key: string;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const local = localStorage.getItem(opts.key);
|
||||||
|
const state = proxy(local ? JSON.parse(local) : val);
|
||||||
|
subscribe(state, () => {
|
||||||
|
localStorage.setItem(opts.key, JSON.stringify(snapshot(state)));
|
||||||
|
});
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
type StorageType = {
|
||||||
|
access_token: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const storage: StorageType = proxyWithPersistant(
|
||||||
|
{
|
||||||
|
access_token: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: process.env.TOKEN_NAME as string,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
type SessionType = {
|
||||||
|
ready: boolean;
|
||||||
|
user?: any;
|
||||||
|
campus?: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
permissions?: any;
|
||||||
|
apiKeys: string[];
|
||||||
|
loading: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const session: SessionType = proxy({
|
||||||
|
ready: false,
|
||||||
|
user: undefined,
|
||||||
|
campus: undefined,
|
||||||
|
permissions: undefined,
|
||||||
|
apiKeys: [],
|
||||||
|
loading: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const state = proxy({
|
||||||
|
storage,
|
||||||
|
session,
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useMyState() {
|
||||||
|
const snap = useSnapshot(state);
|
||||||
|
return { snap };
|
||||||
|
}
|
||||||
125
src/common/pages/MyLoginPage1.tsx
Normal file
125
src/common/pages/MyLoginPage1.tsx
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import {
|
||||||
|
FieldTimeOutlined,
|
||||||
|
LockOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
LoginFormPage,
|
||||||
|
ProConfigProvider,
|
||||||
|
ProFormText,
|
||||||
|
} from '@ant-design/pro-components';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { stateActions } from '..';
|
||||||
|
|
||||||
|
export function MyLoginPage1() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [getCaptcha, setCaptcha] = useState<any>({});
|
||||||
|
const methods = {
|
||||||
|
getCaptcha: () => {
|
||||||
|
Apis.Auth.Captcha().then(async (res) => {
|
||||||
|
setCaptcha(res?.data);
|
||||||
|
console.log(res, 'res');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
methods?.getCaptcha();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<ProConfigProvider>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#f8f8f8',
|
||||||
|
height: '100vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LoginFormPage<ApiTypes.Auth.Login>
|
||||||
|
title="欢迎使用后台管理系统"
|
||||||
|
backgroundVideoUrl="https://gw.alipayobjects.com/v/huamei_gcee1x/afts/video/jXRBRK_VAwoAAAAAAAAAAAAAK4eUAQBr"
|
||||||
|
subTitle="Admin management system"
|
||||||
|
onFinish={async (values: any) => {
|
||||||
|
Apis.Auth.Login({
|
||||||
|
...values,
|
||||||
|
...{ captcha_key: getCaptcha?.key },
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
await stateActions.setLogin(res);
|
||||||
|
navigate('/');
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
methods?.getCaptcha();
|
||||||
|
console.log(err, 'rr');
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
<ProFormText
|
||||||
|
name="username"
|
||||||
|
fieldProps={{
|
||||||
|
size: 'large',
|
||||||
|
prefix: <UserOutlined className={'prefixIcon'} />,
|
||||||
|
}}
|
||||||
|
placeholder={'登录账号'}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入登录账号!',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<ProFormText.Password
|
||||||
|
name="password"
|
||||||
|
fieldProps={{
|
||||||
|
size: 'large',
|
||||||
|
prefix: <LockOutlined className={'prefixIcon'} />,
|
||||||
|
}}
|
||||||
|
placeholder={'登录密码'}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入密码!',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<ProFormText
|
||||||
|
name="captcha"
|
||||||
|
fieldProps={{
|
||||||
|
size: 'large',
|
||||||
|
prefix: <FieldTimeOutlined className={'prefixIcon'} />,
|
||||||
|
}}
|
||||||
|
placeholder={'验证码'}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入验证码!',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: '40px',
|
||||||
|
border: '1px solid #eee',
|
||||||
|
padding: '0 2px',
|
||||||
|
margin: '0 10px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderRadius: '3px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
methods?.getCaptcha();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img height={32} width={100} src={getCaptcha?.img} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
</LoginFormPage>
|
||||||
|
</div>
|
||||||
|
</ProConfigProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
51
src/common/pages/NewMyS2Table/MyS2TableComponent.tsx
Normal file
51
src/common/pages/NewMyS2Table/MyS2TableComponent.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { SheetComponent } from '@antv/s2-react';
|
||||||
|
import { DataType } from '.';
|
||||||
|
|
||||||
|
export function MyS2TableComponent(props: DataType) {
|
||||||
|
return (
|
||||||
|
<SheetComponent
|
||||||
|
sheetType="pivot"
|
||||||
|
dataCfg={{
|
||||||
|
fields: props.fields,
|
||||||
|
data: props.data,
|
||||||
|
meta: props.meta,
|
||||||
|
}}
|
||||||
|
adaptive={true}
|
||||||
|
options={{
|
||||||
|
height: 888,
|
||||||
|
hierarchyType: props.config?.hierarchyType,
|
||||||
|
// style: {
|
||||||
|
// layoutWidthType: 'colAdaptive',
|
||||||
|
// },
|
||||||
|
totals: {
|
||||||
|
row: {
|
||||||
|
showGrandTotals: props.config.rowGrandTotals,
|
||||||
|
showSubTotals: props.config.rowSubTotals,
|
||||||
|
reverseGrandTotalsLayout: true,
|
||||||
|
reverseSubTotalsLayout: true,
|
||||||
|
calcGrandTotals: {
|
||||||
|
aggregation: 'SUM',
|
||||||
|
},
|
||||||
|
calcSubTotals: {
|
||||||
|
aggregation: 'SUM',
|
||||||
|
},
|
||||||
|
// grandTotalsGroupDimensions: ['day'],
|
||||||
|
// subTotalsGroupDimensions: ['day'],
|
||||||
|
},
|
||||||
|
col: {
|
||||||
|
showGrandTotals: props.config.colGrandTotals,
|
||||||
|
showSubTotals: props.config.colSubTotals,
|
||||||
|
reverseGrandTotalsLayout: true,
|
||||||
|
reverseSubTotalsLayout: true,
|
||||||
|
calcGrandTotals: {
|
||||||
|
aggregation: 'SUM',
|
||||||
|
},
|
||||||
|
calcSubTotals: {
|
||||||
|
aggregation: 'SUM',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
106
src/common/pages/NewMyS2Table/MyS2TableExtra.tsx
Normal file
106
src/common/pages/NewMyS2Table/MyS2TableExtra.tsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { Button, Radio, Space, Switch, Typography } from 'antd';
|
||||||
|
import { DataType } from '.';
|
||||||
|
|
||||||
|
function downloadCSV(json: any) {
|
||||||
|
if (json === undefined) return;
|
||||||
|
// 提取表头
|
||||||
|
const headers = Object.keys(json[0]);
|
||||||
|
// 提取数据行
|
||||||
|
const rows = json.map((item: any) => Object.values(item));
|
||||||
|
|
||||||
|
// 构建CSV内容
|
||||||
|
let csvContent = '';
|
||||||
|
// 添加表头
|
||||||
|
csvContent += headers.join(',') + '\r\n';
|
||||||
|
// 添加数据行
|
||||||
|
rows.forEach((row: any) => {
|
||||||
|
csvContent += row.join(',') + '\r\n';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建一个Blob对象,使用CSV内容,并设置类型为text/csv
|
||||||
|
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||||
|
|
||||||
|
// 创建一个链接元素
|
||||||
|
const link = document.createElement('a');
|
||||||
|
// 设置下载的文件名,默认为'download.csv'
|
||||||
|
if (link.download !== undefined) {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
link.setAttribute('href', url);
|
||||||
|
link.setAttribute('download', 'download.csv');
|
||||||
|
// 触发点击事件以下载文件
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
// 清理DOM
|
||||||
|
document.body.removeChild(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MyS2TableExtra({
|
||||||
|
config,
|
||||||
|
data,
|
||||||
|
setConfig,
|
||||||
|
}: {
|
||||||
|
config: DataType['config'];
|
||||||
|
data: DataType['data'];
|
||||||
|
setConfig: (config: DataType['config']) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
<Typography.Text style={{ marginLeft: 20 }}>行小计:</Typography.Text>
|
||||||
|
<Switch
|
||||||
|
value={config?.rowSubTotals || false}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig({ ...config, rowSubTotals: Boolean(e) });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography.Text style={{ marginLeft: 20 }}>行总计:</Typography.Text>
|
||||||
|
<Switch
|
||||||
|
value={config?.rowGrandTotals || false}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig({ ...config, rowGrandTotals: Boolean(e) });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography.Text style={{ marginLeft: 20 }}>列小计:</Typography.Text>
|
||||||
|
<Switch
|
||||||
|
value={config?.colSubTotals || false}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig({ ...config, colSubTotals: Boolean(e) });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography.Text style={{ marginLeft: 20 }}>列总计:</Typography.Text>
|
||||||
|
<Switch
|
||||||
|
value={config?.colGrandTotals || false}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig({ ...config, colGrandTotals: Boolean(e) });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography.Text style={{ marginLeft: 20 }}>类型:</Typography.Text>
|
||||||
|
<Radio.Group
|
||||||
|
size="small"
|
||||||
|
options={[
|
||||||
|
{ label: '树形', value: 'tree' },
|
||||||
|
{ label: '平铺', value: 'grid' },
|
||||||
|
]}
|
||||||
|
value={config?.hierarchyType || 'tree'}
|
||||||
|
onChange={(e) =>
|
||||||
|
setConfig({
|
||||||
|
...config,
|
||||||
|
hierarchyType: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
optionType="button"
|
||||||
|
buttonStyle="solid"
|
||||||
|
style={{ marginRight: 20 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
downloadCSV(data);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
新的导出
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
73
src/common/pages/NewMyS2Table/MySwitcherFields.tsx
Normal file
73
src/common/pages/NewMyS2Table/MySwitcherFields.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { Switcher } from '@antv/s2-react';
|
||||||
|
import { useSetState } from 'react-use';
|
||||||
|
import { DataType } from '.';
|
||||||
|
|
||||||
|
export function MySwitcherFields({
|
||||||
|
fields,
|
||||||
|
setFields,
|
||||||
|
}: {
|
||||||
|
fields: DataType['fields'];
|
||||||
|
setFields: (fields: DataType['fields']) => void;
|
||||||
|
}) {
|
||||||
|
const [switcherFields, setSwitcherFields] = useSetState(() => {
|
||||||
|
return {
|
||||||
|
rows: {
|
||||||
|
selectable: true,
|
||||||
|
allowEmpty: false,
|
||||||
|
items: fields.rows?.map((item) => {
|
||||||
|
return { id: item };
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
selectable: true,
|
||||||
|
allowEmpty: true,
|
||||||
|
items: fields.columns?.map((item) => {
|
||||||
|
return { id: item };
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
values: {
|
||||||
|
selectable: true,
|
||||||
|
allowEmpty: false,
|
||||||
|
items: fields.values?.map((item) => {
|
||||||
|
return { id: item };
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function onSwitcherChange(result: any): void {
|
||||||
|
const fields = {
|
||||||
|
rows: result.rows.items
|
||||||
|
.filter((item: { checked?: boolean }) => item.checked ?? true)
|
||||||
|
.map((item: { id: string }) => item.id),
|
||||||
|
columns: result.columns.items
|
||||||
|
.filter((item: { checked?: boolean }) => item.checked ?? true)
|
||||||
|
.map((item: { id: string }) => item.id),
|
||||||
|
values: result.values.items
|
||||||
|
.filter((item: { checked?: boolean }) => item.checked ?? true)
|
||||||
|
.map((item: { id: string }) => item.id),
|
||||||
|
};
|
||||||
|
|
||||||
|
setSwitcherFields({
|
||||||
|
rows: {
|
||||||
|
selectable: true,
|
||||||
|
allowEmpty: false,
|
||||||
|
items: result.rows.items,
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
selectable: true,
|
||||||
|
allowEmpty: true,
|
||||||
|
items: result.columns.items,
|
||||||
|
},
|
||||||
|
values: {
|
||||||
|
selectable: true,
|
||||||
|
allowEmpty: false,
|
||||||
|
items: result.values.items,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
setFields?.(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Switcher {...switcherFields} onSubmit={onSwitcherChange} />;
|
||||||
|
}
|
||||||
22
src/common/pages/NewMyS2Table/Query.tsx
Normal file
22
src/common/pages/NewMyS2Table/Query.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { BetaSchemaForm, ProCard } from '@ant-design/pro-components';
|
||||||
|
import { PropsType } from '.';
|
||||||
|
|
||||||
|
export default function Query({
|
||||||
|
columns,
|
||||||
|
doRequest,
|
||||||
|
}: {
|
||||||
|
columns?: PropsType['columns'];
|
||||||
|
doRequest: (values: any) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<ProCard>
|
||||||
|
<BetaSchemaForm
|
||||||
|
layoutType="QueryFilter"
|
||||||
|
onFinish={async (values: Record<string, any>) => {
|
||||||
|
doRequest(values);
|
||||||
|
}}
|
||||||
|
columns={columns as any}
|
||||||
|
/>
|
||||||
|
</ProCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
116
src/common/pages/NewMyS2Table/index.tsx
Normal file
116
src/common/pages/NewMyS2Table/index.tsx
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import { MyPageContainer } from '@/common';
|
||||||
|
import { MyResponseType } from '@/common/typings';
|
||||||
|
import { ProCard, ProFormColumnsType } from '@ant-design/pro-components';
|
||||||
|
import { Fields, HierarchyType, Meta, RawData } from '@antv/s2';
|
||||||
|
import { Flex, Space } from 'antd';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useSetState } from 'react-use';
|
||||||
|
import { MyS2TableComponent } from './MyS2TableComponent';
|
||||||
|
import { MyS2TableExtra } from './MyS2TableExtra';
|
||||||
|
import { MySwitcherFields } from './MySwitcherFields';
|
||||||
|
import Query from './Query';
|
||||||
|
|
||||||
|
export type PropsType = {
|
||||||
|
title: string;
|
||||||
|
api: (values?: any) => Promise<MyResponseType>;
|
||||||
|
defaultParams?: Record<string, any>;
|
||||||
|
columns?: ProFormColumnsType<Record<string, any>, 'text'>[] | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DataType = {
|
||||||
|
config: {
|
||||||
|
hierarchyType: HierarchyType | undefined;
|
||||||
|
rowGrandTotals: boolean;
|
||||||
|
rowSubTotals: boolean;
|
||||||
|
colGrandTotals: boolean;
|
||||||
|
colSubTotals: boolean;
|
||||||
|
};
|
||||||
|
data: RawData[];
|
||||||
|
fields: Fields;
|
||||||
|
meta?: Meta[];
|
||||||
|
query?: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function NewMyS2Table(props: PropsType) {
|
||||||
|
const [data, setData] = useSetState<DataType>(undefined);
|
||||||
|
|
||||||
|
// 请求数据
|
||||||
|
function doRequest() {
|
||||||
|
props
|
||||||
|
.api?.({ ...props.defaultParams, ...data.query, fields: data.fields })
|
||||||
|
.then((resp) => {
|
||||||
|
if (!data.config)
|
||||||
|
setData({
|
||||||
|
config: resp.data.config,
|
||||||
|
data: resp.data.data,
|
||||||
|
fields: resp.data.fields,
|
||||||
|
meta: resp.data.meta,
|
||||||
|
});
|
||||||
|
else setData({ data: resp.data.data });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 如果没有columns,直接发起请求
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (props.columns === undefined) doRequest({});
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('useEffect query', data.query, data.fields);
|
||||||
|
if (!data.query && !data.fields) {
|
||||||
|
if (props.columns === undefined) {
|
||||||
|
doRequest();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doRequest();
|
||||||
|
}
|
||||||
|
}, [data.query, data.fields]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={props.title}>
|
||||||
|
{props.columns && (
|
||||||
|
<Query
|
||||||
|
columns={props.columns}
|
||||||
|
doRequest={(values) => {
|
||||||
|
setData({ query: values });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<ProCard>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }}>
|
||||||
|
<Flex
|
||||||
|
justify="space-between"
|
||||||
|
style={{ width: '100%', margin: '10px 0' }}
|
||||||
|
>
|
||||||
|
{data.fields && (
|
||||||
|
<MySwitcherFields
|
||||||
|
fields={data.fields}
|
||||||
|
setFields={(fields: DataType['fields']) => {
|
||||||
|
console.log('fields', fields);
|
||||||
|
setData({ fields });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{data.config && (
|
||||||
|
<MyS2TableExtra
|
||||||
|
config={data.config}
|
||||||
|
setConfig={(config) => {
|
||||||
|
setData({ config });
|
||||||
|
}}
|
||||||
|
data={data.data}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
{data.config && (
|
||||||
|
<MyS2TableComponent
|
||||||
|
config={data.config}
|
||||||
|
fields={data.fields}
|
||||||
|
meta={data.meta}
|
||||||
|
data={data.data}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</ProCard>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
68
src/common/typings.d.ts
vendored
Normal file
68
src/common/typings.d.ts
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { ProColumns, ProFormColumnsType } from '@ant-design/pro-components';
|
||||||
|
|
||||||
|
type MyColumnsType =
|
||||||
|
| ProFormColumnsType<any, 'text'>
|
||||||
|
| ProColumns<any, FormFieldType | 'text' | any>;
|
||||||
|
|
||||||
|
type MyResponseType = {
|
||||||
|
success?: boolean;
|
||||||
|
data?: any;
|
||||||
|
errorCode?: number;
|
||||||
|
errorMessage?: string;
|
||||||
|
showType?: ErrorShowType;
|
||||||
|
meta?: MyPaginationMetaType;
|
||||||
|
};
|
||||||
|
|
||||||
|
type MyPaginationMetaType = {
|
||||||
|
current_page: number;
|
||||||
|
last_page: number;
|
||||||
|
per_page: number;
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type MyParamsType<T> = {
|
||||||
|
q: T;
|
||||||
|
p?: { page: number; perPage: number };
|
||||||
|
t?: { sorter: { sort: string; order: string } };
|
||||||
|
};
|
||||||
|
|
||||||
|
type PermissionsType = MenuDataItem & {
|
||||||
|
parent_id: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type MyModalRefType = {
|
||||||
|
showModal: (data: MyModalProps) => void;
|
||||||
|
hideModal: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
// export type MyModalFormProps = {
|
||||||
|
// refresh: () => void;
|
||||||
|
// item?: Record<string, any>;
|
||||||
|
// title: string;
|
||||||
|
// } & ModalFormProps;
|
||||||
|
|
||||||
|
type MyProFormFieldProps<T> = {
|
||||||
|
value?: T;
|
||||||
|
onChange?: (value: T) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
// type MyEnumItemProps = {
|
||||||
|
// label: string;
|
||||||
|
// value: string | number;
|
||||||
|
// color: string;
|
||||||
|
// textColor: string;
|
||||||
|
// };
|
||||||
|
|
||||||
|
export type MyBetaModalFormProps = {
|
||||||
|
title?: string;
|
||||||
|
// action: ActionType | undefined;
|
||||||
|
reload?: () => void;
|
||||||
|
item?: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MyProEnumItemProps = {
|
||||||
|
[key: string]: {
|
||||||
|
text: string;
|
||||||
|
color?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
14
src/common/utils/mockHelper.ts
Normal file
14
src/common/utils/mockHelper.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export function error(msg: string = '系统错误', code: number = 999) {
|
||||||
|
return {
|
||||||
|
errorCode: code,
|
||||||
|
success: false,
|
||||||
|
errorMessage: msg,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mockSuccess(data: any) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
}
|
||||||
53
src/common/utils/renderTextHelper.tsx
Normal file
53
src/common/utils/renderTextHelper.tsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { Image, Space, Tag } from 'antd';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
|
export const renderTextHelper = {
|
||||||
|
TagList(items: { label: string; value: string; color: string }[]) {
|
||||||
|
return (
|
||||||
|
<Space>
|
||||||
|
{items?.map((item) => (
|
||||||
|
<Tag color={item.color} key={item.value}>
|
||||||
|
{item.label}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Tag({
|
||||||
|
Enums,
|
||||||
|
value,
|
||||||
|
isColor = true,
|
||||||
|
}: {
|
||||||
|
Enums?: any;
|
||||||
|
value?: any;
|
||||||
|
isColor?: any;
|
||||||
|
}) {
|
||||||
|
let item: any = Object.values(Enums).find((data: any) => {
|
||||||
|
return data.value === '' + value;
|
||||||
|
});
|
||||||
|
return isColor ? (
|
||||||
|
<Tag color={item?.color}>{item?.text}</Tag>
|
||||||
|
) : (
|
||||||
|
<>{item?.text}</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Images(images: string[]) {
|
||||||
|
return (
|
||||||
|
<Image.PreviewGroup>
|
||||||
|
{images?.map((img: any) => (
|
||||||
|
<Image
|
||||||
|
key={img.uid}
|
||||||
|
width={100}
|
||||||
|
// height={100}
|
||||||
|
src={img.url}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Image.PreviewGroup>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
RelativeTo(value: string) {
|
||||||
|
return dayjs().to(dayjs(value));
|
||||||
|
},
|
||||||
|
};
|
||||||
109
src/common/utils/rulesHelper.ts
Normal file
109
src/common/utils/rulesHelper.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { Rule } from 'antd/es/form';
|
||||||
|
|
||||||
|
export const rulesHelper = {
|
||||||
|
text: {
|
||||||
|
required: true,
|
||||||
|
rules: [
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
return value && value !== ''
|
||||||
|
? Promise.resolve()
|
||||||
|
: Promise.reject(new Error('不能为空'));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
] as Rule[],
|
||||||
|
},
|
||||||
|
upload(props?: { max?: number; errMsg?: string }) {
|
||||||
|
return {
|
||||||
|
required: true,
|
||||||
|
rules: [
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (!value) return Promise.reject(new Error('请上传'));
|
||||||
|
let doneUploads = value?.filter(
|
||||||
|
(item: { status: string }) => item.status === 'done',
|
||||||
|
);
|
||||||
|
if (!doneUploads) return Promise.reject(new Error('请上传'));
|
||||||
|
|
||||||
|
return doneUploads.length > (props?.max ?? 1)
|
||||||
|
? Promise.reject(new Error(props?.errMsg ?? '请上传'))
|
||||||
|
: Promise.resolve();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
] as Rule[],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
required: true,
|
||||||
|
rules: [
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (value !== undefined && value !== '' && !isNaN(Number(value))) {
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error('请输入数字,且不能为空'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
] as Rule[],
|
||||||
|
},
|
||||||
|
boolean: {
|
||||||
|
required: true,
|
||||||
|
rules: [
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
return value !== undefined && value !== ''
|
||||||
|
? Promise.resolve()
|
||||||
|
: Promise.reject(new Error('不能为空'));
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
] as Rule[],
|
||||||
|
},
|
||||||
|
richtext: {
|
||||||
|
required: true,
|
||||||
|
rules: [
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (value && value !== '<p><br></p>') {
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error('不能为空'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
] as Rule[],
|
||||||
|
},
|
||||||
|
array: {
|
||||||
|
required: true,
|
||||||
|
rules: [
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error('不能为空'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
] as Rule[],
|
||||||
|
},
|
||||||
|
cascader: {
|
||||||
|
required: true,
|
||||||
|
rules: [
|
||||||
|
() => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
value.forEach((item: any) => {
|
||||||
|
if (item === undefined) {
|
||||||
|
return Promise.reject(new Error('不能为空'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error('不能为空'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
] as Rule[],
|
||||||
|
},
|
||||||
|
};
|
||||||
205
src/components/Selects.tsx
Normal file
205
src/components/Selects.tsx
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
import { rulesHelper } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProColumns, ProFormColumnsType } from '@ant-design/pro-components';
|
||||||
|
|
||||||
|
type ReturnType = ProColumns<any, 'text'> & ProFormColumnsType<any, 'text'>;
|
||||||
|
type PropsType = { required?: boolean } & ReturnType;
|
||||||
|
|
||||||
|
export const Selects = {
|
||||||
|
Agents(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '代理',
|
||||||
|
key = 'agents_id',
|
||||||
|
dataIndex = ['agent', 'name'],
|
||||||
|
required = false,
|
||||||
|
hideInTable = false,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
dataIndex: dataIndex,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.Agents()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
LoanCompany(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '资金方',
|
||||||
|
key = 'loan_companies_id',
|
||||||
|
dataIndex = ['loan_company', 'name'],
|
||||||
|
required = false,
|
||||||
|
hideInTable = false,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
dataIndex: dataIndex,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.LoanCompanies()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Markets(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '选择上游',
|
||||||
|
key = 'markets_id',
|
||||||
|
dataIndex = ['market', 'name'],
|
||||||
|
required = false,
|
||||||
|
hideInTable = false,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
dataIndex: dataIndex,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.Markets()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Bosses(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '老板',
|
||||||
|
key = 'bosses_id',
|
||||||
|
dataIndex = ['boss', 'name'],
|
||||||
|
required = false,
|
||||||
|
hideInTable = false,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
dataIndex: dataIndex,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.Bosses()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Factories(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '下游厂家',
|
||||||
|
key = 'factories_id',
|
||||||
|
dataIndex = ['factory', 'name'],
|
||||||
|
required = false,
|
||||||
|
hideInTable = false,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
dataIndex: dataIndex,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.Factories()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Platforms(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '平台',
|
||||||
|
key = 'platforms_id',
|
||||||
|
dataIndex = ['platform', 'name'],
|
||||||
|
required = false,
|
||||||
|
hideInTable = false,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
dataIndex: dataIndex,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.Platforms()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Merchants(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '商户',
|
||||||
|
key = 'merchants_id',
|
||||||
|
dataIndex = ['merchant', 'name'],
|
||||||
|
required = false,
|
||||||
|
hideInTable = false,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
dataIndex: dataIndex,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.Select.Merchants()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
90
src/components/SysSelects.tsx
Normal file
90
src/components/SysSelects.tsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { rulesHelper } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProColumns, ProFormColumnsType } from '@ant-design/pro-components';
|
||||||
|
|
||||||
|
type ReturnType = ProColumns<any, 'text'> & ProFormColumnsType<any, 'text'>;
|
||||||
|
type PropsType = { required?: boolean } & ReturnType;
|
||||||
|
|
||||||
|
export const SysSelects = {
|
||||||
|
Api(props?: PropsType): ReturnType {
|
||||||
|
const { required = false, ...rest } = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: '后端API',
|
||||||
|
dataIndex: 'backend_apis',
|
||||||
|
valueType: 'treeSelect',
|
||||||
|
hideInTable: true,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
showSearch: true,
|
||||||
|
allowClear: true,
|
||||||
|
treeDefaultExpandAll: true,
|
||||||
|
dropdownStyle: { maxHeight: 400, overflow: 'auto' },
|
||||||
|
multiple: true,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'value',
|
||||||
|
value: 'value',
|
||||||
|
children: 'children',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () =>
|
||||||
|
(await Apis.SysPermissions.SelectApi()).data?.children,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
SysPermissionsTree(props?: { guard_name: string } & PropsType): ReturnType {
|
||||||
|
const { guard_name = 'Admin', ...rest } = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: 'parent_id',
|
||||||
|
title: '上级菜单',
|
||||||
|
valueType: 'treeSelect',
|
||||||
|
request: async () => {
|
||||||
|
return Apis.SysPermissions.Tree({ guard_name: guard_name }).then(
|
||||||
|
(res) => res.data,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
fieldProps: {
|
||||||
|
allowClear: true,
|
||||||
|
autoClearSearchValue: true,
|
||||||
|
bordered: true,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
filterTreeNode: true,
|
||||||
|
showSearch: true,
|
||||||
|
treeNodeFilterProp: 'title',
|
||||||
|
treeDefaultExpandAll: true,
|
||||||
|
},
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
SysRoles(props?: PropsType): ReturnType {
|
||||||
|
const {
|
||||||
|
title = '角色',
|
||||||
|
key = 'roles_id',
|
||||||
|
required = false,
|
||||||
|
hideInTable = true,
|
||||||
|
...rest
|
||||||
|
} = props ?? {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: key,
|
||||||
|
valueType: 'select',
|
||||||
|
hideInTable: hideInTable,
|
||||||
|
formItemProps: { ...(required ? rulesHelper.number : {}) },
|
||||||
|
fieldProps: {
|
||||||
|
mode: 'multiple',
|
||||||
|
showSearch: false,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
request: async () => (await Apis.SysRoles.Select()).data,
|
||||||
|
...rest,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
360
src/gen/ApiTypes.d.ts
vendored
Normal file
360
src/gen/ApiTypes.d.ts
vendored
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
declare namespace ApiTypes {
|
||||||
|
namespace Admins {
|
||||||
|
type List = {
|
||||||
|
"username"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"username": string; // 用户名
|
||||||
|
"password": string; // 密码
|
||||||
|
"roles_id"?: string[]; // 角色
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"username": string; // 用户名/手机号
|
||||||
|
"password"?: string; // 密码,[hidden]
|
||||||
|
"roles_id"?: string[]; // 角色
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Agents {
|
||||||
|
type List = {
|
||||||
|
"name"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"name": string; // 简称
|
||||||
|
"full_name"?: string; // 全称
|
||||||
|
"address"?: string; // 地址
|
||||||
|
"contact"?: string; // 联系人
|
||||||
|
"phone"?: string; // 联系电话
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"name": string; // 简称
|
||||||
|
"full_name"?: string; // 全称
|
||||||
|
"address"?: string; // 地址
|
||||||
|
"contact"?: string; // 联系人
|
||||||
|
"phone"?: string; // 联系电话
|
||||||
|
};
|
||||||
|
type Show = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Auth {
|
||||||
|
type Login = {
|
||||||
|
"username": string; // 用户名
|
||||||
|
"password": string; // 密码
|
||||||
|
"captcha": string; // 验证码
|
||||||
|
"captcha_key": string; // 验证码key
|
||||||
|
};
|
||||||
|
type ChangePassword = {
|
||||||
|
"old_password": string; // 老密码
|
||||||
|
"new_password": string; // 新密码
|
||||||
|
"re_new_password": string; // 重复新密码
|
||||||
|
};
|
||||||
|
type PreUpload = {
|
||||||
|
"filename": string; // 文件名称
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Bosses {
|
||||||
|
type List = {
|
||||||
|
"name"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"name": string; // 简称
|
||||||
|
"full_name"?: string; // 全称
|
||||||
|
"address"?: string; // 地址
|
||||||
|
"contact"?: string; // 联系人
|
||||||
|
"phone"?: string; // 联系电话
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"name": string; // 简称
|
||||||
|
"full_name"?: string; // 全称
|
||||||
|
"address"?: string; // 地址
|
||||||
|
"contact"?: string; // 联系人
|
||||||
|
"phone"?: string; // 联系电话
|
||||||
|
};
|
||||||
|
type Show = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Factories {
|
||||||
|
type List = {
|
||||||
|
"name"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"name": string; // 厂家名称
|
||||||
|
"public_key": string; // 下游公钥
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"name": string; // 厂家名称
|
||||||
|
"public_key": string; // 下游公钥
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace LoanCompanies {
|
||||||
|
type List = {
|
||||||
|
"type"?: string; // 用户类型,[enum:LoanCompaniesTypeEnum]
|
||||||
|
"name"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"type"?: string; // 用户类型,[enum:LoanCompaniesTypeEnum]
|
||||||
|
"name": string; // 简称
|
||||||
|
"full_name"?: string; // 全称
|
||||||
|
"address"?: string; // 地址
|
||||||
|
"contact"?: string; // 联系人
|
||||||
|
"phone"?: string; // 联系电话
|
||||||
|
"up_merchant_no": string; // 上游商户号
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"type"?: string; // 用户类型,[enum:LoanCompaniesTypeEnum]
|
||||||
|
"name": string; // 简称
|
||||||
|
"full_name"?: string; // 全称
|
||||||
|
"address"?: string; // 地址
|
||||||
|
"contact"?: string; // 联系人
|
||||||
|
"phone"?: string; // 联系电话
|
||||||
|
"up_merchant_no": string; // 上游商户号
|
||||||
|
};
|
||||||
|
type Show = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace LoanDailyDetails {
|
||||||
|
type List = {
|
||||||
|
"merchants_id"?: number; // 商户ID
|
||||||
|
"date"?: Date; // 日期
|
||||||
|
"order_status"?: string; // 订单状态:LoansOrderStatusEnum
|
||||||
|
};
|
||||||
|
type Export = {
|
||||||
|
"merchants_id"?: number; // 商户ID
|
||||||
|
"date"?: Date; // 日期
|
||||||
|
"order_status"?: string; // 订单状态:LoansOrderStatusEnum
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Loans {
|
||||||
|
type List = {
|
||||||
|
"type"?: string; // 算法类型,[enum:LoansTypeEnum]
|
||||||
|
"name"?: string; // 显示名称
|
||||||
|
"order_status"?: string; // 订单状态,[enum:LoansOrderStatusEnum]
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"merchants_id": number; // 商户id,[ref:merchants]
|
||||||
|
"loan_companies_id": number; // 资金方id,[ref:loan_companies]
|
||||||
|
"name": string; // 显示名称
|
||||||
|
"type"?: string; // 算法类型,[enum:LoansTypeEnum]
|
||||||
|
"loan_days"?: number; // 贷款天数
|
||||||
|
"started_at": Date; // 开始时间
|
||||||
|
"total_due_principal": number; // 总应还-本金
|
||||||
|
"total_due_interest"?: number; // 总应还-利息
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Markets {
|
||||||
|
type List = {
|
||||||
|
"name"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"name": string; // 市场名称
|
||||||
|
"market_no": string; // 市场编号
|
||||||
|
"public_key": string; // 上游公钥
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"name": string; // 市场名称
|
||||||
|
"market_no": string; // 市场编号
|
||||||
|
"public_key": string; // 上游公钥
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace MerchantCounters {
|
||||||
|
type List = {
|
||||||
|
"merchants_id"?: number; // 商户id,[ref:merchants]
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"merchants_id": number; // 商户id,[ref:merchants]
|
||||||
|
"markets_id": number; // 上游市场id,[ref:markets]
|
||||||
|
"name": string; // 名称
|
||||||
|
"up_merchant_no": string; // 上游商家编号
|
||||||
|
"commissions": string[]; // 分账配置
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"name": string; // 名称
|
||||||
|
"up_merchant_no": string; // 上游商家编号
|
||||||
|
"commissions": string[]; // 分账配置
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Merchants {
|
||||||
|
type List = {
|
||||||
|
"agents_id"?: number; // 代理id,[ref:agents]
|
||||||
|
"bosses_id"?: number; // 老板id,[ref:bosses]
|
||||||
|
"factories_id"?: number; // 厂家id,[ref:factories]
|
||||||
|
"platforms_id"?: number; // 平台id,[ref:platforms]
|
||||||
|
"name"?: string; // 商户简称
|
||||||
|
"full_name"?: string; // 商户全称呼
|
||||||
|
"plat_merchant_no"?: string; // 平台商户号
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"agents_id": number; // 代理id,[ref:agents]
|
||||||
|
"bosses_id": number; // 老板id,[ref:bosses]
|
||||||
|
"factories_id": number; // 厂家id,[ref:factories]
|
||||||
|
"platforms_id": number; // 平台id,[ref:platforms]
|
||||||
|
"name": string; // 商户简称
|
||||||
|
"full_name": string; // 商户全称呼
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"agents_id": number; // 代理id,[ref:agents]
|
||||||
|
"bosses_id": number; // 老板id,[ref:bosses]
|
||||||
|
"factories_id": number; // 厂家id,[ref:factories]
|
||||||
|
"platforms_id": number; // 平台id,[ref:platforms]
|
||||||
|
"name": string; // 商户简称
|
||||||
|
"full_name": string; // 商户全称呼
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace OrgUsers {
|
||||||
|
type List = {
|
||||||
|
"type"?: string; // 机构类型,[enum:OrgUsersTypeEnum]
|
||||||
|
"org_name"?: string; // 机构名称
|
||||||
|
"org_id"?: number; // 机构id
|
||||||
|
"username"?: string; // 用户名
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"type": string; // 用户类型,[enum:OrgUsersTypeEnum]
|
||||||
|
"org_name": string; // 机构名称
|
||||||
|
"username": string; // 用户名
|
||||||
|
"password": string; // 密码,[hidden]
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"password": string; // 密码,[hidden]
|
||||||
|
};
|
||||||
|
type Show = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace PayOrders {
|
||||||
|
type List = {
|
||||||
|
"merchant_name"?: string; // 模糊搜索:商户简称
|
||||||
|
"type"?: string; // 交易类型,[enum:PayOrdersTypeEnum]
|
||||||
|
"order_status"?: string; // 订单状态,[enum:PayOrderStatusEnum]
|
||||||
|
"day_date"?: Date; // 日期
|
||||||
|
"down_order_no"?: string; // 下游订单号
|
||||||
|
"up_order_no"?: string; // 上游订单号
|
||||||
|
"up_tx_no"?: string; // 上游交易流水号
|
||||||
|
"amount_order"?: string; // 金额
|
||||||
|
"up_order_at_range"?: string[]; // 上游订单时间范围
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Platforms {
|
||||||
|
type List = {
|
||||||
|
"name"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"name": string; // 平台名称
|
||||||
|
"private_key": string; // 平台私钥
|
||||||
|
"public_key": string; // 平台公钥
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // id
|
||||||
|
"name": string; // 平台名称
|
||||||
|
"private_key": string; // 平台私钥
|
||||||
|
"public_key": string; // 平台公钥
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace Select {
|
||||||
|
}
|
||||||
|
namespace SysPermissions {
|
||||||
|
type List = {
|
||||||
|
"parent_id"?: number; // 上级ID
|
||||||
|
"guard_name": string; //
|
||||||
|
};
|
||||||
|
type Tree = {
|
||||||
|
"parent_id"?: number; // 上级ID
|
||||||
|
"guard_name": string; //
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"name": string; //
|
||||||
|
"key"?: string; //
|
||||||
|
"guard_name": string; //
|
||||||
|
"icon"?: string; // 图标
|
||||||
|
"type": string; // 类型:SysPermissionsTypeEnum
|
||||||
|
"backend_apis"?: string[]; // 后台api
|
||||||
|
"path"?: string; // 路由
|
||||||
|
"parent_id"?: number; //
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // ID
|
||||||
|
"name": string; //
|
||||||
|
"key"?: string; //
|
||||||
|
"guard_name": string; //
|
||||||
|
"icon"?: string; // 图标
|
||||||
|
"type": string; // 类型:SysPermissionsTypeEnum
|
||||||
|
"backend_apis"?: string[]; // 后台api
|
||||||
|
"path"?: string; // 路由
|
||||||
|
"parent_id"?: number; //
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // ID
|
||||||
|
};
|
||||||
|
type Move = {
|
||||||
|
"id": number; // ID
|
||||||
|
"type": string; // 类型:up 升级,down 降级
|
||||||
|
};
|
||||||
|
}
|
||||||
|
namespace SysRoles {
|
||||||
|
type List = {
|
||||||
|
"name"?: string; // 模糊搜索:名称
|
||||||
|
};
|
||||||
|
type Store = {
|
||||||
|
"name": string; // 名称
|
||||||
|
"color"?: string; // 颜色
|
||||||
|
};
|
||||||
|
type Update = {
|
||||||
|
"id": number; // ID
|
||||||
|
"name": string; // 名称
|
||||||
|
"color"?: string; // 颜色
|
||||||
|
};
|
||||||
|
type Delete = {
|
||||||
|
"id": number; // ID
|
||||||
|
};
|
||||||
|
type GetPermissions = {
|
||||||
|
"id": number; // ID
|
||||||
|
};
|
||||||
|
type SetPermissions = {
|
||||||
|
"id": number; // ID
|
||||||
|
"permissions_ids": string[]; // 权限ID
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
270
src/gen/Apis.ts
Normal file
270
src/gen/Apis.ts
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
import { MyResponseType } from '@/common';
|
||||||
|
import { request } from '@umijs/max';
|
||||||
|
|
||||||
|
export const Apis = {
|
||||||
|
Admins: {
|
||||||
|
List(data?: ApiTypes.Admins.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/admins/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Admins.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/admins/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.Admins.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/admins/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Admins.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/admins/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Agents: {
|
||||||
|
List(data?: ApiTypes.Agents.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/agents/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Agents.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/agents/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.Agents.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/agents/update', { data });
|
||||||
|
},
|
||||||
|
Show(data: ApiTypes.Agents.Show): Promise<MyResponseType> {
|
||||||
|
return request('admin/agents/show', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Agents.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/agents/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Auth: {
|
||||||
|
Captcha(): Promise<MyResponseType> {
|
||||||
|
return request('admin/auth/captcha', {});
|
||||||
|
},
|
||||||
|
Login(data: ApiTypes.Auth.Login): Promise<MyResponseType> {
|
||||||
|
return request('admin/auth/login', { data });
|
||||||
|
},
|
||||||
|
Logout(): Promise<MyResponseType> {
|
||||||
|
return request('admin/auth/logout', {});
|
||||||
|
},
|
||||||
|
Me(): Promise<MyResponseType> {
|
||||||
|
return request('admin/auth/me', {});
|
||||||
|
},
|
||||||
|
ChangePassword(data: ApiTypes.Auth.ChangePassword): Promise<MyResponseType> {
|
||||||
|
return request('admin/auth/change_password', { data });
|
||||||
|
},
|
||||||
|
PreUpload(data: ApiTypes.Auth.PreUpload): Promise<MyResponseType> {
|
||||||
|
return request('admin/auth/pre_upload', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bosses: {
|
||||||
|
List(data?: ApiTypes.Bosses.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/bosses/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Bosses.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/bosses/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.Bosses.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/bosses/update', { data });
|
||||||
|
},
|
||||||
|
Show(data: ApiTypes.Bosses.Show): Promise<MyResponseType> {
|
||||||
|
return request('admin/bosses/show', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Bosses.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/bosses/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Factories: {
|
||||||
|
List(data?: ApiTypes.Factories.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/factories/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Factories.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/factories/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.Factories.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/factories/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Factories.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/factories/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LoanCompanies: {
|
||||||
|
List(data?: ApiTypes.LoanCompanies.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/loan_companies/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.LoanCompanies.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/loan_companies/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.LoanCompanies.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/loan_companies/update', { data });
|
||||||
|
},
|
||||||
|
Show(data: ApiTypes.LoanCompanies.Show): Promise<MyResponseType> {
|
||||||
|
return request('admin/loan_companies/show', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.LoanCompanies.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/loan_companies/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LoanDailyDetails: {
|
||||||
|
List(data?: ApiTypes.LoanDailyDetails.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/loan_daily_details/list', { data });
|
||||||
|
},
|
||||||
|
Export(data?: ApiTypes.LoanDailyDetails.Export): Promise<MyResponseType> {
|
||||||
|
return request('admin/loan_daily_details/export', { responseType: 'blob',data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Loans: {
|
||||||
|
List(data?: ApiTypes.Loans.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/loans/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Loans.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/loans/store', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Loans.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/loans/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Markets: {
|
||||||
|
List(data?: ApiTypes.Markets.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/markets/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Markets.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/markets/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.Markets.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/markets/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Markets.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/markets/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MerchantCounters: {
|
||||||
|
List(data?: ApiTypes.MerchantCounters.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchant_counters/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.MerchantCounters.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchant_counters/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.MerchantCounters.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchant_counters/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.MerchantCounters.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchant_counters/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Merchants: {
|
||||||
|
List(data?: ApiTypes.Merchants.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchants/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Merchants.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchants/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.Merchants.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchants/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Merchants.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/merchants/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OrgUsers: {
|
||||||
|
List(data?: ApiTypes.OrgUsers.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/org_users/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.OrgUsers.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/org_users/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.OrgUsers.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/org_users/update', { data });
|
||||||
|
},
|
||||||
|
Show(data: ApiTypes.OrgUsers.Show): Promise<MyResponseType> {
|
||||||
|
return request('admin/org_users/show', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.OrgUsers.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/org_users/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PayOrders: {
|
||||||
|
List(data?: ApiTypes.PayOrders.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/pay_orders/list', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Platforms: {
|
||||||
|
List(data?: ApiTypes.Platforms.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/platforms/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.Platforms.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/platforms/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.Platforms.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/platforms/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.Platforms.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/platforms/delete', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Select: {
|
||||||
|
Agents(): Promise<MyResponseType> {
|
||||||
|
return request('admin/select/agents', {});
|
||||||
|
},
|
||||||
|
LoanCompanies(): Promise<MyResponseType> {
|
||||||
|
return request('admin/select/loan_companies', {});
|
||||||
|
},
|
||||||
|
Factories(): Promise<MyResponseType> {
|
||||||
|
return request('admin/select/factories', {});
|
||||||
|
},
|
||||||
|
Platforms(): Promise<MyResponseType> {
|
||||||
|
return request('admin/select/platforms', {});
|
||||||
|
},
|
||||||
|
Bosses(): Promise<MyResponseType> {
|
||||||
|
return request('admin/select/bosses', {});
|
||||||
|
},
|
||||||
|
Markets(): Promise<MyResponseType> {
|
||||||
|
return request('admin/select/markets', {});
|
||||||
|
},
|
||||||
|
Merchants(): Promise<MyResponseType> {
|
||||||
|
return request('admin/select/merchants', {});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SysPermissions: {
|
||||||
|
List(data: ApiTypes.SysPermissions.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_permissions/list', { data });
|
||||||
|
},
|
||||||
|
Tree(data: ApiTypes.SysPermissions.Tree): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_permissions/tree', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.SysPermissions.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_permissions/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.SysPermissions.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_permissions/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.SysPermissions.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_permissions/delete', { data });
|
||||||
|
},
|
||||||
|
Move(data: ApiTypes.SysPermissions.Move): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_permissions/move', { data });
|
||||||
|
},
|
||||||
|
SelectApi(): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_permissions/select_api', {});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SysRoles: {
|
||||||
|
List(data?: ApiTypes.SysRoles.List): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_roles/list', { data });
|
||||||
|
},
|
||||||
|
Store(data: ApiTypes.SysRoles.Store): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_roles/store', { data });
|
||||||
|
},
|
||||||
|
Update(data: ApiTypes.SysRoles.Update): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_roles/update', { data });
|
||||||
|
},
|
||||||
|
Delete(data: ApiTypes.SysRoles.Delete): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_roles/delete', { data });
|
||||||
|
},
|
||||||
|
Select(): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_roles/select', {});
|
||||||
|
},
|
||||||
|
GetPermissions(data: ApiTypes.SysRoles.GetPermissions): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_roles/get_permissions', { data });
|
||||||
|
},
|
||||||
|
SetPermissions(data: ApiTypes.SysRoles.SetPermissions): Promise<MyResponseType> {
|
||||||
|
return request('admin/sys_roles/set_permissions', { data });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
72
src/gen/Enums.ts
Normal file
72
src/gen/Enums.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// CommissionTypeEnum
|
||||||
|
export const CommissionTypeEnum= {
|
||||||
|
'Platform': {"text":"平台","color":"#1890ff","value":"Platform"},
|
||||||
|
'Agent': {"text":"代理","color":"#722ed1","value":"Agent"},
|
||||||
|
'Repayment': {"text":"还款","color":"#f5222d","value":"Repayment"},
|
||||||
|
'Merchant': {"text":"商家","color":"#52c41a","value":"Merchant"},
|
||||||
|
'Other': {"text":"其他","color":"#bfbfbf","value":"Other"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// LoanCompaniesTypeEnum
|
||||||
|
export const LoanCompaniesTypeEnum= {
|
||||||
|
'DeviceManufacturer': {"text":"设备商","color":"#459423","value":"DeviceManufacturer"},
|
||||||
|
'CapitalProvider': {"text":"资金方","color":"#13952d","value":"CapitalProvider"},
|
||||||
|
'SupplyChain': {"text":"供应链","color":"#033fcc","value":"SupplyChain"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// LoansOrderStatusEnum
|
||||||
|
export const LoansOrderStatusEnum= {
|
||||||
|
'NotStart': {"text":"未开始","color":"#983054","value":"NotStart"},
|
||||||
|
'OnGoing': {"text":"进行中","color":"#a36451","value":"OnGoing"},
|
||||||
|
'Finished': {"text":"已完成","color":"#0ce4b6","value":"Finished"},
|
||||||
|
'Overdue': {"text":"逾期","color":"#7723f8","value":"Overdue"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// LoansTypeEnum
|
||||||
|
export const LoansTypeEnum= {
|
||||||
|
'Daily': {"text":"每日还款(等本等息)","color":"#e847d5","value":"Daily"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// OrgUserTypeEnum
|
||||||
|
export const OrgUsersTypeEnum= {
|
||||||
|
'Agent': {"text":"代理","color":"#bd1087","value":"Agent"},
|
||||||
|
'Bosses': {"text":"老板","color":"#5892ea","value":"Bosses"},
|
||||||
|
'LoanCompanies': {"text":"资金方","color":"#7e2070","value":"LoanCompanies"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// PayOrderStatusEnum
|
||||||
|
export const PayOrderStatusEnum= {
|
||||||
|
'1': {"text":"待支付","color":"#faad14","value":"1"},
|
||||||
|
'2': {"text":"支付成功","color":"#52c41a","value":"2"},
|
||||||
|
'3': {"text":"支付失败","color":"#f5222d","value":"3"},
|
||||||
|
'9': {"text":"待轮询","color":"#1890ff","value":"9"},
|
||||||
|
'0': {"text":"其他","color":"#bfbfbf","value":"0"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// PayOrdersTypeEnum
|
||||||
|
export const PayOrdersTypeEnum= {
|
||||||
|
'1': {"text":"支付","color":"#52c41a","value":"1"},
|
||||||
|
'2': {"text":"退款","color":"#faad14","value":"2"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// SysModuleEnum
|
||||||
|
export const SysModuleEnum= {
|
||||||
|
'Admin': {"text":"管理员","color":"#cf1322","value":"Admin"},
|
||||||
|
'Customer': {"text":"客户","color":"#d4b106","value":"Customer"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// SysPermissionsTypeEnum
|
||||||
|
export const SysPermissionsTypeEnum= {
|
||||||
|
'Directory': {"text":"目录","color":"#6d7e14","value":"Directory"},
|
||||||
|
'Page': {"text":"页面","color":"#4d9a13","value":"Page"},
|
||||||
|
'Button': {"text":"按钮","color":"#97224f","value":"Button"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// SysTasksStatusEnum
|
||||||
|
export const SysTasksStatusEnum= {
|
||||||
|
'1': {"text":"未开始","color":"#bfbfbf","value":"1"},
|
||||||
|
'2': {"text":"未开始","color":"#1890ff","value":"2"},
|
||||||
|
'3': {"text":"已完成","color":"#a0d911","value":"3"},
|
||||||
|
'4': {"text":"错误","color":"#f5222d","value":"4"},
|
||||||
|
};
|
||||||
|
|
||||||
11
src/global.scss
Normal file
11
src/global.scss
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.ant-pro-page-container {
|
||||||
|
.ant-page-header-heading-title {
|
||||||
|
line-height: 51px !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
font-weight: 700;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.ant-pro-grid-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/pages/agents/index.tsx
Normal file
65
src/pages/agents/index.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
|
||||||
|
export default function Index({ title = '代理商' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Agents.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '简称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '全称',
|
||||||
|
dataIndex: 'full_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Agents.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
54
src/pages/agents/modals/Create.tsx
Normal file
54
src/pages/agents/modals/Create.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Agents.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Agents.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
src/pages/agents/modals/Update.tsx
Normal file
55
src/pages/agents/modals/Update.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Agents.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Agents.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
65
src/pages/bosses/index.tsx
Normal file
65
src/pages/bosses/index.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
|
||||||
|
export default function Index({ title = '超市老板' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Bosses.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '简称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '全称',
|
||||||
|
dataIndex: 'full_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Bosses.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
54
src/pages/bosses/modals/Create.tsx
Normal file
54
src/pages/bosses/modals/Create.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Bosses.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Bosses.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
src/pages/bosses/modals/Update.tsx
Normal file
55
src/pages/bosses/modals/Update.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Bosses.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Bosses.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
src/pages/factories/index.tsx
Normal file
55
src/pages/factories/index.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
|
||||||
|
export default function Index({ title = '下游厂家' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
search={false}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Factories.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '厂家名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '下游公钥',
|
||||||
|
dataIndex: 'public_key',
|
||||||
|
},
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.UpdatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Factories.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
43
src/pages/factories/modals/Create.tsx
Normal file
43
src/pages/factories/modals/Create.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Factories.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Factories.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '厂家名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'public_key',
|
||||||
|
title: '下游公钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
44
src/pages/factories/modals/Update.tsx
Normal file
44
src/pages/factories/modals/Update.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Factories.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Factories.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '厂家名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'public_key',
|
||||||
|
title: '下游公钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
src/pages/index.tsx
Normal file
3
src/pages/index.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function index() {
|
||||||
|
return <div>index</div>;
|
||||||
|
}
|
||||||
75
src/pages/loan_companies/index.tsx
Normal file
75
src/pages/loan_companies/index.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { LoanCompaniesTypeEnum } from '@/gen/Enums';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
|
||||||
|
export default function Index({ title = '资金方' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.LoanCompanies.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '类型',
|
||||||
|
dataIndex: 'type',
|
||||||
|
valueEnum: LoanCompaniesTypeEnum,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '简称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '全称',
|
||||||
|
dataIndex: 'full_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '上游商户号',
|
||||||
|
dataIndex: 'up_merchant_no',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.LoanCompanies.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
66
src/pages/loan_companies/modals/Create.tsx
Normal file
66
src/pages/loan_companies/modals/Create.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { LoanCompaniesTypeEnum } from '@/gen/Enums';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.LoanCompanies.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.LoanCompanies.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
key: 'type',
|
||||||
|
title: '类型',
|
||||||
|
valueEnum: LoanCompaniesTypeEnum,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'up_merchant_no',
|
||||||
|
title: '上游商户号',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
67
src/pages/loan_companies/modals/Update.tsx
Normal file
67
src/pages/loan_companies/modals/Update.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { LoanCompaniesTypeEnum } from '@/gen/Enums';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.LoanCompanies.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.LoanCompanies.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
key: 'type',
|
||||||
|
title: '类型',
|
||||||
|
valueEnum: LoanCompaniesTypeEnum,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'up_merchant_no',
|
||||||
|
title: '上游商户号',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'address',
|
||||||
|
title: '地址',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contact',
|
||||||
|
title: '联系人',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone',
|
||||||
|
title: '联系电话',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
104
src/pages/loan_daily_details/index.tsx
Normal file
104
src/pages/loan_daily_details/index.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { LoansOrderStatusEnum } from '@/gen/Enums';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
export default function Index({ title = '还款记录' }) {
|
||||||
|
const [query, setQuery] = useState();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={`${title}管理`}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(
|
||||||
|
params,
|
||||||
|
sort,
|
||||||
|
Apis.LoanDailyDetails.List,
|
||||||
|
setQuery,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
toolBarRender={() => [
|
||||||
|
<MyButtons.Export
|
||||||
|
title="还款计划导出"
|
||||||
|
key="Export"
|
||||||
|
api={Apis.LoanDailyDetails.Export}
|
||||||
|
params={query}
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '所属商户',
|
||||||
|
dataIndex: 'merchants_name',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
Selects.Merchants({
|
||||||
|
hideInTable: true,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '所属资金方',
|
||||||
|
dataIndex: 'loan_companies_name',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
Selects.LoanCompany({
|
||||||
|
hideInTable: true,
|
||||||
|
}),
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
title: '订单状态',
|
||||||
|
dataIndex: 'order_status',
|
||||||
|
valueEnum: LoansOrderStatusEnum,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
dataIndex: 'date',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '应还-本金',
|
||||||
|
dataIndex: 'due_principal',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '应还-利息',
|
||||||
|
dataIndex: 'due_interest',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '应还-递延本金',
|
||||||
|
dataIndex: 'due_deferred_principal',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '应还-总金额',
|
||||||
|
dataIndex: 'due_total_amount',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '已还-总金额',
|
||||||
|
dataIndex: 'paid_total_amount',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '未还-总金额',
|
||||||
|
dataIndex: 'remaining_total_amount',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
// MyColumns.CreatedAt(),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
193
src/pages/loans/index.tsx
Normal file
193
src/pages/loans/index.tsx
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { LoansOrderStatusEnum, LoansTypeEnum } from '@/gen/Enums';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
|
||||||
|
export default function Index({ title = '贷款订单' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={`${title}管理`}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Loans.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '所属商户',
|
||||||
|
dataIndex: ['merchant', 'name'],
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '所属资金方',
|
||||||
|
dataIndex: ['loan_company', 'name'],
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
title: '类型',
|
||||||
|
dataIndex: 'type',
|
||||||
|
valueEnum: LoansTypeEnum,
|
||||||
|
}),
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
title: '订单状态',
|
||||||
|
dataIndex: 'order_status',
|
||||||
|
valueEnum: LoansOrderStatusEnum,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '贷款天数',
|
||||||
|
dataIndex: 'loan_days',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '开始时间',
|
||||||
|
dataIndex: 'started_at',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '结束时间',
|
||||||
|
dataIndex: 'ended_at',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '总应还',
|
||||||
|
search: false,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: '本金',
|
||||||
|
dataIndex: 'total_due_principal',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '利息',
|
||||||
|
dataIndex: 'total_due_interest',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '总金额',
|
||||||
|
dataIndex: 'total_due_amount',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '每日应还',
|
||||||
|
search: false,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: '本金',
|
||||||
|
dataIndex: 'daily_due_principal',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '利息',
|
||||||
|
dataIndex: 'daily_due_interest',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '总金额',
|
||||||
|
dataIndex: 'daily_due_amount',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '已还',
|
||||||
|
search: false,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: '天数',
|
||||||
|
dataIndex: 'repaid_days',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '本金',
|
||||||
|
dataIndex: 'repaid_total_principal',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '利息',
|
||||||
|
dataIndex: 'repaid_total_interest',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '总金额',
|
||||||
|
dataIndex: 'repaid_total_amount',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '剩余应还',
|
||||||
|
search: false,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: '天数',
|
||||||
|
dataIndex: 'remaining_due_days',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '本金',
|
||||||
|
dataIndex: 'remaining_due_principal',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '利息',
|
||||||
|
dataIndex: 'remaining_due_interest',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '总金额',
|
||||||
|
dataIndex: 'remaining_due_amount',
|
||||||
|
search: false,
|
||||||
|
valueType: 'money',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Loans.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
90
src/pages/loans/modals/Create.tsx
Normal file
90
src/pages/loans/modals/Create.tsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyFormItems,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { LoansTypeEnum } from '@/gen/Enums';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { Form, message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Loans.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
width="600px"
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Loans.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
form={form}
|
||||||
|
onOpenChange={(open: boolean) => {
|
||||||
|
if (open) {
|
||||||
|
form.setFieldsValue({ repayment_date: 21, loan_terms: 3 });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
columns={[
|
||||||
|
Selects.Merchants({
|
||||||
|
colProps: { span: 24 },
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
Selects.LoanCompany({
|
||||||
|
colProps: { span: 24 },
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
key: 'name',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
MyFormItems.EnumRadio({
|
||||||
|
title: '算法类型',
|
||||||
|
key: 'type',
|
||||||
|
valueEnum: LoansTypeEnum,
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '贷款天数',
|
||||||
|
key: 'loan_days',
|
||||||
|
colProps: { span: 12 },
|
||||||
|
formItemProps: { ...rulesHelper.number },
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '还款起始日',
|
||||||
|
key: 'started_at',
|
||||||
|
valueType: 'date',
|
||||||
|
colProps: { span: 12 },
|
||||||
|
formItemProps: { ...rulesHelper.number },
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
MyFormItems.Money({
|
||||||
|
title: '总应还-本金',
|
||||||
|
key: 'total_due_principal',
|
||||||
|
colProps: { span: 12 },
|
||||||
|
formItemProps: { ...rulesHelper.number },
|
||||||
|
width: '100%',
|
||||||
|
}),
|
||||||
|
MyFormItems.Money({
|
||||||
|
title: '总应还-利息',
|
||||||
|
key: 'total_due_interest',
|
||||||
|
colProps: { span: 12 },
|
||||||
|
formItemProps: { ...rulesHelper.number },
|
||||||
|
width: '100%',
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
src/pages/login.tsx
Normal file
5
src/pages/login.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { MyLoginPage1 } from '@/common';
|
||||||
|
|
||||||
|
export default function Login() {
|
||||||
|
return <MyLoginPage1 />;
|
||||||
|
}
|
||||||
60
src/pages/markets/index.tsx
Normal file
60
src/pages/markets/index.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
|
||||||
|
export default function Index({ title = '上游市场' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
search={false}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Markets.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '市场名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '市场编号',
|
||||||
|
dataIndex: 'market_no',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '上游公钥',
|
||||||
|
dataIndex: 'public_key',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
MyColumns.UpdatedAt(),
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Markets.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
48
src/pages/markets/modals/Create.tsx
Normal file
48
src/pages/markets/modals/Create.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Markets.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Markets.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '市场名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'market_no',
|
||||||
|
title: '市场编号',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'public_key',
|
||||||
|
title: '上游公钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
49
src/pages/markets/modals/Update.tsx
Normal file
49
src/pages/markets/modals/Update.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Markets.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Markets.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '市场名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'market_no',
|
||||||
|
title: '市场编号',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'public_key',
|
||||||
|
title: '上游公钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
136
src/pages/merchants/index.tsx
Normal file
136
src/pages/merchants/index.tsx
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import CreateCounters from './modals/CreateCounters';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
import UpdateCounters from './modals/UpdateCounters';
|
||||||
|
|
||||||
|
export default function Index({ title = '商户' }) {
|
||||||
|
const ExpandedRowRender = (e: any) => {
|
||||||
|
const columns = [
|
||||||
|
{ title: 'id', dataIndex: 'id' },
|
||||||
|
{ title: '上游', dataIndex: ['market', 'name'] },
|
||||||
|
{ title: '名称', dataIndex: 'name' },
|
||||||
|
{ title: '上游商家编号', dataIndex: 'up_merchant_no' },
|
||||||
|
{ title: '平台商户号', dataIndex: 'plat_merchant_no' },
|
||||||
|
{ title: '平台柜台号', dataIndex: 'plat_counter_no' },
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<UpdateCounters item={item} reload={action?.reload} title="柜台" />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.MerchantCounters.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
pagination={false}
|
||||||
|
columns={columns}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(
|
||||||
|
{ ...params, merchants_id: e?.id },
|
||||||
|
sort,
|
||||||
|
Apis.MerchantCounters.List,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<CreateCounters
|
||||||
|
key="Create"
|
||||||
|
reload={action?.reload}
|
||||||
|
title="添加柜台"
|
||||||
|
item={{ merchants_id: e?.id }}
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
headerTitle="柜台信息"
|
||||||
|
search={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Merchants.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
expandable={{
|
||||||
|
expandedRowRender: ExpandedRowRender,
|
||||||
|
}}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
Selects.Agents({ dataIndex: 'agents_name' }),
|
||||||
|
Selects.Bosses({ dataIndex: 'bosses_name' }),
|
||||||
|
Selects.Factories({ dataIndex: 'factories_name' }),
|
||||||
|
Selects.Platforms({ dataIndex: 'platforms_name' }),
|
||||||
|
// {
|
||||||
|
// title: '代理',
|
||||||
|
// dataIndex: 'agents_name',
|
||||||
|
// search: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: '厂家',
|
||||||
|
// dataIndex: 'factories_name',
|
||||||
|
// search: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: '平台',
|
||||||
|
// dataIndex: 'platforms_name',
|
||||||
|
// search: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: '老板',
|
||||||
|
// dataIndex: 'bosses_name',
|
||||||
|
// search: false,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
title: '简称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '全称',
|
||||||
|
dataIndex: 'full_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '平台商户号',
|
||||||
|
dataIndex: 'plat_merchant_no',
|
||||||
|
},
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Merchants.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
47
src/pages/merchants/modals/Create.tsx
Normal file
47
src/pages/merchants/modals/Create.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Merchants.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Merchants.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
Selects.Agents({ required: true }),
|
||||||
|
Selects.Bosses({ required: true }),
|
||||||
|
Selects.Factories({ required: true }),
|
||||||
|
Selects.Platforms({ required: true }),
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
88
src/pages/merchants/modals/CreateCounters.tsx
Normal file
88
src/pages/merchants/modals/CreateCounters.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyFormItems,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { CommissionTypeEnum } from '@/gen/Enums';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function CreateCounters(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.MerchantCounters.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="800px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.MerchantCounters.Store({ ...props?.item, ...values })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
Selects.Markets({ required: true }),
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'up_merchant_no',
|
||||||
|
title: '上游商家编号',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
valueType: 'formList',
|
||||||
|
dataIndex: 'commissions',
|
||||||
|
title: '分佣配置',
|
||||||
|
formItemProps: { ...rulesHelper.array },
|
||||||
|
fieldProps: {
|
||||||
|
copyIconProps: false,
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
valueType: 'group',
|
||||||
|
colProps: { span: 24 },
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
key: 'seq',
|
||||||
|
colProps: { span: 3 },
|
||||||
|
title: '序号',
|
||||||
|
width: '100%',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
MyFormItems.EnumSelect({
|
||||||
|
key: 'type',
|
||||||
|
title: '类型',
|
||||||
|
colProps: { span: 4 },
|
||||||
|
valueEnum: CommissionTypeEnum,
|
||||||
|
required: true,
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
key: 'merchant_no',
|
||||||
|
colProps: { span: 9 },
|
||||||
|
title: '商户编号',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'percent',
|
||||||
|
colProps: { span: 8 },
|
||||||
|
title: '分佣比例%(0为自动计算)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
48
src/pages/merchants/modals/Update.tsx
Normal file
48
src/pages/merchants/modals/Update.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Merchants.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Merchants.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
Selects.Agents({ required: true }),
|
||||||
|
Selects.Bosses({ required: true }),
|
||||||
|
Selects.Factories({ required: true }),
|
||||||
|
Selects.Platforms({ required: true }),
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '简称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'full_name',
|
||||||
|
title: '全称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
89
src/pages/merchants/modals/UpdateCounters.tsx
Normal file
89
src/pages/merchants/modals/UpdateCounters.tsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyFormItems,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { CommissionTypeEnum } from '@/gen/Enums';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function UpdateCounters(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.MerchantCounters.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="800px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.MerchantCounters.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
Selects.Markets({ required: true }),
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'up_merchant_no',
|
||||||
|
title: '上游商家编号',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
valueType: 'formList',
|
||||||
|
dataIndex: 'commissions',
|
||||||
|
title: '分佣配置',
|
||||||
|
formItemProps: { ...rulesHelper.array },
|
||||||
|
fieldProps: {
|
||||||
|
copyIconProps: false,
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
valueType: 'group',
|
||||||
|
colProps: { span: 24 },
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
key: 'seq',
|
||||||
|
colProps: { span: 3 },
|
||||||
|
title: '序号',
|
||||||
|
width: '100%',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
MyFormItems.EnumSelect({
|
||||||
|
key: 'type',
|
||||||
|
title: '类型',
|
||||||
|
colProps: { span: 4 },
|
||||||
|
valueEnum: CommissionTypeEnum,
|
||||||
|
required: true,
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
key: 'merchant_no',
|
||||||
|
colProps: { span: 9 },
|
||||||
|
title: '商户编号',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'percent',
|
||||||
|
colProps: { span: 8 },
|
||||||
|
title: '分佣比例%(0为自动计算)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
71
src/pages/org_users/index.tsx
Normal file
71
src/pages/org_users/index.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
import { OrgUsersTypeEnum } from '@/gen/Enums';
|
||||||
|
|
||||||
|
export default function Index({ title = '账号管理' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.OrgUsers.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
title: '类型',
|
||||||
|
dataIndex: 'type',
|
||||||
|
valueEnum: OrgUsersTypeEnum,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '机构名称',
|
||||||
|
dataIndex: ['org', 'name'],
|
||||||
|
key: 'org_name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '账号',
|
||||||
|
dataIndex: 'username',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'last_login_ip',
|
||||||
|
dataIndex: 'last_login_ip',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'last_login_at',
|
||||||
|
dataIndex: 'last_login_at',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
MyColumns.UpdatedAt(),
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.OrgUsers.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
57
src/pages/org_users/modals/Create.tsx
Normal file
57
src/pages/org_users/modals/Create.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyFormItems,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { OrgUsersTypeEnum } from '@/gen/Enums';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.OrgUsers.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.OrgUsers.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
MyFormItems.EnumRadio({
|
||||||
|
key: 'type',
|
||||||
|
title: '类型',
|
||||||
|
valueEnum: OrgUsersTypeEnum
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
key: 'org_name',
|
||||||
|
title: '主体名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'username',
|
||||||
|
title: '用户名',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'password',
|
||||||
|
title: '密码',
|
||||||
|
valueType: 'password',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
55
src/pages/org_users/modals/Update.tsx
Normal file
55
src/pages/org_users/modals/Update.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Selects } from '@/components/Selects';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.OrgUsers.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.OrgUsers.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'type',
|
||||||
|
title: '类型',
|
||||||
|
readonly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: ['org','name'],
|
||||||
|
title: '机构名称',
|
||||||
|
readonly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'username',
|
||||||
|
title: '用户名',
|
||||||
|
readonly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'password',
|
||||||
|
title: '密码',
|
||||||
|
valueType: 'password',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
75
src/pages/pay_orders/index.tsx
Normal file
75
src/pages/pay_orders/index.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { MyColumns, MyPageContainer, MyProTableProps } from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { PayOrderStatusEnum, PayOrdersTypeEnum } from '@/gen/Enums';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
|
||||||
|
export default function Index({ title = '支付明细' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.PayOrders.List)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: '交易时间',
|
||||||
|
search: false,
|
||||||
|
dataIndex: 'up_order_at',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '交易时间范围',
|
||||||
|
key: 'up_order_at_range',
|
||||||
|
valueType: 'dateRange',
|
||||||
|
hideInTable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '商户',
|
||||||
|
dataIndex: 'merchant_name',
|
||||||
|
},
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
title: '交易类型',
|
||||||
|
dataIndex: 'type',
|
||||||
|
valueEnum: PayOrdersTypeEnum,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '下单金额',
|
||||||
|
dataIndex: 'amount_order',
|
||||||
|
},
|
||||||
|
MyColumns.EnumTag({
|
||||||
|
title: '订单状态',
|
||||||
|
dataIndex: 'order_status',
|
||||||
|
valueEnum: PayOrderStatusEnum,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
title: '平台商户号',
|
||||||
|
dataIndex: 'plat_merchant_no',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '平台柜台号',
|
||||||
|
dataIndex: 'plat_counter_no',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '上游商家编号',
|
||||||
|
dataIndex: 'up_merchant_no',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '下游订单号',
|
||||||
|
dataIndex: 'down_order_no',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '上游订单号',
|
||||||
|
dataIndex: 'up_order_no',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '上游流水号',
|
||||||
|
dataIndex: 'up_tx_no',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
61
src/pages/platforms/index.tsx
Normal file
61
src/pages/platforms/index.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
|
||||||
|
export default function Index({ title = '平台' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
search={false}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Platforms.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '平台名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '平台私钥',
|
||||||
|
dataIndex: 'private_key',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '平台公钥',
|
||||||
|
dataIndex: 'public_key',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
MyColumns.UpdatedAt(),
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Platforms.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
49
src/pages/platforms/modals/Create.tsx
Normal file
49
src/pages/platforms/modals/Create.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Create(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Platforms.Store>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`添加${props.title}`}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
trigger={<MyButtons.Create title={`添加${props.title}`} />}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Platforms.Store(values)
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '平台名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'private_key',
|
||||||
|
title: '平台私钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'public_key',
|
||||||
|
title: '平台公钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
50
src/pages/platforms/modals/Update.tsx
Normal file
50
src/pages/platforms/modals/Update.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import {
|
||||||
|
MyBetaModalFormProps,
|
||||||
|
MyButtons,
|
||||||
|
MyModalFormProps,
|
||||||
|
rulesHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||||
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
export default function Update(props: MyBetaModalFormProps) {
|
||||||
|
return (
|
||||||
|
<BetaSchemaForm<ApiTypes.Platforms.Update>
|
||||||
|
{...MyModalFormProps.props}
|
||||||
|
title={`编辑${props.title}`}
|
||||||
|
trigger={<MyButtons.Edit />}
|
||||||
|
wrapperCol={{ span: 24 }}
|
||||||
|
width="500px"
|
||||||
|
request={() => Promise.resolve(props.item)}
|
||||||
|
onFinish={async (values) =>
|
||||||
|
Apis.Platforms.Update({ ...values, id: props.item?.id ?? 0 })
|
||||||
|
.then(() => {
|
||||||
|
props.reload?.();
|
||||||
|
message.success(props.title + '成功');
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false)
|
||||||
|
}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: '平台名称',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'private_key',
|
||||||
|
title: '平台私钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'public_key',
|
||||||
|
title: '平台公钥',
|
||||||
|
valueType: 'textarea',
|
||||||
|
formItemProps: { ...rulesHelper.text },
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
68
src/pages/system/admins/index.tsx
Normal file
68
src/pages/system/admins/index.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import {
|
||||||
|
MyButtons,
|
||||||
|
MyColumns,
|
||||||
|
MyPageContainer,
|
||||||
|
MyProTableProps,
|
||||||
|
renderTextHelper,
|
||||||
|
} from '@/common';
|
||||||
|
import { Apis } from '@/gen/Apis';
|
||||||
|
import { ProTable } from '@ant-design/pro-components';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import Create from './modals/Create';
|
||||||
|
import Update from './modals/Update';
|
||||||
|
|
||||||
|
export default function Index({ title = '管理员' }) {
|
||||||
|
return (
|
||||||
|
<MyPageContainer title={title}>
|
||||||
|
<ProTable
|
||||||
|
{...MyProTableProps.props}
|
||||||
|
search={false}
|
||||||
|
request={async (params, sort) =>
|
||||||
|
MyProTableProps.request(params, sort, Apis.Admins.List)
|
||||||
|
}
|
||||||
|
toolBarRender={(action) => [
|
||||||
|
<Create key="Create" reload={action?.reload} title={title} />,
|
||||||
|
]}
|
||||||
|
columns={[
|
||||||
|
MyColumns.ID(),
|
||||||
|
{
|
||||||
|
title: '账号',
|
||||||
|
dataIndex: 'username',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '角色',
|
||||||
|
dataIndex: 'roles',
|
||||||
|
renderText: renderTextHelper.TagList,
|
||||||
|
hideInSearch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'last_login_ip',
|
||||||
|
dataIndex: 'last_login_ip',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'last_login_at',
|
||||||
|
dataIndex: 'last_login_at',
|
||||||
|
search: false,
|
||||||
|
},
|
||||||
|
MyColumns.UpdatedAt(),
|
||||||
|
MyColumns.CreatedAt(),
|
||||||
|
MyColumns.Option({
|
||||||
|
render: (_, item: any, index, action) => (
|
||||||
|
<Space key={index}>
|
||||||
|
<Update item={item} reload={action?.reload} title={title} />
|
||||||
|
<MyButtons.Delete
|
||||||
|
onConfirm={() =>
|
||||||
|
Apis.Admins.Delete({ id: item.id }).then(() =>
|
||||||
|
action?.reload(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</MyPageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user