import PropTypes from 'prop-types'; import { useState, useEffect, useMemo, useCallback } from 'react'; import { GridRowModes, DataGrid, GridToolbarContainer, GridActionsCellItem, GridToolbarExport, GridToolbarColumnsButton, GridToolbarFilterButton, GridToolbarQuickFilter, GridToolbarDensitySelector } from '@mui/x-data-grid'; import { zhCN } from '@mui/x-data-grid/locales'; import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/DeleteOutlined'; import SaveIcon from '@mui/icons-material/Save'; import CancelIcon from '@mui/icons-material/Close'; import { showError, showSuccess, trims } from 'utils/common'; import { API } from 'utils/api'; import { ValueFormatter, priceType } from './component/util'; function validation(row, rows) { if (row.model === '') { return '模型名称不能为空'; } // 判断 type 是否是 等于 tokens || times if (row.type !== 'tokens' && row.type !== 'times') { return '类型只能是tokens或times'; } if (row.channel_type <= 0) { return '所属渠道类型错误'; } // 判断 model是否是唯一值 if (rows.filter((r) => r.model === row.model && (row.isNew || r.id !== row.id)).length > 0) { return '模型名称不能重复'; } if (row.input === '' || row.input < 0) { return '输入倍率必须大于等于0'; } if (row.output === '' || row.output < 0) { return '输出倍率必须大于等于0'; } return false; } function randomId() { return Math.random().toString(36).substr(2, 9); } function EditToolbar({ setRows, setRowModesModel }) { const handleClick = () => { const id = randomId(); setRows((oldRows) => [{ id, model: '', type: 'tokens', channel_type: 1, input: 0, output: 0, isNew: true }, ...oldRows]); setRowModesModel((oldModel) => ({ [id]: { mode: GridRowModes.Edit, fieldToFocus: 'name' }, ...oldModel })); }; return ( ); } EditToolbar.propTypes = { setRows: PropTypes.func.isRequired, setRowModesModel: PropTypes.func.isRequired }; const Single = ({ ownedby, prices, reloadData }) => { const [rows, setRows] = useState([]); const [rowModesModel, setRowModesModel] = useState({}); const [selectedRow, setSelectedRow] = useState(null); const addOrUpdatePirces = useCallback( async (newRow, oldRow, reject, resolve) => { try { let res; newRow = trims(newRow); if (oldRow.model == '') { res = await API.post('/api/prices/single', newRow); } else { let modelEncode = encodeURIComponent(oldRow.model); res = await API.put('/api/prices/single/' + modelEncode, newRow); } const { success, message } = res.data; if (success) { showSuccess('保存成功'); resolve(newRow); reloadData(); } else { reject(new Error(message)); } } catch (error) { reject(new Error(error)); } }, [reloadData] ); const handleEditClick = useCallback( (id) => () => { setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.Edit } }); }, [rowModesModel] ); const handleSaveClick = useCallback( (id) => () => { setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } }); }, [rowModesModel] ); const handleDeleteClick = useCallback( (id) => () => { setSelectedRow(rows.find((row) => row.id === id)); }, [rows] ); const handleClose = () => { setSelectedRow(null); }; const handleConfirmDelete = async () => { // 执行删除操作 await deletePirces(selectedRow.model); setSelectedRow(null); }; const handleCancelClick = useCallback( (id) => () => { setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View, ignoreModifications: true } }); const editedRow = rows.find((row) => row.id === id); if (editedRow.isNew) { setRows(rows.filter((row) => row.id !== id)); } }, [rowModesModel, rows] ); const processRowUpdate = useCallback( (newRow, oldRows) => new Promise((resolve, reject) => { if ( !newRow.isNew && newRow.model === oldRows.model && newRow.input === oldRows.input && newRow.output === oldRows.output && newRow.type === oldRows.type && newRow.channel_type === oldRows.channel_type ) { return resolve(oldRows); } const updatedRow = { ...newRow, isNew: false }; const error = validation(updatedRow, rows); if (error) { return reject(new Error(error)); } const response = addOrUpdatePirces(updatedRow, oldRows, reject, resolve); return response; }), [rows, addOrUpdatePirces] ); const handleProcessRowUpdateError = useCallback((error) => { showError(error.message); }, []); const handleRowModesModelChange = (newRowModesModel) => { setRowModesModel(newRowModesModel); }; const modelRatioColumns = useMemo( () => [ { field: 'model', sortable: true, headerName: '模型名称', minWidth: 220, flex: 1, editable: true }, { field: 'type', sortable: true, headerName: '类型', flex: 0.5, minWidth: 100, type: 'singleSelect', valueOptions: priceType, editable: true }, { field: 'channel_type', sortable: true, headerName: '供应商', flex: 0.5, minWidth: 100, type: 'singleSelect', valueOptions: ownedby, editable: true }, { field: 'input', sortable: false, headerName: '输入倍率', flex: 0.8, minWidth: 150, type: 'number', editable: true, valueFormatter: (params) => ValueFormatter(params.value) }, { field: 'output', sortable: false, headerName: '输出倍率', flex: 0.8, minWidth: 150, type: 'number', editable: true, valueFormatter: (params) => ValueFormatter(params.value) }, { field: 'actions', type: 'actions', headerName: '操作', flex: 0.5, minWidth: 100, // width: 100, cellClassName: 'actions', hideable: false, disableExport: true, getActions: ({ id }) => { const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit; if (isInEditMode) { return [ } key={'Save-' + id} label="Save" sx={{ color: 'primary.main' }} onClick={handleSaveClick(id)} />, } key={'Cancel-' + id} label="Cancel" className="textPrimary" onClick={handleCancelClick(id)} color="inherit" /> ]; } return [ } label="Edit" className="textPrimary" onClick={handleEditClick(id)} color="inherit" />, } label="Delete" onClick={handleDeleteClick(id)} color="inherit" /> ]; } } ], [handleCancelClick, handleDeleteClick, handleEditClick, handleSaveClick, rowModesModel, ownedby] ); const deletePirces = async (modelName) => { try { let modelEncode = encodeURIComponent(modelName); const res = await API.delete('/api/prices/single/' + modelEncode); const { success, message } = res.data; if (success) { showSuccess('保存成功'); await reloadData(); } else { showError(message); } } catch (error) { console.error(error); } }; useEffect(() => { let modelRatioList = []; let id = 0; for (let key in prices) { modelRatioList.push({ id: id++, ...prices[key] }); } setRows(modelRatioList); }, [prices]); return ( { // event.defaultMuiPrevented = true; // }} onRowEditStop={(params, event) => { if (params.reason === 'rowFocusOut') { event.defaultMuiPrevented = true; } }} slots={{ toolbar: EditToolbar }} slotProps={{ toolbar: { setRows, setRowModesModel } }} /> 确定删除? {`确定删除 ${selectedRow?.model} 吗?`} ); }; export default Single; Single.propTypes = { prices: PropTypes.array, ownedby: PropTypes.array, reloadData: PropTypes.func };