fix: harden uploads downloads and deployment config
This commit is contained in:
@@ -2,6 +2,24 @@ import axios from 'axios';
|
||||
import { message } from 'antd';
|
||||
import { API_CONFIG } from '../utils/config';
|
||||
|
||||
const parseFilenameFromDisposition = (contentDisposition) => {
|
||||
if (!contentDisposition) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const utf8Match = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i);
|
||||
if (utf8Match?.[1]) {
|
||||
try {
|
||||
return decodeURIComponent(utf8Match[1]);
|
||||
} catch {
|
||||
return utf8Match[1];
|
||||
}
|
||||
}
|
||||
|
||||
const simpleMatch = contentDisposition.match(/filename="?([^"]+)"?/i);
|
||||
return simpleMatch?.[1] || '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 下载作品原图
|
||||
* @param {number} workId - 作品ID
|
||||
@@ -34,7 +52,8 @@ export const downloadWork = async (workId, fileName = null) => {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName || `work_${workId}.jpg`;
|
||||
const dispositionName = parseFilenameFromDisposition(response.headers?.['content-disposition']);
|
||||
link.download = dispositionName || fileName || `work_${workId}`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
@@ -9,9 +9,47 @@ import { createPayment, queryPaymentStatus } from '../api/payment';
|
||||
import { downloadWork } from '../api/download';
|
||||
import { isLoggedIn } from '../api/auth';
|
||||
import { API_CONFIG } from '../utils/config';
|
||||
import Header from '../components/Header';
|
||||
import Footer from '../components/Footer';
|
||||
import './WorkDetail.css';
|
||||
import Header from '../components/Header';
|
||||
import Footer from '../components/Footer';
|
||||
import './WorkDetail.css';
|
||||
|
||||
const parseTags = (rawTags) => {
|
||||
if (!rawTags) {
|
||||
return [];
|
||||
}
|
||||
if (Array.isArray(rawTags)) {
|
||||
return rawTags.filter(Boolean);
|
||||
}
|
||||
if (typeof rawTags !== 'string') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const trimmed = rawTags.trim();
|
||||
if (!trimmed) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (trimmed.startsWith('[')) {
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed);
|
||||
return Array.isArray(parsed) ? parsed.filter(Boolean) : [];
|
||||
} catch {
|
||||
// 回退到逗号分隔解析,避免详情页白屏
|
||||
}
|
||||
}
|
||||
|
||||
return trimmed
|
||||
.split(',')
|
||||
.map((tag) => tag.trim())
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
const getDownloadFilename = (work) => {
|
||||
const imagePath = String(work?.original_image || '');
|
||||
const extMatch = imagePath.match(/\.[a-zA-Z0-9]+$/);
|
||||
const ext = extMatch ? extMatch[0] : '.jpg';
|
||||
return `${work?.title || 'work'}${ext}`;
|
||||
};
|
||||
|
||||
const WorkDetail = () => {
|
||||
const { id } = useParams();
|
||||
@@ -97,7 +135,7 @@ const WorkDetail = () => {
|
||||
}
|
||||
|
||||
// 尝试直接下载
|
||||
const result = await downloadWork(id, `${workData.title}.jpg`);
|
||||
const result = await downloadWork(id, getDownloadFilename(workData));
|
||||
|
||||
// 如果需要购买,显示购买确认弹窗
|
||||
if (!result.success && result.needPurchase) {
|
||||
@@ -148,7 +186,7 @@ const WorkDetail = () => {
|
||||
setPaymentUrl('');
|
||||
message.success('支付成功!开始下载...');
|
||||
// 重新尝试下载
|
||||
await downloadWork(id, `${workData.title}.jpg`);
|
||||
await downloadWork(id, getDownloadFilename(workData));
|
||||
}
|
||||
}
|
||||
}, 3000); // 每3秒检查一次
|
||||
@@ -212,7 +250,7 @@ const WorkDetail = () => {
|
||||
}
|
||||
|
||||
// 解析标签
|
||||
const tags = workData.tags ? (typeof workData.tags === 'string' ? JSON.parse(workData.tags) : workData.tags) : [];
|
||||
const tags = parseTags(workData.tags);
|
||||
|
||||
return (
|
||||
<div className="work-detail-page">
|
||||
|
||||
Reference in New Issue
Block a user