更新
This commit is contained in:
@@ -161,4 +161,35 @@ class RequestCancelManager {
|
||||
|
||||
// 导出单例实例
|
||||
export const requestDeduplicator = new RequestDeduplicator();
|
||||
export const requestCancelManager = new RequestCancelManager();
|
||||
export const requestCancelManager = new RequestCancelManager();
|
||||
|
||||
/**
|
||||
* 通用文件上传方法(支持图片、文件)
|
||||
* @param {File} file - 要上传的文件对象
|
||||
* @param {string} [uploadUrl='/v1/attachment/upload'] - 上传接口地址
|
||||
* @returns {Promise<string>} - 上传成功后返回文件url
|
||||
*/
|
||||
export async function uploadFile(file: File, uploadUrl: string = '/v1/attachment/upload'): Promise<string> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : '';
|
||||
const headers: Record<string, string> = {};
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||||
try {
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: formData,
|
||||
});
|
||||
const res = await response.json();
|
||||
if (res?.url) {
|
||||
return res.url;
|
||||
}
|
||||
if (res?.data?.url) {
|
||||
return res.data.url;
|
||||
}
|
||||
throw new Error(res?.msg || '文件上传失败');
|
||||
} catch (e: any) {
|
||||
throw new Error(e?.message || '文件上传失败');
|
||||
}
|
||||
}
|
||||
@@ -304,6 +304,7 @@ export function BasicSettings({
|
||||
|
||||
// 新增:用于文件选择的ref
|
||||
const uploadInputRef = useRef<HTMLInputElement>(null);
|
||||
const uploadOrderInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// 更新电话获客设置
|
||||
const handlePhoneSettingsUpdate = () => {
|
||||
@@ -648,6 +649,9 @@ export function BasicSettings({
|
||||
transition: "border 0.2s",
|
||||
textAlign: "center",
|
||||
position: "relative",
|
||||
height: 180 + 12, // 图片高度180+上下padding
|
||||
overflow: "hidden",
|
||||
minHeight: 192,
|
||||
}}
|
||||
onClick={() => handleMaterialSelect(material)}
|
||||
>
|
||||
@@ -675,40 +679,31 @@ export function BasicSettings({
|
||||
</button>
|
||||
{/* 删除自定义海报按钮 */}
|
||||
{isCustom && (
|
||||
<button
|
||||
type="button"
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 8,
|
||||
right: 8,
|
||||
width: 24,
|
||||
height: 24,
|
||||
width: 28,
|
||||
height: 28,
|
||||
background: "rgba(0,0,0,0.5)",
|
||||
border: "none",
|
||||
borderRadius: "50%",
|
||||
padding: 0,
|
||||
zIndex: 2,
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
lineHeight: 20,
|
||||
color: "#ffffff",
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemoveCustomPoster(material.id);
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: "#fff",
|
||||
fontWeight: 700,
|
||||
fontSize: 16,
|
||||
lineHeight: "24px",
|
||||
}}
|
||||
>
|
||||
×
|
||||
</span>
|
||||
</button>
|
||||
×
|
||||
</div>
|
||||
)}
|
||||
<img
|
||||
src={material.preview}
|
||||
@@ -719,12 +714,14 @@ export function BasicSettings({
|
||||
objectFit: "cover",
|
||||
borderRadius: 4,
|
||||
marginBottom: 0,
|
||||
display: "block",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
top: "-32px",
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
width: "100%",
|
||||
background: "rgba(0,0,0,0.5)",
|
||||
color: "#fff",
|
||||
@@ -733,6 +730,7 @@ export function BasicSettings({
|
||||
borderBottomLeftRadius: 4,
|
||||
borderBottomRightRadius: 4,
|
||||
textAlign: "center",
|
||||
zIndex: 3,
|
||||
}}
|
||||
>
|
||||
{material.name}
|
||||
@@ -753,7 +751,7 @@ export function BasicSettings({
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: 220,
|
||||
height: 190,
|
||||
}}
|
||||
onClick={() => uploadInputRef.current?.click()}
|
||||
>
|
||||
@@ -801,62 +799,75 @@ export function BasicSettings({
|
||||
index={0}
|
||||
/>
|
||||
</div>
|
||||
{/* 订单导入区块 */}
|
||||
{/* 订单导入区块优化 */}
|
||||
<div style={openOrder} className="my-4">
|
||||
<Button theme="default" onClick={() => setIsImportDialogOpen(true)}>
|
||||
{importedTags.length
|
||||
? `已导入订单(${importedTags.length})`
|
||||
: "导入订单"}
|
||||
</Button>
|
||||
<Dialog visible={isImportDialogOpen} onClose={handleImportDialogClose}>
|
||||
<div style={{ fontWeight: 600, fontSize: 16, marginBottom: 12 }}>
|
||||
导入订单
|
||||
</div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Button
|
||||
theme="primary"
|
||||
onClick={handleDownloadTemplate}
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
下载模板
|
||||
</Button>
|
||||
<div style={{ fontWeight: 500, marginBottom: 8 }}>订单表格上传</div>
|
||||
<div style={{ display: "flex", gap: 12, marginBottom: 4 }}>
|
||||
<Button
|
||||
type="button"
|
||||
style={{ display: "flex", alignItems: "center", gap: 4 }}
|
||||
theme="default"
|
||||
onClick={handleDownloadTemplate}
|
||||
>
|
||||
<span className="iconfont" style={{ fontSize: 18 }}>
|
||||
↓
|
||||
</span>{" "}
|
||||
下载模板
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
style={{ display: "flex", alignItems: "center", gap: 4 }}
|
||||
theme="default"
|
||||
onClick={() => uploadOrderInputRef.current?.click()}
|
||||
>
|
||||
<span className="iconfont" style={{ fontSize: 18 }}>
|
||||
↑
|
||||
</span>{" "}
|
||||
上传订单表格
|
||||
<input
|
||||
ref={uploadOrderInputRef}
|
||||
type="file"
|
||||
accept=".csv"
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
style={{ display: "none" }}
|
||||
onChange={handleFileImport}
|
||||
style={{ display: "inline-block" }}
|
||||
/>
|
||||
</div>
|
||||
{importedTags.length > 0 && (
|
||||
<Table
|
||||
columns={[
|
||||
{ colKey: "phone", title: "手机号" },
|
||||
{ colKey: "wechat", title: "微信号" },
|
||||
{ colKey: "source", title: "来源" },
|
||||
{ colKey: "orderAmount", title: "订单金额" },
|
||||
{ colKey: "orderDate", title: "下单日期" },
|
||||
]}
|
||||
data={importedTags}
|
||||
rowKey="phone"
|
||||
style={{ marginTop: 12 }}
|
||||
/>
|
||||
)}
|
||||
</Dialog>
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ color: "#888", fontSize: 13, marginBottom: 8 }}>
|
||||
支持 CSV、Excel 格式,上传后将文件保存到服务器
|
||||
</div>
|
||||
{/* 已导入数据表格可复用原有Table渲染 */}
|
||||
{importedTags.length > 0 && (
|
||||
<Table
|
||||
columns={[
|
||||
{ colKey: "phone", title: "手机号" },
|
||||
{ colKey: "wechat", title: "微信号" },
|
||||
{ colKey: "source", title: "来源" },
|
||||
{ colKey: "orderAmount", title: "订单金额" },
|
||||
{ colKey: "orderDate", title: "下单日期" },
|
||||
]}
|
||||
data={importedTags}
|
||||
rowKey="phone"
|
||||
style={{ marginTop: 12 }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{/* 电话获客设置区块,仅在选择电话获客场景时显示 */}
|
||||
{formData.scenario === "phone" && (
|
||||
{formData.scenario === 5 && (
|
||||
<div style={{ margin: "16px 0" }}>
|
||||
<Button theme="default" onClick={() => setIsPhoneSettingsOpen(true)}>
|
||||
电话获客设置
|
||||
</Button>
|
||||
<Dialog
|
||||
visible={isPhoneSettingsOpen}
|
||||
onClose={handlePhoneSettingsDialogClose}
|
||||
<div
|
||||
style={{
|
||||
background: "#f7f8fa",
|
||||
borderRadius: 10,
|
||||
padding: 20,
|
||||
boxShadow: "0 2px 8px rgba(0,0,0,0.03)",
|
||||
marginBottom: 12,
|
||||
}}
|
||||
>
|
||||
<div style={{ fontWeight: 600, fontSize: 16, marginBottom: 12 }}>
|
||||
<div style={{ fontWeight: 600, fontSize: 16, marginBottom: 16 }}>
|
||||
电话获客设置
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
@@ -902,15 +913,12 @@ export function BasicSettings({
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Button block theme="primary" onClick={handlePhoneSettingsUpdate}>
|
||||
保存设置
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* 微信群设置区块,仅在选择微信群场景时显示 */}
|
||||
{formData.scenario === "weixinqun" && (
|
||||
{formData.scenario === 7 && (
|
||||
<div style={{ margin: "16px 0" }}>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<Input
|
||||
@@ -932,7 +940,7 @@ export function BasicSettings({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Button block theme="primary" onClick={onNext}>
|
||||
<Button className="mt-4" block theme="primary" onClick={onNext}>
|
||||
下一步
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user