Browse Source

主题编辑

master
nili 3 years ago
parent
commit
5aa8cb2e05
  1. 1
      config/routes.ts
  2. 1
      dist/471.4a4b65f3.async.js
  3. 1
      dist/471.bede4387.async.js
  4. 78
      dist/750.002ec865.async.js
  5. 0
      dist/750.9563962e.chunk.css
  6. 78
      dist/765.0e611d9e.async.js
  7. 15
      dist/asset-manifest.json
  8. 2
      dist/author/index.html
  9. 2
      dist/index.html
  10. 1
      dist/p__AuthorPage.378c67f2.async.js
  11. 1
      dist/p__AuthorPage.aa0c0ad9.async.js
  12. 1
      dist/p__PoemPage.7789b67f.async.js
  13. 1
      dist/p__PoemPage.e0b147d0.async.js
  14. 1
      dist/p__TopicPage.464a4ea1.async.js
  15. 2
      dist/p__VersePage.3f7eff53.async.js
  16. 2
      dist/poem/index.html
  17. 254
      dist/topic/index.html
  18. 76
      dist/umi.f5f5d15b.js
  19. 2
      dist/verse/index.html
  20. 2
      src/components/AuthorSelect/index.tsx
  21. 42
      src/components/CategorySelect/index.tsx
  22. 10
      src/components/PoemSelect.tsx
  23. 2
      src/pages/AuthorPage/components/AuthorForm.tsx
  24. 7
      src/pages/AuthorPage/index.tsx
  25. 7
      src/pages/PoemPage/index.tsx
  26. 129
      src/pages/TopicPage/components/CategoryForm.tsx
  27. 100
      src/pages/TopicPage/components/TopicForm.tsx
  28. 231
      src/pages/TopicPage/index.tsx
  29. 7
      src/pages/VersePage/index.tsx
  30. 60
      src/services/luigi/category.ts
  31. 4
      src/services/luigi/index.ts
  32. 38
      src/services/luigi/topic.ts
  33. 102
      src/services/luigi/typings.d.ts

1
config/routes.ts

@ -24,5 +24,6 @@ export default [
{ name: '作者', icon: 'smile', path: '/author', component: './AuthorPage' },
{ name: '诗词', icon: 'smile', path: '/poem', component: './PoemPage' },
{ name: '金句', icon: 'smile', path: '/verse', component: './VersePage' },
{ name: '主题', icon: 'smile', path: '/topic', component: './TopicPage' },
{ component: './404' },
];

1
dist/471.4a4b65f3.async.js

File diff suppressed because one or more lines are too long

1
dist/471.bede4387.async.js

File diff suppressed because one or more lines are too long

78
dist/750.002ec865.async.js

File diff suppressed because one or more lines are too long

0
dist/765.9563962e.chunk.css → dist/750.9563962e.chunk.css

78
dist/765.0e611d9e.async.js

File diff suppressed because one or more lines are too long

15
dist/asset-manifest.json

