Browse Source

作者crud

master
nili 3 years ago
parent
commit
12790d2705
  1. 1
      config/routes.ts
  2. 26
      dist/502.219197d7.async.js
  3. 0
      dist/502.7bff7c20.chunk.css
  4. 9
      dist/asset-manifest.json
  5. 254
      dist/author/index.html
  6. 2
      dist/index.html
  7. 1
      dist/p__AuthorPage.13dc7e47.async.js
  8. 1
      dist/p__PoemPage.172ee8ed.async.js
  9. 1
      dist/p__PoemPage.87b66799.async.js
  10. 2
      dist/poem/index.html
  11. 24
      dist/umi.c65a8521.js
  12. 59
      src/pages/AuthorPage/components/AuthorForm.tsx
  13. 164
      src/pages/AuthorPage/index.tsx
  14. 56
      src/pages/PoemDetail/index.tsx
  15. 27
      src/services/luigi/author.ts
  16. 5
      src/services/luigi/poem.ts
  17. 18
      src/services/luigi/typings.d.ts

1
config/routes.ts

@ -21,6 +21,7 @@ export default [
// },
// { name: '查询表格', icon: 'table', path: '/list', component: './TableList' },
{ path: '/', redirect: '/poem' },
{ name: '作者', icon: 'smile', path: '/author', component: './AuthorPage' },
{ name: '诗词', icon: 'smile', path: '/poem', component: './PoemPage' },
{ component: './404' },
];

26
dist/594.dbe33938.async.js → dist/502.219197d7.async.js

File diff suppressed because one or more lines are too long

0
dist/594.7bff7c20.chunk.css → dist/502.7bff7c20.chunk.css

9
dist/asset-manifest.json

@ -1,16 +1,17 @@
{
"/umi.css": "/umi.3237de05.css",
"/umi.js": "/umi.f1794508.js",
"/umi.js": "/umi.c65a8521.js",
"/t__plugin-layout__Layout.css": "/t__plugin-layout__Layout.44b8ae54.chunk.css",
"/t__plugin-layout__Layout.js": "/t__plugin-layout__Layout.85d3f9bc.async.js",
"/p__PoemPage.js": "/p__PoemPage.172ee8ed.async.js",
"/p__AuthorPage.js": "/p__AuthorPage.13dc7e47.async.js",
"/p__PoemPage.js": "/p__PoemPage.87b66799.async.js",
"/p__404.css": "/p__404.572eeed8.chunk.css",
"/p__404.js": "/p__404.341bc6c9.async.js",
"/799.f321cbac.async.js": "/799.f321cbac.async.js",
"/105.2ed7a7f1.chunk.css": "/105.2ed7a7f1.chunk.css",
"/105.a25c9d08.async.js": "/105.a25c9d08.async.js",
"/594.7bff7c20.chunk.css": "/594.7bff7c20.chunk.css",
"/594.dbe33938.async.js": "/594.dbe33938.async.js",
"/502.7bff7c20.chunk.css": "/502.7bff7c20.chunk.css",
"/502.219197d7.async.js": "/502.219197d7.async.js",
"/icons/icon-512x512.png": "/icons/icon-512x512.png",
"/favicon.ico": "/favicon.ico",
"/logo.svg": "/logo.svg",

254
dist/author/index.html

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

2
dist/index.html

@ -249,6 +249,6 @@
</div>
</div>
<script src="/umi.f1794508.js"></script>
<script src="/umi.c65a8521.js"></script>
</body>
</html>

1
dist/p__AuthorPage.13dc7e47.async.js

File diff suppressed because one or more lines are too long

1
dist/p__PoemPage.172ee8ed.async.js

File diff suppressed because one or more lines are too long

1
dist/p__PoemPage.87b66799.async.js

File diff suppressed because one or more lines are too long

2
dist/poem/index.html

@ -249,6 +249,6 @@
</div>
</div>
<script src="/umi.f1794508.js"></script>
<script src="/umi.c65a8521.js"></script>
</body>
</html>

24
dist/umi.f1794508.js → dist/umi.c65a8521.js

File diff suppressed because one or more lines are too long

59
src/pages/AuthorPage/components/AuthorForm.tsx

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

164
src/pages/AuthorPage/index.tsx

@ -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="创建" />]}
/>
);
};

56
src/pages/PoemDetail/index.tsx

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

27
src/services/luigi/author.ts

@ -17,6 +17,33 @@ export async function getAuthorByIdUsingGET(
});
}
/** authorList POST /api/luigi/author/list */
export async function authorListUsingPOST(
body: API.PaginationQuery,
options?: { [key: string]: any },
) {
return request<API.ResponseCommonListAuthor>('/api/luigi/author/list', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** saveAuthor POST /api/luigi/author/save */
export async function saveAuthorUsingPOST(body: API.Author, options?: { [key: string]: any }) {
return request<API.Responseint>('/api/luigi/author/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** seek GET /api/luigi/author/seek */
export async function seekUsingGET(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)

5
src/services/luigi/poem.ts

@ -18,7 +18,10 @@ export async function poemDetailUsingGET(
}
/** poemList POST /api/luigi/poem/list */
export async function poemListUsingPOST(body: API.PoemQuery, options?: { [key: string]: any }) {
export async function poemListUsingPOST(
body: API.PaginationQuery,
options?: { [key: string]: any },
) {
return request<API.ResponseCommonListPoemBo>('/api/luigi/poem/list', {
method: 'POST',
headers: {

18
src/services/luigi/typings.d.ts

@ -22,6 +22,17 @@ declare namespace API {
total?: number;
};
type Note = {
annotation?: string;
citation?: string;
};
type PaginationQuery = {
current?: number;
pageSize?: number;
query?: QueryParam[];
};
type PoemBo = {
authorId?: number;
authorName?: string;
@ -29,17 +40,12 @@ declare namespace API {
id?: number;
line?: string;
note?: string;
noteList?: Note[];
status?: number;
title?: string;
translation?: string;
};
type PoemQuery = {
current?: number;
pageSize?: number;
query?: QueryParam[];
};
type QueryParam = {
key?: string;
val?: string;

Loading…
Cancel
Save