Browse Source

Merge remote-tracking branch 'origin/dev' into dev

pull/10/head
西大锐 1 year ago
parent
commit
cb4ac403e8
100 changed files with 5012 additions and 4451 deletions
  1. +2
    -2
      react-ui/.eslintrc.js
  2. +2
    -2
      react-ui/config/defaultSettings.ts
  3. +14
    -14
      react-ui/package.json
  4. +13
    -16
      react-ui/src/app.tsx
  5. +78
    -82
      react-ui/src/components/DictTag/index.tsx
  6. +2
    -2
      react-ui/src/components/HeaderDropdown/index.tsx
  7. +10
    -9
      react-ui/src/components/IconSelector/Category.tsx
  8. +7
    -10
      react-ui/src/components/IconSelector/CopyableIcon.tsx
  9. +30
    -27
      react-ui/src/components/IconSelector/IconPicSearcher.tsx
  10. +2
    -2
      react-ui/src/components/IconSelector/fields.ts
  11. +18
    -14
      react-ui/src/components/IconSelector/index.tsx
  12. +3
    -4
      react-ui/src/components/IconSelector/themeIcons.tsx
  13. +5
    -5
      react-ui/src/components/RightContent/AvatarDropdown.tsx
  14. +2
    -3
      react-ui/src/enums/pagesEnums.ts
  15. +0
    -1
      react-ui/src/enums/status.d.ts
  16. +26
    -30
      react-ui/src/global.less
  17. +24
    -24
      react-ui/src/locales/en-US/app.ts
  18. +12
    -12
      react-ui/src/locales/zh-CN.ts
  19. +10
    -10
      react-ui/src/locales/zh-CN/monitor/job-log.ts
  20. +17
    -17
      react-ui/src/locales/zh-CN/monitor/job.ts
  21. +11
    -11
      react-ui/src/locales/zh-CN/monitor/logininfor.ts
  22. +1
    -2
      react-ui/src/locales/zh-CN/monitor/onlineUser.ts
  23. +17
    -17
      react-ui/src/locales/zh-CN/monitor/operlog.ts
  24. +1
    -2
      react-ui/src/locales/zh-CN/monitor/server.ts
  25. +12
    -12
      react-ui/src/locales/zh-CN/system/config.ts
  26. +16
    -16
      react-ui/src/locales/zh-CN/system/dept.ts
  27. +20
    -20
      react-ui/src/locales/zh-CN/system/menu.ts
  28. +11
    -11
      react-ui/src/locales/zh-CN/system/notice.ts
  29. +11
    -11
      react-ui/src/locales/zh-CN/system/post.ts
  30. +19
    -19
      react-ui/src/locales/zh-CN/system/role.ts
  31. +29
    -29
      react-ui/src/locales/zh-CN/system/user.ts
  32. +284
    -192
      react-ui/src/pages/Dataset/datasetIntro.jsx
  33. +53
    -63
      react-ui/src/pages/Dataset/index.jsx
  34. +271
    -277
      react-ui/src/pages/Dataset/index.less
  35. +326
    -246
      react-ui/src/pages/Dataset/personalData.jsx
  36. +206
    -157
      react-ui/src/pages/Dataset/publicData.jsx
  37. +4
    -3
      react-ui/src/pages/Experiment/experimentText/LogList.tsx
  38. +39
    -39
      react-ui/src/pages/Experiment/experimentText/editPipeline.less
  39. +12
    -11
      react-ui/src/pages/Experiment/experimentText/logGroup.tsx
  40. +10
    -3
      react-ui/src/pages/Experiment/experimentText/props.jsx
  41. +0
    -11
      react-ui/src/pages/Experiment/status.ts
  42. +10
    -0
      react-ui/src/pages/Experiment/types.ts
  43. +43
    -53
      react-ui/src/pages/Model/index.jsx
  44. +269
    -272
      react-ui/src/pages/Model/index.less
  45. +88
    -39
      react-ui/src/pages/Model/modelIntro.jsx
  46. +5
    -5
      react-ui/src/pages/Monitor/Job/detail.tsx
  47. +30
    -17
      react-ui/src/pages/Monitor/Job/edit.tsx
  48. +37
    -23
      react-ui/src/pages/Monitor/Job/index.tsx
  49. +5
    -8
      react-ui/src/pages/Monitor/JobLog/detail.tsx
  50. +23
    -17
      react-ui/src/pages/Monitor/JobLog/index.tsx
  51. +32
    -34
      react-ui/src/pages/Monitor/Online/index.tsx
  52. +25
    -25
      react-ui/src/pages/Pipeline/editPipeline/editPipeline.less
  53. +654
    -601
      react-ui/src/pages/Pipeline/editPipeline/index.jsx
  54. +72
    -60
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx
  55. +37
    -41
      react-ui/src/pages/Pipeline/editPipeline/modelMenus.less
  56. +149
    -121
      react-ui/src/pages/Pipeline/editPipeline/props.jsx
  57. +269
    -247
      react-ui/src/pages/Pipeline/index.jsx
  58. +57
    -59
      react-ui/src/pages/Pipeline/index.less
  59. +27
    -26
      react-ui/src/pages/System/Config/edit.tsx
  60. +30
    -12
      react-ui/src/pages/System/Config/index.tsx
  61. +8
    -9
      react-ui/src/pages/System/Dept/edit.tsx
  62. +29
    -18
      react-ui/src/pages/System/Dept/index.tsx
  63. +18
    -17
      react-ui/src/pages/System/Dict/edit.tsx
  64. +26
    -16
      react-ui/src/pages/System/Dict/index.tsx
  65. +16
    -15
      react-ui/src/pages/System/DictData/edit.tsx
  66. +38
    -23
      react-ui/src/pages/System/DictData/index.tsx
  67. +31
    -31
      react-ui/src/pages/System/Logininfor/edit.tsx
  68. +28
    -13
      react-ui/src/pages/System/Logininfor/index.tsx
  69. +29
    -25
      react-ui/src/pages/System/Menu/edit.tsx
  70. +20
    -17
      react-ui/src/pages/System/Menu/index.tsx
  71. +29
    -28
      react-ui/src/pages/System/Notice/edit.tsx
  72. +29
    -19
      react-ui/src/pages/System/Notice/index.tsx
  73. +5
    -6
      react-ui/src/pages/System/Operlog/detail.tsx
  74. +25
    -16
      react-ui/src/pages/System/Operlog/index.tsx
  75. +27
    -26
      react-ui/src/pages/System/Post/edit.tsx
  76. +20
    -16
      react-ui/src/pages/System/Post/index.tsx
  77. +257
    -248
      react-ui/src/pages/System/Role/authUser.tsx
  78. +213
    -205
      react-ui/src/pages/System/Role/components/DataScope.tsx
  79. +15
    -11
      react-ui/src/pages/System/Role/components/UserSelectorModal.tsx
  80. +17
    -11
      react-ui/src/pages/System/Role/edit.tsx
  81. +56
    -32
      react-ui/src/pages/System/Role/index.tsx
  82. +61
    -61
      react-ui/src/pages/System/User/components/AuthRole.tsx
  83. +3
    -4
      react-ui/src/pages/System/User/components/DeptTree.tsx
  84. +5
    -5
      react-ui/src/pages/System/User/components/ResetPwd.tsx
  85. +15
    -27
      react-ui/src/pages/System/User/edit.tsx
  86. +72
    -36
      react-ui/src/pages/System/User/index.tsx
  87. +3
    -8
      react-ui/src/pages/Tool/Gen/components/BaseInfo.tsx
  88. +4
    -4
      react-ui/src/pages/Tool/Gen/components/ColumnInfo.tsx
  89. +4
    -8
      react-ui/src/pages/Tool/Gen/components/GenInfo.tsx
  90. +7
    -7
      react-ui/src/pages/Tool/Gen/components/PreviewCode.tsx
  91. +22
    -18
      react-ui/src/pages/Tool/Gen/edit.tsx
  92. +5
    -5
      react-ui/src/pages/Tool/Gen/import.tsx
  93. +12
    -12
      react-ui/src/pages/Tool/Gen/index.tsx
  94. +2
    -2
      react-ui/src/pages/Tool/Gen/service.ts
  95. +3
    -4
      react-ui/src/pages/User/Center/Center.less
  96. +9
    -9
      react-ui/src/pages/User/Center/components/AvatarCropper/index.less
  97. +7
    -7
      react-ui/src/pages/User/Center/components/AvatarCropper/index.tsx
  98. +4
    -5
      react-ui/src/pages/User/Center/components/BaseInfo/index.tsx
  99. +50
    -52
      react-ui/src/pages/User/Center/components/ResetPassword/index.tsx
  100. +296
    -277
      react-ui/src/pages/User/Login/index.tsx

+ 2
- 2
react-ui/.eslintrc.js View File

@@ -5,6 +5,6 @@ module.exports = {
REACT_APP_ENV: true,
},
rules: {
"@typescript-eslint/no-use-before-define": "off"
}
'@typescript-eslint/no-use-before-define': 'off',
},
};

+ 2
- 2
react-ui/config/defaultSettings.ts View File

