Merge branch 'yongpxu-dev' into yongpxu-dev4

This commit is contained in:
笔记本里的永平
2025-07-23 19:12:42 +08:00
9 changed files with 323 additions and 247 deletions

View File

@@ -20,7 +20,6 @@ export async function uploadFile(
"Content-Type": "multipart/form-data",
},
});
return res.url;
} catch (e: any) {
throw new Error(e?.message || "文件上传失败");

View File

@@ -150,9 +150,18 @@ export default function FriendSelection({
};
// 获取已选好友详细信息
const selectedFriendObjs = friends.filter((friend) =>
selectedFriends.includes(friend.id)
);
const selectedFriendObjs = [
...friends.filter((friend) => selectedFriends.includes(friend.id)),
...selectedFriends
.filter((id) => !friends.some((friend) => friend.id === id))
.map((id) => ({
id,
nickname: id,
wechatId: id,
avatar: "",
customer: "",
})),
];
// 删除已选好友
const handleRemoveFriend = (id: string) => {

View File

@@ -598,6 +598,7 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
onChange={async (e) => {
const file = e.target.files?.[0];
if (file) {
// 直接上传
try {
const url = await uploadFile(file);
const newPoster = {
@@ -606,14 +607,9 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
type: "poster",
preview: url,
};
console.log(newPoster);
setCustomPosters((prev) => [...prev, newPoster]);
setSelectedMaterials([newPoster]);
onChange({ ...formData, materials: [newPoster] });
} catch (err) {
// 可加toast提示
log;
}
e.target.value = "";
}

View File

@@ -1,19 +1,10 @@
"use client";
import React, { useState, useEffect } from "react";
import {
Form,
Input,
Button,
Checkbox,
Modal,
Alert,
Select,
message,
} from "antd";
import { QuestionCircleOutlined, MessageOutlined } from "@ant-design/icons";
import { Input, Button, Modal, Alert, Select } from "antd";
import { MessageOutlined } from "@ant-design/icons";
import DeviceSelection from "@/components/DeviceSelection";
import Layout from "@/components/Layout/Layout";
import styles from "./friend.module.scss";
interface FriendRequestSettingsProps {
formData: any;
@@ -46,8 +37,8 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
}) => {
const [isTemplateDialogOpen, setIsTemplateDialogOpen] = useState(false);
const [hasWarnings, setHasWarnings] = useState(false);
const [selectedDevices, setSelectedDevices] = useState<any[]>(
formData.selectedDevices || []
const [selectedDevices, setSelectedDevices] = useState<string[]>(
formData.device || []
);
const [showRemarkTip, setShowRemarkTip] = useState(false);
@@ -97,57 +88,48 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
};
return (
<>
<Layout
footer={
<div className="p-4 border-t bg-white">
<div className="flex justify-between">
<Button onClick={onPrev}></Button>
<Button type="primary" onClick={handleNext}>
</Button>
</div>
</div>
}
>
<div className="p-4 space-y-6">
<div>
<span className="font-medium text-base"></span>
<div className="mt-2">
<div className={styles["friend-container"]}>
{/* 选择设备区块 */}
<div className={styles["friend-label"]}></div>
<div className={styles["friend-block"]}>
<DeviceSelection
selectedDevices={selectedDevices.map((d) => d.id)}
selectedDevices={selectedDevices}
onSelect={(deviceIds) => {
const newSelectedDevices = deviceIds.map((id) => ({
id,
name: `设备 ${id}`,
status: "online",
}));
setSelectedDevices(newSelectedDevices);
setSelectedDevices(deviceIds);
onChange({ ...formData, device: deviceIds });
}}
placeholder="选择设备"
/>
</div>
</div>
<div className="mb-4">
<div className="flex items-center space-x-2 mb-1 relative">
<span className="font-medium text-base"></span>
{/* 好友备注区块 */}
<div className={styles["friend-label"]}></div>
<div className={styles["friend-block"]} style={{ position: "relative" }}>
<Select
value={formData.remarkType || "phone"}
onChange={(value) => onChange({ ...formData, remarkType: value })}
style={{ width: "100%" }}
>
{remarkTypes.map((type) => (
<Select.Option key={type.value} value={type.value}>
{type.label}
</Select.Option>
))}
</Select>
<span
className="inline-flex items-center justify-center w-5 h-5 rounded-full bg-gray-200 text-gray-500 text-xs cursor-pointer hover:bg-gray-300 transition-colors"
className={styles["friend-remark-q"]}
onMouseEnter={() => setShowRemarkTip(true)}
onMouseLeave={() => setShowRemarkTip(false)}
onClick={() => setShowRemarkTip((v) => !v)}
>
?
</span>
{showRemarkTip && (
<div className="absolute left-24 top-0 z-20 w-64 p-3 bg-white border border-gray-200 rounded shadow-lg text-sm text-gray-700">
<div className={styles["friend-remark-tip"]}>
<div></div>
<div className="mt-2 text-xs text-gray-500">
<div style={{ marginTop: 8, color: "#888", fontSize: 12 }}>
</div>
<div className="mt-1 text-blue-600">
<div style={{ marginTop: 4, color: "#1677ff" }}>
{formData.remarkType === "phone" &&
`138****1234+${getScenarioTitle()}`}
{formData.remarkType === "nickname" &&
@@ -158,43 +140,31 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
</div>
)}
</div>
<Select
value={formData.remarkType || "phone"}
onChange={(value) => onChange({ ...formData, remarkType: value })}
className="w-full mt-2"
>
{remarkTypes.map((type) => (
<Select.Option key={type.value} value={type.value}>
{type.label}
</Select.Option>
))}
</Select>
</div>
<div>
<div className="flex items-center justify-between">
<span className="font-medium text-base"></span>
<Button
onClick={() => setIsTemplateDialogOpen(true)}
className="text-blue-500"
>
<MessageOutlined className="h-4 w-4 mr-2" />
</Button>
</div>
{/* 招呼语区块 */}
<div className={styles["friend-label"]}></div>
<div className={styles["friend-block"]}>
<Input
value={formData.greeting}
onChange={(e) =>
onChange({ ...formData, greeting: e.target.value })
}
onChange={(e) => onChange({ ...formData, greeting: e.target.value })}
placeholder="请输入招呼语"
className="mt-2"
suffix={
<Button
type="link"
onClick={() => setIsTemplateDialogOpen(true)}
style={{ padding: 0 }}
>
<MessageOutlined />
</Button>
}
/>
</div>
<div>
<span className="font-medium text-base"></span>
<div className="flex items-center space-x-2 mt-2">
{/* 添加间隔区块 */}
<div className={styles["friend-label"]}></div>
<div
className={styles["friend-interval-row"] + " " + styles["friend-block"]}
>
<Input
type="number"
value={formData.addFriendInterval || 1}
@@ -204,21 +174,21 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
addFriendInterval: Number(e.target.value),
})
}
style={{ width: 100 }}
/>
<div className="w-10"></div>
</div>
<span></span>
</div>
<div>
<span className="font-medium text-base"></span>
<div className="flex items-center space-x-2 mt-2">
{/* 允许加人时间段区块 */}
<div className={styles["friend-label"]}></div>
<div className={styles["friend-time-row"] + " " + styles["friend-block"]}>
<Input
type="time"
value={formData.addFriendTimeStart || "09:00"}
onChange={(e) =>
onChange({ ...formData, addFriendTimeStart: e.target.value })
}
className="w-32"
style={{ width: 120 }}
/>
<span></span>
<Input
@@ -227,10 +197,9 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
onChange={(e) =>
onChange({ ...formData, addFriendTimeEnd: e.target.value })
}
className="w-32"
style={{ width: 120 }}
/>
</div>
</div>
{hasWarnings && (
<Alert
@@ -238,30 +207,37 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
description="您有未完成的设置项,建议完善后再进入下一步。"
type="warning"
showIcon
className="bg-amber-50 border-amber-200"
style={{ marginBottom: 16 }}
/>
)}
</div>
</Layout>
{/* 底部按钮 */}
<div className={styles["friend-footer"]}>
<Button onClick={onPrev}></Button>
<Button type="primary" onClick={handleNext}>
</Button>
</div>
{/* 招呼语模板弹窗 */}
<Modal
open={isTemplateDialogOpen}
onCancel={() => setIsTemplateDialogOpen(false)}
footer={null}
>
<div className="space-y-2">
<div>
{greetingTemplates.map((template, index) => (
<Button
key={index}
onClick={() => handleTemplateSelect(template)}
style={{ width: "100%", marginBottom: 8 }}
className={styles["friend-modal-btn"]}
>
{template}
</Button>
))}
</div>
</Modal>
</>
</div>
);
};

View File

@@ -1,5 +1,5 @@
import React, { useState } from "react";
import { Form, Input, Button, Tabs, Modal, Alert, Upload, message } from "antd";
import { Input, Button, Tabs, Modal, Alert, message } from "antd";
import {
PlusOutlined,
CloseOutlined,
@@ -13,7 +13,7 @@ import {
LinkOutlined,
TeamOutlined,
} from "@ant-design/icons";
import Layout from "@/components/Layout/Layout";
import styles from "./messages.module.scss";
interface MessageContent {
id: string;
@@ -194,9 +194,9 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
key: plan.day.toString(),
label: plan.day === 0 ? "即时消息" : `${plan.day}`,
children: (
<div className="space-y-4">
<div className={styles["messages-day-panel"]}>
{plan.messages.map((message, messageIndex) => (
<div key={message.id} className="space-y-4 p-4 bg-gray-50 rounded-lg">
<div key={message.id} className={styles["messages-message-card"]}>
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
{plan.day === 0 ? (
@@ -524,7 +524,10 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
</div>
))}
<Button onClick={() => handleAddMessage(dayIndex)} className="w-full">
<Button
onClick={() => handleAddMessage(dayIndex)}
className={styles["messages-add-message-btn"]}
>
<PlusOutlined className="w-4 h-4 mr-2" />
</Button>
@@ -533,31 +536,24 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
}));
return (
<>
<Layout
footer={
<div className="p-4 border-t bg-white">
<div className="flex justify-between">
<div className={styles["messages-container"]}>
<div className={styles["messages-header"]}>
<h2 className={styles["messages-title"]}></h2>
<Button onClick={() => setIsAddDayPlanOpen(true)}>
<PlusOutlined />
</Button>
</div>
<Tabs
defaultActiveKey="0"
items={items}
className={styles["messages-tab"]}
/>
<div className={styles["messages-footer"]}>
<Button onClick={onPrev}></Button>
<Button type="primary" onClick={onNext}>
</Button>
</div>
</div>
}
>
<div className="p-4 space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-lg font-semibold"></h2>
<Button onClick={() => setIsAddDayPlanOpen(true)}>
<PlusOutlined className="h-4 w-4" />
</Button>
</div>
<Tabs defaultActiveKey="0" items={items} />
</div>
</Layout>
{/* 添加天数计划弹窗 */}
<Modal
title="添加消息计划"
@@ -569,11 +565,13 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
}}
>
<p className="text-sm text-gray-500 mb-4"></p>
<Button onClick={handleAddDayPlan} className="w-full">
<Button
onClick={handleAddDayPlan}
className={styles["messages-modal-btn"]}
>
{dayPlans.length}
</Button>
</Modal>
{/* 选择群聊弹窗 */}
<Modal
title="选择群聊"
@@ -584,15 +582,14 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
setIsGroupSelectOpen(false);
}}
>
<div className="space-y-2">
<div>
{mockGroups.map((group) => (
<div
key={group.id}
className={`p-4 rounded-lg cursor-pointer hover:bg-gray-100 ${
selectedGroupId === group.id
? "bg-blue-50 border border-blue-200"
: ""
}`}
className={
styles["messages-group-select-item"] +
(selectedGroupId === group.id ? " " + styles.selected : "")
}
onClick={() => handleSelectGroup(group.id)}
>
<div className="font-medium">{group.name}</div>
@@ -603,7 +600,7 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
))}
</div>
</Modal>
</>
</div>
);
};

