From 9354c22eb96e5a216be82668a4f894428ddda63a Mon Sep 17 00:00:00 2001 From: nili Date: Thu, 31 Mar 2022 16:36:55 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=97=E6=AD=8C=E5=88=97=E8=A1=A8=E5=88=9D?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.ts | 24 ++- config/proxy.ts | 2 +- config/routes.ts | 54 ++----- package.json | 1 + src/app.tsx | 28 +++- src/components/AuthorSelect/index.tsx | 28 ++++ src/components/DebunceSelect/index.tsx | 66 ++++++++ src/components/Footer/index.tsx | 9 +- src/components/RightContent/index.tsx | 14 +- src/global.tsx | 36 +++-- src/pages/Admin.tsx | 28 ++-- src/pages/PoemDetail/index.tsx | 56 +++++++ src/pages/PoemPage/index.less | 6 + src/pages/PoemPage/index.tsx | 138 ++++++++++++++++ src/pages/TableList/components/UpdateForm.tsx | 89 +++-------- src/pages/TableList/index.tsx | 148 ++++++------------ src/pages/Welcome.tsx | 16 +- src/pages/user/Login/index.tsx | 140 +++++------------ src/services/ant-design-pro/api.ts | 68 +------- src/services/ant-design-pro/index.ts | 2 + src/services/ant-design-pro/login.ts | 29 +++- src/services/ant-design-pro/rule.ts | 42 +++++ src/services/ant-design-pro/typings.d.ts | 15 +- src/services/luigi/author.ts | 18 +++ src/services/luigi/index.ts | 12 ++ src/services/luigi/poem.ts | 30 ++++ src/services/luigi/typings.d.ts | 88 +++++++++++ src/services/luigi/user.ts | 11 ++ 28 files changed, 722 insertions(+), 476 deletions(-) create mode 100644 src/components/AuthorSelect/index.tsx create mode 100644 src/components/DebunceSelect/index.tsx create mode 100644 src/pages/PoemDetail/index.tsx create mode 100644 src/pages/PoemPage/index.less create mode 100644 src/pages/PoemPage/index.tsx create mode 100644 src/services/ant-design-pro/rule.ts create mode 100644 src/services/luigi/author.ts create mode 100644 src/services/luigi/index.ts create mode 100644 src/services/luigi/poem.ts create mode 100644 src/services/luigi/typings.d.ts create mode 100644 src/services/luigi/user.ts diff --git a/config/config.ts b/config/config.ts index 72eca9d..3b30ac5 100644 --- a/config/config.ts +++ b/config/config.ts @@ -1,13 +1,10 @@ // https://umijs.org/config/ import { defineConfig } from 'umi'; import { join } from 'path'; - import defaultSettings from './defaultSettings'; import proxy from './proxy'; import routes from './routes'; - const { REACT_APP_ENV } = process.env; - export default defineConfig({ hash: true, antd: {}, @@ -16,18 +13,10 @@ export default defineConfig({ }, layout: { // https://umijs.org/zh-CN/plugins/plugin-layout - locale: true, + locale: false, siderWidth: 208, ...defaultSettings, }, - // https://umijs.org/zh-CN/plugins/plugin-locale - locale: { - // default zh-CN - default: 'zh-CN', - antd: true, - // default true, when it is true, will use `navigator.language` overwrite default - baseNavigator: true, - }, dynamicImport: { loading: '@ant-design/pro-layout/es/PageLoading', }, @@ -64,11 +53,16 @@ export default defineConfig({ }, { requestLibPath: "import { request } from 'umi'", - schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json', - projectName: 'swagger', + // 或者使用在线的版本 + schemaPath: 'http://localhost:8001/api/luigi/swagger/v3/api-docs', + // schemaPath: join(__dirname, 'swaggerApi.json'), + mock: false, + projectName: 'luigi', }, ], - nodeModulesTransform: { type: 'none' }, + nodeModulesTransform: { + type: 'none', + }, mfsu: {}, webpack5: {}, exportStatic: {}, diff --git a/config/proxy.ts b/config/proxy.ts index a8194b7..843ef9a 100644 --- a/config/proxy.ts +++ b/config/proxy.ts @@ -11,7 +11,7 @@ export default { // localhost:8000/api/** -> https://preview.pro.ant.design/api/** '/api/': { // 要代理的地址 - target: 'https://preview.pro.ant.design', + target: 'http://localhost:8001', // 配置了这个可以从 http 代理到 https // 依赖 origin 的功能可能需要这个,比如 cookie changeOrigin: true, diff --git a/config/routes.ts b/config/routes.ts index ea518bb..34cfca5 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -1,58 +1,26 @@ -export default [ +export default [ { path: '/user', layout: false, routes: [ - { - path: '/user', - routes: [ - { - name: 'login', - path: '/user/login', - component: './user/Login', - }, - ], - }, - { - component: './404', - }, + { path: '/user', routes: [{ name: '登录', path: '/user/login', component: './user/Login' }] }, + { component: './404' }, ], }, - { - path: '/welcome', - name: 'welcome', - icon: 'smile', - component: './Welcome', - }, + { path: '/welcome', name: '欢迎', icon: 'smile', component: './Welcome' }, { path: '/admin', - name: 'admin', + name: '管理页', icon: 'crown', access: 'canAdmin', component: './Admin', routes: [ - { - path: '/admin/sub-page', - name: 'sub-page', - icon: 'smile', - component: './Welcome', - }, - { - component: './404', - }, + { path: '/admin/sub-page', name: '二级管理页', icon: 'smile', component: './Welcome' }, + { component: './404' }, ], }, - { - name: 'list.table-list', - icon: 'table', - path: '/list', - component: './TableList', - }, - { - path: '/', - redirect: '/welcome', - }, - { - component: './404', - }, + { name: '查询表格', icon: 'table', path: '/list', component: './TableList' }, + { path: '/', redirect: '/welcome' }, + { icon: 'smile', path: '/poem', component: './PoemPage' }, + { component: './404' }, ]; diff --git a/package.json b/package.json index 6b2f975..08f525b 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "@umijs/preset-ant-design-pro": "^1.3.0", "@umijs/preset-dumi": "^1.1.0", "@umijs/preset-react": "^1.8.17", + "@umijs/preset-ui": "^2.2.9", "@umijs/yorkie": "^2.0.5", "cross-env": "^7.0.0", "cross-port-killer": "^1.3.0", diff --git a/src/app.tsx b/src/app.tsx index 5857101..1ec3895 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,14 +1,14 @@ -import type { Settings as LayoutSettings } from '@ant-design/pro-layout'; -import { SettingDrawer } from '@ant-design/pro-layout'; -import { PageLoading } from '@ant-design/pro-layout'; -import type { RunTimeLayoutConfig } from 'umi'; -import { history, Link } from 'umi'; -import RightContent from '@/components/RightContent'; import Footer from '@/components/Footer'; -import { currentUser as queryCurrentUser } from './services/ant-design-pro/api'; +import RightContent from '@/components/RightContent'; import { BookOutlined, LinkOutlined } from '@ant-design/icons'; +import { PageLoading, SettingDrawer } from '@ant-design/pro-layout'; +import { history, Link, RequestConfig } from 'umi'; + import defaultSettings from '../config/defaultSettings'; +import { getCurrentUsingGET } from './services/luigi/user'; +import type { Settings as LayoutSettings } from '@ant-design/pro-layout'; +import type { RunTimeLayoutConfig } from 'umi'; const isDev = process.env.NODE_ENV === 'development'; const loginPath = '/user/login'; @@ -28,7 +28,7 @@ export async function getInitialState(): Promise<{ }> { const fetchUserInfo = async () => { try { - const msg = await queryCurrentUser(); + const msg = await getCurrentUsingGET(); return msg.data; } catch (error) { history.push(loginPath); @@ -106,3 +106,15 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) = ...initialState?.settings, }; }; + +export const request: RequestConfig = { + errorConfig: { + adaptor: (resData) => { + return { + ...resData, + success: resData.code == 1, + errorMessage: resData.message, + }; + }, + }, +}; diff --git a/src/components/AuthorSelect/index.tsx b/src/components/AuthorSelect/index.tsx new file mode 100644 index 0000000..3ce57b3 --- /dev/null +++ b/src/components/AuthorSelect/index.tsx @@ -0,0 +1,28 @@ +import { seekUsingGET } from '@/services/luigi/author'; +import React from 'react'; + +import DebounceSelect from '../DebunceSelect'; + +const AuthorSelect: React.FC<{ + value?: string; + onChange?: (value: string) => void; +}> = (props) => { + return ( + { + if (typeof newValue == 'string') { + props.onChange(JSON.parse(newValue)); + } else { + props.onChange(newValue); + } + }} + style={{ + width: '100%', + }} + /> + ); +}; + +export default AuthorSelect; diff --git a/src/components/DebunceSelect/index.tsx b/src/components/DebunceSelect/index.tsx new file mode 100644 index 0000000..6f29623 --- /dev/null +++ b/src/components/DebunceSelect/index.tsx @@ -0,0 +1,66 @@ +import { Select, Spin } from 'antd'; +import { SelectProps } from 'antd/es/select'; +import debounce from 'lodash/debounce'; +import React from 'react'; +import { useEffect } from '../../.umi/.cache/.mfsu/mf-dep_vendors-node_modules_react_index_js.598bdd42.async'; + +export interface DebounceSelectProps + extends Omit, 'options' | 'children'> { + fetchOptions: (search: string) => Promise; + debounceTimeout?: number; + initOption?: string; +} + +function DebounceSelect< + ValueType extends { key?: string; label: React.ReactNode; value: string | number } = any, +>({ fetchOptions, debounceTimeout = 800, initOption, ...props }: DebounceSelectProps) { + const [fetching, setFetching] = React.useState(false); + const initOptions = []; + let defaultValue = null; + if (initOption && typeof initOption == 'string') { + const option = JSON.parse(initOption); + initOptions.push(option); + defaultValue = option.value; + } + const [options, setOptions] = React.useState(initOptions); + + const fetchRef = React.useRef(0); + + const debounceFetcher = React.useMemo(() => { + const loadOptions = (value: string | number) => { + fetchRef.current += 1; + const fetchId = fetchRef.current; + setOptions([]); + setFetching(true); + + fetchOptions({ query: value }).then((newOptions) => { + if (fetchId !== fetchRef.current) { + // for fetch callback order + return; + } + const list = newOptions.data.list.map((user: { id: number; name: string }) => ({ + label: user.name, + value: user.id, + })); + setOptions(list); + setFetching(false); + }); + }; + return debounce(loadOptions, debounceTimeout); + }, [fetchOptions, debounceTimeout]); + + return ( + + showSearch + labelInValue + filterOption={false} + defaultValue={defaultValue} + onSearch={debounceFetcher} + notFoundContent={fetching ? : null} + {...props} + options={options} + /> + ); +} + +export default DebounceSelect; diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index 4336de9..916cc2f 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -1,16 +1,9 @@ -import { useIntl } from 'umi'; import { GithubOutlined } from '@ant-design/icons'; import { DefaultFooter } from '@ant-design/pro-layout'; const Footer: React.FC = () => { - const intl = useIntl(); - const defaultMessage = intl.formatMessage({ - id: 'app.copyright.produced', - defaultMessage: '蚂蚁集团体验技术部出品', - }); - + const defaultMessage = '蚂蚁集团体验技术部出品'; const currentYear = new Date().getFullYear(); - return ( { @@ -21,6 +20,7 @@ const GlobalHeaderRight: React.FC = () => { if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') { className = `${styles.right} ${styles.dark}`; } + return ( { placeholder="站内搜索" defaultValue="umi ui" options={[ - { label: umi ui, value: 'umi ui' }, + { + label: umi ui, + value: 'umi ui', + }, { label: Ant Design, value: 'Ant Design', @@ -41,8 +44,7 @@ const GlobalHeaderRight: React.FC = () => { label: Pro Layout, value: 'Pro Layout', }, - ]} - // onSearch={value => { + ]} // onSearch={value => { // console.log('input', value); // }} /> @@ -55,8 +57,8 @@ const GlobalHeaderRight: React.FC = () => { - ); }; + export default GlobalHeaderRight; diff --git a/src/global.tsx b/src/global.tsx index 29f47a0..061fd9f 100644 --- a/src/global.tsx +++ b/src/global.tsx @@ -1,7 +1,5 @@ import { Button, message, notification } from 'antd'; -import { useIntl } from 'umi'; import defaultSettings from '../config/defaultSettings'; - const { pwa } = defaultSettings; const isHttps = document.location.protocol === 'https:'; @@ -17,28 +15,29 @@ const clearCache = () => { }) .catch((e) => console.log(e)); } -}; +}; // if pwa is true -// if pwa is true if (pwa) { // Notify user if offline now window.addEventListener('sw.offline', () => { - message.warning(useIntl().formatMessage({ id: 'app.pwa.offline' })); - }); + message.warning('当前处于离线状态'); + }); // Pop up a prompt on the page asking the user if they want to use the latest version - // Pop up a prompt on the page asking the user if they want to use the latest version window.addEventListener('sw.updated', (event: Event) => { const e = event as CustomEvent; + const reloadSW = async () => { // Check if there is sw whose state is waiting in ServiceWorkerRegistration // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration const worker = e.detail && e.detail.waiting; + if (!worker) { return true; - } - // Send skip-waiting event to waiting SW with MessageChannel + } // Send skip-waiting event to waiting SW with MessageChannel + await new Promise((resolve, reject) => { const channel = new MessageChannel(); + channel.port1.onmessage = (msgEvent) => { if (msgEvent.data.error) { reject(msgEvent.data.error); @@ -46,13 +45,19 @@ if (pwa) { resolve(msgEvent.data); } }; - worker.postMessage({ type: 'skip-waiting' }, [channel.port2]); - }); + worker.postMessage( + { + type: 'skip-waiting', + }, + [channel.port2], + ); + }); clearCache(); window.location.reload(); return true; }; + const key = `open${Date.now()}`; const btn = ( ); notification.open({ - message: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated' }), - description: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }), + message: '有新内容', + description: '请点击“刷新”按钮或者手动刷新页面', btn, key, onClose: async () => null, @@ -76,6 +81,7 @@ if (pwa) { } else if ('serviceWorker' in navigator && isHttps) { // unregister service worker const { serviceWorker } = navigator; + if (serviceWorker.getRegistrations) { serviceWorker.getRegistrations().then((sws) => { sws.forEach((sw) => { @@ -83,9 +89,9 @@ if (pwa) { }); }); } + serviceWorker.getRegistration().then((sw) => { if (sw) sw.unregister(); }); - clearCache(); } diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx index d8922fa..9b9676b 100644 --- a/src/pages/Admin.tsx +++ b/src/pages/Admin.tsx @@ -2,23 +2,13 @@ import React from 'react'; import { HeartTwoTone, SmileTwoTone } from '@ant-design/icons'; import { Card, Typography, Alert } from 'antd'; import { PageHeaderWrapper } from '@ant-design/pro-layout'; -import { useIntl } from 'umi'; const Admin: React.FC = () => { - const intl = useIntl(); return ( - + { marginBottom: 48, }} /> - + Ant Design Pro You -

