fix: npm lint errors

This commit is contained in:
2025-11-24 09:39:30 +08:00
parent b1fb054714
commit 0256f0cf22
17 changed files with 195 additions and 222 deletions

View File

@@ -5,10 +5,10 @@ import PeopleForm from './PeopleForm.tsx'
import InputDrawer from './InputDrawer.tsx'
import { createPeoplesBatch, type People } from '../apis'
const { Panel } = Collapse as any
const Panel = Collapse.Panel
const { Content } = Layout
type FormItem = { id: string; initialData?: any }
type FormItem = { id: string; initialData?: Partial<People> }
type Props = { inputOpen?: boolean; onCloseInput?: () => void; containerEl?: HTMLElement | null }
@@ -29,7 +29,18 @@ const BatchRegister: React.FC<Props> = ({ inputOpen = false, onCloseInput, conta
delete instancesRef.current[id]
}
const buildPeople = (values: any, common: any): People => {
type FormValues = {
name: string;
contact?: string;
gender: string;
age: number;
height?: number;
marital_status?: string;
introduction?: Record<string, string>;
match_requirement?: string;
cover?: string;
}
const buildPeople = (values: FormValues, common: { contact?: string }): People => {
return {
name: values.name,
contact: values.contact || common.contact || undefined,
@@ -43,9 +54,9 @@ const BatchRegister: React.FC<Props> = ({ inputOpen = false, onCloseInput, conta
}
}
const handleInputResult = (list: any) => {
const handleInputResult = (list: unknown) => {
const arr = Array.isArray(list) ? list : [list]
const next: FormItem[] = arr.map((data: any) => ({ id: `${Date.now()}-${Math.random()}`, initialData: data }))
const next: FormItem[] = arr.map((data) => ({ id: `${Date.now()}-${Math.random()}`, initialData: data as Partial<People> }))
setItems((prev) => [...prev, ...next])
}
@@ -61,12 +72,12 @@ const BatchRegister: React.FC<Props> = ({ inputOpen = false, onCloseInput, conta
message.error('表单未就绪')
return
}
const allValues: any[] = []
const allValues: FormValues[] = []
for (const f of forms) {
try {
const v = await f.validateFields()
allValues.push(v)
} catch (err: any) {
} catch {
setLoading(false)
message.error('请完善全部表单后再提交')
return
@@ -87,7 +98,7 @@ const BatchRegister: React.FC<Props> = ({ inputOpen = false, onCloseInput, conta
setItems([{ id: `${Date.now()}-${Math.random()}` }])
commonForm.resetFields()
}
} catch (e: any) {
} catch {
message.error('提交失败')
} finally {
setLoading(false)

View File

@@ -7,7 +7,7 @@ import './InputDrawer.css';
type Props = {
open: boolean;
onClose: () => void;
onResult?: (data: any) => void;
onResult?: (data: unknown) => void;
containerEl?: HTMLElement | null; // 抽屉挂载容器(用于放在标题栏下方)
showUpload?: boolean; // 透传到输入面板,控制图片上传按钮
mode?: 'input' | 'search' | 'batch-image'; // 透传到输入面板,控制工作模式
@@ -31,7 +31,7 @@ const InputDrawer: React.FC<Props> = ({ open, onClose, onResult, containerEl, sh
// 在输入处理成功onResult 被调用)后,自动关闭抽屉
const handleResult = React.useCallback(
(data: any) => {
(data: unknown) => {
onResult?.(data);
onClose();
},

View File

@@ -1,5 +1,6 @@
import React from 'react';
import { Input, Upload, message, Button, Spin, Tag } from 'antd';
import type { UploadFile, RcFile } from 'antd/es/upload/interface';
import { PictureOutlined, SendOutlined, LoadingOutlined, SearchOutlined } from '@ant-design/icons';
import { postInput, postInputImage, getPeoples } from '../apis';
import './InputPanel.css';
@@ -7,14 +8,14 @@ import './InputPanel.css';
const { TextArea } = Input;
interface InputPanelProps {
onResult?: (data: any) => void;
onResult?: (data: unknown) => void;
showUpload?: boolean; // 是否显示图片上传按钮,默认显示
mode?: 'input' | 'search' | 'batch-image'; // 输入面板工作模式,新增批量图片模式
}
const InputPanel: React.FC<InputPanelProps> = ({ onResult, showUpload = true, mode = 'input' }) => {
const [value, setValue] = React.useState('');
const [fileList, setFileList] = React.useState<any[]>([]);
const [fileList, setFileList] = React.useState<UploadFile[]>([]);
const [loading, setLoading] = React.useState(false);
// 批量模式不保留文本内容
@@ -63,9 +64,9 @@ const InputPanel: React.FC<InputPanelProps> = ({ onResult, showUpload = true, mo
}
setLoading(true);
try {
const results: any[] = [];
const results: unknown[] = [];
for (let i = 0; i < fileList.length; i++) {
const f = fileList[i].originFileObj || fileList[i];
const f = fileList[i].originFileObj as RcFile | undefined;
if (!f) continue;
const resp = await postInputImage(f);
if (resp && resp.error_code === 0 && resp.data) {
@@ -95,7 +96,7 @@ const InputPanel: React.FC<InputPanelProps> = ({ onResult, showUpload = true, mo
// 如果有图片,优先处理图片上传
if (hasImage) {
const file = fileList[0].originFileObj || fileList[0];
const file = fileList[0].originFileObj as RcFile | undefined;
if (!file) {
message.error('图片文件无效,请重新选择');
return;
@@ -152,18 +153,18 @@ const InputPanel: React.FC<InputPanelProps> = ({ onResult, showUpload = true, mo
if (!items || items.length === 0) return;
if (mode === 'batch-image') {
const newEntries: any[] = [];
const newEntries: UploadFile[] = [];
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.kind === 'file') {
const file = item.getAsFile();
if (file && file.type.startsWith('image/')) {
const entry = {
const entry: UploadFile<RcFile> = {
uid: `${Date.now()}-${Math.random()}`,
name: 'image',
status: 'done',
originFileObj: file,
} as any;
originFileObj: file as unknown as RcFile,
};
newEntries.push(entry);
}
}
@@ -190,14 +191,13 @@ const InputPanel: React.FC<InputPanelProps> = ({ onResult, showUpload = true, mo
if (firstImage) {
e.preventDefault();
setValue('');
setFileList([
{
uid: `${Date.now()}-${Math.random()}`,
name: 'image',
status: 'done',
originFileObj: firstImage,
} as any,
]);
const item: UploadFile<RcFile> = {
uid: `${Date.now()}-${Math.random()}`,
name: 'image',
status: 'done',
originFileObj: firstImage as unknown as RcFile,
};
setFileList([item]);
message.success('已添加剪贴板图片');
}
}
@@ -278,9 +278,9 @@ const InputPanel: React.FC<InputPanelProps> = ({ onResult, showUpload = true, mo
fileList={fileList}
onChange={({ fileList: nextFileList }) => {
if (mode === 'batch-image') {
const normalized = nextFileList.map((entry: any) => {
const raw = entry.originFileObj || entry;
return { ...entry, name: 'image', originFileObj: raw };
const normalized: UploadFile<RcFile>[] = nextFileList.map((entry) => {
const raw = (entry as UploadFile<RcFile>).originFileObj;
return { ...(entry as UploadFile<RcFile>), name: 'image', originFileObj: raw };
});
setValue('');
setFileList(normalized);
@@ -290,15 +290,15 @@ const InputPanel: React.FC<InputPanelProps> = ({ onResult, showUpload = true, mo
return;
}
// 仅添加第一张
const first = nextFileList[0] as any;
const raw = first.originFileObj || first;
const renamed = { ...first, name: 'image', originFileObj: raw };
const first = nextFileList[0] as UploadFile<RcFile>;
const raw = first.originFileObj;
const renamed: UploadFile<RcFile> = { ...first, name: 'image', originFileObj: raw };
setValue('');
setFileList([renamed]);
}
}}
onRemove={(file) => {
setFileList((prev) => prev.filter((x) => x.uid !== (file as any).uid));
setFileList((prev) => prev.filter((x) => x.uid !== (file as UploadFile<RcFile>).uid));
return true;
}}
showUploadList={false}

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { Row, Col, Input, Button } from 'antd';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import './KeyValueList.css';
@@ -15,11 +15,8 @@ type Props = {
const KeyValueList: React.FC<Props> = ({ value, onChange }) => {
const [rows, setRows] = useState<KeyValuePair[]>([]);
const initializedRef = useRef(false);
useEffect(() => {
// 初始化时提供一行空输入;之后只合并父值,不再自动新增空行
const initializedRef = (KeyValueList as any)._initializedRef || { current: false };
(KeyValueList as any)._initializedRef = initializedRef;
setRows((prev) => {
const existingIdByKey = new Map(prev.filter((r) => r.k).map((r) => [r.k, r.id]));
const valuePairs: KeyValuePair[] = value

View File

@@ -66,7 +66,7 @@ const LayoutWrapper: React.FC = () => {
showInput={isHome || isList || isBatch}
/>
{/* 下方为主布局:左侧菜单 + 右侧内容 */}
<Layout ref={layoutShellRef as any} className="layout-shell">
<Layout ref={layoutShellRef} className="layout-shell">
<SiderMenu
onNavigate={handleNavigate}
selectedKey={selectedKey}

View File

@@ -1,10 +1,11 @@
import React from 'react';
import { Modal, Form, Input, Button, message } from 'antd';
import type { LoginRequest } from '../apis/types';
interface Props {
open: boolean;
onCancel: () => void;
onOk: (values: any) => Promise<void>;
onOk: (values: LoginRequest) => Promise<void>;
title: string;
username?: string;
usernameReadOnly?: boolean;
@@ -30,12 +31,12 @@ const LoginModal: React.FC<Props> = ({ open, onCancel, onOk, title, username, us
const payload = isEmail
? { email: username, password }
: { phone: username, password };
await onOk(payload as any);
await onOk(payload as LoginRequest);
if (!hideSuccessMessage) {
message.success('登录成功');
}
onCancel();
} catch (error) {
} catch {
message.error('登录失败');
}
};

View File

@@ -3,15 +3,16 @@ import { Layout, Typography } from 'antd';
import PeopleForm from './PeopleForm.tsx';
import InputDrawer from './InputDrawer.tsx';
import './MainContent.css';
import type { People } from '../apis';
const { Content } = Layout;
type Props = { inputOpen?: boolean; onCloseInput?: () => void; containerEl?: HTMLElement | null };
const MainContent: React.FC<Props> = ({ inputOpen = false, onCloseInput, containerEl }) => {
const [formData, setFormData] = React.useState<any>(null);
const [formData, setFormData] = React.useState<Partial<People> | null>(null);
const handleInputResult = (data: any) => {
setFormData(data);
const handleInputResult = (data: unknown) => {
setFormData(data as Partial<People>);
};
return (
@@ -24,7 +25,7 @@ const MainContent: React.FC<Props> = ({ inputOpen = false, onCloseInput, contain
</Typography.Paragraph>
<PeopleForm initialData={formData} />
<PeopleForm initialData={formData || undefined} />
</div>
{/* 首页右侧输入抽屉,仅在顶栏点击后弹出;挂载到标题栏下方容器 */}

View File

@@ -8,7 +8,7 @@ import { createPeople, type People } from '../apis';
const { TextArea } = Input;
interface PeopleFormProps {
initialData?: any;
initialData?: Partial<People>;
// 编辑模式下由父组件控制提交,隐藏内部提交按钮
hideSubmitButton?: boolean;
// 暴露 AntD Form 实例给父组件,用于在外部触发校验与取值
@@ -22,11 +22,7 @@ const PeopleForm: React.FC<PeopleFormProps> = ({ initialData, hideSubmitButton =
// 当 initialData 变化时,自动填充表单
useEffect(() => {
if (initialData) {
console.log('收到API返回数据自动填充表单:', initialData);
// 处理返回的数据,将其转换为表单需要的格式
const formData: any = {};
const formData: Partial<People> = {};
if (initialData.name) formData.name = initialData.name;
if (initialData.contact) formData.contact = initialData.contact;
if (initialData.cover) formData.cover = initialData.cover;
@@ -35,13 +31,8 @@ const PeopleForm: React.FC<PeopleFormProps> = ({ initialData, hideSubmitButton =
if (initialData.height) formData.height = initialData.height;
if (initialData.marital_status) formData.marital_status = initialData.marital_status;
if (initialData.match_requirement) formData.match_requirement = initialData.match_requirement;
if (initialData.introduction) formData.introduction = initialData.introduction;
// 设置表单字段值
if (initialData.introduction) formData.introduction = initialData.introduction as Record<string, string>;
form.setFieldsValue(formData);
// 显示成功消息
// message.success('已自动填充表单,请检查并确认信息');
}
}, [initialData, form]);
@@ -52,7 +43,18 @@ const PeopleForm: React.FC<PeopleFormProps> = ({ initialData, hideSubmitButton =
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onFinish = async (values: any) => {
type FormValues = {
name: string;
contact?: string;
gender: string;
age: number;
height?: number;
marital_status?: string;
introduction?: Record<string, string>;
match_requirement?: string;
cover?: string;
};
const onFinish = async (values: FormValues) => {
setLoading(true);
try {
@@ -81,16 +83,14 @@ const PeopleForm: React.FC<PeopleFormProps> = ({ initialData, hideSubmitButton =
message.error(response.error_info || '提交失败,请重试');
}
} catch (error: any) {
console.error('提交失败:', error);
// 根据错误类型显示不同的错误信息
if (error.status === 422) {
} catch (e) {
const err = e as { status?: number; message?: string };
if (err.status === 422) {
message.error('表单数据格式有误,请检查输入内容');
} else if (error.status >= 500) {
} else if ((err.status ?? 0) >= 500) {
message.error('服务器错误,请稍后重试');
} else {
message.error(error.message || '提交失败,请重试');
message.error(err.message || '提交失败,请重试');
}
} finally {
setLoading(false);

View File

@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Modal, Form, Input, Button, message } from 'antd';
import { useAuth } from '../contexts/AuthContext';
import { useAuth } from '../contexts/useAuth';
import type { RegisterRequest } from '../apis/types';
interface Props {
@@ -29,7 +29,7 @@ const RegisterModal: React.FC<Props> = ({ open, onCancel }) => {
await sendCode({ target_type, target, scene: 'register' });
message.success('验证码已发送');
setStep('verify');
} catch (error) {
} catch {
message.error('发送验证码失败');
}
};
@@ -40,7 +40,7 @@ const RegisterModal: React.FC<Props> = ({ open, onCancel }) => {
await register({ ...registerPayload, ...values } as RegisterRequest);
message.success('注册成功');
onCancel();
} catch (error) {
} catch {
message.error('注册失败');
}
};

View File

@@ -22,7 +22,7 @@ export type Resource = Omit<People, 'id'> & { id: string };
// 统一转换 API 返回的人员列表为表格需要的结构
function transformPeoples(list: People[] = []): Resource[] {
return (list || []).map((person: any) => ({
return (list || []).map((person: Partial<People>) => ({
id: person.id || `person-${Date.now()}-${Math.random()}`,
name: person.name || '未知',
gender: person.gender || '其他/保密',
@@ -72,7 +72,7 @@ async function fetchResources(): Promise<Resource[]> {
return transformed;
} catch (error: any) {
} catch (error: unknown) {
console.error('获取人员列表失败:', error);
message.error('获取人员列表失败,使用模拟数据');
@@ -463,124 +463,70 @@ async function fetchResources(): Promise<Resource[]> {
}
// 数字范围筛选下拉
function NumberRangeFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters }: FilterDropdownProps) {
const [min, max] = String(selectedKeys?.[0] ?? ':').split(':');
const [localMin, setLocalMin] = React.useState<number | undefined>(min ? Number(min) : undefined);
const [localMax, setLocalMax] = React.useState<number | undefined>(max ? Number(max) : undefined);
return (
<div style={{ padding: 8 }}>
<Space direction="vertical" style={{ width: 200 }}>
<InputNumber placeholder="最小值" value={localMin} onChange={(v) => setLocalMin(v ?? undefined)} style={{ width: '100%' }} />
<InputNumber placeholder="最大值" value={localMax} onChange={(v) => setLocalMax(v ?? undefined)} style={{ width: '100%' }} />
<Space>
<Button type="primary" size="small" icon={<SearchOutlined />} onClick={() => { const key = `${localMin ?? ''}:${localMax ?? ''}`; setSelectedKeys?.([key]); confirm?.({ closeDropdown: true }); }}></Button>
<Button size="small" onClick={() => { setLocalMin(undefined); setLocalMax(undefined); setSelectedKeys?.([]); clearFilters?.(); confirm?.({ closeDropdown: true }); }}></Button>
</Space>
</Space>
</div>
);
}
function buildNumberRangeFilter(dataIndex: keyof Resource, label: string): ColumnType<Resource> {
return {
title: label,
dataIndex,
sorter: (a: Resource, b: Resource) => Number((a as any)[dataIndex] ?? 0) - Number((b as any)[dataIndex] ?? 0),
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }: FilterDropdownProps) => {
const [min, max] = String(selectedKeys?.[0] ?? ':').split(':');
const [localMin, setLocalMin] = React.useState<number | undefined>(min ? Number(min) : undefined);
const [localMax, setLocalMax] = React.useState<number | undefined>(max ? Number(max) : undefined);
return (
<div style={{ padding: 8 }}>
<Space direction="vertical" style={{ width: 200 }}>
<InputNumber
placeholder="最小值"
value={localMin}
onChange={(v) => setLocalMin(v ?? undefined)}
style={{ width: '100%' }}
/>
<InputNumber
placeholder="最大值"
value={localMax}
onChange={(v) => setLocalMax(v ?? undefined)}
style={{ width: '100%' }}
/>
<Space>
<Button
type="primary"
size="small"
icon={<SearchOutlined />}
onClick={() => {
const key = `${localMin ?? ''}:${localMax ?? ''}`;
setSelectedKeys?.([key]);
confirm?.({ closeDropdown: true });
}}
>
</Button>
<Button
size="small"
onClick={() => {
setLocalMin(undefined);
setLocalMax(undefined);
setSelectedKeys?.([]);
clearFilters?.();
confirm?.({ closeDropdown: true });
}}
>
</Button>
</Space>
</Space>
</div>
);
sorter: (a: Resource, b: Resource) => {
const av = a[dataIndex] as number | undefined;
const bv = b[dataIndex] as number | undefined;
return Number(av ?? 0) - Number(bv ?? 0);
},
filterDropdown: (props) => <NumberRangeFilterDropdown {...props} />,
onFilter: (filterValue: React.Key | boolean, record: Resource) => {
const [minStr, maxStr] = String(filterValue).split(':');
const min = minStr ? Number(minStr) : undefined;
const max = maxStr ? Number(maxStr) : undefined;
const val = Number((record as any)[dataIndex] ?? NaN);
if (Number.isNaN(val)) return false;
if (min !== undefined && val < min) return false;
if (max !== undefined && val > max) return false;
const val = record[dataIndex] as number | undefined;
if (val === undefined || Number.isNaN(Number(val))) return false;
if (min !== undefined && Number(val) < min) return false;
if (max !== undefined && Number(val) > max) return false;
return true;
},
} as ColumnType<Resource>;
}
// 枚举筛选下拉(用于性别等枚举类列)
function EnumFilterDropdown({ setSelectedKeys, selectedKeys, confirm, clearFilters, options, label }: FilterDropdownProps & { options: Array<{ label: string; value: string }>; label: string }) {
const [val, setVal] = React.useState<string | undefined>(selectedKeys && selectedKeys[0] ? String(selectedKeys[0]) : undefined);
return (
<div className="byte-table-custom-filter" style={{ padding: 8 }}>
<Space direction="vertical" style={{ width: 200 }}>
<Select allowClear placeholder={`请选择${label}`} value={val} onChange={(v) => setVal(v)} options={options} style={{ width: '100%' }} />
<Space>
<Button type="primary" size="small" icon={<SearchOutlined />} onClick={() => { setSelectedKeys?.(val ? [val] : []); confirm?.({ closeDropdown: true }); }}></Button>
<Button size="small" onClick={() => { setVal(undefined); setSelectedKeys?.([]); clearFilters?.(); confirm?.({ closeDropdown: true }); }}></Button>
</Space>
</Space>
</div>
);
}
function buildEnumFilter(dataIndex: keyof Resource, label: string, options: Array<{ label: string; value: string }>): ColumnType<Resource> {
return {
title: label,
dataIndex,
key: String(dataIndex),
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }: FilterDropdownProps) => {
const [val, setVal] = React.useState<string | undefined>(
(selectedKeys && selectedKeys[0] ? String(selectedKeys[0]) : undefined)
);
return (
<div className="byte-table-custom-filter" style={{ padding: 8 }}>
<Space direction="vertical" style={{ width: 200 }}>
<Select
allowClear
placeholder={`请选择${label}`}
value={val}
onChange={(v) => setVal(v)}
options={options}
style={{ width: '100%' }}
/>
<Space>
<Button
type="primary"
size="small"
icon={<SearchOutlined />}
onClick={() => {
setSelectedKeys?.(val ? [val] : []);
confirm?.({ closeDropdown: true });
}}
>
</Button>
<Button
size="small"
onClick={() => {
setVal(undefined);
setSelectedKeys?.([]);
clearFilters?.();
confirm?.({ closeDropdown: true });
}}
>
</Button>
</Space>
</Space>
</div>
);
},
onFilter: (filterValue: React.Key | boolean, record: Resource) =>
String((record as any)[dataIndex]) === String(filterValue),
filterDropdown: (props) => <EnumFilterDropdown {...props} options={options} label={label} />,
onFilter: (filterValue: React.Key | boolean, record: Resource) => String(record[dataIndex] ?? '') === String(filterValue),
render: (g: string) => {
const color = g === '男' ? 'blue' : g === '女' ? 'magenta' : 'default';
return <Tag color={color}>{g}</Tag>;
@@ -654,7 +600,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
} else {
message.error(res.error_info || '删除失败');
}
} catch (err: any) {
} catch {
message.error('删除失败');
} finally {
await reloadResources();
@@ -688,7 +634,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
onFilter: (filterValue: React.Key | boolean, record: Resource) => String(record.name).includes(String(filterValue)),
render: (text: string, record: Resource) => {
// 图片图标逻辑
const hasCover = record.cover && record.cover.trim() !== '';
const hasCover = typeof record.cover === 'string' && record.cover.trim() !== '';
const pictureIcon = (
<PictureOutlined
style={{
@@ -696,7 +642,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
cursor: hasCover ? 'pointer' : 'default'
}}
onClick={hasCover ? () => {
setCurrentImageUrl(record.cover);
setCurrentImageUrl(record.cover as string);
setImageModalVisible(true);
} : undefined}
/>
@@ -834,7 +780,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
title: '操作',
key: 'actions',
width: 80,
render: (_: any, record: Resource) => (
render: (_: unknown, record: Resource) => (
<Dropdown
trigger={["click"]}
menu={{
@@ -952,8 +898,9 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
} else {
message.error(res.error_info || '更新失败');
}
} catch (err: any) {
if (err?.errorFields) {
} catch (err) {
const hasErrorFields = typeof err === 'object' && err !== null && 'errorFields' in err;
if (hasErrorFields) {
message.error('请完善表单后再保存');
} else {
message.error('更新失败');
@@ -1003,7 +950,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
}
},
}
: ({} as any)
: {}
}
pagination={{
...pagination,
@@ -1055,7 +1002,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
)}
{record.created_at && (
<div style={{ fontSize: '12px', color: '#999', marginTop: '12px' }}>
{record.created_at ? '录入于: ' + formatDate(record.created_at) : ''}
{record.created_at ? '录入于: ' + formatDate(Number(record.created_at)) : ''}
</div>
)}
@@ -1064,7 +1011,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
<span></span>
</Typography.Title>
{record.match_requirement ? (
<div>{record.match_requirement}</div>
<div>{String(record.match_requirement)}</div>
) : (
<div style={{ color: '#9ca3af' }}></div>
)}
@@ -1078,7 +1025,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
{record.comments && record.comments.remark ? (
<Space>
<Button size="small" onClick={() => {
setEditingRemark({ recordId: record.id, content: record.comments.remark.content });
setEditingRemark({ recordId: record.id, content: record.comments?.remark?.content || '' });
setRemarkModalVisible(true);
}}></Button>
<Button size="small" danger onClick={async () => {
@@ -1090,7 +1037,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
} else {
message.error(res.error_info || '清空失败');
}
} catch (err) {
} catch {
message.error('清空失败');
}
}}></Button>
@@ -1121,7 +1068,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
<InputDrawer
open={inputOpen}
onClose={onCloseInput || (() => {})}
onResult={(list: any) => {
onResult={(list: unknown) => {
// setInputResult(list);
const mapped = transformPeoples(Array.isArray(list) ? list : []);
setData(mapped);
@@ -1186,13 +1133,14 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
} else {
message.error(res.error_info || '更新失败');
}
} catch (err: any) {
if (err?.errorFields) {
message.error('请完善表单后再确认');
} else {
message.error('更新失败');
} catch (err) {
const hasErrorFields = typeof err === 'object' && err !== null && 'errorFields' in err;
if (hasErrorFields) {
message.error('请完善表单后再确认');
} else {
message.error('更新失败');
}
}
}
}}
destroyOnHidden
okText="确认"
@@ -1225,7 +1173,7 @@ const ResourceList: React.FC<Props> = ({ inputOpen = false, onCloseInput, contai
} else {
message.error(res.error_info || '操作失败');
}
} catch (err) {
} catch {
message.error('操作失败');
}
}}

View File

@@ -1,6 +1,6 @@
import LoginModal from './LoginModal';
import RegisterModal from './RegisterModal';
import { useAuth } from '../contexts/AuthContext';
import { useAuth } from '../contexts/useAuth';
import React from 'react';
import { Layout, Menu, Grid, Drawer, Button } from 'antd';
import { FormOutlined, UnorderedListOutlined, MenuOutlined, CopyOutlined, UserOutlined, SettingOutlined } from '@ant-design/icons';

View File

@@ -2,7 +2,7 @@ import React from 'react'
import { Form, Input, Button, message, Card, Space, Upload, Modal } from 'antd'
import 'react-image-crop/dist/ReactCrop.css'
import ReactCrop, { centerCrop, makeAspectCrop, type Crop } from 'react-image-crop'
import { useAuth } from '../contexts/AuthContext'
import { useAuth } from '../contexts/useAuth'
import { updateMe, deleteUser, uploadAvatar, updatePhone, updateEmail } from '../apis'
import { UserOutlined, EditOutlined } from '@ant-design/icons'
import LoginModal from './LoginModal';