diff --git a/config/config.ts b/config/config.ts index 6b51745c..e93cb0b9 100644 --- a/config/config.ts +++ b/config/config.ts @@ -14,7 +14,7 @@ const isProduction = env === 'production'; const t = Date.now(); export default defineConfig({ proxy: { - ...proxy() + ...proxy('http://csvhs44p420c73bdb41g-80.agent.damodel.com') }, history: { type: 'hash' diff --git a/package.json b/package.json index a07278d5..33509151 100644 --- a/package.json +++ b/package.json @@ -54,11 +54,11 @@ "query-string": "^9.0.0", "rc-resize-observer": "^1.4.0", "rc-virtual-list": "^3.14.8", + "re-resizable": "^6.10.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hotkeys-hook": "^4.5.0", "simplebar-react": "^3.2.6", - "umap-js": "^1.4.0", "umi-presets-pro": "^2.0.3", "wavesurfer.js": "^7.8.8", "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c949ffa9..9057ed3f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -125,6 +125,9 @@ dependencies: rc-virtual-list: specifier: ^3.14.8 version: 3.14.8(react-dom@18.2.0)(react@18.2.0) + re-resizable: + specifier: ^6.10.1 + version: 6.10.1(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -137,9 +140,6 @@ dependencies: simplebar-react: specifier: ^3.2.6 version: 3.2.6(react@18.2.0) - umap-js: - specifier: ^1.4.0 - version: 1.4.0 umi-presets-pro: specifier: ^2.0.3 version: 2.0.3(@babel/core@7.25.7)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.21.6)(dva@2.5.0-beta.2)(rc-field-form@2.4.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.24) @@ -11643,10 +11643,6 @@ packages: is-decimal: 1.0.4 dev: false - /is-any-array@0.1.1: - resolution: {integrity: sha512-qTiELO+kpTKqPgxPYbshMERlzaFu29JDnpB8s3bjg+JkxBpw29/qqSaOdKv2pCdaG92rLGeG/zG2GauX58hfoA==, tarball: https://registry.npmjs.org/is-any-array/-/is-any-array-0.1.1.tgz} - dev: false - /is-any-array@2.0.1: resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==, tarball: https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz} dev: false @@ -12983,13 +12979,6 @@ packages: resolution: {integrity: sha512-7GO+Xk382d+HhVgjebaQnJ4Tcm8+uaL9Mc76UdxhBAU0aFWs6JDjINZLnrlZ0KDiIi9Erc52bD26QOvYsG7Nnw==, tarball: https://registry.npmjs.org/ml-dataset-iris/-/ml-dataset-iris-1.2.1.tgz} dev: false - /ml-levenberg-marquardt@2.1.1: - resolution: {integrity: sha512-2+HwUqew4qFFFYujYlQtmFUrxCB4iJAPqnUYro3P831wj70eJZcANwcRaIMGUVaH9NDKzfYuA4N5u67KExmaRA==, tarball: https://registry.npmjs.org/ml-levenberg-marquardt/-/ml-levenberg-marquardt-2.1.1.tgz} - dependencies: - is-any-array: 0.1.1 - ml-matrix: 6.12.0 - dev: false - /ml-matrix@6.12.0: resolution: {integrity: sha512-AGfR+pWaC0GmzjUnB6BfwhndPEUGz0i7QUYdqNuw1zhTov/vSRJ9pP2hs6BoGpaSbtXgrKjZz2zjD1M0xuur6A==, tarball: https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.12.0.tgz} dependencies: @@ -16147,6 +16136,16 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /re-resizable@6.10.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-m33nSWRH57UZLmep5M/LatkZ2NRqimVD/bOOpvymw5Zf33+eTSEixsUugscOZzAtK0/nx+OSuOf8VbKJx/4ptw==, tarball: https://registry.npmjs.org/re-resizable/-/re-resizable-6.10.1.tgz} + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-dom@18.1.0(react@18.1.0): resolution: {integrity: sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w==, tarball: https://registry.npmjs.org/react-dom/-/react-dom-18.1.0.tgz} peerDependencies: @@ -18462,12 +18461,6 @@ packages: resolution: {integrity: sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==, tarball: https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.38.tgz} dev: false - /umap-js@1.4.0: - resolution: {integrity: sha512-xxpviF9wUO6Nxrx+C58SoDgea+h2PnVaRPKDelWv0HotmY6BeWeh0kAPJoumfqUkzUvowGsYfMbnsWI0b9do+A==, tarball: https://registry.npmjs.org/umap-js/-/umap-js-1.4.0.tgz} - dependencies: - ml-levenberg-marquardt: 2.1.1 - dev: false - /umi-presets-pro@2.0.3(@babel/core@7.25.7)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.21.6)(dva@2.5.0-beta.2)(rc-field-form@2.4.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.24): resolution: {integrity: sha512-sHKynw/fi7UeUftzTRPRsrV5GHV4BWvWYhyvwkg8s+shmt0ROPW/52y4gxBziEvetxl8yWMKUCWk50OUDOcrww==, tarball: https://registry.npmjs.org/umi-presets-pro/-/umi-presets-pro-2.0.3.tgz} dependencies: diff --git a/src/assets/images/img_fallback.png b/src/assets/images/img_fallback.png new file mode 100644 index 00000000..d3cbad03 Binary files /dev/null and b/src/assets/images/img_fallback.png differ diff --git a/src/assets/styles/common.less b/src/assets/styles/common.less index 9011d77b..12d2f01a 100644 --- a/src/assets/styles/common.less +++ b/src/assets/styles/common.less @@ -89,6 +89,16 @@ justify-content: center; } +.justify-start { + display: flex; + justify-content: flex-start; +} + +.justify-end { + display: flex; + justify-content: flex-end; +} + // align-items: center .flex-center { display: flex; @@ -170,6 +180,10 @@ font-size: 24px; } +.font-size-32 { + font-size: 32px; +} + .m-b-0 { margin-bottom: 0; } diff --git a/src/components/alert-info/index.tsx b/src/components/alert-info/index.tsx new file mode 100644 index 00000000..0ae4646f --- /dev/null +++ b/src/components/alert-info/index.tsx @@ -0,0 +1,39 @@ +import { WarningOutlined } from '@ant-design/icons'; +import { Typography } from 'antd'; +import React from 'react'; + +interface AlertInfoProps { + type: 'danger' | 'warning'; + message: string; + rows?: number; + icon?: React.ReactNode; +} + +const AlertInfo: React.FC = (props) => { + const { message, type, rows = 1 } = props; + if (!message) { + return null; + } + + return ( + + + {message} + + ); +}; + +export default React.memo(AlertInfo); diff --git a/src/components/audio-player/index.tsx b/src/components/audio-player/index.tsx index 8127c011..75a948b5 100644 --- a/src/components/audio-player/index.tsx +++ b/src/components/audio-player/index.tsx @@ -61,7 +61,7 @@ const AudioPlayer: React.FC = forwardRef((props, ref) => { setPlayOn(false); setAudioState((prestate: any) => { return { - currentTime: 0, + currentTime: audioRef.current?.ended ? 0 : prestate.currentTime, duration: prestate.duration }; }); @@ -87,6 +87,7 @@ const AudioPlayer: React.FC = forwardRef((props, ref) => { const handleLoadedMetadata = useCallback( (data: any) => { + console.log('loadmetadata++++++++'); const duration = Math.ceil(audioRef.current?.duration || 0); setAudioState({ currentTime: 0, diff --git a/src/components/auto-image/index.tsx b/src/components/auto-image/index.tsx index 059d7848..7f564ebf 100644 --- a/src/components/auto-image/index.tsx +++ b/src/components/auto-image/index.tsx @@ -1,3 +1,4 @@ +import fallbackImg from '@/assets/images/img_fallback.png'; import { DownloadOutlined, EyeOutlined, @@ -13,9 +14,16 @@ import { round } from 'lodash'; import React, { useCallback, useEffect, useState } from 'react'; import './index.less'; -const AutoImage: React.FC = (props) => { - const { height = 100, ...rest } = props; - const [width, setWidth] = useState(0); +const AutoImage: React.FC< + ImageProps & { + height: number | string; + width?: number | string; + autoSize?: boolean; + } +> = (props) => { + const { height = 100, width: w, autoSize, ...rest } = props; + const [width, setWidth] = useState(w || 0); + const [isError, setIsError] = useState(false); const getImgRatio = useCallback((url: string): Promise<{ ratio: number }> => { return new Promise((resolve) => { @@ -31,8 +39,15 @@ const AutoImage: React.FC = (props) => { }, []); const handleOnLoad = useCallback(async () => { + if (autoSize) { + return; + } const { ratio } = await getImgRatio(props.src || ''); - setWidth(height * ratio); + if (typeof height === 'number') { + setWidth(height * ratio); + } else { + throw new Error('Height must be a number'); + } }, [getImgRatio, height, props.src]); const onDownload = () => { @@ -47,6 +62,10 @@ const AutoImage: React.FC = (props) => { link.remove(); }; + const handleOnError = () => { + setIsError(true); + }; + useEffect(() => { handleOnLoad(); }, [handleOnLoad]); @@ -54,8 +73,10 @@ const AutoImage: React.FC = (props) => { return ( , toolbarRender: ( diff --git a/src/components/echarts/index.ts b/src/components/echarts/index.ts index cf15aa39..9c0aea2e 100644 --- a/src/components/echarts/index.ts +++ b/src/components/echarts/index.ts @@ -12,6 +12,7 @@ import type { TooltipComponentOption } from 'echarts/components'; import { + DataZoomComponent, DatasetComponent, GridComponent, LegendComponent, @@ -44,6 +45,7 @@ echarts.use([ GridComponent, DatasetComponent, TransformComponent, + DataZoomComponent, BarChart, LineChart, ScatterChart, diff --git a/src/components/echarts/scatter.tsx b/src/components/echarts/scatter.tsx index 33e19afa..774fe767 100644 --- a/src/components/echarts/scatter.tsx +++ b/src/components/echarts/scatter.tsx @@ -17,35 +17,47 @@ const options: any = { borderRadius: 4 }, xAxis: { + min: -1, + max: 1, scale: false, slient: true, splitNumber: 15, splitLine: { lineStyle: { - color: 'rgba(5,5,5,0.06)' + color: '#F2F2F2' } }, axisLine: { - show: false + show: false, + lineStyle: { + color: '#F2F2F2' + } }, axisTick: { show: false }, axisLabel: { show: false - } + }, + boundaryGap: [0.05, 0.05] }, yAxis: { + min: -1, + max: 1, scale: false, slient: true, splitNumber: 10, + boundaryGap: [0.05, 0.05], splitLine: { lineStyle: { - color: 'rgba(5,5,5,0.06)' + color: '#F2F2F2' } }, axisLine: { - show: false + show: false, + lineStyle: { + color: '#F2F2F2' + } }, axisTick: { show: false @@ -54,6 +66,7 @@ const options: any = { show: false } }, + symbol: 'roundRect', label: { show: true, @@ -67,16 +80,7 @@ const options: any = { }; const Scatter: React.FC = (props) => { - const { - seriesData, - xAxisData, - height, - width, - showEmpty, - labelFormatter, - legendData, - title - } = props; + const { seriesData, xAxisData, height, width, showEmpty, title } = props; const chart = useRef(null); @@ -118,18 +122,21 @@ const Scatter: React.FC = (props) => { [] ); - const dataOptions = useMemo((): any => { - if (!seriesData.length) { - options.xAxis.min = 0; - options.xAxis.max = 1; - options.yAxis.min = 0; - options.yAxis.max = 1; - } else { - options.xAxis.min = null; - options.xAxis.max = null; - options.yAxis.min = null; - options.yAxis.max = null; + const renderNameInTooltip = useCallback((dataList: any[]) => { + if (!dataList.length || dataList.length < 2) { + return null; } + const renderText = (item: any) => { + return ` + ${item.name} + `; + }; + return renderText; + }, []); + const dataOptions = useMemo((): any => { const seriseDataList = seriesData.map((item: any, index: number) => { return { ...item, @@ -147,15 +154,11 @@ const Scatter: React.FC = (props) => { formatter(params: any, callback?: (val: any) => any) { const dataList = findOverlappingPoints(seriseDataList, params.data); let result = ''; + const renderText: any = renderNameInTooltip(dataList); dataList.forEach((item: any) => { result += ` - - ${item.name} - + ${renderText ? renderText(item) : ''} ${item.text} `; }); @@ -168,6 +171,9 @@ const Scatter: React.FC = (props) => { }, series: { type: 'scatter', + labelLayout: { + hideOverlap: true + }, data: seriseDataList } }; diff --git a/src/components/highlight-code/code-viewer-dark.tsx b/src/components/highlight-code/code-viewer-dark.tsx index d040b09b..65ee712d 100644 --- a/src/components/highlight-code/code-viewer-dark.tsx +++ b/src/components/highlight-code/code-viewer-dark.tsx @@ -9,6 +9,7 @@ interface CodeViewerProps { ignoreIllegals?: boolean; copyable?: boolean; height?: string | number; + style?: React.CSSProperties; } const DarkViewer: React.FC = (props) => { const { @@ -22,6 +23,7 @@ const DarkViewer: React.FC = (props) => { return ( = (props) => { const { @@ -17,11 +18,13 @@ const LightViewer: React.FC = (props) => { autodetect, ignoreIllegals, copyable, + style, height = 'auto' } = props || {}; return ( = (props) => { const { @@ -20,7 +21,8 @@ const CodeViewer: React.FC = (props) => { autodetect = true, ignoreIllegals = true, copyable = true, - height = 'auto' + height = 'auto', + style } = props || {}; const highlightedCode = useMemo(() => { @@ -69,7 +71,8 @@ const CodeViewer: React.FC = (props) => { } )} style={{ - height: height + height: height, + ...style }} > = (props) => { const { + style, code, lang = 'bash', copyable = true, @@ -26,9 +28,11 @@ const HighlightCode: React.FC<{ code={code} copyable={copyable} height={height} + style={style} /> ) : ( = ( description={description} disabled={props.disabled} onClick={handleClickWrapper} + className="seal-input-number" > void; } const RowTextarea: React.FC = (props) => { - const { value, onChange, style, label, placeholder } = props; + const { value, onChange, style, label, placeholder, height = 46 } = props; const intl = useIntl(); const rowTextAreaRef = React.useRef(null); const [autoSize, setAutoSize] = useState<{ @@ -64,7 +65,7 @@ const RowTextarea: React.FC = (props) => { style={{ display: autoSize.focus ? 'block' : 'none' }} className="textarea-wrapper" > - {label} + {label && {label}} = (props) => { } {!autoSize.focus && (
-
- {label} +
+ {label && {label}} {value || ( {placeholder} diff --git a/src/components/seal-form/seal-select.tsx b/src/components/seal-form/seal-select.tsx index f88c1006..be2faf39 100644 --- a/src/components/seal-form/seal-select.tsx +++ b/src/components/seal-form/seal-select.tsx @@ -1,7 +1,9 @@ import { isNotEmptyValue } from '@/utils/index'; +import { useIntl } from '@umijs/max'; import type { SelectProps } from 'antd'; import { Form, Select } from 'antd'; -import { useEffect, useRef, useState } from 'react'; +import { cloneDeep } from 'lodash'; +import { useEffect, useMemo, useRef, useState } from 'react'; import Wrapper from './components/wrapper'; import { SealFormItemProps } from './types'; @@ -12,9 +14,11 @@ const SealSelect: React.FC = (props) => { children, required, description, + options, isInFormItems = true, ...rest } = props; + const intl = useIntl(); const [isFocus, setIsFocus] = useState(false); const inputRef = useRef(null); let status = ''; @@ -23,6 +27,19 @@ const SealSelect: React.FC = (props) => { status = statusData?.status || ''; } + const _options = useMemo(() => { + if (!options?.length) { + return []; + } + const list = cloneDeep(options); + return list.map((item: any) => { + if (item.locale) { + item.label = intl.formatMessage({ id: item.label as string }); + } + return item; + }); + }, [options, intl]); + useEffect(() => { if (isNotEmptyValue(props.value)) { setIsFocus(true); @@ -70,6 +87,7 @@ const SealSelect: React.FC = (props) => {