diff --git a/src/pages/user/edit/Profile.tsx b/src/pages/user/edit/Profile.tsx index 22120ba..6d65da1 100644 --- a/src/pages/user/edit/Profile.tsx +++ b/src/pages/user/edit/Profile.tsx @@ -1,14 +1,16 @@ -import { Form, Input } from 'antd'; +import { Button, Form, Input } from 'antd'; import { useUserStore } from '../store'; -import { useEffect } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useShallow } from 'zustand/react/shallow'; import { isObjectNull } from '@/utils/is-null'; import { useLayoutStore } from '@/modules/layout/store'; import { AvatarUpload } from '../module/AvatarUpload'; import { UploadOutlined } from '@ant-design/icons'; import PandaPNG from '@/assets/panda.png'; +import { FileUpload } from '../module/FileUpload'; export const Profile = () => { const [form] = Form.useForm(); + const ref = useRef(null); const userStore = useUserStore( useShallow((state) => { return { @@ -17,18 +19,20 @@ export const Profile = () => { formData: state.formData, updateData: state.updateData, setFormData: state.setFormData, + updateSelf: state.updateSelf, }; }), ); - + const [avatar, setAvatar] = useState(''); const layoutStore = useLayoutStore( useShallow((state) => { return { me: state.me, + setMe: state.setMe, }; }), ); - const avatar = layoutStore.me?.avatar; + // const avatar = layoutStore.me?.avatar; useEffect(() => { const fromData = layoutStore.me; if (isObjectNull(fromData)) { @@ -36,8 +40,20 @@ export const Profile = () => { } else { form.setFieldsValue(fromData); } - console.log('fromData', fromData); + setAvatar(fromData.avatar || ''); }, [layoutStore.me]); + const onChange = (path: string) => { + let url = '/resources/' + path; + console.log('path', url); + form.setFieldsValue({ avatar: url }); + setAvatar(url + '?t=' + new Date().getTime()); + }; + const onFinish = async (values) => { + const newMe = await userStore.updateSelf(values); + if (newMe) { + layoutStore.setMe(newMe); + } + }; return (
@@ -51,23 +67,24 @@ export const Profile = () => {
- - + { - console.log('upload'); - }} - /> +
+ { + ref.current?.open?.(); + }} + /> + +
} />
@@ -75,13 +92,9 @@ export const Profile = () => {
- +
diff --git a/src/pages/user/module/AvatarUpload.tsx b/src/pages/user/module/AvatarUpload.tsx index 285bf59..5f5c514 100644 --- a/src/pages/user/module/AvatarUpload.tsx +++ b/src/pages/user/module/AvatarUpload.tsx @@ -51,14 +51,19 @@ export const AvatarUpload = () => { console.log('file', file); return ''; }; + const customAction = (file) => { + console.log('file', file); + } return ( {imageUrl ? avatar : uploadButton} diff --git a/src/pages/user/module/FileUpload.tsx b/src/pages/user/module/FileUpload.tsx new file mode 100644 index 0000000..d4bd23f --- /dev/null +++ b/src/pages/user/module/FileUpload.tsx @@ -0,0 +1,80 @@ +import { message } from 'antd'; +import { useImperativeHandle, useRef, forwardRef } from 'react'; +import type { GetProp, UploadProps } from 'antd'; +type FileTypeOrg = Parameters>[0]; + +export type FileType = { + name: string; + size: number; + lastModified: number; + webkitRelativePath: string; // 包含name +}; + +const beforeUpload = (file: FileTypeOrg) => { + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; + if (!isJpgOrPng) { + message.error('You can only upload JPG/PNG file!'); + } + const isLt2M = file.size / 1024 / 1024 < 2; + if (!isLt2M) { + message.error('Image must smaller than 2MB!'); + } + return isJpgOrPng && isLt2M; +}; +type Props = { + onChange: (path: string) => void; +}; +export const FileUpload = forwardRef((props, ref) => { + const inputRef = useRef(null); + const onChange = async (e) => { + if (!beforeUpload(e.target.files[0])) { + return; + } + console.log(e.target.files); + const file = e.target.files[0]; + const endType = file.name.split('.').pop(); + const formData = new FormData(); + formData.append('file', file, `avatar.${endType}`); // 保留文件夹路径 + const res = await fetch('/api/upload', { + method: 'POST', + body: formData, // + headers: { + Authorization: 'Bearer ' + localStorage.getItem('token'), + }, + }).then((res) => res.json()); + if (res?.code === 200) { + console.log('res', res); + // + const [file] = res.data; + const { path } = file || {}; + props?.onChange?.(path); + // + } else { + message.error(res.message || 'Request failed'); + } + // 清理之前上传的文件 + e.target.value = ''; + }; + // 把ref 传递到上层 + useImperativeHandle(ref, () => { + return { + open: () => { + inputRef.current?.click(); + }, + }; + }); + return ( +
+ +
+ ); +}); diff --git a/src/pages/user/store/index.ts b/src/pages/user/store/index.ts index cede8cf..2eb44c8 100644 --- a/src/pages/user/store/index.ts +++ b/src/pages/user/store/index.ts @@ -11,6 +11,7 @@ type UserStore = { list: any[]; getList: () => Promise; updateData: (data: any) => Promise; + updateSelf: (data: any) => Promise; deleteData: (id: string) => Promise; }; export const useUserStore = create((set, get) => { @@ -51,6 +52,22 @@ export const useUserStore = create((set, get) => { message.error(res.message || 'Request failed'); } }, + updateSelf: async (data) => { + const loaded = message.loading('Action in progress..', 0); + const res = await query.post({ + path: 'user', + key: 'updateSelf', + data, + }); + loaded(); + if (res.code === 200) { + message.success('Success'); + set({ formData: res.data }); + return res.data; + } else { + message.error(res.message || 'Request failed'); + } + }, deleteData: async (id) => { const { getList } = get(); const res = await query.post({ diff --git a/theme b/theme index bff9266..c4e0ec2 160000 --- a/theme +++ b/theme @@ -1 +1 @@ -Subproject commit bff92667f4bed0f8d15ed5e6fe1c75ce22480bd2 +Subproject commit c4e0ec2a5322503a4755d9b42d8f628d76ba0b28