blob: 8ca4067ce8abb25a2ed3e4d7e08a34b9186aebbb [file] [log] [blame]
Krishyaf1d0ea82025-05-03 17:01:58 +08001import React, { useEffect, useState, useRef } from 'react';
2import './Promotion.css';
Krishya6bf199c2025-06-06 21:14:23 +08003import { useUser } from '../../../context/UserContext';
Krishyaf1d0ea82025-05-03 17:01:58 +08004
Krishyaf1d0ea82025-05-03 17:01:58 +08005const Promotion = () => {
Krishya6bf199c2025-06-06 21:14:23 +08006 const { user } = useUser();
Krishyaf1d0ea82025-05-03 17:01:58 +08007 const [promotions, setPromotions] = useState([]);
Krishya6bf199c2025-06-06 21:14:23 +08008 const [torrents, setTorrents] = useState([]);
Krishyaf1d0ea82025-05-03 17:01:58 +08009 const [loading, setLoading] = useState(true);
Krishyaf1d0ea82025-05-03 17:01:58 +080010 const [promoIndex, setPromoIndex] = useState(0);
Krishyaf1d0ea82025-05-03 17:01:58 +080011 const promoTimerRef = useRef(null);
Krishyaf1d0ea82025-05-03 17:01:58 +080012
Krishya6bf199c2025-06-06 21:14:23 +080013 // 新增:控制创建对话框显示
14 const [showCreateDialog, setShowCreateDialog] = useState(false);
15
16 // 创建促销活动表单状态
17 const [formData, setFormData] = useState({
18 name: '',
19 startTime: '',
20 endTime: '',
21 discountPercentage: '',
22 uploadCoeff: '',
23 downloadCoeff: '',
24 description: ''
25 });
26
Krishyaf1d0ea82025-05-03 17:01:58 +080027 useEffect(() => {
28 fetchData();
Krishya6bf199c2025-06-06 21:14:23 +080029 fetchTorrentList();
Krishyaf1d0ea82025-05-03 17:01:58 +080030 }, []);
31
Krishyaf1d0ea82025-05-03 17:01:58 +080032 useEffect(() => {
33 if (promotions.length === 0) return;
Krishyaf1d0ea82025-05-03 17:01:58 +080034 clearInterval(promoTimerRef.current);
35 promoTimerRef.current = setInterval(() => {
36 setPromoIndex(prev => (prev + 1) % promotions.length);
37 }, 5000);
38 return () => clearInterval(promoTimerRef.current);
39 }, [promotions]);
40
Krishyaf1d0ea82025-05-03 17:01:58 +080041 const fetchData = async () => {
42 try {
Krishya6bf199c2025-06-06 21:14:23 +080043 const response = await fetch('/seeds/promotions');
44 const json = await response.json();
45 const promoData = Array.isArray(json?.data) ? json.data : [];
Krishyaf1d0ea82025-05-03 17:01:58 +080046 setPromotions(promoData);
Krishyaf1d0ea82025-05-03 17:01:58 +080047 } catch (error) {
Krishya8f2fec82025-06-04 21:54:46 +080048 console.error('获取促销活动失败:', error);
Krishyaf1d0ea82025-05-03 17:01:58 +080049 } finally {
50 setLoading(false);
51 }
52 };
53
Krishya6bf199c2025-06-06 21:14:23 +080054 const fetchTorrentList = async () => {
55 try {
56 const response = await fetch('/seeds/list');
57 const json = await response.json();
58 const torrentList = Array.isArray(json?.data) ? json.data : [];
59 setTorrents(torrentList);
60 } catch (error) {
61 console.error('获取种子列表失败:', error);
62 }
63 };
64
65 // 打开创建促销活动弹窗
66 const openCreateDialog = () => {
67 // 重置表单数据
68 setFormData({
69 name: '',
70 startTime: '',
71 endTime: '',
72 discountPercentage: '',
73 uploadCoeff: '',
74 downloadCoeff: '',
75 description: ''
76 });
77 setShowCreateDialog(true);
78 };
79
80 // 关闭弹窗
81 const closeCreateDialog = () => {
82 setShowCreateDialog(false);
83 };
84
85 // 处理表单输入变化
86 const handleInputChange = (e) => {
87 const { name, value } = e.target;
88 setFormData(prev => ({
89 ...prev,
90 [name]: value
91 }));
92 };
93
94 // 提交创建促销活动
95 const handleCreatePromotion = async () => {
96 if (torrents.length === 0) {
97 alert('没有可用的种子,请先上传种子');
98 return;
99 }
100 if (!formData.name.trim()) {
101 alert('促销名称不能为空');
102 return;
103 }
104 if (!formData.startTime || !formData.endTime) {
105 alert('促销开始时间和结束时间不能为空');
106 return;
107 }
108 if (new Date(formData.startTime) >= new Date(formData.endTime)) {
109 alert('促销结束时间必须晚于开始时间');
110 return;
111 }
112 if (!formData.discountPercentage || isNaN(formData.discountPercentage)) {
113 alert('折扣百分比必须是数字');
114 return;
115 }
116
117 const applicableTorrentIds = torrents.map(t => t.id);
118
119 const newPromo = {
120 name: formData.name,
121 startTime: new Date(formData.startTime).toISOString(),
122 endTime: new Date(formData.endTime).toISOString(),
123 discountPercentage: Number(formData.discountPercentage),
124 uploadCoeff: formData.uploadCoeff ? Number(formData.uploadCoeff) : undefined,
125 downloadCoeff: formData.downloadCoeff ? Number(formData.downloadCoeff) : undefined,
126 applicableTorrentIds: JSON.stringify(applicableTorrentIds), // ✅ 关键修改
127 description: formData.description
128 };
129
130
131 try {
132 const res = await fetch('/seeds/promotions', {
133 method: 'POST',
134 headers: { 'Content-Type': 'application/json' },
135 body: JSON.stringify(newPromo)
136 });
137 const json = await res.json();
138 if (json.code === 200) {
139 alert('促销活动创建成功');
140 fetchData();
141 setShowCreateDialog(false);
142 } else {
143 alert('创建失败: ' + (json.msg || '未知错误'));
144 }
145 } catch (err) {
146 console.error('创建促销失败:', err);
147 alert('创建促销失败');
148 }
149 };
150
151 const handleDeletePromotion = async (promotionId) => {
152 if (!window.confirm('确认删除该促销活动吗?')) return;
153
154 try {
155 const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
156 const json = await res.json();
157 if (json.success) {
158 alert('删除成功');
159 fetchData();
160 } else {
161 alert('删除失败: ' + json.message);
162 }
163 } catch (err) {
164 console.error('删除失败:', err);
165 }
166 };
167
168 const isAdmin = user?.role === 'admin';
169 const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
170 const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
171 const currentPromo = promotions[promoIndex];
172
Krishyaf1d0ea82025-05-03 17:01:58 +0800173 if (loading) {
174 return <div className="promotion-container">加载中...</div>;
175 }
176
Krishyaf1d0ea82025-05-03 17:01:58 +0800177 return (
178 <div className="promotion-container carousel-container">
Krishyaf1d0ea82025-05-03 17:01:58 +0800179 <section className="carousel-section">
180 <h2>当前促销活动</h2>
Krishya6bf199c2025-06-06 21:14:23 +0800181
182 {isAdmin && (
183 <button className="create-btn" onClick={openCreateDialog}>
184 创建促销活动
185 </button>
186 )}
187
Krishya2283d882025-05-27 22:25:19 +0800188 {promotions.length === 0 || !currentPromo ? (
Krishyaf1d0ea82025-05-03 17:01:58 +0800189 <div className="empty-state">暂无促销活动</div>
190 ) : (
191 <div
192 className="carousel"
193 onMouseEnter={() => clearInterval(promoTimerRef.current)}
194 onMouseLeave={() => {
195 promoTimerRef.current = setInterval(() => {
196 setPromoIndex(prev => (prev + 1) % promotions.length);
197 }, 3000);
198 }}
199 >
200 <button className="arrow left" onClick={prevPromo}>&lt;</button>
201 <div className="slide">
Krishya2e0f49a2025-05-29 10:59:01 +0800202 <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
Krishyaf1d0ea82025-05-03 17:01:58 +0800203 <div><strong>促销时间:</strong>
Krishya2e0f49a2025-05-29 10:59:01 +0800204 {currentPromo?.pStartTime && currentPromo?.pEndTime
205 ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
Krishya2283d882025-05-27 22:25:19 +0800206 : '未知'}
Krishyaf1d0ea82025-05-03 17:01:58 +0800207 </div>
Krishya2e0f49a2025-05-29 10:59:01 +0800208 <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
209 <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
Krishya2283d882025-05-27 22:25:19 +0800210 {currentPromo?.description && (
Krishya2e0f49a2025-05-29 10:59:01 +0800211 <div><strong>描述:</strong>{currentPromo.description}</div>
Krishyaf1d0ea82025-05-03 17:01:58 +0800212 )}
Krishya6bf199c2025-06-06 21:14:23 +0800213 {isAdmin && (
214 <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
215 删除该活动
216 </button>
217 )}
Krishyaf1d0ea82025-05-03 17:01:58 +0800218 </div>
219 <button className="arrow right" onClick={nextPromo}>&gt;</button>
220 </div>
221 )}
222 </section>
Krishya6bf199c2025-06-06 21:14:23 +0800223
224 {/* 创建促销活动弹窗 */}
225 {showCreateDialog && (
226 <div className="dialog-overlay">
227 <div className="dialog">
228 <h3>创建促销活动</h3>
229 <div className="form-item">
230 <label>促销名称:</label>
231 <input
232 type="text"
233 name="name"
234 value={formData.name}
235 onChange={handleInputChange}
236 placeholder="请输入促销名称"
237 />
238 </div>
239 <div className="form-item">
240 <label>开始时间:</label>
241 <input
242 type="datetime-local"
243 name="startTime"
244 value={formData.startTime}
245 onChange={handleInputChange}
246 />
247 </div>
248 <div className="form-item">
249 <label>结束时间:</label>
250 <input
251 type="datetime-local"
252 name="endTime"
253 value={formData.endTime}
254 onChange={handleInputChange}
255 />
256 </div>
257 <div className="form-item">
258 <label>折扣百分比(数字):</label>
259 <input
260 type="number"
261 name="discountPercentage"
262 value={formData.discountPercentage}
263 onChange={handleInputChange}
264 placeholder="例如:20 表示 20% 折扣"
265 min="0"
266 max="100"
267 />
268 </div>
269 <div className="form-item">
270 <label>上传奖励系数(可选):</label>
271 <input
272 type="number"
273 name="uploadCoeff"
274 value={formData.uploadCoeff}
275 onChange={handleInputChange}
276 placeholder="例如:1.5"
277 step="0.1"
278 />
279 </div>
280 <div className="form-item">
281 <label>下载折扣系数(可选):</label>
282 <input
283 type="number"
284 name="downloadCoeff"
285 value={formData.downloadCoeff}
286 onChange={handleInputChange}
287 placeholder="例如:0.8"
288 step="0.1"
289 />
290 </div>
291 <div className="form-item">
292 <label>描述(可选):</label>
293 <textarea
294 name="description"
295 value={formData.description}
296 onChange={handleInputChange}
297 placeholder="促销活动描述"
298 rows={3}
299 />
300 </div>
301 <div className="dialog-buttons">
302 <button onClick={handleCreatePromotion}>确定</button>
303 <button onClick={closeCreateDialog}>取消</button>
304 </div>
305 </div>
306 </div>
307 )}
Krishyaf1d0ea82025-05-03 17:01:58 +0800308 </div>
309 );
310};
311
312export default Promotion;
Krishya2283d882025-05-27 22:25:19 +0800313
Krishya6bf199c2025-06-06 21:14:23 +0800314
315// import React, { useEffect, useState, useRef } from 'react';
316// import './Promotion.css';
317// import { useUser } from '../../../context/UserContext';
318
319// const Promotion = () => {
320// const { user } = useUser();
321// const [promotions, setPromotions] = useState([]);
322// const [torrents, setTorrents] = useState([]);
323// const [loading, setLoading] = useState(true);
324// const [promoIndex, setPromoIndex] = useState(0);
325// const promoTimerRef = useRef(null);
326
327// // 新增:控制模态框显示与表单状态
328// const [showCreateModal, setShowCreateModal] = useState(false);
329// const [formData, setFormData] = useState({
330// name: '',
331// description: '',
332// discountPercentage: 0,
333// startTime: '',
334// endTime: '',
335// applicableTorrentIds: [],
336// });
337
338// useEffect(() => {
339// fetchData();
340// fetchTorrentList();
341// }, []);
342
343// useEffect(() => {
344// if (promotions.length === 0) return;
345// clearInterval(promoTimerRef.current);
346// promoTimerRef.current = setInterval(() => {
347// setPromoIndex(prev => (prev + 1) % promotions.length);
348// }, 5000);
349// return () => clearInterval(promoTimerRef.current);
350// }, [promotions]);
351
352// const fetchData = async () => {
353// try {
354// const response = await fetch('/seeds/promotions');
355// const json = await response.json();
356// const promoData = Array.isArray(json?.data) ? json.data : [];
357// setPromotions(promoData);
358// } catch (error) {
359// console.error('获取促销活动失败:', error);
360// } finally {
361// setLoading(false);
362// }
363// };
364
365// const fetchTorrentList = async () => {
366// try {
367// const response = await fetch('/seeds/list');
368// const json = await response.json();
369// const torrentList = Array.isArray(json?.data) ? json.data : [];
370// setTorrents(torrentList);
371// } catch (error) {
372// console.error('获取种子列表失败:', error);
373// }
374// };
375
376// // 打开模态框时,重置表单数据,默认设置时间并填入所有种子ID
377// const openCreateModal = () => {
378// if (torrents.length === 0) {
379// alert('没有可用的种子,请先上传种子');
380// return;
381// }
382// setFormData({
383// name: '',
384// description: '',
385// discountPercentage: 20,
386// startTime: new Date().toISOString().slice(0, 16), // 用于datetime-local输入框,格式 YYYY-MM-DDTHH:mm
387// endTime: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 16),
388// applicableTorrentIds: torrents.map(t => t.id),
389// });
390// setShowCreateModal(true);
391// };
392
393// // 表单输入处理
394// const handleInputChange = (e) => {
395// const { name, value } = e.target;
396// setFormData(prev => ({
397// ...prev,
398// [name]: name === 'discountPercentage' ? Number(value) : value,
399// }));
400// };
401
402// // 点击确定提交创建
403// const handleCreateConfirm = async () => {
404// if (!formData.name) {
405// alert('促销名称不能为空');
406// return;
407// }
408// if (!formData.startTime || !formData.endTime) {
409// alert('请选择开始时间和结束时间');
410// return;
411// }
412// if (formData.discountPercentage <= 0 || formData.discountPercentage >= 100) {
413// alert('折扣百分比应在1-99之间');
414// return;
415// }
416// if (!formData.applicableTorrentIds.length) {
417// alert('请选择适用的种子');
418// return;
419// }
420
421// // 准备发送数据,适配后端字段名
422// const newPromo = {
423// name: formData.name,
424// description: formData.description,
425// discountPercentage: formData.discountPercentage,
426// startTime: new Date(formData.startTime).toISOString(),
427// endTime: new Date(formData.endTime).toISOString(),
428// applicableTorrentIds: formData.applicableTorrentIds,
429// };
430
431// try {
432// const res = await fetch('/seeds/promotions', {
433// method: 'POST',
434// headers: { 'Content-Type': 'application/json' },
435// body: JSON.stringify(newPromo),
436// });
437// const json = await res.json();
438// if (json.code === 200) {
439// alert('促销活动创建成功');
440// setShowCreateModal(false);
441// fetchData();
442// } else {
443// alert('创建失败: ' + (json.msg || '未知错误'));
444// }
445// } catch (err) {
446// console.error('创建促销失败:', err);
447// alert('创建促销失败');
448// }
449// };
450
451// const handleCancel = () => {
452// setShowCreateModal(false);
453// };
454
455// const handleDeletePromotion = async (promotionId) => {
456// if (!window.confirm('确认删除该促销活动吗?')) return;
457
458// try {
459// const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
460// const json = await res.json();
461// if (json.success) {
462// alert('删除成功');
463// fetchData();
464// } else {
465// alert('删除失败: ' + json.message);
466// }
467// } catch (err) {
468// console.error('删除失败:', err);
469// }
470// };
471
472// const isAdmin = user?.role === 'admin';
473// const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
474// const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
475// const currentPromo = promotions[promoIndex];
476
477// if (loading) {
478// return <div className="promotion-container">加载中...</div>;
479// }
480
481// return (
482// <div className="promotion-container carousel-container">
483// <section className="carousel-section">
484// <h2>当前促销活动</h2>
485
486// {isAdmin && (
487// <button className="create-btn" onClick={openCreateModal}>
488// 创建促销活动
489// </button>
490// )}
491
492// {promotions.length === 0 || !currentPromo ? (
493// <div className="empty-state">暂无促销活动</div>
494// ) : (
495// <div
496// className="carousel"
497// onMouseEnter={() => clearInterval(promoTimerRef.current)}
498// onMouseLeave={() => {
499// promoTimerRef.current = setInterval(() => {
500// setPromoIndex(prev => (prev + 1) % promotions.length);
501// }, 3000);
502// }}
503// >
504// <button className="arrow left" onClick={prevPromo}>&lt;</button>
505// <div className="slide">
506// <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
507// <div><strong>促销时间:</strong>
508// {currentPromo?.startTime && currentPromo?.endTime
509// ? `${new Date(currentPromo.startTime).toLocaleString()} ~ ${new Date(currentPromo.endTime).toLocaleString()}`
510// : '未知'}
511// </div>
512// <div><strong>折扣百分比:</strong>{currentPromo?.discountPercentage ?? '无'}</div>
513// {currentPromo?.description && (
514// <div><strong>描述:</strong>{currentPromo.description}</div>
515// )}
516// {isAdmin && (
517// <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
518// 删除该活动
519// </button>
520// )}
521// </div>
522// <button className="arrow right" onClick={nextPromo}>&gt;</button>
523// </div>
524// )}
525// </section>
526
527// {/* 创建促销模态框 */}
528// {showCreateModal && (
529// <div className="modal-overlay">
530// <div className="modal-content">
531// <h3>创建促销活动</h3>
532// <label>
533// 促销名称:
534// <input
535// type="text"
536// name="name"
537// value={formData.name}
538// onChange={handleInputChange}
539// />
540// </label>
541// <label>
542// 描述:
543// <textarea
544// name="description"
545// value={formData.description}
546// onChange={handleInputChange}
547// rows={3}
548// />
549// </label>
550// <label>
551// 折扣百分比:
552// <input
553// type="number"
554// name="discountPercentage"
555// value={formData.discountPercentage}
556// min={1}
557// max={99}
558// onChange={handleInputChange}
559// />
560// </label>
561// <label>
562// 开始时间:
563// <input
564// type="datetime-local"
565// name="startTime"
566// value={formData.startTime}
567// onChange={handleInputChange}
568// />
569// </label>
570// <label>
571// 结束时间:
572// <input
573// type="datetime-local"
574// name="endTime"
575// value={formData.endTime}
576// onChange={handleInputChange}
577// />
578// </label>
579// <label>
580// 适用种子ID(逗号分隔,可留空默认所有):
581// <input
582// type="text"
583// name="applicableTorrentIds"
584// value={formData.applicableTorrentIds.join(',')}
585// onChange={(e) => {
586// const ids = e.target.value
587// .split(',')
588// .map(id => id.trim())
589// .filter(id => id !== '')
590// .map(id => Number(id))
591// .filter(id => !isNaN(id));
592// setFormData(prev => ({ ...prev, applicableTorrentIds: ids }));
593// }}
594// />
595// </label>
596
597// <div className="modal-buttons">
598// <button onClick={handleCreateConfirm}>确定</button>
599// <button onClick={handleCancel}>取消</button>
600// </div>
601// </div>
602// </div>
603// )}
604
605// {/* 模态框简单样式 */}
606// <style>{`
607// .modal-overlay {
608// position: fixed;
609// top: 0; left: 0; right: 0; bottom: 0;
610// background: rgba(0,0,0,0.4);
611// display: flex;
612// justify-content: center;
613// align-items: center;
614// z-index: 999;
615// }
616// .modal-content {
617// background: white;
618// padding: 20px;
619// border-radius: 6px;
620// width: 320px;
621// max-width: 90%;
622// }
623// .modal-content label {
624// display: block;
625// margin-bottom: 10px;
626// font-size: 14px;
627// }
628// .modal-content input[type="text"],
629// .modal-content input[type="number"],
630// .modal-content input[type="datetime-local"],
631// .modal-content textarea {
632// width: 100%;
633// box-sizing: border-box;
634// padding: 5px;
635// font-size: 14px;
636// margin-top: 4px;
637// }
638// .modal-buttons {
639// margin-top: 15px;
640// text-align: right;
641// }
642// .modal-buttons button {
643// margin-left: 10px;
644// padding: 6px 12px;
645// font-size: 14px;
646// }
647// `}</style>
648// </div>
649// );
650// };
651
652// export default Promotion;
653
654
655// import React, { useEffect, useState, useRef } from 'react';
656// import './Promotion.css';
657// import { useUser } from '../../../context/UserContext';
658
659// const Promotion = () => {
660// const { user } = useUser();
661// const [promotions, setPromotions] = useState([]);
662// const [torrents, setTorrents] = useState([]); // 新增,存放种子列表
663// const [loading, setLoading] = useState(true);
664// const [promoIndex, setPromoIndex] = useState(0);
665// const promoTimerRef = useRef(null);
666
667// useEffect(() => {
668// fetchData();
669// fetchTorrentList(); // 新增,获取种子列表
670// }, []);
671
672// useEffect(() => {
673// if (promotions.length === 0) return;
674// clearInterval(promoTimerRef.current);
675// promoTimerRef.current = setInterval(() => {
676// setPromoIndex(prev => (prev + 1) % promotions.length);
677// }, 5000);
678// return () => clearInterval(promoTimerRef.current);
679// }, [promotions]);
680
681// // 获取促销数据
682// const fetchData = async () => {
683// try {
684// const response = await fetch('/seeds/promotions');
685// const json = await response.json();
686// const promoData = Array.isArray(json?.data) ? json.data : [];
687// setPromotions(promoData);
688// } catch (error) {
689// console.error('获取促销活动失败:', error);
690// } finally {
691// setLoading(false);
692// }
693// };
694
695// // 获取种子列表,赋值给torrents
696// const fetchTorrentList = async () => {
697// try {
698// const response = await fetch('/seeds/list');
699// const json = await response.json();
700// const torrentList = Array.isArray(json?.data) ? json.data : [];
701// setTorrents(torrentList);
702// } catch (error) {
703// console.error('获取种子列表失败:', error);
704// }
705// };
706
707// // 创建促销时,自动使用当前种子的id列表,而不是写死
708// const handleCreatePromotion = async () => {
709// if (torrents.length === 0) {
710// alert('没有可用的种子,请先上传种子');
711// return;
712// }
713
714// const applicableTorrentIds = torrents.map(t => t.id); // 获取所有种子id数组
715
716// const newPromo = {
717// name: '测试促销活动',
718// startTime: new Date().toISOString(),
719// endTime: new Date(Date.now() + 7 * 86400000).toISOString(),
720// discountPercentage: 20,
721// applicableTorrentIds: applicableTorrentIds, // 动态传入种子ID数组
722// description: '这是一个测试促销活动'
723// };
724
725// try {
726// const res = await fetch('/seeds/promotions', {
727// method: 'POST',
728// headers: {
729// 'Content-Type': 'application/json'
730// },
731// body: JSON.stringify(newPromo)
732// });
733// const json = await res.json();
734// if (json.code === 200) {
735// alert('促销活动创建成功');
736// fetchData();
737// } else {
738// alert('创建失败: ' + (json.msg || '未知错误'));
739// }
740// } catch (err) {
741// console.error('创建促销失败:', err);
742// alert('创建促销失败');
743// }
744// };
745
746// const handleDeletePromotion = async (promotionId) => {
747// if (!window.confirm('确认删除该促销活动吗?')) return;
748
749// try {
750// const res = await fetch(`/seeds/promotions/${promotionId}`, {
751// method: 'DELETE'
752// });
753// const json = await res.json();
754// if (json.success) {
755// alert('删除成功');
756// fetchData();
757// } else {
758// alert('删除失败: ' + json.message);
759// }
760// } catch (err) {
761// console.error('删除失败:', err);
762// }
763// };
764
765// const isAdmin = user?.role === 'admin';
766// const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
767// const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
768// const currentPromo = promotions[promoIndex];
769
770// if (loading) {
771// return <div className="promotion-container">加载中...</div>;
772// }
773
774// return (
775// <div className="promotion-container carousel-container">
776// <section className="carousel-section">
777// <h2>当前促销活动</h2>
778
779// {isAdmin && (
780// <button className="create-btn" onClick={handleCreatePromotion}>
781// 创建促销活动
782// </button>
783// )}
784
785// {promotions.length === 0 || !currentPromo ? (
786// <div className="empty-state">暂无促销活动</div>
787// ) : (
788// <div
789// className="carousel"
790// onMouseEnter={() => clearInterval(promoTimerRef.current)}
791// onMouseLeave={() => {
792// promoTimerRef.current = setInterval(() => {
793// setPromoIndex(prev => (prev + 1) % promotions.length);
794// }, 3000);
795// }}
796// >
797// <button className="arrow left" onClick={prevPromo}>&lt;</button>
798// <div className="slide">
799// <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
800// <div><strong>促销时间:</strong>
801// {currentPromo?.pStartTime && currentPromo?.pEndTime
802// ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
803// : '未知'}
804// </div>
805// <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
806// <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
807// {currentPromo?.description && (
808// <div><strong>描述:</strong>{currentPromo.description}</div>
809// )}
810// {isAdmin && (
811// <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
812// 删除该活动
813// </button>
814// )}
815// </div>
816// <button className="arrow right" onClick={nextPromo}>&gt;</button>
817// </div>
818// )}
819// </section>
820// </div>
821// );
822// };
823
824// export default Promotion;
825