Browse Source
- Remove src/services/swagger (unused API services) - Remove src/pages/list/table-list (routing points to different path) - Remove src/pages/form/step-form/service.ts (pure frontend form) - Remove src/pages/form/advanced-form/components/TableForm.tsx - Remove src/pages/account/settings/components/PhoneView.tsx - Remove src/pages/dashboard/analysis/components/Charts/MiniProgress - Remove WaterWave and autoHeight components (unused) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>pull/11631/head
14 changed files with 0 additions and 1364 deletions
@ -1,39 +0,0 @@ |
|||
import { Input } from 'antd'; |
|||
import React from 'react'; |
|||
import useStyles from './index.style'; |
|||
|
|||
type PhoneViewProps = { |
|||
value?: string; |
|||
onChange?: (value: string) => void; |
|||
}; |
|||
const PhoneView: React.FC<PhoneViewProps> = (props) => { |
|||
const { styles } = useStyles(); |
|||
const { value, onChange } = props; |
|||
let values = ['', '']; |
|||
if (value) { |
|||
values = value.split('-'); |
|||
} |
|||
return ( |
|||
<> |
|||
<Input |
|||
className={styles.area_code} |
|||
value={values[0]} |
|||
onChange={(e) => { |
|||
if (onChange) { |
|||
onChange(`${e.target.value}-${values[1]}`); |
|||
} |
|||
}} |
|||
/> |
|||
<Input |
|||
className={styles.phone_number} |
|||
onChange={(e) => { |
|||
if (onChange) { |
|||
onChange(`${values[0]}-${e.target.value}`); |
|||
} |
|||
}} |
|||
value={values[1]} |
|||
/> |
|||
</> |
|||
); |
|||
}; |
|||
export default PhoneView; |
|||
@ -1,48 +0,0 @@ |
|||
import { Tooltip } from 'antd'; |
|||
import React from 'react'; |
|||
export type MiniProgressProps = { |
|||
target: number; |
|||
targetLabel?: string; |
|||
color?: string; |
|||
size?: number; |
|||
percent?: number; |
|||
style?: React.CSSProperties; |
|||
}; |
|||
const MiniProgress: React.FC<MiniProgressProps> = ({ |
|||
targetLabel, |
|||
target, |
|||
color = 'rgb(19, 194, 194)', |
|||
size, |
|||
percent, |
|||
}) => { |
|||
return ( |
|||
<div> |
|||
<Tooltip title={targetLabel}> |
|||
<div |
|||
style={{ |
|||
left: target ? `${target}%` : undefined, |
|||
}} |
|||
> |
|||
<span |
|||
style={{ |
|||
backgroundColor: color || undefined, |
|||
}} |
|||
/> |
|||
<span |
|||
style={{ |
|||
backgroundColor: color || undefined, |
|||
}} |
|||
/> |
|||
</div> |
|||
</Tooltip> |
|||
<div |
|||
style={{ |
|||
backgroundColor: color || undefined, |
|||
width: percent ? `${percent}%` : undefined, |
|||
height: size || undefined, |
|||
}} |
|||
/> |
|||
</div> |
|||
); |
|||
}; |
|||
export default MiniProgress; |
|||
@ -1,215 +0,0 @@ |
|||
import { useEffect, useRef, useState } from 'react'; |
|||
import autoHeight from '../../../../monitor/components/Charts/autoHeight'; |
|||
|
|||
/* eslint no-return-assign: 0 */ |
|||
/* eslint no-mixed-operators: 0 */ |
|||
// riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90
|
|||
|
|||
export type WaterWaveProps = { |
|||
title: React.ReactNode; |
|||
color?: string; |
|||
height?: number; |
|||
percent: number; |
|||
style?: React.CSSProperties; |
|||
}; |
|||
|
|||
const WaterWave: React.FC<WaterWaveProps> = ({ |
|||
title, |
|||
color = '#1890FF', |
|||
height = 1, |
|||
percent, |
|||
}) => { |
|||
const [radio, setRadio] = useState(1); |
|||
const timerRef = useRef<number>(0); |
|||
const rootRef = useRef<HTMLDivElement>(null); |
|||
const nodeRef = useRef<HTMLCanvasElement>(null); |
|||
|
|||
const renderChart = (type?: string) => { |
|||
const data = percent / 100; |
|||
cancelAnimationFrame(timerRef.current); |
|||
if (!nodeRef.current || (data !== 0 && !data)) { |
|||
return; |
|||
} |
|||
const canvas = nodeRef.current; |
|||
const ctx = canvas.getContext('2d'); |
|||
if (!ctx) { |
|||
return; |
|||
} |
|||
const canvasWidth = canvas.width; |
|||
const canvasHeight = canvas.height; |
|||
const radius = canvasWidth / 2; |
|||
const lineWidth = 2; |
|||
const cR = radius - lineWidth; |
|||
ctx.beginPath(); |
|||
ctx.lineWidth = lineWidth * 2; |
|||
const axisLength = canvasWidth - lineWidth; |
|||
const unit = axisLength / 8; |
|||
const range = 0.2; // 振幅
|
|||
let currRange = range; |
|||
const xOffset = lineWidth; |
|||
let sp = 0; // 周期偏移量
|
|||
let currData = 0; |
|||
const waveupsp = 0.005; // 水波上涨速度
|
|||
|
|||
let arcStack: number[][] = []; |
|||
const bR = radius - lineWidth; |
|||
const circleOffset = -(Math.PI / 2); |
|||
let circleLock = true; |
|||
for ( |
|||
let i = circleOffset; |
|||
i < circleOffset + 2 * Math.PI; |
|||
i += 1 / (8 * Math.PI) |
|||
) { |
|||
arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]); |
|||
} |
|||
const cStartPoint = arcStack.shift() as number[]; |
|||
ctx.strokeStyle = color; |
|||
ctx.moveTo(cStartPoint[0], cStartPoint[1]); |
|||
const drawSin = () => { |
|||
if (!ctx) { |
|||
return; |
|||
} |
|||
ctx.beginPath(); |
|||
ctx.save(); |
|||
const sinStack = []; |
|||
for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) { |
|||
const x = sp + (xOffset + i) / unit; |
|||
const y = Math.sin(x) * currRange; |
|||
const dx = i; |
|||
const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y; |
|||
ctx.lineTo(dx, dy); |
|||
sinStack.push([dx, dy]); |
|||
} |
|||
const startPoint = sinStack.shift() as number[]; |
|||
ctx.lineTo(xOffset + axisLength, canvasHeight); |
|||
ctx.lineTo(xOffset, canvasHeight); |
|||
ctx.lineTo(startPoint[0], startPoint[1]); |
|||
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight); |
|||
gradient.addColorStop(0, '#ffffff'); |
|||
gradient.addColorStop(1, color); |
|||
ctx.fillStyle = gradient; |
|||
ctx.fill(); |
|||
ctx.restore(); |
|||
}; |
|||
const render = () => { |
|||
if (!ctx) { |
|||
return; |
|||
} |
|||
ctx.clearRect(0, 0, canvasWidth, canvasHeight); |
|||
if (circleLock && type !== 'update') { |
|||
if (arcStack.length) { |
|||
const temp = arcStack.shift() as number[]; |
|||
ctx.lineTo(temp[0], temp[1]); |
|||
ctx.stroke(); |
|||
} else { |
|||
circleLock = false; |
|||
ctx.lineTo(cStartPoint[0], cStartPoint[1]); |
|||
ctx.stroke(); |
|||
arcStack = []; |
|||
ctx.globalCompositeOperation = 'destination-over'; |
|||
ctx.beginPath(); |
|||
ctx.lineWidth = lineWidth; |
|||
ctx.arc(radius, radius, bR, 0, 2 * Math.PI, true); |
|||
ctx.beginPath(); |
|||
ctx.save(); |
|||
ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, true); |
|||
ctx.restore(); |
|||
ctx.clip(); |
|||
ctx.fillStyle = color; |
|||
} |
|||
} else { |
|||
if (data >= 0.85) { |
|||
if (currRange > range / 4) { |
|||
const t = range * 0.01; |
|||
currRange -= t; |
|||
} |
|||
} else if (data <= 0.1) { |
|||
if (currRange < range * 1.5) { |
|||
const t = range * 0.01; |
|||
currRange += t; |
|||
} |
|||
} else { |
|||
if (currRange <= range) { |
|||
const t = range * 0.01; |
|||
currRange += t; |
|||
} |
|||
if (currRange >= range) { |
|||
const t = range * 0.01; |
|||
currRange -= t; |
|||
} |
|||
} |
|||
if (data - currData > 0) { |
|||
currData += waveupsp; |
|||
} |
|||
if (data - currData < 0) { |
|||
currData -= waveupsp; |
|||
} |
|||
sp += 0.07; |
|||
drawSin(); |
|||
} |
|||
timerRef.current = requestAnimationFrame(render); |
|||
}; |
|||
render(); |
|||
}; |
|||
|
|||
const resize = () => { |
|||
if (rootRef.current) { |
|||
const { offsetWidth } = rootRef.current.parentNode as HTMLElement; |
|||
setRadio(offsetWidth < height ? offsetWidth / height : 1); |
|||
} |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
renderChart(); |
|||
resize(); |
|||
const handleResize = () => { |
|||
requestAnimationFrame(resize); |
|||
}; |
|||
window.addEventListener('resize', handleResize, { passive: true }); |
|||
|
|||
return () => { |
|||
window.removeEventListener('resize', handleResize); |
|||
}; |
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|||
}, []); |
|||
|
|||
useEffect(() => { |
|||
renderChart('update'); |
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|||
}, [percent]); |
|||
|
|||
useEffect(() => { |
|||
return () => { |
|||
cancelAnimationFrame(timerRef.current); |
|||
}; |
|||
}, []); |
|||
|
|||
return ( |
|||
<div |
|||
ref={rootRef} |
|||
style={{ |
|||
transform: `scale(${radio})`, |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
width: height, |
|||
height, |
|||
overflow: 'hidden', |
|||
}} |
|||
> |
|||
<canvas ref={nodeRef} width={height * 2} height={height * 2} /> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
width: height, |
|||
}} |
|||
> |
|||
{title && <span>{title}</span>} |
|||
<h4>{percent}%</h4> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default autoHeight()(WaterWave); |
|||
@ -1,215 +0,0 @@ |
|||
import { useEffect, useRef, useState } from 'react'; |
|||
import autoHeight from '../autoHeight'; |
|||
|
|||
/* eslint no-return-assign: 0 */ |
|||
/* eslint no-mixed-operators: 0 */ |
|||
// riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90
|
|||
|
|||
export type WaterWaveProps = { |
|||
title: React.ReactNode; |
|||
color?: string; |
|||
height?: number; |
|||
percent: number; |
|||
style?: React.CSSProperties; |
|||
}; |
|||
|
|||
const WaterWave: React.FC<WaterWaveProps> = ({ |
|||
title, |
|||
color = '#1890FF', |
|||
height = 1, |
|||
percent, |
|||
}) => { |
|||
const [radio, setRadio] = useState(1); |
|||
const timerRef = useRef<number>(0); |
|||
const rootRef = useRef<HTMLDivElement>(null); |
|||
const nodeRef = useRef<HTMLCanvasElement>(null); |
|||
|
|||
const renderChart = (type?: string) => { |
|||
const data = percent / 100; |
|||
cancelAnimationFrame(timerRef.current); |
|||
if (!nodeRef.current || (data !== 0 && !data)) { |
|||
return; |
|||
} |
|||
const canvas = nodeRef.current; |
|||
const ctx = canvas.getContext('2d'); |
|||
if (!ctx) { |
|||
return; |
|||
} |
|||
const canvasWidth = canvas.width; |
|||
const canvasHeight = canvas.height; |
|||
const radius = canvasWidth / 2; |
|||
const lineWidth = 2; |
|||
const cR = radius - lineWidth; |
|||
ctx.beginPath(); |
|||
ctx.lineWidth = lineWidth * 2; |
|||
const axisLength = canvasWidth - lineWidth; |
|||
const unit = axisLength / 8; |
|||
const range = 0.2; // 振幅
|
|||
let currRange = range; |
|||
const xOffset = lineWidth; |
|||
let sp = 0; // 周期偏移量
|
|||
let currData = 0; |
|||
const waveupsp = 0.005; // 水波上涨速度
|
|||
|
|||
let arcStack: number[][] = []; |
|||
const bR = radius - lineWidth; |
|||
const circleOffset = -(Math.PI / 2); |
|||
let circleLock = true; |
|||
for ( |
|||
let i = circleOffset; |
|||
i < circleOffset + 2 * Math.PI; |
|||
i += 1 / (8 * Math.PI) |
|||
) { |
|||
arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]); |
|||
} |
|||
const cStartPoint = arcStack.shift() as number[]; |
|||
ctx.strokeStyle = color; |
|||
ctx.moveTo(cStartPoint[0], cStartPoint[1]); |
|||
const drawSin = () => { |
|||
if (!ctx) { |
|||
return; |
|||
} |
|||
ctx.beginPath(); |
|||
ctx.save(); |
|||
const sinStack = []; |
|||
for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) { |
|||
const x = sp + (xOffset + i) / unit; |
|||
const y = Math.sin(x) * currRange; |
|||
const dx = i; |
|||
const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y; |
|||
ctx.lineTo(dx, dy); |
|||
sinStack.push([dx, dy]); |
|||
} |
|||
const startPoint = sinStack.shift() as number[]; |
|||
ctx.lineTo(xOffset + axisLength, canvasHeight); |
|||
ctx.lineTo(xOffset, canvasHeight); |
|||
ctx.lineTo(startPoint[0], startPoint[1]); |
|||
const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight); |
|||
gradient.addColorStop(0, '#ffffff'); |
|||
gradient.addColorStop(1, color); |
|||
ctx.fillStyle = gradient; |
|||
ctx.fill(); |
|||
ctx.restore(); |
|||
}; |
|||
const render = () => { |
|||
if (!ctx) { |
|||
return; |
|||
} |
|||
ctx.clearRect(0, 0, canvasWidth, canvasHeight); |
|||
if (circleLock && type !== 'update') { |
|||
if (arcStack.length) { |
|||
const temp = arcStack.shift() as number[]; |
|||
ctx.lineTo(temp[0], temp[1]); |
|||
ctx.stroke(); |
|||
} else { |
|||
circleLock = false; |
|||
ctx.lineTo(cStartPoint[0], cStartPoint[1]); |
|||
ctx.stroke(); |
|||
arcStack = []; |
|||
ctx.globalCompositeOperation = 'destination-over'; |
|||
ctx.beginPath(); |
|||
ctx.lineWidth = lineWidth; |
|||
ctx.arc(radius, radius, bR, 0, 2 * Math.PI, true); |
|||
ctx.beginPath(); |
|||
ctx.save(); |
|||
ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, true); |
|||
ctx.restore(); |
|||
ctx.clip(); |
|||
ctx.fillStyle = color; |
|||
} |
|||
} else { |
|||
if (data >= 0.85) { |
|||
if (currRange > range / 4) { |
|||
const t = range * 0.01; |
|||
currRange -= t; |
|||
} |
|||
} else if (data <= 0.1) { |
|||
if (currRange < range * 1.5) { |
|||
const t = range * 0.01; |
|||
currRange += t; |
|||
} |
|||
} else { |
|||
if (currRange <= range) { |
|||
const t = range * 0.01; |
|||
currRange += t; |
|||
} |
|||
if (currRange >= range) { |
|||
const t = range * 0.01; |
|||
currRange -= t; |
|||
} |
|||
} |
|||
if (data - currData > 0) { |
|||
currData += waveupsp; |
|||
} |
|||
if (data - currData < 0) { |
|||
currData -= waveupsp; |
|||
} |
|||
sp += 0.07; |
|||
drawSin(); |
|||
} |
|||
timerRef.current = requestAnimationFrame(render); |
|||
}; |
|||
render(); |
|||
}; |
|||
|
|||
const resize = () => { |
|||
if (rootRef.current) { |
|||
const { offsetWidth } = rootRef.current.parentNode as HTMLElement; |
|||
setRadio(offsetWidth < height ? offsetWidth / height : 1); |
|||
} |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
renderChart(); |
|||
resize(); |
|||
const handleResize = () => { |
|||
requestAnimationFrame(resize); |
|||
}; |
|||
window.addEventListener('resize', handleResize, { passive: true }); |
|||
|
|||
return () => { |
|||
window.removeEventListener('resize', handleResize); |
|||
}; |
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|||
}, []); |
|||
|
|||
useEffect(() => { |
|||
renderChart('update'); |
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|||
}, [percent]); |
|||
|
|||
useEffect(() => { |
|||
return () => { |
|||
cancelAnimationFrame(timerRef.current); |
|||
}; |
|||
}, []); |
|||
|
|||
return ( |
|||
<div |
|||
ref={rootRef} |
|||
style={{ |
|||
transform: `scale(${radio})`, |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
width: height, |
|||
height, |
|||
overflow: 'hidden', |
|||
}} |
|||
> |
|||
<canvas ref={nodeRef} width={height * 2} height={height * 2} /> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
width: height, |
|||
}} |
|||
> |
|||
{title && <span>{title}</span>} |
|||
<h4>{percent}%</h4> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default autoHeight()(WaterWave); |
|||
@ -1,69 +0,0 @@ |
|||
import React, { useEffect, useRef, useState } from 'react'; |
|||
|
|||
export type IReactComponent<P = any> = React.ComponentClass<P> | React.FC<P>; |
|||
|
|||
function computeHeight(node: HTMLDivElement) { |
|||
const { style } = node; |
|||
style.height = '100%'; |
|||
const totalHeight = parseInt(`${getComputedStyle(node).height}`, 10); |
|||
const padding = |
|||
parseInt(`${getComputedStyle(node).paddingTop}`, 10) + |
|||
parseInt(`${getComputedStyle(node).paddingBottom}`, 10); |
|||
return totalHeight - padding; |
|||
} |
|||
|
|||
function getAutoHeight(n: HTMLDivElement) { |
|||
if (!n) { |
|||
return 0; |
|||
} |
|||
|
|||
const node = n; |
|||
|
|||
let height = computeHeight(node); |
|||
const parentNode = node.parentNode as HTMLDivElement; |
|||
if (parentNode) { |
|||
height = computeHeight(parentNode); |
|||
} |
|||
|
|||
return height; |
|||
} |
|||
|
|||
type AutoHeightProps = { |
|||
height?: number; |
|||
}; |
|||
|
|||
function autoHeight() { |
|||
return <P extends AutoHeightProps>( |
|||
WrappedComponent: React.ComponentClass<P> | React.FC<P>, |
|||
): React.FC<P & AutoHeightProps> => { |
|||
const AutoHeightComponent: React.FC<P & AutoHeightProps> = (props) => { |
|||
const [computedHeight, setComputedHeight] = useState(0); |
|||
const rootRef = useRef<HTMLDivElement>(null); |
|||
|
|||
useEffect(() => { |
|||
const { height } = props; |
|||
if (!height && rootRef.current) { |
|||
let h = getAutoHeight(rootRef.current); |
|||
setComputedHeight(h); |
|||
if (h < 1) { |
|||
h = getAutoHeight(rootRef.current); |
|||
setComputedHeight(h); |
|||
} |
|||
} |
|||
}, [props]); |
|||
|
|||
const { height } = props; |
|||
const h = height || computedHeight; |
|||
|
|||
return ( |
|||
<div ref={rootRef}> |
|||
{h > 0 && <WrappedComponent {...props} height={h} />} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
return AutoHeightComponent; |
|||
}; |
|||
} |
|||
|
|||
export default autoHeight; |
|||
@ -1,268 +0,0 @@ |
|||
import { PlusOutlined } from '@ant-design/icons'; |
|||
import { Button, Divider, Input, message, Popconfirm, Table } from 'antd'; |
|||
import type { FC } from 'react'; |
|||
import React, { useState } from 'react'; |
|||
import useStyles from '../style.style'; |
|||
|
|||
type TableFormDateType = { |
|||
key: string; |
|||
workId?: string; |
|||
name?: string; |
|||
department?: string; |
|||
isNew?: boolean; |
|||
editable?: boolean; |
|||
}; |
|||
type TableFormProps = { |
|||
value?: TableFormDateType[]; |
|||
onChange?: (value: TableFormDateType[]) => void; |
|||
}; |
|||
const TableForm: FC<TableFormProps> = ({ value, onChange }) => { |
|||
const { styles } = useStyles(); |
|||
const [clickedCancel, setClickedCancel] = useState(false); |
|||
const [loading, setLoading] = useState(false); |
|||
const [index, setIndex] = useState(0); |
|||
const [cacheOriginData, setCacheOriginData] = useState<Record<string, any>>( |
|||
{}, |
|||
); |
|||
const [data, setData] = useState(value); |
|||
const getRowByKey = (key: string, newData?: TableFormDateType[]) => |
|||
(newData || data)?.filter((item) => item.key === key)[0]; |
|||
const toggleEditable = ( |
|||
e: React.MouseEvent | React.KeyboardEvent, |
|||
key: string, |
|||
) => { |
|||
e.preventDefault(); |
|||
const newData = data?.map((item) => ({ |
|||
...item, |
|||
})); |
|||
const target = getRowByKey(key, newData); |
|||
if (target) { |
|||
// 进入编辑状态时保存原始数据
|
|||
if (!target.editable) { |
|||
cacheOriginData[key] = { |
|||
...target, |
|||
}; |
|||
setCacheOriginData(cacheOriginData); |
|||
} |
|||
target.editable = !target.editable; |
|||
setData(newData); |
|||
} |
|||
}; |
|||
const newMember = () => { |
|||
const newData = |
|||
data?.map((item) => ({ |
|||
...item, |
|||
})) || []; |
|||
newData.push({ |
|||
key: `NEW_TEMP_ID_${index}`, |
|||
workId: '', |
|||
name: '', |
|||
department: '', |
|||
editable: true, |
|||
isNew: true, |
|||
}); |
|||
setIndex(index + 1); |
|||
setData(newData); |
|||
}; |
|||
const remove = (key: string) => { |
|||
const newData = data?.filter( |
|||
(item) => item.key !== key, |
|||
) as TableFormDateType[]; |
|||
setData(newData); |
|||
if (onChange) { |
|||
onChange(newData); |
|||
} |
|||
}; |
|||
const handleFieldChange = ( |
|||
e: React.ChangeEvent<HTMLInputElement>, |
|||
fieldName: keyof TableFormDateType, |
|||
key: string, |
|||
) => { |
|||
const newData = [...(data as TableFormDateType[])]; |
|||
const target = getRowByKey(key, newData); |
|||
if (target?.[fieldName]) { |
|||
target[fieldName as 'key'] = e.target.value; |
|||
setData(newData); |
|||
} |
|||
}; |
|||
const saveRow = (e: React.MouseEvent | React.KeyboardEvent, key: string) => { |
|||
e.persist(); |
|||
setLoading(true); |
|||
setTimeout(() => { |
|||
if (clickedCancel) { |
|||
setClickedCancel(false); |
|||
return; |
|||
} |
|||
const target = getRowByKey(key) || ({} as any); |
|||
if (!target.workId || !target.name || !target.department) { |
|||
message.error('请填写完整成员信息。'); |
|||
(e.target as HTMLInputElement).focus(); |
|||
setLoading(false); |
|||
return; |
|||
} |
|||
delete target.isNew; |
|||
toggleEditable(e, key); |
|||
if (onChange) { |
|||
onChange(data as TableFormDateType[]); |
|||
} |
|||
setLoading(false); |
|||
}, 500); |
|||
}; |
|||
const handleKeyPress = (e: React.KeyboardEvent, key: string) => { |
|||
if (e.key === 'Enter') { |
|||
saveRow(e, key); |
|||
} |
|||
}; |
|||
const cancel = (e: React.MouseEvent, key: string) => { |
|||
setClickedCancel(true); |
|||
e.preventDefault(); |
|||
const newData = [...(data as TableFormDateType[])]; |
|||
// 编辑前的原始数据
|
|||
let cacheData = []; |
|||
cacheData = newData.map((item) => { |
|||
if (item.key === key) { |
|||
if (cacheOriginData[key]) { |
|||
const originItem = { |
|||
...item, |
|||
...cacheOriginData[key], |
|||
editable: false, |
|||
}; |
|||
delete cacheOriginData[key]; |
|||
setCacheOriginData(cacheOriginData); |
|||
return originItem; |
|||
} |
|||
} |
|||
return item; |
|||
}); |
|||
setData(cacheData); |
|||
setClickedCancel(false); |
|||
}; |
|||
const columns = [ |
|||
{ |
|||
title: '成员姓名', |
|||
dataIndex: 'name', |
|||
key: 'name', |
|||
width: '20%', |
|||
render: (text: string, record: TableFormDateType) => { |
|||
if (record.editable) { |
|||
return ( |
|||
<Input |
|||
value={text} |
|||
autoFocus |
|||
onChange={(e) => handleFieldChange(e, 'name', record.key)} |
|||
onKeyPress={(e) => handleKeyPress(e, record.key)} |
|||
placeholder="成员姓名" |
|||
/> |
|||
); |
|||
} |
|||
return text; |
|||
}, |
|||
}, |
|||
{ |
|||
title: '工号', |
|||
dataIndex: 'workId', |
|||
key: 'workId', |
|||
width: '20%', |
|||
render: (text: string, record: TableFormDateType) => { |
|||
if (record.editable) { |
|||
return ( |
|||
<Input |
|||
value={text} |
|||
onChange={(e) => handleFieldChange(e, 'workId', record.key)} |
|||
onKeyPress={(e) => handleKeyPress(e, record.key)} |
|||
placeholder="工号" |
|||
/> |
|||
); |
|||
} |
|||
return text; |
|||
}, |
|||
}, |
|||
{ |
|||
title: '所属部门', |
|||
dataIndex: 'department', |
|||
key: 'department', |
|||
width: '40%', |
|||
render: (text: string, record: TableFormDateType) => { |
|||
if (record.editable) { |
|||
return ( |
|||
<Input |
|||
value={text} |
|||
onChange={(e) => handleFieldChange(e, 'department', record.key)} |
|||
onKeyPress={(e) => handleKeyPress(e, record.key)} |
|||
placeholder="所属部门" |
|||
/> |
|||
); |
|||
} |
|||
return text; |
|||
}, |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
key: 'action', |
|||
render: (_text: string, record: TableFormDateType) => { |
|||
if (!!record.editable && loading) { |
|||
return null; |
|||
} |
|||
if (record.editable) { |
|||
if (record.isNew) { |
|||
return ( |
|||
<span> |
|||
<a onClick={(e) => saveRow(e, record.key)}>添加</a> |
|||
<Divider type="vertical" /> |
|||
<Popconfirm |
|||
title="是否要删除此行?" |
|||
onConfirm={() => remove(record.key)} |
|||
> |
|||
<a>删除</a> |
|||
</Popconfirm> |
|||
</span> |
|||
); |
|||
} |
|||
return ( |
|||
<span> |
|||
<a onClick={(e) => saveRow(e, record.key)}>保存</a> |
|||
<Divider type="vertical" /> |
|||
<a onClick={(e) => cancel(e, record.key)}>取消</a> |
|||
</span> |
|||
); |
|||
} |
|||
return ( |
|||
<span> |
|||
<a onClick={(e) => toggleEditable(e, record.key)}>编辑</a> |
|||
<Divider type="vertical" /> |
|||
<Popconfirm |
|||
title="是否要删除此行?" |
|||
onConfirm={() => remove(record.key)} |
|||
> |
|||
<a>删除</a> |
|||
</Popconfirm> |
|||
</span> |
|||
); |
|||
}, |
|||
}, |
|||
]; |
|||
return ( |
|||
<> |
|||
<Table<TableFormDateType> |
|||
loading={loading} |
|||
columns={columns} |
|||
dataSource={data} |
|||
pagination={false} |
|||
rowClassName={(record) => (record.editable ? styles.editable : '')} |
|||
/> |
|||
<Button |
|||
style={{ |
|||
width: '100%', |
|||
marginTop: 16, |
|||
marginBottom: 8, |
|||
}} |
|||
type="dashed" |
|||
onClick={newMember} |
|||
> |
|||
<PlusOutlined /> |
|||
新增成员 |
|||
</Button> |
|||
</> |
|||
); |
|||
}; |
|||
export default TableForm; |
|||
@ -1,8 +0,0 @@ |
|||
import { request } from '@umijs/max'; |
|||
|
|||
export async function fakeSubmitForm(params: any) { |
|||
return request('/api/stepForm', { |
|||
method: 'POST', |
|||
data: params, |
|||
}); |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
export type TableListItem = { |
|||
key: number; |
|||
disabled?: boolean; |
|||
href: string; |
|||
avatar: string; |
|||
name: string; |
|||
owner: string; |
|||
desc: string; |
|||
callNo: number; |
|||
status: 0 | 1 | 2 | 3; |
|||
updatedAt: string; |
|||
createdAt: string; |
|||
progress: number; |
|||
}; |
|||
@ -1,63 +0,0 @@ |
|||
import { request } from '@umijs/max'; |
|||
import type { TableListItem } from './data'; |
|||
|
|||
/** 获取规则列表 GET /api/rule */ |
|||
export async function rule( |
|||
params: { |
|||
// query
|
|||
/** 当前的页码 */ |
|||
current?: number; |
|||
/** 页面的容量 */ |
|||
pageSize?: number; |
|||
}, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<{ |
|||
data: TableListItem[]; |
|||
/** 列表的内容总数 */ |
|||
total?: number; |
|||
success?: boolean; |
|||
}>('/api/rule', { |
|||
method: 'GET', |
|||
params: { |
|||
...params, |
|||
}, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** 新建规则 PUT /api/rule */ |
|||
export async function updateRule( |
|||
data: { [key: string]: any }, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<TableListItem>('/api/rule', { |
|||
data, |
|||
method: 'PUT', |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** 新建规则 POST /api/rule */ |
|||
export async function addRule( |
|||
data: { [key: string]: any }, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<TableListItem>('/api/rule', { |
|||
data, |
|||
method: 'POST', |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** 删除规则 DELETE /api/rule */ |
|||
export async function removeRule( |
|||
data: { key: number[] }, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<Record<string, any>>('/api/rule', { |
|||
data, |
|||
method: 'DELETE', |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
// @ts-ignore
|
|||
/* eslint-disable */ |
|||
// API 更新时间:
|
|||
// API 唯一标识:
|
|||
import * as pet from './pet'; |
|||
import * as store from './store'; |
|||
import * as user from './user'; |
|||
export default { |
|||
pet, |
|||
store, |
|||
user, |
|||
}; |
|||
@ -1,153 +0,0 @@ |
|||
// @ts-ignore
|
|||
/* eslint-disable */ |
|||
import { request } from '@umijs/max'; |
|||
|
|||
/** Update an existing pet PUT /pet */ |
|||
export async function updatePet(body: API.Pet, options?: { [key: string]: any }) { |
|||
return request<any>('/pet', { |
|||
method: 'PUT', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
data: body, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Add a new pet to the store POST /pet */ |
|||
export async function addPet(body: API.Pet, options?: { [key: string]: any }) { |
|||
return request<any>('/pet', { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json', |
|||
}, |
|||
data: body, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Find pet by ID Returns a single pet GET /pet/${param0} */ |
|||
export async function getPetById( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.getPetByIdParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { petId: param0, ...queryParams } = params; |
|||
return request<API.Pet>(`/pet/${param0}`, { |
|||
method: 'GET', |
|||
params: { ...queryParams }, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Updates a pet in the store with form data POST /pet/${param0} */ |
|||
export async function updatePetWithForm( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.updatePetWithFormParams, |
|||
body: { name?: string; status?: string }, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { petId: param0, ...queryParams } = params; |
|||
const formData = new FormData(); |
|||
|
|||
Object.keys(body).forEach((ele) => { |
|||
const item = (body as any)[ele]; |
|||
|
|||
if (item !== undefined && item !== null) { |
|||
formData.append( |
|||
ele, |
|||
typeof item === 'object' && !(item instanceof File) ? JSON.stringify(item) : item, |
|||
); |
|||
} |
|||
}); |
|||
|
|||
return request<any>(`/pet/${param0}`, { |
|||
method: 'POST', |
|||
params: { ...queryParams }, |
|||
data: formData, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Deletes a pet DELETE /pet/${param0} */ |
|||
export async function deletePet( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.deletePetParams & { |
|||
// header
|
|||
api_key?: string; |
|||
}, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { petId: param0, ...queryParams } = params; |
|||
return request<any>(`/pet/${param0}`, { |
|||
method: 'DELETE', |
|||
headers: {}, |
|||
params: { ...queryParams }, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** uploads an image POST /pet/${param0}/uploadImage */ |
|||
export async function uploadFile( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.uploadFileParams, |
|||
body: { additionalMetadata?: string; file?: string }, |
|||
file?: File, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { petId: param0, ...queryParams } = params; |
|||
const formData = new FormData(); |
|||
|
|||
if (file) { |
|||
formData.append('file', file); |
|||
} |
|||
|
|||
Object.keys(body).forEach((ele) => { |
|||
const item = (body as any)[ele]; |
|||
|
|||
if (item !== undefined && item !== null) { |
|||
formData.append( |
|||
ele, |
|||
typeof item === 'object' && !(item instanceof File) ? JSON.stringify(item) : item, |
|||
); |
|||
} |
|||
}); |
|||
|
|||
return request<API.ApiResponse>(`/pet/${param0}/uploadImage`, { |
|||
method: 'POST', |
|||
params: { ...queryParams }, |
|||
data: formData, |
|||
requestType: 'form', |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Finds Pets by status Multiple status values can be provided with comma separated strings GET /pet/findByStatus */ |
|||
export async function findPetsByStatus( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.findPetsByStatusParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<API.Pet[]>('/pet/findByStatus', { |
|||
method: 'GET', |
|||
params: { |
|||
...params, |
|||
}, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Finds Pets by tags Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. GET /pet/findByTags */ |
|||
export async function findPetsByTags( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.findPetsByTagsParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<API.Pet[]>('/pet/findByTags', { |
|||
method: 'GET', |
|||
params: { |
|||
...params, |
|||
}, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
@ -1,48 +0,0 @@ |
|||
// @ts-ignore
|
|||
/* eslint-disable */ |
|||
import { request } from '@umijs/max'; |
|||
|
|||
/** Returns pet inventories by status Returns a map of status codes to quantities GET /store/inventory */ |
|||
export async function getInventory(options?: { [key: string]: any }) { |
|||
return request<Record<string, any>>('/store/inventory', { |
|||
method: 'GET', |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Place an order for a pet POST /store/order */ |
|||
export async function placeOrder(body: API.Order, options?: { [key: string]: any }) { |
|||
return request<API.Order>('/store/order', { |
|||
method: 'POST', |
|||
data: body, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Find purchase order by ID For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions GET /store/order/${param0} */ |
|||
export async function getOrderById( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.getOrderByIdParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { orderId: param0, ...queryParams } = params; |
|||
return request<API.Order>(`/store/order/${param0}`, { |
|||
method: 'GET', |
|||
params: { ...queryParams }, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Delete purchase order by ID For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors DELETE /store/order/${param0} */ |
|||
export async function deleteOrder( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.deleteOrderParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { orderId: param0, ...queryParams } = params; |
|||
return request<any>(`/store/order/${param0}`, { |
|||
method: 'DELETE', |
|||
params: { ...queryParams }, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
@ -1,112 +0,0 @@ |
|||
declare namespace API { |
|||
type ApiResponse = { |
|||
code?: number; |
|||
type?: string; |
|||
message?: string; |
|||
}; |
|||
|
|||
type Category = { |
|||
id?: number; |
|||
name?: string; |
|||
}; |
|||
|
|||
type deleteOrderParams = { |
|||
/** ID of the order that needs to be deleted */ |
|||
orderId: number; |
|||
}; |
|||
|
|||
type deletePetParams = { |
|||
api_key?: string; |
|||
/** Pet id to delete */ |
|||
petId: number; |
|||
}; |
|||
|
|||
type deleteUserParams = { |
|||
/** The name that needs to be deleted */ |
|||
username: string; |
|||
}; |
|||
|
|||
type findPetsByStatusParams = { |
|||
/** Status values that need to be considered for filter */ |
|||
status: ('available' | 'pending' | 'sold')[]; |
|||
}; |
|||
|
|||
type findPetsByTagsParams = { |
|||
/** Tags to filter by */ |
|||
tags: string[]; |
|||
}; |
|||
|
|||
type getOrderByIdParams = { |
|||
/** ID of pet that needs to be fetched */ |
|||
orderId: number; |
|||
}; |
|||
|
|||
type getPetByIdParams = { |
|||
/** ID of pet to return */ |
|||
petId: number; |
|||
}; |
|||
|
|||
type getUserByNameParams = { |
|||
/** The name that needs to be fetched. Use user1 for testing. */ |
|||
username: string; |
|||
}; |
|||
|
|||
type loginUserParams = { |
|||
/** The user name for login */ |
|||
username: string; |
|||
/** The password for login in clear text */ |
|||
password: string; |
|||
}; |
|||
|
|||
type Order = { |
|||
id?: number; |
|||
petId?: number; |
|||
quantity?: number; |
|||
shipDate?: string; |
|||
/** Order Status */ |
|||
status?: 'placed' | 'approved' | 'delivered'; |
|||
complete?: boolean; |
|||
}; |
|||
|
|||
type Pet = { |
|||
id?: number; |
|||
category?: Category; |
|||
name: string; |
|||
photoUrls: string[]; |
|||
tags?: Tag[]; |
|||
/** pet status in the store */ |
|||
status?: 'available' | 'pending' | 'sold'; |
|||
}; |
|||
|
|||
type Tag = { |
|||
id?: number; |
|||
name?: string; |
|||
}; |
|||
|
|||
type updatePetWithFormParams = { |
|||
/** ID of pet that needs to be updated */ |
|||
petId: number; |
|||
}; |
|||
|
|||
type updateUserParams = { |
|||
/** name that need to be updated */ |
|||
username: string; |
|||
}; |
|||
|
|||
type uploadFileParams = { |
|||
/** ID of pet to update */ |
|||
petId: number; |
|||
}; |
|||
|
|||
type User = { |
|||
id?: number; |
|||
username?: string; |
|||
firstName?: string; |
|||
lastName?: string; |
|||
email?: string; |
|||
password?: string; |
|||
phone?: string; |
|||
/** User Status */ |
|||
userStatus?: number; |
|||
}; |
|||
} |
|||
@ -1,100 +0,0 @@ |
|||
// @ts-ignore
|
|||
/* eslint-disable */ |
|||
import { request } from '@umijs/max'; |
|||
|
|||
/** Create user This can only be done by the logged in user. POST /user */ |
|||
export async function createUser(body: API.User, options?: { [key: string]: any }) { |
|||
return request<any>('/user', { |
|||
method: 'POST', |
|||
data: body, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Get user by user name GET /user/${param0} */ |
|||
export async function getUserByName( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.getUserByNameParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { username: param0, ...queryParams } = params; |
|||
return request<API.User>(`/user/${param0}`, { |
|||
method: 'GET', |
|||
params: { ...queryParams }, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Updated user This can only be done by the logged in user. PUT /user/${param0} */ |
|||
export async function updateUser( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.updateUserParams, |
|||
body: API.User, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { username: param0, ...queryParams } = params; |
|||
return request<any>(`/user/${param0}`, { |
|||
method: 'PUT', |
|||
params: { ...queryParams }, |
|||
data: body, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Delete user This can only be done by the logged in user. DELETE /user/${param0} */ |
|||
export async function deleteUser( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.deleteUserParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
const { username: param0, ...queryParams } = params; |
|||
return request<any>(`/user/${param0}`, { |
|||
method: 'DELETE', |
|||
params: { ...queryParams }, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Creates list of users with given input array POST /user/createWithArray */ |
|||
export async function createUsersWithArrayInput( |
|||
body: API.User[], |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<any>('/user/createWithArray', { |
|||
method: 'POST', |
|||
data: body, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Creates list of users with given input array POST /user/createWithList */ |
|||
export async function createUsersWithListInput(body: API.User[], options?: { [key: string]: any }) { |
|||
return request<any>('/user/createWithList', { |
|||
method: 'POST', |
|||
data: body, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Logs user into the system GET /user/login */ |
|||
export async function loginUser( |
|||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
|||
params: API.loginUserParams, |
|||
options?: { [key: string]: any }, |
|||
) { |
|||
return request<string>('/user/login', { |
|||
method: 'GET', |
|||
params: { |
|||
...params, |
|||
}, |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
|
|||
/** Logs out current logged in user session GET /user/logout */ |
|||
export async function logoutUser(options?: { [key: string]: any }) { |
|||
return request<any>('/user/logout', { |
|||
method: 'GET', |
|||
...(options || {}), |
|||
}); |
|||
} |
|||
Loading…
Reference in new issue