+

Want to add more pages? Please refer to{' '} use block diff --git a/src/pages/PoemDetail/index.tsx b/src/pages/PoemDetail/index.tsx new file mode 100644 index 0000000..306479d --- /dev/null +++ b/src/pages/PoemDetail/index.tsx @@ -0,0 +1,56 @@ +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 ( + { + 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 + > + + + {(form) => { + return ; + }} + + + ); +}; diff --git a/src/pages/PoemPage/index.less b/src/pages/PoemPage/index.less new file mode 100644 index 0000000..7cca51e --- /dev/null +++ b/src/pages/PoemPage/index.less @@ -0,0 +1,6 @@ +@import '~antd/es/style/themes/default.less'; + +.main { + width: 100%; + background: @component-background; +} diff --git a/src/pages/PoemPage/index.tsx b/src/pages/PoemPage/index.tsx new file mode 100644 index 0000000..a0d5dca --- /dev/null +++ b/src/pages/PoemPage/index.tsx @@ -0,0 +1,138 @@ +import AuthorSelect from '@/components/AuthorSelect'; +import { poemListUsingPOST } from '@/services/luigi/poem'; +import { PlusOutlined } from '@ant-design/icons'; +import ProTable from '@ant-design/pro-table'; +import { Button } from 'antd'; +import React, { useRef, useState } from 'react'; + +import type { ProColumns, ActionType } from '@ant-design/pro-table'; +const columns: ProColumns[] = [ + { + dataIndex: 'index', + valueType: 'indexBorder', + width: 48, + }, + { + title: '标题', + dataIndex: 'title', + ellipsis: true, + hideInSearch: true, + tip: '标题过长会自动收缩', + formItemProps: { + rules: [ + { + required: true, + message: '此项为必填项', + }, + ], + }, + }, + { + title: '状态', + dataIndex: 'status', + valueType: 'select', + valueEnum: { + 0: { + text: '未校准', + status: 'Error', + }, + 1: { + text: '已校准', + status: 'Success', + }, + }, + }, + { + title: '作者', + dataIndex: 'authorName', + hideInSearch: true, + }, + { + title: '作者', + dataIndex: 'author', + hideInTable: true, + formItemProps: { + rules: [ + { + required: true, + message: '此项为必填项', + }, + ], + }, + renderFormItem: (item, { type, defaultRender, ...rest }, form) => { + return ; + }, + }, + { + title: '首行', + dataIndex: 'line', + hideInSearch: true, + }, +]; + +export default () => { + const actionRef = useRef(); + + return ( + + columns={columns} + actionRef={actionRef} + cardBordered + request={async (params = {}, sort, filter) => { + const query: API.QueryParam[] = []; + if (params.author) { + let author = params.author; + if (typeof params.author == 'string') { + author = JSON.parse(params.author); + } + query.push({ key: 'authorId', val: author.value }); + } + if (params.status) { + query.push({ key: 'status', val: params.status }); + } + const response = await poemListUsingPOST({ + current: params.current, + pageSize: params.pageSize, + query: query, + }); + return { data: response.data?.list, total: response.data?.total }; + }} + editable={{ + type: 'multiple', + }} + columnsState={{ + persistenceKey: 'pro-table-singe-demos', + persistenceType: 'localStorage', + onChange(value) { + console.log('value: ', value); + }, + }} + rowKey="id" + search={{ + labelWidth: 'auto', + }} + form={{ + // 由于配置了 transform,提交的参与与定义的不同这里需要转化一下 + syncToUrl: (values, type) => { + if (type === 'get') { + return { + ...values, + created_at: [values.startTime, values.endTime], + }; + } + return values; + }, + }} + pagination={{ + pageSize: 5, + }} + dateFormatter="string" + headerTitle="高级表格" + toolBarRender={() => [ + , + ]} + /> + ); +}; diff --git a/src/pages/TableList/components/UpdateForm.tsx b/src/pages/TableList/components/UpdateForm.tsx index 058a1df..defa912 100644 --- a/src/pages/TableList/components/UpdateForm.tsx +++ b/src/pages/TableList/components/UpdateForm.tsx @@ -8,8 +8,6 @@ import { ProFormRadio, ProFormDateTimePicker, } from '@ant-design/pro-form'; -import { useIntl, FormattedMessage } from 'umi'; - export type FormValueType = { target?: string; template?: string; @@ -17,7 +15,6 @@ export type FormValueType = { time?: string; frequency?: string; } & Partial; - export type UpdateFormProps = { onCancel: (flag?: boolean, formVals?: FormValueType) => void; onSubmit: (values: FormValueType) => Promise; @@ -26,7 +23,6 @@ export type UpdateFormProps = { }; const UpdateForm: React.FC = (props) => { - const intl = useIntl(); return ( = (props) => { return ( { @@ -59,50 +54,28 @@ const UpdateForm: React.FC = (props) => { name: props.values.name, desc: props.values.desc, }} - title={intl.formatMessage({ - id: 'pages.searchTable.updateForm.basicConfig', - defaultMessage: '基本信息', - })} + title={'基本信息'} > - ), + message: '请输入规则名称!', }, ]} /> - ), + message: '请输入至少五个字符的规则描述!', min: 5, }, ]} @@ -113,18 +86,12 @@ const UpdateForm: React.FC = (props) => { target: '0', template: '0', }} - title={intl.formatMessage({ - id: 'pages.searchTable.updateForm.ruleProps.title', - defaultMessage: '配置规则属性', - })} + title={'配置规则属性'} > = (props) => { = (props) => { /> = (props) => { type: '1', frequency: 'month', }} - title={intl.formatMessage({ - id: 'pages.searchTable.updateForm.schedulingPeriod.title', - defaultMessage: '设定调度周期', - })} + title={'设定调度周期'} > - ), + message: '请选择开始时间!', }, ]} /> { const hide = message.loading('正在添加'); + try { await addRule({ ...fields }); hide(); @@ -30,15 +30,16 @@ const handleAdd = async (fields: API.RuleListItem) => { return false; } }; - /** * @en-US Update node * @zh-CN 更新节点 * * @param fields */ + const handleUpdate = async (fields: FormValueType) => { const hide = message.loading('Configuring'); + try { await updateRule({ name: fields.name, @@ -46,7 +47,6 @@ const handleUpdate = async (fields: FormValueType) => { key: fields.key, }); hide(); - message.success('Configuration is successful'); return true; } catch (error) { @@ -55,16 +55,17 @@ const handleUpdate = async (fields: FormValueType) => { return false; } }; - /** * Delete node * @zh-CN 删除节点 * * @param selectedRows */ + const handleRemove = async (selectedRows: API.RuleListItem[]) => { const hide = message.loading('正在删除'); if (!selectedRows) return true; + try { await removeRule({ key: selectedRows.map((row) => row.key), @@ -89,28 +90,20 @@ const TableList: React.FC = () => { * @en-US The pop-up window of the distribution update window * @zh-CN 分布更新窗口的弹窗 * */ - const [updateModalVisible, handleUpdateModalVisible] = useState(false); + const [updateModalVisible, handleUpdateModalVisible] = useState(false); const [showDetail, setShowDetail] = useState(false); - const actionRef = useRef(); const [currentRow, setCurrentRow] = useState(); const [selectedRowsState, setSelectedRows] = useState([]); - /** * @en-US International configuration * @zh-CN 国际化配置 * */ - const intl = useIntl(); const columns: ProColumns[] = [ { - title: ( - - ), + title: '规则名称', dataIndex: 'name', tip: 'The rule name is the unique key', render: (dom, entity) => { @@ -127,94 +120,61 @@ const TableList: React.FC = () => { }, }, { - title: , + title: '描述', dataIndex: 'desc', valueType: 'textarea', }, { - title: ( - - ), + title: '服务调用次数', dataIndex: 'callNo', sorter: true, hideInForm: true, - renderText: (val: string) => - `${val}${intl.formatMessage({ - id: 'pages.searchTable.tenThousand', - defaultMessage: ' 万 ', - })}`, + renderText: (val: string) => `${val}${'万'}`, }, { - title: , + title: '状态', dataIndex: 'status', hideInForm: true, valueEnum: { 0: { - text: ( - - ), + text: '关闭', status: 'Default', }, 1: { - text: ( - - ), + text: '运行中', status: 'Processing', }, 2: { - text: ( - - ), + text: '已上线', status: 'Success', }, 3: { - text: ( - - ), + text: '异常', status: 'Error', }, }, }, { - title: ( - - ), + title: '上次调度时间', sorter: true, dataIndex: 'updatedAt', valueType: 'dateTime', renderFormItem: (item, { defaultRender, ...rest }, form) => { const status = form.getFieldValue('status'); + if (`${status}` === '0') { return false; } + if (`${status}` === '3') { - return ( - - ); + return ; } + return defaultRender(item); }, }, { - title: , + title: '操作', dataIndex: 'option', valueType: 'option', render: (_, record) => [ @@ -225,25 +185,18 @@ const TableList: React.FC = () => { setCurrentRow(record); }} > - + 配置 , - + 订阅警报 , ], }, ]; - return ( - headerTitle={intl.formatMessage({ - id: 'pages.searchTable.title', - defaultMessage: 'Enquiry form', - })} + headerTitle={'查询表格'} actionRef={actionRef} rowKey="key" search={{ @@ -257,7 +210,7 @@ const TableList: React.FC = () => { handleModalVisible(true); }} > - + 新建 , ]} request={rule} @@ -272,17 +225,17 @@ const TableList: React.FC = () => { - {' '} - {selectedRowsState.length}{' '} - -    + 已选择{' '} + + {selectedRowsState.length} + {' '} + 项    - {' '} - {selectedRowsState.reduce((pre, item) => pre + item.callNo!, 0)}{' '} - + 服务调用次数总计 {selectedRowsState.reduce((pre, item) => pre + item.callNo!, 0)} 万 } @@ -294,31 +247,22 @@ const TableList: React.FC = () => { actionRef.current?.reloadAndRest?.(); }} > - - - + )} { const success = await handleAdd(value as API.RuleListItem); + if (success) { handleModalVisible(false); + if (actionRef.current) { actionRef.current.reload(); } @@ -329,12 +273,7 @@ const TableList: React.FC = () => { rules={[ { required: true, - message: ( - - ), + message: '规则名称为必填项', }, ]} width="md" @@ -345,9 +284,11 @@ const TableList: React.FC = () => { { const success = await handleUpdate(value); + if (success) { handleUpdateModalVisible(false); setCurrentRow(undefined); + if (actionRef.current) { actionRef.current.reload(); } @@ -355,6 +296,7 @@ const TableList: React.FC = () => { }} onCancel={() => { handleUpdateModalVisible(false); + if (!showDetail) { setCurrentRow(undefined); } diff --git a/src/pages/Welcome.tsx b/src/pages/Welcome.tsx index 9041b18..ce2e8d5 100644 --- a/src/pages/Welcome.tsx +++ b/src/pages/Welcome.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { PageContainer } from '@ant-design/pro-layout'; import { Card, Alert, Typography } from 'antd'; -import { useIntl, FormattedMessage } from 'umi'; import styles from './Welcome.less'; const CodePreview: React.FC = ({ children }) => ( @@ -13,16 +12,11 @@ const CodePreview: React.FC = ({ children }) => ( ); const Welcome: React.FC = () => { - const intl = useIntl(); - return ( { }} /> - {' '} + 高级表格{' '} - + 欢迎使用 yarn add @ant-design/pro-table @@ -48,13 +42,13 @@ const Welcome: React.FC = () => { marginBottom: 12, }} > - {' '} + 高级布局{' '} - + 欢迎使用 yarn add @ant-design/pro-layout diff --git a/src/pages/user/Login/index.tsx b/src/pages/user/Login/index.tsx index 7d0fe35..558138d 100644 --- a/src/pages/user/Login/index.tsx +++ b/src/pages/user/Login/index.tsx @@ -9,11 +9,10 @@ import { import { Alert, message, Tabs } from 'antd'; import React, { useState } from 'react'; import { ProFormCaptcha, ProFormCheckbox, ProFormText, LoginForm } from '@ant-design/pro-form'; -import { useIntl, history, FormattedMessage, SelectLang, useModel } from 'umi'; +import { history, useModel } from 'umi'; import Footer from '@/components/Footer'; import { login } from '@/services/ant-design-pro/api'; import { getFakeCaptcha } from '@/services/ant-design-pro/login'; - import styles from './index.less'; const LoginMessage: React.FC<{ @@ -34,15 +33,11 @@ const Login: React.FC = () => { const [type, setType] = useState('account'); const { initialState, setInitialState } = useModel('@@initialState'); - const intl = useIntl(); - const fetchUserInfo = async () => { const userInfo = await initialState?.fetchUserInfo?.(); + if (userInfo) { - await setInitialState((s) => ({ - ...s, - currentUser: userInfo, - })); + await setInitialState((s) => ({ ...s, currentUser: userInfo })); } }; @@ -50,52 +45,44 @@ const Login: React.FC = () => { try { // 登录 const msg = await login({ ...values, type }); + if (msg.status === 'ok') { - const defaultLoginSuccessMessage = intl.formatMessage({ - id: 'pages.login.success', - defaultMessage: '登录成功!', - }); + const defaultLoginSuccessMessage = '登录成功!'; message.success(defaultLoginSuccessMessage); await fetchUserInfo(); /** 此方法会跳转到 redirect 参数所在的位置 */ + if (!history) return; const { query } = history.location; - const { redirect } = query as { redirect: string }; + const { redirect } = query as { + redirect: string; + }; history.push(redirect || '/'); return; } - console.log(msg); - // 如果失败去设置用户错误信息 + + console.log(msg); // 如果失败去设置用户错误信息 + setUserLoginState(msg); } catch (error) { - const defaultLoginFailureMessage = intl.formatMessage({ - id: 'pages.login.failure', - defaultMessage: '登录失败,请重试!', - }); + const defaultLoginFailureMessage = '登录失败,请重试!'; message.error(defaultLoginFailureMessage); } }; - const { status, type: loginType } = userLoginState; + const { status, type: loginType } = userLoginState; return (

-
- {SelectLang && } -
} title="Ant Design" - subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })} + subTitle={'Ant Design 是西湖区最具影响力的 Web 设计规范'} initialValues={{ autoLogin: true, }} actions={[ - , + '其他登录方式 :', , , , @@ -105,29 +92,12 @@ const Login: React.FC = () => { }} > - - + + {status === 'error' && loginType === 'account' && ( - + )} {type === 'account' && ( <> @@ -137,19 +107,11 @@ const Login: React.FC = () => { size: 'large', prefix: , }} - placeholder={intl.formatMessage({ - id: 'pages.login.username.placeholder', - defaultMessage: '用户名: admin or user', - })} + placeholder={'用户名: admin or user'} rules={[ { required: true, - message: ( - - ), + message: '用户名是必填项!', }, ]} /> @@ -159,19 +121,11 @@ const Login: React.FC = () => { size: 'large', prefix: , }} - placeholder={intl.formatMessage({ - id: 'pages.login.password.placeholder', - defaultMessage: '密码: ant.design', - })} + placeholder={'密码: ant.design'} rules={[ { required: true, - message: ( - - ), + message: '密码是必填项!', }, ]} /> @@ -187,28 +141,15 @@ const Login: React.FC = () => { prefix: , }} name="mobile" - placeholder={intl.formatMessage({ - id: 'pages.login.phoneNumber.placeholder', - defaultMessage: '手机号', - })} + placeholder={'请输入手机号!'} rules={[ { required: true, - message: ( - - ), + message: '手机号是必填项!', }, { pattern: /^1\d{10}$/, - message: ( - - ), + message: '不合法的手机号!', }, ]} /> @@ -220,41 +161,30 @@ const Login: React.FC = () => { captchaProps={{ size: 'large', }} - placeholder={intl.formatMessage({ - id: 'pages.login.captcha.placeholder', - defaultMessage: '请输入验证码', - })} + placeholder={'请输入验证码!'} captchaTextRender={(timing, count) => { if (timing) { - return `${count} ${intl.formatMessage({ - id: 'pages.getCaptchaSecondText', - defaultMessage: '获取验证码', - })}`; + return `${count} ${'秒后重新获取'}`; } - return intl.formatMessage({ - id: 'pages.login.phoneLogin.getVerificationCode', - defaultMessage: '获取验证码', - }); + + return '获取验证码'; }} name="captcha" rules={[ { required: true, - message: ( - - ), + message: '验证码是必填项!', }, ]} onGetCaptcha={async (phone) => { const result = await getFakeCaptcha({ phone, }); + if (result === false) { return; } + message.success('获取验证码成功!验证码为:1234'); }} /> @@ -266,14 +196,14 @@ const Login: React.FC = () => { }} > - + 自动登录 - + 忘记密码 ?
diff --git a/src/services/ant-design-pro/api.ts b/src/services/ant-design-pro/api.ts index 74fce0c..06e33d2 100644 --- a/src/services/ant-design-pro/api.ts +++ b/src/services/ant-design-pro/api.ts @@ -4,34 +4,12 @@ import { request } from 'umi'; /** 获取当前的用户 GET /api/currentUser */ export async function currentUser(options?: { [key: string]: any }) { - return request<{ - data: API.CurrentUser; - }>('/api/currentUser', { + return request('/api/currentUser', { method: 'GET', ...(options || {}), }); } -/** 退出登录接口 POST /api/login/outLogin */ -export async function outLogin(options?: { [key: string]: any }) { - return request>('/api/login/outLogin', { - method: 'POST', - ...(options || {}), - }); -} - -/** 登录接口 POST /api/login/account */ -export async function login(body: API.LoginParams, options?: { [key: string]: any }) { - return request('/api/login/account', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - data: body, - ...(options || {}), - }); -} - /** 此处后端没有提供注释 GET /api/notices */ export async function getNotices(options?: { [key: string]: any }) { return request('/api/notices', { @@ -39,47 +17,3 @@ export async function getNotices(options?: { [key: string]: any }) { ...(options || {}), }); } - -/** 获取规则列表 GET /api/rule */ -export async function rule( - params: { - // query - /** 当前的页码 */ - current?: number; - /** 页面的容量 */ - pageSize?: number; - }, - options?: { [key: string]: any }, -) { - return request('/api/rule', { - method: 'GET', - params: { - ...params, - }, - ...(options || {}), - }); -} - -/** 新建规则 PUT /api/rule */ -export async function updateRule(options?: { [key: string]: any }) { - return request('/api/rule', { - method: 'PUT', - ...(options || {}), - }); -} - -/** 新建规则 POST /api/rule */ -export async function addRule(options?: { [key: string]: any }) { - return request('/api/rule', { - method: 'POST', - ...(options || {}), - }); -} - -/** 删除规则 DELETE /api/rule */ -export async function removeRule(options?: { [key: string]: any }) { - return request>('/api/rule', { - method: 'DELETE', - ...(options || {}), - }); -} diff --git a/src/services/ant-design-pro/index.ts b/src/services/ant-design-pro/index.ts index 1ac489f..9ae58be 100644 --- a/src/services/ant-design-pro/index.ts +++ b/src/services/ant-design-pro/index.ts @@ -4,7 +4,9 @@ // API 唯一标识: import * as api from './api'; import * as login from './login'; +import * as rule from './rule'; export default { api, login, + rule, }; diff --git a/src/services/ant-design-pro/login.ts b/src/services/ant-design-pro/login.ts index 42f95ff..ae15060 100644 --- a/src/services/ant-design-pro/login.ts +++ b/src/services/ant-design-pro/login.ts @@ -4,18 +4,35 @@ import { request } from 'umi'; /** 发送验证码 POST /api/login/captcha */ export async function getFakeCaptcha( - params: { - // query - /** 手机号 */ - phone?: string; - }, + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.getFakeCaptchaParams, options?: { [key: string]: any }, ) { return request('/api/login/captcha', { - method: 'GET', + method: 'POST', params: { ...params, }, ...(options || {}), }); } + +/** 登录接口 POST /api/login/outLogin */ +export async function outLogin(options?: { [key: string]: any }) { + return request>('/api/login/outLogin', { + method: 'POST', + ...(options || {}), + }); +} + +/** 登录接口 POST /api/login/account */ +export async function login(body: API.LoginParams, options?: { [key: string]: any }) { + return request('/api/login/account', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} diff --git a/src/services/ant-design-pro/rule.ts b/src/services/ant-design-pro/rule.ts new file mode 100644 index 0000000..d0405b7 --- /dev/null +++ b/src/services/ant-design-pro/rule.ts @@ -0,0 +1,42 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** 获取规则列表 GET /api/rule */ +export async function rule( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.ruleParams, + options?: { [key: string]: any }, +) { + return request('/api/rule', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** 新建规则 PUT /api/rule */ +export async function updateRule(options?: { [key: string]: any }) { + return request('/api/rule', { + method: 'PUT', + ...(options || {}), + }); +} + +/** 新建规则 POST /api/rule */ +export async function addRule(options?: { [key: string]: any }) { + return request('/api/rule', { + method: 'POST', + ...(options || {}), + }); +} + +/** 删除规则 DELETE /api/rule */ +export async function removeRule(options?: { [key: string]: any }) { + return request>('/api/rule', { + method: 'DELETE', + ...(options || {}), + }); +} diff --git a/src/services/ant-design-pro/typings.d.ts b/src/services/ant-design-pro/typings.d.ts index 13e5a68..cd8ab46 100644 --- a/src/services/ant-design-pro/typings.d.ts +++ b/src/services/ant-design-pro/typings.d.ts @@ -1,6 +1,3 @@ -// @ts-ignore -/* eslint-disable */ - declare namespace API { type CurrentUser = { name?: string; @@ -98,4 +95,16 @@ declare namespace API { description?: string; type?: NoticeIconItemType; }; + + type getFakeCaptchaParams = { + /** 手机号 */ + phone?: string; + }; + + type ruleParams = { + /** 当前的页码 */ + current?: number; + /** 页面的容量 */ + pageSize?: number; + }; } diff --git a/src/services/luigi/author.ts b/src/services/luigi/author.ts new file mode 100644 index 0000000..18baeb1 --- /dev/null +++ b/src/services/luigi/author.ts @@ -0,0 +1,18 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** seek GET /api/luigi/author/seek */ +export async function seekUsingGET( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.seekUsingGETParams, + options?: { [key: string]: any }, +) { + return request('/api/luigi/author/seek', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} diff --git a/src/services/luigi/index.ts b/src/services/luigi/index.ts new file mode 100644 index 0000000..5f21cfb --- /dev/null +++ b/src/services/luigi/index.ts @@ -0,0 +1,12 @@ +// @ts-ignore +/* eslint-disable */ +// API 更新时间: +// API 唯一标识: +import * as author from './author'; +import * as poem from './poem'; +import * as user from './user'; +export default { + author, + poem, + user, +}; diff --git a/src/services/luigi/poem.ts b/src/services/luigi/poem.ts new file mode 100644 index 0000000..b762126 --- /dev/null +++ b/src/services/luigi/poem.ts @@ -0,0 +1,30 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** poemDetail GET /api/luigi/poem/detail */ +export async function poemDetailUsingGET( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.poemDetailUsingGETParams, + options?: { [key: string]: any }, +) { + return request('/api/luigi/poem/detail', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** poemList POST /api/luigi/poem/list */ +export async function poemListUsingPOST(body: API.PoemQuery, options?: { [key: string]: any }) { + return request('/api/luigi/poem/list', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} diff --git a/src/services/luigi/typings.d.ts b/src/services/luigi/typings.d.ts new file mode 100644 index 0000000..3555ea3 --- /dev/null +++ b/src/services/luigi/typings.d.ts @@ -0,0 +1,88 @@ +declare namespace API { + type Author = { + dynasty?: string; + id?: number; + introduction?: string; + name?: string; + poemCnt?: number; + status?: number; + }; + + type CommonListAuthor = { + current?: number; + list?: Author[]; + pageSize?: number; + total?: number; + }; + + type CommonListPoemBo = { + current?: number; + list?: PoemBo[]; + pageSize?: number; + total?: number; + }; + + type PoemBo = { + authorId?: number; + authorName?: string; + content?: string; + id?: number; + line?: string; + note?: string; + status?: number; + title?: string; + translation?: string; + }; + + type PoemQuery = { + current?: number; + pageSize?: number; + query?: QueryParam[]; + }; + + type QueryParam = { + key?: string; + val?: string; + }; + + type ResponseCommonListAuthor = { + code?: number; + data?: CommonListAuthor; + message?: string; + }; + + type ResponseCommonListPoemBo = { + code?: number; + data?: CommonListPoemBo; + message?: string; + }; + + type ResponsePoemBo = { + code?: number; + data?: PoemBo; + message?: string; + }; + + type ResponseUserBo = { + code?: number; + data?: UserBo; + message?: string; + }; + + type UserBo = { + avatar?: string; + id?: number; + name?: string; + role?: string; + }; + + type seekUsingGETParams = { + /** name */ + name: string; + }; + + type poemDetailUsingGETParams = { + /** id */ + id: number; + }; +} diff --git a/src/services/luigi/user.ts b/src/services/luigi/user.ts new file mode 100644 index 0000000..99f3c4d --- /dev/null +++ b/src/services/luigi/user.ts @@ -0,0 +1,11 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from 'umi'; + +/** getCurrent GET /api/luigi/user/current */ +export async function getCurrentUsingGET(options?: { [key: string]: any }) { + return request('/api/luigi/user/current', { + method: 'GET', + ...(options || {}), + }); +}