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