View File

@@ -0,0 +1,48 @@
.friend-container {
padding: 12px;
}
.friend-label {
margin-bottom: 12px;
font-weight: 500;
}
.friend-block {
margin-bottom: 16px;
}
.friend-remark-tip {
position: absolute;
right: 0;
top: 36px;
z-index: 10;
background: #fff;
border: 1px solid #eee;
border-radius: 6px;
padding: 12px;
width: 220px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.friend-remark-q {
position: absolute;
right: 8px;
top: 8px;
cursor: pointer;
color: #888;
}
.friend-interval-row {
display: flex;
align-items: center;
gap: 8px;
}
.friend-time-row {
display: flex;
align-items: center;
gap: 8px;
}
.friend-footer {
display: flex;
justify-content: space-between;
margin-top: 32px;
}
.friend-modal-btn {
width: 100%;
margin-bottom: 8px;
}

View File

@@ -0,0 +1,60 @@
.messages-container {
padding: 16px;
}
.messages-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.messages-title {
font-size: 18px;
font-weight: 600;
}
.messages-tab {
margin-bottom: 16px;
}
.messages-day-panel {
background: #fafbfc;
border-radius: 10px;
padding: 16px;
margin-bottom: 16px;
}
.messages-message-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
padding: 16px;
margin-bottom: 16px;
}
.messages-message-type-btns {
display: flex;
gap: 8px;
margin-bottom: 8px;
}
.messages-add-message-btn {
width: 100%;
margin-top: 8px;
}
.messages-footer {
display: flex;
justify-content: space-between;
margin-top: 32px;
}
.messages-modal-btn {
width: 100%;
margin-bottom: 8px;
}
.messages-group-select-item {
padding: 16px;
border-radius: 8px;
cursor: pointer;
background: #fff;
margin-bottom: 8px;
border: 1px solid #eee;
transition: border 0.2s, background 0.2s;
}
.messages-group-select-item.selected {
background: #e6f7ff;
border: 1.5px solid #1677ff;
}

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { NavBar, Button, Toast, SpinLoading, Dialog, Card } from "antd-mobile";
import { Button, Toast, SpinLoading, Dialog, Card } from "antd-mobile";
import NavCommon from "@/components/NavCommon";
import { Input } from "antd";
import {
PlusOutlined,
@@ -230,25 +231,15 @@ const AutoLike: React.FC = () => {
<Layout
header={
<>
<NavBar
back={null}
style={{ background: "#fff" }}
left={
<div className="nav-title">
<ArrowLeftOutlined
twoToneColor="#1677ff"
onClick={() => navigate(-1)}
/>
</div>
}
<NavCommon
title="自动点赞"
backFn={() => navigate("/workspace")}
right={
<Button size="small" color="primary" onClick={handleCreateNew}>
<PlusOutlined />
</Button>
}
>
<span className="nav-title"></span>
</NavBar>
/>
{/* 搜索栏 */}
<div className="search-bar">

View File

@@ -40,7 +40,7 @@ const workspaceRoutes = [
auth: true,
},
{
path: "/workspace/auto-like/:id/edit",
path: "/workspace/auto-like/edit/:id",
element: <NewAutoLike />,
auth: true,
},