@@ -9,7 +9,7 @@ const Settings: ProLayoutProps & {
} = {
navTheme: 'light',
// 拂晓蓝
colorPrimary: '#1890ff',
colorPrimary: '#1664ff',
layout: 'mix',
contentWidth: 'Fluid',
fixedHeader: false,
@@ -19,7 +19,7 @@ const Settings: ProLayoutProps & {
title: '复杂智能软件',
pwa: true,
logo: '/assets/images/left-top-logo.png',
iconfontUrl: '',
iconfontUrl: '',
token: {
// 参见ts声明,demo 见文档,通过token 修改样式
//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


+ 14
- 14
react-ui/package.json View File

@@ -4,19 +4,10 @@
"private": true,
"description": "An out-of-box UI solution for enterprise applications",
"scripts": {
"dev": "npm run start:dev",
"analyze": "cross-env ANALYZE=1 max build",
"build": "max build",
"deploy": "npm run build && npm run gh-pages",
"preview": "npm run build && max preview --port 8000",
"serve": "umi-serve",
"start": "cross-env UMI_ENV=dev max dev",
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev",
"start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev",
"start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev",
"start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev",
"test": "jest",
"test:coverage": "npm run jest -- --coverage",
"test:update": "npm run jest -- -u",
"dev": "npm run start:dev",
"docker-hub:build": "docker build -f Dockerfile.hub -t ant-design-pro ./",
"docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build",
"docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up",
@@ -24,7 +15,6 @@
"docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up",
"docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro",
"docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro",
"analyze": "cross-env ANALYZE=1 max build",
"gh-pages": "gh-pages -d dist",
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
"postinstall": "max setup",
@@ -38,8 +28,18 @@
"openapi": "max openapi",
"prepare": "cd .. && husky install",
"prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"",
"tsc": "tsc --noEmit",
"record": "cross-env NODE_ENV=development REACT_APP_ENV=test max record --scene=login"
"preview": "npm run build && max preview --port 8000",
"record": "cross-env NODE_ENV=development REACT_APP_ENV=test max record --scene=login",
"serve": "umi-serve",
"start": "cross-env UMI_ENV=dev max dev",
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev",
"start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev",
"start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev",
"start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev",
"test": "jest",
"test:coverage": "npm run jest -- --coverage",
"test:update": "npm run jest -- -u",
"tsc": "tsc --noEmit"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",


+ 13
- 16
react-ui/src/app.tsx View File

@@ -2,7 +2,6 @@ import RightContent from '@/components/RightContent';
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
import type { RunTimeLayoutConfig } from '@umijs/max';
import { history } from '@umijs/max';
import axios from 'axios';
import defaultSettings from '../config/defaultSettings';
import '../public/fonts/font.css';
import { getAccessToken } from './access';
@@ -17,8 +16,7 @@ import {
setRemoteMenu,
} from './services/session';
export { requestConfig as request } from './requestConfig';
axios.defaults.baseUrl = 'http://172.20.32.150:8082';
const isDev = process.env.NODE_ENV === 'development';
// const isDev = process.env.NODE_ENV === 'development';

/**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
@@ -34,10 +32,9 @@ export async function getInitialState(): Promise<{
const response = await getUserInfo({
skipErrorHandler: true,
});
if (response.user.avatar === '') {
response.user.avatar =
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
}
response.user.avatar =
response.user.avatar ||
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
return {
...response.user,
permissions: response.permissions,
@@ -66,7 +63,7 @@ export async function getInitialState(): Promise<{
}

// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
export const layout: RunTimeLayoutConfig = ({ initialState }) => {
return {
rightContentRender: () => <RightContent />,
waterMarkProps: {
@@ -155,26 +152,26 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
};
};

export async function onRouteChange({ clientRoutes, location }) {
export async function onRouteChange({ clientRoutes, location }: any) {
const menus = getRemoteMenu();
// console.log('onRouteChange', clientRoutes, location, menus);
console.log('onRouteChange', clientRoutes, location, menus);
if (menus === null && location.pathname !== PageEnum.LOGIN) {
console.log('refresh');
history.go(0);
}
}

// export function patchRoutes({ routes, routeComponents }) {
// console.log('patchRoutes', routes, routeComponents);
// }
export function patchRoutes({ routes, routeComponents }: any) {
console.log('patchRoutes', routes, routeComponents);
}

export async function patchClientRoutes({ routes }) {
// console.log('patchClientRoutes', routes);
export async function patchClientRoutes({ routes }: any) {
console.log('patchClientRoutes', routes);
patchRouteWithRemoteMenus(routes);
}

export function render(oldRender: () => void) {
// console.log('render get routers', oldRender)
console.log('render get routers', oldRender);
const token = getAccessToken();
if (!token || token?.length === 0) {
oldRender();


+ 78
- 82
react-ui/src/components/DictTag/index.tsx View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Tag } from 'antd';
import { ProSchemaValueEnumType } from '@ant-design/pro-components';
import { Tag } from 'antd';
import { DefaultOptionType } from 'antd/es/select';
import React from 'react';

/* *
*
@@ -11,105 +11,101 @@ import { DefaultOptionType } from 'antd/es/select';
* */

export interface DictValueEnumType extends ProSchemaValueEnumType {
id?: string | number;
key?: string | number;
value: string | number;
label: string;
listClass?: string;
id?: string | number;
key?: string | number;
value: string | number;
label: string;
listClass?: string;
}

export interface DictOptionType extends DefaultOptionType {
id?: string | number;
key?: string | number;
text: string;
listClass?: string;
id?: string | number;
key?: string | number;
text: string;
listClass?: string;
}


export type DictValueEnumObj = Record<string | number, DictValueEnumType>;

export type DictTagProps = {
key?: string;
value?: string | number;
enums?: DictValueEnumObj;
options?: DictOptionType[];
key?: string;
value?: string | number;
enums?: DictValueEnumObj;
options?: DictOptionType[];
};

const DictTag: React.FC<DictTagProps> = (props) => {
function getDictColor(type?: string) {
switch (type) {
case 'primary':
return 'blue';
case 'success':
return 'success';
case 'info':
return 'green';
case 'warning':
return 'warning';
case 'danger':
return 'error';
case 'default':
default:
return 'default';
}
function getDictColor(type?: string) {
switch (type) {
case 'primary':
return 'blue';
case 'success':
return 'success';
case 'info':
return 'green';
case 'warning':
return 'warning';
case 'danger':
return 'error';
case 'default':
default:
return 'default';
}
}

function getDictLabelByValue(value: string | number | undefined): string {
if (value === undefined) {
return '';
}
if (props.enums) {
const item = props.enums[value];
return item.label;
}
if (props.options) {
if (!Array.isArray(props.options)) {
console.log('DictTag options is no array!')
return '';
}
for (const item of props.options) {
if (item.value === value) {
return item.text;
}
}
function getDictLabelByValue(value: string | number | undefined): string {
if (value === undefined) {
return '';
}
if (props.enums) {
const item = props.enums[value];
return item.label;
}
if (props.options) {
if (!Array.isArray(props.options)) {
console.log('DictTag options is no array!');
return '';
}
for (const item of props.options) {
if (item.value === value) {
return item.text;
}
return String(props.value);
}
}
return String(props.value);
}

function getDictListClassByValue(value: string | number | undefined): string {
if (value === undefined) {
return 'default';
}
if (props.enums) {
const item = props.enums[value];
return item.listClass || 'default';
}
if (props.options) {
if (!Array.isArray(props.options)) {
console.log('DictTag options is no array!')
return 'default';
}
for (const item of props.options) {
if (item.value === value) {
return item.listClass || 'default';
}
}
function getDictListClassByValue(value: string | number | undefined): string {
if (value === undefined) {
return 'default';
}
if (props.enums) {
const item = props.enums[value];
return item.listClass || 'default';
}
if (props.options) {
if (!Array.isArray(props.options)) {
console.log('DictTag options is no array!');
return 'default';
}
for (const item of props.options) {
if (item.value === value) {
return item.listClass || 'default';
}
return String(props.value);
}
}
return String(props.value);
}

const getTagColor = () => {
return getDictColor(getDictListClassByValue(props.value).toLowerCase());
};

const getTagText = (): string => {
return getDictLabelByValue(props.value);
};
const getTagColor = () => {
return getDictColor(getDictListClassByValue(props.value).toLowerCase());
};

return (
<Tag color={getTagColor()}>{getTagText()}</Tag>
)
}
const getTagText = (): string => {
return getDictLabelByValue(props.value);
};

return <Tag color={getTagColor()}>{getTagText()}</Tag>;
};

export default DictTag;
export default DictTag;

+ 2
- 2
react-ui/src/components/HeaderDropdown/index.tsx View File

@@ -1,8 +1,8 @@
import { useEmotionCss } from '@ant-design/use-emotion-css';
import { Dropdown } from 'antd';
import type { DropDownProps } from 'antd/es/dropdown';
import React from 'react';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import classNames from 'classnames';
import React from 'react';

export type HeaderDropdownProps = {
overlayClassName?: string;


+ 10
- 9
react-ui/src/components/IconSelector/Category.tsx View File

@@ -1,8 +1,8 @@
import { useIntl } from '@umijs/max';
import * as React from 'react';
import CopyableIcon from './CopyableIcon';
import type { ThemeType } from './index';
import type { CategoriesKeys } from './fields';
import { useIntl } from '@umijs/max';
import type { ThemeType } from './index';
import styles from './style.less';

interface CategoryProps {
@@ -13,8 +13,7 @@ interface CategoryProps {
onSelect: (type: string, name: string) => any;
}

const Category: React.FC<CategoryProps> = props => {

const Category: React.FC<CategoryProps> = (props) => {
const { icons, title, newIcons, theme } = props;
const intl = useIntl();
const [justCopied, setJustCopied] = React.useState<string | null>(null);
@@ -40,12 +39,14 @@ const Category: React.FC<CategoryProps> = props => {

return (
<div>
<h4>{intl.formatMessage({
id: `app.docs.components.icon.category.${title}`,
defaultMessage: '信息',
})}</h4>
<h4>
{intl.formatMessage({
id: `app.docs.components.icon.category.${title}`,
defaultMessage: '信息',
})}
</h4>
<ul className={styles.anticonsList}>
{icons.map(name => (
{icons.map((name) => (
<CopyableIcon
key={name}
name={name}


+ 7
- 10
react-ui/src/components/IconSelector/CopyableIcon.tsx View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import * as AntdIcons from '@ant-design/icons';
import { Tooltip } from 'antd';
import classNames from 'classnames';
import * as AntdIcons from '@ant-design/icons';
import * as React from 'react';
import type { ThemeType } from './index';
import styles from './style.less';

@@ -17,23 +17,20 @@ export interface CopyableIconProps {
onSelect: (type: string, text: string) => any;
}

const CopyableIcon: React.FC<CopyableIconProps> = ({
name,
justCopied,
onSelect,
theme,
}) => {
const CopyableIcon: React.FC<CopyableIconProps> = ({ name, justCopied, onSelect, theme }) => {
const className = classNames({
copied: justCopied === name,
[theme]: !!theme,
});
return (
<li className={className}
<li
className={className}
onClick={() => {
if (onSelect) {
onSelect(theme, name);
}
}}>
}}
>
<Tooltip title={name}>
{React.createElement(allIcons[name], { className: styles.anticon })}
</Tooltip>


+ 30
- 27
react-ui/src/components/IconSelector/IconPicSearcher.tsx View File

@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Upload, Tooltip, Popover, Modal, Progress, Spin, Result } from 'antd';
import * as AntdIcons from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Modal, Popover, Progress, Result, Spin, Tooltip, Upload } from 'antd';
import React, { useCallback, useEffect, useState } from 'react';
import './style.less';

const allIcons: { [key: string]: any } = AntdIcons;
@@ -34,7 +34,7 @@ interface iconObject {

const PicSearcher: React.FC = () => {
const intl = useIntl();
const {formatMessage} = intl;
const { formatMessage } = intl;
const [state, setState] = useState<PicSearcherState>({
loading: false,
modalOpen: false,
@@ -53,15 +53,15 @@ const PicSearcher: React.FC = () => {
event_label: icons[0].className,
});
}
icons = icons.map(i => ({ score: i.score, type: i.className.replace(/\s/g, '-') }));
setState(prev => ({ ...prev, loading: false, error: false, icons }));
icons = icons.map((i) => ({ score: i.score, type: i.className.replace(/\s/g, '-') }));
setState((prev) => ({ ...prev, loading: false, error: false, icons }));
} catch {
setState(prev => ({ ...prev, loading: false, error: true }));
setState((prev) => ({ ...prev, loading: false, error: true }));
}
};
// eslint-disable-next-line class-methods-use-this
const toImage = (url: string) =>
new Promise(resolve => {
new Promise((resolve) => {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;
@@ -71,11 +71,11 @@ const PicSearcher: React.FC = () => {
});

const uploadFile = useCallback((file: File) => {
setState(prev => ({ ...prev, loading: true }));
setState((prev) => ({ ...prev, loading: true }));
const reader = new FileReader();
reader.onload = () => {
toImage(reader.result as string).then(predict);
setState(prev => ({
setState((prev) => ({
...prev,
fileList: [{ uid: 1, name: file.name, status: 'done', url: reader.result }],
}));
@@ -99,7 +99,7 @@ const PicSearcher: React.FC = () => {
}
}, []);
const toggleModal = useCallback(() => {
setState(prev => ({
setState((prev) => ({
...prev,
modalOpen: !prev.modalOpen,
popoverVisible: false,
@@ -115,12 +115,12 @@ const PicSearcher: React.FC = () => {
const script = document.createElement('script');
script.onload = async () => {
await window.antdIconClassifier.load();
setState(prev => ({ ...prev, modelLoaded: true }));
setState((prev) => ({ ...prev, modelLoaded: true }));
document.addEventListener('paste', onPaste);
};
script.src = 'https://cdn.jsdelivr.net/gh/lewis617/antd-icon-classifier@0.0/dist/main.js';
document.head.appendChild(script);
setState(prev => ({ ...prev, popoverVisible: !localStorage.getItem('disableIconTip') }));
setState((prev) => ({ ...prev, popoverVisible: !localStorage.getItem('disableIconTip') }));
return () => {
document.removeEventListener('paste', onPaste);
};
@@ -129,7 +129,7 @@ const PicSearcher: React.FC = () => {
return (
<div className="iconPicSearcher">
<Popover
content={formatMessage({id: 'app.docs.components.icon.pic-searcher.intro'})}
content={formatMessage({ id: 'app.docs.components.icon.pic-searcher.intro' })}
open={state.popoverVisible}
>
<AntdIcons.CameraOutlined className="icon-pic-btn" onClick={toggleModal} />
@@ -148,7 +148,6 @@ const PicSearcher: React.FC = () => {
spinning={!state.modelLoaded}
tip={formatMessage({
id: 'app.docs.components.icon.pic-searcher.modelloading',

})}
>
<div style={{ height: 100 }} />
@@ -158,7 +157,7 @@ const PicSearcher: React.FC = () => {
<Dragger
accept="image/jpeg, image/png"
listType="picture"
customRequest={o => uploadFile(o.file as File)}
customRequest={(o) => uploadFile(o.file as File)}
fileList={state.fileList}
showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }}
>
@@ -166,21 +165,21 @@ const PicSearcher: React.FC = () => {
<AntdIcons.InboxOutlined />
</p>
<p className="ant-upload-text">
{formatMessage({id: 'app.docs.components.icon.pic-searcher.upload-text'})}
{formatMessage({ id: 'app.docs.components.icon.pic-searcher.upload-text' })}
</p>
<p className="ant-upload-hint">
{formatMessage({id: 'app.docs.components.icon.pic-searcher.upload-hint'})}
{formatMessage({ id: 'app.docs.components.icon.pic-searcher.upload-hint' })}
</p>
</Dragger>
)}
<Spin
spinning={state.loading}
tip={formatMessage({id: 'app.docs.components.icon.pic-searcher.matching'})}
tip={formatMessage({ id: 'app.docs.components.icon.pic-searcher.matching' })}
>
<div className="icon-pic-search-result">
{state.icons.length > 0 && (
<div className="result-tip">
{formatMessage({id: 'app.docs.components.icon.pic-searcher.result-tip'})}
{formatMessage({ id: 'app.docs.components.icon.pic-searcher.result-tip' })}
</div>
)}
<table>
@@ -188,25 +187,27 @@ const PicSearcher: React.FC = () => {
<thead>
<tr>
<th className="col-icon">
{formatMessage({id: 'app.docs.components.icon.pic-searcher.th-icon'})}
{formatMessage({ id: 'app.docs.components.icon.pic-searcher.th-icon' })}
</th>
<th>
{formatMessage({ id: 'app.docs.components.icon.pic-searcher.th-score' })}
</th>
<th>{formatMessage({id: 'app.docs.components.icon.pic-searcher.th-score'})}</th>
</tr>
</thead>
)}
<tbody>
{state.icons.map(icon => {
{state.icons.map((icon) => {
const { type } = icon;
const iconName = `${type
.split('-')
.map(str => `${str[0].toUpperCase()}${str.slice(1)}`)
.map((str) => `${str[0].toUpperCase()}${str.slice(1)}`)
.join('')}Outlined`;
return (
<tr key={iconName}>
<td className="col-icon">
<Tooltip title={icon.type} placement="right">
{React.createElement(allIcons[iconName])}
</Tooltip>
<Tooltip title={icon.type} placement="right">
{React.createElement(allIcons[iconName])}
</Tooltip>
</td>
<td>
<Progress percent={Math.ceil(icon.score * 100)} />
@@ -220,7 +221,9 @@ const PicSearcher: React.FC = () => {
<Result
status="500"
title="503"
subTitle={formatMessage({id: 'app.docs.components.icon.pic-searcher.server-error'})}
subTitle={formatMessage({
id: 'app.docs.components.icon.pic-searcher.server-error',
})}
/>
)}
</div>


+ 2
- 2
react-ui/src/components/IconSelector/fields.ts View File

@@ -1,7 +1,7 @@
import * as AntdIcons from '@ant-design/icons/lib/icons';

const all = Object.keys(AntdIcons)
.map(n => n.replace(/(Outlined|Filled|TwoTone)$/, ''))
.map((n) => n.replace(/(Outlined|Filled|TwoTone)$/, ''))
.filter((n, i, arr) => arr.indexOf(n) === i);

const direction = [
@@ -206,7 +206,7 @@ const logo = [

const datum = [...direction, ...suggestion, ...editor, ...data, ...logo];

const other = all.filter(n => !datum.includes(n));
const other = all.filter((n) => !datum.includes(n));

export const categories = {
direction,


+ 18
- 14
react-ui/src/components/IconSelector/index.tsx View File

@@ -1,13 +1,13 @@
import * as React from 'react';
import Icon, * as AntdIcons from '@ant-design/icons';
import { Radio, Input, Empty } from 'antd';
import { Empty, Input, Radio } from 'antd';
import type { RadioChangeEvent } from 'antd/es/radio/interface';
import debounce from 'lodash/debounce';
import * as React from 'react';
import Category from './Category';
import IconPicSearcher from './IconPicSearcher';
import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons';
import type { CategoriesKeys } from './fields';
import { categories } from './fields';
import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons';
// import { useIntl } from '@umijs/max';

export enum ThemeType {
@@ -41,13 +41,13 @@ const IconSelector: React.FC<IconSelectorProps> = (props) => {

const handleSearchIcon = React.useCallback(
debounce((searchKey: string) => {
setDisplayState(prevState => ({ ...prevState, searchKey }));
setDisplayState((prevState) => ({ ...prevState, searchKey }));
}),
[],
);

const handleChangeTheme = React.useCallback((e: RadioChangeEvent) => {
setDisplayState(prevState => ({ ...prevState, theme: e.target.value as ThemeType }));
setDisplayState((prevState) => ({ ...prevState, theme: e.target.value as ThemeType }));
}, []);

const renderCategories = React.useMemo<React.ReactNode | React.ReactNode[]>(() => {
@@ -62,15 +62,19 @@ const IconSelector: React.FC<IconSelectorProps> = (props) => {
.replace(new RegExp(`^<([a-zA-Z]*)\\s/>$`, 'gi'), (_, name) => name)
.replace(/(Filled|Outlined|TwoTone)$/, '')
.toLowerCase();
iconList = iconList.filter((iconName:string) => iconName.toLowerCase().includes(matchKey));
iconList = iconList.filter((iconName: string) =>
iconName.toLowerCase().includes(matchKey),
);
}

// CopyrightCircle is same as Copyright, don't show it
iconList = iconList.filter((icon:string) => icon !== 'CopyrightCircle');
iconList = iconList.filter((icon: string) => icon !== 'CopyrightCircle');

return {
category: key,
icons: iconList.map((iconName:string) => iconName + theme).filter((iconName:string) => allIcons[iconName]),
icons: iconList
.map((iconName: string) => iconName + theme)
.filter((iconName: string) => allIcons[iconName]),
};
})
.filter(({ icons }) => !!icons.length)
@@ -101,16 +105,16 @@ const IconSelector: React.FC<IconSelectorProps> = (props) => {
buttonStyle="solid"
options={[
{
label: <Icon component={OutlinedIcon} />,
value: ThemeType.Outlined
label: <Icon component={OutlinedIcon} />,
value: ThemeType.Outlined,
},
{
label: <Icon component={FilledIcon} />,
value: ThemeType.Filled
value: ThemeType.Filled,
},
{
label: <Icon component={TwoToneIcon} />,
value: ThemeType.TwoTone
value: ThemeType.TwoTone,
},
]}
>
@@ -128,7 +132,7 @@ const IconSelector: React.FC<IconSelectorProps> = (props) => {
// placeholder={messages['app.docs.components.icon.search.placeholder']}
style={{ margin: '0 10px', flex: 1 }}
allowClear
onChange={e => handleSearchIcon(e.currentTarget.value)}
onChange={(e) => handleSearchIcon(e.currentTarget.value)}
size="large"
autoFocus
suffix={<IconPicSearcher />}
@@ -139,4 +143,4 @@ const IconSelector: React.FC<IconSelectorProps> = (props) => {
);
};

export default IconSelector
export default IconSelector;

+ 3
- 4
react-ui/src/components/IconSelector/themeIcons.tsx View File

@@ -1,7 +1,6 @@
import * as React from 'react';


export const FilledIcon: React.FC = props => {
export const FilledIcon: React.FC = (props) => {
const path =
'M864 64H160C107 64 64 107 64 160v' +
'704c0 53 43 96 96 96h704c53 0 96-43 96-96V16' +
@@ -13,7 +12,7 @@ export const FilledIcon: React.FC = props => {
);
};

export const OutlinedIcon: React.FC = props => {
export const OutlinedIcon: React.FC = (props) => {
const path =
'M864 64H160C107 64 64 107 64 160v7' +
'04c0 53 43 96 96 96h704c53 0 96-43 96-96V160c' +
@@ -27,7 +26,7 @@ export const OutlinedIcon: React.FC = props => {
);
};

export const TwoToneIcon: React.FC = props => {
export const TwoToneIcon: React.FC = (props) => {
const path =
'M16 512c0 273.932 222.066 496 496 49' +
'6s496-222.068 496-496S785.932 16 512 16 16 238.' +


+ 5
- 5
react-ui/src/components/RightContent/AvatarDropdown.tsx View File

@@ -1,17 +1,17 @@
import { clearSessionToken } from '@/access';
import { PageEnum } from '@/enums/pagesEnums';
import { setRemoteMenu } from '@/services/session';
import { logout } from '@/services/system/auth';
import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
import { setAlpha } from '@ant-design/pro-components';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import { history, useModel } from '@umijs/max';
import { Avatar, Spin } from 'antd';
import { setAlpha } from '@ant-design/pro-components';
import { stringify } from 'querystring';
import type { MenuInfo } from 'rc-menu/lib/interface';
import React, { useCallback } from 'react';
import { flushSync } from 'react-dom';
import HeaderDropdown from '../HeaderDropdown';
import { setRemoteMenu } from '@/services/session';
import { PageEnum } from '@/enums/pagesEnums';
import { clearSessionToken } from '@/access';
import { logout } from '@/services/system/auth';

export type GlobalHeaderRightProps = {
menu?: boolean;


+ 2
- 3
react-ui/src/enums/pagesEnums.ts View File

@@ -1,4 +1,3 @@

export enum PageEnum {
LOGIN = '/user/login'
}
LOGIN = '/user/login',
}

+ 0
- 1
react-ui/src/enums/status.d.ts View File

@@ -1 +0,0 @@


+ 26
- 30
react-ui/src/global.less View File

@@ -19,8 +19,8 @@ body,
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
left: unset;
}
.ant-layout-sider-children{
margin-top: 60px!important;
.ant-layout-sider-children {
margin-top: 60px !important;
}
canvas {
display: block;
@@ -31,67 +31,65 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.ant-pro-layout .ant-pro-layout-content{
.ant-pro-layout .ant-pro-layout-content {
padding: 10px;
}
.ant-pro-layout .ant-pro-layout-bg-list{
background:#f9fafb;
.ant-pro-layout .ant-pro-layout-bg-list {
background: #f9fafb;
}
.ant-table-wrapper .ant-table-thead >tr>th{
.ant-table-wrapper .ant-table-thead > tr > th {
background-color: #fff;
}
.ant-table-wrapper .ant-table-thead >tr>td{
.ant-table-wrapper .ant-table-thead > tr > td {
background-color: #fff;
}
.ant-menu-light .ant-menu-item-selected{
background:rgba(197, 232, 255, 0.8)!important;
.ant-menu-light .ant-menu-item-selected {
background: rgba(197, 232, 255, 0.8) !important;
}
.ant-pro-base-menu-inline{
.ant-pro-base-menu-inline {
// height: 87vh;
background:#f2f5f7;
border-radius:0px 20px 20px 0px;
background: #f2f5f7;
border-radius: 0px 20px 20px 0px;
}
.ant-pro-layout .ant-pro-layout-content{
.ant-pro-layout .ant-pro-layout-content {
background-color: transparent;
}

.ant-pro-global-header-logo img{
.ant-pro-global-header-logo img {
height: 21px;
}
.ant-pro-layout .ant-layout-sider.ant-pro-sider{
.ant-pro-layout .ant-layout-sider.ant-pro-sider {
height: 87vh;
}
.ant-pro-layout .ant-pro-layout-container{
.ant-pro-layout .ant-pro-layout-container {
height: 98vh;
}
.ant-pagination .ant-pagination-item-active a{
background:#1664ff;
.ant-pagination .ant-pagination-item-active a {
color: #fff;
background: #1664ff;
border-color: #1664ff;
}
.ant-pagination .ant-pagination-item-active a:hover{
background:rgba(22, 100, 255, 0.8);
.ant-pagination .ant-pagination-item-active a:hover {
color: #fff;
background: rgba(22, 100, 255, 0.8);
border-color: rgba(22, 100, 255, 0.8);
}
// ::-webkit-scrollbar-button {
// background: #97a1bd;
// }
::-webkit-scrollbar{
width:9px;
::-webkit-scrollbar {
width: 9px;
border-radius: 2px;
}
::-webkit-scrollbar-thumb{
::-webkit-scrollbar-thumb {
// background-color: #9aa3bc!important;
width: 7px;
background:rgba(77, 87, 123,0.5)!important;
background: rgba(77, 87, 123, 0.5) !important;
}
::-webkit-scrollbar-track{
::-webkit-scrollbar-track {
// background-color: #eaf1ff!important;
width: 9px;
background:rgba(22, 100, 255,0.06)!important;
background: rgba(22, 100, 255, 0.06) !important;
}
ul,
ol {
@@ -114,5 +112,3 @@ ol {
}
}
}



+ 24
- 24
react-ui/src/locales/en-US/app.ts View File

@@ -1,26 +1,26 @@
export default {
'app.docs.components.icon.search.placeholder': 'Search icons here, click icon to copy code',
'app.docs.components.icon.outlined': 'Outlined',
'app.docs.components.icon.filled': 'Filled',
'app.docs.components.icon.two-tone': 'Two Tone',
'app.docs.components.icon.category.direction': 'Directional Icons',
'app.docs.components.icon.category.suggestion': 'Suggested Icons',
'app.docs.components.icon.category.editor': 'Editor Icons',
'app.docs.components.icon.category.data': 'Data Icons',
'app.docs.components.icon.category.other': 'Application Icons',
'app.docs.components.icon.category.logo': 'Brand and Logos',
'app.docs.components.icon.pic-searcher.intro':
'AI Search by image is online, you are welcome to use it! 🎉',
'app.docs.components.icon.pic-searcher.title': 'Search by image',
'app.docs.components.icon.pic-searcher.upload-text':
'Click, drag, or paste file to this area to upload',
'app.docs.components.icon.pic-searcher.upload-hint':
'We will find the best matching icon based on the image provided',
'app.docs.components.icon.pic-searcher.server-error':
'Predict service is temporarily unavailable',
'app.docs.components.icon.pic-searcher.matching': 'Matching...',
'app.docs.components.icon.pic-searcher.modelloading': 'Model is loading...',
'app.docs.components.icon.pic-searcher.result-tip': 'Matched the following icons for you:',
'app.docs.components.icon.pic-searcher.th-icon': 'Icon',
'app.docs.components.icon.pic-searcher.th-score': 'Probability',
'app.docs.components.icon.search.placeholder': 'Search icons here, click icon to copy code',
'app.docs.components.icon.outlined': 'Outlined',
'app.docs.components.icon.filled': 'Filled',
'app.docs.components.icon.two-tone': 'Two Tone',
'app.docs.components.icon.category.direction': 'Directional Icons',
'app.docs.components.icon.category.suggestion': 'Suggested Icons',
'app.docs.components.icon.category.editor': 'Editor Icons',
'app.docs.components.icon.category.data': 'Data Icons',
'app.docs.components.icon.category.other': 'Application Icons',
'app.docs.components.icon.category.logo': 'Brand and Logos',
'app.docs.components.icon.pic-searcher.intro':
'AI Search by image is online, you are welcome to use it! 🎉',
'app.docs.components.icon.pic-searcher.title': 'Search by image',
'app.docs.components.icon.pic-searcher.upload-text':
'Click, drag, or paste file to this area to upload',
'app.docs.components.icon.pic-searcher.upload-hint':
'We will find the best matching icon based on the image provided',
'app.docs.components.icon.pic-searcher.server-error':
'Predict service is temporarily unavailable',
'app.docs.components.icon.pic-searcher.matching': 'Matching...',
'app.docs.components.icon.pic-searcher.modelloading': 'Model is loading...',
'app.docs.components.icon.pic-searcher.result-tip': 'Matched the following icons for you:',
'app.docs.components.icon.pic-searcher.th-icon': 'Icon',
'app.docs.components.icon.pic-searcher.th-score': 'Probability',
};

+ 12
- 12
react-ui/src/locales/zh-CN.ts View File

@@ -2,25 +2,25 @@ import app from './zh-CN/app';
import component from './zh-CN/component';
import globalHeader from './zh-CN/globalHeader';
import sysmenu from './zh-CN/menu';
import job from './zh-CN/monitor/job';
import joblog from './zh-CN/monitor/job-log';
import logininfor from './zh-CN/monitor/logininfor';
import onlineUser from './zh-CN/monitor/onlineUser';
import operlog from './zh-CN/monitor/operlog';
import server from './zh-CN/monitor/server';
import pages from './zh-CN/pages';
import pwa from './zh-CN/pwa';
import settingDrawer from './zh-CN/settingDrawer';
import settings from './zh-CN/settings';
import user from './zh-CN/system/user';
import menu from './zh-CN/system/menu';
import config from './zh-CN/system/config';
import dept from './zh-CN/system/dept';
import dict from './zh-CN/system/dict';
import dictData from './zh-CN/system/dict-data';
import role from './zh-CN/system/role';
import dept from './zh-CN/system/dept';
import post from './zh-CN/system/post';
import config from './zh-CN/system/config';
import menu from './zh-CN/system/menu';
import notice from './zh-CN/system/notice';
import operlog from './zh-CN/monitor/operlog';
import logininfor from './zh-CN/monitor/logininfor';
import onlineUser from './zh-CN/monitor/onlineUser';
import job from './zh-CN/monitor/job';
import joblog from './zh-CN/monitor/job-log';
import server from './zh-CN/monitor/server';
import post from './zh-CN/system/post';
import role from './zh-CN/system/role';
import user from './zh-CN/system/user';

export default {
'navBar.lang': '语言',


+ 10
- 10
react-ui/src/locales/zh-CN/monitor/job-log.ts View File

@@ -1,18 +1,18 @@
/**
* 定时任务调度日志
*
*
* @author whiteshader
* @date 2023-02-07
*/

export default {
'monitor.job.log.title': '定时任务调度日志',
'monitor.job.log.job_log_id': '任务日志编号',
'monitor.job.log.job_name': '任务名称',
'monitor.job.log.job_group': '任务组名',
'monitor.job.log.invoke_target': '调用方法',
'monitor.job.log.job_message': '日志信息',
'monitor.job.log.status': '执行状态',
'monitor.job.log.exception_info': '异常信息',
'monitor.job.log.create_time': '创建时间',
'monitor.job.log.title': '定时任务调度日志',
'monitor.job.log.job_log_id': '任务日志编号',
'monitor.job.log.job_name': '任务名称',
'monitor.job.log.job_group': '任务组名',
'monitor.job.log.invoke_target': '调用方法',
'monitor.job.log.job_message': '日志信息',
'monitor.job.log.status': '执行状态',
'monitor.job.log.exception_info': '异常信息',
'monitor.job.log.create_time': '创建时间',
};

+ 17
- 17
react-ui/src/locales/zh-CN/monitor/job.ts View File

@@ -1,25 +1,25 @@
/**
* 定时任务调度
*
*
* @author whiteshader@163.com
* @date 2023-02-07
*/

export default {
'monitor.job.title': '定时任务调度',
'monitor.job.job_id': '任务编号',
'monitor.job.job_name': '任务名称',
'monitor.job.job_group': '任务组名',
'monitor.job.invoke_target': '调用方法',
'monitor.job.cron_expression': 'cron执行表达式',
'monitor.job.misfire_policy': '执行策略',
'monitor.job.concurrent': '是否并发执行',
'monitor.job.next_valid_time': '下次执行时间',
'monitor.job.status': '状态',
'monitor.job.create_by': '创建者',
'monitor.job.create_time': '创建时间',
'monitor.job.update_by': '更新者',
'monitor.job.update_time': '更新时间',
'monitor.job.remark': '备注信息',
'monitor.job.detail': '任务详情',
'monitor.job.title': '定时任务调度',
'monitor.job.job_id': '任务编号',
'monitor.job.job_name': '任务名称',
'monitor.job.job_group': '任务组名',
'monitor.job.invoke_target': '调用方法',
'monitor.job.cron_expression': 'cron执行表达式',
'monitor.job.misfire_policy': '执行策略',
'monitor.job.concurrent': '是否并发执行',
'monitor.job.next_valid_time': '下次执行时间',
'monitor.job.status': '状态',
'monitor.job.create_by': '创建者',
'monitor.job.create_time': '创建时间',
'monitor.job.update_by': '更新者',
'monitor.job.update_time': '更新时间',
'monitor.job.remark': '备注信息',
'monitor.job.detail': '任务详情',
};

+ 11
- 11
react-ui/src/locales/zh-CN/monitor/logininfor.ts View File

@@ -1,13 +1,13 @@
export default {
'monitor.logininfor.title': '系统访问记录',
'monitor.logininfor.info_id': '访问编号',
'monitor.logininfor.user_name': '用户账号',
'monitor.logininfor.ipaddr': '登录IP地址',
'monitor.logininfor.login_location': '登录地点',
'monitor.logininfor.browser': '浏览器类型',
'monitor.logininfor.os': '操作系统',
'monitor.logininfor.status': '登录状态',
'monitor.logininfor.msg': '提示消息',
'monitor.logininfor.login_time': '访问时间',
'monitor.logininfor.unlock': '解锁',
'monitor.logininfor.title': '系统访问记录',
'monitor.logininfor.info_id': '访问编号',
'monitor.logininfor.user_name': '用户账号',
'monitor.logininfor.ipaddr': '登录IP地址',
'monitor.logininfor.login_location': '登录地点',
'monitor.logininfor.browser': '浏览器类型',
'monitor.logininfor.os': '操作系统',
'monitor.logininfor.status': '登录状态',
'monitor.logininfor.msg': '提示消息',
'monitor.logininfor.login_time': '访问时间',
'monitor.logininfor.unlock': '解锁',
};

+ 1
- 2
react-ui/src/locales/zh-CN/monitor/onlineUser.ts View File

@@ -1,9 +1,8 @@

/* *
*
* @author whiteshader@163.com
* @datetime 2021/09/16
*
*
* */

export default {


+ 17
- 17
react-ui/src/locales/zh-CN/monitor/operlog.ts View File

@@ -1,19 +1,19 @@
export default {
'monitor.operlog.title': '操作日志记录',
'monitor.operlog.oper_id': '日志主键',
'monitor.operlog.business_type': '业务类型',
'monitor.operlog.method': '方法名称',
'monitor.operlog.request_method': '请求方式',
'monitor.operlog.operator_type': '操作类别',
'monitor.operlog.oper_name': '操作人员',
'monitor.operlog.dept_name': '部门名称',
'monitor.operlog.oper_url': '请求URL',
'monitor.operlog.oper_ip': '主机地址',
'monitor.operlog.oper_location': '操作地点',
'monitor.operlog.oper_param': '请求参数',
'monitor.operlog.json_result': '返回参数',
'monitor.operlog.status': '操作状态',
'monitor.operlog.error_msg': '错误消息',
'monitor.operlog.oper_time': '操作时间',
'monitor.operlog.module': '操作模块',
'monitor.operlog.title': '操作日志记录',
'monitor.operlog.oper_id': '日志主键',
'monitor.operlog.business_type': '业务类型',
'monitor.operlog.method': '方法名称',
'monitor.operlog.request_method': '请求方式',
'monitor.operlog.operator_type': '操作类别',
'monitor.operlog.oper_name': '操作人员',
'monitor.operlog.dept_name': '部门名称',
'monitor.operlog.oper_url': '请求URL',
'monitor.operlog.oper_ip': '主机地址',
'monitor.operlog.oper_location': '操作地点',
'monitor.operlog.oper_param': '请求参数',
'monitor.operlog.json_result': '返回参数',
'monitor.operlog.status': '操作状态',
'monitor.operlog.error_msg': '错误消息',
'monitor.operlog.oper_time': '操作时间',
'monitor.operlog.module': '操作模块',
};

+ 1
- 2
react-ui/src/locales/zh-CN/monitor/server.ts View File

@@ -1,9 +1,8 @@

/* *
*
* @author whiteshader@163.com
* @datetime 2021/09/16
*
*
* */

export default {


+ 12
- 12
react-ui/src/locales/zh-CN/system/config.ts View File

@@ -1,14 +1,14 @@
export default {
'system.config.title': '参数配置',
'system.config.config_id': '参数主键',
'system.config.config_name': '参数名称',
'system.config.config_key': '参数键名',
'system.config.config_value': '参数键值',
'system.config.config_type': '系统内置',
'system.config.create_by': '创建者',
'system.config.create_time': '创建时间',
'system.config.update_by': '更新者',
'system.config.update_time': '更新时间',
'system.config.remark': '备注',
'system.config.refreshCache': '刷新缓存',
'system.config.title': '参数配置',
'system.config.config_id': '参数主键',
'system.config.config_name': '参数名称',
'system.config.config_key': '参数键名',
'system.config.config_value': '参数键值',
'system.config.config_type': '系统内置',
'system.config.create_by': '创建者',
'system.config.create_time': '创建时间',
'system.config.update_by': '更新者',
'system.config.update_time': '更新时间',
'system.config.remark': '备注',
'system.config.refreshCache': '刷新缓存',
};

+ 16
- 16
react-ui/src/locales/zh-CN/system/dept.ts View File

@@ -1,18 +1,18 @@
export default {
'system.dept.title': '部门',
'system.dept.dept_id': '部门id',
'system.dept.parent_id': '父部门id',
'system.dept.parent_dept': '上级部门',
'system.dept.ancestors': '祖级列表',
'system.dept.dept_name': '部门名称',
'system.dept.order_num': '显示顺序',
'system.dept.leader': '负责人',
'system.dept.phone': '联系电话',
'system.dept.email': '邮箱',
'system.dept.status': '部门状态',
'system.dept.del_flag': '删除标志',
'system.dept.create_by': '创建者',
'system.dept.create_time': '创建时间',
'system.dept.update_by': '更新者',
'system.dept.update_time': '更新时间',
'system.dept.title': '部门',
'system.dept.dept_id': '部门id',
'system.dept.parent_id': '父部门id',
'system.dept.parent_dept': '上级部门',
'system.dept.ancestors': '祖级列表',
'system.dept.dept_name': '部门名称',
'system.dept.order_num': '显示顺序',
'system.dept.leader': '负责人',
'system.dept.phone': '联系电话',
'system.dept.email': '邮箱',
'system.dept.status': '部门状态',
'system.dept.del_flag': '删除标志',
'system.dept.create_by': '创建者',
'system.dept.create_time': '创建时间',
'system.dept.update_by': '更新者',
'system.dept.update_time': '更新时间',
};

+ 20
- 20
react-ui/src/locales/zh-CN/system/menu.ts View File

@@ -1,22 +1,22 @@
export default {
'system.menu.title': '菜单权限',
'system.menu.menu_id': '菜单编号',
'system.menu.menu_name': '菜单名称',
'system.menu.parent_id': '上级菜单',
'system.menu.order_num': '显示顺序',
'system.menu.path': '路由地址',
'system.menu.component': '组件路径',
'system.menu.query': '路由参数',
'system.menu.is_frame': '是否为外链',
'system.menu.is_cache': '是否缓存',
'system.menu.menu_type': '菜单类型',
'system.menu.visible': '显示状态',
'system.menu.status': '菜单状态',
'system.menu.perms': '权限标识',
'system.menu.icon': '菜单图标',
'system.menu.create_by': '创建者',
'system.menu.create_time': '创建时间',
'system.menu.update_by': '更新者',
'system.menu.update_time': '更新时间',
'system.menu.remark': '备注',
'system.menu.title': '菜单权限',
'system.menu.menu_id': '菜单编号',
'system.menu.menu_name': '菜单名称',
'system.menu.parent_id': '上级菜单',
'system.menu.order_num': '显示顺序',
'system.menu.path': '路由地址',
'system.menu.component': '组件路径',
'system.menu.query': '路由参数',
'system.menu.is_frame': '是否为外链',
'system.menu.is_cache': '是否缓存',
'system.menu.menu_type': '菜单类型',
'system.menu.visible': '显示状态',
'system.menu.status': '菜单状态',
'system.menu.perms': '权限标识',
'system.menu.icon': '菜单图标',
'system.menu.create_by': '创建者',
'system.menu.create_time': '创建时间',
'system.menu.update_by': '更新者',
'system.menu.update_time': '更新时间',
'system.menu.remark': '备注',
};

+ 11
- 11
react-ui/src/locales/zh-CN/system/notice.ts View File

@@ -1,13 +1,13 @@
export default {
'system.notice.title': '通知公告',
'system.notice.notice_id': '公告编号',
'system.notice.notice_title': '公告标题',
'system.notice.notice_type': '公告类型',
'system.notice.notice_content': '公告内容',
'system.notice.status': '公告状态',
'system.notice.create_by': '创建者',
'system.notice.create_time': '创建时间',
'system.notice.update_by': '更新者',
'system.notice.update_time': '更新时间',
'system.notice.remark': '备注',
'system.notice.title': '通知公告',
'system.notice.notice_id': '公告编号',
'system.notice.notice_title': '公告标题',
'system.notice.notice_type': '公告类型',
'system.notice.notice_content': '公告内容',
'system.notice.status': '公告状态',
'system.notice.create_by': '创建者',
'system.notice.create_time': '创建时间',
'system.notice.update_by': '更新者',
'system.notice.update_time': '更新时间',
'system.notice.remark': '备注',
};

+ 11
- 11
react-ui/src/locales/zh-CN/system/post.ts View File

@@ -1,13 +1,13 @@
export default {
'system.post.title': '岗位信息',
'system.post.post_id': '岗位编号',
'system.post.post_code': '岗位编码',
'system.post.post_name': '岗位名称',
'system.post.post_sort': '显示顺序',
'system.post.status': '状态',
'system.post.create_by': '创建者',
'system.post.create_time': '创建时间',
'system.post.update_by': '更新者',
'system.post.update_time': '更新时间',
'system.post.remark': '备注',
'system.post.title': '岗位信息',
'system.post.post_id': '岗位编号',
'system.post.post_code': '岗位编码',
'system.post.post_name': '岗位名称',
'system.post.post_sort': '显示顺序',
'system.post.status': '状态',
'system.post.create_by': '创建者',
'system.post.create_time': '创建时间',
'system.post.update_by': '更新者',
'system.post.update_time': '更新时间',
'system.post.remark': '备注',
};

+ 19
- 19
react-ui/src/locales/zh-CN/system/role.ts View File

@@ -1,21 +1,21 @@
export default {
'system.role.title': '角色信息',
'system.role.role_id': '角色编号',
'system.role.role_name': '角色名称',
'system.role.role_key': '权限字符',
'system.role.role_sort': '显示顺序',
'system.role.data_scope': '数据范围',
'system.role.menu_check_strictly': '菜单树选择项是否关联显示',
'system.role.dept_check_strictly': '部门树选择项是否关联显示',
'system.role.status': '角色状态',
'system.role.del_flag': '删除标志',
'system.role.create_by': '创建者',
'system.role.create_time': '创建时间',
'system.role.update_by': '更新者',
'system.role.update_time': '更新时间',
'system.role.remark': '备注',
'system.role.auth': '菜单权限',
'system.role.auth.user': '选择用户',
'system.role.auth.addUser': '添加用户',
'system.role.auth.cancelAll': '批量取消授权',
'system.role.title': '角色信息',
'system.role.role_id': '角色编号',
'system.role.role_name': '角色名称',
'system.role.role_key': '权限字符',
'system.role.role_sort': '显示顺序',
'system.role.data_scope': '数据范围',
'system.role.menu_check_strictly': '菜单树选择项是否关联显示',
'system.role.dept_check_strictly': '部门树选择项是否关联显示',
'system.role.status': '角色状态',
'system.role.del_flag': '删除标志',
'system.role.create_by': '创建者',
'system.role.create_time': '创建时间',
'system.role.update_by': '更新者',
'system.role.update_time': '更新时间',
'system.role.remark': '备注',
'system.role.auth': '菜单权限',
'system.role.auth.user': '选择用户',
'system.role.auth.addUser': '添加用户',
'system.role.auth.cancelAll': '批量取消授权',
};

+ 29
- 29
react-ui/src/locales/zh-CN/system/user.ts View File

@@ -1,31 +1,31 @@
export default {
'system.user.title': '用户信息',
'system.user.user_id': '用户编号',
'system.user.dept_name': '部门',
'system.user.user_name': '用户账号',
'system.user.nick_name': '用户昵称',
'system.user.user_type': '用户类型',
'system.user.email': '用户邮箱',
'system.user.phonenumber': '手机号码',
'system.user.sex': '用户性别',
'system.user.avatar': '头像地址',
'system.user.password': '密码',
'system.user.status': '帐号状态',
'system.user.del_flag': '删除标志',
'system.user.login_ip': '最后登录IP',
'system.user.login_date': '最后登录时间',
'system.user.create_by': '创建者',
'system.user.create_time': '创建时间',
'system.user.update_by': '更新者',
'system.user.update_time': '更新时间',
'system.user.remark': '备注',
'system.user.post': '岗位',
'system.user.role': '角色',
'system.user.auth.role': '分配角色',
'system.user.reset.password': '密码重置',
'system.user.modify_info': '编辑用户信息',
'system.user.old_password': '旧密码',
'system.user.new_password': '新密码',
'system.user.confirm_password': '确认密码',
'system.user.modify_avatar': '修改头像',
'system.user.title': '用户信息',
'system.user.user_id': '用户编号',
'system.user.dept_name': '部门',
'system.user.user_name': '用户账号',
'system.user.nick_name': '用户昵称',
'system.user.user_type': '用户类型',
'system.user.email': '用户邮箱',
'system.user.phonenumber': '手机号码',
'system.user.sex': '用户性别',
'system.user.avatar': '头像地址',
'system.user.password': '密码',
'system.user.status': '帐号状态',
'system.user.del_flag': '删除标志',
'system.user.login_ip': '最后登录IP',
'system.user.login_date': '最后登录时间',
'system.user.create_by': '创建者',
'system.user.create_time': '创建时间',
'system.user.update_by': '更新者',
'system.user.update_time': '更新时间',
'system.user.remark': '备注',
'system.user.post': '岗位',
'system.user.role': '角色',
'system.user.auth.role': '分配角色',
'system.user.reset.password': '密码重置',
'system.user.modify_info': '编辑用户信息',
'system.user.old_password': '旧密码',
'system.user.new_password': '新密码',
'system.user.confirm_password': '确认密码',
'system.user.modify_avatar': '修改头像',
};

+ 284
- 192
react-ui/src/pages/Dataset/datasetIntro.jsx View File

@@ -1,88 +1,95 @@

import React ,{useEffect,useState,useRef}from 'react';
import Styles from './index.less'
import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,Select,Table,Upload} from 'antd';
import { PlusOutlined,PlusCircleOutlined, DeleteOutlined,UploadOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import {getDatasetList,getDatasetById,getDatasetVersionsById,getDatasetVersionIdList,deleteDatasetVersion,addDatasetVersionDetail,exportDataset} from '@/services/dataset/index.js'
import { useParams } from 'react-router-dom'
import {downLoadZip} from '@/utils/downloadfile'
const { Search } = Input;
import { getAccessToken } from '@/access';
import {
addDatasetVersionDetail,
deleteDatasetVersion,
getDatasetById,
getDatasetVersionIdList,
getDatasetVersionsById,
} from '@/services/dataset/index.js';
import { downLoadZip } from '@/utils/downloadfile';
import {
DeleteOutlined,
DownloadOutlined,
PlusCircleOutlined,
UploadOutlined,
} from '@ant-design/icons';
import { Button, Form, Input, Modal, Select, Table, Tabs, Upload, message } from 'antd';
import moment from 'moment';
import { getAccessToken } from '@/access';
import { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import Styles from './index.less';
const { Search } = Input;
const { TabPane } = Tabs;

const Dataset= React.FC = () => {
const Dataset = () => {
const props = {
action: '/api/mmp/dataset/upload',
// headers: {
// 'X-Requested-With': null
// },
headers: {
Authorization:getAccessToken(),
'X-Requested-With': null
Authorization: getAccessToken(),
'X-Requested-With': null,
},
onChange({ file, fileList }) {
if (file.status !== 'uploading') {
console.log(file, fileList);
setFormList(fileList.map(item=>{
return {
...form.getFieldsValue(),
dataset_id:locationParams.id,
file_name:item.response.data[0].fileName,
file_size:item.response.data[0].fileSize,
url:item.response.data[0].url,
}
}))
setFormList(
fileList.map((item) => {
return {
...form.getFieldsValue(),
dataset_id: locationParams.id,
file_name: item.response.data[0].fileName,
file_size: item.response.data[0].fileSize,
url: item.response.data[0].url,
};
}),
);
}
},
defaultFileList: [
],
defaultFileList: [],
};
const [form] = Form.useForm();
const [formList,setFormList]=useState([])
const [formList, setFormList] = useState([]);
const [dialogTitle, setDialogTitle] = useState('新建版本');
const [isModalOpen,setIsModalOpen]=useState(false)
const [datasetDetailObj,setDatasetDetailObj]=useState({
});
const [version,setVersion]=useState('')
const [isModalOpen, setIsModalOpen] = useState(false);
const [datasetDetailObj, setDatasetDetailObj] = useState({});
const [version, setVersion] = useState('');
const [versionList, setVersionList] = useState([]);
const locationParams =useParams () //新版本获取路由参数接口
console.log(locationParams);
const locationParams = useParams(); //新版本获取路由参数接口
const [wordList, setWordList] = useState([]);
const getDatasetByDetail=()=>{
getDatasetById(locationParams.id).then(ret=>{
const [activeTabKey, setActiveTabKey] = useState('1');
const getDatasetByDetail = () => {
getDatasetById(locationParams.id).then((ret) => {
console.log(ret);
if(ret.code==200){
setDatasetDetailObj(ret.data)
}
})
}
const getDatasetVersionList=()=>{
getDatasetVersionsById(locationParams.id).then(ret=>{
setDatasetDetailObj(ret.data);
});
};
const getDatasetVersionList = () => {
getDatasetVersionsById(locationParams.id).then((ret) => {
console.log(ret);
if(ret.code==200&&ret.data&&ret.data.length>0){
setVersionList(ret.data.map(item=>{
return {
'label':item,
'value':item
}
}))
if (ret.data && ret.data.length > 0) {
setVersionList(
ret.data.map((item) => {
return {
label: item,
value: item,
};
}),
);
}
})
}
useEffect(()=>{
getDatasetByDetail()
getDatasetVersionList()
return ()=>{
}
},[])
});
};
useEffect(() => {
getDatasetByDetail();
getDatasetVersionList();
return () => {};
}, []);
const showModal = () => {
form.resetFields()
form.setFieldsValue({name:datasetDetailObj.name})
setDialogTitle('创建新版本')
form.resetFields();
form.setFieldsValue({ name: datasetDetailObj.name });
setDialogTitle('创建新版本');
setIsModalOpen(true);
};
const handleCancel = () => {
@@ -91,80 +98,74 @@ const Dataset= React.FC = () => {
const handleExport = async () => {
const hide = message.loading('正在下载');
hide();
downLoadZip(`/api/mmp/dataset/downloadAllFiles`,{dataset_id:locationParams.id,version})
downLoadZip(`/api/mmp/dataset/downloadAllFiles`, { dataset_id: locationParams.id, version });
};
const deleteDataset=()=>{
const deleteDataset = () => {
Modal.confirm({
title: '删除',
content: '确定删除数据集版本?',
okText: '确认',
cancelText: '取消',

onOk: () => {
deleteDatasetVersion({dataset_id:locationParams.id,version}).then(ret=>{
if(ret.code==200){
message.success('删除成功')
getDatasetVersions({version,dataset_id:locationParams.id})
}
else{
message.error(ret.msg)
}
onOk: () => {
deleteDatasetVersion({ dataset_id: locationParams.id, version }).then((ret) => {
message.success('删除成功');
getDatasetVersions({ version, dataset_id: locationParams.id });
});
},
});
}
const onFinish = (values) => {
addDatasetVersionDetail(formList).then(ret=>{
console.log(ret);
getDatasetVersionList()
setIsModalOpen(false);
})
};
const getDatasetVersions=(params)=>{
getDatasetVersionIdList(params).then(ret=>{
};
const onFinish = (values) => {
addDatasetVersionDetail(formList).then((ret) => {
console.log(ret);
if(ret.code==200){
setWordList(ret.data)
}
})
}
const handleChange=(value)=>{
getDatasetVersionList();
setIsModalOpen(false);
});
};
const getDatasetVersions = (params) => {
getDatasetVersionIdList(params).then((res) => {
setWordList(
res.data.map((v) => ({
...v,
key: v.id,
})),
);
});
};
const handleChange = (value) => {
console.log(value);
if(value){
getDatasetVersions({version:value,dataset_id:locationParams.id})
setVersion(value)
}
else{
setVersion(null)
if (value) {
getDatasetVersions({ version: value, dataset_id: locationParams.id });
setVersion(value);
} else {
setVersion(null);
}
}
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
const downloadAlone=(e,record)=>{
const downloadAlone = (e, record) => {
console.log(record);
const hide = message.loading('正在下载');
hide();
downLoadZip(`/api/mmp//dataset/download/${record.id}`)
}
downLoadZip(`/api/mmp/dataset/download/${record.id}`);
};
const columns = [
// {
// title: '序号',
// dataIndex: 'index',
// key: 'index',
// width: 80,
// render(text, record, index) {
// return (
// <span>{(pageOption.current.page - 1) * 10 + index + 1}</span>
// )
// }
// // render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`,
// },
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 80,
render(text, record, index) {
return <span>{(pageOption.current.page - 1) * 10 + index + 1}</span>;
},
// render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`,
},
{
title: '文件名称',
dataIndex: 'file_name',
key: 'file_name',
render: (text,record) => <a onClick={(e)=>downloadAlone(e,record)}>{text}</a>,
render: (text, record) => <a onClick={(e) => downloadAlone(e, record)}>{text}</a>,
},
{
title: '版本号',
@@ -182,80 +183,128 @@ const Dataset= React.FC = () => {
key: 'update_time',
render: (text) => <span>{moment(text).format('YYYY-MM-DD HH:mm:ss')}</span>,
},
{
title: '操作',
dataIndex: 'option',
width: '100px',
key: 'option',
render: (_, record) => [
<Button
type="link"
size="small"
key="download"
icon={<DownloadOutlined />}
onClick={(e) => downloadAlone(e, record)}
>
下载
</Button>,
],
},
];
const pageOption = useRef({page: 1,size: 10})
const pageOption = useRef({ page: 1, size: 10 });

// 当前页面切换
const paginationChange = async (current, size) => {
console.log('page', current, size)
pageOption.current={
page:current,
size:size
}
console.log('page', current, size);
pageOption.current = {
page: current,
size: size,
};
// getList()
}
return (<div className={Styles.datasetBox}>
<div className={Styles.datasetIntroTopBox}>
<span style={{color:'#1d1d20',fontSize:'20px'}}>{datasetDetailObj.name}</span>
<div className={Styles.smallTagBox}>
<div className={Styles.tagItem}>{datasetDetailObj.data_tag||'...'}</div>
};
return (
<div className={Styles.datasetBox}>
<div className={Styles.datasetIntroTopBox}>
<span style={{ color: '#1d1d20', fontSize: '20px' }}>{datasetDetailObj.name}</span>
<div className={Styles.smallTagBox}>
<div className={Styles.tagItem}>{datasetDetailObj.data_tag || '...'}</div>
<div className={Styles.tagItem}>{datasetDetailObj.data_type}</div>
{/* <div className={Styles.tagItem}>English</div> */}
</div>
</div>
<div className={Styles.datasetIntroCneterBox}>
<Tabs
defaultActiveKey="1"
>
<TabPane tab="数据集简介" key="1">
<div className={Styles.datasetIntroTitle}>简介</div>
<div className={Styles.datasetIntroText}>{datasetDetailObj.description}</div>
</TabPane>
<TabPane tab="数据集文件/版本" key="2">
<div className={Styles.dataListBox}>
<div>数据集文件列表</div>
<div className={Styles.dataButtonList}>
<div style={{display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'}}>
<span style={{marginRight:'10px'}}>版本号:</span>
<Select
placeholder="请选择版本号"
style={{
width: 160,
}}
allowClear
onChange={handleChange}
options={versionList}
/>
<Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}>
创建新版本
</Button>
</div>
<div style={{display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'}}>
<Button type="primary" className={Styles.plusButton} style={{margin:'0 20px 0 0' }} onClick={deleteDataset} icon = {<DeleteOutlined style={{color:'#1664ff', }} />}>
删除
</Button>
<Button type="primary" disabled={!version} className={Styles.plusButton} style={{margin:'0 20px 0 0' }} onClick={handleExport} icon = {<UploadOutlined style={{color:'#1664ff'}} />}>
下载
</Button>
</div>
</div>
<Table columns={columns} dataSource={wordList} pagination={false} />
</div>
</TabPane>
</Tabs>
</div>
<Modal title={<div style={{display:'flex',alignItems:'center',fontWeight:500}}>
<img style={{width:'20px',marginRight:'10px'}} src={`/assets/images/pipeline-edit-icon.png`} alt="" />{dialogTitle}
</div>} open={isModalOpen} className={Styles.modal} okButtonProps={{
htmlType: 'submit',
form: 'form',
}} onCancel={handleCancel}>
</div>
<div className={Styles.datasetIntroCneterBox}>
<Tabs activeKey={activeTabKey} onChange={(key) => setActiveTabKey(key)}>
<TabPane tab="数据集简介" key="1">
<div className={Styles.datasetIntroTitle}>简介</div>
<div className={Styles.datasetIntroText}>{datasetDetailObj.description}</div>
</TabPane>
<TabPane tab="数据集文件/版本" key="2">
<div className={Styles.dataListBox}>
<div>数据集文件列表</div>
<div className={Styles.dataButtonList}>
<div
style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}
>
<span style={{ marginRight: '10px' }}>版本号:</span>
<Select
placeholder="请选择版本号"
style={{
width: 160,
}}
allowClear
onChange={handleChange}
options={versionList}
/>
<Button
type="primary"
className={Styles.plusButton}
onClick={showModal}
icon={<PlusCircleOutlined style={{ color: '#1664ff' }} />}
>
创建新版本
</Button>
</div>
<div
style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}
>
<Button
type="primary"
className={Styles.plusButton}
style={{ margin: '0 20px 0 0' }}
onClick={deleteDataset}
icon={<DeleteOutlined style={{ color: '#1664ff' }} />}
>
删除
</Button>
<Button
type="primary"
disabled={!version}
className={Styles.plusButton}
style={{ margin: '0 20px 0 0' }}
onClick={handleExport}
icon={<DownloadOutlined style={{ color: '#1664ff' }} />}
>
下载
</Button>
</div>
</div>
<div style={{ marginBottom: '10px', fontSize: '14px' }}>
{wordList.length > 0 ? wordList[0].description : null}
</div>
<Table columns={columns} dataSource={wordList} pagination={false} />
</div>
</TabPane>
</Tabs>
</div>
<Modal
title={
<div style={{ display: 'flex', alignItems: 'center', fontWeight: 500 }}>
<img
style={{ width: '20px', marginRight: '10px' }}
src={`/assets/images/pipeline-edit-icon.png`}
alt=""
/>
{dialogTitle}
</div>
}
open={isModalOpen}
className={Styles.modal}
okButtonProps={{
htmlType: 'submit',
form: 'form',
}}
onCancel={handleCancel}
>
<Form
name="form"
form={form}
@@ -271,28 +320,71 @@ const Dataset= React.FC = () => {
label="数据集名称"
name="name"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
{
required: true,
message: '请输入数据集名称',
},
]}
>
<Input disabled placeholder="请输入数据集名称"/>
<Input disabled placeholder="请输入数据集名称" />
</Form.Item>
<Form.Item
<Form.Item
label="数据集版本"
name="version"
rules={[
{
required: true,
message: '请输入数据集版本',
},
]}
>
<Input placeholder="请输入数据集版本"/>
<Input placeholder="请输入数据集版本" maxLength={64} showCount allowClear />
</Form.Item>
<Form.Item
label="版本描述"
name="description"
rules={[
{
required: true,
message: '请输入版本描述',
},
]}
>
<Input.TextArea
placeholder="请输入版本描述"
autoSize={{ minRows: 2, maxRows: 6 }}
maxLength={256}
showCount
allowClear
/>
</Form.Item>
<Form.Item
label="数据集文件"
name="dataset_version_vos"
rules={[
{
required: true,
message: '请上传数据集文件',
},
]}
>
<Upload {...props}>
<Button
style={{
fontSize: '14px',
border: '1px solid',
borderColor: '#1664ff',
background: '#fff',
}}
icon={<UploadOutlined style={{ color: '#1664ff' }} />}
>
上传文件
</Button>
</Upload>
</Form.Item>
<Form.Item label="数据文件" name="dataset_version_vos">
<Upload {...props}>
<Button style={{fontSize:'14px',border:'1px solid',borderColor:'#1664ff',background:'#fff'}} icon={<UploadOutlined style={{color:'#1664ff'}} />}>上传文件</Button>
</Upload>
</Form.Item>
</Form>
</Modal>

</div>)
</div>
);
};
export default Dataset;
export default Dataset;

+ 53
- 63
react-ui/src/pages/Dataset/index.jsx View File

@@ -1,84 +1,74 @@

import React ,{useEffect,useState}from 'react';
import Styles from './index.less'
import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,} from 'antd';
import { PlusOutlined,PlusCircleOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import {getDatasetList} from '@/services/dataset/index.js'
import { getDatasetList } from '@/services/dataset/index.js';
import { Form, Input, Tabs } from 'antd';
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import Styles from './index.less';
import PersonalData from './personalData';
import PublicData from './publicData';
const { Search } = Input;
import { useNavigate} from 'react-router-dom';
import moment from 'moment';
const { TabPane } = Tabs;
import PublicData from './publicData';
import PersonalData from './personalData'
const leftdataList=[1,2,3]
const leftdataList = [1, 2, 3];

const Dataset= React.FC = () => {
const [queryFlow,setQueryFlow]=useState({
page:0,
size:10,
name:null
const Dataset = (React.FC = () => {
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
name: null,
});
const navgite=useNavigate();
const [isModalOpen,setIsModalOpen]=useState(false)
const [datasetList,setDatasetList]=useState([]);
const [total,setTotal]=useState(0);
const navgite = useNavigate();
const [isModalOpen, setIsModalOpen] = useState(false);
const [datasetList, setDatasetList] = useState([]);
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建数据');
const getDatasetlist=()=>{
getDatasetList(queryFlow).then(ret=>{
const getDatasetlist = () => {
getDatasetList(queryFlow).then((ret) => {
console.log(ret);
if(ret.code==200){
setDatasetList(ret.data.content)
setTotal(ret.data.totalElements)
if (ret.code == 200) {
setDatasetList(ret.data.content);
setTotal(ret.data.totalElements);
}
})
}
});
};

const showModal = () => {
form.resetFields()
setDialogTitle('新建数据集')
form.resetFields();
setDialogTitle('新建数据集');
setIsModalOpen(true);
};
const handleOk = () => {
console.log(1111);
console.log(1111);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const onFinish = (values) => {
};
const routeToIntro=(e,record)=>{
e.stopPropagation()
navgite({pathname:'/dataset/datasetIntro' });
}
const onFinish = (values) => {};
const routeToIntro = (e, record) => {
e.stopPropagation();
navgite({ pathname: '/dataset/datasetIntro' });
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
useEffect(()=>{
getDatasetlist()
return ()=>{
}
},[])
return (<div className={Styles.datasetBox}>
<div className={Styles.datasetTopBox}>
</div>
<div className={Styles.datasetAllBox}>
<Tabs
defaultActiveKey="1"
>
<TabPane tab="数据广场" key="1">
<PublicData/>
</TabPane>
<TabPane tab="个人数据" key="2">
<PersonalData/>
</TabPane>
</Tabs>
</div>
</div>)
};
export default Dataset;
useEffect(() => {
getDatasetlist();
return () => {};
}, []);
return (
<div className={Styles.datasetBox}>
<div className={Styles.datasetTopBox}></div>
<div className={Styles.datasetAllBox}>
<Tabs defaultActiveKey="1">
<TabPane tab="数据广场" key="1">
<PublicData />
</TabPane>
<TabPane tab="个人数据" key="2">
<PersonalData />
</TabPane>
</Tabs>
</div>
</div>
);
});
export default Dataset;

+ 271
- 277
react-ui/src/pages/Dataset/index.less View File

@@ -1,303 +1,297 @@
.datasetTopBox{
.datasetTopBox {
display: flex;
align-items: center;
width: 100%;
height: 49px;
padding: 0 30px;
padding-right: 30px;
background-image: url(/assets/images/pipeline-back.png);
background-size: 100% 100%;
}
.datasetIntroTopBox {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 110px;
margin-bottom: 10px;
padding: 25px 30px;
background-image: url(/assets/images/dataset-back.png);
background-size: 100% 100%;
.smallTagBox {
display: flex;
align-items: center;
padding-right: 30px;
width: 100%;
height: 49px;
background-size: 100% 100%;
background-image: url(/assets/images/pipeline-back.png);
padding: 0 30px;
color: #1664ff;
font-size: 14px;
.tagItem {
margin-right: 20px;
padding: 4px 10px;
background: rgba(22, 100, 255, 0.1);
border-radius: 4px;
}
}
}
.datasetIntroTopBox{
.dataListBox {
padding: 20px 30px;
color: #1d1d20;
font-size: 16px;
background: #ffffff;
border-radius: 10px;
box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09);
.dataButtonList {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: 100%;
height: 110px;
background-size: 100% 100%;
background-image: url(/assets/images/dataset-back.png);
margin-bottom: 10px;
padding: 25px 30px;
.smallTagBox{
display: flex;
align-items: center;
color:#1664ff;
font-size:14px;
.tagItem{
padding: 4px 10px;
background: rgba(22, 100, 255, 0.1);
border-radius:4px;
margin-right: 20px;
}
}
}
.dataListBox{
padding: 20px 30px;
background:#ffffff;
border-radius:10px;
box-shadow:0px 2px 12px rgba(180, 182, 191, 0.09);
color:#1d1d20;
font-size:16px;
.dataButtonList{
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
margin: 24px 0 30px 0;
color:#575757;
font-size:16px;
}
height: 32px;
margin: 24px 0 30px 0;
color: #575757;
font-size: 16px;
}
}
.datasetIntroCneterBox{
height: 77vh;
padding: 20px 30px;
background:#ffffff;
border-radius:10px;
box-shadow:0px 2px 12px rgba(180, 182, 191, 0.09);
.datasetIntroCneterBox {
height: 77vh;
padding: 20px 30px;
background: #ffffff;
border-radius: 10px;
box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09);
}
.datasetIntroTitle{
color:#1d1d20;
font-size:15px;
margin: 37px 0 10px 0;
.datasetIntroTitle {
margin: 37px 0 10px 0;
color: #1d1d20;
font-size: 15px;
}
.datasetIntroText{
color:#575757;
font-size:14px;
margin-bottom: 30px;
.datasetIntroText {
margin-bottom: 30px;
color: #575757;
font-size: 14px;
}
.datasetBox{
background:#f9fafb;
font-family: 'Alibaba';
:global{
.ant-tabs-top >.ant-tabs-nav{
margin: 0;
}
.ant-pagination{
text-align: right;
}
.datasetBox {
font-family: 'Alibaba';
background: #f9fafb;
:global {
.ant-tabs-top > .ant-tabs-nav {
margin: 0;
}
.ant-pagination {
text-align: right;
}
}
}
.datasetAllBox{
:global{
.ant-tabs-nav .ant-tabs-nav-wrap{
margin: -48px 0 0 30px;
}
.datasetAllBox {
:global {
.ant-tabs-nav .ant-tabs-nav-wrap {
margin: -48px 0 0 30px;
}
}
}
.plusButton{
margin: 0 18px 0 20px;
background:rgba(22, 100, 255, 0.06);
border:1px solid;
border-color:rgba(22, 100, 255, 0.11);
border-radius:4px;
color:#1d1d20;
font-size:14px;
font-family: 'Alibaba';
.plusButton {
margin: 0 18px 0 20px;
color: #1d1d20;
font-size: 14px;
font-family: 'Alibaba';
background: rgba(22, 100, 255, 0.06);
border: 1px solid;
border-color: rgba(22, 100, 255, 0.11);
border-radius: 4px;
}
.plusButton:hover{
background:rgba(22, 100, 255, 0.06)!important;
border:1px solid!important;
border-color:rgba(22, 100, 255, 0.11)!important;
color:#1d1d20!important;
.plusButton:hover {
color: #1d1d20 !important;
background: rgba(22, 100, 255, 0.06) !important;
border: 1px solid !important;
border-color: rgba(22, 100, 255, 0.11) !important;
}
.datasetCneterBox{
display: flex;
justify-content: space-between;
height: 85vh;
width: 100%;
:global{
.ant-btn{
color:#1d1d20;
font-size:14px;
}
.datasetCneterBox {
display: flex;
justify-content: space-between;
width: 100%;
height: 85vh;
:global {
.ant-btn {
color: #1d1d20;
font-size: 14px;
}
.datasetCneterLeftBox{
width:340px;
height:100%;
background:#ffffff;
box-shadow:0px 3px 6px rgba(146, 146, 146, 0.09);
margin-right: 10px;
padding-top: 15px;
.custTab{
display: flex;
border-bottom: 1px solid #e0eaff;
height: 32px;
.tabItem{
width: 52px;
height: 100%;
text-align: center;
color:#808080;
font-size:15px;
cursor: pointer;
}
}
.datasetCneterLeftBox {
width: 340px;
height: 100%;
margin-right: 10px;
padding-top: 15px;
background: #ffffff;
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);
.custTab {
display: flex;
height: 32px;
border-bottom: 1px solid #e0eaff;
.tabItem {
width: 52px;
height: 100%;
color: #808080;
font-size: 15px;
text-align: center;
cursor: pointer;
}
}
.leftContentBox {
max-height: 80vh;
padding: 15px 20px;
overflow-x: hidden;
overflow-y: auto;
.itemTitle {
margin-bottom: 15px;
color: #1d1d20;
font-size: 14px;
}
.itemBox {
display: flex;
flex-wrap: wrap;
align-content: start;
width: 110%;
.messageBox {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: 92px;
height: 62px;
margin: 0 12px 20px 0;
padding: 11px 0px 7px 0px;
color: #1d1d20;
font-size: 12px;
border: 1px solid;
border-color: rgba(22, 100, 255, 0.05);
border-radius: 4px;
cursor: pointer;
.ptIcon {
display: block;
}
.hoverIcon {
display: none;
}
.messageText {
width: 65px;
overflow: hidden;
white-space: nowrap;
text-align: center;
text-overflow: ellipsis;
}
}
.leftContentBox{
max-height: 80vh;
overflow-y: auto;
overflow-x: hidden;
padding: 15px 20px;
.itemTitle{
color:#1d1d20;
font-size:14px;
margin-bottom: 15px;
}
.itemBox{
width: 110%;
display: flex;
flex-wrap: wrap;
align-content: start;
.messageBox{
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
cursor: pointer;
width:92px;
height:62px;
border:1px solid;
border-color:rgba(22, 100, 255, 0.05);
border-radius:4px;
margin: 0 12px 20px 0;
padding: 11px 0px 7px 0px;
color:#1d1d20;
font-size:12px;
.ptIcon{
display: block;
}
.hoverIcon{
display: none;
}
.messageText{
width: 65px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.messageBox:hover{
background:rgba(22, 100, 255, 0.03);
border:1px solid;
border-color:#1664ff;
.ptIcon{
display: none;
}
.hoverIcon{
display: block;
}
}
.active{
background:rgba(22, 100, 255, 0.03)!important;
border:1px solid!important;
border-color:#1664ff!important;
.ptIcon{
display: none!important;
}
.hoverIcon{
display: block!important;
}
}
}
.messageBox:hover {
background: rgba(22, 100, 255, 0.03);
border: 1px solid;
border-color: #1664ff;
.ptIcon {
display: none;
}
.hoverIcon {
display: block;
}
}
.active {
background: rgba(22, 100, 255, 0.03) !important;
border: 1px solid !important;
border-color: #1664ff !important;
.ptIcon {
display: none !important;
}
.hoverIcon {
display: block !important;
}
}
}
}
}

.datasetCneterRightBox{
display: flex;
flex-direction: column;
padding: 22px 30px 26px 30px;
flex: 1;
height:100%;
background:#ffffff;
box-shadow:0px 3px 6px rgba(146, 146, 146, 0.09);
.dataSource{
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
margin-bottom: 30px;
color:rgba(29, 29, 32, 0.8);
font-size:15px;
.datasetCneterRightBox {
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
padding: 22px 30px 26px 30px;
background: #ffffff;
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);
.dataSource {
display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
margin-bottom: 30px;
color: rgba(29, 29, 32, 0.8);
font-size: 15px;
}
.dataContent {
display: flex;
flex: 1;
flex-wrap: wrap;
align-content: flex-start;
width: 100%;
.dataItem {
position: relative;
width: 32%;
height: 66px;
margin: 0 15px 18px 0;
background: rgba(128, 128, 128, 0.05);
border-radius: 8px;
box-shadow: 0px 0px 12px rgba(75, 84, 137, 0.05);
cursor: pointer;
.itemText {
position: absolute;
top: 10px;
left: 20px;
color: #1d1d20;
font-size: 15px;
}
.itemTime {
position: absolute;
bottom: 10px;
left: 20px;
color: #808080;
font-size: 14px;
}
.dataContent{
width: 100%;
flex: 1;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
.dataItem{
width: 32%;
margin: 0 15px 18px 0;
height:66px;
position: relative;
background:rgba(128, 128, 128, 0.05);
border-radius:8px;
box-shadow:0px 0px 12px rgba(75, 84, 137, 0.05);
cursor: pointer;
.itemText{
position: absolute;
left: 20px;
top: 10px;
color:#1d1d20;
font-size:15px;
}
.itemTime{
position: absolute;
left: 20px;
bottom: 10px;
color:#808080;
font-size:14px;
}
.itemIcon{
position: absolute;
right: 20px;
bottom: 10px;
color:#808080;
font-size:14px;
}
}
.itemIcon {
position: absolute;
right: 20px;
bottom: 10px;
color: #808080;
font-size: 14px;
}
}
}
}
}
.modal {
:global {
.ant-modal-content {
background:linear-gradient(180deg,#cfdfff 0%,#d4e2ff 9.77%,#ffffff 40%,#ffffff 100%);
border-radius:21px;
padding: 20px 67px;
width: 825px;

}
.ant-modal-header{
background-color: transparent;
margin: 20px 0;
}
.ant-input{
border-color:#e6e6e6;
height: 40px;
}
.ant-form-item .ant-form-item-label >label{
color:rgba(29, 29, 32, 0.8);
}
.ant-modal-footer{
margin: 40px 0 30px 0;
display: flex;
justify-content: center;
}
.ant-btn{
width:110px;
height:40px;
font-size:18px;
background:rgba(22, 100, 255, 0.06);
border-radius:10px;
border-color: transparent;

}
.ant-btn-primary{
background:#1664ff;
}
:global {
.ant-modal-content {
width: 825px;
padding: 20px 67px;
background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%);
border-radius: 21px;
}
.ant-modal-header {
margin: 20px 0;
background-color: transparent;
}
.ant-input {
height: 40px;
border-color: #e6e6e6;
}
}
.ant-form-item .ant-form-item-label > label {
color: rgba(29, 29, 32, 0.8);
}
.ant-modal-footer {
display: flex;
justify-content: center;
margin: 40px 0 30px 0;
}
.ant-btn {
width: 110px;
height: 40px;
font-size: 18px;
background: rgba(22, 100, 255, 0.06);
border-color: transparent;
border-radius: 10px;
}
.ant-btn-primary {
background: #1664ff;
}
}
}

+ 326
- 246
react-ui/src/pages/Dataset/personalData.jsx View File

@@ -1,240 +1,302 @@

import React ,{useEffect,useState}from 'react';
import Styles from './index.less'
import './index.less'
import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,Select,Upload } from 'antd';
import { PlusOutlined,PlusCircleOutlined,UploadOutlined , DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import {getDatasetList,addDatesetAndVesion,getAssetIcon} from '@/services/dataset/index.js'
import { getDictSelectOption } from "@/services/system/dict";
const { Search } = Input;
import { useNavigate} from 'react-router-dom';
import { getAccessToken } from '@/access';
import { addDatesetAndVesion, getAssetIcon, getDatasetList } from '@/services/dataset/index.js';
import { getDictSelectOption } from '@/services/system/dict';
import { PlusCircleOutlined, UploadOutlined } from '@ant-design/icons';
import { Button, Form, Input, Modal, Pagination, Radio, Select, Upload } from 'antd';
import moment from 'moment';
import axios from 'axios'
import { getAccessToken } from '@/access';
const leftdataList=[1,2,3]

const PublicData= React.FC = () => {
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import './index.less';
import Styles from './index.less';
const { Search } = Input;
const leftdataList = [1, 2, 3];

const PublicData = (React.FC = () => {
const props = {
action: '/api/mmp/dataset/upload',
// headers: {
// 'X-Requested-With': null
// },
headers: {
Authorization:getAccessToken(),
'X-Requested-With': null
Authorization: getAccessToken(),
'X-Requested-With': null,
},
onChange({ file, fileList }) {
if (file.status !== 'uploading') {
console.log(file, fileList);
form.setFieldsValue({dataset_version_vos:fileList.map(item=>item.response.data[0])})
form.setFieldsValue({ dataset_version_vos: fileList.map((item) => item.response.data[0]) });
}
},
defaultFileList: [
],
defaultFileList: [],
};
const [queryFlow,setQueryFlow]=useState({
page:0,
size:10,
name:null,
available_range:0,
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
name: null,
available_range: 0,
});
const [iconParams, setIconParams] = useState({
name: null,
page: 0,
size: 10000,
});
const [iconParams,setIconParams]=useState({
name:null,
page:0,
size:10000
})
const [activeType,setActiveType]=useState(null)
const [activeTag,setActiveTag]=useState(null)
const [datasetTypeList,setDatasetTypeList]=useState([])
const [datasetDirectionList,setDatasetDirectionList]=useState([])
const navgite=useNavigate();
const [clusterOptions,setClusterOptions]=useState([])
const [isModalOpen,setIsModalOpen]=useState(false)
const [datasetList,setDatasetList]=useState([]);
const [total,setTotal]=useState(0);
const [activeType, setActiveType] = useState(null);
const [activeTag, setActiveTag] = useState(null);
const [datasetTypeList, setDatasetTypeList] = useState([]);
const [datasetDirectionList, setDatasetDirectionList] = useState([]);
const navgite = useNavigate();
const [clusterOptions, setClusterOptions] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [datasetList, setDatasetList] = useState([]);
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建数据');
const getDatasetlist=(queryFlow)=>{
getDatasetList(queryFlow).then(ret=>{
const getDatasetlist = (queryFlow) => {
getDatasetList(queryFlow).then((ret) => {
console.log(ret);
if(ret.code==200){
setDatasetList(ret.data.content)
setTotal(ret.data.totalElements)
if (ret.code == 200) {
setDatasetList(ret.data.content);
setTotal(ret.data.totalElements);
}
})
}
});
};

const showModal = () => {
form.resetFields()
setDialogTitle('新建数据集')
form.resetFields();
setDialogTitle('新建数据集');
setIsModalOpen(true);
};
const getAssetIconList=(params)=>{
getAssetIcon(params).then(ret=>{
const getAssetIconList = (params) => {
getAssetIcon(params).then((ret) => {
console.log(ret);
if(ret.code==200&&ret.data.content&&ret.data.content.length>0){
setDatasetTypeList(ret.data.content.filter(item=>item.category_id==1))
setDatasetDirectionList(ret.data.content.filter(item=>item.category_id==2))
if (ret.code == 200 && ret.data.content && ret.data.content.length > 0) {
setDatasetTypeList(ret.data.content.filter((item) => item.category_id == 1));
setDatasetDirectionList(ret.data.content.filter((item) => item.category_id == 2));
} else {
setDatasetTypeList([]);
setDatasetDirectionList([]);
}
else{
setDatasetTypeList([])
setDatasetDirectionList([])
}
})
}
const onSearch=(values)=>{
});
};
const onSearch = (values) => {
console.log(values);
getAssetIconList({...iconParams,name:values})
}
const nameSearch=(values)=>{
getAssetIconList({ ...iconParams, name: values });
};
const nameSearch = (values) => {
console.log(values);
getDatasetlist({...queryFlow,name:values})
}
getDatasetlist({ ...queryFlow, name: values });
};
const handleOk = () => {
console.log(1111);
console.log(1111);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const chooseDatasetType=(val,item)=>{
console.log(val,item);
if(item.path==queryFlow.data_type){
setActiveType('')
setQueryFlow({...queryFlow,data_type:null})
getDatasetlist({...queryFlow,data_type:null})
}
else{
setActiveType(item.path)
setQueryFlow({...queryFlow,data_type:item.path})
getDatasetlist({...queryFlow,data_type:item.path})
const chooseDatasetType = (val, item) => {
console.log(val, item);
if (item.path == queryFlow.data_type) {
setActiveType('');
setQueryFlow({ ...queryFlow, data_type: null });
getDatasetlist({ ...queryFlow, data_type: null });
} else {
setActiveType(item.path);
setQueryFlow({ ...queryFlow, data_type: item.path });
getDatasetlist({ ...queryFlow, data_type: item.path });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
// })
};
const chooseDatasetTag=(val,item)=>{
console.log(val,item);
if(item.path==queryFlow.data_tag){
setActiveTag('')
setQueryFlow({...queryFlow,data_tag:null})
getDatasetlist({...queryFlow,data_tag:null})
}
else{
setActiveTag(item.path)
setQueryFlow({...queryFlow,data_tag:item.path})
getDatasetlist({...queryFlow,data_tag:item.path})
const chooseDatasetTag = (val, item) => {
console.log(val, item);
if (item.path == queryFlow.data_tag) {
setActiveTag('');
setQueryFlow({ ...queryFlow, data_tag: null });
getDatasetlist({ ...queryFlow, data_tag: null });
} else {
setActiveTag(item.path);
setQueryFlow({ ...queryFlow, data_tag: item.path });
getDatasetlist({ ...queryFlow, data_tag: item.path });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
// })
};
const onFinish = (values) => {
addDatesetAndVesion(values).then(ret=>{
console.log(ret);
setIsModalOpen(false);
getDatasetlist(queryFlow)
})
};
const routeToIntro=(e,record)=>{
e.stopPropagation()
addDatesetAndVesion(values).then((ret) => {
console.log(ret);
setIsModalOpen(false);
getDatasetlist(queryFlow);
});
};
const routeToIntro = (e, record) => {
e.stopPropagation();
console.log(record);
navgite({pathname:`/dataset/datasetIntro/${record.id}` });
}
navgite({ pathname: `/dataset/datasetIntro/${record.id}` });
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
useEffect(()=>{
useEffect(() => {
getDictSelectOption('available_cluster').then((data) => {
setClusterOptions(data);
});
getAssetIconList(iconParams)
getDatasetlist(queryFlow)
return ()=>{
}
},[])
return (<>

<div className={Styles.datasetCneterBox}>
<div className={Styles.datasetCneterLeftBox}>
<div className={Styles.leftContentBox}>
<Search
placeholder="搜索"
allowClear
onSearch={onSearch}
style={{
width: 300,
marginBottom:'15px',
}}
/>
<div className={Styles.itemTitle}>分类</div>
<div className={Styles.itemBox}>
{datasetTypeList&&datasetTypeList.length>0?datasetTypeList.map(item=>{return <div >
<div className={[Styles.messageBox, item.path===activeType?Styles.active:null].join(' ')} onClick={(e)=>{chooseDatasetType(e, item)}} >
<img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}.png`} alt="" />
<img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}-hover.png`} alt="" />
<span className={Styles.messageText} >{item.name}</span>
getAssetIconList(iconParams);
getDatasetlist(queryFlow);
return () => {};
}, []);
return (
<>
<div className={Styles.datasetCneterBox}>
<div className={Styles.datasetCneterLeftBox}>
<div className={Styles.leftContentBox}>
<Search
placeholder="搜索"
allowClear
onSearch={onSearch}
style={{
width: 300,
marginBottom: '15px',
}}
/>
<div className={Styles.itemTitle}>分类</div>
<div className={Styles.itemBox}>
{datasetTypeList && datasetTypeList.length > 0
? datasetTypeList.map((item) => {
return (
<div>
<div
className={[
Styles.messageBox,
item.path === activeType ? Styles.active : null,
].join(' ')}
onClick={(e) => {
chooseDatasetType(e, item);
}}
>
<img
className={Styles.ptIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}.png`}
alt=""
/>
<img
className={Styles.hoverIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}-hover.png`}
alt=""
/>
<span className={Styles.messageText}>{item.name}</span>
</div>
</div>
);
})
: ''}
</div>
<div className={Styles.itemTitle}>研究方向/应用领域</div>
<div className={Styles.itemBox}>
{datasetDirectionList && datasetDirectionList.length > 0
? datasetDirectionList.map((item) => {
return (
<div>
<div
className={[
Styles.messageBox,
item.path === activeTag ? Styles.active : null,
].join(' ')}
onClick={(e) => {
chooseDatasetTag(e, item);
}}
>
<img
className={Styles.ptIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}.png`}
alt=""
/>
<img
className={Styles.hoverIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}-hover.png`}
alt=""
/>
<span className={Styles.messageText}>{item.name}</span>
</div>
</div>
);
})
: ''}
</div>
</div>
</div>}):''}
</div>
<div className={Styles.itemTitle}>研究方向/应用领域</div>
<div className={Styles.itemBox}>
{datasetDirectionList&&datasetDirectionList.length>0?datasetDirectionList.map(item=>{return <div >
<div className={[Styles.messageBox, item.path===activeTag?Styles.active:null].join(' ')}onClick={(e)=>{chooseDatasetTag(e, item)}}>
<img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}.png`} alt="" />
<img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}-hover.png`} alt="" />
<span className={Styles.messageText} >{item.name}</span>
</div>
<div className={Styles.datasetCneterRightBox}>
<div className={Styles.dataSource}>
<span>数据总数:{total}个</span>
<div>
<Search
placeholder="按数据名称筛选"
allowClear
onSearch={nameSearch}
style={{
width: 300,
}}
/>
<Button
type="primary"
className={Styles.plusButton}
onClick={showModal}
icon={<PlusCircleOutlined style={{ color: '#1664ff' }} />}
>
新建数据集
</Button>
</div>
</div>
</div>}):''}
</div>
</div>
</div>
<div className={Styles.datasetCneterRightBox}>
<div className={Styles.dataSource}>
<span>数据总数:{total}个</span>
<div>
<Search
placeholder="按数据名称筛选"
allowClear
onSearch={nameSearch}
style={{
width: 300,
}}
/>
<Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}>
新建数据集
</Button>
<div className={Styles.dataContent}>
{datasetList && datasetList.length > 0
? datasetList.map((item) => {
return (
<div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}>
<div className={Styles.itemText}>{item.name}</div>
<div className={Styles.itemTime}>
<span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span>
</div>
<div className={Styles.itemIcon}>
<img
style={{ width: '17px', marginRight: '3px' }}
src={`/assets/images/upload-icon.png`}
alt=""
/>
<span>1582</span>
</div>
</div>
);
})
: ''}
{/* <Select.Option value="demo">Demo</Select.Option> */}
</div>
<Pagination size="small" total={total} showSizeChanger showQuickJumper />
</div>
</div>
<div className={Styles.dataContent}>
{datasetList&&datasetList.length>0?datasetList.map(item=>{return <div className={Styles.dataItem} onClick={(e)=>routeToIntro(e,item)}>
<div className={Styles.itemText}>{item.name}</div>
<div className={Styles.itemTime}><span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span></div>
<div className={Styles.itemIcon}><img style={{width:'17px',marginRight:'3px'}} src={`/assets/images/upload-icon.png`} alt="" /><span>1582</span></div>
</div>}):''}
{/* <Select.Option value="demo">Demo</Select.Option> */}
</div>
<Pagination
size="small"
total={total}
showSizeChanger
showQuickJumper
/>
</div>
</div>
<Modal title={<div style={{display:'flex',alignItems:'center',fontWeight:500}}>
<img style={{width:'20px',marginRight:'10px'}} src={`/assets/images/pipeline-edit-icon.png`} alt="" />{dialogTitle}
</div>} open={isModalOpen} className={Styles.modal} okButtonProps={{
htmlType: 'submit',
form: 'form',
}} onCancel={handleCancel}>
<Modal
title={
<div style={{ display: 'flex', alignItems: 'center', fontWeight: 500 }}>
<img
style={{ width: '20px', marginRight: '10px' }}
src={`/assets/images/pipeline-edit-icon.png`}
alt=""
/>
{dialogTitle}
</div>
}
open={isModalOpen}
className={Styles.modal}
okButtonProps={{
htmlType: 'submit',
form: 'form',
}}
onCancel={handleCancel}
>
<Form
name="form"
form={form}
@@ -249,94 +311,112 @@ const PublicData= React.FC = () => {
<Form.Item
label="数据名称"
name="name"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Input placeholder="请输入数据名称"/>
<Input placeholder="请输入数据名称" />
</Form.Item>
<Form.Item
label="数据集版本"
name="version"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Input placeholder="请输入数据集版本"/>
<Input placeholder="请输入数据集版本" />
</Form.Item>
<Form.Item
label="数据集分类"
name="data_type"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Select
allowClear
placeholder="请选择数据集分类"
options={datasetTypeList.map(item=>{return {value:item.id,label:item.name}})}
/>
</Form.Item>
<Form.Item
allowClear
placeholder="请选择数据集分类"
options={datasetTypeList.map((item) => {
return { value: item.id, label: item.name };
})}
/>
</Form.Item>
<Form.Item
label="研究方向/应用领域"
name="data_tag"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Select
allowClear
placeholder="请选择研究方向/应用领域"
options={datasetDirectionList.map(item=>{return {value:item.id,label:item.name}})}
/>
allowClear
placeholder="请选择研究方向/应用领域"
options={datasetDirectionList.map((item) => {
return { value: item.id, label: item.name };
})}
/>
</Form.Item>
<Form.Item
label="集群版本"
name="available_cluster"
>
<Select
allowClear
placeholder="请选择集群版本"
options={clusterOptions}
/>
<Form.Item label="集群版本" name="available_cluster">
<Select allowClear placeholder="请选择集群版本" options={clusterOptions} />
</Form.Item>
<Form.Item
label="数据简介"
name="description"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Input placeholder="请输入数据简介"/>
<Input placeholder="请输入数据简介" />
</Form.Item>
<Form.Item label="选择流水线" name="range">
<Radio.Group>
<Radio value="0">仅自己可见</Radio>
<Radio value="1">工作空间可见</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="数据文件" name="dataset_version_vos">
<Upload {...props}>
<Button style={{fontSize:'14px',border:'1px solid',borderColor:'#1664ff',background:'#fff'}} icon={<UploadOutlined style={{color:'#1664ff',fontSize:'14px'}} />}>上传文件</Button>
</Upload>
</Form.Item>
<Radio.Group>
<Radio value="0">仅自己可见</Radio>
<Radio value="1">工作空间可见</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="数据文件" name="dataset_version_vos">
<Upload {...props}>
<Button
style={{
fontSize: '14px',
border: '1px solid',
borderColor: '#1664ff',
background: '#fff',
}}
icon={<UploadOutlined style={{ color: '#1664ff', fontSize: '14px' }} />}
>
上传文件
</Button>
</Upload>
</Form.Item>
</Form>
</Modal>
</>)
};
export default PublicData;
</>
);
});
export default PublicData;

+ 206
- 157
react-ui/src/pages/Dataset/publicData.jsx View File

@@ -1,195 +1,244 @@

import React ,{useEffect,useState}from 'react';
import Styles from './index.less'
import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,} from 'antd';
import { PlusOutlined,PlusCircleOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import {getDatasetList,getAssetIcon} from '@/services/dataset/index.js'
const { Search } = Input;
import { useNavigate} from 'react-router-dom';
import { getAssetIcon, getDatasetList } from '@/services/dataset/index.js';
import { Form, Input, Pagination } from 'antd';
import moment from 'moment';
const leftdataList=[1,2,3]
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import Styles from './index.less';
const { Search } = Input;
const leftdataList = [1, 2, 3];

const PublicData= React.FC = () => {
const [queryFlow,setQueryFlow]=useState({
page:0,
size:10,
name:null,
available_range:1
const PublicData = (React.FC = () => {
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
name: null,
available_range: 1,
});
const [iconParams,setIconParams]=useState({
name:null,
page:0,
size:10000
})
const navgite=useNavigate();
const [datasetTypeList,setDatasetTypeList]=useState([])
const [datasetDirectionList,setDatasetDirectionList]=useState([])
const [activeType,setActiveType]=useState(null)
const [activeTag,setActiveTag]=useState(null)
const [isModalOpen,setIsModalOpen]=useState(false)
const [datasetList,setDatasetList]=useState([]);
const [total,setTotal]=useState(0);
const [iconParams, setIconParams] = useState({
name: null,
page: 0,
size: 10000,
});
const navgite = useNavigate();
const [datasetTypeList, setDatasetTypeList] = useState([]);
const [datasetDirectionList, setDatasetDirectionList] = useState([]);
const [activeType, setActiveType] = useState(null);
const [activeTag, setActiveTag] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [datasetList, setDatasetList] = useState([]);
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建数据');
const getDatasetlist=(queryFlow)=>{
getDatasetList(queryFlow).then(ret=>{
const getDatasetlist = (queryFlow) => {
getDatasetList(queryFlow).then((ret) => {
console.log(ret);
if(ret.code==200){
setDatasetList(ret.data.content)
setTotal(ret.data.totalElements)
if (ret.code == 200) {
setDatasetList(ret.data.content);
setTotal(ret.data.totalElements);
}
})
}
const onSearch=(values)=>{
});
};
const onSearch = (values) => {
console.log(values);
getAssetIconList({...iconParams,name:values})
}
const getAssetIconList=(params)=>{
getAssetIcon(params).then(ret=>{
getAssetIconList({ ...iconParams, name: values });
};
const getAssetIconList = (params) => {
getAssetIcon(params).then((ret) => {
console.log(ret);
if(ret.code==200&&ret.data.content&&ret.data.content.length>0){
setDatasetTypeList(ret.data.content.filter(item=>item.category_id==1))
setDatasetDirectionList(ret.data.content.filter(item=>item.category_id==2))
}
else{
setDatasetTypeList([])
setDatasetDirectionList([])
if (ret.code == 200 && ret.data.content && ret.data.content.length > 0) {
setDatasetTypeList(ret.data.content.filter((item) => item.category_id == 1));
setDatasetDirectionList(ret.data.content.filter((item) => item.category_id == 2));
} else {
setDatasetTypeList([]);
setDatasetDirectionList([]);
}
})
}
const nameSearch=(values)=>{
});
};
const nameSearch = (values) => {
console.log(values);
getDatasetlist({...queryFlow,name:values})
}
getDatasetlist({ ...queryFlow, name: values });
};
const showModal = () => {
form.resetFields()
setDialogTitle('新建数据集')
form.resetFields();
setDialogTitle('新建数据集');
setIsModalOpen(true);
};
const handleOk = () => {
console.log(1111);
console.log(1111);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const chooseDatasetType=(val,item)=>{
console.log(val,item);
if(item.path==queryFlow.data_type){
setActiveType('')
setQueryFlow({...queryFlow,data_type:null})
getDatasetlist({...queryFlow,data_type:null})
}
else{
setActiveType(item.path)
setQueryFlow({...queryFlow,data_type:item.path})
getDatasetlist({...queryFlow,data_type:item.path})
const chooseDatasetType = (val, item) => {
console.log(val, item);
if (item.path == queryFlow.data_type) {
setActiveType('');
setQueryFlow({ ...queryFlow, data_type: null });
getDatasetlist({ ...queryFlow, data_type: null });
} else {
setActiveType(item.path);
setQueryFlow({ ...queryFlow, data_type: item.path });
getDatasetlist({ ...queryFlow, data_type: item.path });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
// })
};
const chooseDatasetTag=(val,item)=>{
console.log(val,item);
if(item.path==queryFlow.data_tag){
setActiveTag('')
setQueryFlow({...queryFlow,data_tag:null})
getDatasetlist({...queryFlow,data_tag:null})
}
else{
setActiveTag(item.path)
setQueryFlow({...queryFlow,data_tag:item.path})
getDatasetlist({...queryFlow,data_tag:item.path})
const chooseDatasetTag = (val, item) => {
console.log(val, item);
if (item.path == queryFlow.data_tag) {
setActiveTag('');
setQueryFlow({ ...queryFlow, data_tag: null });
getDatasetlist({ ...queryFlow, data_tag: null });
} else {
setActiveTag(item.path);
setQueryFlow({ ...queryFlow, data_tag: item.path });
getDatasetlist({ ...queryFlow, data_tag: item.path });
}
// setQueryFlow({...queryFlow,data_type:item.path},()=>{
// getDatasetlist()
// })
};

const routeToIntro=(e,record)=>{
e.stopPropagation()
console.log(record);
navgite({pathname:`/dataset/datasetIntro/${record.id}` });
}
const routeToIntro = (e, record) => {
e.stopPropagation();
console.log(record);
navgite({ pathname: `/dataset/datasetIntro/${record.id}` });
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
useEffect(()=>{
getAssetIconList(iconParams)
getDatasetlist(queryFlow)
return ()=>{
}
},[])
return (<>

<div className={Styles.datasetCneterBox}>
<div className={Styles.datasetCneterLeftBox}>
<div className={Styles.leftContentBox}>
<Search
placeholder="搜索"
allowClear
onSearch={onSearch}
style={{
width: 300,
marginBottom:'15px',
}}
/>
<div className={Styles.itemTitle}>分类</div>
<div className={Styles.itemBox}>
{datasetTypeList&&datasetTypeList.length>0?datasetTypeList.map(item=>{return <div >
<div className={[Styles.messageBox, item.path===activeType?Styles.active:null].join(' ')} onClick={(e)=>{chooseDatasetType(e, item)}}>
<img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}.png`} alt="" />
<img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}-hover.png`} alt="" />
<span className={Styles.messageText} >{item.name}</span>
useEffect(() => {
getAssetIconList(iconParams);
getDatasetlist(queryFlow);
return () => {};
}, []);
return (
<>
<div className={Styles.datasetCneterBox}>
<div className={Styles.datasetCneterLeftBox}>
<div className={Styles.leftContentBox}>
<Search
placeholder="搜索"
allowClear
onSearch={onSearch}
style={{
width: 300,
marginBottom: '15px',
}}
/>
<div className={Styles.itemTitle}>分类</div>
<div className={Styles.itemBox}>
{datasetTypeList && datasetTypeList.length > 0
? datasetTypeList.map((item) => {
return (
<div>
<div
className={[
Styles.messageBox,
item.path === activeType ? Styles.active : null,
].join(' ')}
onClick={(e) => {
chooseDatasetType(e, item);
}}
>
<img
className={Styles.ptIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}.png`}
alt=""
/>
<img
className={Styles.hoverIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}-hover.png`}
alt=""
/>
<span className={Styles.messageText}>{item.name}</span>
</div>
</div>
);
})
: ''}
</div>
<div className={Styles.itemTitle}>研究方向/应用领域</div>
<div className={Styles.itemBox}>
{datasetDirectionList && datasetDirectionList.length > 0
? datasetDirectionList.map((item) => {
return (
<div>
<div
className={[
Styles.messageBox,
item.path === activeTag ? Styles.active : null,
].join(' ')}
onClick={(e) => {
chooseDatasetTag(e, item);
}}
>
<img
className={Styles.ptIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}.png`}
alt=""
/>
<img
className={Styles.hoverIcon}
style={{ width: '22px' }}
src={`/assets/images/dataset/${item.path}-hover.png`}
alt=""
/>
<span className={Styles.messageText}>{item.name}</span>
</div>
</div>
);
})
: ''}
</div>
</div>
</div>}):''}
</div>
<div className={Styles.itemTitle}>研究方向/应用领域</div>
<div className={Styles.itemBox}>
{datasetDirectionList&&datasetDirectionList.length>0?datasetDirectionList.map(item=>{return <div >
<div className={[Styles.messageBox, item.path===activeTag?Styles.active:null].join(' ')} onClick={(e)=>{chooseDatasetTag(e, item)}}>
<img className={Styles.ptIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}.png`} alt="" />
<img className={Styles.hoverIcon} style={{width:'22px'}} src={`/assets/images/dataset/${item.path}-hover.png`} alt="" />
<span className={Styles.messageText} >{item.name}</span>
</div>
<div className={Styles.datasetCneterRightBox}>
<div className={Styles.dataSource}>
<span>数据总数:{total}个</span>
<div>
<Search
placeholder="按数据名称筛选"
allowClear
onSearch={nameSearch}
style={{
width: 300,
}}
/>
</div>
</div>
</div>}):''}
</div>
</div>
</div>
<div className={Styles.datasetCneterRightBox}>
<div className={Styles.dataSource}>
<span>数据总数:{total}个</span>
<div>
<Search
placeholder="按数据名称筛选"
allowClear
onSearch={nameSearch}
style={{
width: 300,
}}
/>
<div className={Styles.dataContent}>
{datasetList && datasetList.length > 0
? datasetList.map((item) => {
return (
<div className={Styles.dataItem} onClick={(e) => routeToIntro(e, item)}>
<div className={Styles.itemText}>{item.name}</div>
<div className={Styles.itemTime}>
<span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span>
</div>
<div className={Styles.itemIcon}>
<img
style={{ width: '17px', marginRight: '3px' }}
src={`/assets/images/upload-icon.png`}
alt=""
/>
<span>1582</span>
</div>
</div>
);
})
: ''}
{/* <Select.Option value="demo">Demo</Select.Option> */}
</div>
<Pagination size="small" total={total} showSizeChanger showQuickJumper />
</div>
</div>
<div className={Styles.dataContent}>
{datasetList&&datasetList.length>0?datasetList.map(item=>{return <div className={Styles.dataItem} onClick={(e)=>routeToIntro(e,item)}>
<div className={Styles.itemText}>{item.name}</div>
<div className={Styles.itemTime}><span>最近更新: {moment(item.update_time).format('YYYY-MM-DD')}</span></div>
<div className={Styles.itemIcon}><img style={{width:'17px',marginRight:'3px'}} src={`/assets/images/upload-icon.png`} alt="" /><span>1582</span></div>
</div>}):''}
{/* <Select.Option value="demo">Demo</Select.Option> */}
</div>
<Pagination
size="small"
total={total}
showSizeChanger
showQuickJumper
/>
</div>
</div>
</>)
};
export default PublicData;
</>
);
});
export default PublicData;

+ 4
- 3
react-ui/src/pages/Experiment/experimentText/LogList.tsx View File

@@ -1,8 +1,9 @@
import LogGroup from './logGroup';
import { ExperimentStatus } from '../types';
import LogGroup, { type LogGroupProps } from './logGroup';

type LogListProps = {
list: any[];
status: string;
list: Omit<LogGroupProps, 'status'>[];
status: ExperimentStatus;
};

function LogList({ list = [], status }: LogListProps) {


+ 39
- 39
react-ui/src/pages/Experiment/experimentText/editPipeline.less View File

@@ -1,61 +1,61 @@
#graph {
height: 100%;
width: 100%;
position: relative;
}
.editPipelinePropsContent{
position: relative;
width: 100%;
height: 100%;
}
.editPipelinePropsContent {
display: flex;
align-items: center;
width: 100%;
height:43px;
background:#f8fbff;
color:#1d1d20;
font-size:15px;
font-family: 'Alibaba';
padding: 0 20px;
height: 43px;
margin-bottom: 10px;
padding: 0 20px;
color: #1d1d20;
font-size: 15px;
font-family: 'Alibaba';
background: #f8fbff;
}
.centerContainer{
flex: 1;
.centerContainer {
display: flex;
flex: 1;
flex-direction: column;
}
.buttonList{
.buttonList {
display: flex;
align-items: center;
padding: 0 30px;
width: 100%;
height:45px;
background:#ffffff;
box-shadow:0px 3px 6px rgba(146, 146, 146, 0.09);
}
.detailBox{
color:#1d1d20;
font-size:15px;
margin-bottom: 15px;
display: flex;
align-items: center;
}
.allMessageItem{
height: 45px;
padding: 0 30px;
background: #ffffff;
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);
}
.detailBox {
display: flex;
align-items: center;
color:rgba(29, 29, 32, 0.8);
font-size:15px;
margin-right: 30px;
margin-bottom: 15px;
color: #1d1d20;
font-size: 15px;
}
.resultTop{
border-bottom: 1px solid #eee;
.allMessageItem {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
margin-right: 30px;
color: rgba(29, 29, 32, 0.8);
font-size: 15px;
}
.resultContent{
width: 100%;
.resultTop {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.resultContent {
display: flex;

align-items: center;
padding: 0 20px 0 0;
justify-content: space-between;
width: 100%;
margin-bottom: 10px;
}
padding: 0 20px 0 0;
}

+ 12
- 11
react-ui/src/pages/Experiment/experimentText/logGroup.tsx View File

@@ -3,34 +3,35 @@ import { getExperimentPodsLog } from '@/services/experiment/index.js';
import { DoubleRightOutlined, DownOutlined, UpOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import { useEffect, useState } from 'react';
import { ExperimentStatus } from '../types';
import styles from './logGroup.less';

type LogGroupProps = {
log_type?: string;
pod_name?: string;
log_content?: string;
start_time?: string;
status: string;
export type LogGroupProps = {
log_type: 'normal' | 'resource'; // 日志类型
pod_name?: string; // 分布式名称
log_content?: string; // 日志内容
start_time?: string; // 日志开始时间
status: ExperimentStatus; // 实验状态
};

type Log = {
start_time: string;
log_content: string;
start_time: string; // 日志开始时间
log_content: string; // 日志内容
};

function LogGroup({
log_type = '',
log_type = 'normal',
pod_name = '',
log_content = '',
start_time = '',
status = '',
status = ExperimentStatus.Pending,
}: LogGroupProps) {
const [collapse, setCollapse] = useState(true);
const [logList, setLogList, logListRef] = useStateRef<Log[]>([]);
const [completed, setCompleted] = useState(false);

useEffect(() => {
if (status === 'Running') {
if (status === ExperimentStatus.Running) {
const timerId = setInterval(() => {
requestExperimentPodsLog();
}, 5000);


+ 10
- 3
react-ui/src/pages/Experiment/experimentText/props.jsx View File

@@ -160,7 +160,12 @@ const Props = forwardRef(({ onParentChange }, ref) => {
Object.keys(stagingItem.control_strategy) &&
Object.keys(stagingItem.control_strategy).length > 0
? Object.keys(stagingItem.control_strategy).map((item) => (
<Form.Item label={stagingItem.control_strategy[item].label} disabled name={item}>
<Form.Item
key={item}
label={stagingItem.control_strategy[item].label}
disabled
name={item}
>
<Input disabled />
</Form.Item>
))
@@ -178,6 +183,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
Object.keys(stagingItem.in_parameters).length > 0
? Object.keys(stagingItem.in_parameters).map((item) => (
<Form.Item
key={item}
label={stagingItem.in_parameters[item].label + '(' + item + ')'}
name={item}
disabled
@@ -200,6 +206,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
Object.keys(stagingItem.out_parameters).length > 0
? Object.keys(stagingItem.out_parameters).map((item) => (
<Form.Item
key={item}
label={stagingItem.out_parameters[item].label + '(' + item + ')'}
disabled
rules={[{ required: stagingItem.out_parameters[item].require ? true : false }]}
@@ -227,7 +234,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
>
{resultObj && resultObj.length > 0
? resultObj.map((item) => (
<div>
<div key={item.name}>
<div className={Styles.resultTop}>
<span>{item.name}</span>
<div style={{ display: 'flex' }}>
@@ -249,7 +256,7 @@ const Props = forwardRef(({ onParentChange }, ref) => {
</div>
{item.value && item.value.length > 0
? item.value.map((ele) => (
<div className={Styles.resultContent}>
<div className={Styles.resultContent} key={ele.name}>
<span>{ele.name}</span>
<span>{ele.size}</span>
</div>


+ 0
- 11
react-ui/src/pages/Experiment/status.ts View File

@@ -4,17 +4,6 @@ export interface StatusInfo {
icon: string;
}

export enum ExperimentStatus {
Running = 'Running',
Succeeded = 'Succeeded',
Pending = 'Pending',
Failed = 'Failed',
Error = 'Error',
Terminated = 'Terminated',
Skipped = 'Skipped',
Omitted = 'Omitted',
}

export const experimentStatusInfo: Record<string, StatusInfo | undefined> = {
Running: {
label: '运行中',


+ 10
- 0
react-ui/src/pages/Experiment/types.ts View File

@@ -0,0 +1,10 @@
export enum ExperimentStatus {
Running = 'Running',
Succeeded = 'Succeeded',
Pending = 'Pending',
Failed = 'Failed',
Error = 'Error',
Terminated = 'Terminated',
Skipped = 'Skipped',
Omitted = 'Omitted',
}

+ 43
- 53
react-ui/src/pages/Model/index.jsx View File

@@ -1,27 +1,24 @@

import React ,{useEffect,useState}from 'react';
import Styles from './index.less'
import { Input, Space ,Button,Tabs,Pagination,Modal, Form,message, Radio,} from 'antd';
import { PlusOutlined,PlusCircleOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import { Form, Input, Tabs } from 'antd';
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import Styles from './index.less';
import PersonalData from './personalData';
import PublicData from './publicData';
// import {getModelList} from '@/services/dataset/index.js'
const { Search } = Input;
import { useNavigate} from 'react-router-dom';
import moment from 'moment';
const { TabPane } = Tabs;
import PublicData from './publicData';
import PersonalData from './personalData'
const leftdataList=[1,2,3]
const leftdataList = [1, 2, 3];

const Dataset= React.FC = () => {
const [queryFlow,setQueryFlow]=useState({
page:0,
size:10,
name:null
const Dataset = () => {
const [queryFlow, setQueryFlow] = useState({
page: 0,
size: 10,
name: null,
});
const navgite=useNavigate();
const [isModalOpen,setIsModalOpen]=useState(false)
const [datasetList,setDatasetList]=useState([]);
const [total,setTotal]=useState(0);
const navgite = useNavigate();
const [isModalOpen, setIsModalOpen] = useState(false);
const [datasetList, setDatasetList] = useState([]);
const [total, setTotal] = useState(0);
const [form] = Form.useForm();
const [dialogTitle, setDialogTitle] = useState('新建数据');
// const getModelLists=()=>{
@@ -35,49 +32,42 @@ const Dataset= React.FC = () => {
// }

const showModal = () => {
form.resetFields()
setDialogTitle('新建数据集')
form.resetFields();
setDialogTitle('新建数据集');
setIsModalOpen(true);
};
const handleOk = () => {
console.log(1111);
console.log(1111);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const onFinish = (values) => {
};
const routeToIntro=(e,record)=>{
e.stopPropagation()
navgite({pathname:'/dataset/datasetIntro' });
}
const onFinish = (values) => {};
const routeToIntro = (e, record) => {
e.stopPropagation();
navgite({ pathname: '/dataset/datasetIntro' });
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
useEffect(()=>{
return ()=>{
}
},[])
return (<div className={Styles.datasetBox}>
<div className={Styles.datasetTopBox}>
</div>
<div className={Styles.datasetAllBox}>
<Tabs
defaultActiveKey="1"
>
<TabPane tab="模型广场" key="1">
<PublicData/>
</TabPane>
<TabPane tab="个人模型" key="2">
<PersonalData/>
</TabPane>
</Tabs>
</div>
</div>)
useEffect(() => {
return () => {};
}, []);
return (
<div className={Styles.datasetBox}>
<div className={Styles.datasetTopBox}></div>
<div className={Styles.datasetAllBox}>
<Tabs defaultActiveKey="1">
<TabPane tab="模型广场" key="1">
<PublicData />
</TabPane>
<TabPane tab="个人模型" key="2">
<PersonalData />
</TabPane>
</Tabs>
</div>
</div>
);
};
export default Dataset;
export default Dataset;

+ 269
- 272
react-ui/src/pages/Model/index.less View File

@@ -1,296 +1,293 @@
.datasetTopBox{
.datasetTopBox {
display: flex;
align-items: center;
width: 100%;
height: 49px;
padding: 0 30px;
padding-right: 30px;
background-image: url(/assets/images/pipeline-back.png);
background-size: 100% 100%;
}
.datasetIntroTopBox {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
height: 110px;
margin-bottom: 10px;
padding: 25px 30px;
background-image: url(/assets/images/dataset-back.png);

background-size: 100% 100%;
.smallTagBox {
display: flex;
align-items: center;
padding-right: 30px;
width: 100%;
height: 49px;
background-size: 100% 100%;
background-image: url(/assets/images/pipeline-back.png);
padding: 0 30px;
color: #1664ff;
font-size: 14px;
.tagItem {
margin-right: 20px;
padding: 4px 10px;
background: rgba(22, 100, 255, 0.1);
border-radius: 4px;
}
}
}
.datasetIntroTopBox{
.dataListBox {
padding: 20px 30px;
color: #1d1d20;
font-size: 16px;
background: #ffffff;
border-radius: 10px;
box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09);
.dataButtonList {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: 100%;
height: 110px;
background-size: 100% 100%;
background-image: url(/assets/images/dataset-back.png);
margin-bottom: 10px;
padding: 25px 30px;
.smallTagBox{
display: flex;
align-items: center;
color:#1664ff;
font-size:14px;
.tagItem{
padding: 4px 10px;
background: rgba(22, 100, 255, 0.1);
border-radius:4px;
margin-right: 20px;
}
}
}
.dataListBox{
padding: 20px 30px;
background:#ffffff;
border-radius:10px;
box-shadow:0px 2px 12px rgba(180, 182, 191, 0.09);
color:#1d1d20;
font-size:16px;
.dataButtonList{
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
margin: 24px 0 30px 0;
color:#575757;
font-size:16px;
}
height: 32px;
margin: 24px 0 30px 0;
color: #575757;
font-size: 16px;
}
}
.datasetIntroCneterBox{
height: 77vh;
padding: 20px 30px;
background:#ffffff;
border-radius:10px;
box-shadow:0px 2px 12px rgba(180, 182, 191, 0.09);
.datasetIntroCneterBox {
height: 77vh;
padding: 20px 30px;
background: #ffffff;
border-radius: 10px;
box-shadow: 0px 2px 12px rgba(180, 182, 191, 0.09);
}
.datasetIntroTitle{
color:#1d1d20;
font-size:15px;
margin: 37px 0 10px 0;
.datasetIntroTitle {
margin: 37px 0 10px 0;
color: #1d1d20;
font-size: 15px;
}
.datasetIntroText{
color:#575757;
font-size:14px;
margin-bottom: 30px;
.datasetIntroText {
margin-bottom: 30px;
color: #575757;
font-size: 14px;
}
.datasetBox{
background:#f9fafb;
font-family: 'Alibaba';
:global{
.ant-tabs-top >.ant-tabs-nav{
margin: 0;
}
.ant-pagination{
text-align: right;
}
.datasetBox {
font-family: 'Alibaba';
background: #f9fafb;
:global {
.ant-tabs-top > .ant-tabs-nav {
margin: 0;
}
.ant-pagination {
text-align: right;
}
}
}
.datasetAllBox{
:global{
.ant-tabs-nav .ant-tabs-nav-wrap{
margin: -48px 0 0 30px;
}
.datasetAllBox {
:global {
.ant-tabs-nav .ant-tabs-nav-wrap {
margin: -48px 0 0 30px;
}
}
}
.plusButton{
margin: 0 18px 0 20px;
background:rgba(22, 100, 255, 0.06);
border:1px solid;
border-color:rgba(22, 100, 255, 0.11);
border-radius:4px;
color:#1d1d20;
font-size:14px;
font-family: 'Alibaba';
.plusButton {
margin: 0 18px 0 20px;
color: #1d1d20;
font-size: 14px;
font-family: 'Alibaba';
background: rgba(22, 100, 255, 0.06);
border: 1px solid;
border-color: rgba(22, 100, 255, 0.11);
border-radius: 4px;
}
.plusButton:hover{
background:rgba(22, 100, 255, 0.06)!important;
border:1px solid!important;
border-color:rgba(22, 100, 255, 0.11)!important;
color:#1d1d20!important;
.plusButton:hover {
color: #1d1d20 !important;
background: rgba(22, 100, 255, 0.06) !important;
border: 1px solid !important;
border-color: rgba(22, 100, 255, 0.11) !important;
}
.datasetCneterBox{
display: flex;
justify-content: space-between;
height: 85vh;
width: 100%;
.datasetCneterLeftBox{
width:340px;
height:100%;
background:#ffffff;
box-shadow:0px 3px 6px rgba(146, 146, 146, 0.09);
margin-right: 10px;
padding-top: 15px;
.custTab{
display: flex;
border-bottom: 1px solid #e0eaff;
height: 32px;
.tabItem{
width: 52px;
height: 100%;
text-align: center;
color:#808080;
font-size:15px;
cursor: pointer;
}
.datasetCneterBox {
display: flex;
justify-content: space-between;
width: 100%;
height: 85vh;

.datasetCneterLeftBox {
width: 340px;
height: 100%;
margin-right: 10px;
padding-top: 15px;
background: #ffffff;
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);
.custTab {
display: flex;
height: 32px;
border-bottom: 1px solid #e0eaff;
.tabItem {
width: 52px;
height: 100%;
color: #808080;
font-size: 15px;
text-align: center;
cursor: pointer;
}
}
.leftContentBox {
max-height: 80vh;
padding: 15px 20px;
overflow-x: hidden;
overflow-y: auto;
.itemTitle {
margin-bottom: 15px;
color: #1d1d20;
font-size: 14px;
}
.itemBox {
display: flex;
flex-wrap: wrap;
align-content: start;
width: 110%;
.messageBox {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: 92px;
height: 62px;
margin: 0 12px 20px 0;
padding: 11px 0px 7px 0px;
color: #1d1d20;
font-size: 12px;
border: 1px solid;
border-color: rgba(22, 100, 255, 0.05);
border-radius: 4px;
cursor: pointer;
.ptIcon {
display: block;
}
.hoverIcon {
display: none;
}
.messageText {
width: 65px;
overflow: hidden;
white-space: nowrap;
text-align: center;
text-overflow: ellipsis;
transition: all 0.2s;
}
}
.messageBox:hover {
background: rgba(22, 100, 255, 0.03);
border: 1px solid;
border-color: #1664ff;
.ptIcon {
display: none;
}
.hoverIcon {
display: block;
}
}
.leftContentBox{
max-height: 80vh;
overflow-y: auto;
overflow-x: hidden;
padding: 15px 20px;
.itemTitle{
color:#1d1d20;
font-size:14px;
margin-bottom: 15px;
}
.itemBox{
width: 110%;
display: flex;
flex-wrap: wrap;
align-content: start;
.messageBox{
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
cursor: pointer;
width:92px;
height:62px;
border:1px solid;
border-color:rgba(22, 100, 255, 0.05);
border-radius:4px;
margin: 0 12px 20px 0;
padding: 11px 0px 7px 0px;
color:#1d1d20;
font-size:12px;
.ptIcon{
display: block;
}
.hoverIcon{
display: none;
}
.messageText{
width: 65px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: all 0.2s;
}
}
.messageBox:hover{
background:rgba(22, 100, 255, 0.03);
border:1px solid;
border-color:#1664ff;
.ptIcon{
display: none;
}
.hoverIcon{
display: block;
}
}
.active{
background:rgba(22, 100, 255, 0.03)!important;
border:1px solid!important;
border-color:#1664ff!important;
.ptIcon{
display: none!important;
}
.hoverIcon{
display: block!important;
}
}
}
.active {
background: rgba(22, 100, 255, 0.03) !important;
border: 1px solid !important;
border-color: #1664ff !important;
.ptIcon {
display: none !important;
}
.hoverIcon {
display: block !important;
}
}
}
}
.datasetCneterRightBox{
display: flex;
flex-direction: column;
padding: 22px 30px 26px 30px;
flex: 1;
height:100%;
background:#ffffff;
box-shadow:0px 3px 6px rgba(146, 146, 146, 0.09);
.dataSource{
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
margin-bottom: 30px;
color:rgba(29, 29, 32, 0.8);
font-size:15px;
}
.datasetCneterRightBox {
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
padding: 22px 30px 26px 30px;
background: #ffffff;
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);
.dataSource {
display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
margin-bottom: 30px;
color: rgba(29, 29, 32, 0.8);
font-size: 15px;
}
.dataContent {
display: flex;
flex: 1;
flex-wrap: wrap;
align-content: flex-start;
width: 100%;
.dataItem {
position: relative;
width: 32%;
height: 66px;
margin: 0 15px 18px 0;
background: rgba(128, 128, 128, 0.05);
border-radius: 8px;
box-shadow: 0px 0px 12px rgba(75, 84, 137, 0.05);
cursor: pointer;
.itemText {
position: absolute;
top: 10px;
left: 20px;
color: #1d1d20;
font-size: 15px;
}
.itemTime {
position: absolute;
bottom: 10px;
left: 20px;
color: #808080;
font-size: 14px;
}
.dataContent{
width: 100%;
flex: 1;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
.dataItem{
width: 32%;
margin: 0 15px 18px 0;
height:66px;
position: relative;
background:rgba(128, 128, 128, 0.05);
border-radius:8px;
box-shadow:0px 0px 12px rgba(75, 84, 137, 0.05);
cursor: pointer;
.itemText{
position: absolute;
left: 20px;
top: 10px;
color:#1d1d20;
font-size:15px;
}
.itemTime{
position: absolute;
left: 20px;
bottom: 10px;
color:#808080;
font-size:14px;
}
.itemIcon{
position: absolute;
right: 20px;
bottom: 10px;
color:#808080;
font-size:14px;
}
}
.itemIcon {
position: absolute;
right: 20px;
bottom: 10px;
color: #808080;
font-size: 14px;
}
}
}
}
}
.modal {
:global {
.ant-modal-content {
background:linear-gradient(180deg,#cfdfff 0%,#d4e2ff 9.77%,#ffffff 40%,#ffffff 100%);
border-radius:21px;
padding: 20px 67px;
width: 825px;

}
.ant-modal-header{
background-color: transparent;
margin: 20px 0;
}
.ant-input{
border-color:#e6e6e6;
height: 40px;
}
.ant-form-item .ant-form-item-label >label{
color:rgba(29, 29, 32, 0.8);
}
.ant-modal-footer{
margin: 40px 0 30px 0;
display: flex;
justify-content: center;
}
.ant-btn{
width:110px;
height:40px;
font-size:18px;
background:rgba(22, 100, 255, 0.06);
border-radius:10px;
border-color: transparent;
}
.ant-btn-primary{
background:#1664ff;
}
:global {
.ant-modal-content {
width: 825px;
padding: 20px 67px;
background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%);
border-radius: 21px;
}
.ant-modal-header {
margin: 20px 0;
background-color: transparent;
}
.ant-input {
height: 40px;
border-color: #e6e6e6;
}
}
.ant-form-item .ant-form-item-label > label {
color: rgba(29, 29, 32, 0.8);
}
.ant-modal-footer {
display: flex;
justify-content: center;
margin: 40px 0 30px 0;
}
.ant-btn {
width: 110px;
height: 40px;
font-size: 18px;
background: rgba(22, 100, 255, 0.06);
border-color: transparent;
border-radius: 10px;
}
.ant-btn-primary {
background: #1664ff;
}
}
}

+ 88
- 39
react-ui/src/pages/Model/modelIntro.jsx View File

@@ -7,7 +7,12 @@ import {
getModelVersionsById,
} from '@/services/dataset/index.js';
import { downLoadZip } from '@/utils/downloadfile';
import { DeleteOutlined, PlusCircleOutlined, UploadOutlined } from '@ant-design/icons';
import {
DeleteOutlined,
DownloadOutlined,
PlusCircleOutlined,
UploadOutlined,
} from '@ant-design/icons';
import { Button, Form, Input, Modal, Select, Table, Tabs, Upload, message } from 'antd';
import moment from 'moment';
import { useEffect, useRef, useState } from 'react';
@@ -57,15 +62,13 @@ const Dataset = () => {
const getModelByDetail = () => {
getModelById(locationParams.id).then((ret) => {
console.log(ret);
if (ret.code == 200) {
setDatasetDetailObj(ret.data);
}
setDatasetDetailObj(ret.data);
});
};
const getModelVersionsList = () => {
getModelVersionsById(locationParams.id).then((ret) => {
console.log(ret);
if (ret.code == 200 && ret.data && ret.data.length > 0) {
if (ret.data && ret.data.length > 0) {
setVersionList(
ret.data.map((item) => {
return {
@@ -101,12 +104,8 @@ const Dataset = () => {

onOk: () => {
deleteModelVersion({ models_id: locationParams.id, version }).then((ret) => {
if (ret.code == 200) {
message.success('删除成功');
getModelVersions({ version, models_id: locationParams.id });
} else {
message.error(ret.msg);
}
message.success('删除成功');
getModelVersions({ version, models_id: locationParams.id });
});
},
});
@@ -121,9 +120,7 @@ const Dataset = () => {
const getModelVersions = (params) => {
getModelVersionIdList(params).then((ret) => {
console.log(ret);
if (ret.code == 200) {
setWordList(ret.data);
}
setWordList(ret.data);
});
};
const handleExport = async () => {
@@ -150,18 +147,16 @@ const Dataset = () => {
console.log('Failed:', errorInfo);
};
const columns = [
// {
// title: '序号',
// dataIndex: 'index',
// key: 'index',
// width: 80,
// render(text, record, index) {
// return (
// <span>{(pageOption.current.page - 1) * 10 + index + 1}</span>
// )
// }
// // render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`,
// },
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 80,
render(text, record, index) {
return <span>{(pageOption.current.page - 1) * 10 + index + 1}</span>;
},
// render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`,
},
{
title: '文件名称',
dataIndex: 'file_name',
@@ -184,6 +179,23 @@ const Dataset = () => {
key: 'update_time',
render: (text) => <span>{moment(text).format('YYYY-MM-DD HH:mm:ss')}</span>,
},
{
title: '操作',
dataIndex: 'option',
width: '100px',
key: 'option',
render: (_, record) => [
<Button
type="link"
size="small"
key="download"
icon={<DownloadOutlined />}
onClick={(e) => downloadAlone(e, record)}
>
下载
</Button>,
],
},
];
const pageOption = useRef({ page: 1, size: 10 });

@@ -256,12 +268,15 @@ const Dataset = () => {
disabled={!version}
style={{ margin: '0 20px 0 0' }}
onClick={handleExport}
icon={<UploadOutlined style={{ color: '#1664ff' }} />}
icon={<DownloadOutlined style={{ color: '#1664ff' }} />}
>
下载
</Button>
</div>
</div>
<div style={{ marginBottom: '10px', fontSize: '14px' }}>
{wordList.length > 0 ? wordList[0].description : null}
</div>
<Table columns={columns} dataSource={wordList} pagination={false} />
</div>
</TabPane>
@@ -300,21 +315,55 @@ const Dataset = () => {
<Form.Item
label="模型名称"
name="name"
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
rules={[
{
required: true,
message: '请输入模型名称',
},
]}
>
<Input disabled placeholder="请输入数据集名称" />
<Input disabled placeholder="请输入模型名称" />
</Form.Item>
<Form.Item label="模型版本" name="version">
<Input placeholder="请输入数据集版本" />
<Form.Item
label="模型版本"
name="version"
rules={[
{
required: true,
message: '请输入模型版本',
},
]}
>
<Input placeholder="请输入模型版本" maxLength={64} showCount allowClear />
</Form.Item>
<Form.Item label="模型文件" name="dataset_version_vos">
<Form.Item
label="版本描述"
name="description"
rules={[
{
required: true,
message: '请输入版本描述',
},
]}
>
<Input.TextArea
placeholder="请输入版本描述"
autoSize={{ minRows: 2, maxRows: 6 }}
maxLength={256}
showCount
allowClear
/>
</Form.Item>
<Form.Item
label="模型文件"
name="dataset_version_vos"
rules={[
{
required: true,
message: '请上传模型文件',
},
]}
>
<Upload {...props}>
<Button
style={{


+ 5
- 5
react-ui/src/pages/Monitor/Job/detail.tsx View File

@@ -1,14 +1,14 @@
import React, { useEffect } from 'react';
import { Modal, Descriptions, Button } from 'antd';
import { FormattedMessage, useIntl } from '@umijs/max';
import { getValueEnumLabel } from '@/utils/options';
import { DictValueEnumObj } from '@/components/DictTag';
import { getValueEnumLabel } from '@/utils/options';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Button, Descriptions, Modal } from 'antd';
import React, { useEffect } from 'react';

/* *
*
* @author whiteshader@163.com
* @datetime 2023/02/07
*
*
* */

export type OperlogFormValueType = Record<string, unknown> & Partial<API.Monitor.Job>;


+ 30
- 17
react-ui/src/pages/Monitor/Job/edit.tsx View File

@@ -1,20 +1,20 @@
import React, { useEffect } from 'react';
import { DictOptionType, DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormCaptcha,
ProFormDigit,
ProFormText,
ProFormTextArea,
ProFormRadio,
ProFormSelect,
ProFormCaptcha,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictOptionType, DictValueEnumObj } from '@/components/DictTag';
import React, { useEffect } from 'react';

/**
* 定时任务调度 Edit Form
*
*
* @author whiteshader
* @date 2023-02-07
*/
@@ -83,7 +83,8 @@ const JobForm: React.FC<JobFormProps> = (props) => {
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
onFinish={handleFinish}
>
<ProFormDigit
name="jobId"
label={intl.formatMessage({
@@ -143,7 +144,12 @@ const JobForm: React.FC<JobFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入调用目标字符串!" defaultMessage="请输入调用目标字符串!" />,
message: (
<FormattedMessage
id="请输入调用目标字符串!"
defaultMessage="请输入调用目标字符串!"
/>
),
},
]}
/>
@@ -153,7 +159,7 @@ const JobForm: React.FC<JobFormProps> = (props) => {
id: 'monitor.job.cron_expression',
defaultMessage: 'cron执行表达式',
})}
captchaTextRender={() => "生成表达式"}
captchaTextRender={() => '生成表达式'}
onGetCaptcha={() => {
// form.setFieldValue('cronExpression', '0/20 * * * * ?');
return new Promise((resolve, reject) => {
@@ -172,17 +178,22 @@ const JobForm: React.FC<JobFormProps> = (props) => {
valueEnum={{
0: '立即执行',
1: '执行一次',
3: '放弃执行'
3: '放弃执行',
}}
rules={[
{
required: false,
message: <FormattedMessage id="请输入计划执行错误策略!" defaultMessage="请输入计划执行错误策略!" />,
message: (
<FormattedMessage
id="请输入计划执行错误策略!"
defaultMessage="请输入计划执行错误策略!"
/>
),
},
]}
fieldProps={{
optionType: "button",
buttonStyle: "solid"
optionType: 'button',
buttonStyle: 'solid',
}}
/>
<ProFormRadio.Group
@@ -200,12 +211,14 @@ const JobForm: React.FC<JobFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入是否并发执行!" defaultMessage="请输入是否并发执行!" />,
message: (
<FormattedMessage id="请输入是否并发执行!" defaultMessage="请输入是否并发执行!" />
),
},
]}
fieldProps={{
optionType: "button",
buttonStyle: "solid"
optionType: 'button',
buttonStyle: 'solid',
}}
/>
<ProFormRadio.Group


+ 37
- 23
react-ui/src/pages/Monitor/Job/index.tsx View File

@@ -1,19 +1,36 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess, history } from '@umijs/max';
import { Dropdown, FormInstance, Space } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
import { getJobList, removeJob, addJob, updateJob, exportJob, runJob } from '@/services/monitor/job';
import DictTag from '@/components/DictTag';
import {
addJob,
exportJob,
getJobList,
removeJob,
runJob,
updateJob,
} from '@/services/monitor/job';
import { getDictSelectOption, getDictValueEnum } from '@/services/system/dict';
import UpdateForm from './edit';
import {
DeleteOutlined,
DownOutlined,
EditOutlined,
ExclamationCircleOutlined,
PlusOutlined,
} from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, history, useAccess, useIntl } from '@umijs/max';
import { Button, Dropdown, FormInstance, Modal, Space, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import DetailForm from './detail';
import DictTag from '@/components/DictTag';
import UpdateForm from './edit';

/**
* 定时任务调度 List Page
*
*
* @author whiteshader
* @date 2023-02-07
*/
@@ -126,7 +143,6 @@ const handleExport = async () => {
}
};


const JobTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();

@@ -184,7 +200,7 @@ const JobTableList: React.FC = () => {
valueType: 'text',
valueEnum: jobGroupOptions,
render: (_, record) => {
return (<DictTag options={jobGroupOptions} value={record.jobGroup} />);
return <DictTag options={jobGroupOptions} value={record.jobGroup} />;
},
},
{
@@ -203,7 +219,7 @@ const JobTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -216,7 +232,7 @@ const JobTableList: React.FC = () => {
type="link"
size="small"
key="edit"
icon = <EditOutlined />
icon=<EditOutlined />
hidden={!access.hasPerms('monitor:job:edit')}
onClick={() => {
setModalVisible(true);
@@ -230,7 +246,7 @@ const JobTableList: React.FC = () => {
size="small"
danger
key="batchRemove"
icon = <DeleteOutlined />
icon=<DeleteOutlined />
hidden={!access.hasPerms('monitor:job:remove')}
onClick={async () => {
Modal.confirm({
@@ -282,15 +298,13 @@ const JobTableList: React.FC = () => {
}
},
});
}
else if (key === 'detail') {
} else if (key === 'detail') {
setDetailModalVisible(true);
setCurrentRow(record);
}
else if( key === 'log') {
} else if (key === 'log') {
history.push(`/monitor/job-log/index/${record.jobId}`);
}
}
},
}}
>
<a className="ant-dropdown-link" onClick={(e) => e.preventDefault()}>
@@ -347,7 +361,7 @@ const JobTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>
@@ -439,7 +453,7 @@ const JobTableList: React.FC = () => {
}}
open={modalVisible}
values={currentRow || {}}
jobGroupOptions={jobGroupOptions||{}}
jobGroupOptions={jobGroupOptions || {}}
statusOptions={statusOptions}
/>
<DetailForm


+ 5
- 8
react-ui/src/pages/Monitor/JobLog/detail.tsx View File

@@ -1,14 +1,14 @@
import { DictValueEnumObj } from '@/components/DictTag';
import { getValueEnumLabel } from '@/utils/options';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Descriptions, Modal } from 'antd';
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';

/* *
*
* @author whiteshader@163.com
* @datetime 2021/09/16
*
*
* */

export type JobLogFormValueType = Record<string, unknown> & Partial<API.Monitor.JobLog>;
@@ -22,19 +22,16 @@ export type JobLogFormProps = {
};

const JobLogDetailForm: React.FC<JobLogFormProps> = (props) => {

const { values, statusOptions, jobGroupOptions } = props;

useEffect(() => {
}, []);
useEffect(() => {}, []);

const intl = useIntl();
const handleOk = () => {
};
const handleOk = () => {};
const handleCancel = () => {
props.onCancel();
};
return (
<Modal
width={640}


+ 23
- 17
react-ui/src/pages/Monitor/JobLog/index.tsx View File

@@ -1,19 +1,24 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess, useParams, history } from '@umijs/max';
import DictTag from '@/components/DictTag';
import { getJob } from '@/services/monitor/job';
import { exportJobLog, getJobLogList, removeJobLog } from '@/services/monitor/jobLog';
import { getDictValueEnum } from '@/services/system/dict';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, history, useAccess, useIntl, useParams } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getJobLogList, removeJobLog, exportJobLog } from '@/services/monitor/jobLog';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import DetailForm from './detail';
import { getDictValueEnum } from '@/services/system/dict';
import { getJob } from '@/services/monitor/job';
import DictTag from '@/components/DictTag';

/**
* 定时任务调度日志 List Page
*
*
* @author whiteshader
* @date 2023-02-07
*/
@@ -80,7 +85,6 @@ const handleExport = async () => {
}
};


const JobLogTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();

@@ -107,10 +111,10 @@ const JobLogTableList: React.FC = () => {
const jobId = params.id || 0;
useEffect(() => {
if (jobId !== undefined && jobId !== 0) {
getJob(Number(jobId)).then(response => {
getJob(Number(jobId)).then((response) => {
setQueryParams({
jobName: response.data.jobName,
jobGroup: response.data.jobGroup
jobGroup: response.data.jobGroup,
});
});
}
@@ -140,7 +144,9 @@ const JobLogTableList: React.FC = () => {
valueType: 'text',
},
{
title: <FormattedMessage id="monitor.job.log.invoke_target" defaultMessage="调用目标字符串" />,
title: (
<FormattedMessage id="monitor.job.log.invoke_target" defaultMessage="调用目标字符串" />
),
dataIndex: 'invokeTarget',
valueType: 'textarea',
},
@@ -155,7 +161,7 @@ const JobLogTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -253,7 +259,7 @@ const JobLogTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>


+ 32
- 34
react-ui/src/pages/Monitor/Online/index.tsx View File

@@ -1,20 +1,18 @@
import { forceLogout, getOnlineUserList } from '@/services/monitor/online';
import { DeleteOutlined } from '@ant-design/icons';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import React, { useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import { getOnlineUserList, forceLogout } from '@/services/monitor/online';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { DeleteOutlined } from '@ant-design/icons';
import React, { useEffect, useRef } from 'react';

/* *
*
* @author whiteshader@163.com
* @datetime 2023/02/07
*
*
* */


const handleForceLogout = async (selectedRow: API.Monitor.OnlineUserType) => {
const hide = message.loading('正在强制下线');
try {
@@ -130,32 +128,32 @@ const OnlineUserTableList: React.FC = () => {
];

return (
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.Monitor.OnlineUserType>
headerTitle={intl.formatMessage({
id: 'pages.searchTable.title',
defaultMessage: '信息',
})}
actionRef={actionRef}
formRef={formTableRef}
rowKey="tokenId"
key="logininforList"
search={{
labelWidth: 120,
}}
request={(params) =>
getOnlineUserList({ ...params } as API.Monitor.OnlineUserListParams).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
columns={columns}
/>
</div>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.Monitor.OnlineUserType>
headerTitle={intl.formatMessage({
id: 'pages.searchTable.title',
defaultMessage: '信息',
})}
actionRef={actionRef}
formRef={formTableRef}
rowKey="tokenId"
key="logininforList"
search={{
labelWidth: 120,
}}
request={(params) =>
getOnlineUserList({ ...params } as API.Monitor.OnlineUserListParams).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
columns={columns}
/>
</div>
);
};



+ 25
- 25
react-ui/src/pages/Pipeline/editPipeline/editPipeline.less View File

@@ -1,46 +1,46 @@
#graph {
height: 100%;
width: 100%;
position: relative;
}
.editPipelinePropsContent{
position: relative;
width: 100%;
height: 100%;
}
.editPipelinePropsContent {
display: flex;
align-items: center;
width: 100%;
height:43px;
background:#f8fbff;
height: 43px;
margin-bottom: 10px;
color:#1d1d20;
font-size:15px;
font-family: 'Alibaba';
padding: 0 20px;
color: #1d1d20;
font-size: 15px;
font-family: 'Alibaba';
background: #f8fbff;
}
.centerContainer{
flex: 1;
.centerContainer {
display: flex;
flex: 1;
flex-direction: column;
}
.buttonList{
.buttonList {
display: flex;
align-items: center;
justify-content: end;
padding: 0 30px;
width: 100%;
height:45px;
background:#ffffff;
box-shadow:0px 3px 6px rgba(146, 146, 146, 0.09);
height: 45px;
padding: 0 30px;
background: #ffffff;
box-shadow: 0px 3px 6px rgba(146, 146, 146, 0.09);
}
.rightmenu {
position: absolute;
top: 0px;
left: 0px;
width: 120px;
height: 146px;
left: 0px;
top: 0px;
background-color: #ffffff;
font-size: 12px;
color: #333333;
overflow-y: auto;
color: #333333;
font-size: 12px;

background-color: #ffffff;
}

.rightmenuItem {
@@ -48,6 +48,6 @@
cursor: pointer;
}
.rightmenuItem:hover {
background-color: rgba(24, 144, 255, 0.3);
color: #ffffff;
}
background-color: rgba(24, 144, 255, 0.3);
}

+ 654
- 601
react-ui/src/pages/Pipeline/editPipeline/index.jsx
File diff suppressed because it is too large
View File


+ 72
- 60
react-ui/src/pages/Pipeline/editPipeline/modelMenus.jsx View File

@@ -1,62 +1,74 @@
import React ,{ useState,useEffect,useRef }from 'react';
import { Collapse, Divider } from 'antd';
import Styles from './modelMenus.less'
import {getComponentAll} from '@/services/pipeline/index.js'
import { getComponentAll } from '@/services/pipeline/index.js';
import { Collapse } from 'antd';
import { useEffect, useState } from 'react';
import Styles from './modelMenus.less';
const items = [
{
key: '1',
label: 'This is panel header 1',
children: [1,2,3,4,5],
},
{
key: '2',
label: 'This is panel header 2',
children: [1,2,3,4,5],
},
{
key: '3',
label: 'This is panel header 3',
children: [1,2,3,4,5],
},
];
const modelMenus = ({onParDragEnd}) => {
const [modelMenusList,setModelMenusList]=useState([])
useEffect(()=>{
getComponentAll().then(ret=>{
console.log(ret);
if(ret.code==200){
setModelMenusList(ret.data)
}
})
},[])
const dragEnd=(e,data)=>{
console.log(e,data);
onParDragEnd({...data,x:e.clientX,y:e.clientY,label:data.component_label,img:`/assets/images/${data.icon_path}.png`})
}
const { Panel } = Collapse;
return (<div style={{width:'250px',height:'99%'}} className={Styles.collapse}>
<Collapse
collapsible="header"
defaultActiveKey={['1']}
expandIconPosition="end"
>
{
key: '1',
label: 'This is panel header 1',
children: [1, 2, 3, 4, 5],
},
{
key: '2',
label: 'This is panel header 2',
children: [1, 2, 3, 4, 5],
},
{
key: '3',
label: 'This is panel header 3',
children: [1, 2, 3, 4, 5],
},
];
const modelMenus = ({ onParDragEnd }) => {
const [modelMenusList, setModelMenusList] = useState([]);
useEffect(() => {
getComponentAll().then((ret) => {
console.log(ret);
if (ret.code == 200) {
setModelMenusList(ret.data);
}
});
}, []);
const dragEnd = (e, data) => {
console.log(e, data);
onParDragEnd({
...data,
x: e.clientX,
y: e.clientY,
label: data.component_label,
img: `/assets/images/${data.icon_path}.png`,
});
};
const { Panel } = Collapse;
return (
<div style={{ width: '250px', height: '99%' }} className={Styles.collapse}>
<Collapse collapsible="header" defaultActiveKey={['1']} expandIconPosition="end">
{modelMenusList && modelMenusList.length > 0
? modelMenusList.map(item => (
<Panel
header={<div>{item.name}</div>}
key={item.key}
>
{item.value&&item.value.length>0?item.value.map(ele=>(<div draggable="true" onDragEnd={(e)=>{dragEnd(e,ele)}} className={Styles.collapseItem}>
<img style={{height:'16px',marginRight:'15px'}} src={`/assets/images/${ele.icon_path}.png`} alt="" />
{ele.component_label}
</div>)
):''}
</Panel>
))
: ""}
</Collapse>
</div>)};
export default modelMenus;
? modelMenusList.map((item) => (
<Panel header={<div>{item.name}</div>} key={item.key}>
{item.value && item.value.length > 0
? item.value.map((ele) => (
<div
draggable="true"
onDragEnd={(e) => {
dragEnd(e, ele);
}}
className={Styles.collapseItem}
>
<img
style={{ height: '16px', marginRight: '15px' }}
src={`/assets/images/${ele.icon_path}.png`}
alt=""
/>
{ele.component_label}
</div>
))
: ''}
</Panel>
))
: ''}
</Collapse>
</div>
);
};
export default modelMenus;

+ 37
- 41
react-ui/src/pages/Pipeline/editPipeline/modelMenus.less View File

@@ -1,44 +1,40 @@
.collapseList{
.collapseList {
}
.collapseItem{
display: flex;
align-items: center;
color:#575757;
font-size:14px;
height:40px;
cursor: pointer;
border-radius:4px;
padding: 0 16px;
.collapseItem {
display: flex;
align-items: center;
height: 40px;
padding: 0 16px;
color: #575757;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
}
.collapseItem:hover{
background:rgba(22, 100, 255, 0.08);
.collapseItem:hover {
background: rgba(22, 100, 255, 0.08);
}
.collapse {
:global {
.ant-collapse {
background-color: #fff;
border-color: transparent !important;
}
.ant-collapse > .ant-collapse-item > .ant-collapse-header {
margin-bottom: 5px;
background-color: #fff;
border-color: transparent;
}
.ant-collapse > .ant-collapse-item {
margin: 0 10px;
border-color: rgba(20, 49, 179, 0.12);
border-radius: 0px;
}
.ant-collapse .ant-collapse-content {
padding-bottom: 15px;
border-top: 1px solid transparent;
}
.ant-collapse .ant-collapse-content > .ant-collapse-content-box {
padding: 0;
}
}
}
.collapse{
:global {
.ant-collapse{
border-color: transparent!important;
background-color: #fff;
}
.ant-collapse>.ant-collapse-item >.ant-collapse-header{
background-color: #fff;
border-color: transparent;
margin-bottom: 5px;
}
.ant-collapse>.ant-collapse-item{
border-radius: 0px;
border-color:rgba(20, 49, 179, 0.12);
margin: 0 10px;
}
.ant-collapse .ant-collapse-content{
padding-bottom: 15px;
border-top: 1px solid transparent;
}
.ant-collapse .ant-collapse-content>.ant-collapse-content-box{
padding: 0;
}
}
}

+ 149
- 121
react-ui/src/pages/Pipeline/editPipeline/props.jsx View File

@@ -1,75 +1,93 @@
import React, { useState,useImperativeHandle ,forwardRef } from 'react';
import { Button, Drawer,Form, Input , } from 'antd';
import Styles from './editPipeline.less'
import { Drawer, Form, Input } from 'antd';
import { forwardRef, useImperativeHandle, useState } from 'react';
import Styles from './editPipeline.less';
const { TextArea } = Input;
const Props = forwardRef(({onParentChange}, ref) =>{
const [form] = Form.useForm();
const [stagingItem,setStagingItem]=useState({})
const [open, setOpen] = useState(false);
const afterOpenChange=()=>{
if(!open){
console.log(111,open);
console.log(stagingItem,form.getFieldsValue());
for(let i in form.getFieldsValue()){
for(let j in stagingItem.in_parameters){
if(i==j){
console.log(j,i);
stagingItem.in_parameters[j].value=form.getFieldsValue()[i]
}
const Props = forwardRef(({ onParentChange }, ref) => {
const [form] = Form.useForm();
const [stagingItem, setStagingItem] = useState({});
const [open, setOpen] = useState(false);
const afterOpenChange = () => {
if (!open) {
console.log(111, open);

console.log(stagingItem, form.getFieldsValue());
for (let i in form.getFieldsValue()) {
for (let j in stagingItem.in_parameters) {
if (i == j) {
console.log(j, i);
stagingItem.in_parameters[j].value = form.getFieldsValue()[i];
}
for(let p in stagingItem.out_parameters){
if(i==p){
stagingItem.out_parameters[p].value=form.getFieldsValue()[i]
}
}
for (let p in stagingItem.out_parameters) {
if (i == p) {
stagingItem.out_parameters[p].value = form.getFieldsValue()[i];
}
for(let k in stagingItem.control_strategy){
if(i==k){
stagingItem.control_strategy[k].value=form.getFieldsValue()[i]
}
}
for (let k in stagingItem.control_strategy) {
if (i == k) {
stagingItem.control_strategy[k].value = form.getFieldsValue()[i];
}
}
// setStagingItem({...stagingItem,})
console.log((stagingItem.control_strategy));
onParentChange({...stagingItem,control_strategy:JSON.stringify(stagingItem.control_strategy),in_parameters:JSON.stringify(stagingItem.in_parameters),out_parameters:JSON.stringify(stagingItem.out_parameters),...form.getFieldsValue()})
// onParentChange({...stagingItem,...form.getFieldsValue()})
}
// setStagingItem({...stagingItem,})
console.log(stagingItem.control_strategy);
onParentChange({
...stagingItem,
control_strategy: JSON.stringify(stagingItem.control_strategy),
in_parameters: JSON.stringify(stagingItem.in_parameters),
out_parameters: JSON.stringify(stagingItem.out_parameters),
...form.getFieldsValue(),
});
// onParentChange({...stagingItem,...form.getFieldsValue()})
}
const onClose=()=> {
setOpen(false);
};
const onFinish = (values) => {
console.log('Success:', values);
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
useImperativeHandle(ref, () => ({
showDrawer (e) {
if(e.item&&e.item.getModel()){
// console.log(e.item.getModel().in_parameters);
form.resetFields();
form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters),control_strategy:JSON.parse(e.item.getModel().control_strategy)})
// form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
// setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
// setTimeout(() => {
// console.log(stagingItem);
// }, (500));
setOpen(true);
}
},
}));
};
const onClose = () => {
setOpen(false);
};
const onFinish = (values) => {
console.log('Success:', values);
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
useImperativeHandle(ref, () => ({
showDrawer(e) {
if (e.item && e.item.getModel()) {
// console.log(e.item.getModel().in_parameters);
form.resetFields();
form.setFieldsValue({
...e.item.getModel(),
in_parameters: JSON.parse(e.item.getModel().in_parameters),
out_parameters: JSON.parse(e.item.getModel().out_parameters),
control_strategy: JSON.parse(e.item.getModel().control_strategy),
});
setStagingItem({
...e.item.getModel(),
in_parameters: JSON.parse(e.item.getModel().in_parameters),
out_parameters: JSON.parse(e.item.getModel().out_parameters),
control_strategy: JSON.parse(e.item.getModel().control_strategy),
});
// form.setFieldsValue({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
// setStagingItem({...e.item.getModel(),in_parameters:JSON.parse(e.item.getModel().in_parameters),out_parameters:JSON.parse(e.item.getModel().out_parameters)})
// setTimeout(() => {
// console.log(stagingItem);
// }, (500));
setOpen(true);
}
},
}));
return (
<>
<Drawer title="编辑任务" placement="right" getContainer={false} closeIcon={false} onClose={onClose} afterOpenChange={afterOpenChange} open={open}>
<Form
<Drawer
title="编辑任务"
placement="right"
getContainer={false}
closeIcon={false}
onClose={onClose}
afterOpenChange={afterOpenChange}
open={open}
>
<Form
name="form"
form={form}
layout="vertical"
@@ -89,10 +107,14 @@ const Props = forwardRef(({onParentChange}, ref) =>{
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<div className={Styles.editPipelinePropsContent}>
<img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/static-message.png'} alt="" />
基本信息
</div>
<div className={Styles.editPipelinePropsContent}>
<img
style={{ width: '13px', marginRight: '10px' }}
src={'/assets/images/static-message.png'}
alt=""
/>
基本信息
</div>
<Form.Item
label="任务名称"
name="label"
@@ -108,7 +130,6 @@ const Props = forwardRef(({onParentChange}, ref) =>{
<Form.Item
label="任务ID"
name="id"
rules={[
{
required: true,
@@ -116,11 +137,15 @@ const Props = forwardRef(({onParentChange}, ref) =>{
},
]}
>
<Input disabled/>
<Input disabled />
</Form.Item>
<div className={Styles.editPipelinePropsContent}>
<img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/duty-message.png'} alt="" />
任务信息
<img
style={{ width: '13px', marginRight: '10px' }}
src={'/assets/images/duty-message.png'}
alt=""
/>
任务信息
</div>
<Form.Item
label="镜像"
@@ -134,17 +159,11 @@ const Props = forwardRef(({onParentChange}, ref) =>{
>
<Input />
</Form.Item>
<Form.Item
label="工作目录"
name="working_directory"
>
<Form.Item label="工作目录" name="working_directory">
<Input />
</Form.Item>
<Form.Item
label="启动命令"
name="command"
>

<Form.Item label="启动命令" name="command">
<Input />
</Form.Item>
<Form.Item
@@ -159,54 +178,63 @@ const Props = forwardRef(({onParentChange}, ref) =>{
>
<Input />
</Form.Item>
<Form.Item
label="挂载路径"
name="mount_path"
>
<Form.Item label="挂载路径" name="mount_path">
<Input />
</Form.Item>
<Form.Item
label="环境变量"
name="env_variables"
>
<TextArea />
</Form.Item>
{stagingItem.control_strategy&&Object.keys(stagingItem.control_strategy)&&Object.keys(stagingItem.control_strategy).length>0?Object.keys(stagingItem.control_strategy).map(item=>
<Form.Item
label={stagingItem.control_strategy[item].label}
name={item}
>
<Input />
<Form.Item label="环境变量" name="env_variables">
<TextArea />
</Form.Item>
):''}
{stagingItem.control_strategy &&
Object.keys(stagingItem.control_strategy) &&
Object.keys(stagingItem.control_strategy).length > 0
? Object.keys(stagingItem.control_strategy).map((item) => (
<Form.Item label={stagingItem.control_strategy[item].label} name={item}>
<Input />
</Form.Item>
))
: ''}
<div className={Styles.editPipelinePropsContent}>
<img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/duty-message.png'} alt="" />
输入参数
<img
style={{ width: '13px', marginRight: '10px' }}
src={'/assets/images/duty-message.png'}
alt=""
/>
输入参数
</div>
{stagingItem.in_parameters&&Object.keys(stagingItem.in_parameters)&&Object.keys(stagingItem.in_parameters).length>0?Object.keys(stagingItem.in_parameters).map(item=>
<Form.Item
label={stagingItem.in_parameters[item].label+'('+item+')'}
name={item}
rules={[{ required: stagingItem.in_parameters[item].require?true:false}]}
>
<Input />
</Form.Item>
):''}
{stagingItem.in_parameters &&
Object.keys(stagingItem.in_parameters) &&
Object.keys(stagingItem.in_parameters).length > 0
? Object.keys(stagingItem.in_parameters).map((item) => (
<Form.Item
label={stagingItem.in_parameters[item].label + '(' + item + ')'}
name={item}
rules={[{ required: stagingItem.in_parameters[item].require ? true : false }]}
>
<Input />
</Form.Item>
))
: ''}
<div className={Styles.editPipelinePropsContent}>
<img style={{width:'13px',marginRight:'10px'}} src={'/assets/images/duty-message.png'} alt="" />
输出参数
<img
style={{ width: '13px', marginRight: '10px' }}
src={'/assets/images/duty-message.png'}
alt=""
/>
输出参数
</div>
{stagingItem.out_parameters&&Object.keys(stagingItem.out_parameters)&&Object.keys(stagingItem.out_parameters).length>0?Object.keys(stagingItem.out_parameters).map(item=>
<Form.Item
label={stagingItem.out_parameters[item].label+'('+item+')'}
rules={[{ required: stagingItem.out_parameters[item].require?true:false}]}
name={item}
>
<Input />
</Form.Item>
):''}
{stagingItem.out_parameters &&
Object.keys(stagingItem.out_parameters) &&
Object.keys(stagingItem.out_parameters).length > 0
? Object.keys(stagingItem.out_parameters).map((item) => (
<Form.Item
label={stagingItem.out_parameters[item].label + '(' + item + ')'}
rules={[{ required: stagingItem.out_parameters[item].require ? true : false }]}
name={item}
>
<Input />
</Form.Item>
))
: ''}
</Form>
</Drawer>
</>


+ 269
- 247
react-ui/src/pages/Pipeline/index.jsx View File

@@ -1,250 +1,266 @@
import React ,{ useState,useEffect,useRef }from 'react';
import { Space, Table, Tag,Button,Modal, Form, Input ,message} from 'antd';
import { PlusOutlined,PlusCircleOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined ,CopyOutlined} from '@ant-design/icons';
import {getWorkflow,addWorkflow,removeWorkflow,cloneWorkflow,getWorkflowById,editWorkflow} from '@/services/pipeline/index.js'
import Styles from './index.less'
import momnet from 'moment'
import { useNavigate} from 'react-router-dom';
import {
addWorkflow,
cloneWorkflow,
editWorkflow,
getWorkflow,
getWorkflowById,
removeWorkflow,
} from '@/services/pipeline/index.js';
import { CopyOutlined, DeleteOutlined, EditOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { Button, Form, Input, Modal, Space, Table, message } from 'antd';
import momnet from 'moment';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import Styles from './index.less';
const { TextArea } = Input;

const Pipeline = React.FC = () => {
const [form] = Form.useForm();
const navgite=useNavigate();
const [formId,setFormId]=useState(null)
const [dialogTitle,setDialogTitle]=useState('新建流水线')
const [pipeList, setPipeList] = useState([]);
const [total, setTotal] = useState(0);
const [isModalOpen, setIsModalOpen] = useState(false);
const editTable=(e,record)=>{
e.stopPropagation()
getWorkflowById(record.id).then(ret=>{
if(ret.code==200){
form.resetFields()
form.setFieldsValue({...ret.data})
setFormId(ret.data.id)
setDialogTitle('编辑流水线')
setIsModalOpen(true)
const Pipeline = () => {
const [form] = Form.useForm();
const navgite = useNavigate();

const [formId, setFormId] = useState(null);
const [dialogTitle, setDialogTitle] = useState('新建流水线');
const [pipeList, setPipeList] = useState([]);
const [total, setTotal] = useState(0);
const [isModalOpen, setIsModalOpen] = useState(false);
const editTable = (e, record) => {
e.stopPropagation();
getWorkflowById(record.id).then((ret) => {
if (ret.code == 200) {
form.resetFields();
form.setFieldsValue({ ...ret.data });
setFormId(ret.data.id);
setDialogTitle('编辑流水线');
setIsModalOpen(true);
}
});
};
const routeToEdit = (e, record) => {
e.stopPropagation();
navgite({ pathname: `/pipeline/pytorchtext/${record.id}/${record.name}` });
};
const showModal = () => {
form.resetFields();
setDialogTitle('新建流水线');
setIsModalOpen(true);
};
const handleOk = () => {
console.log(1111);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const onFinish = (values) => {
if (formId) {
editWorkflow({ ...values, id: formId }).then((ret) => {
message.success('编辑成功');
getList();
setIsModalOpen(false);
});
} else {
addWorkflow(values).then((ret) => {
console.log(ret);
if (ret.code == 200) {
navgite({ pathname: `/pipeline/pytorchtext/${ret.data.id}/${ret.data.name}` });
}
})
});
}
const routeToEdit=(e,record)=>{
e.stopPropagation()
navgite({pathname:`/pipeline/pytorchtext/${record.id}/${record.name}` });
}
const showModal = () => {
form.resetFields()
setDialogTitle('新建流水线')
setIsModalOpen(true);
};
const handleOk = () => {
console.log(1111);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const onFinish = (values) => {
if(formId){
editWorkflow({...values,id:formId}).then(ret=>{
message.success('编辑成功')
getList()
setIsModalOpen(false)
})
}
else{
addWorkflow(values).then(ret=>{
console.log(ret);
if(ret.code==200){
navgite({pathname:`/pipeline/pytorchtext/${ret.data.id}/${ret.data.name}`,});
}
}
)
}
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
const pageOption = useRef({ page: 1, size: 10 });
const paginationProps = {
showQuickJumper: true,
showTotal: () => `共${total}条`,
total: total,
page: pageOption.current.page,
size: pageOption.current.size,
onChange: (current, size) => paginationChange(current, size),
};
// 当前页面切换
const paginationChange = async (current, size) => {
console.log('page', current, size);
pageOption.current = {
page: current,
size: size,
};
const pageOption = useRef({page: 1,size: 10})
const paginationProps = {
showQuickJumper: true,
showTotal: () => `共${total}条`,
total: total,
page: pageOption.current.page,
getList();
};
const getList = () => {
let params = {
offset: 1,
page: pageOption.current.page - 1,
size: pageOption.current.size,
onChange: (current, size) => paginationChange(current, size)
}
// 当前页面切换
const paginationChange = async (current, size) => {
console.log('page', current, size)
pageOption.current={
page:current,
size:size
};
console.log(params, pageOption);
getWorkflow(params).then((ret) => {
if (ret.code == 200) {
setPipeList(ret.data.content);

setTotal(ret.data.totalElements);
}
getList()
}
const getList=()=>{
let params={
offset:1,
page:pageOption.current.page-1,
size:pageOption.current.size
}
console.log(params,pageOption);
getWorkflow(params).then(ret=>{
if(ret.code==200){
setPipeList(ret.data.content)
setTotal(ret.data.totalElements)
}
});
};
useEffect(() => {
getList();
}, []);
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 80,
render(text, record, index) {
return <span>{(pageOption.current.page - 1) * 10 + index + 1}</span>;
},
// render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`,
},
{
title: '流水线名称',
dataIndex: 'name',
key: 'name',
render: (text, record) => <a onClick={(e) => routeToEdit(e, record)}>{text}</a>,
},
{
title: '流水线描述',
dataIndex: 'description',
key: 'description',
},
{
title: '创建时间',
dataIndex: 'create_time',
key: 'create_time',
render: (text) => <span>{momnet(text).format('YYYY-MM-DD HH:mm:ss')}</span>,
},
{
title: '修改时间',
dataIndex: 'update_time',
key: 'update_time',
render: (text) => <span>{momnet(text).format('YYYY-MM-DD HH:mm:ss')}</span>,
},
{
title: '操作',
key: 'action',

})
}
useEffect(()=>{
getList()
},[])
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 80,
render(text, record, index) {
return (
<span>{(pageOption.current.page - 1) * 10 + index + 1}</span>
)
}
// render: (text, record, index) => `${((curPage-1)*10)+(index+1)}`,
},
{
title: '流水线名称',
dataIndex: 'name',
key: 'name',
render: (text,record) => <a onClick={(e)=>routeToEdit(e,record)}>{text}</a>,
},
{
title: '流水线描述',
dataIndex: 'description',
key: 'description',
},
{
title: '创建时间',
dataIndex: 'create_time',
key: 'create_time',
render: (text) => <span>{momnet(text).format('YYYY-MM-DD HH:mm:ss')}</span>,
},
{
title: '修改时间',
dataIndex: 'update_time',
key: 'update_time',
render: (text) => <span>{momnet(text).format('YYYY-MM-DD HH:mm:ss')}</span>,
},
{
title: '操作',
key: 'action',
render: (_, record) => (
<Space size="small">
<Button
type="link"
size="small"
key="edit"
icon = {< EditOutlined />}
onClick={(e) => {
editTable(e,record)
}}
>
编辑
</Button>
<Button
type="link"
size="small"
key="clone"
icon = {< CopyOutlined />}
onClick={async () => {
Modal.confirm({
title: '复制',
content: '确定复制该条流水线吗?',
okText: '确认',
cancelText: '取消',
onOk: () => {
console.log(record);
cloneWorkflow(record.id).then(ret=>{
if(ret.code==200){
message.success('复制成功')
getList()
render: (_, record) => (
<Space size="small">
<Button
type="link"
size="small"
key="edit"
icon={<EditOutlined />}
onClick={(e) => {
editTable(e, record);
}}
>
编辑
</Button>
<Button
type="link"
size="small"
key="clone"
icon={<CopyOutlined />}
onClick={async () => {
Modal.confirm({
title: '复制',
content: '确定复制该条流水线吗?',
okText: '确认',
cancelText: '取消',
onOk: () => {
console.log(record);
cloneWorkflow(record.id).then((ret) => {
if (ret.code == 200) {
message.success('复制成功');
getList();
} else {
message.error('复制失败');
}
else{
message.error('复制失败')
});

// if (success) {
// if (actionRef.current) {
// actionRef.current.reload();
// }
// }
},
});
}}
>
复制
</Button>
<Button
type="link"
size="small"
danger
style={{ color: '#f98e1b' }}
key="batchRemove"
icon={<DeleteOutlined />}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确定删除该条流水线吗?',
okText: '确认',
cancelText: '取消',
onOk: () => {
console.log(record);
removeWorkflow(record.id).then((ret) => {
if (ret.code == 200) {
message.success('删除成功');
getList();
} else {
message.error(ret.msg);
}
});
// if (success) {
// if (actionRef.current) {
// actionRef.current.reload();
// }
// }
},
});
}}
>
复制
</Button>
});

// if (success) {
// if (actionRef.current) {
// actionRef.current.reload();
// }
// }
},
});
}}
>
删除
</Button>
</Space>
),
},
];
return (
<div>
<div className={Styles.pipelineTopBox}>
<Button
type="link"
size="small"
danger
style={{color:'#f98e1b'}}
key="batchRemove"
icon = {< DeleteOutlined />}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确定删除该条流水线吗?',
okText: '确认',
cancelText: '取消',
onOk: () => {
console.log(record);
removeWorkflow(record.id).then(ret=>{
if(ret.code==200){
message.success('删除成功')
getList()
}
else{
message.error(ret.msg)
}
});
// if (success) {
// if (actionRef.current) {
// actionRef.current.reload();
// }
// }
},
});
}}
type="primary"
className={Styles.plusButton}
onClick={showModal}
icon={<PlusCircleOutlined style={{ color: '#1664ff' }} />}
>
删除
</Button>
</Space>
),
},
];
return (<div>
<div className={Styles.pipelineTopBox}>
<Button type="primary" className={Styles.plusButton} onClick={showModal} icon = {<PlusCircleOutlined style={{color:'#1664ff'}} />}>
新建流水线
</Button>
</div>
<Table columns={columns} dataSource={pipeList} pagination={paginationProps}/>
<Modal title={<div style={{display:'flex',alignItems:'center',fontWeight:500}}>
<img style={{width:'20px',marginRight:'10px'}} src={`/assets/images/pipeline-edit-icon.png`} alt="" />{dialogTitle}
</div>} open={isModalOpen} className={Styles.modal} okButtonProps={{
htmlType: 'submit',
form: 'form',
}} onCancel={handleCancel}>
</div>
<Table columns={columns} dataSource={pipeList} pagination={paginationProps} />
<Modal
title={
<div style={{ display: 'flex', alignItems: 'center', fontWeight: 500 }}>
<img
style={{ width: '20px', marginRight: '10px' }}
src={`/assets/images/pipeline-edit-icon.png`}
alt=""
/>
{dialogTitle}
</div>
}
open={isModalOpen}
className={Styles.modal}
okButtonProps={{
htmlType: 'submit',
form: 'form',
}}
onCancel={handleCancel}
>
<Form
name="form"
form={form}
@@ -259,28 +275,34 @@ const Pipeline = React.FC = () => {
<Form.Item
label="流水线名称"
name="name"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Input />
</Form.Item>
<Form.Item
label="流水线描述"
name="description"
rules={[
// {
// required: true,
// message: 'Please input your username!',
// },
]}
rules={
[
// {
// required: true,
// message: 'Please input your username!',
// },
]
}
>
<Input />
</Form.Item>
</Form>
</Modal>
</div>)};
export default Pipeline;
</div>
);
};
export default Pipeline;

+ 57
- 59
react-ui/src/pages/Pipeline/index.less View File

@@ -1,65 +1,63 @@
.pipelineTopBox{
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 30px;
width: 100%;
height: 49px;
background-size: 100% 100%;
background-image: url(/assets/images/pipeline-back.png);
margin-bottom: 10px;
.pipelineTopBox {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
height: 49px;
margin-bottom: 10px;
padding-right: 30px;
background-image: url(/assets/images/pipeline-back.png);
background-size: 100% 100%;
}
.plusButton{
background:rgba(22, 100, 255, 0.06);
border:1px solid;
border-color:rgba(22, 100, 255, 0.11);
border-radius:4px;
color:#1d1d20;
font-size:14px;
font-family: 'Alibaba';
.plusButton {
color: #1d1d20;
font-size: 14px;
font-family: 'Alibaba';
background: rgba(22, 100, 255, 0.06);
border: 1px solid;
border-color: rgba(22, 100, 255, 0.11);
border-radius: 4px;
}
.plusButton:hover{
background:rgba(22, 100, 255, 0.06)!important;
border:1px solid!important;
border-color:rgba(22, 100, 255, 0.11)!important;
color:#1d1d20!important;
.plusButton:hover {
color: #1d1d20 !important;
background: rgba(22, 100, 255, 0.06) !important;
border: 1px solid !important;
border-color: rgba(22, 100, 255, 0.11) !important;
}
.modal {
:global {
.ant-modal-content {
background:linear-gradient(180deg,#cfdfff 0%,#d4e2ff 9.77%,#ffffff 40%,#ffffff 100%);
border-radius:21px;
padding: 20px 67px;
width: 825px;

}
.ant-modal-header{
background-color: transparent;
margin: 20px 0;
}
.ant-input{
border-color:#e6e6e6;
height: 40px;
}
.ant-form-item .ant-form-item-label >label{
color:rgba(29, 29, 32, 0.8);
}
.ant-modal-footer{
margin: 40px 0 30px 0;
display: flex;
justify-content: center;
}
.ant-btn{
width:110px;
height:40px;
font-size:18px;
background:rgba(22, 100, 255, 0.06);
border-radius:10px;
border-color: transparent;
}
.ant-btn-primary{
background:#1664ff;
}
:global {
.ant-modal-content {
width: 825px;
padding: 20px 67px;
background: linear-gradient(180deg, #cfdfff 0%, #d4e2ff 9.77%, #ffffff 40%, #ffffff 100%);
border-radius: 21px;
}
.ant-modal-header {
margin: 20px 0;
background-color: transparent;
}
.ant-input {
height: 40px;
border-color: #e6e6e6;
}
.ant-form-item .ant-form-item-label > label {
color: rgba(29, 29, 32, 0.8);
}
.ant-modal-footer {
display: flex;
justify-content: center;
margin: 40px 0 30px 0;
}
.ant-btn {
width: 110px;
height: 40px;
font-size: 18px;
background: rgba(22, 100, 255, 0.06);
border-color: transparent;
border-radius: 10px;
}
.ant-btn-primary {
background: #1664ff;
}
}
}

+ 27
- 26
react-ui/src/pages/System/Config/edit.tsx View File

@@ -1,14 +1,14 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormRadio,
ProFormText,
ProFormTextArea,
ProFormRadio,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictValueEnumObj } from '@/components/DictTag';
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React, { useEffect } from 'react';

export type ConfigFormData = Record<string, unknown> & Partial<API.System.Config>;

@@ -22,22 +22,22 @@ export type ConfigFormProps = {

const ConfigForm: React.FC<ConfigFormProps> = (props) => {
const [form] = Form.useForm();
const { configTypeOptions } = props;

useEffect(() => {
form.resetFields();
form.setFieldsValue({
configId: props.values.configId,
configName: props.values.configName,
configKey: props.values.configKey,
configValue: props.values.configValue,
configType: props.values.configType,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
configId: props.values.configId,
configName: props.values.configName,
configKey: props.values.configKey,
configValue: props.values.configValue,
configType: props.values.configType,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
});
}, [form, props]);

@@ -65,12 +65,13 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
<ProForm
form={form}
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
layout="horizontal"
onFinish={handleFinish}
>
<ProFormDigit
name="configId"
label={intl.formatMessage({
@@ -84,7 +85,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入参数主键!" defaultMessage="请输入参数主键!" />,
message: <FormattedMessage id="请输入参数主键!" defaultMessage="请输入参数主键!" />,
},
]}
/>
@@ -99,7 +100,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入参数名称!" defaultMessage="请输入参数名称!" />,
message: <FormattedMessage id="请输入参数名称!" defaultMessage="请输入参数名称!" />,
},
]}
/>
@@ -114,7 +115,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入参数键名!" defaultMessage="请输入参数键名!" />,
message: <FormattedMessage id="请输入参数键名!" defaultMessage="请输入参数键名!" />,
},
]}
/>
@@ -129,7 +130,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入参数键值!" defaultMessage="请输入参数键值!" />,
message: <FormattedMessage id="请输入参数键值!" defaultMessage="请输入参数键值!" />,
},
]}
/>
@@ -145,7 +146,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入系统内置!" defaultMessage="请输入系统内置!" />,
message: <FormattedMessage id="请输入系统内置!" defaultMessage="请输入系统内置!" />,
},
]}
/>
@@ -160,7 +161,7 @@ const ConfigForm: React.FC<ConfigFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入备注!" defaultMessage="请输入备注!" />,
message: <FormattedMessage id="请输入备注!" defaultMessage="请输入备注!" />,
},
]}
/>


+ 30
- 12
react-ui/src/pages/System/Config/index.tsx View File

@@ -1,14 +1,32 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import DictTag from '@/components/DictTag';
import {
addConfig,
exportConfig,
getConfigList,
refreshConfigCache,
removeConfig,
updateConfig,
} from '@/services/system/config';
import { getDictValueEnum } from '@/services/system/dict';
import {
DeleteOutlined,
DownloadOutlined,
ExclamationCircleOutlined,
PlusOutlined,
ReloadOutlined,
} from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, ReloadOutlined, DownloadOutlined } from '@ant-design/icons';
import { getConfigList, removeConfig, addConfig, updateConfig, exportConfig, refreshConfigCache } from '@/services/system/config';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';

/**
* 添加节点
@@ -103,7 +121,7 @@ const handleRemoveOne = async (selectedRow: API.System.Config) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -183,7 +201,7 @@ const ConfigTableList: React.FC = () => {
valueType: 'select',
valueEnum: configTypeOptions,
render: (_, record) => {
return (<DictTag enums={configTypeOptions} value={record.configType} />);
return <DictTag enums={configTypeOptions} value={record.configType} />;
},
},
{
@@ -283,7 +301,7 @@ const ConfigTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>


+ 8
- 9
react-ui/src/pages/System/Dept/edit.tsx View File

@@ -1,15 +1,15 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormRadio,
ProFormText,
ProFormTreeSelect,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import { DataNode } from 'antd/es/tree';
import { DictValueEnumObj } from '@/components/DictTag';
import React, { useEffect } from 'react';

export type DeptFormData = Record<string, unknown> & Partial<API.System.Dept>;

@@ -76,7 +76,8 @@ const DeptForm: React.FC<DeptFormProps> = (props) => {
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
onFinish={handleFinish}
>
<ProFormDigit
name="deptId"
label={intl.formatMessage({
@@ -107,9 +108,7 @@ const DeptForm: React.FC<DeptFormProps> = (props) => {
rules={[
{
required: true,
message: (
<FormattedMessage id="请输入用户昵称!" defaultMessage="请选择上级部门!" />
),
message: <FormattedMessage id="请输入用户昵称!" defaultMessage="请选择上级部门!" />,
},
]}
/>


+ 29
- 18
react-ui/src/pages/System/Dept/index.tsx View File

@@ -1,15 +1,27 @@
import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getDeptList, removeDept, addDept, updateDept, exportDept, getDeptListExcludeChild } from '@/services/system/dept';
import UpdateForm from './edit';
import DictTag from '@/components/DictTag';
import {
addDept,
exportDept,
getDeptList,
getDeptListExcludeChild,
removeDept,
updateDept,
} from '@/services/system/dept';
import { getDictValueEnum } from '@/services/system/dict';
import { buildTreeData } from '@/utils/tree';
import DictTag from '@/components/DictTag';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './edit';

/**
* 添加节点
@@ -104,7 +116,7 @@ const handleRemoveOne = async (selectedRow: API.System.Dept) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -120,9 +132,8 @@ const handleExport = async () => {
}
};


const DeptTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();
const formTableRef = useRef<FormInstance>();

const [modalVisible, setModalVisible] = useState<boolean>(false);

@@ -139,7 +150,7 @@ const DeptTableList: React.FC = () => {
const intl = useIntl();

useEffect(() => {
getDictValueEnum('sys_normal_disable').then((data) => {
getDictValueEnum('sys_normal_disable').then((data) => {
setStatusOptions(data);
});
}, []);
@@ -161,7 +172,7 @@ const DeptTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -179,7 +190,7 @@ const DeptTableList: React.FC = () => {
getDeptListExcludeChild(record.deptId).then((res) => {
if (res.code === 200) {
let depts = buildTreeData(res.data, 'deptId', 'deptName', '', '', '');
if(depts.length === 0) {
if (depts.length === 0) {
depts = [{ id: 0, title: '无上级', children: undefined, key: 0, value: 0 }];
}
setDeptTree(depts);
@@ -258,7 +269,7 @@ const DeptTableList: React.FC = () => {
</Button>,
<Button
type="primary"
key="remove"
key="remove"
hidden={selectedRows?.length === 0 || !access.hasPerms('system:dept:remove')}
onClick={async () => {
Modal.confirm({
@@ -273,7 +284,7 @@ const DeptTableList: React.FC = () => {
}
},
onCancel() {},
});
});
}}
>
<DeleteOutlined />


+ 18
- 17
react-ui/src/pages/System/Dict/edit.tsx View File

@@ -1,14 +1,14 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormRadio,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictValueEnumObj } from '@/components/DictTag';
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React, { useEffect } from 'react';

export type DictTypeFormData = Record<string, unknown> & Partial<API.System.DictType>;

@@ -28,15 +28,15 @@ const DictTypeForm: React.FC<DictTypeFormProps> = (props) => {
useEffect(() => {
form.resetFields();
form.setFieldsValue({
dictId: props.values.dictId,
dictName: props.values.dictName,
dictType: props.values.dictType,
status: props.values.status,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
dictId: props.values.dictId,
dictName: props.values.dictName,
dictType: props.values.dictType,
status: props.values.status,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
});
}, [form, props]);

@@ -64,12 +64,13 @@ const DictTypeForm: React.FC<DictTypeFormProps> = (props) => {
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
<ProForm
form={form}
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
onFinish={handleFinish}
>
<ProFormDigit
name="dictId"
label={intl.formatMessage({


+ 26
- 16
react-ui/src/pages/System/Dict/index.tsx View File

@@ -1,14 +1,25 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess, history } from '@umijs/max';
import DictTag from '@/components/DictTag';
import {
addDictType,
exportDictType,
getDictTypeList,
getDictValueEnum,
removeDictType,
updateDictType,
} from '@/services/system/dict';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, history, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getDictTypeList, removeDictType, addDictType, updateDictType, exportDictType } from '@/services/system/dict';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';

/**
* 添加节点
@@ -103,7 +114,7 @@ const handleRemoveOne = async (selectedRow: API.System.DictType) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -119,9 +130,8 @@ const handleExport = async () => {
}
};


const DictTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();
const formTableRef = useRef<FormInstance>();

const [modalVisible, setModalVisible] = useState<boolean>(false);

@@ -176,7 +186,7 @@ const DictTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -190,7 +200,7 @@ const DictTableList: React.FC = () => {
dataIndex: 'createTime',
valueType: 'dateRange',
render: (_, record) => {
return (<span>{record.createTime.toString()} </span>);
return <span>{record.createTime.toString()} </span>;
},
search: {
transform: (value) => {
@@ -277,7 +287,7 @@ const DictTableList: React.FC = () => {
</Button>,
<Button
type="primary"
key="remove"
key="remove"
hidden={selectedRows?.length === 0 || !access.hasPerms('system:dictType:remove')}
onClick={async () => {
Modal.confirm({
@@ -292,7 +302,7 @@ const DictTableList: React.FC = () => {
}
},
onCancel() {},
});
});
}}
>
<DeleteOutlined />


+ 16
- 15
react-ui/src/pages/System/DictData/edit.tsx View File

@@ -1,15 +1,15 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormSelect,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictValueEnumObj } from '@/components/DictTag';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React, { useEffect } from 'react';

export type DataFormData = Record<string, unknown> & Partial<API.System.DictData>;

@@ -75,7 +75,8 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
onFinish={handleFinish}
>
<ProFormDigit
name="dictCode"
label={intl.formatMessage({
@@ -163,12 +164,12 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
colProps={{ md: 12, xl: 24 }}
placeholder="请输入回显样式"
valueEnum={{
'default': '默认',
'primary': '主要',
'success': '成功',
'info': '信息',
'warning': '警告',
'danger': '危险',
default: '默认',
primary: '主要',
success: '成功',
info: '信息',
warning: '警告',
danger: '危险',
}}
rules={[
{
@@ -199,8 +200,8 @@ const DictDataForm: React.FC<DataFormProps> = (props) => {
defaultMessage: '是否默认',
})}
valueEnum={{
'Y': '是',
'N': '否',
Y: '是',
N: '否',
}}
initialValue={'N'}
colProps={{ md: 12, xl: 24 }}


+ 38
- 23
react-ui/src/pages/System/DictData/index.tsx View File

@@ -1,14 +1,25 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess, history, useParams } from '@umijs/max';
import DictTag from '@/components/DictTag';
import { getDictType, getDictTypeOptionSelect, getDictValueEnum } from '@/services/system/dict';
import {
addDictData,
exportDictData,
getDictDataList,
removeDictData,
updateDictData,
} from '@/services/system/dictdata';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, history, useAccess, useIntl, useParams } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getDictDataList, removeDictData, addDictData, updateDictData, exportDictData } from '@/services/system/dictdata';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './edit';
import { getDictValueEnum, getDictType, getDictTypeOptionSelect } from '@/services/system/dict';
import DictTag from '@/components/DictTag';

/**
* 添加节点
@@ -123,9 +134,7 @@ export type DictTypeArgs = {
id: string;
};


const DictDataTableList: React.FC = () => {

const formTableRef = useRef<FormInstance>();

const [dictId, setDictId] = useState<string>('');
@@ -221,7 +230,7 @@ const DictDataTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -235,7 +244,7 @@ const DictDataTableList: React.FC = () => {
dataIndex: 'createTime',
valueType: 'dateRange',
render: (_, record) => {
return (<span>{record.createTime.toString()} </span>);
return <span>{record.createTime.toString()} </span>;
},
search: {
transform: (value) => {
@@ -314,7 +323,11 @@ const DictDataTableList: React.FC = () => {
key="add"
hidden={!access.hasPerms('system:data:add')}
onClick={async () => {
setCurrentRow({ dictType: dictType, isDefault: 'N', status: '0' } as API.System.DictData);
setCurrentRow({
dictType: dictType,
isDefault: 'N',
status: '0',
} as API.System.DictData);
setModalVisible(true);
}}
>
@@ -336,7 +349,7 @@ const DictDataTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>
@@ -356,14 +369,16 @@ const DictDataTableList: React.FC = () => {
</Button>,
]}
request={(params) =>
getDictDataList({ ...params, dictType } as API.System.DictDataListParams).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
getDictDataList({ ...params, dictType } as API.System.DictDataListParams).then(
(res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
},
)
}
columns={columns}
rowSelection={{


+ 31
- 31
react-ui/src/pages/System/Logininfor/edit.tsx View File

@@ -1,14 +1,14 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormRadio,
ProFormText,
ProFormTimePicker,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictValueEnumObj } from '@/components/DictTag';
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React, { useEffect } from 'react';

export type LogininforFormData = Record<string, unknown> & Partial<API.Monitor.Logininfor>;

@@ -22,21 +22,21 @@ export type LogininforFormProps = {

const LogininforForm: React.FC<LogininforFormProps> = (props) => {
const [form] = Form.useForm();
const { statusOptions, } = props;
const { statusOptions } = props;

useEffect(() => {
form.resetFields();
form.setFieldsValue({
infoId: props.values.infoId,
userName: props.values.userName,
ipaddr: props.values.ipaddr,
loginLocation: props.values.loginLocation,
browser: props.values.browser,
os: props.values.os,
status: props.values.status,
msg: props.values.msg,
loginTime: props.values.loginTime,
infoId: props.values.infoId,
userName: props.values.userName,
ipaddr: props.values.ipaddr,
loginLocation: props.values.loginLocation,
browser: props.values.browser,
os: props.values.os,
status: props.values.status,
msg: props.values.msg,
loginTime: props.values.loginTime,
});
}, [form, props]);

@@ -65,11 +65,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
form={form}
grid={true}
layout="horizontal"
onFinish={handleFinish}>
<ProForm form={form} grid={true} layout="horizontal" onFinish={handleFinish}>
<ProFormDigit
name="infoId"
label={intl.formatMessage({
@@ -83,7 +79,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入访问编号!" defaultMessage="请输入访问编号!" />,
message: <FormattedMessage id="请输入访问编号!" defaultMessage="请输入访问编号!" />,
},
]}
/>
@@ -98,7 +94,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入用户账号!" defaultMessage="请输入用户账号!" />,
message: <FormattedMessage id="请输入用户账号!" defaultMessage="请输入用户账号!" />,
},
]}
/>
@@ -113,7 +109,9 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入登录IP地址!" defaultMessage="请输入登录IP地址!" />,
message: (
<FormattedMessage id="请输入登录IP地址!" defaultMessage="请输入登录IP地址!" />
),
},
]}
/>
@@ -128,7 +126,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入登录地点!" defaultMessage="请输入登录地点!" />,
message: <FormattedMessage id="请输入登录地点!" defaultMessage="请输入登录地点!" />,
},
]}
/>
@@ -143,7 +141,9 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入浏览器类型!" defaultMessage="请输入浏览器类型!" />,
message: (
<FormattedMessage id="请输入浏览器类型!" defaultMessage="请输入浏览器类型!" />
),
},
]}
/>
@@ -158,7 +158,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入操作系统!" defaultMessage="请输入操作系统!" />,
message: <FormattedMessage id="请输入操作系统!" defaultMessage="请输入操作系统!" />,
},
]}
/>
@@ -174,7 +174,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入登录状态!" defaultMessage="请输入登录状态!" />,
message: <FormattedMessage id="请输入登录状态!" defaultMessage="请输入登录状态!" />,
},
]}
/>
@@ -189,7 +189,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入提示消息!" defaultMessage="请输入提示消息!" />,
message: <FormattedMessage id="请输入提示消息!" defaultMessage="请输入提示消息!" />,
},
]}
/>
@@ -204,7 +204,7 @@ const LogininforForm: React.FC<LogininforFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入访问时间!" defaultMessage="请输入访问时间!" />,
message: <FormattedMessage id="请输入访问时间!" defaultMessage="请输入访问时间!" />,
},
]}
/>


+ 28
- 13
react-ui/src/pages/System/Logininfor/index.tsx View File

@@ -1,13 +1,29 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, UnlockOutlined } from '@ant-design/icons';
import { getLogininforList, removeLogininfor, exportLogininfor, unlockLogininfor, cleanLogininfor } from '@/services/monitor/logininfor';
import DictTag from '@/components/DictTag';
import {
cleanLogininfor,
exportLogininfor,
getLogininforList,
removeLogininfor,
unlockLogininfor,
} from '@/services/monitor/logininfor';
import { getDictValueEnum } from '@/services/system/dict';
import {
DeleteOutlined,
ExclamationCircleOutlined,
PlusOutlined,
UnlockOutlined,
} from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';

/**
* 删除节点
@@ -88,7 +104,6 @@ const handleExport = async () => {
}
};


const LogininforTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();

@@ -148,7 +163,7 @@ const LogininforTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -196,7 +211,7 @@ const LogininforTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>
@@ -220,7 +235,7 @@ const LogininforTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>
@@ -243,7 +258,7 @@ const LogininforTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>


+ 29
- 25
react-ui/src/pages/System/Menu/edit.tsx View File

@@ -1,18 +1,18 @@
import React, { useEffect, useState } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import IconSelector from '@/components/IconSelector';
import { createIcon } from '@/utils/IconUtil';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormRadio,
ProFormTreeSelect,
ProFormSelect,
ProFormText,
ProFormTreeSelect,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import { DataNode } from 'antd/es/tree';
import { createIcon } from '@/utils/IconUtil';
import { DictValueEnumObj } from '@/components/DictTag';
import IconSelector from '@/components/IconSelector';
import React, { useEffect, useState } from 'react';

export type MenuFormData = Record<string, unknown> & Partial<API.System.Menu>;

@@ -27,7 +27,6 @@ export type MenuFormProps = {
};

const MenuForm: React.FC<MenuFormProps> = (props) => {

const [form] = Form.useForm();

const [menuTypeId, setMenuTypeId] = useState<any>('M');
@@ -91,7 +90,8 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
onFinish={handleFinish}
>
<ProFormDigit
name="menuId"
label={intl.formatMessage({
@@ -114,7 +114,7 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
id: 'system.menu.parent_id',
defaultMessage: '上级菜单',
})}
params={{menuTree}}
params={{ menuTree }}
request={async () => {
return menuTree;
}}
@@ -122,11 +122,13 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入父菜单编号!" defaultMessage="请输入父菜单编号!" />,
message: (
<FormattedMessage id="请输入父菜单编号!" defaultMessage="请输入父菜单编号!" />
),
},
]}
fieldProps = {{
defaultValue: 0
fieldProps={{
defaultValue: 0,
}}
/>
<ProFormRadio.Group
@@ -206,8 +208,8 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
message: <FormattedMessage id="请输入显示顺序!" defaultMessage="请输入显示顺序!" />,
},
]}
fieldProps = {{
defaultValue: 1
fieldProps={{
defaultValue: 1,
}}
/>
<ProFormRadio.Group
@@ -227,11 +229,13 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入是否为外链!" defaultMessage="请输入是否为外链!" />,
message: (
<FormattedMessage id="请输入是否为外链!" defaultMessage="请输入是否为外链!" />
),
},
]}
fieldProps = {{
defaultValue: '1'
fieldProps={{
defaultValue: '1',
}}
/>
<ProFormText
@@ -318,8 +322,8 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
message: <FormattedMessage id="请输入是否缓存!" defaultMessage="请输入是否缓存!" />,
},
]}
fieldProps = {{
defaultValue: 0
fieldProps={{
defaultValue: 0,
}}
/>
<ProFormRadio.Group
@@ -338,8 +342,8 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
message: <FormattedMessage id="请输入显示状态!" defaultMessage="请输入显示状态!" />,
},
]}
fieldProps = {{
defaultValue: '0'
fieldProps={{
defaultValue: '0',
}}
/>
<ProFormRadio.Group
@@ -358,8 +362,8 @@ const MenuForm: React.FC<MenuFormProps> = (props) => {
message: <FormattedMessage id="请输入菜单状态!" defaultMessage="请输入菜单状态!" />,
},
]}
fieldProps = {{
defaultValue: '0'
fieldProps={{
defaultValue: '0',
}}
/>
</ProForm>


+ 20
- 17
react-ui/src/pages/System/Menu/index.tsx View File

@@ -1,15 +1,20 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getMenuList, removeMenu, addMenu, updateMenu, exportMenu } from '@/services/system/menu';
import UpdateForm from './edit';
import DictTag from '@/components/DictTag';
import { getDictValueEnum } from '@/services/system/dict';
import { addMenu, exportMenu, getMenuList, removeMenu, updateMenu } from '@/services/system/menu';
import { buildTreeData } from '@/utils/tree';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import { Button, Modal, message } from 'antd';
import { DataNode } from 'antd/es/tree';
import DictTag from '@/components/DictTag';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './edit';

/**
* 添加节点
@@ -88,7 +93,7 @@ const handleRemoveOne = async (selectedRow: API.System.Menu) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -104,9 +109,7 @@ const handleExport = async () => {
}
};


const MenuTableList: React.FC = () => {

const [modalVisible, setModalVisible] = useState<boolean>(false);

const actionRef = useRef<ActionType>();
@@ -123,7 +126,7 @@ const MenuTableList: React.FC = () => {
const intl = useIntl();

useEffect(() => {
getDictValueEnum('sys_show_hide').then((data) => {
getDictValueEnum('sys_show_hide').then((data) => {
setVisibleOptions(data);
});
getDictValueEnum('sys_normal_disable').then((data) => {
@@ -131,7 +134,7 @@ const MenuTableList: React.FC = () => {
});
}, []);

const columns: ProColumns<API.System.Menu>[] = [
const columns: ProColumns<API.System.Menu>[] = [
{
title: <FormattedMessage id="system.menu.menu_name" defaultMessage="菜单名称" />,
dataIndex: 'menuName',
@@ -167,7 +170,7 @@ const MenuTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -245,7 +248,7 @@ const MenuTableList: React.FC = () => {
</Button>,
<Button
type="primary"
key="remove"
key="remove"
hidden={selectedRows?.length === 0 || !access.hasPerms('system:menu:remove')}
onClick={async () => {
Modal.confirm({
@@ -260,7 +263,7 @@ const MenuTableList: React.FC = () => {
}
},
onCancel() {},
});
});
}}
>
<DeleteOutlined />


+ 29
- 28
react-ui/src/pages/System/Notice/edit.tsx View File

@@ -1,15 +1,15 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
ProFormRadio,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictValueEnumObj } from '@/components/DictTag';
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React, { useEffect } from 'react';

export type NoticeFormData = Record<string, unknown> & Partial<API.System.Notice>;

@@ -24,22 +24,22 @@ export type NoticeFormProps = {

const NoticeForm: React.FC<NoticeFormProps> = (props) => {
const [form] = Form.useForm();
const { noticeTypeOptions,statusOptions, } = props;
const { noticeTypeOptions, statusOptions } = props;

useEffect(() => {
form.resetFields();
form.setFieldsValue({
noticeId: props.values.noticeId,
noticeTitle: props.values.noticeTitle,
noticeType: props.values.noticeType,
noticeContent: props.values.noticeContent,
status: props.values.status,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
noticeId: props.values.noticeId,
noticeTitle: props.values.noticeTitle,
noticeType: props.values.noticeType,
noticeContent: props.values.noticeContent,
status: props.values.status,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
});
}, [form, props]);

@@ -67,12 +67,13 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
<ProForm
form={form}
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
layout="horizontal"
onFinish={handleFinish}
>
<ProFormDigit
name="noticeId"
label={intl.formatMessage({
@@ -86,7 +87,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入公告编号!" defaultMessage="请输入公告编号!" />,
message: <FormattedMessage id="请输入公告编号!" defaultMessage="请输入公告编号!" />,
},
]}
/>
@@ -100,7 +101,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入公告标题!" defaultMessage="请输入公告标题!" />,
message: <FormattedMessage id="请输入公告标题!" defaultMessage="请输入公告标题!" />,
},
]}
/>
@@ -116,7 +117,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入公告类型!" defaultMessage="请输入公告类型!" />,
message: <FormattedMessage id="请输入公告类型!" defaultMessage="请输入公告类型!" />,
},
]}
/>
@@ -132,7 +133,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入公告状态!" defaultMessage="请输入公告状态!" />,
message: <FormattedMessage id="请输入公告状态!" defaultMessage="请输入公告状态!" />,
},
]}
/>
@@ -147,7 +148,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入公告内容!" defaultMessage="请输入公告内容!" />,
message: <FormattedMessage id="请输入公告内容!" defaultMessage="请输入公告内容!" />,
},
]}
/>
@@ -162,7 +163,7 @@ const NoticeForm: React.FC<NoticeFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入备注!" defaultMessage="请输入备注!" />,
message: <FormattedMessage id="请输入备注!" defaultMessage="请输入备注!" />,
},
]}
/>


+ 29
- 19
react-ui/src/pages/System/Notice/index.tsx View File

@@ -1,14 +1,25 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import DictTag from '@/components/DictTag';
import { getDictValueEnum } from '@/services/system/dict';
import {
addNotice,
exportNotice,
getNoticeList,
removeNotice,
updateNotice,
} from '@/services/system/notice';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getNoticeList, removeNotice, addNotice, updateNotice, exportNotice } from '@/services/system/notice';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';

/**
* 添加节点
@@ -103,7 +114,7 @@ const handleRemoveOne = async (selectedRow: API.System.Notice) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -119,9 +130,8 @@ const handleExport = async () => {
}
};


const NoticeTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();
const formTableRef = useRef<FormInstance>();

const [modalVisible, setModalVisible] = useState<boolean>(false);

@@ -137,16 +147,16 @@ const NoticeTableList: React.FC = () => {
/** 国际化配置 */
const intl = useIntl();

useEffect(() => {
useEffect(() => {
getDictValueEnum('sys_notice_type').then((data) => {
setNoticeTypeOptions(data);
});
});
getDictValueEnum('sys_notice_status').then((data) => {
setStatusOptions(data);
});
}, []);

const columns: ProColumns<API.System.Notice>[] = [
const columns: ProColumns<API.System.Notice>[] = [
{
title: <FormattedMessage id="system.notice.notice_id" defaultMessage="公告编号" />,
dataIndex: 'noticeId',
@@ -176,7 +186,7 @@ const NoticeTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -190,7 +200,7 @@ const NoticeTableList: React.FC = () => {
dataIndex: 'createTime',
valueType: 'dateRange',
render: (_, record) => {
return (<span>{record.createTime.toString()} </span>);
return <span>{record.createTime.toString()} </span>;
},
search: {
transform: (value) => {
@@ -277,7 +287,7 @@ const NoticeTableList: React.FC = () => {
</Button>,
<Button
type="primary"
key="remove"
key="remove"
hidden={selectedRows?.length === 0 || !access.hasPerms('system:notice:remove')}
onClick={async () => {
Modal.confirm({
@@ -292,7 +302,7 @@ const NoticeTableList: React.FC = () => {
}
},
onCancel() {},
});
});
}}
>
<DeleteOutlined />


+ 5
- 6
react-ui/src/pages/System/Operlog/detail.tsx View File

@@ -1,8 +1,8 @@
import React from 'react';
import { Descriptions, Modal } from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictValueEnumObj } from '@/components/DictTag';
import { getValueEnumLabel } from '@/utils/options';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Descriptions, Modal } from 'antd';
import React from 'react';

export type OperlogFormData = Record<string, unknown> & Partial<API.Monitor.Operlog>;

@@ -17,12 +17,11 @@ export type OperlogFormProps = {
};

const OperlogDetailForm: React.FC<OperlogFormProps> = (props) => {

const { values, businessTypeOptions, operatorTypeOptions, statusOptions, } = props;
const { values, businessTypeOptions, operatorTypeOptions, statusOptions } = props;

const intl = useIntl();
const handleOk = () => {
console.log("handle ok");
console.log('handle ok');
};
const handleCancel = () => {
props.onCancel();


+ 25
- 16
react-ui/src/pages/System/Operlog/index.tsx View File

@@ -1,14 +1,25 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import DictTag from '@/components/DictTag';
import {
addOperlog,
exportOperlog,
getOperlogList,
removeOperlog,
updateOperlog,
} from '@/services/monitor/operlog';
import { getDictValueEnum } from '@/services/system/dict';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getOperlogList, removeOperlog, addOperlog, updateOperlog, exportOperlog } from '@/services/monitor/operlog';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './detail';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';

/**
* 添加节点
@@ -79,12 +90,11 @@ const handleRemove = async (selectedRows: API.Monitor.Operlog[]) => {
return false;
}
};

/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -100,7 +110,6 @@ const handleExport = async () => {
}
};


const OperlogTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();

@@ -149,7 +158,7 @@ const OperlogTableList: React.FC = () => {
valueType: 'select',
valueEnum: businessTypeOptions,
render: (_, record) => {
return (<DictTag enums={businessTypeOptions} value={record.businessType} />);
return <DictTag enums={businessTypeOptions} value={record.businessType} />;
},
},
{
@@ -163,7 +172,7 @@ const OperlogTableList: React.FC = () => {
valueType: 'select',
valueEnum: operatorTypeOptions,
render: (_, record) => {
return (<DictTag enums={operatorTypeOptions} value={record.operatorType} />);
return <DictTag enums={operatorTypeOptions} value={record.operatorType} />;
},
},
{
@@ -187,7 +196,7 @@ const OperlogTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag key="status" enums={statusOptions} value={record.status} />);
return <DictTag key="status" enums={statusOptions} value={record.status} />;
},
},
{
@@ -260,7 +269,7 @@ const OperlogTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>


+ 27
- 26
react-ui/src/pages/System/Post/edit.tsx View File

@@ -1,14 +1,14 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormRadio,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { Form, Modal} from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DictValueEnumObj } from '@/components/DictTag';
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React, { useEffect } from 'react';

export type PostFormData = Record<string, unknown> & Partial<API.System.Post>;

@@ -23,21 +23,21 @@ export type PostFormProps = {
const PostForm: React.FC<PostFormProps> = (props) => {
const [form] = Form.useForm();

const { statusOptions, } = props;
const { statusOptions } = props;

useEffect(() => {
form.resetFields();
form.setFieldsValue({
postId: props.values.postId,
postCode: props.values.postCode,
postName: props.values.postName,
postSort: props.values.postSort,
status: props.values.status,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
postId: props.values.postId,
postCode: props.values.postCode,
postName: props.values.postName,
postSort: props.values.postSort,
status: props.values.status,
createBy: props.values.createBy,
createTime: props.values.createTime,
updateBy: props.values.updateBy,
updateTime: props.values.updateTime,
remark: props.values.remark,
});
}, [form, props]);

@@ -65,12 +65,13 @@ const PostForm: React.FC<PostFormProps> = (props) => {
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
<ProForm
form={form}
grid={true}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
layout="horizontal"
onFinish={handleFinish}
>
<ProFormDigit
name="postId"
label={intl.formatMessage({
@@ -83,7 +84,7 @@ const PostForm: React.FC<PostFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入岗位编号!" defaultMessage="请输入岗位编号!" />,
message: <FormattedMessage id="请输入岗位编号!" defaultMessage="请输入岗位编号!" />,
},
]}
/>
@@ -97,7 +98,7 @@ const PostForm: React.FC<PostFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入岗位名称!" defaultMessage="请输入岗位名称!" />,
message: <FormattedMessage id="请输入岗位名称!" defaultMessage="请输入岗位名称!" />,
},
]}
/>
@@ -111,7 +112,7 @@ const PostForm: React.FC<PostFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入岗位编码!" defaultMessage="请输入岗位编码!" />,
message: <FormattedMessage id="请输入岗位编码!" defaultMessage="请输入岗位编码!" />,
},
]}
/>
@@ -125,7 +126,7 @@ const PostForm: React.FC<PostFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入显示顺序!" defaultMessage="请输入显示顺序!" />,
message: <FormattedMessage id="请输入显示顺序!" defaultMessage="请输入显示顺序!" />,
},
]}
/>
@@ -140,7 +141,7 @@ const PostForm: React.FC<PostFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入状态!" defaultMessage="请输入状态!" />,
message: <FormattedMessage id="请输入状态!" defaultMessage="请输入状态!" />,
},
]}
/>
@@ -154,7 +155,7 @@ const PostForm: React.FC<PostFormProps> = (props) => {
rules={[
{
required: false,
message: <FormattedMessage id="请输入备注!" defaultMessage="请输入备注!" />,
message: <FormattedMessage id="请输入备注!" defaultMessage="请输入备注!" />,
},
]}
/>


+ 20
- 16
react-ui/src/pages/System/Post/index.tsx View File

@@ -1,14 +1,19 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import DictTag from '@/components/DictTag';
import { getDictValueEnum } from '@/services/system/dict';
import { addPost, exportPost, getPostList, removePost, updatePost } from '@/services/system/post';
import { DeleteOutlined, ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import { getPostList, removePost, addPost, updatePost, exportPost } from '@/services/system/post';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UpdateForm from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';

/**
* 添加节点
@@ -103,7 +108,7 @@ const handleRemoveOne = async (selectedRow: API.System.Post) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -119,9 +124,8 @@ const handleExport = async () => {
}
};


const PostTableList: React.FC = () => {
const formTableRef = useRef<FormInstance>();
const formTableRef = useRef<FormInstance>();

const [modalVisible, setModalVisible] = useState<boolean>(false);

@@ -142,7 +146,7 @@ const PostTableList: React.FC = () => {
});
}, []);

const columns: ProColumns<API.System.Post>[] = [
const columns: ProColumns<API.System.Post>[] = [
{
title: <FormattedMessage id="system.post.post_id" defaultMessage="岗位编号" />,
dataIndex: 'postId',
@@ -170,7 +174,7 @@ const PostTableList: React.FC = () => {
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -249,7 +253,7 @@ const PostTableList: React.FC = () => {
</Button>,
<Button
type="primary"
key="remove"
key="remove"
hidden={selectedRows?.length === 0 || !access.hasPerms('system:post:remove')}
onClick={async () => {
Modal.confirm({
@@ -264,7 +268,7 @@ const PostTableList: React.FC = () => {
}
},
onCancel() {},
});
});
}}
>
<DeleteOutlined />


+ 257
- 248
react-ui/src/pages/System/Role/authUser.tsx View File

@@ -1,14 +1,24 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess, history, useParams } from '@umijs/max';
import { Button, Modal, message } from 'antd';
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, RollbackOutlined } from '@ant-design/icons';
import { authUserSelectAll, authUserCancel, authUserCancelAll, allocatedUserList, unallocatedUserList } from '@/services/system/role';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';
import UserSelectorModal from './components/UserSelectorModal';
import { HttpResult } from '@/enums/httpEnum';
import { getDictValueEnum } from '@/services/system/dict';
import {
allocatedUserList,
authUserCancel,
authUserCancelAll,
authUserSelectAll,
unallocatedUserList,
} from '@/services/system/role';
import {
DeleteOutlined,
ExclamationCircleOutlined,
PlusOutlined,
RollbackOutlined,
} from '@ant-design/icons';
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, history, useAccess, useIntl, useParams } from '@umijs/max';
import { Button, Modal, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import UserSelectorModal from './components/UserSelectorModal';

/**
* 删除节点
@@ -16,258 +26,257 @@ import { HttpResult } from '@/enums/httpEnum';
* @param selectedRows
*/
const cancelAuthUserAll = async (roleId: string, selectedRows: API.System.User[]) => {
const hide = message.loading('正在取消授权');
if (!selectedRows) return true;
try {
const userIds = selectedRows.map((row) => row.userId).join(',');
const resp = await authUserCancelAll({roleId, userIds});
hide();
if (resp.code === 200) {
message.success('取消授权成功,即将刷新');
} else {
message.error(resp.msg);
}
return true;
} catch (error) {
hide();
message.error('取消授权失败,请重试');
return false;
}
const hide = message.loading('正在取消授权');
if (!selectedRows) return true;
try {
const userIds = selectedRows.map((row) => row.userId).join(',');
const resp = await authUserCancelAll({ roleId, userIds });
hide();
if (resp.code === 200) {
message.success('取消授权成功,即将刷新');
} else {
message.error(resp.msg);
}
return true;
} catch (error) {
hide();
message.error('取消授权失败,请重试');
return false;
}
};

const cancelAuthUser = async (roleId: string, userId: number) => {
const hide = message.loading('正在取消授权');
try {
const resp = await authUserCancel({ userId, roleId });
hide();
if (resp.code === 200) {
message.success('取消授权成功,即将刷新');
} else {
message.error(resp.msg);
}
return true;
} catch (error) {
hide();
message.error('取消授权失败,请重试');
return false;
}
const hide = message.loading('正在取消授权');
try {
const resp = await authUserCancel({ userId, roleId });
hide();
if (resp.code === 200) {
message.success('取消授权成功,即将刷新');
} else {
message.error(resp.msg);
}
return true;
} catch (error) {
hide();
message.error('取消授权失败,请重试');
return false;
}
};


const AuthUserTableList: React.FC = () => {
const [modalVisible, setModalVisible] = useState<boolean>(false);

const [modalVisible, setModalVisible] = useState<boolean>(false);

const actionRef = useRef<ActionType>();
const [selectedRows, setSelectedRows] = useState<API.System.User[]>([]);
const [statusOptions, setStatusOptions] = useState<any>([]);
const actionRef = useRef<ActionType>();
const [selectedRows, setSelectedRows] = useState<API.System.User[]>([]);
const [statusOptions, setStatusOptions] = useState<any>([]);

const access = useAccess();
const access = useAccess();

/** 国际化配置 */
const intl = useIntl();
/** 国际化配置 */
const intl = useIntl();

const params = useParams();
if (params.id === undefined) {
history.back();
}
const roleId = params.id || '0';
const params = useParams();
if (params.id === undefined) {
history.back();
}
const roleId = params.id || '0';

useEffect(() => {
getDictValueEnum('sys_normal_disable').then((data) => {
setStatusOptions(data);
});
}, []);
useEffect(() => {
getDictValueEnum('sys_normal_disable').then((data) => {
setStatusOptions(data);
});
}, []);

const columns: ProColumns<API.System.User>[] = [
{
title: <FormattedMessage id="system.user.user_id" defaultMessage="用户编号" />,
dataIndex: 'deptId',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.user_name" defaultMessage="用户账号" />,
dataIndex: 'userName',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.nick_name" defaultMessage="用户昵称" />,
dataIndex: 'nickName',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.phonenumber" defaultMessage="手机号码" />,
dataIndex: 'phonenumber',
valueType: 'text',
},
{
title: <FormattedMessage id="system.role.create_time" defaultMessage="创建时间" />,
dataIndex: 'createTime',
valueType: 'dateRange',
render: (_, record) => {
return (<span>{record.createTime.toString()} </span>);
},
hideInSearch: true,
},
{
title: <FormattedMessage id="system.user.status" defaultMessage="帐号状态" />,
dataIndex: 'status',
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
},
},
{
title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
dataIndex: 'option',
width: '60px',
valueType: 'option',
render: (_, record) => [
<Button
type="link"
size="small"
danger
icon={<DeleteOutlined />}
key="remove"
hidden={!access.hasPerms('system:role:remove')}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确认要取消该用户' + record.userName + '"角色授权吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
const success = await cancelAuthUser(roleId, record.userId);
if (success) {
if (actionRef.current) {
actionRef.current.reload();
}
}
},
});
}}
>
取消授权
</Button>,
],
},
];
const columns: ProColumns<API.System.User>[] = [
{
title: <FormattedMessage id="system.user.user_id" defaultMessage="用户编号" />,
dataIndex: 'deptId',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.user_name" defaultMessage="用户账号" />,
dataIndex: 'userName',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.nick_name" defaultMessage="用户昵称" />,
dataIndex: 'nickName',
valueType: 'text',
},
{
title: <FormattedMessage id="system.user.phonenumber" defaultMessage="手机号码" />,
dataIndex: 'phonenumber',
valueType: 'text',
},
{
title: <FormattedMessage id="system.role.create_time" defaultMessage="创建时间" />,
dataIndex: 'createTime',
valueType: 'dateRange',
render: (_, record) => {
return <span>{record.createTime.toString()} </span>;
},
hideInSearch: true,
},
{
title: <FormattedMessage id="system.user.status" defaultMessage="帐号状态" />,
dataIndex: 'status',
valueType: 'select',
valueEnum: statusOptions,
render: (_, record) => {
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
dataIndex: 'option',
width: '60px',
valueType: 'option',
render: (_, record) => [
<Button
type="link"
size="small"
danger
icon={<DeleteOutlined />}
key="remove"
hidden={!access.hasPerms('system:role:remove')}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确认要取消该用户' + record.userName + '"角色授权吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
const success = await cancelAuthUser(roleId, record.userId);
if (success) {
if (actionRef.current) {
actionRef.current.reload();
}
}
},
});
}}
>
取消授权
</Button>,
],
},
];

return (
<PageContainer>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.System.User>
headerTitle={intl.formatMessage({
id: 'pages.searchTable.title',
defaultMessage: '信息',
})}
actionRef={actionRef}
rowKey="userId"
key="userList"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button
type="primary"
key="add"
hidden={!access.hasPerms('system:role:add')}
onClick={async () => {
setModalVisible(true);
}}
>
<PlusOutlined /> <FormattedMessage id="system.role.auth.addUser" defaultMessage="添加用户" />
</Button>,
<Button
type="primary"
key="remove"
hidden={selectedRows?.length === 0 || !access.hasPerms('system:role:remove')}
onClick={async () => {
Modal.confirm({
title: '是否确认删除所选数据项?',
icon: <ExclamationCircleOutlined />,
content: '请谨慎操作',
async onOk() {
const success = await cancelAuthUserAll(roleId, selectedRows);
if (success) {
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
});
}}
>
<DeleteOutlined />
<FormattedMessage id="system.role.auth.cancelAll" defaultMessage="批量取消授权" />
</Button>,
<Button
type="primary"
key="back"
onClick={async () => {
history.back();
}}
>
<RollbackOutlined />
<FormattedMessage id="pages.goback" defaultMessage="返回" />
</Button>,
]}
request={(params) =>
allocatedUserList({ ...params, roleId } as API.System.RoleListParams).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => {
setSelectedRows(selectedRows);
},
}}
/>
</div>
<UserSelectorModal
open={modalVisible}
onSubmit={(values: React.Key[]) => {
const userIds = values.join(",");
if (userIds === "") {
message.warning("请选择要分配的用户");
return;
}
authUserSelectAll({ roleId: roleId, userIds: userIds }).then(resp => {
if (resp.code === HttpResult.SUCCESS) {
message.success('更新成功!');
if (actionRef.current) {
actionRef.current.reload();
}
} else {
message.warning(resp.msg);
}
})
setModalVisible(false);
}}
onCancel={() => {
setModalVisible(false);
}}
params={{roleId}}
request={(params) =>
unallocatedUserList({ ...params } as API.System.RoleListParams).then((res) => {
const result = {
data: res.rows,
total: res.rows.length,
success: true,
};
return result;
})
}
/>
</PageContainer>
);
return (
<PageContainer>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.System.User>
headerTitle={intl.formatMessage({
id: 'pages.searchTable.title',
defaultMessage: '信息',
})}
actionRef={actionRef}
rowKey="userId"
key="userList"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button
type="primary"
key="add"
hidden={!access.hasPerms('system:role:add')}
onClick={async () => {
setModalVisible(true);
}}
>
<PlusOutlined />{' '}
<FormattedMessage id="system.role.auth.addUser" defaultMessage="添加用户" />
</Button>,
<Button
type="primary"
key="remove"
hidden={selectedRows?.length === 0 || !access.hasPerms('system:role:remove')}
onClick={async () => {
Modal.confirm({
title: '是否确认删除所选数据项?',
icon: <ExclamationCircleOutlined />,
content: '请谨慎操作',
async onOk() {
const success = await cancelAuthUserAll(roleId, selectedRows);
if (success) {
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
},
onCancel() {},
});
}}
>
<DeleteOutlined />
<FormattedMessage id="system.role.auth.cancelAll" defaultMessage="批量取消授权" />
</Button>,
<Button
type="primary"
key="back"
onClick={async () => {
history.back();
}}
>
<RollbackOutlined />
<FormattedMessage id="pages.goback" defaultMessage="返回" />
</Button>,
]}
request={(params) =>
allocatedUserList({ ...params, roleId } as API.System.RoleListParams).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => {
setSelectedRows(selectedRows);
},
}}
/>
</div>
<UserSelectorModal
open={modalVisible}
onSubmit={(values: React.Key[]) => {
const userIds = values.join(',');
if (userIds === '') {
message.warning('请选择要分配的用户');
return;
}
authUserSelectAll({ roleId: roleId, userIds: userIds }).then((resp) => {
if (resp.code === HttpResult.SUCCESS) {
message.success('更新成功!');
if (actionRef.current) {
actionRef.current.reload();
}
} else {
message.warning(resp.msg);
}
});
setModalVisible(false);
}}
onCancel={() => {
setModalVisible(false);
}}
params={{ roleId }}
request={(params) =>
unallocatedUserList({ ...params } as API.System.RoleListParams).then((res) => {
const result = {
data: res.rows,
total: res.rows.length,
success: true,
};
return result;
})
}
/>
</PageContainer>
);
};

export default AuthUserTableList;

+ 213
- 205
react-ui/src/pages/System/Role/components/DataScope.tsx View File

@@ -1,233 +1,241 @@
import React, { useEffect, useState } from 'react';
import { Checkbox, Col, Form, Modal, Row, Tree } from 'antd';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Key, ProForm, ProFormDigit, ProFormSelect, ProFormText } from '@ant-design/pro-components';
import { DataNode } from 'antd/es/tree';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Checkbox, Col, Form, Modal, Row, Tree } from 'antd';
import { CheckboxValueType } from 'antd/es/checkbox/Group';
import { DataNode } from 'antd/es/tree';
import React, { useEffect, useState } from 'react';

/* *
*
* @author whiteshader@163.com
* @datetime 2023/02/06
*
*
* */

export type FormValueType = any & Partial<API.System.Dept>;

export type DataScopeFormProps = {
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
onSubmit: (values: FormValueType) => Promise<void>;
open: boolean;
values: Partial<API.System.Role>;
deptTree: DataNode[];
deptCheckedKeys: string[];
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
onSubmit: (values: FormValueType) => Promise<void>;
open: boolean;
values: Partial<API.System.Role>;
deptTree: DataNode[];
deptCheckedKeys: string[];
};

const DataScopeForm: React.FC<DataScopeFormProps> = (props) => {
const [form] = Form.useForm();
const [form] = Form.useForm();

const { deptTree, deptCheckedKeys } = props;
const [dataScopeType, setDataScopeType] = useState<string | undefined>('1');
const [deptIds, setDeptIds] = useState<string[] | {checked: string[], halfChecked: string[]}>([]);
const [deptTreeExpandKey, setDeptTreeExpandKey] = useState<Key[]>([]);
const [checkStrictly, setCheckStrictly] = useState<boolean>(true);
const { deptTree, deptCheckedKeys } = props;
const [dataScopeType, setDataScopeType] = useState<string | undefined>('1');
const [deptIds, setDeptIds] = useState<string[] | { checked: string[]; halfChecked: string[] }>(
[],
);
const [deptTreeExpandKey, setDeptTreeExpandKey] = useState<Key[]>([]);
const [checkStrictly, setCheckStrictly] = useState<boolean>(true);

useEffect(() => {
setDeptIds(deptCheckedKeys);
form.resetFields();
form.setFieldsValue({
roleId: props.values.roleId,
roleName: props.values.roleName,
roleKey: props.values.roleKey,
dataScope: props.values.dataScope,
});
setDataScopeType(props.values.dataScope);
}, [props.values]);

useEffect(() => {
setDeptIds(deptCheckedKeys);
form.resetFields();
form.setFieldsValue({
roleId: props.values.roleId,
roleName: props.values.roleName,
roleKey: props.values.roleKey,
dataScope: props.values.dataScope,
});
setDataScopeType(props.values.dataScope);
}, [props.values]);
const intl = useIntl();
const handleOk = () => {
form.submit();
};
const handleCancel = () => {
props.onCancel();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit({ ...values, deptIds } as FormValueType);
};

const intl = useIntl();
const handleOk = () => {
form.submit();
};
const handleCancel = () => {
props.onCancel();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit({ ...values, deptIds } as FormValueType);
};

const getAllDeptNode = (node: DataNode[]) => {
let keys: any[] = [];
node.forEach(value => {
keys.push(value.key);
if(value.children) {
keys = keys.concat(getAllDeptNode(value.children));
}
});
return keys;
}
const getAllDeptNode = (node: DataNode[]) => {
let keys: any[] = [];
node.forEach((value) => {
keys.push(value.key);
if (value.children) {
keys = keys.concat(getAllDeptNode(value.children));
}
});
return keys;
};

const deptAllNodes = getAllDeptNode(deptTree);
const deptAllNodes = getAllDeptNode(deptTree);

const onDeptOptionChange = (checkedValues: CheckboxValueType[]) => {
if (checkedValues.includes('deptExpand')) {
setDeptTreeExpandKey(deptAllNodes);
} else {
setDeptTreeExpandKey([]);
}
if (checkedValues.includes('deptNodeAll')) {
setDeptIds(deptAllNodes);
} else {
setDeptIds([]);
}

const onDeptOptionChange = (checkedValues: CheckboxValueType[]) => {
if(checkedValues.includes('deptExpand')) {
setDeptTreeExpandKey(deptAllNodes);
} else {
setDeptTreeExpandKey([]);
}
if(checkedValues.includes('deptNodeAll')) {
setDeptIds(deptAllNodes);
} else {
setDeptIds([]);
}
if(checkedValues.includes('deptCheckStrictly')) {
setCheckStrictly(false);
} else {
setCheckStrictly(true);
}
};
if (checkedValues.includes('deptCheckStrictly')) {
setCheckStrictly(false);
} else {
setCheckStrictly(true);
}
};

return (
<Modal
width={640}
title={intl.formatMessage({
id: 'system.user.auth.role',
defaultMessage: '分配角色',
})}
open={props.open}
destroyOnClose
forceRender
onOk={handleOk}
onCancel={handleCancel}
return (
<Modal
width={640}
title={intl.formatMessage({
id: 'system.user.auth.role',
defaultMessage: '分配角色',
})}
open={props.open}
destroyOnClose
forceRender
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
form={form}
grid={true}
layout="horizontal"
onFinish={handleFinish}
initialValues={{
login_password: '',
confirm_password: '',
}}
>
<ProFormDigit
name="roleId"
label={intl.formatMessage({
id: 'system.role.role_id',
defaultMessage: '角色编号',
})}
colProps={{ md: 12, xl: 12 }}
placeholder="请输入角色编号"
disabled
hidden={true}
rules={[
{
required: false,
message: <FormattedMessage id="请输入角色编号!" defaultMessage="请输入角色编号!" />,
},
]}
/>
<ProFormText
name="roleName"
label={intl.formatMessage({
id: 'system.role.role_name',
defaultMessage: '角色名称',
})}
disabled
placeholder="请输入角色名称"
rules={[
{
required: true,
message: <FormattedMessage id="请输入角色名称!" defaultMessage="请输入角色名称!" />,
},
]}
/>
<ProFormText
name="roleKey"
label={intl.formatMessage({
id: 'system.role.role_key',
defaultMessage: '权限字符串',
})}
disabled
placeholder="请输入角色权限字符串"
rules={[
{
required: true,
message: (
<FormattedMessage
id="请输入角色权限字符串!"
defaultMessage="请输入角色权限字符串!"
/>
),
},
]}
/>
<ProFormSelect
name="dataScope"
label="权限范围"
initialValue={'1'}
placeholder="请输入用户性别"
valueEnum={{
'1': '全部数据权限',
'2': '自定数据权限',
'3': '本部门数据权限',
'4': '本部门及以下数据权限',
'5': '仅本人数据权限',
}}
rules={[
{
required: true,
},
]}
fieldProps={{
onChange: (value) => {
setDataScopeType(value);
},
}}
/>
<ProForm.Item
name="deptIds"
label={intl.formatMessage({
id: 'system.role.auth',
defaultMessage: '菜单权限',
})}
required={dataScopeType === '1'}
hidden={dataScopeType !== '1'}
>
<ProForm
form={form}
grid={true}
layout="horizontal"
onFinish={handleFinish}
initialValues={{
login_password: '',
confirm_password: '',
<Row gutter={[16, 16]}>
<Col md={24}>
<Checkbox.Group
options={[
{ label: '展开/折叠', value: 'deptExpand' },
{ label: '全选/全不选', value: 'deptNodeAll' },
// { label: '父子联动', value: 'deptCheckStrictly' },
]}
onChange={onDeptOptionChange}
/>
</Col>
<Col md={24}>
<Tree
checkable={true}
checkStrictly={checkStrictly}
expandedKeys={deptTreeExpandKey}
treeData={deptTree}
checkedKeys={deptIds}
defaultCheckedKeys={deptCheckedKeys}
onCheck={(checkedKeys: any, checkInfo: any) => {
console.log(checkedKeys, checkInfo);
if (checkStrictly) {
return setDeptIds(checkedKeys.checked);
} else {
return setDeptIds({
checked: checkedKeys,
halfChecked: checkInfo.halfCheckedKeys,
});
}
}}
>

<ProFormDigit
name="roleId"
label={intl.formatMessage({
id: 'system.role.role_id',
defaultMessage: '角色编号',
})}
colProps={{ md: 12, xl: 12 }}
placeholder="请输入角色编号"
disabled
hidden={true}
rules={[
{
required: false,
message: <FormattedMessage id="请输入角色编号!" defaultMessage="请输入角色编号!" />,
},
]}
/>
<ProFormText
name="roleName"
label={intl.formatMessage({
id: 'system.role.role_name',
defaultMessage: '角色名称',
})}
disabled
placeholder="请输入角色名称"
rules={[
{
required: true,
message: <FormattedMessage id="请输入角色名称!" defaultMessage="请输入角色名称!" />,
},
]}
/>
<ProFormText
name="roleKey"
label={intl.formatMessage({
id: 'system.role.role_key',
defaultMessage: '权限字符串',
})}
disabled
placeholder="请输入角色权限字符串"
rules={[
{
required: true,
message: <FormattedMessage id="请输入角色权限字符串!" defaultMessage="请输入角色权限字符串!" />,
},
]}
/>
<ProFormSelect
name="dataScope"
label='权限范围'
initialValue={'1'}
placeholder="请输入用户性别"
valueEnum={{
"1": "全部数据权限",
"2": "自定数据权限",
"3": "本部门数据权限",
"4": "本部门及以下数据权限",
"5": "仅本人数据权限"
}}
rules={[
{
required: true,
},
]}
fieldProps={{
onChange: (value) => {
setDataScopeType(value);
},
}}
/>
<ProForm.Item
name="deptIds"
label={intl.formatMessage({
id: 'system.role.auth',
defaultMessage: '菜单权限',
})}
required={dataScopeType === '1'}
hidden={dataScopeType !== '1'}
>
<Row gutter={[16, 16]}>
<Col md={24}>
<Checkbox.Group
options={[
{ label: '展开/折叠', value: 'deptExpand' },
{ label: '全选/全不选', value: 'deptNodeAll' },
// { label: '父子联动', value: 'deptCheckStrictly' },
]}
onChange={onDeptOptionChange} />
</Col>
<Col md={24}>
<Tree
checkable={true}
checkStrictly={checkStrictly}
expandedKeys={deptTreeExpandKey}
treeData={deptTree}
checkedKeys={deptIds}
defaultCheckedKeys={deptCheckedKeys}
onCheck={(checkedKeys: any, checkInfo: any) => {
console.log(checkedKeys, checkInfo);
if(checkStrictly) {
return setDeptIds(checkedKeys.checked);
} else {
return setDeptIds({checked: checkedKeys, halfChecked: checkInfo.halfCheckedKeys});
}
}}
onExpand={(expandedKeys: Key[]) => {
setDeptTreeExpandKey(deptTreeExpandKey.concat(expandedKeys));
}}
/>
</Col>
</Row>
</ProForm.Item>
</ProForm>
</Modal>
);
onExpand={(expandedKeys: Key[]) => {
setDeptTreeExpandKey(deptTreeExpandKey.concat(expandedKeys));
}}
/>
</Col>
</Row>
</ProForm.Item>
</ProForm>
</Modal>
);
};

export default DataScopeForm;

+ 15
- 11
react-ui/src/pages/System/Role/components/UserSelectorModal.tsx View File

@@ -1,16 +1,21 @@
import React, { useEffect, useRef, useState } from 'react';
import { Modal } from 'antd';
import { FormattedMessage, useIntl } from '@umijs/max';
import { ActionType, ParamsType, ProColumns, ProTable, RequestData } from '@ant-design/pro-components';
import { getDictValueEnum } from '@/services/system/dict';
import DictTag from '@/components/DictTag';

import { getDictValueEnum } from '@/services/system/dict';
import {
ActionType,
ParamsType,
ProColumns,
ProTable,
RequestData,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Modal } from 'antd';
import React, { useEffect, useRef, useState } from 'react';

/* *
*
* @author whiteshader@163.com
* @datetime 2023/02/10
*
*
* */

export type DataScopeFormProps = {
@@ -22,7 +27,6 @@ export type DataScopeFormProps = {
};

const UserSelectorModal: React.FC<DataScopeFormProps> = (props) => {
const actionRef = useRef<ActionType>();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [statusOptions, setStatusOptions] = useState<any>([]);
@@ -71,7 +75,7 @@ const UserSelectorModal: React.FC<DataScopeFormProps> = (props) => {
hideInSearch: true,
valueEnum: statusOptions,
render: (_, record) => {
return (<DictTag enums={statusOptions} value={record.status} />);
return <DictTag enums={statusOptions} value={record.status} />;
},
},
{
@@ -80,9 +84,9 @@ const UserSelectorModal: React.FC<DataScopeFormProps> = (props) => {
valueType: 'dateRange',
hideInSearch: true,
render: (_, record) => {
return (<span>{record.createTime.toString()} </span>);
return <span>{record.createTime.toString()} </span>;
},
}
},
];

return (


+ 17
- 11
react-ui/src/pages/System/Role/edit.tsx View File

@@ -1,15 +1,15 @@
import React, { useEffect, useState } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormRadio,
ProFormText,
ProFormTextArea,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import Tree, { DataNode } from 'antd/es/tree';
import { DictValueEnumObj } from '@/components/DictTag';
import React, { useEffect, useState } from 'react';

export type RoleFormData = Record<string, unknown> & Partial<API.System.Role>;

@@ -78,7 +78,8 @@ const RoleForm: React.FC<RoleFormProps> = (props) => {
grid={true}
layout="horizontal"
submitter={false}
onFinish={handleFinish}>
onFinish={handleFinish}
>
<ProFormDigit
name="roleId"
label={intl.formatMessage({
@@ -119,7 +120,12 @@ const RoleForm: React.FC<RoleFormProps> = (props) => {
rules={[
{
required: true,
message: <FormattedMessage id="请输入角色权限字符串!" defaultMessage="请输入角色权限字符串!" />,
message: (
<FormattedMessage
id="请输入角色权限字符串!"
defaultMessage="请输入角色权限字符串!"
/>
),
},
]}
/>
@@ -136,8 +142,8 @@ const RoleForm: React.FC<RoleFormProps> = (props) => {
message: <FormattedMessage id="请输入显示顺序!" defaultMessage="请输入显示顺序!" />,
},
]}
fieldProps = {{
defaultValue: 1
fieldProps={{
defaultValue: 1,
}}
/>
<ProFormRadio.Group
@@ -154,8 +160,8 @@ const RoleForm: React.FC<RoleFormProps> = (props) => {
message: <FormattedMessage id="请输入角色状态!" defaultMessage="请输入角色状态!" />,
},
]}
fieldProps = {{
defaultValue: "0"
fieldProps={{
defaultValue: '0',
}}
/>
<ProForm.Item
@@ -172,7 +178,7 @@ const RoleForm: React.FC<RoleFormProps> = (props) => {
defaultExpandAll={false}
treeData={menuTree}
defaultCheckedKeys={menuCheckedKeys}
onCheck={(checkedKeys: any) => {
onCheck={(checkedKeys: any) => {
return setMenuIds(checkedKeys.checked);
}}
/>


+ 56
- 32
react-ui/src/pages/System/Role/index.tsx View File

@@ -1,16 +1,38 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess, history } from '@umijs/max';
import { DataNode } from 'antd/es/tree';
import { Button, message, Modal, Dropdown, FormInstance, Space, Switch } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, EditOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined } from '@ant-design/icons';
import { getRoleList, removeRole, addRole, updateRole, exportRole, getRoleMenuList, changeRoleStatus, updateRoleDataScope, getDeptTreeSelect, getRole } from '@/services/system/role';
import UpdateForm from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import { formatTreeData } from '@/utils/tree';
import { getMenuTree } from '@/services/system/menu';
import {
addRole,
changeRoleStatus,
exportRole,
getDeptTreeSelect,
getRole,
getRoleList,
getRoleMenuList,
removeRole,
updateRole,
updateRoleDataScope,
} from '@/services/system/role';
import { formatTreeData } from '@/utils/tree';
import {
DeleteOutlined,
DownOutlined,
EditOutlined,
ExclamationCircleOutlined,
PlusOutlined,
} from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, history, useAccess, useIntl } from '@umijs/max';
import { Button, Dropdown, FormInstance, Modal, Space, Switch, message } from 'antd';
import { DataNode } from 'antd/es/tree';
import React, { useEffect, useRef, useState } from 'react';
import DataScopeForm from './components/DataScope';
import UpdateForm from './edit';

const { confirm } = Modal;

@@ -107,7 +129,7 @@ const handleRemoveOne = async (selectedRow: API.System.Role) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -123,9 +145,7 @@ const handleExport = async () => {
}
};


const RoleTableList: React.FC = () => {

const [messageApi, contextHolder] = message.useMessage();
const formTableRef = useRef<FormInstance>();

@@ -152,12 +172,12 @@ const RoleTableList: React.FC = () => {
}, []);

const showChangeStatusConfirm = (record: API.System.Role) => {
let text = record.status === "1" ? "启用" : "停用";
let text = record.status === '1' ? '启用' : '停用';
const newStatus = record.status === '0' ? '1' : '0';
confirm({
title: `确认要${text}${record.roleName}角色吗?`,
onOk() {
changeRoleStatus(record.roleId, newStatus).then(resp => {
changeRoleStatus(record.roleId, newStatus).then((resp) => {
if (resp.code === 200) {
messageApi.open({
type: 'success',
@@ -211,7 +231,8 @@ const RoleTableList: React.FC = () => {
unCheckedChildren="停用"
defaultChecked
onClick={() => showChangeStatusConfirm(record)}
/>)
/>
);
},
},
{
@@ -219,7 +240,7 @@ const RoleTableList: React.FC = () => {
dataIndex: 'createTime',
valueType: 'dateRange',
render: (_, record) => {
return (<span>{record.createTime.toString()} </span>);
return <span>{record.createTime.toString()} </span>;
},
search: {
transform: (value) => {
@@ -247,9 +268,11 @@ const RoleTableList: React.FC = () => {
if (res.code === 200) {
const treeData = formatTreeData(res.menus);
setMenuTree(treeData);
setMenuIds(res.checkedKeys.map(item => {
return `${item}`
}));
setMenuIds(
res.checkedKeys.map((item) => {
return `${item}`;
}),
);
setModalVisible(true);
setCurrentRow(record);
} else {
@@ -303,25 +326,26 @@ const RoleTableList: React.FC = () => {
],
onClick: ({ key }: any) => {
if (key === 'datascope') {
getRole(record.roleId).then(resp => {
if(resp.code === 200) {
getRole(record.roleId).then((resp) => {
if (resp.code === 200) {
setCurrentRow(resp.data);
setDataScopeModalOpen(true);
}
})
getDeptTreeSelect(record.roleId).then(resp => {
});
getDeptTreeSelect(record.roleId).then((resp) => {
if (resp.code === 200) {
setMenuTree(formatTreeData(resp.depts));
setMenuIds(resp.checkedKeys.map((item:number) => {
return `${item}`
}));
setMenuIds(
resp.checkedKeys.map((item: number) => {
return `${item}`;
}),
);
}
})
}
else if (key === 'authUser') {
});
} else if (key === 'authUser') {
history.push(`/system/role-auth/user/${record.roleId}`);
}
}
},
}}
>
<a onClick={(e) => e.preventDefault()}>
@@ -388,7 +412,7 @@ const RoleTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>


+ 61
- 61
react-ui/src/pages/System/User/components/AuthRole.tsx View File

@@ -1,81 +1,81 @@
import React, { useEffect } from 'react';
import { Form, Modal } from 'antd';
import { useIntl } from '@umijs/max';
import { ProForm, ProFormSelect } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React, { useEffect } from 'react';

/* *
*
* @author whiteshader@163.com
* @datetime 2023/02/06
*
*
* */

export type FormValueType = any & Partial<API.System.Dept>;

export type AuthRoleFormProps = {
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
onSubmit: (values: FormValueType) => Promise<void>;
open: boolean;
roleIds: number[];
roles: string[];
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
onSubmit: (values: FormValueType) => Promise<void>;
open: boolean;
roleIds: number[];
roles: string[];
};

const AuthRoleForm: React.FC<AuthRoleFormProps> = (props) => {
const [form] = Form.useForm();
const [form] = Form.useForm();

useEffect(() => {
form.resetFields();
form.setFieldValue( 'roleIds', props.roleIds);
});
useEffect(() => {
form.resetFields();
form.setFieldValue('roleIds', props.roleIds);
});

const intl = useIntl();
const handleOk = () => {
form.submit();
};
const handleCancel = () => {
props.onCancel();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit(values as FormValueType);
};
const intl = useIntl();
const handleOk = () => {
form.submit();
};
const handleCancel = () => {
props.onCancel();
};
const handleFinish = async (values: Record<string, any>) => {
props.onSubmit(values as FormValueType);
};

return (
<Modal
width={640}
title={intl.formatMessage({
id: 'system.user.auth.role',
defaultMessage: '分配角色',
})}
open={props.open}
destroyOnClose
forceRender
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
form={form}
grid={true}
layout="horizontal"
onFinish={handleFinish}
initialValues={{
login_password: '',
confirm_password: '',
}}
>
<ProFormSelect
name="roleIds"
mode="multiple"
label={intl.formatMessage({
id: 'system.user.role',
defaultMessage: '角色',
})}
options={props.roles}
placeholder="请选择角色"
rules={[{ required: true, message: '请选择角色!' }]}
/>
</ProForm>
</Modal>
);
return (
<Modal
width={640}
title={intl.formatMessage({
id: 'system.user.auth.role',
defaultMessage: '分配角色',
})}
open={props.open}
destroyOnClose
forceRender
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
form={form}
grid={true}
layout="horizontal"
onFinish={handleFinish}
initialValues={{
login_password: '',
confirm_password: '',
}}
>
<ProFormSelect
name="roleIds"
mode="multiple"
label={intl.formatMessage({
id: 'system.user.role',
defaultMessage: '角色',
})}
options={props.roles}
placeholder="请选择角色"
rules={[{ required: true, message: '请选择角色!' }]}
/>
</ProForm>
</Modal>
);
};

export default AuthRoleForm;

+ 3
- 4
react-ui/src/pages/System/User/components/DeptTree.tsx View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Tree, message } from 'antd';
import { getDeptTree } from '@/services/system/user';
import { Tree, message } from 'antd';
import React, { useEffect, useState } from 'react';

const { DirectoryTree } = Tree;

@@ -8,10 +8,9 @@ const { DirectoryTree } = Tree;
*
* @author whiteshader@163.com
* @datetime 2023/02/06
*
*
* */


export type TreeProps = {
onSelect: (values: any) => Promise<void>;
};


+ 5
- 5
react-ui/src/pages/System/User/components/ResetPwd.tsx View File

@@ -1,13 +1,13 @@
import React from 'react';
import { Form, Modal } from 'antd';
import { useIntl } from '@umijs/max';
import { ProForm, ProFormText } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import React from 'react';

/* *
*
* @author whiteshader@163.com
* @datetime 2023/02/06
*
*
* */

export type FormValueType = any & Partial<API.System.User>;
@@ -82,7 +82,7 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
rules={[
{
required: true,
message: "确认密码",
message: '确认密码',
},
{ validator: checkPassword },
]}


+ 15
- 27
react-ui/src/pages/System/User/edit.tsx View File

@@ -1,25 +1,24 @@
import React, { useEffect } from 'react';
import { DictValueEnumObj } from '@/components/DictTag';
import {
ProForm,
ProFormText,
ProFormSelect,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
ProFormTreeSelect,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, Modal } from 'antd';
import { useIntl, FormattedMessage } from '@umijs/max';
import { DataNode } from 'antd/es/tree';
import { DictValueEnumObj } from '@/components/DictTag';
import React, { useEffect } from 'react';

/* *
*
* @author whiteshader@163.com
* @datetime 2023/02/06
*
*
* */


export type UserFormData = Record<string, unknown> & Partial<API.System.User>;

export type UserFormProps = {
@@ -39,7 +38,7 @@ export type UserFormProps = {
const UserForm: React.FC<UserFormProps> = (props) => {
const [form] = Form.useForm();
const userId = Form.useWatch('userId', form);
const { sexOptions, statusOptions, } = props;
const { sexOptions, statusOptions } = props;
const { roles, posts, depts } = props;

useEffect(() => {
@@ -91,7 +90,8 @@ const UserForm: React.FC<UserFormProps> = (props) => {
form={form}
layout="horizontal"
submitter={false}
onFinish={handleFinish}>
onFinish={handleFinish}
>
<ProFormText
name="nickName"
label={intl.formatMessage({
@@ -103,9 +103,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
rules={[
{
required: true,
message: (
<FormattedMessage id="请输入用户昵称!" defaultMessage="请输入用户昵称!" />
),
message: <FormattedMessage id="请输入用户昵称!" defaultMessage="请输入用户昵称!" />,
},
]}
/>
@@ -123,9 +121,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
rules={[
{
required: true,
message: (
<FormattedMessage id="请输入用户部门!" defaultMessage="请输入用户部门!" />
),
message: <FormattedMessage id="请输入用户部门!" defaultMessage="请输入用户部门!" />,
},
]}
/>
@@ -140,9 +136,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
rules={[
{
required: false,
message: (
<FormattedMessage id="请输入手机号码!" defaultMessage="请输入手机号码!" />
),
message: <FormattedMessage id="请输入手机号码!" defaultMessage="请输入手机号码!" />,
},
]}
/>
@@ -157,9 +151,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
rules={[
{
required: false,
message: (
<FormattedMessage id="请输入用户邮箱!" defaultMessage="请输入用户邮箱!" />
),
message: <FormattedMessage id="请输入用户邮箱!" defaultMessage="请输入用户邮箱!" />,
},
]}
/>
@@ -207,9 +199,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
rules={[
{
required: false,
message: (
<FormattedMessage id="请输入用户性别!" defaultMessage="请输入用户性别!" />
),
message: <FormattedMessage id="请输入用户性别!" defaultMessage="请输入用户性别!" />,
},
]}
/>
@@ -226,9 +216,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
rules={[
{
required: false,
message: (
<FormattedMessage id="请输入帐号状态!" defaultMessage="请输入帐号状态!" />
),
message: <FormattedMessage id="请输入帐号状态!" defaultMessage="请输入帐号状态!" />,
},
]}
/>


+ 72
- 36
react-ui/src/pages/System/User/index.tsx View File

@@ -1,20 +1,51 @@

import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import { Card, Col, Dropdown, FormInstance, Row, Space, Switch } from 'antd';
import { Button, message, Modal } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
import { getUserList, removeUser, addUser, updateUser, exportUser, getUser, changeUserStatus, updateAuthRole, resetUserPwd } from '@/services/system/user';
import UpdateForm from './edit';
import { getDictValueEnum } from '@/services/system/dict';
import { DataNode } from 'antd/es/tree';
import { getDeptTree } from '@/services/system/user';
import DeptTree from './components/DeptTree';
import ResetPwd from './components/ResetPwd';
import { getPostList } from '@/services/system/post';
import { getRoleList } from '@/services/system/role';
import {
addUser,
changeUserStatus,
exportUser,
getDeptTree,
getUser,
getUserList,
removeUser,
resetUserPwd,
updateAuthRole,
updateUser,
} from '@/services/system/user';
import {
DeleteOutlined,
DownOutlined,
EditOutlined,
ExclamationCircleOutlined,
PlusOutlined,
} from '@ant-design/icons';
import {
ActionType,
FooterToolbar,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useAccess, useIntl } from '@umijs/max';
import {
Button,
Card,
Col,
Dropdown,
FormInstance,
Modal,
Row,
Space,
Switch,
message,
} from 'antd';
import { DataNode } from 'antd/es/tree';
import React, { useEffect, useRef, useState } from 'react';
import AuthRoleForm from './components/AuthRole';
import DeptTree from './components/DeptTree';
import ResetPwd from './components/ResetPwd';
import UpdateForm from './edit';

const { confirm } = Modal;

@@ -22,7 +53,7 @@ const { confirm } = Modal;
*
* @author whiteshader@163.com
* @datetime 2023/02/06
*
*
* */

/**
@@ -102,7 +133,7 @@ const handleRemoveOne = async (selectedRow: API.System.User) => {
/**
* 导出数据
*
*
*
*/
const handleExport = async () => {
const hide = message.loading('正在导出');
@@ -156,12 +187,12 @@ const UserTableList: React.FC = () => {
}, []);

const showChangeStatusConfirm = (record: API.System.User) => {
let text = record.status === "1" ? "启用" : "停用";
let text = record.status === '1' ? '启用' : '停用';
const newStatus = record.status === '0' ? '1' : '0';
confirm({
title: `确认要${text}${record.userName}用户吗?`,
onOk() {
changeUserStatus(record.userId, newStatus).then(resp => {
changeUserStatus(record.userId, newStatus).then((resp) => {
if (resp.code === 200) {
messageApi.open({
type: 'success',
@@ -178,7 +209,7 @@ const UserTableList: React.FC = () => {
},
});
};
const fetchUserInfo = async (userId: number) => {
const res = await getUser(userId);
setPostIds(res.postIds);
@@ -221,7 +252,7 @@ const UserTableList: React.FC = () => {
title: <FormattedMessage id="system.user.dept_name" defaultMessage="部门" />,
dataIndex: ['dept', 'deptName'],
valueType: 'text',
hideInSearch: true
hideInSearch: true,
},
{
title: <FormattedMessage id="system.user.phonenumber" defaultMessage="手机号码" />,
@@ -241,7 +272,8 @@ const UserTableList: React.FC = () => {
unCheckedChildren="停用"
defaultChecked
onClick={() => showChangeStatusConfirm(record)}
/>)
/>
);
},
},
{
@@ -297,7 +329,9 @@ const UserTableList: React.FC = () => {
menu={{
items: [
{
label: <FormattedMessage id="system.user.reset.password" defaultMessage="密码重置" />,
label: (
<FormattedMessage id="system.user.reset.password" defaultMessage="密码重置" />
),
key: 'reset',
disabled: !access.hasPerms('system:user:edit'),
},
@@ -311,13 +345,12 @@ const UserTableList: React.FC = () => {
if (key === 'reset') {
setResetPwdModalVisible(true);
setCurrentRow(record);
}
else if (key === 'authRole') {
} else if (key === 'authRole') {
fetchUserInfo(record.userId);
setAuthRoleModalVisible(true);
setCurrentRow(record);
}
}
},
}}
>
<a onClick={(e) => e.preventDefault()}>
@@ -369,7 +402,7 @@ const UserTableList: React.FC = () => {
const treeData = await getDeptTree({});
setDeptTree(treeData);

const postResp = await getPostList()
const postResp = await getPostList();
if (postResp.code === 200) {
setPostList(
postResp.rows.map((item: any) => {
@@ -381,7 +414,7 @@ const UserTableList: React.FC = () => {
);
}

const roleResp = await getRoleList()
const roleResp = await getRoleList();
if (roleResp.code === 200) {
setRoleList(
roleResp.rows.map((item: any) => {
@@ -396,7 +429,8 @@ const UserTableList: React.FC = () => {
setModalVisible(true);
}}
>
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
<PlusOutlined />{' '}
<FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
</Button>,
<Button
type="primary"
@@ -414,7 +448,7 @@ const UserTableList: React.FC = () => {
actionRef.current?.reloadAndRest?.();
}
},
onCancel() { },
onCancel() {},
});
}}
>
@@ -434,14 +468,16 @@ const UserTableList: React.FC = () => {
</Button>,
]}
request={(params) =>
getUserList({ ...params, deptId: selectDept.id } as API.System.UserListParams).then((res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
})
getUserList({ ...params, deptId: selectDept.id } as API.System.UserListParams).then(
(res) => {
const result = {
data: res.rows,
total: res.total,
success: true,
};
return result;
},
)
}
columns={columns}
rowSelection={{


+ 3
- 8
react-ui/src/pages/Tool/Gen/components/BaseInfo.tsx View File

@@ -1,8 +1,8 @@
import { ProForm, ProFormText, ProFormTextArea } from '@ant-design/pro-components';
import { history } from '@umijs/max';
import { Button, Col, Form, message, Row } from 'antd';
import React, { Fragment, useEffect } from 'react';
import { history } from '@umijs/max';
import styles from '../style.less';
import { ProForm, ProFormText, ProFormTextArea } from '@ant-design/pro-components';

export type BaseInfoProps = {
values?: any;
@@ -55,7 +55,6 @@ const BaseInfo: React.FC<BaseInfoProps> = (props) => {
<Row>
<Col span={12} order={1}>
<ProFormText

name="tableName"
label="表名称"
rules={[
@@ -67,16 +66,12 @@ const BaseInfo: React.FC<BaseInfoProps> = (props) => {
/>
</Col>
<Col span={12} order={2}>
<ProFormText
name="tableComment"
label="表描述"
/>
<ProFormText name="tableComment" label="表描述" />
</Col>
</Row>
<Row>
<Col span={12} order={1}>
<ProFormText

name="className"
label="实体类名称"
rules={[


+ 4
- 4
react-ui/src/pages/Tool/Gen/components/ColumnInfo.tsx View File

@@ -1,10 +1,10 @@
import { EditableProTable, ProColumns } from '@ant-design/pro-components';
import { history } from '@umijs/max';
import type { FormInstance } from 'antd';
import { Button, Checkbox, Col, Row, Tag } from 'antd';
import React, { Fragment, useEffect, useRef, useState } from 'react';
import type { GenCodeType } from '../data';
import { Button, Checkbox, Col, Row, Tag } from 'antd';
import type { FormInstance } from 'antd';
import { history } from '@umijs/max';
import styles from '../style.less';
import { EditableProTable, ProColumns } from '@ant-design/pro-components';

export type ColumnInfoProps = {
parentType?: string;


+ 4
- 8
react-ui/src/pages/Tool/Gen/components/GenInfo.tsx View File

@@ -1,10 +1,10 @@
import { ProForm, ProFormRadio, ProFormSelect, ProFormText } from '@ant-design/pro-components';
import { history } from '@umijs/max';
import { Button, Col, Divider, Form, Row, TreeSelect } from 'antd';
import { DataNode } from 'antd/es/tree';
import React, { Fragment, useEffect, useState } from 'react';
import { history } from '@umijs/max';
import type { TableInfo } from '../data';
import styles from '../style.less';
import { DataNode } from 'antd/es/tree';
import { ProForm, ProFormRadio, ProFormSelect, ProFormText } from '@ant-design/pro-components';

export type GenInfoProps = {
values?: any;
@@ -140,11 +140,7 @@ const GenInfo: React.FC<GenInfoProps> = (props) => {
<ProFormText name="functionName" label="生成功能名" />
</Col>
<Col span={12} order={2}>
<ProForm.Item
labelCol={{ span: 20 }}
name="parentMenuId"
label="父菜单"
>
<ProForm.Item labelCol={{ span: 20 }} name="parentMenuId" label="父菜单">
<TreeSelect
style={{ width: '74%' }}
defaultValue={props.values.parentMenuId}


+ 7
- 7
react-ui/src/pages/Tool/Gen/components/PreviewCode.tsx View File

@@ -1,9 +1,9 @@
import React, { useEffect } from 'react';
import { useIntl } from '@umijs/max';
import { Modal, Tabs } from 'antd';
import type { TabsProps } from 'antd';
import Highlight from 'react-highlight';
import { Modal, Tabs } from 'antd';
import 'highlight.js/styles/base16/material.css';
import React, { useEffect } from 'react';
import Highlight from 'react-highlight';

interface PreviewTableProps {
open: boolean;
@@ -17,10 +17,10 @@ const PreviewTableCode: React.FC<PreviewTableProps> = (props) => {
const keys = Object.keys(props.data);
keys.forEach((key) => {
panes.push({
key: key + '1',
label: key.substring(key.lastIndexOf('/') + 1, key.indexOf('.vm')),
children: <Highlight className="java">{props.data[key]}</Highlight>,
} as TabsProps);
key: key + '1',
label: key.substring(key.lastIndexOf('/') + 1, key.indexOf('.vm')),
children: <Highlight className="java">{props.data[key]}</Highlight>,
} as TabsProps);
});

useEffect(() => {}, []);


+ 22
- 18
react-ui/src/pages/Tool/Gen/edit.tsx View File

@@ -1,16 +1,16 @@
import { getDictTypeList } from '@/services/system/dict';
import { getMenuTree } from '@/services/system/menu';
import { formatTreeData } from '@/utils/tree';
import { useLocation } from '@umijs/max';
import { Card, Layout, Steps, message } from 'antd';
import queryString from 'query-string';
import React, { useEffect, useState } from 'react';
import BaseInfo from './components/BaseInfo';
import { Card, Layout, message, Steps } from 'antd';
import ColumnInfo from './components/ColumnInfo';
import GenInfo from './components/GenInfo';
import type { GenCodeType } from './data';
import { getGenCode, updateData } from './service';
import { formatTreeData } from '@/utils/tree';
import styles from './style.less';
import type { GenCodeType } from './data';
import { getMenuTree } from '@/services/system/menu';
import { getDictTypeList } from '@/services/system/dict';
import queryString from 'query-string';
import { useLocation } from '@umijs/max';

const { Content } = Layout;

@@ -163,17 +163,21 @@ const TableList: React.FC = () => {
return (
<Content>
<Card className={styles.tabsCard} bordered={false}>
<Steps current={currentStep} className={styles.steps} items={[
{
title: '基本信息',
},
{
title: '字段信息',
},
{
title: '生成信息',
},
]} />
<Steps
current={currentStep}
className={styles.steps}
items={[
{
title: '基本信息',
},
{
title: '字段信息',
},
{
title: '生成信息',
},
]}
/>
{stepComponent}
</Card>
</Content>


+ 5
- 5
react-ui/src/pages/Tool/Gen/import.tsx View File

@@ -1,10 +1,10 @@
import { Button, Card, message, Layout } from 'antd';
import { PlusOutlined, RollbackOutlined } from '@ant-design/icons';
import { ProColumns, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, history } from '@umijs/max';
import { Button, Card, Layout, message } from 'antd';
import React, { useState } from 'react';
import { history, FormattedMessage } from '@umijs/max';
import { importTables, queryTableList } from './service';
import type { GenCodeType } from './data.d';
import { ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, RollbackOutlined } from '@ant-design/icons';
import { importTables, queryTableList } from './service';

const { Content } = Layout;



+ 12
- 12
react-ui/src/pages/Tool/Gen/index.tsx View File

@@ -1,26 +1,26 @@
import { DownloadOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, message, Drawer, Modal, Card, Layout } from 'antd';
import {
ActionType,
FooterToolbar,
ProColumns,
ProDescriptions,
ProDescriptionsItemProps,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, history, useAccess } from '@umijs/max';
import type { FormInstance } from 'antd';
import React, { useState, useRef } from 'react';
import { history, FormattedMessage, useAccess } from '@umijs/max';
import { Button, Card, Drawer, Layout, Modal, message } from 'antd';
import React, { useRef, useState } from 'react';
import PreviewForm from './components/PreviewCode';
import type { GenCodeTableListParams, GenCodeType } from './data.d';
import {
batchGenCode,
genCode,
previewCode,
getGenCodeList,
previewCode,
removeData,
syncDbInfo,
} from './service';
import {
ActionType,
FooterToolbar,
ProColumns,
ProDescriptions,
ProDescriptionsItemProps,
ProTable,
} from '@ant-design/pro-components';

const { Content } = Layout;



+ 2
- 2
react-ui/src/pages/Tool/Gen/service.ts View File

@@ -1,6 +1,6 @@
import { request } from '@umijs/max';
import { downLoadZip } from '@/utils/downloadfile';
import type { GenCodeType, GenCodeTableListParams } from './data.d';
import { request } from '@umijs/max';
import type { GenCodeTableListParams, GenCodeType } from './data.d';

// 查询分页列表
export async function getGenCodeList(params?: GenCodeTableListParams) {


+ 3
- 4
react-ui/src/pages/User/Center/Center.less View File

@@ -1,11 +1,10 @@

.avatarHolder {
margin-bottom: 16px;
text-align: center;
position: relative;
display: inline-block;
height: 120px;
margin-bottom: 16px;
text-align: center;

& > img {
width: 120px;
height: 120px;


+ 9
- 9
react-ui/src/pages/User/Center/components/AvatarCropper/index.less View File

@@ -1,10 +1,10 @@
.avatarPreview {
position: absolute;
top: 50%;
transform: translate(50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
}
position: absolute;
top: 50%;
width: 200px;
height: 200px;
overflow: hidden;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
transform: translate(50%, -50%);
}

+ 7
- 7
react-ui/src/pages/User/Center/components/AvatarCropper/index.tsx View File

@@ -1,10 +1,4 @@
import React, { useEffect, useRef, useState } from 'react';
import { Modal, Row, Col, Button, Space, Upload, message } from 'antd';
import { useIntl } from '@umijs/max';
import { uploadAvatar } from '@/services/system/user';
import { Cropper } from 'react-cropper';
import './cropper.css';
import styles from './index.less';
import {
MinusOutlined,
PlusOutlined,
@@ -12,6 +6,12 @@ import {
UndoOutlined,
UploadOutlined,
} from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Button, Col, Modal, Row, Space, Upload, message } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import { Cropper } from 'react-cropper';
import './cropper.css';
import styles from './index.less';

/* *
*
@@ -44,7 +44,7 @@ const AvatarCropperForm: React.FC<AvatarCropperProps> = (props) => {
formData.append('avatarfile', blob);
uploadAvatar(formData).then((res) => {
if (res.code === 200) {
message.success(res.msg);
message.success(res.msg);
props.onFinished(true);
} else {
message.warning(res.msg);


+ 4
- 5
react-ui/src/pages/User/Center/components/BaseInfo/index.tsx View File

@@ -1,9 +1,8 @@
import React from 'react';
import { Form, message, Row } from 'antd';
import { FormattedMessage, useIntl } from '@umijs/max';
import { ProForm, ProFormRadio, ProFormText } from '@ant-design/pro-components';
import { updateUserProfile } from '@/services/system/user';

import { ProForm, ProFormRadio, ProFormText } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, message, Row } from 'antd';
import React from 'react';

export type BaseInfoProps = {
values: Partial<API.CurrentUser> | undefined;


+ 50
- 52
react-ui/src/pages/User/Center/components/ResetPassword/index.tsx View File

@@ -1,8 +1,8 @@
import React from 'react';
import { Form, message } from 'antd';
import { FormattedMessage, useIntl } from '@umijs/max';
import { updateUserPwd } from '@/services/system/user';
import { ProForm, ProFormText } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, message } from 'antd';
import React from 'react';

const ResetPassword: React.FC = () => {
const [form] = Form.useForm();
@@ -27,55 +27,53 @@ const ResetPassword: React.FC = () => {

return (
<>
<ProForm form={form} onFinish={handleFinish}>
<ProFormText.Password
name="oldPassword"
label={intl.formatMessage({
id: 'system.user.old_password',
defaultMessage: '旧密码',
})}
width="xl"
placeholder="请输入旧密码"
rules={[
{
required: true,
message: <FormattedMessage id="请输入旧密码!" defaultMessage="请输入旧密码!" />,
},
]}
/>
<ProFormText.Password
name="newPassword"
label={intl.formatMessage({
id: 'system.user.new_password',
defaultMessage: '新密码',
})}
width="xl"
placeholder="请输入新密码"
rules={[
{
required: true,
message: <FormattedMessage id="请输入新密码!" defaultMessage="请输入新密码!" />,
},
]}
/>
<ProFormText.Password
name="confirmPassword"
label={intl.formatMessage({
id: 'system.user.confirm_password',
defaultMessage: '确认密码',
})}
width="xl"
placeholder="请输入确认密码"
rules={[
{
required: true,
message: (
<FormattedMessage id="请输入确认密码!" defaultMessage="请输入确认密码!" />
),
},
{ validator: checkPassword },
]}
/>
<ProForm form={form} onFinish={handleFinish}>
<ProFormText.Password
name="oldPassword"
label={intl.formatMessage({
id: 'system.user.old_password',
defaultMessage: '旧密码',
})}
width="xl"
placeholder="请输入旧密码"
rules={[
{
required: true,
message: <FormattedMessage id="请输入旧密码!" defaultMessage="请输入旧密码!" />,
},
]}
/>
<ProFormText.Password
name="newPassword"
label={intl.formatMessage({
id: 'system.user.new_password',
defaultMessage: '新密码',
})}
width="xl"
placeholder="请输入新密码"
rules={[
{
required: true,
message: <FormattedMessage id="请输入新密码!" defaultMessage="请输入新密码!" />,
},
]}
/>
<ProFormText.Password
name="confirmPassword"
label={intl.formatMessage({
id: 'system.user.confirm_password',
defaultMessage: '确认密码',
})}
width="xl"
placeholder="请输入确认密码"
rules={[
{
required: true,
message: <FormattedMessage id="请输入确认密码!" defaultMessage="请输入确认密码!" />,
},
{ validator: checkPassword },
]}
/>
</ProForm>
</>
);


+ 296
- 277
react-ui/src/pages/User/Login/index.tsx View File

@@ -1,6 +1,6 @@
import Footer from '@/components/Footer';
import { getCaptchaImg, login } from '@/services/system/auth';
import { clearSessionToken, setSessionToken } from '@/access';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import { getCaptchaImg, login } from '@/services/system/auth';
import {
AlipayCircleOutlined,
LockOutlined,
@@ -16,13 +16,11 @@ import {
ProFormText,
} from '@ant-design/pro-components';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import styles from './login.less';
import { FormattedMessage, history, SelectLang, useIntl, useModel, Helmet } from '@umijs/max';
import { Alert, Col, message, Row, Tabs, Image } from 'antd';
import Settings from '../../../../config/defaultSettings';
import { FormattedMessage, SelectLang, history, useIntl, useModel } from '@umijs/max';
import { Alert, Col, Image, Row, message } from 'antd';
import React, { useEffect, useState } from 'react';
import { flushSync } from 'react-dom';
import { clearSessionToken, setSessionToken } from '@/access';
import styles from './login.less';

const ActionIcons = () => {
const langClassName = useEmotionCss(({ token }) => {
@@ -86,7 +84,7 @@ const LoginMessage: React.FC<{
};

const Login: React.FC = () => {
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({code: 200});
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({ code: 200 });
const [type, setType] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const [captchaCode, setCaptchaCode] = useState<string>('');
@@ -96,86 +94,85 @@ const Login: React.FC = () => {
return {
display: 'flex',
height: '100vh',
backgroundColor:"#fff",
backgroundColor: '#fff',
backgroundSize: '100% 100%',
};
});
const containerLeftBox= useEmotionCss(() => {
const containerLeftBox = useEmotionCss(() => {
return {
background:'linear-gradient(180deg,#e2ecff 0%,#f6fafe 100%)',
width:'43%',
height:'100%',
position:'relative'
background: 'linear-gradient(180deg,#e2ecff 0%,#f6fafe 100%)',
width: '43%',
height: '100%',
position: 'relative',
};
});
const leftTopBoX= useEmotionCss(() => {
const leftTopBoX = useEmotionCss(() => {
return {
display:'flex',
position:'absolute',
display: 'flex',
position: 'absolute',
top: '55px',
left: '60px',
fontWeight:'500',
color:'#1d1d20',
fontSize:'36px',
fontWeight: '500',
color: '#1d1d20',
fontSize: '36px',
fontFamily: 'Alibaba',
};
});
const centerTitleBoX= useEmotionCss(() => {
const centerTitleBoX = useEmotionCss(() => {
return {
display:'flex',
position:'absolute',
display: 'flex',
position: 'absolute',
top: '163px',
left: '50%',
transform:'translateX(-50%)',
fontWeight:'500',
color:'#111111',
fontSize:'45px',
fontFamily: 'Alibaba'
transform: 'translateX(-50%)',
fontWeight: '500',
color: '#111111',
fontSize: '45px',
fontFamily: 'Alibaba',
};
});
const centerMessage=useEmotionCss(() => {
const centerMessage = useEmotionCss(() => {
return {
display:'flex',
position:'absolute',
display: 'flex',
position: 'absolute',
top: '242px',
left: '50%',
transform:'translateX(-50%)',
fontWeight:'500',
color:'#606b7a',
fontSize:'26px',
transform: 'translateX(-50%)',
fontWeight: '500',
color: '#606b7a',
fontSize: '26px',
fontFamily: 'Alibaba',
letterSpacing:'8px'
letterSpacing: '8px',
};
});
const containerRightBox = useEmotionCss(() => {
return {
background:'#fff',
width:'57%',
height:'100%',
position:'relative'
background: '#fff',
width: '57%',
height: '100%',
position: 'relative',
};
});
const rightTopTitle =useEmotionCss(() => {
const rightTopTitle = useEmotionCss(() => {
return {
display:'flex',
position:'absolute',
alignItems:'center',
display: 'flex',
position: 'absolute',
alignItems: 'center',
top: '147px',
left: '230px',
fontFamily: 'Alibaba',
};
});
const containerLoginForm=useEmotionCss(() => {
const containerLoginForm = useEmotionCss(() => {
return {
width:'640px',
position:'absolute',
background:'#ffffff',
borderRadius:'10px',
boxShadow:'0px 3px 20px rgba(153, 153, 153, 0.16)',
padding:'62px 36px 45px 36px',
left:'230px',
top:'220px'
width: '640px',
position: 'absolute',
background: '#ffffff',
borderRadius: '10px',
boxShadow: '0px 3px 20px rgba(153, 153, 153, 0.16)',
padding: '62px 36px 45px 36px',
left: '230px',
top: '220px',
};
});
const intl = useIntl();
@@ -244,243 +241,265 @@ const Login: React.FC = () => {
<div className={containerClassName}>
<div className={containerLeftBox}>
<div className={leftTopBoX}>
<img src="/assets/images/left-top-logo.png" style={{height:'42px',marginRight:'10px'}} alt="" />
复杂智能软件
<img
src="/assets/images/left-top-logo.png"
style={{ height: '42px', marginRight: '10px' }}
alt=""
/>
复杂智能软件
</div>
<div className={centerTitleBoX}>
<span style={{whiteSpace:'nowrap'}}>复杂智能软件</span>
<img src="/assets/images/ai-logo.png" style={{height:'47px',marginTop:'-10px'}} alt="" />
<span style={{ whiteSpace: 'nowrap' }}>复杂智能软件</span>

<img
src="/assets/images/ai-logo.png"
style={{ height: '47px', marginTop: '-10px' }}
alt=""
/>
</div>
<div className={centerMessage}>
<span style={{whiteSpace:'nowrap'}}>大语言模型运维 统一管理平台</span>
<span style={{ whiteSpace: 'nowrap' }}>大语言模型运维 统一管理平台</span>
</div>
<img src="/assets/images/left-back-logo.png" style={{width:'90%',position:'absolute',top:'326px',left: '50%',
transform:'translateX(-50%)',}} alt="" />
<img
src="/assets/images/left-back-logo.png"
style={{
width: '90%',
position: 'absolute',
top: '326px',
left: '50%',
transform: 'translateX(-50%)',
}}
alt=""
/>
</div>
<div className={containerRightBox}>
<div className={rightTopTitle}>
<span style={{color:'#111111',fontSize:'36px'}}>hello~</span>
<span style={{color:'#606b7a',fontSize:'32px',marginLeft:'10px'}}>欢迎登陆</span>
<span style={{color:'#1664ff',fontSize:'32px'}}>复杂智能软件</span>
<span style={{ color: '#111111', fontSize: '36px' }}>hello~</span>
<span style={{ color: '#606b7a', fontSize: '32px', marginLeft: '10px' }}>欢迎登陆</span>
<span style={{ color: '#1664ff', fontSize: '32px' }}>复杂智能软件</span>
</div>
<div className={containerLoginForm}>
<div style={{color:'#1d1d20',fontSize:'22px',marginLeft:'30px',fontFamily: 'Alibaba',}}>账号登录</div>
<LoginForm
title=""
className={styles.loginForm}
initialValues={{
autoLogin: true,
}}
// actions={[
// <FormattedMessage
// key="loginWith"
// id="pages.login.loginWith"
// defaultMessage="其他登录方式"
// />,
// <ActionIcons key="icons" />,
// ]}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>


{code !== 200 && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: '账户或密码错误(admin/admin123)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="username"
initialValue="admin"
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
defaultMessage: '用户名: admin',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.username.required"
defaultMessage="请输入用户名!"
/>
),
},
]}
/>
<ProFormText.Password
name="password"
initialValue="admin123"
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: '密码: admin123',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.password.required"
defaultMessage="请输入密码!"
/>
),
},
]}
/>
<Row>
<Col flex={4}>
<ProFormText
style={{
float: 'right',
}}
name="code"
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules"
defaultMessage="请输入验证啊"
/>
),
},
]}
/>
</Col>
<Col >
<Image
src={captchaCode}
alt="验证码"
style={{
display: 'inline-block',
verticalAlign: 'top',
cursor: 'pointer',
paddingLeft: '22px',
width: '170px',
height:'66px'
}}
preview={false}
onClick={() => getCaptchaCode()}
/>
</Col>
</Row>
</>
)}

{code !== 200 && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: '手机号',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="请输入手机号!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="手机号格式错误!"
/>
),
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证码',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: '获取验证码',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: '获取验证码',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
onGetCaptcha={async (phone) => {
const result = await getFakeCaptcha({
phone,
});
if (!result) {
return;
}
message.success('获取验证码成功!验证码为:1234');
}}
/>
</>
)}
<div className={containerLoginForm}>
<div
style={{
marginBottom: 24,
color: '#1d1d20',
fontSize: '22px',
marginLeft: '30px',
fontFamily: 'Alibaba',
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="记住密码" />
</ProFormCheckbox>
账号登录
</div>
</LoginForm>
</div>
<LoginForm
title=""
className={styles.loginForm}
initialValues={{
autoLogin: true,
}}
// actions={[
// <FormattedMessage
// key="loginWith"
// id="pages.login.loginWith"
// defaultMessage="其他登录方式"
// />,
// <ActionIcons key="icons" />,
// ]}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
{code !== 200 && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: '账户或密码错误(admin/admin123)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="username"
initialValue="admin"
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
defaultMessage: '用户名: admin',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.username.required"
defaultMessage="请输入用户名!"
/>
),
},
]}
/>
<ProFormText.Password
name="password"
initialValue="admin123"
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: '密码: admin123',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.password.required"
defaultMessage="请输入密码!"
/>
),
},
]}
/>
<Row>
<Col flex={4}>
<ProFormText
style={{
float: 'right',
}}
name="code"
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules"
defaultMessage="请输入验证啊"
/>
),
},
]}
/>
</Col>
<Col>
<Image
src={captchaCode}
alt="验证码"
style={{
display: 'inline-block',
verticalAlign: 'top',
cursor: 'pointer',
paddingLeft: '22px',
width: '170px',
height: '66px',
}}
preview={false}
onClick={() => getCaptchaCode()}
/>
</Col>
</Row>
</>
)}

{code !== 200 && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: '手机号',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="请输入手机号!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="手机号格式错误!"
/>
),
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证码',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: '获取验证码',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: '获取验证码',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
onGetCaptcha={async (phone) => {
const result = await getFakeCaptcha({
phone,
});
if (!result) {
return;
}
message.success('获取验证码成功!验证码为:1234');
}}
/>
</>
)}
<div
style={{
marginBottom: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="记住密码" />
</ProFormCheckbox>
</div>
</LoginForm>
</div>
</div>
{/* <Helmet>
<title>


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save