@ -1,21 +1,22 @@
{
"/umi.css": "/umi.3237de05.css",
"/umi.js": "/umi.bef416f0.js",
"/umi.js": "/umi.f5f5d15b.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__AuthorPage.js": "/p__AuthorPage.aa0c0ad9.async.js",
"/p__AuthorPage.js": "/p__AuthorPage.378c67f2.async.js",
"/p__PoemPage.css": "/p__PoemPage.661ee886.chunk.css",
"/p__PoemPage.js": "/p__PoemPage.e0b147d0.async.js",
"/p__PoemPage.js": "/p__PoemPage.7789b67f.async.js",
"/p__VersePage.css": "/p__VersePage.661ee886.chunk.css",
"/p__VersePage.js": "/p__VersePage.1bfa01c7.async.js",
"/p__VersePage.js": "/p__VersePage.3f7eff53.async.js",
"/p__TopicPage.js": "/p__TopicPage.464a4ea1.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",
"/765.9563962e.chunk.css": "/765.9563962e.chunk.css",
"/765.0e611d9e.async.js": "/765.0e611d9e.async.js",
"/471.bede4387.async.js": "/471.bede4387.async.js",
"/750.9563962e.chunk.css": "/750.9563962e.chunk.css",
"/750.002ec865.async.js": "/750.002ec865.async.js",
"/471.4a4b65f3.async.js": "/471.4a4b65f3.async.js",
"/icons/icon-512x512.png": "/icons/icon-512x512.png",
"/favicon.ico": "/favicon.ico",
"/logo.svg": "/logo.svg",

2
dist/author/index.html

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

2
dist/index.html

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

1
dist/p__AuthorPage.378c67f2.async.js

File diff suppressed because one or more lines are too long

1
dist/p__AuthorPage.aa0c0ad9.async.js

File diff suppressed because one or more lines are too long

1
dist/p__PoemPage.7789b67f.async.js

File diff suppressed because one or more lines are too long

1
dist/p__PoemPage.e0b147d0.async.js

File diff suppressed because one or more lines are too long

1
dist/p__TopicPage.464a4ea1.async.js

File diff suppressed because one or more lines are too long

2
dist/p__VersePage.1bfa01c7.async.js → dist/p__VersePage.3f7eff53.async.js

@ -1 +1 @@
(self.webpackChunkant_design_pro=self.webpackChunkant_design_pro||[]).push([[507],{61173:function(C,f,t){"use strict";t.r(f);var B=t(57663),D=t(71577),U=t(62350),P=t(75443),h=t(3182),o=t(11849),v=t(93224),A=t(402),I=t(61859),M=t(94043),u=t.n(M),T=t(79667),y=t(97830),c=t(26697),R=t(39750),g=t(67294),O=t(579),n=t(85893),j=[{dataIndex:"id",title:"id",width:"10%"},{title:"\u91D1\u53E5",dataIndex:"content",hideInSearch:!0,width:"30%"},{title:"\u8BD7\u8BCD\u6807\u9898",dataIndex:"title",ellipsis:!0,hideInSearch:!0,render:function(_,e){return(0,n.jsx)(I.Z.Link,{target:"_blank",href:"/poem?id="+e.originId,children:e.title})}},{title:"\u4F5C\u8005",dataIndex:"authorName",ellipsis:!0,hideInSearch:!0,render:function(_,e){return(0,n.jsx)(I.Z.Link,{target:"_blank",href:"/author?id="+e.authorId,children:e.authorName})}},{title:"\u4F5C\u8005",dataIndex:"authorId",hideInTable:!0,renderFormItem:function(_,e){var d=e.type,r=e.defaultRender,s=(0,v.Z)(e,["type","defaultRender"]);return(0,n.jsx)(T.Z,(0,o.Z)({},s))}},{title:"\u8BD7\u8BCD",dataIndex:"originId",hideInTable:!0,renderFormItem:function(_,e){var d=e.type,r=e.defaultRender,s=(0,v.Z)(e,["type","defaultRender"]);return(0,n.jsx)(y.Z,(0,o.Z)({},s))}},{title:"\u72B6\u6001",dataIndex:"status",valueType:"select",valueEnum:{0:{text:"\u672A\u6821\u51C6",status:"Error"},1:{text:"\u5DF2\u6821\u51C6",status:"Success"}}},{title:"\u64CD\u4F5C",valueType:"option",key:"option",render:function(_,e,d,r){return[(0,n.jsx)(O.Z,{verseId:e.id,formTitle:e.title||"\u7F16\u8F91",trigger:(0,n.jsx)("a",{href:"#",children:"\u7F16\u8F91"}),refresh:function(){return r==null?void 0:r.reload()}},e.id),(0,n.jsx)(P.Z,{title:"\u786E\u5B9A\u5220\u9664\u5417?",onConfirm:(0,h.Z)(u().mark(function s(){return u().wrap(function(a){for(;;)switch(a.prev=a.next){case 0:return a.next=2,(0,c.px)({id:e.id,status:-1});case 2:r==null||r.reload();case 3:case"end":return a.stop()}},s)})),okText:"Yes",cancelText:"No",children:(0,n.jsx)("a",{href:"#",children:"\u5220\u9664"})},"delete"+e.id),(0,n.jsx)(P.Z,{title:"\u786E\u5B9A\u6807\u8BB0\u5417?",onConfirm:(0,h.Z)(u().mark(function s(){return u().wrap(function(a){for(;;)switch(a.prev=a.next){case 0:return a.next=2,(0,c.px)({id:e.id,status:e.status==0?1:0});case 2:r==null||r.reload();case 3:case"end":return a.stop()}},s)})),okText:"Yes",cancelText:"No",children:(0,n.jsx)("a",{href:"#",children:e.status==0?"\u6821\u51C6":"\u53D6\u6D88\u6821\u51C6"})},"mark_"+e.id)]}}];f.default=function(){var i=(0,g.useRef)();return(0,n.jsx)(R.ZP,{columns:j,actionRef:i,cardBordered:!0,request:(0,h.Z)(u().mark(function _(){var e,d,r,s,m,a,p=arguments;return u().wrap(function(l){for(;;)switch(l.prev=l.next){case 0:return r=p.length>0&&p[0]!==void 0?p[0]:{},s=[],m=["id","authorId","status","originId"],Object.keys(r).forEach(function(E){m.includes(E)&&r[E]&&s.push({key:E,val:r[E]})}),l.next=6,(0,c.c)({current:r.current,pageSize:r.pageSize,query:s});case 6:return a=l.sent,l.abrupt("return",{data:(e=a.data)===null||e===void 0?void 0:e.list,total:(d=a.data)===null||d===void 0?void 0:d.total});case 8:case"end":return l.stop()}},_)})),columnsState:{persistenceKey:"pro-table-singe-demos",persistenceType:"localStorage"},rowKey:"id",search:{labelWidth:"auto"},pagination:{pageSize:20},form:{syncToUrl:function(e,d){return d==="get"?(0,o.Z)((0,o.Z)({},e),{},{created_at:[e.startTime,e.endTime]}):e}},headerTitle:"\u5217\u8868",dateFormatter:"string",toolBarRender:function(){return[(0,n.jsx)(O.Z,{trigger:(0,n.jsx)(D.Z,{type:"primary",children:"\u7F16\u8F91"}),formTitle:"\u521B\u5EFA"},"new")]}})}}}]);
(self.webpackChunkant_design_pro=self.webpackChunkant_design_pro||[]).push([[507],{61173:function(B,f,t){"use strict";t.r(f);var C=t(57663),D=t(71577),U=t(62350),v=t(75443),h=t(3182),l=t(11849),P=t(93224),A=t(402),I=t(61859),M=t(94043),i=t.n(M),T=t(79667),R=t(97830),c=t(26697),y=t(39750),g=t(67294),O=t(579),n=t(85893),j=[{dataIndex:"id",title:"id",width:"10%"},{title:"\u91D1\u53E5",dataIndex:"content",hideInSearch:!0,width:"30%"},{title:"\u8BD7\u8BCD\u6807\u9898",dataIndex:"title",ellipsis:!0,hideInSearch:!0,render:function(_,e){return(0,n.jsx)(I.Z.Link,{target:"_blank",href:"/poem?id="+e.originId,children:e.title})}},{title:"\u4F5C\u8005",dataIndex:"authorName",ellipsis:!0,hideInSearch:!0,render:function(_,e){return(0,n.jsx)(I.Z.Link,{target:"_blank",href:"/author?id="+e.authorId,children:e.authorName})}},{title:"\u4F5C\u8005",dataIndex:"authorId",hideInTable:!0,renderFormItem:function(_,e){var d=e.type,r=e.defaultRender,s=(0,P.Z)(e,["type","defaultRender"]);return(0,n.jsx)(T.Z,(0,l.Z)({},s))}},{title:"\u8BD7\u8BCD",dataIndex:"originId",hideInTable:!0,renderFormItem:function(_,e){var d=e.type,r=e.defaultRender,s=(0,P.Z)(e,["type","defaultRender"]);return(0,n.jsx)(R.Z,(0,l.Z)({},s))}},{title:"\u72B6\u6001",dataIndex:"status",valueType:"select",valueEnum:{0:{text:"\u672A\u6821\u51C6",status:"Error"},1:{text:"\u5DF2\u6821\u51C6",status:"Success"}}},{title:"\u64CD\u4F5C",valueType:"option",key:"option",render:function(_,e,d,r){return[(0,n.jsx)(O.Z,{verseId:e.id,formTitle:e.title||"\u7F16\u8F91",trigger:(0,n.jsx)("a",{href:"#",children:"\u7F16\u8F91"}),refresh:function(){return r==null?void 0:r.reload()}},e.id),(0,n.jsx)(v.Z,{title:"\u786E\u5B9A\u5220\u9664\u5417?",onConfirm:(0,h.Z)(i().mark(function s(){return i().wrap(function(a){for(;;)switch(a.prev=a.next){case 0:return a.next=2,(0,c.px)({id:e.id,status:-1});case 2:r==null||r.reload();case 3:case"end":return a.stop()}},s)})),okText:"Yes",cancelText:"No",children:(0,n.jsx)("a",{href:"#",children:"\u5220\u9664"})},"delete"+e.id),(0,n.jsx)(v.Z,{title:"\u786E\u5B9A\u6807\u8BB0\u5417?",onConfirm:(0,h.Z)(i().mark(function s(){return i().wrap(function(a){for(;;)switch(a.prev=a.next){case 0:return a.next=2,(0,c.px)({id:e.id,status:e.status==0?1:0});case 2:r==null||r.reload();case 3:case"end":return a.stop()}},s)})),okText:"Yes",cancelText:"No",children:(0,n.jsx)("a",{href:"#",children:e.status==0?"\u6821\u51C6":"\u53D6\u6D88\u6821\u51C6"})},"mark_"+e.id)]}}];f.default=function(){var u=(0,g.useRef)();return(0,n.jsx)(y.ZP,{columns:j,actionRef:u,cardBordered:!0,request:(0,h.Z)(i().mark(function _(){var e,d,r,s,m,a,p=arguments;return i().wrap(function(o){for(;;)switch(o.prev=o.next){case 0:return r=p.length>0&&p[0]!==void 0?p[0]:{},s=[],m=["id","authorId","status","originId"],Object.keys(r).forEach(function(E){m.includes(E)&&r[E]&&s.push({key:E,val:r[E]})}),o.next=6,(0,c.c)({current:r.current,pageSize:r.pageSize,query:s});case 6:return a=o.sent,o.abrupt("return",{data:(e=a.data)===null||e===void 0?void 0:e.list,total:(d=a.data)===null||d===void 0?void 0:d.total});case 8:case"end":return o.stop()}},_)})),columnsState:{persistenceKey:"pro-table-singe-demos",persistenceType:"localStorage"},rowKey:"id",search:{labelWidth:"auto"},pagination:{pageSize:20},form:{syncToUrl:function(e,d){return d==="get"?(0,l.Z)((0,l.Z)({},e),{},{created_at:[e.startTime,e.endTime]}):e}},headerTitle:"\u5217\u8868",dateFormatter:"string",toolBarRender:function(){var e;return[(0,n.jsx)(O.Z,{refresh:(e=u.current)===null||e===void 0?void 0:e.reload,trigger:(0,n.jsx)(D.Z,{type:"primary",children:"\u65B0\u5EFA"}),formTitle:"\u521B\u5EFA"},"new")]}})}}}]);

2
dist/poem/index.html

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

254
dist/topic/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.f5f5d15b.js"></script>
</body>
</html>

76
dist/umi.bef416f0.js → dist/umi.f5f5d15b.js

File diff suppressed because one or more lines are too long

2
dist/verse/index.html

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

2
src/components/AuthorSelect/index.tsx

@ -8,7 +8,7 @@ const AuthorSelect: React.FC<{
value?: number;
onChange?: (value: ValueType) => void;
}> = (props) => {
const [initOption, setInitOption] = React.useState();
const [initOption, setInitOption] = React.useState<ValueType>();
React.useEffect(() => {
if (!props.value) {
return;

42
src/components/CategorySelect/index.tsx

@ -0,0 +1,42 @@
import { seekCategoryUsingGET } from '@/services/luigi/category';
import React from 'react';
import DebounceSelect from '../DebunceSelect';
import type { ValueType } from '../DebunceSelect';
const CategorySelect: React.FC<{
value?: API.Category;
onChange?: (value: API.Category) => void;
}> = (props) => {
return (
<DebounceSelect
initOption={
props.value
? { label: props.value.title, value: props.value.id, key: props.value.id }
: undefined
}
fetchOptions={async (query) => {
const response = await seekCategoryUsingGET({
title: query,
});
if (response.data?.list) {
return response.data.list?.map((category) => {
const data: ValueType = { label: category.title, value: category.id, key: category.id };
return data;
});
}
return undefined;
}}
onChange={(val) => {
if (props.onChange) {
props.onChange({ id: val });
}
}}
style={{
width: '100%',
}}
/>
);
};
export default CategorySelect;

10
src/components/PoemSelect.tsx

@ -5,12 +5,16 @@ import DebounceSelect from './DebunceSelect';
import type { ValueType } from './DebunceSelect';
const PoemSelect: React.FC<{
value?: number;
value?: number | API.Category;
onChange?: (value: ValueType) => void;
}> = (props) => {
const [initOption, setInitOption] = React.useState();
let defaultOption: ValueType = undefined;
if (props.value && isNaN(props.value)) {
defaultOption = { key: props.value.id, label: props.value.title, value: props.value.id };
}
const [initOption, setInitOption] = React.useState<ValueType>(defaultOption);
React.useEffect(() => {
if (!props.value) {
if (!props.value || isNaN(props.value)) {
return;
}
const fetch = async () => {

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

@ -1,5 +1,5 @@
import { DrawerForm, ProFormText, ProFormTextArea } from '@ant-design/pro-form';
import { Button, message } from 'antd';
import { message } from 'antd';
import React, { useRef } from 'react';
import { getAuthorByIdUsingGET, saveAuthorUsingPOST } from '../../../services/luigi/author';

7
src/pages/AuthorPage/index.tsx

@ -153,7 +153,12 @@ export default () => {
headerTitle="列表"
dateFormatter="string"
toolBarRender={() => [
<AuthorForm key="new" trigger={<Button type="primary"></Button>} formTitle="创建" />,
<AuthorForm
refresh={actionRef.current?.reload}
key="new"
trigger={<Button type="primary"></Button>}
formTitle="创建"
/>,
]}
/>
);

7
src/pages/PoemPage/index.tsx

@ -161,7 +161,12 @@ export default () => {
headerTitle="列表"
dateFormatter="string"
toolBarRender={() => [
<PoemForm trigger={<Button type="primary"></Button>} key="new" formTitle="创建" />,
<PoemForm
refresh={actionRef.current?.reload}
trigger={<Button type="primary"></Button>}
key="new"
formTitle="创建"
/>,
]}
/>
);

129
src/pages/TopicPage/components/CategoryForm.tsx

@ -0,0 +1,129 @@
import PoemSelect from '@/components/PoemSelect';
import { categoryDetailUsingGET, saveCategoryUsingPOST } from '@/services/luigi/category';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { DrawerForm, ProFormText } from '@ant-design/pro-form';
import { Button, Col, Form, message, Row } from 'antd';
import React, { useRef } from 'react';
import type { ProFormInstance } from '@ant-design/pro-form';
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
};
const CategoryForm: React.FC<{
trigger: JSX.Element;
formTitle: string;
categoryId?: number;
refresh?: () => void;
}> = (props) => {
const formRef = useRef<ProFormInstance<API.PoemBo>>();
return (
<DrawerForm<API.CategoryDetail>
title={props.formTitle}
formRef={formRef}
layout="horizontal"
{...formItemLayout}
trigger={props.trigger}
autoFocusFirstInput
drawerProps={{
destroyOnClose: true,
}}
onVisibleChange={async (visible: boolean) => {
if (!visible || !props.categoryId) {
return;
}
const response = await categoryDetailUsingGET({ id: props.categoryId });
if (response.data) {
formRef.current?.setFieldsValue(response.data);
}
}}
onFinish={async (values) => {
const poemList: API.Poem[] | undefined = values.poems;
if (poemList) {
const ids = poemList.map((x) => {
return typeof x === 'number' ? x : x.id;
});
const cids = JSON.stringify(ids);
values.poemIds = cids;
}
values.poems = undefined;
const rsp = await saveCategoryUsingPOST({ ...values, id: props.categoryId });
if (rsp.code) {
message.success('提交成功');
if (props.refresh) {
props.refresh();
}
return true;
}
return false;
}}
>
<ProFormText
fieldProps={{ maxLength: 10 }}
width="md"
name="title"
label="标题"
placeholder="请输入"
/>
<ProFormText
fieldProps={{ maxLength: 10 }}
width="md"
name="subTitle"
label="副标题"
placeholder="请输入"
/>
<ProFormText
fieldProps={{ maxLength: 10 }}
width="md"
name="desc"
label="描述"
placeholder="请输入"
/>
<ProFormText
fieldProps={{ maxLength: 10 }}
width="md"
name="image"
label="图片地址"
placeholder="请输入"
/>
<Form.List name="poems">
{(fields, { add, remove }, { errors }) => (
<>
<Form.Item label="诗词" required={true}>
{fields.map((field) => (
<Row key={field.key}>
<Col span={10}>
<Form.Item {...field} key={field.key}>
<PoemSelect />
</Form.Item>
</Col>
<Col offset={1}>
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
/>
</Col>
</Row>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
style={{ width: '60%' }}
icon={<PlusOutlined />}
>
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</Form.Item>
</>
)}
</Form.List>
</DrawerForm>
);
};
export default CategoryForm;

100
src/pages/TopicPage/components/TopicForm.tsx

@ -0,0 +1,100 @@
import CategorySelect from '@/components/CategorySelect';
import { getTopicDetailUsingGET } from '@/services/luigi/topic';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { DrawerForm, ProFormText } from '@ant-design/pro-form';
import { Button, Col, Form, message, Row } from 'antd';
import React, { useRef } from 'react';
import { saveTopicUsingPOST } from '@/services/luigi/topic';
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 14 },
};
import type { ProFormInstance } from '@ant-design/pro-form';
const TopicForm: React.FC<{
trigger: JSX.Element;
formTitle: string;
topicId?: number;
refresh?: () => void;
}> = (props) => {
const formRef = useRef<ProFormInstance<API.PoemBo>>();
return (
<DrawerForm<API.TopicDetail>
title={props.formTitle}
formRef={formRef}
layout="horizontal"
{...formItemLayout}
trigger={props.trigger}
autoFocusFirstInput
drawerProps={{
destroyOnClose: true,
}}
onVisibleChange={async (visible: boolean) => {
if (!visible || !props.topicId) {
return;
}
const response = await getTopicDetailUsingGET({ id: props.topicId });
if (response.data) {
formRef.current?.setFieldsValue(response.data);
}
}}
onFinish={async (values) => {
const categoryList: API.Category[] | undefined = values.categoryList;
if (categoryList) {
const ids = categoryList.map((x) => x.id);
const cids = JSON.stringify(ids);
values.cids = cids;
}
const rsp = await saveTopicUsingPOST({ ...values, id: props.topicId });
if (rsp.code) {
message.success('提交成功');
if (props.refresh) {
props.refresh();
}
return true;
}
return false;
}}
>
<ProFormText width="md" name="title" label="标题" placeholder="请输入" />
<Form.List name="categoryList">
{(fields, { add, remove }, { errors }) => (
<>
<Form.Item label="分类" required={true}>
{fields.map((field) => (
<Row key={field.key}>
<Col span={10}>
<Form.Item {...field} key={field.key}>
<CategorySelect />
</Form.Item>
</Col>
<Col offset={1}>
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => remove(field.name)}
/>
</Col>
</Row>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
style={{ width: '60%' }}
icon={<PlusOutlined />}
>
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</Form.Item>
</>
)}
</Form.List>
</DrawerForm>
);
};
export default TopicForm;

231
src/pages/TopicPage/index.tsx

@ -0,0 +1,231 @@
import { getTopicListUsingGET } from '@/services/luigi/topic';
import type { ActionType, ProColumns } from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import { Button, Popconfirm, Tabs, Image } from 'antd';
import React from 'react';
import { saveTopicUsingPOST } from '../../services/luigi/topic';
import TopicForm from './components/TopicForm';
import { saveCategoryUsingPOST, categoryListUsingPOST } from '../../services/luigi/category';
import CategoryForm from './components/CategoryForm';
const { TabPane } = Tabs;
const topicColumns: ProColumns<API.Topic>[] = [
{
dataIndex: 'id',
title: 'id',
},
{
title: '标题',
dataIndex: 'title',
ellipsis: true,
tip: '标题过长会自动收缩',
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: {
0: {
text: '未校准',
status: 'Error',
},
1: {
text: '已校准',
status: 'Success',
},
},
},
{
title: '操作',
valueType: 'option',
key: 'option',
width: '25%',
render: (text, record, _, action) => [
<TopicForm
key={record.id}
topicId={record.id}
formTitle={record.title || '编辑'}
trigger={<a href="#"></a>}
refresh={() => action?.reload()}
/>,
<Popconfirm
title="确定删除吗?"
key={'delete' + record.id}
onConfirm={async () => {
await saveTopicUsingPOST({ id: record.id, status: -1 });
action?.reload();
}}
okText="Yes"
cancelText="No"
>
<a href="#"></a>
</Popconfirm>,
<Popconfirm
title="确定标记吗?"
key={'mark_' + record.id}
onConfirm={async () => {
await saveTopicUsingPOST({ id: record.id, status: record.status == 0 ? 1 : 0 });
action?.reload();
}}
okText="Yes"
cancelText="No"
>
<a href="#">{record.status == 0 ? '校准' : '取消校准'}</a>
</Popconfirm>,
],
},
];
const cateColumns: ProColumns<API.Category>[] = [
{
dataIndex: 'id',
title: 'id',
},
{
title: '标题',
dataIndex: 'title',
ellipsis: true,
tip: '标题过长会自动收缩',
},
{
title: '副标题',
dataIndex: 'subTitle',
ellipsis: true,
hideInSearch: true,
},
{
title: '描述',
dataIndex: 'desc',
ellipsis: true,
hideInSearch: true,
},
{
title: '图片',
dataIndex: 'image',
ellipsis: true,
hideInSearch: true,
render: (item, record) => {
if (record.image) {
return <Image src={record.image} />;
}
return null;
},
},
{
title: '状态',
dataIndex: 'status',
valueType: 'select',
valueEnum: {
0: {
text: '未校准',
status: 'Error',
},
1: {
text: '已校准',
status: 'Success',
},
},
},
{
title: '操作',
valueType: 'option',
key: 'option',
width: '25%',
render: (text, record, _, action) => [
<CategoryForm
key={record.id}
categoryId={record.id}
formTitle={record.title || '编辑'}
trigger={<a href="#"></a>}
refresh={() => action?.reload()}
/>,
<Popconfirm
title="确定删除吗?"
key={'delete' + record.id}
onConfirm={async () => {
await saveCategoryUsingPOST({ id: record.id, status: -1 });
action?.reload();
}}
okText="Yes"
cancelText="No"
>
<a href="#"></a>
</Popconfirm>,
<Popconfirm
title="确定标记吗?"
key={'mark_' + record.id}
onConfirm={async () => {
await saveCategoryUsingPOST({ 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 = React.useRef<ActionType>();
return (
<Tabs defaultActiveKey="1" style={{ backgroundColor: 'white', padding: '24px' }}>
<TabPane tab="主题" key="1">
<ProTable<API.Topic>
columns={topicColumns}
actionRef={actionRef}
request={async () => {
const response = await getTopicListUsingGET();
return { data: response.data?.list, total: response.data?.list?.length };
}}
rowKey="outUserNo"
pagination={false}
toolBarRender={() => [
<TopicForm
refresh={actionRef.current?.reload}
trigger={<Button type="primary"></Button>}
key="new"
formTitle="创建"
/>,
]}
search={false}
/>
</TabPane>
<TabPane tab="分类" key="2">
<ProTable<API.Category>
columns={cateColumns}
actionRef={actionRef}
request={async (params = {}) => {
const query: API.QueryParam[] = [];
const allowedKey = ['id', , 'status', 'title'];
Object.keys(params).forEach((x) => {
if (allowedKey.includes(x) && params[x]) {
query.push({ key: x, val: params[x] });
}
});
const response = await categoryListUsingPOST({
current: params.current,
pageSize: params.pageSize,
query: query,
});
return { data: response.data?.list, total: response.data?.total };
}}
rowKey="outUserNo"
pagination={{ pageSize: 20 }}
toolBarRender={() => [
<CategoryForm
refresh={actionRef.current?.reload}
trigger={<Button type="primary"></Button>}
key="new"
formTitle="创建"
/>,
]}
/>
</TabPane>
</Tabs>
);
};

7
src/pages/VersePage/index.tsx

@ -167,7 +167,12 @@ export default () => {
headerTitle="列表"
dateFormatter="string"
toolBarRender={() => [
<VerseForm key="new" trigger={<Button type="primary"></Button>} formTitle="创建" />,
<VerseForm
refresh={actionRef.current?.reload}
key="new"
trigger={<Button type="primary"></Button>}
formTitle="创建"
/>,
]}
/>
);

60
src/services/luigi/category.ts

@ -0,0 +1,60 @@
// @ts-ignore
/* eslint-disable */
import { request } from 'umi';
/** categoryDetail GET /api/luigi/category/detail */
export async function categoryDetailUsingGET(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.categoryDetailUsingGETParams,
options?: { [key: string]: any },
) {
return request<API.ResponseCategoryDetail>('/api/luigi/category/detail', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** categoryList POST /api/luigi/category/list */
export async function categoryListUsingPOST(
body: API.PaginationQuery,
options?: { [key: string]: any },
) {
return request<API.ResponseCommonListCategory>('/api/luigi/category/list', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** saveCategory POST /api/luigi/category/save */
export async function saveCategoryUsingPOST(body: API.Category, options?: { [key: string]: any }) {
return request<API.Responseint>('/api/luigi/category/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** seekCategory GET /api/luigi/category/seek */
export async function seekCategoryUsingGET(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.seekCategoryUsingGETParams,
options?: { [key: string]: any },
) {
return request<API.ResponseCommonListCategory>('/api/luigi/category/seek', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}

4
src/services/luigi/index.ts

@ -3,12 +3,16 @@
// API 更新时间:
// API 唯一标识:
import * as author from './author';
import * as category from './category';
import * as poem from './poem';
import * as topic from './topic';
import * as user from './user';
import * as verse from './verse';
export default {
author,
category,
poem,
topic,
user,
verse,
};

38
src/services/luigi/topic.ts

@ -0,0 +1,38 @@
// @ts-ignore
/* eslint-disable */
import { request } from 'umi';
/** getTopicDetail GET /api/luigi/topic/detail */
export async function getTopicDetailUsingGET(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getTopicDetailUsingGETParams,
options?: { [key: string]: any },
) {
return request<API.ResponseTopicDetail>('/api/luigi/topic/detail', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** getTopicList GET /api/luigi/topic/list */
export async function getTopicListUsingGET(options?: { [key: string]: any }) {
return request<API.ResponseCommonListTopic>('/api/luigi/topic/list', {
method: 'GET',
...(options || {}),
});
}
/** saveTopic POST /api/luigi/topic/save */
export async function saveTopicUsingPOST(body: API.TopicDetail, options?: { [key: string]: any }) {
return request<API.Responseint>('/api/luigi/topic/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}

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

@ -8,6 +8,29 @@ declare namespace API {
status?: number;
};
type Category = {
desc?: string;
id?: number;
image?: string;
poemIds?: string;
status?: number;
subTitle?: string;
title?: string;
type?: string;
};
type CategoryDetail = {
desc?: string;
id?: number;
image?: string;
poemIds?: string;
poems?: Poem[];
status?: number;
subTitle?: string;
title?: string;
type?: string;
};
type CommonListAuthor = {
current?: number;
list?: Author[];
@ -15,6 +38,13 @@ declare namespace API {
total?: number;
};
type CommonListCategory = {
current?: number;
list?: Category[];
pageSize?: number;
total?: number;
};
type CommonListPoemBo = {
current?: number;
list?: PoemBo[];
@ -22,6 +52,13 @@ declare namespace API {
total?: number;
};
type CommonListTopic = {
current?: number;
list?: Topic[];
pageSize?: number;
total?: number;
};
type CommonListVerse = {
current?: number;
list?: Verse[];
@ -40,6 +77,17 @@ declare namespace API {
query?: QueryParam[];
};
type Poem = {
authorId?: number;
content?: string;
id?: number;
line?: string;
note?: string;
status?: number;
title?: string;
translation?: string;
};
type PoemBo = {
authorId?: number;
authorName?: string;
@ -64,18 +112,36 @@ declare namespace API {
message?: string;
};
type ResponseCategoryDetail = {
code?: number;
data?: CategoryDetail;
message?: string;
};
type ResponseCommonListAuthor = {
code?: number;
data?: CommonListAuthor;
message?: string;
};
type ResponseCommonListCategory = {
code?: number;
data?: CommonListCategory;
message?: string;
};
type ResponseCommonListPoemBo = {
code?: number;
data?: CommonListPoemBo;
message?: string;
};
type ResponseCommonListTopic = {
code?: number;
data?: CommonListTopic;
message?: string;
};
type ResponseCommonListVerse = {
code?: number;
data?: CommonListVerse;
@ -88,6 +154,12 @@ declare namespace API {
message?: string;
};
type ResponseTopicDetail = {
code?: number;
data?: TopicDetail;
message?: string;
};
type ResponseUserBo = {
code?: number;
data?: UserBo;
@ -106,6 +178,21 @@ declare namespace API {
message?: string;
};
type Topic = {
cids?: string;
id?: number;
status?: number;
title?: string;
};
type TopicDetail = {
categoryList?: Category[];
cids?: string;
id?: number;
status?: number;
title?: string;
};
type UserBo = {
avatar?: string;
id?: number;
@ -135,6 +222,16 @@ declare namespace API {
name: string;
};
type categoryDetailUsingGETParams = {
/** id */
id: number;
};
type seekCategoryUsingGETParams = {
/** title */
title: string;
};
type poemDetailUsingGETParams = {
/** id */
id: number;
@ -145,6 +242,11 @@ declare namespace API {
title: string;
};
type getTopicDetailUsingGETParams = {
/** id */
id: number;
};
type getVerseByIdUsingGETParams = {
/** id */
id: number;

Loading…
Cancel
Save