33 changed files with 1121 additions and 139 deletions
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
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
File diff suppressed because one or more lines are too long
@ -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")]}})}}}]); |
@ -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> |
File diff suppressed because one or more lines are too long
@ -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; |
@ -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; |
@ -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; |
@ -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> |
||||
|
); |
||||
|
}; |
@ -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 || {}), |
||||
|
}); |
||||
|
} |
@ -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 || {}), |
||||
|
}); |
||||
|
} |
Loading…
Reference in new issue