├── src ├── pages │ ├── Activate │ │ ├── index.less │ │ └── index.tsx │ ├── Task │ │ ├── List │ │ │ ├── index.less │ │ │ └── index.tsx │ │ └── components │ │ │ └── TaskContent.tsx │ ├── AccountList │ │ ├── index.less │ │ ├── components │ │ │ ├── button │ │ │ │ ├── DelButton.tsx │ │ │ │ └── SyncButton.tsx │ │ │ └── contents │ │ │ │ ├── UpdateContent.tsx │ │ │ │ ├── AddContent.tsx │ │ │ │ ├── ReconnectContent.tsx │ │ │ │ └── MoreContent.tsx │ │ └── index.tsx │ ├── Draw │ │ └── index.less │ ├── Probe │ │ ├── index.less │ │ └── index.tsx │ ├── 404.tsx │ ├── components │ │ └── Modal.tsx │ ├── Welcome.tsx │ ├── User │ │ └── Login │ │ │ └── index.tsx │ └── Setting │ │ └── index.tsx ├── services │ ├── mj │ │ ├── index.ts │ │ ├── typings.d.ts │ │ └── api.ts │ └── swagger │ │ ├── index.ts │ │ ├── store.ts │ │ ├── typings.d.ts │ │ ├── user.ts │ │ └── pet.ts ├── locales │ ├── zh-CN │ │ ├── component.ts │ │ ├── pwa.ts │ │ ├── globalHeader.ts │ │ ├── settingDrawer.ts │ │ ├── menu.ts │ │ ├── settings.ts │ │ └── pages.ts │ ├── en-US │ │ ├── component.ts │ │ ├── pwa.ts │ │ ├── globalHeader.ts │ │ ├── settingDrawer.ts │ │ ├── menu.ts │ │ ├── settings.ts │ │ └── pages.ts │ ├── zh-CN.ts │ └── en-US.ts ├── access.ts ├── manifest.json ├── typings.d.ts ├── components │ ├── RightContent │ │ ├── index.tsx │ │ └── AvatarDropdown.tsx │ ├── HeaderDropdown │ │ └── index.tsx │ ├── Footer │ │ └── index.tsx │ └── JsonEditor │ │ └── index.tsx ├── global.less ├── service-worker.js ├── global.tsx ├── requestErrorConfig.ts └── app.tsx ├── types └── cache │ ├── cache.json │ └── mock │ └── mock.cache.js ├── public ├── CNAME ├── logo.png ├── niji.webp ├── favicon.ico ├── insightface.webp ├── midjourney.webp └── scripts │ └── loading.js ├── .env ├── .eslintignore ├── .eslintrc.js ├── jsconfig.json ├── .editorconfig ├── .prettierignore ├── .prettierrc.js ├── jest.config.ts ├── .gitignore ├── tsconfig.json ├── config ├── defaultSettings.ts ├── proxy.ts ├── oneapi.json ├── routes.ts └── config.ts ├── README.md ├── tests └── setupTests.jsx ├── package.json └── LICENSE /src/pages/Activate/index.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /types/cache/cache.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /types/cache/mock/mock.cache.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/CNAME: -------------------------------------------------------------------------------- 1 | preview.pro.ant.design -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # MJ-SERVER 2 | MJ_SERVER=http://127.0.0.1:8080 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /lambda/ 2 | /scripts 3 | /config 4 | .history 5 | public 6 | dist 7 | .umi 8 | mock -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litter-coder/midjourney-proxy-admin/HEAD/public/logo.png -------------------------------------------------------------------------------- /public/niji.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litter-coder/midjourney-proxy-admin/HEAD/public/niji.webp -------------------------------------------------------------------------------- /src/pages/Task/List/index.less: -------------------------------------------------------------------------------- 1 | .tableToolbar{ 2 | text-align: right; 3 | padding: 15px 0; 4 | } 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litter-coder/midjourney-proxy-admin/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/pages/AccountList/index.less: -------------------------------------------------------------------------------- 1 | .tableToolbar{ 2 | text-align: right; 3 | padding: 15px 0; 4 | } 5 | -------------------------------------------------------------------------------- /public/insightface.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litter-coder/midjourney-proxy-admin/HEAD/public/insightface.webp -------------------------------------------------------------------------------- /public/midjourney.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/litter-coder/midjourney-proxy-admin/HEAD/public/midjourney.webp -------------------------------------------------------------------------------- /src/services/mj/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | /* eslint-disable */ 3 | // API 更新时间: 4 | // API 唯一标识: 5 | import * as api from './api'; 6 | export default { 7 | api, 8 | }; 9 | -------------------------------------------------------------------------------- /src/locales/zh-CN/component.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.tagSelect.expand': '展开', 3 | 'component.tagSelect.collapse': '收起', 4 | 'component.tagSelect.all': '全部', 5 | }; 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('@umijs/lint/dist/config/eslint')], 3 | globals: { 4 | page: true, 5 | REACT_APP_ENV: true, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/locales/en-US/component.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.tagSelect.expand': 'Expand', 3 | 'component.tagSelect.collapse': 'Collapse', 4 | 'component.tagSelect.all': 'All', 5 | }; 6 | -------------------------------------------------------------------------------- /src/pages/Draw/index.less: -------------------------------------------------------------------------------- 1 | .cardTitleTime { 2 | font-size: 13px; 3 | font-weight: normal; 4 | margin-left: 10px; 5 | color: gray; 6 | } 7 | 8 | .taskErrorTip { 9 | color: red; 10 | font-size: 15px; 11 | } 12 | -------------------------------------------------------------------------------- /src/locales/zh-CN/pwa.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.pwa.offline': '当前处于离线状态', 3 | 'app.pwa.serviceworker.updated': '有新内容', 4 | 'app.pwa.serviceworker.updated.hint': '请点击“刷新”按钮或者手动刷新页面', 5 | 'app.pwa.serviceworker.updated.ok': '刷新', 6 | }; 7 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "baseUrl": ".", 7 | "paths": { 8 | "@/*": ["./src/*"] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/services/swagger/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | /* eslint-disable */ 3 | // API 更新时间: 4 | // API 唯一标识: 5 | import * as pet from './pet'; 6 | import * as store from './store'; 7 | import * as user from './user'; 8 | export default { 9 | pet, 10 | store, 11 | user, 12 | }; 13 | -------------------------------------------------------------------------------- /src/locales/en-US/pwa.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.pwa.offline': 'You are offline now', 3 | 'app.pwa.serviceworker.updated': 'New content is available', 4 | 'app.pwa.serviceworker.updated.hint': 'Please press the "Refresh" button to reload current page', 5 | 'app.pwa.serviceworker.updated.ok': 'Refresh', 6 | }; 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /src/access.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://umijs.org/zh-CN/plugins/plugin-access 3 | * */ 4 | export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) { 5 | const { currentUser } = initialState ?? {}; 6 | return { 7 | canAdmin: currentUser && currentUser.access === 'admin', 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.svg 2 | .umi 3 | .umi-production 4 | /dist 5 | .dockerignore 6 | .DS_Store 7 | .eslintignore 8 | *.png 9 | *.toml 10 | docker 11 | .editorconfig 12 | Dockerfile* 13 | .gitignore 14 | .prettierignore 15 | LICENSE 16 | .eslintcache 17 | *.lock 18 | yarn-error.log 19 | .history 20 | CNAME 21 | /build 22 | /public 23 | -------------------------------------------------------------------------------- /src/pages/Probe/index.less: -------------------------------------------------------------------------------- 1 | // index.less 2 | .logCard { 3 | border-radius: 4px; // 设置边框圆角 4 | padding: 16px; // 设置内边距 5 | height: 75vh; // 设置卡片高度 6 | overflow-y: auto; // 设置垂直滚动 7 | } 8 | 9 | .logContent { 10 | white-space: pre-wrap; // 保留空白符和换行符 11 | font-family: monospace; // 设置字体为等宽字体 12 | font-size: 14px; // 设置字体大小 13 | color: #333; // 设置字体颜色 14 | } 15 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: true, 3 | trailingComma: 'all', 4 | printWidth: 100, 5 | proseWrap: 'never', 6 | endOfLine: 'lf', 7 | overrides: [ 8 | { 9 | files: '.prettierrc', 10 | options: { 11 | parser: 'json', 12 | }, 13 | }, 14 | { 15 | files: 'document.ejs', 16 | options: { 17 | parser: 'html', 18 | }, 19 | }, 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { history } from '@umijs/max'; 2 | import { Button, Result } from 'antd'; 3 | import React from 'react'; 4 | 5 | const NoFoundPage: React.FC = () => ( 6 | history.push('/')}> 12 | Back Home 13 | 14 | } 15 | /> 16 | ); 17 | 18 | export default NoFoundPage; 19 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ant Design Pro", 3 | "short_name": "Ant Design Pro", 4 | "display": "standalone", 5 | "start_url": "./?utm_source=homescreen", 6 | "theme_color": "#002140", 7 | "background_color": "#001529", 8 | "icons": [ 9 | { 10 | "src": "icons/icon-192x192.png", 11 | "sizes": "192x192" 12 | }, 13 | { 14 | "src": "icons/icon-128x128.png", 15 | "sizes": "128x128" 16 | }, 17 | { 18 | "src": "icons/icon-512x512.png", 19 | "sizes": "512x512" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { configUmiAlias, createConfig } from '@umijs/max/test'; 2 | 3 | export default async () => { 4 | const config = await configUmiAlias({ 5 | ...createConfig({ 6 | target: 'browser', 7 | }), 8 | }); 9 | 10 | console.log(); 11 | return { 12 | ...config, 13 | testEnvironmentOptions: { 14 | ...(config?.testEnvironmentOptions || {}), 15 | url: 'http://localhost:8000', 16 | }, 17 | setupFiles: [...(config.setupFiles || []), './tests/setupTests.jsx'], 18 | globals: { 19 | ...config.globals, 20 | localStorage: null, 21 | }, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'slash2'; 2 | declare module '*.css'; 3 | declare module '*.less'; 4 | declare module '*.scss'; 5 | declare module '*.sass'; 6 | declare module '*.svg'; 7 | declare module '*.png'; 8 | declare module '*.jpg'; 9 | declare module '*.jpeg'; 10 | declare module '*.gif'; 11 | declare module '*.bmp'; 12 | declare module '*.tiff'; 13 | declare module 'omit.js'; 14 | declare module 'numeral'; 15 | declare module '@antv/data-set'; 16 | declare module 'mockjs'; 17 | declare module 'react-fittext'; 18 | declare module 'bizcharts-plugin-slider'; 19 | 20 | declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | false; 21 | -------------------------------------------------------------------------------- /src/pages/components/Modal.tsx: -------------------------------------------------------------------------------- 1 | import { Modal } from 'antd'; 2 | 3 | const MyModal = ({ 4 | title, 5 | modalVisible, 6 | hideModal, 7 | modalContent, 8 | footer, 9 | modalWidth, 10 | }: { 11 | title: string; 12 | modalVisible: boolean; 13 | hideModal: () => void; 14 | modalContent: any; 15 | footer: any; 16 | modalWidth: number; 17 | }) => { 18 | return ( 19 | 26 | {modalContent} 27 | 28 | ); 29 | }; 30 | 31 | export default MyModal; 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | **/node_modules 5 | # roadhog-api-doc ignore 6 | /src/utils/request-temp.js 7 | _roadhog-api-doc 8 | 9 | # production 10 | /dist 11 | 12 | # misc 13 | .DS_Store 14 | npm-debug.log* 15 | yarn-error.log 16 | 17 | /coverage 18 | .idea 19 | yarn.lock 20 | package-lock.json 21 | *bak 22 | .vscode 23 | 24 | 25 | # visual studio code 26 | .history 27 | *.log 28 | functions/* 29 | .temp/** 30 | 31 | # umi 32 | .umi 33 | .umi-production 34 | .umi-test 35 | 36 | # screenshot 37 | screenshot 38 | .firebase 39 | .eslintcache 40 | 41 | build 42 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "importHelpers": true, 7 | "jsx": "preserve", 8 | "esModuleInterop": true, 9 | "sourceMap": true, 10 | "baseUrl": "./", 11 | "skipLibCheck": true, 12 | "experimentalDecorators": true, 13 | "strict": true, 14 | "resolveJsonModule": true, 15 | "allowSyntheticDefaultImports": true, 16 | "paths": { 17 | "@/*": ["./src/*"], 18 | "@@/*": ["./src/.umi/*"], 19 | "@@test/*": ["./src/.umi-test/*"] 20 | } 21 | }, 22 | "include": ["./**/*.d.ts", "./**/*.ts", "./**/*.tsx"] 23 | } 24 | -------------------------------------------------------------------------------- /config/defaultSettings.ts: -------------------------------------------------------------------------------- 1 | import { ProLayoutProps } from '@ant-design/pro-components'; 2 | 3 | /** 4 | * @name 5 | */ 6 | const Settings: ProLayoutProps & { 7 | pwa?: boolean; 8 | logo?: string; 9 | } = { 10 | navTheme: 'light', 11 | // 拂晓蓝 12 | colorPrimary: '#1890ff', 13 | layout: 'mix', 14 | contentWidth: 'Fluid', 15 | fixedHeader: false, 16 | fixSiderbar: true, 17 | colorWeak: false, 18 | title: 'Midjourney Proxy Admin', 19 | pwa: true, 20 | logo: './logo.svg', 21 | iconfontUrl: '', 22 | token: { 23 | // 参见ts声明,demo 见文档,通过token 修改样式 24 | //https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F 25 | }, 26 | }; 27 | 28 | export default Settings; 29 | -------------------------------------------------------------------------------- /src/components/RightContent/index.tsx: -------------------------------------------------------------------------------- 1 | import { QuestionCircleOutlined } from '@ant-design/icons'; 2 | import { SelectLang as UmiSelectLang } from '@umijs/max'; 3 | import React from 'react'; 4 | 5 | export type SiderTheme = 'light' | 'dark'; 6 | 7 | export const SelectLang = () => { 8 | return ( 9 | 14 | ); 15 | }; 16 | 17 | export const Question = () => { 18 | return ( 19 |
{ 25 | window.open('https://pro.ant.design/docs/getting-started'); 26 | }} 27 | > 28 | 29 |
30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /config/proxy.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 代理的配置 3 | * @see 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 4 | * ------------------------------- 5 | * The agent cannot take effect in the production environment 6 | * so there is no configuration of the production environment 7 | * For details, please see 8 | * https://pro.ant.design/docs/deploy 9 | * 10 | * @doc https://umijs.org/docs/guides/proxy 11 | */ 12 | 13 | const MJ_SERVER = process.env.MJ_SERVER; 14 | 15 | export default { 16 | // 如果需要自定义本地开发服务器 请取消注释按需调整 17 | dev: { 18 | // localhost:8000/api/** -> https://preview.pro.ant.design/api/** 19 | '/mj/': { 20 | // 要代理的地址 21 | target: MJ_SERVER, 22 | // 配置了这个可以从 http 代理到 https 23 | // 依赖 origin 的功能可能需要这个,比如 cookie 24 | changeOrigin: true, 25 | }, 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/locales/zh-CN/globalHeader.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.globalHeader.search': '站内搜索', 3 | 'component.globalHeader.search.example1': '搜索提示一', 4 | 'component.globalHeader.search.example2': '搜索提示二', 5 | 'component.globalHeader.search.example3': '搜索提示三', 6 | 'component.globalHeader.help': '使用文档', 7 | 'component.globalHeader.notification': '通知', 8 | 'component.globalHeader.notification.empty': '你已查看所有通知', 9 | 'component.globalHeader.message': '消息', 10 | 'component.globalHeader.message.empty': '您已读完所有消息', 11 | 'component.globalHeader.event': '待办', 12 | 'component.globalHeader.event.empty': '你已完成所有待办', 13 | 'component.noticeIcon.clear': '清空', 14 | 'component.noticeIcon.cleared': '清空了', 15 | 'component.noticeIcon.empty': '暂无数据', 16 | 'component.noticeIcon.view-more': '查看更多', 17 | }; 18 | -------------------------------------------------------------------------------- /src/locales/zh-CN.ts: -------------------------------------------------------------------------------- 1 | import component from './zh-CN/component'; 2 | import globalHeader from './zh-CN/globalHeader'; 3 | import menu from './zh-CN/menu'; 4 | import pages from './zh-CN/pages'; 5 | import pwa from './zh-CN/pwa'; 6 | import settingDrawer from './zh-CN/settingDrawer'; 7 | import settings from './zh-CN/settings'; 8 | 9 | export default { 10 | 'navBar.lang': '语言', 11 | 'layout.user.link.help': '帮助', 12 | 'layout.user.link.privacy': '隐私', 13 | 'layout.user.link.terms': '条款', 14 | 'app.copyright.produced': 'Midjourney Proxy Admin', 15 | 'app.preview.down.block': '下载此页面到本地项目', 16 | 'app.welcome.link.fetch-blocks': '获取全部区块', 17 | 'app.welcome.link.block-list': '基于 block 开发,快速构建标准页面', 18 | ...pages, 19 | ...globalHeader, 20 | ...menu, 21 | ...settingDrawer, 22 | ...settings, 23 | ...pwa, 24 | ...component, 25 | }; 26 | -------------------------------------------------------------------------------- /src/locales/en-US.ts: -------------------------------------------------------------------------------- 1 | import component from './en-US/component'; 2 | import globalHeader from './en-US/globalHeader'; 3 | import menu from './en-US/menu'; 4 | import pages from './en-US/pages'; 5 | import pwa from './en-US/pwa'; 6 | import settingDrawer from './en-US/settingDrawer'; 7 | import settings from './en-US/settings'; 8 | 9 | export default { 10 | 'navBar.lang': 'Languages', 11 | 'layout.user.link.help': 'Help', 12 | 'layout.user.link.privacy': 'Privacy', 13 | 'layout.user.link.terms': 'Terms', 14 | 'app.copyright.produced': 'Midjourney Proxy Admin', 15 | 'app.preview.down.block': 'Download this page to your local project', 16 | 'app.welcome.link.fetch-blocks': 'Get all block', 17 | 'app.welcome.link.block-list': 'Quickly build standard, pages based on `block` development', 18 | ...globalHeader, 19 | ...menu, 20 | ...settingDrawer, 21 | ...settings, 22 | ...pwa, 23 | ...component, 24 | ...pages, 25 | }; 26 | -------------------------------------------------------------------------------- /src/locales/en-US/globalHeader.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.globalHeader.search': 'Search', 3 | 'component.globalHeader.search.example1': 'Search example 1', 4 | 'component.globalHeader.search.example2': 'Search example 2', 5 | 'component.globalHeader.search.example3': 'Search example 3', 6 | 'component.globalHeader.help': 'Help', 7 | 'component.globalHeader.notification': 'Notification', 8 | 'component.globalHeader.notification.empty': 'You have viewed all notifications.', 9 | 'component.globalHeader.message': 'Message', 10 | 'component.globalHeader.message.empty': 'You have viewed all messsages.', 11 | 'component.globalHeader.event': 'Event', 12 | 'component.globalHeader.event.empty': 'You have viewed all events.', 13 | 'component.noticeIcon.clear': 'Clear', 14 | 'component.noticeIcon.cleared': 'Cleared', 15 | 'component.noticeIcon.empty': 'No notifications', 16 | 'component.noticeIcon.view-more': 'View more', 17 | }; 18 | -------------------------------------------------------------------------------- /src/global.less: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | margin: 0; 6 | padding: 0; 7 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 8 | 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 9 | 'Noto Color Emoji'; 10 | } 11 | 12 | .colorWeak { 13 | filter: invert(80%); 14 | } 15 | 16 | .ant-layout { 17 | min-height: 100vh; 18 | } 19 | .ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed { 20 | left: unset; 21 | } 22 | 23 | canvas { 24 | display: block; 25 | } 26 | 27 | body { 28 | text-rendering: optimizeLegibility; 29 | -webkit-font-smoothing: antialiased; 30 | -moz-osx-font-smoothing: grayscale; 31 | } 32 | 33 | ul, 34 | ol { 35 | list-style: none; 36 | } 37 | 38 | @media (max-width: 768px) { 39 | .ant-table { 40 | width: 100%; 41 | overflow-x: auto; 42 | &-thead > tr, 43 | &-tbody > tr { 44 | > th, 45 | > td { 46 | white-space: pre; 47 | > span { 48 | display: block; 49 | } 50 | } 51 | } 52 | } 53 | } 54 | 55 | .ant-pro-form-login-top{ 56 | padding: 0 30vw; 57 | } -------------------------------------------------------------------------------- /src/components/HeaderDropdown/index.tsx: -------------------------------------------------------------------------------- 1 | import { Dropdown, Tag } from 'antd'; 2 | import type { DropDownProps } from 'antd/es/dropdown'; 3 | import React from 'react'; 4 | import { useEmotionCss } from '@ant-design/use-emotion-css'; 5 | import classNames from 'classnames'; 6 | import { useModel } from '@umijs/max'; 7 | 8 | export type HeaderDropdownProps = { 9 | overlayClassName?: string; 10 | placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter'; 11 | } & Omit; 12 | 13 | const HeaderDropdown: React.FC = ({ overlayClassName: cls, ...restProps }) => { 14 | const { initialState } = useModel('@@initialState'); 15 | const { currentUser } = initialState || {}; 16 | const className = useEmotionCss(({ token }) => { 17 | return { 18 | [`@media screen and (max-width: ${token.screenXS})`]: { 19 | width: '100%', 20 | }, 21 | }; 22 | }); 23 | return <>{currentUser?.version}; 24 | }; 25 | 26 | export default HeaderDropdown; 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # midjourney-proxy-admin 2 | [midjourney-proxy-plus](https://github.com/litter-coder/midjourney-proxy-plus) 的管理后台 3 | 4 | # 主要功能 5 | 6 | - [x] 支持MJ账号的增删改查功能 7 | - [x] 支持MJ账号的详细信息查询和账号同步操作 8 | - [x] 支持MJ账号的并发队列设置 9 | - [x] 支持MJ的账号settings设置 10 | - [x] 支持MJ的任务查询 11 | - [x] 提供功能齐全的绘图测试页面 12 | 13 | # 后续计划 14 | 15 | - [ ] 任务查询功能优化 16 | - [ ] 支持MJ的队列内容查询 17 | 18 | # 部署方式 19 | 20 | ## 1.运行环境 21 | 22 | 支持 Linux、MacOS、Windows 系统(可在Linux服务器上长期运行),同时需安装 `node18`。 23 | 24 | **(1) 克隆项目代码:** 25 | 26 | ```bash 27 | git clone https://github.com/litter-coder/midjourney-proxy-admin 28 | cd midjourney-proxy-admin/ 29 | ``` 30 | 31 | **(2) 安装依赖 :** 32 | 33 | ```bash 34 | npm install 35 | ``` 36 | 37 | ## 2.配置 38 | 39 | 配置文件在根目录的`.env`中: 40 | 41 | ```shell 42 | # MJ-SERVER 43 | MJ_SERVER=http://127.0.0.1:8080 44 | ``` 45 | 46 | ## 3.运行 47 | 48 | 使用nohup命令在后台运行程序: 49 | 50 | ``` 51 | nohup npm run start > out.log 2>&1 & disown 52 | # 在后台运行程序 53 | ``` 54 | 55 | ## 4.其他 56 | 57 | ### 1.查看进程 58 | 59 | ```shell 60 | ps -ef | grep npm 61 | ``` 62 | 63 | ### 2.结束进程 64 | 65 | ```sh 66 | kill -9 [进程id] 67 | ``` 68 | 69 | # 联系我们 70 | 71 | 问题咨询和商务合作可联系 72 | 73 | 微信二维码 74 | 75 | -------------------------------------------------------------------------------- /src/locales/zh-CN/settingDrawer.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.setting.pagestyle': '整体风格设置', 3 | 'app.setting.pagestyle.dark': '暗色菜单风格', 4 | 'app.setting.pagestyle.light': '亮色菜单风格', 5 | 'app.setting.content-width': '内容区域宽度', 6 | 'app.setting.content-width.fixed': '定宽', 7 | 'app.setting.content-width.fluid': '流式', 8 | 'app.setting.themecolor': '主题色', 9 | 'app.setting.themecolor.dust': '薄暮', 10 | 'app.setting.themecolor.volcano': '火山', 11 | 'app.setting.themecolor.sunset': '日暮', 12 | 'app.setting.themecolor.cyan': '明青', 13 | 'app.setting.themecolor.green': '极光绿', 14 | 'app.setting.themecolor.daybreak': '拂晓蓝(默认)', 15 | 'app.setting.themecolor.geekblue': '极客蓝', 16 | 'app.setting.themecolor.purple': '酱紫', 17 | 'app.setting.navigationmode': '导航模式', 18 | 'app.setting.sidemenu': '侧边菜单布局', 19 | 'app.setting.topmenu': '顶部菜单布局', 20 | 'app.setting.fixedheader': '固定 Header', 21 | 'app.setting.fixedsidebar': '固定侧边菜单', 22 | 'app.setting.fixedsidebar.hint': '侧边菜单布局时可配置', 23 | 'app.setting.hideheader': '下滑时隐藏 Header', 24 | 'app.setting.hideheader.hint': '固定 Header 时可配置', 25 | 'app.setting.othersettings': '其他设置', 26 | 'app.setting.weakmode': '色弱模式', 27 | 'app.setting.copy': '拷贝设置', 28 | 'app.setting.copyinfo': '拷贝成功,请到 config/defaultSettings.js 中替换默认配置', 29 | 'app.setting.production.hint': 30 | '配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改配置文件', 31 | }; 32 | -------------------------------------------------------------------------------- /src/components/Footer/index.tsx: -------------------------------------------------------------------------------- 1 | import { GithubOutlined } from '@ant-design/icons'; 2 | import { DefaultFooter } from '@ant-design/pro-components'; 3 | import { useIntl } from '@umijs/max'; 4 | import React from 'react'; 5 | 6 | const Footer: React.FC = () => { 7 | const intl = useIntl(); 8 | const defaultMessage = intl.formatMessage({ 9 | id: 'app.copyright.produced', 10 | defaultMessage: 'Midjourney Proxy Admin', 11 | }); 12 | 13 | const currentYear = new Date().getFullYear(); 14 | 15 | return ( 16 | , 31 | href: 'https://github.com/novicezk/midjourney-proxy', 32 | blankTarget: true, 33 | }, 34 | { 35 | key: 'Midjourney Proxy Plus', 36 | title: 'Midjourney Proxy Plus', 37 | href: 'https://github.com/litter-coder/midjourney-proxy-plus', 38 | blankTarget: true, 39 | }, 40 | ]} 41 | /> 42 | ); 43 | }; 44 | 45 | export default Footer; 46 | -------------------------------------------------------------------------------- /src/locales/en-US/settingDrawer.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.setting.pagestyle': 'Page style setting', 3 | 'app.setting.pagestyle.dark': 'Dark style', 4 | 'app.setting.pagestyle.light': 'Light style', 5 | 'app.setting.content-width': 'Content Width', 6 | 'app.setting.content-width.fixed': 'Fixed', 7 | 'app.setting.content-width.fluid': 'Fluid', 8 | 'app.setting.themecolor': 'Theme Color', 9 | 'app.setting.themecolor.dust': 'Dust Red', 10 | 'app.setting.themecolor.volcano': 'Volcano', 11 | 'app.setting.themecolor.sunset': 'Sunset Orange', 12 | 'app.setting.themecolor.cyan': 'Cyan', 13 | 'app.setting.themecolor.green': 'Polar Green', 14 | 'app.setting.themecolor.daybreak': 'Daybreak Blue (default)', 15 | 'app.setting.themecolor.geekblue': 'Geek Glue', 16 | 'app.setting.themecolor.purple': 'Golden Purple', 17 | 'app.setting.navigationmode': 'Navigation Mode', 18 | 'app.setting.sidemenu': 'Side Menu Layout', 19 | 'app.setting.topmenu': 'Top Menu Layout', 20 | 'app.setting.fixedheader': 'Fixed Header', 21 | 'app.setting.fixedsidebar': 'Fixed Sidebar', 22 | 'app.setting.fixedsidebar.hint': 'Works on Side Menu Layout', 23 | 'app.setting.hideheader': 'Hidden Header when scrolling', 24 | 'app.setting.hideheader.hint': 'Works when Hidden Header is enabled', 25 | 'app.setting.othersettings': 'Other Settings', 26 | 'app.setting.weakmode': 'Weak Mode', 27 | 'app.setting.copy': 'Copy Setting', 28 | 'app.setting.copyinfo': 'copy success,please replace defaultSettings in src/models/setting.js', 29 | 'app.setting.production.hint': 30 | 'Setting panel shows in development environment only, please manually modify', 31 | }; 32 | -------------------------------------------------------------------------------- /tests/setupTests.jsx: -------------------------------------------------------------------------------- 1 | const localStorageMock = { 2 | getItem: jest.fn(), 3 | setItem: jest.fn(), 4 | removeItem: jest.fn(), 5 | clear: jest.fn(), 6 | }; 7 | 8 | global.localStorage = localStorageMock; 9 | 10 | Object.defineProperty(URL, 'createObjectURL', { 11 | writable: true, 12 | value: jest.fn(), 13 | }); 14 | 15 | class Worker { 16 | constructor(stringUrl) { 17 | this.url = stringUrl; 18 | this.onmessage = () => {}; 19 | } 20 | 21 | postMessage(msg) { 22 | this.onmessage(msg); 23 | } 24 | } 25 | window.Worker = Worker; 26 | 27 | /* eslint-disable global-require */ 28 | if (typeof window !== 'undefined') { 29 | // ref: https://github.com/ant-design/ant-design/issues/18774 30 | if (!window.matchMedia) { 31 | Object.defineProperty(global.window, 'matchMedia', { 32 | writable: true, 33 | configurable: true, 34 | value: jest.fn(() => ({ 35 | matches: false, 36 | addListener: jest.fn(), 37 | removeListener: jest.fn(), 38 | })), 39 | }); 40 | } 41 | if (!window.matchMedia) { 42 | Object.defineProperty(global.window, 'matchMedia', { 43 | writable: true, 44 | configurable: true, 45 | value: jest.fn((query) => ({ 46 | matches: query.includes('max-width'), 47 | addListener: jest.fn(), 48 | removeListener: jest.fn(), 49 | })), 50 | }); 51 | } 52 | } 53 | const errorLog = console.error; 54 | Object.defineProperty(global.window.console, 'error', { 55 | writable: true, 56 | configurable: true, 57 | value: (...rest) => { 58 | const logStr = rest.join(''); 59 | if (logStr.includes('Warning: An update to %s inside a test was not wrapped in act(...)')) { 60 | return; 61 | } 62 | errorLog(...rest); 63 | }, 64 | }); 65 | -------------------------------------------------------------------------------- /src/services/swagger/store.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | /* eslint-disable */ 3 | import { request } from '@umijs/max'; 4 | 5 | /** Returns pet inventories by status Returns a map of status codes to quantities GET /store/inventory */ 6 | export async function getInventory(options?: { [key: string]: any }) { 7 | return request>('/store/inventory', { 8 | method: 'GET', 9 | ...(options || {}), 10 | }); 11 | } 12 | 13 | /** Place an order for a pet POST /store/order */ 14 | export async function placeOrder(body: API.Order, options?: { [key: string]: any }) { 15 | return request('/store/order', { 16 | method: 'POST', 17 | data: body, 18 | ...(options || {}), 19 | }); 20 | } 21 | 22 | /** Find purchase order by ID For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions GET /store/order/${param0} */ 23 | export async function getOrderById( 24 | // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) 25 | params: API.getOrderByIdParams, 26 | options?: { [key: string]: any }, 27 | ) { 28 | const { orderId: param0, ...queryParams } = params; 29 | return request(`/store/order/${param0}`, { 30 | method: 'GET', 31 | params: { ...queryParams }, 32 | ...(options || {}), 33 | }); 34 | } 35 | 36 | /** Delete purchase order by ID For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors DELETE /store/order/${param0} */ 37 | export async function deleteOrder( 38 | // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) 39 | params: API.deleteOrderParams, 40 | options?: { [key: string]: any }, 41 | ) { 42 | const { orderId: param0, ...queryParams } = params; 43 | return request(`/store/order/${param0}`, { 44 | method: 'DELETE', 45 | params: { ...queryParams }, 46 | ...(options || {}), 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /src/pages/AccountList/components/button/DelButton.tsx: -------------------------------------------------------------------------------- 1 | import { deleteAccount } from '@/services/mj/api'; 2 | import { Button, Popconfirm, notification } from 'antd'; 3 | import { DeleteOutlined } from '@ant-design/icons'; 4 | import React, { useState } from 'react'; 5 | import { useIntl } from '@umijs/max'; 6 | 7 | // 定义 DelButton 接受的 props 类型 8 | interface DelButtonProps { 9 | record: Record; 10 | onSuccess: () => void; 11 | } 12 | 13 | const DelButton: React.FC = ({ record, onSuccess }) => { 14 | const [open, setOpen] = useState(false); 15 | const [confirmLoading, setConfirmLoading] = useState(false); 16 | const [api, contextHolder] = notification.useNotification(); 17 | const intl = useIntl(); 18 | 19 | const showPopconfirm = () => { 20 | setOpen(true); 21 | }; 22 | 23 | const handleOk = async () => { 24 | setConfirmLoading(true); 25 | try { 26 | const res = await deleteAccount(record.id); 27 | setOpen(false); 28 | if (res.code == 1) { 29 | api.success({ 30 | message: 'success', 31 | description: intl.formatMessage({ id: 'pages.account.deleteSuccess' }) 32 | }); 33 | onSuccess(); 34 | } else { 35 | api.error({ 36 | message: 'error', 37 | description: res.description 38 | }); 39 | } 40 | } catch (error) { 41 | console.error(error); 42 | } finally { 43 | setConfirmLoading(false); 44 | } 45 | }; 46 | 47 | const handleCancel = () => { 48 | setOpen(false); 49 | }; 50 | 51 | return ( 52 | 60 | {contextHolder} 61 | 63 | 64 | ); 65 | }; 66 | 67 | export default DelButton; 68 | -------------------------------------------------------------------------------- /config/oneapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.1", 3 | "info": { 4 | "title": "Ant Design Pro", 5 | "version": "1.0.0" 6 | }, 7 | "servers": [ 8 | { 9 | "url": "http://localhost:8000/" 10 | }, 11 | { 12 | "url": "https://localhost:8000/" 13 | } 14 | ], 15 | "paths": { 16 | "/swagger": { 17 | "x-swagger-pipe": "swagger_raw" 18 | } 19 | }, 20 | "components": { 21 | "schemas": { 22 | "LoginResult": { 23 | "type": "object", 24 | "properties": { 25 | "status": { 26 | "type": "string" 27 | }, 28 | "type": { 29 | "type": "string" 30 | }, 31 | "currentAuthority": { 32 | "type": "string" 33 | } 34 | } 35 | }, 36 | "PageParams": { 37 | "type": "object", 38 | "properties": { 39 | "current": { 40 | "type": "number" 41 | }, 42 | "pageSize": { 43 | "type": "number" 44 | } 45 | } 46 | }, 47 | "NoticeIconItem": { 48 | "type": "object", 49 | "properties": { 50 | "id": { 51 | "type": "string" 52 | }, 53 | "extra": { 54 | "type": "string", 55 | "format": "any" 56 | }, 57 | "key": { "type": "string" }, 58 | "read": { 59 | "type": "boolean" 60 | }, 61 | "avatar": { 62 | "type": "string" 63 | }, 64 | "title": { 65 | "type": "string" 66 | }, 67 | "status": { 68 | "type": "string" 69 | }, 70 | "datetime": { 71 | "type": "string", 72 | "format": "date" 73 | }, 74 | "description": { 75 | "type": "string" 76 | }, 77 | "type": { 78 | "extensions": { 79 | "x-is-enum": true 80 | }, 81 | "$ref": "#/components/schemas/NoticeIconItemType" 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /config/routes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @name umi 的路由配置 3 | * @description 只支持 path,component,routes,redirect,wrappers,name,icon 的配置 4 | * @param path path 只支持两种占位符配置,第一种是动态参数 :id 的形式,第二种是 * 通配符,通配符只能出现路由字符串的最后。 5 | * @param component 配置 location 和 path 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径,如果是相对路径,会从 src/pages 开始找起。 6 | * @param routes 配置子路由,通常在需要为多个路径增加 layout 组件时使用。 7 | * @param redirect 配置路由跳转 8 | * @param wrappers 配置路由组件的包装组件,通过包装组件可以为当前的路由组件组合进更多的功能。 比如,可以用于路由级别的权限校验 9 | * @param name 配置路由的标题,默认读取国际化文件 menu.ts 中 menu.xxxx 的值,如配置 name 为 login,则读取 menu.ts 中 menu.login 的取值作为标题 10 | * @param icon 配置路由的图标,取值参考 https://ant.design/components/icon-cn, 注意去除风格后缀和大小写,如想要配置图标为 则取值应为 stepBackward 或 StepBackward,如想要配置图标为 则取值应为 user 或者 User 11 | * @doc https://umijs.org/docs/guides/routes 12 | */ 13 | export default [ 14 | { 15 | path: '/user', 16 | layout: false, 17 | routes: [ 18 | { 19 | name: 'login', 20 | path: 'login', 21 | component: './User/Login', 22 | }, 23 | ], 24 | }, 25 | { 26 | path: '/welcome', 27 | name: 'welcome', 28 | icon: 'smile', 29 | component: './Welcome', 30 | }, 31 | { 32 | path: '/', 33 | redirect: '/welcome', 34 | }, 35 | { 36 | name: 'list.account-list', 37 | icon: 'crown', 38 | path: '/account', 39 | component: './AccountList', 40 | }, 41 | { 42 | name: 'task-list', 43 | icon: 'bars', 44 | path: '/task', 45 | component: './Task/List', 46 | }, 47 | { 48 | name: 'draw-test', 49 | icon: 'experiment', 50 | path: '/draw-test', 51 | component: './Draw', 52 | }, 53 | { 54 | name: 'probe', 55 | icon: 'profile', 56 | path: '/probe', 57 | component: './Probe', 58 | }, 59 | { 60 | name: 'setting', 61 | icon: 'setting', 62 | path: '/setting', 63 | component: './Setting', 64 | }, 65 | { 66 | name: 'activate', 67 | icon: 'key', 68 | path: '/activate', 69 | component: './Activate', 70 | }, 71 | { 72 | path: '*', 73 | layout: false, 74 | component: './404', 75 | }, 76 | ]; 77 | -------------------------------------------------------------------------------- /src/locales/zh-CN/menu.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.welcome': '欢迎', 3 | 'menu.more-blocks': '更多区块', 4 | 'menu.home': '首页', 5 | 'menu.admin': '管理页', 6 | 'menu.admin.sub-page': '二级管理页', 7 | 'menu.login': '登录', 8 | 'menu.register': '注册', 9 | 'menu.register-result': '注册结果', 10 | 'menu.dashboard': 'Dashboard', 11 | 'menu.dashboard.analysis': '分析页', 12 | 'menu.dashboard.monitor': '监控页', 13 | 'menu.dashboard.workplace': '工作台', 14 | 'menu.exception.403': '403', 15 | 'menu.exception.404': '404', 16 | 'menu.exception.500': '500', 17 | 'menu.form': '表单页', 18 | 'menu.form.basic-form': '基础表单', 19 | 'menu.form.step-form': '分步表单', 20 | 'menu.form.step-form.info': '分步表单(填写转账信息)', 21 | 'menu.form.step-form.confirm': '分步表单(确认转账信息)', 22 | 'menu.form.step-form.result': '分步表单(完成)', 23 | 'menu.form.advanced-form': '高级表单', 24 | 'menu.list': '列表页', 25 | 'menu.list.table-list': '查询表格', 26 | 'menu.list.account-list': '账号管理', 27 | 'menu.task-list': '任务查询', 28 | 'menu.draw-test': '绘画测试', 29 | 'menu.probe': '日志查看', 30 | 'menu.activate': '服务激活', 31 | 'menu.setting': '系统设置', 32 | 'menu.api-doc': 'API文档', 33 | 'menu.list.basic-list': '标准列表', 34 | 'menu.list.card-list': '卡片列表', 35 | 'menu.list.search-list': '搜索列表', 36 | 'menu.list.search-list.articles': '搜索列表(文章)', 37 | 'menu.list.search-list.projects': '搜索列表(项目)', 38 | 'menu.list.search-list.applications': '搜索列表(应用)', 39 | 'menu.profile': '详情页', 40 | 'menu.profile.basic': '基础详情页', 41 | 'menu.profile.advanced': '高级详情页', 42 | 'menu.result': '结果页', 43 | 'menu.result.success': '成功页', 44 | 'menu.result.fail': '失败页', 45 | 'menu.exception': '异常页', 46 | 'menu.exception.not-permission': '403', 47 | 'menu.exception.not-find': '404', 48 | 'menu.exception.server-error': '500', 49 | 'menu.exception.trigger': '触发错误', 50 | 'menu.account': '个人页', 51 | 'menu.account.center': '个人中心', 52 | 'menu.account.settings': '个人设置', 53 | 'menu.account.trigger': '触发报错', 54 | 'menu.account.logout': '退出登录', 55 | 'menu.editor': '图形编辑器', 56 | 'menu.editor.flow': '流程编辑器', 57 | 'menu.editor.mind': '脑图编辑器', 58 | 'menu.editor.koni': '拓扑编辑器', 59 | }; 60 | -------------------------------------------------------------------------------- /src/pages/AccountList/components/button/SyncButton.tsx: -------------------------------------------------------------------------------- 1 | import { refreshAccount } from '@/services/mj/api'; 2 | import { Button, Popconfirm, notification } from 'antd'; 3 | import { SyncOutlined } from '@ant-design/icons'; 4 | import React, { useState } from 'react'; 5 | import { useIntl } from '@umijs/max'; 6 | 7 | interface SyncButtonProps { 8 | record: Record; 9 | onSuccess: () => void; 10 | } 11 | 12 | const SyncButton: React.FC = ({ record, onSuccess }) => { 13 | const [open, setOpen] = useState(false); 14 | const [confirmLoading, setConfirmLoading] = useState(false); 15 | const [api, contextHolder] = notification.useNotification(); 16 | const intl = useIntl(); 17 | 18 | const showPopconfirm = () => { 19 | setOpen(true); 20 | }; 21 | 22 | const handleOk = async () => { 23 | setConfirmLoading(true); 24 | try { 25 | const res = await refreshAccount(record.id); 26 | setOpen(false); 27 | if (res.code == 1) { 28 | api.success({ 29 | message: 'success', 30 | description: intl.formatMessage({ id: 'pages.account.syncSuccess' }) 31 | }); 32 | onSuccess(); 33 | } else { 34 | api.error({ 35 | message: 'error', 36 | description: res.description 37 | }); 38 | onSuccess(); 39 | } 40 | } catch (error) { 41 | console.error(error); 42 | } finally { 43 | setConfirmLoading(false); 44 | } 45 | }; 46 | 47 | const handleCancel = () => { 48 | setOpen(false); 49 | }; 50 | 51 | return ( 52 | 60 | {contextHolder} 61 | 64 | 65 | ); 66 | }; 67 | 68 | export default SyncButton; 69 | -------------------------------------------------------------------------------- /src/service-worker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-restricted-globals */ 2 | /* eslint-disable no-underscore-dangle */ 3 | /* globals workbox */ 4 | workbox.core.setCacheNameDetails({ 5 | prefix: 'antd-pro', 6 | suffix: 'v5', 7 | }); 8 | // Control all opened tabs ASAP 9 | workbox.clientsClaim(); 10 | 11 | /** 12 | * Use precaching list generated by workbox in build process. 13 | * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.precaching 14 | */ 15 | workbox.precaching.precacheAndRoute(self.__precacheManifest || []); 16 | 17 | /** 18 | * Register a navigation route. 19 | * https://developers.google.com/web/tools/workbox/modules/workbox-routing#how_to_register_a_navigation_route 20 | */ 21 | workbox.routing.registerNavigationRoute('/index.html'); 22 | 23 | /** 24 | * Use runtime cache: 25 | * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.routing#.registerRoute 26 | * 27 | * Workbox provides all common caching strategies including CacheFirst, NetworkFirst etc. 28 | * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.strategies 29 | */ 30 | 31 | /** Handle API requests */ 32 | workbox.routing.registerRoute(/\/api\//, workbox.strategies.networkFirst()); 33 | 34 | /** Handle third party requests */ 35 | workbox.routing.registerRoute( 36 | /^https:\/\/gw\.alipayobjects\.com\//, 37 | workbox.strategies.networkFirst(), 38 | ); 39 | workbox.routing.registerRoute( 40 | /^https:\/\/cdnjs\.cloudflare\.com\//, 41 | workbox.strategies.networkFirst(), 42 | ); 43 | workbox.routing.registerRoute(/\/color.less/, workbox.strategies.networkFirst()); 44 | 45 | /** Response to client after skipping waiting with MessageChannel */ 46 | addEventListener('message', (event) => { 47 | const replyPort = event.ports[0]; 48 | const message = event.data; 49 | if (replyPort && message && message.type === 'skip-waiting') { 50 | event.waitUntil( 51 | self.skipWaiting().then( 52 | () => { 53 | replyPort.postMessage({ 54 | error: null, 55 | }); 56 | }, 57 | (error) => { 58 | replyPort.postMessage({ 59 | error, 60 | }); 61 | }, 62 | ), 63 | ); 64 | } 65 | }); 66 | -------------------------------------------------------------------------------- /src/locales/en-US/menu.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.welcome': 'Welcome', 3 | 'menu.more-blocks': 'More Blocks', 4 | 'menu.home': 'Home', 5 | 'menu.admin': 'Admin', 6 | 'menu.admin.sub-page': 'Sub-Page', 7 | 'menu.login': 'Login', 8 | 'menu.register': 'Register', 9 | 'menu.register-result': 'Register Result', 10 | 'menu.dashboard': 'Dashboard', 11 | 'menu.dashboard.analysis': 'Analysis', 12 | 'menu.dashboard.monitor': 'Monitor', 13 | 'menu.dashboard.workplace': 'Workplace', 14 | 'menu.exception.403': '403', 15 | 'menu.exception.404': '404', 16 | 'menu.exception.500': '500', 17 | 'menu.form': 'Form', 18 | 'menu.form.basic-form': 'Basic Form', 19 | 'menu.form.step-form': 'Step Form', 20 | 'menu.form.step-form.info': 'Step Form(write transfer information)', 21 | 'menu.form.step-form.confirm': 'Step Form(confirm transfer information)', 22 | 'menu.form.step-form.result': 'Step Form(finished)', 23 | 'menu.form.advanced-form': 'Advanced Form', 24 | 'menu.list': 'List', 25 | 'menu.list.table-list': 'Search Table', 26 | 'menu.list.account-list': 'Account Manage', 27 | 'menu.api-doc': 'API DOC', 28 | 'menu.task-list': 'Task Search', 29 | 'menu.draw-test': 'Draw Test', 30 | 'menu.probe': 'Log Probe', 31 | 'menu.setting': 'System Setting', 32 | 'menu.activate': 'System Activate', 33 | 'menu.list.basic-list': 'Basic List', 34 | 'menu.list.card-list': 'Card List', 35 | 'menu.list.search-list': 'Search List', 36 | 'menu.list.search-list.articles': 'Search List(articles)', 37 | 'menu.list.search-list.projects': 'Search List(projects)', 38 | 'menu.list.search-list.applications': 'Search List(applications)', 39 | 'menu.profile': 'Profile', 40 | 'menu.profile.basic': 'Basic Profile', 41 | 'menu.profile.advanced': 'Advanced Profile', 42 | 'menu.result': 'Result', 43 | 'menu.result.success': 'Success', 44 | 'menu.result.fail': 'Fail', 45 | 'menu.exception': 'Exception', 46 | 'menu.exception.not-permission': '403', 47 | 'menu.exception.not-find': '404', 48 | 'menu.exception.server-error': '500', 49 | 'menu.exception.trigger': 'Trigger', 50 | 'menu.account': 'Account', 51 | 'menu.account.center': 'Account Center', 52 | 'menu.account.settings': 'Account Settings', 53 | 'menu.account.trigger': 'Trigger Error', 54 | 'menu.account.logout': 'Logout', 55 | 'menu.editor': 'Graphic Editor', 56 | 'menu.editor.flow': 'Flow Editor', 57 | 'menu.editor.mind': 'Mind Editor', 58 | 'menu.editor.koni': 'Koni Editor', 59 | }; 60 | -------------------------------------------------------------------------------- /src/components/JsonEditor/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import AceEditor from 'react-ace'; 3 | 4 | import 'ace-builds/src-noconflict/mode-json'; 5 | import 'ace-builds/src-noconflict/theme-textmate'; 6 | 7 | interface JsonEditorFormItemProps { 8 | value?: object; 9 | onChange?: (value: object) => void; 10 | } 11 | 12 | const JsonEditor: React.FC = ({ value = {}, onChange }) => { 13 | const [textValue, setTextValue] = React.useState(JSON.stringify(value, null, 2)); 14 | const [isValidJson, setIsValidJson] = React.useState(true); 15 | 16 | useEffect(() => { 17 | const json1 = JSON.stringify(value); 18 | const json2 = JSON.stringify(JSON.parse(textValue)); 19 | if (json1 !== json2) { 20 | setTextValue(JSON.stringify(value, null, 2)); 21 | } 22 | }, [value]); 23 | 24 | const handleChange = (newValue: string) => { 25 | setTextValue(newValue); 26 | try { 27 | const parsedValue = JSON.parse(newValue); 28 | setIsValidJson(true); 29 | if (onChange) { 30 | onChange(parsedValue); 31 | } 32 | } catch (error) { 33 | setIsValidJson(false); 34 | } 35 | }; 36 | return ( 37 |
38 | 62 | {!isValidJson && ( 63 |
JSON 格式错误,请检查输入!
64 | )} 65 |
66 | ); 67 | }; 68 | 69 | export default JsonEditor; -------------------------------------------------------------------------------- /src/pages/AccountList/components/contents/UpdateContent.tsx: -------------------------------------------------------------------------------- 1 | import { Card, Alert, Row, Col, Form, FormInstance, Input, Switch, InputNumber } from 'antd'; 2 | import { useEffect } from 'react'; 3 | const { TextArea } = Input; 4 | import { useIntl } from '@umijs/max'; 5 | 6 | const UpdateContent = ({ 7 | form, 8 | onSubmit, 9 | record, 10 | }: { 11 | form: FormInstance; 12 | onSubmit: (values: any) => void; 13 | record: Record; 14 | }) => { 15 | const intl = useIntl(); 16 | // 当组件挂载或者record更新时,设置表单的初始值 17 | useEffect(() => { 18 | record.weight=record['properties']['weight']; 19 | form.setFieldsValue(record); 20 | }); 21 | 22 | return ( 23 |
31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |