nili
3 years ago
17 changed files with 555 additions and 95 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,254 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<meta name="theme-color" content="#1890ff" /> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> |
|||
<meta |
|||
name="keywords" |
|||
content="antd,umi,umijs,ant design,Scaffolding, layout, Ant Design, project, Pro, admin, console, homepage, out-of-the-box, middle and back office, solution, component library" |
|||
/> |
|||
<meta |
|||
name="description" |
|||
content=" |
|||
An out-of-box UI solution for enterprise applications as a React boilerplate." |
|||
/> |
|||
<meta |
|||
name="description" |
|||
content=" |
|||
Out-of-the-box mid-stage front-end/design solution." |
|||
/> |
|||
<meta |
|||
name="viewport" |
|||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" |
|||
/> |
|||
<title>Ant Design Pro</title> |
|||
<link rel="icon" href="/favicon.ico" type="image/x-icon" /> |
|||
<link rel="stylesheet" href="/umi.3237de05.css" /> |
|||
<script> |
|||
window.routerBase = "/"; |
|||
</script> |
|||
<script> |
|||
//! umi version: 3.5.21 |
|||
</script> |
|||
</head> |
|||
<body> |
|||
<noscript> |
|||
<div class="noscript-container"> |
|||
Hi there! Please |
|||
<div class="noscript-enableJS"> |
|||
<a |
|||
href="https://www.enablejavascript.io/en" |
|||
target="_blank" |
|||
rel="noopener noreferrer" |
|||
> |
|||
<b>enable Javascript</b> |
|||
</a> |
|||
</div> |
|||
in your browser to use Ant Design, Out-of-the-box mid-stage front/design |
|||
solution! |
|||
</div> |
|||
</noscript> |
|||
<div id="root"> |
|||
<style> |
|||
html, |
|||
body, |
|||
#root { |
|||
height: 100%; |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
#root { |
|||
background-repeat: no-repeat; |
|||
background-size: 100% auto; |
|||
} |
|||
.noscript-container { |
|||
display: flex; |
|||
align-content: center; |
|||
justify-content: center; |
|||
margin-top: 90px; |
|||
font-size: 20px; |
|||
font-family: "Lucida Sans", "Lucida Sans Regular", "Lucida Grande", |
|||
"Lucida Sans Unicode", Geneva, Verdana, sans-serif; |
|||
} |
|||
.noscript-enableJS { |
|||
padding-right: 3px; |
|||
padding-left: 3px; |
|||
} |
|||
.page-loading-warp { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 98px; |
|||
} |
|||
.ant-spin { |
|||
position: absolute; |
|||
display: none; |
|||
-webkit-box-sizing: border-box; |
|||
box-sizing: border-box; |
|||
margin: 0; |
|||
padding: 0; |
|||
color: rgba(0, 0, 0, 0.65); |
|||
color: #1890ff; |
|||
font-size: 14px; |
|||
font-variant: tabular-nums; |
|||
line-height: 1.5; |
|||
text-align: center; |
|||
list-style: none; |
|||
opacity: 0; |
|||
-webkit-transition: -webkit-transform 0.3s |
|||
cubic-bezier(0.78, 0.14, 0.15, 0.86); |
|||
transition: -webkit-transform 0.3s |
|||
cubic-bezier(0.78, 0.14, 0.15, 0.86); |
|||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86); |
|||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86), |
|||
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86); |
|||
-webkit-font-feature-settings: "tnum"; |
|||
font-feature-settings: "tnum"; |
|||
} |
|||
|
|||
.ant-spin-spinning { |
|||
position: static; |
|||
display: inline-block; |
|||
opacity: 1; |
|||
} |
|||
|
|||
.ant-spin-dot { |
|||
position: relative; |
|||
display: inline-block; |
|||
width: 20px; |
|||
height: 20px; |
|||
font-size: 20px; |
|||
} |
|||
|
|||
.ant-spin-dot-item { |
|||
position: absolute; |
|||
display: block; |
|||
width: 9px; |
|||
height: 9px; |
|||
background-color: #1890ff; |
|||
border-radius: 100%; |
|||
-webkit-transform: scale(0.75); |
|||
-ms-transform: scale(0.75); |
|||
transform: scale(0.75); |
|||
-webkit-transform-origin: 50% 50%; |
|||
-ms-transform-origin: 50% 50%; |
|||
transform-origin: 50% 50%; |
|||
opacity: 0.3; |
|||
-webkit-animation: antspinmove 1s infinite linear alternate; |
|||
animation: antSpinMove 1s infinite linear alternate; |
|||
} |
|||
|
|||
.ant-spin-dot-item:nth-child(1) { |
|||
top: 0; |
|||
left: 0; |
|||
} |
|||
|
|||
.ant-spin-dot-item:nth-child(2) { |
|||
top: 0; |
|||
right: 0; |
|||
-webkit-animation-delay: 0.4s; |
|||
animation-delay: 0.4s; |
|||
} |
|||
|
|||
.ant-spin-dot-item:nth-child(3) { |
|||
right: 0; |
|||
bottom: 0; |
|||
-webkit-animation-delay: 0.8s; |
|||
animation-delay: 0.8s; |
|||
} |
|||
|
|||
.ant-spin-dot-item:nth-child(4) { |
|||
bottom: 0; |
|||
left: 0; |
|||
-webkit-animation-delay: 1.2s; |
|||
animation-delay: 1.2s; |
|||
} |
|||
|
|||
.ant-spin-dot-spin { |
|||
-webkit-transform: rotate(45deg); |
|||
-ms-transform: rotate(45deg); |
|||
transform: rotate(45deg); |
|||
-webkit-animation: antrotate 1.2s infinite linear; |
|||
animation: antRotate 1.2s infinite linear; |
|||
} |
|||
|
|||
.ant-spin-lg .ant-spin-dot { |
|||
width: 32px; |
|||
height: 32px; |
|||
font-size: 32px; |
|||
} |
|||
|
|||
.ant-spin-lg .ant-spin-dot i { |
|||
width: 14px; |
|||
height: 14px; |
|||
} |
|||
|
|||
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { |
|||
.ant-spin-blur { |
|||
background: #fff; |
|||
opacity: 0.5; |
|||
} |
|||
} |
|||
|
|||
@-webkit-keyframes antSpinMove { |
|||
to { |
|||
opacity: 1; |
|||
} |
|||
} |
|||
|
|||
@keyframes antSpinMove { |
|||
to { |
|||
opacity: 1; |
|||
} |
|||
} |
|||
|
|||
@-webkit-keyframes antRotate { |
|||
to { |
|||
-webkit-transform: rotate(405deg); |
|||
transform: rotate(405deg); |
|||
} |
|||
} |
|||
|
|||
@keyframes antRotate { |
|||
to { |
|||
-webkit-transform: rotate(405deg); |
|||
transform: rotate(405deg); |
|||
} |
|||
} |
|||
</style> |
|||
<div |
|||
style=" |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 100%; |
|||
min-height: 420px; |
|||
" |
|||
> |
|||
<img src="/pro_icon.svg" alt="logo" width="256" /> |
|||
<div class="page-loading-warp"> |
|||
<div class="ant-spin ant-spin-lg ant-spin-spinning"> |
|||
<span class="ant-spin-dot ant-spin-dot-spin" |
|||
><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i |
|||
><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i |
|||
></span> |
|||
</div> |
|||
</div> |
|||
<div |
|||
style="display: flex; align-items: center; justify-content: center" |
|||
> |
|||
<img |
|||
src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg" |
|||
width="32" |
|||
style="margin-right: 8px" |
|||
/> |
|||
Ant Design |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script src="/umi.c65a8521.js"></script> |
|||
</body> |
|||
</html> |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,59 @@ |
|||
import { DrawerForm, ProFormText, ProFormTextArea } from '@ant-design/pro-form'; |
|||
import { Button, message } from 'antd'; |
|||
import React, { useRef } from 'react'; |
|||
|
|||
import { getAuthorByIdUsingGET, saveAuthorUsingPOST } from '../../../services/luigi/author'; |
|||
|
|||
import type { ProFormInstance } from '@ant-design/pro-form'; |
|||
const AuthorForm: React.FC<{ |
|||
triggerText: string; |
|||
formTitle: string; |
|||
authorId?: number; |
|||
refresh?: () => void; |
|||
}> = (props) => { |
|||
const formRef = useRef<ProFormInstance<API.PoemBo>>(); |
|||
return ( |
|||
<DrawerForm<API.PoemBo> |
|||
title={props.formTitle} |
|||
formRef={formRef} |
|||
layout="horizontal" |
|||
trigger={<Button type="primary">{props.triggerText}</Button>} |
|||
autoFocusFirstInput |
|||
drawerProps={{ |
|||
destroyOnClose: true, |
|||
}} |
|||
onVisibleChange={async (visible: boolean) => { |
|||
if (!visible || !props.authorId) { |
|||
return; |
|||
} |
|||
const response = await getAuthorByIdUsingGET({ id: props.authorId }); |
|||
if (response.data) { |
|||
formRef.current?.setFieldsValue(response.data); |
|||
} |
|||
}} |
|||
onFinish={async (values) => { |
|||
const rsp = await saveAuthorUsingPOST({ ...values, id: props.authorId }); |
|||
if (rsp.code) { |
|||
message.success('提交成功'); |
|||
if (props.refresh) { |
|||
props.refresh(); |
|||
} |
|||
return true; |
|||
} |
|||
return false; |
|||
}} |
|||
> |
|||
<ProFormText width="md" name="name" label="名字" placeholder="请输入" /> |
|||
<ProFormText width="md" name="dynasty" label="朝代" placeholder="请输入" /> |
|||
<ProFormTextArea |
|||
fieldProps={{ autoSize: true }} |
|||
width="md" |
|||
name="introduction" |
|||
label="介绍" |
|||
placeholder="请输入" |
|||
/> |
|||
</DrawerForm> |
|||
); |
|||
}; |
|||
|
|||
export default AuthorForm; |
@ -0,0 +1,164 @@ |
|||
import AuthorSelect from '@/components/AuthorSelect'; |
|||
import { poemListUsingPOST } from '@/services/luigi/poem'; |
|||
import ProTable from '@ant-design/pro-table'; |
|||
import { Popconfirm } from 'antd'; |
|||
import React, { useRef } from 'react'; |
|||
|
|||
import { saveAuthorUsingPOST } from '@/services/luigi/author'; |
|||
import AuthorForm from './components/AuthorForm'; |
|||
import { authorListUsingPOST } from '../../services/luigi/author'; |
|||
|
|||
import type { ProColumns, ActionType } from '@ant-design/pro-table'; |
|||
const columns: ProColumns<API.PoemBo>[] = [ |
|||
{ |
|||
dataIndex: 'id', |
|||
title: 'id', |
|||
}, |
|||
{ |
|||
title: '名字', |
|||
dataIndex: 'name', |
|||
ellipsis: true, |
|||
hideInSearch: true, |
|||
formItemProps: { |
|||
rules: [ |
|||
{ |
|||
required: true, |
|||
message: '此项为必填项', |
|||
}, |
|||
], |
|||
}, |
|||
}, |
|||
{ |
|||
title: '朝代', |
|||
dataIndex: 'dynasty', |
|||
ellipsis: true, |
|||
hideInSearch: true, |
|||
}, |
|||
{ |
|||
title: '名字', |
|||
dataIndex: 'id', |
|||
hideInTable: true, |
|||
renderFormItem: (item, { type, defaultRender, ...rest }) => { |
|||
return <AuthorSelect {...rest} />; |
|||
}, |
|||
}, |
|||
{ |
|||
title: '状态', |
|||
dataIndex: 'status', |
|||
valueType: 'select', |
|||
valueEnum: { |
|||
0: { |
|||
text: '未校准', |
|||
status: 'Error', |
|||
}, |
|||
1: { |
|||
text: '已校准', |
|||
status: 'Success', |
|||
}, |
|||
}, |
|||
}, |
|||
{ |
|||
title: '作品数量', |
|||
dataIndex: 'poemCnt', |
|||
hideInSearch: true, |
|||
render: (item, record) => { |
|||
return ( |
|||
<a target="blank" href={'/poem?authorId=' + record.id}> |
|||
{item} |
|||
</a> |
|||
); |
|||
}, |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
valueType: 'option', |
|||
key: 'option', |
|||
render: (text, record, _, action) => [ |
|||
<AuthorForm |
|||
key={record.id} |
|||
authorId={record.id} |
|||
formTitle={record.title || '编辑'} |
|||
triggerText="编辑" |
|||
refresh={() => action?.reload()} |
|||
/>, |
|||
<Popconfirm |
|||
title="确定删除吗?" |
|||
key={'delete' + record.id} |
|||
onConfirm={async () => { |
|||
await saveAuthorUsingPOST({ id: record.id, status: -1 }); |
|||
action?.reload(); |
|||
}} |
|||
okText="Yes" |
|||
cancelText="No" |
|||
> |
|||
<a href="#">删除</a> |
|||
</Popconfirm>, |
|||
<Popconfirm |
|||
title="确定标记吗?" |
|||
key={'mark_' + record.id} |
|||
onConfirm={async () => { |
|||
await saveAuthorUsingPOST({ id: record.id, status: record.status == 0 ? 1 : 0 }); |
|||
action?.reload(); |
|||
}} |
|||
okText="Yes" |
|||
cancelText="No" |
|||
> |
|||
<a href="#">{record.status == 0 ? '校准' : '取消校准'}</a> |
|||
</Popconfirm>, |
|||
], |
|||
}, |
|||
]; |
|||
|
|||
export default () => { |
|||
const actionRef = useRef<ActionType>(); |
|||
|
|||
return ( |
|||
<ProTable<API.PoemBo> |
|||
columns={columns} |
|||
actionRef={actionRef} |
|||
cardBordered |
|||
request={async (params = {}) => { |
|||
const query: API.QueryParam[] = []; |
|||
const allowedKey = ['id', 'name', 'status']; |
|||
Object.keys(params).forEach((x) => { |
|||
if (allowedKey.includes(x) && params[x]) { |
|||
query.push({ key: x, val: params[x] }); |
|||
} |
|||
}); |
|||
|
|||
const response = await authorListUsingPOST({ |
|||
current: params.current, |
|||
pageSize: params.pageSize, |
|||
query: query, |
|||
}); |
|||
return { data: response.data?.list, total: response.data?.total }; |
|||
}} |
|||
columnsState={{ |
|||
persistenceKey: 'pro-table-singe-demos', |
|||
persistenceType: 'localStorage', |
|||
}} |
|||
rowKey="id" |
|||
search={{ |
|||
labelWidth: 'auto', |
|||
}} |
|||
pagination={{ |
|||
pageSize: 20, |
|||
}} |
|||
form={{ |
|||
// 由于配置了 transform,提交的参与与定义的不同这里需要转化一下
|
|||
syncToUrl: (values, type) => { |
|||
if (type === 'get') { |
|||
return { |
|||
...values, |
|||
created_at: [values.startTime, values.endTime], |
|||
}; |
|||
} |
|||
return values; |
|||
}, |
|||
}} |
|||
headerTitle="列表" |
|||
dateFormatter="string" |
|||
toolBarRender={() => [<AuthorForm key="new" triggerText="新建" formTitle="创建" />]} |
|||
/> |
|||
); |
|||
}; |
@ -1,56 +0,0 @@ |
|||
import React from 'react'; |
|||
import { Form, message } from 'antd'; |
|||
import ProForm, { |
|||
ProFormDateRangePicker, |
|||
ProFormSelect, |
|||
ProFormDatePicker, |
|||
} from '@ant-design/pro-form'; |
|||
import AuthorSelect from '@/components/AuthorSelect'; |
|||
|
|||
export default () => { |
|||
return ( |
|||
<ProForm |
|||
onFinish={async () => { |
|||
message.success('提交成功'); |
|||
}} |
|||
syncToUrl={(values, type) => { |
|||
if (type === 'get') { |
|||
// 为了配合 transform
|
|||
// startTime 和 endTime 拼成 createTimeRanger
|
|||
return { |
|||
...values, |
|||
createTimeRanger: |
|||
values.startTime || values.endTime ? [values.startTime, values.endTime] : undefined, |
|||
}; |
|||
} |
|||
// expirationTime 不同步到 url
|
|||
return { |
|||
...values, |
|||
expirationTime: undefined, |
|||
}; |
|||
}} |
|||
initialValues={{ |
|||
name: '蚂蚁设计有限公司', |
|||
useMode: 'chapter', |
|||
}} |
|||
autoFocusFirstInput |
|||
> |
|||
<ProFormSelect |
|||
options={[ |
|||
{ |
|||
value: 'chapter', |
|||
label: '盖章后生效', |
|||
}, |
|||
]} |
|||
width="sm" |
|||
name="useMode" |
|||
label="合同约定生效方式" |
|||
/> |
|||
<Form.Item name="authorId"> |
|||
{(form) => { |
|||
return <AuthorSelect />; |
|||
}} |
|||
</Form.Item> |
|||
</ProForm> |
|||
); |
|||
}; |
Loading…
Reference in new issue