blob: a7e48029cfe14b90a2957cd6f6265ad1547a9489 [file] [log] [blame]
LaoeGaoci656ab002025-06-05 17:48:28 +08001'use client';
2
3import { useRef, useState } from 'react';
4import { Avatar } from 'primereact/avatar';
5import { Button } from 'primereact/button';
6// 弹窗
7import { Dialog } from 'primereact/dialog';
8// 头像下拉框
9import { OverlayPanel } from 'primereact/overlaypanel';
10// 输入框
11import { FloatLabel } from "primereact/floatlabel";
12import { InputText } from 'primereact/inputtext';
13// 页面跳转
14import Link from 'next/link';
15// 文件上传
16import { FileUpload } from 'primereact/fileupload';
17// 通知
18import { Toast } from 'primereact/toast';
19// 接口传输
20import axios from 'axios';
LaoeGaocid0773912025-06-09 00:38:40 +080021import { useLocalStorage } from '../../hook/useLocalStorage';
LaoeGaoci656ab002025-06-05 17:48:28 +080022// 样式
23import './user-avatar.scss';
LaoeGaocid0773912025-06-09 00:38:40 +080024interface User {
25 Id: number;
26}
LaoeGaoci656ab002025-06-05 17:48:28 +080027// 用户下拉框
28export default function UserAvatar() {
LaoeGaocid0773912025-06-09 00:38:40 +080029 const user = useLocalStorage<User>('user');
30 const userId: number = user?.Id ?? -1;
31
LaoeGaoci656ab002025-06-05 17:48:28 +080032 // 功能选项
33 const op = useRef<OverlayPanel>(null);
34 let hoverTimeout: NodeJS.Timeout;
35 // 通知
36 const toast = useRef<Toast>(null);
37 // 控制三个弹窗可见性
38 const [showEditSignature, setShowEditSignature] = useState(false);
39 const [showEditAvatar, setShowEditAvatar] = useState(false);
40 const [showEditPassword, setShowEditPassword] = useState(false);
41 // 头像URL
42 const [avatarUrl, setAvatar] = useState<string>('');
43 // 签名
44 const [signValue, setSignValue] = useState<string>('');
45 // 新密码
46 const [passwardValue, setPasswardValue] = useState<string>('');
47 const [newPasswardValue, setNewPasswardValue] = useState<string>('');
48 // 老密码
49 const [oldPasswardValue, setOldPasswardValue] = useState<string>('');
50
51
52 const handleMouseEnter = (event: React.MouseEvent) => {
53 clearTimeout(hoverTimeout);
54 op.current?.show(event, event.currentTarget);
55 };
56
57 const handleMouseLeave = () => {
58 hoverTimeout = setTimeout(() => {
59 op.current?.hide();
60 }, 300);
61 };
62
63
64 // 修改密码接口
65 const editPassward = async () => {
66 try {
67 await axios.put(process.env.PUBLIC_URL + `/user/password`, {
LaoeGaocid0773912025-06-09 00:38:40 +080068 params: { userId, password: oldPasswardValue, newPassword: passwardValue }
LaoeGaoci656ab002025-06-05 17:48:28 +080069 });
70 toast.current?.show({ severity: 'success', summary: 'success', detail: '修改密码成功' });
71 setShowEditPassword(false);
72 } catch (err) {
73 console.error('修改密码失败', err);
74 toast.current?.show({ severity: 'error', summary: 'error', detail: '修改密码失败' });
75 }
76 }
77 // 修改签名接口
78 const editSign = async () => {
79 try {
80 await axios.put(process.env.PUBLIC_URL + `/user/signature`, {
LaoeGaocid0773912025-06-09 00:38:40 +080081 params: { userId, signature: signValue }
LaoeGaoci656ab002025-06-05 17:48:28 +080082 });
83 toast.current?.show({ severity: 'success', summary: 'success', detail: '修改签名成功' });
84 setShowEditSignature(false);
85 } catch (err) {
86 console.error('修改签名失败', err);
87 toast.current?.show({ severity: 'error', summary: 'error', detail: '修改签名失败' });
88 }
89 }
90
91 // 修改头像接口
92 const editAvatar = async () => {
93 try {
94 await axios.put(process.env.PUBLIC_URL + `/user/avatar`, {
LaoeGaocid0773912025-06-09 00:38:40 +080095 params: { userId, avatar: avatarUrl }
LaoeGaoci656ab002025-06-05 17:48:28 +080096 });
97 toast.current?.show({ severity: 'success', summary: 'success', detail: '修改头像成功' });
98 setShowEditAvatar(false);
99 } catch (err) {
100 console.error('修改头像失败', err);
101 toast.current?.show({ severity: 'error', summary: 'error', detail: '修改头像失败' });
102 }
103 }
104 return (
105 <div
106 onMouseEnter={handleMouseEnter}
107 onMouseLeave={handleMouseLeave}
108 className="user-avatar-wrapper"
109 >
110 <Toast ref={toast}></Toast>
111 <Link href="/user" className="no-underline">
112 <Avatar
113 image="/images/avatar/asiyajavayant.png"
114 size="large"
115 shape="circle"
116 className="user-avatar-link"
117 />
118 </Link>
119
120 <OverlayPanel ref={op} dismissable={false}>
121 <div
122 onMouseEnter={() => clearTimeout(hoverTimeout)}
123 onMouseLeave={handleMouseLeave}
124 className="user-overlay-panel"
125 >
126 <Button
127 text
128 icon="pi pi-pencil"
129 label="修改签名"
130 onClick={() => setShowEditSignature(true)}
131 />
132 <Button
133 text
134 icon="pi pi-image"
135 label="修改头像"
136 onClick={() => setShowEditAvatar(true)}
137 />
138 <Button
139 text
140 icon="pi pi-unlock"
141 label="修改密码"
142 onClick={() => setShowEditPassword(true)}
143 />
144 </div>
145 </OverlayPanel>
146
147 {/* 修改签名弹窗 */}
148 <Dialog
149 header="修改签名"
150 visible={showEditSignature}
151 style={{ width: '30vw' }}
152 onHide={() => {
153 setSignValue('');
154 setShowEditSignature(false);
155 }}
156 modal
157 >
158 <div className="dialog-container">
159 <div className="dialog-input-group">
160 <FloatLabel>
161 <InputText id="username" value={signValue} onChange={(e) => setSignValue(e.target.value)} />
162 <label htmlFor="username">个性签名</label>
163 </FloatLabel>
164 </div>
165 <div className="dialog-button-group">
166 <Button label="确定" className="p-button-sm" onClick={() => editSign()} />
167 <Button
168 label="取消"
169 className="p-button-secondary p-button-sm"
170 onClick={() => {
171 setSignValue('');
172 setShowEditSignature(false);
173 }}
174 />
175 </div>
176 </div>
177 </Dialog>
178
179 {/* 修改头像弹窗 */}
180 <Dialog
181 header="修改头像"
182 visible={showEditAvatar}
183 style={{ display: 'flex', flexDirection: 'column', width: '30vw' }}
184 onHide={() => {
185 setAvatar('');
186 setShowEditAvatar(false);
187 }}
188 modal
189 >
190 <div className="dialog-container">
191 <FileUpload
192 mode="advanced"
193 name="file"
194 customUpload
195 uploadHandler={async (e) => {
196 const formData = new FormData();
197 formData.append("file", e.files[0]);
198
199 try {
200 const res = await axios.post(`${process.env.PUBLIC_URL}/file/avatar`, formData);
201
202 const fileUrl = res.data.url;
203 console.log(fileUrl);
204 setAvatar(fileUrl);
205 toast.current?.show({ severity: 'success', summary: '上传成功' });
206 } catch (error) {
207 console.log(error);
208 toast.current?.show({ severity: 'error', summary: '上传失败' });
209 }
210 }}
211 auto
212 accept="image/*"
213 chooseLabel="上传头像"
214 />
215
216 <div className="dialog-button-group">
217 <Button label="确定" className="p-button-sm" onClick={() => editAvatar()} />
218 <Button
219 label="取消"
220 className="p-button-secondary p-button-sm"
221 onClick={() => setShowEditAvatar(false)}
222 />
223 </div>
224 </div>
225 </Dialog>
226
227 {/* 修改密码弹窗 */}
228 <Dialog
229 header="修改密码"
230 visible={showEditPassword}
231 style={{ width: '30vw' }}
232 onHide={() => {
233 setOldPasswardValue('');
234 setPasswardValue('');
235 setNewPasswardValue('');
236 setShowEditPassword(false);
237 }}
238 modal
239 >
240 <div className="dialog-container">
241 <div className="dialog-input-group">
242 <FloatLabel>
243 <InputText id="username" value={oldPasswardValue} onChange={(e) => setOldPasswardValue(e.target.value)} />
244 <label htmlFor="username">输入旧密码</label>
245 </FloatLabel>
246 </div>
247 <div className="dialog-input-group">
248 <FloatLabel>
249 <InputText id="username" value={passwardValue} onChange={(e) => setPasswardValue(e.target.value)} />
250 <label htmlFor="username">更新密码</label>
251 </FloatLabel>
252 </div>
253 <div className="dialog-input-group">
254 <FloatLabel>
255 <InputText id="username" value={newPasswardValue} onChange={(e) => setNewPasswardValue(e.target.value)} />
256 <label htmlFor="username">确认密码</label>
257 </FloatLabel>
258 </div>
259 <div className="dialog-button-group">
260 <Button label="确定" className="p-button-sm" onClick={() => {
261 if (passwardValue !== newPasswardValue) {
262 toast.current?.show({
263 severity: 'warn',
264 summary: '两次密码不一致',
265 detail: '请确保新密码和确认密码一致',
266 });
267 return;
268 } else {
269 editPassward();
270 }
271 }} />
272 <Button
273 label="取消"
274 className="p-button-secondary p-button-sm"
275 onClick={() => {
276 setOldPasswardValue('');
277 setPasswardValue('');
278 setNewPasswardValue('');
279 setShowEditPassword(false);
280 }}
281 />
282 </div>
283 </div>
284 </Dialog>
285 </div>
286 );
287
288}