FEAT => 本次更新项目为:
内容库处理完成
This commit is contained in:
21
nkebao/src/components/ContentSelection/data.ts
Normal file
21
nkebao/src/components/ContentSelection/data.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// 内容库接口类型
|
||||
export interface ContentItem {
|
||||
id: number;
|
||||
name: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 组件属性接口
|
||||
export interface ContentSelectionProps {
|
||||
selectedContent: ContentItem[];
|
||||
onSelect: (selectedItems: ContentItem[]) => void;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
visible?: boolean;
|
||||
onVisibleChange?: (visible: boolean) => void;
|
||||
selectedListMaxHeight?: number;
|
||||
showInput?: boolean;
|
||||
showSelectedList?: boolean;
|
||||
readonly?: boolean;
|
||||
onConfirm?: (selectedItems: ContentItem[]) => void;
|
||||
}
|
||||
@@ -7,17 +7,7 @@ import Layout from "@/components/Layout/Layout";
|
||||
import PopupHeader from "@/components/PopuLayout/header";
|
||||
import PopupFooter from "@/components/PopuLayout/footer";
|
||||
import { getContentLibraryList } from "./api";
|
||||
|
||||
// 内容库接口类型
|
||||
interface ContentLibraryItem {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
sourceType?: number; // 1=文本 2=图片 3=视频
|
||||
creatorName?: string;
|
||||
updateTime?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
import { ContentItem, ContentSelectionProps } from "./data";
|
||||
|
||||
// 类型标签文本
|
||||
const getTypeText = (type?: number) => {
|
||||
@@ -43,29 +33,9 @@ const formatDate = (dateStr?: string) => {
|
||||
.padStart(2, "0")}`;
|
||||
};
|
||||
|
||||
// 组件属性接口
|
||||
interface ContentLibrarySelectionProps {
|
||||
selectedLibraries: (string | number)[];
|
||||
onSelect: (libraries: string[]) => void;
|
||||
onSelectDetail?: (libraries: ContentLibraryItem[]) => void;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
visible?: boolean;
|
||||
onVisibleChange?: (visible: boolean) => void;
|
||||
selectedListMaxHeight?: number;
|
||||
showInput?: boolean;
|
||||
showSelectedList?: boolean;
|
||||
readonly?: boolean;
|
||||
onConfirm?: (
|
||||
selectedIds: string[],
|
||||
selectedItems: ContentLibraryItem[],
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default function ContentLibrarySelection({
|
||||
selectedLibraries,
|
||||
export default function ContentSelection({
|
||||
selectedContent,
|
||||
onSelect,
|
||||
onSelectDetail,
|
||||
placeholder = "选择内容库",
|
||||
className = "",
|
||||
visible,
|
||||
@@ -75,24 +45,19 @@ export default function ContentLibrarySelection({
|
||||
showSelectedList = true,
|
||||
readonly = false,
|
||||
onConfirm,
|
||||
}: ContentLibrarySelectionProps) {
|
||||
}: ContentSelectionProps) {
|
||||
const [popupVisible, setPopupVisible] = useState(false);
|
||||
const [libraries, setLibraries] = useState<ContentLibraryItem[]>([]);
|
||||
const [libraries, setLibraries] = useState<ContentItem[]>([]);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [totalLibraries, setTotalLibraries] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// 获取已选内容库详细信息
|
||||
const selectedLibraryObjs = libraries.filter(item =>
|
||||
selectedLibraries.includes(item.id),
|
||||
);
|
||||
|
||||
// 删除已选内容库
|
||||
const handleRemoveLibrary = (id: string) => {
|
||||
const handleRemoveLibrary = (id: number) => {
|
||||
if (readonly) return;
|
||||
onSelect(selectedLibraries.filter(g => g !== id));
|
||||
onSelect(selectedContent.filter(c => c.id !== id));
|
||||
};
|
||||
|
||||
// 受控弹窗逻辑
|
||||
@@ -153,30 +118,24 @@ export default function ContentLibrarySelection({
|
||||
};
|
||||
|
||||
// 处理内容库选择
|
||||
const handleLibraryToggle = (libraryId: string) => {
|
||||
const handleLibraryToggle = (library: ContentItem) => {
|
||||
if (readonly) return;
|
||||
const newSelected = selectedLibraries.includes(libraryId)
|
||||
? selectedLibraries.filter(id => id !== libraryId)
|
||||
: [...selectedLibraries, libraryId];
|
||||
const newSelected = selectedContent.some(c => c.id === library.id)
|
||||
? selectedContent.filter(c => c.id !== library.id)
|
||||
: [...selectedContent, library];
|
||||
onSelect(newSelected);
|
||||
if (onSelectDetail) {
|
||||
const selectedObjs = libraries.filter(item =>
|
||||
newSelected.includes(item.id),
|
||||
);
|
||||
onSelectDetail(selectedObjs);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取显示文本
|
||||
const getDisplayText = () => {
|
||||
if (selectedLibraries.length === 0) return "";
|
||||
return `已选择 ${selectedLibraries.length} 个内容库`;
|
||||
if (selectedContent.length === 0) return "";
|
||||
return `已选择 ${selectedContent.length} 个内容库`;
|
||||
};
|
||||
|
||||
// 确认选择
|
||||
const handleConfirm = () => {
|
||||
if (onConfirm) {
|
||||
onConfirm(selectedLibraries, selectedLibraryObjs);
|
||||
onConfirm(selectedContent);
|
||||
}
|
||||
setRealVisible(false);
|
||||
};
|
||||
@@ -202,7 +161,7 @@ export default function ContentLibrarySelection({
|
||||
</div>
|
||||
)}
|
||||
{/* 已选内容库列表窗口 */}
|
||||
{showSelectedList && selectedLibraryObjs.length > 0 && (
|
||||
{showSelectedList && selectedContent.length > 0 && (
|
||||
<div
|
||||
className={style.selectedListWindow}
|
||||
style={{
|
||||
@@ -214,7 +173,7 @@ export default function ContentLibrarySelection({
|
||||
background: "#fff",
|
||||
}}
|
||||
>
|
||||
{selectedLibraryObjs.map(item => (
|
||||
{selectedContent.map(item => (
|
||||
<div
|
||||
key={item.id}
|
||||
className={style.selectedListRow}
|
||||
@@ -284,7 +243,7 @@ export default function ContentLibrarySelection({
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
loading={loading}
|
||||
selectedCount={selectedLibraries.length}
|
||||
selectedCount={selectedContent.length}
|
||||
onPageChange={setCurrentPage}
|
||||
onCancel={() => setRealVisible(false)}
|
||||
onConfirm={handleConfirm}
|
||||
@@ -301,8 +260,8 @@ export default function ContentLibrarySelection({
|
||||
{libraries.map(item => (
|
||||
<label key={item.id} className={style.libraryItem}>
|
||||
<Checkbox
|
||||
checked={selectedLibraries.includes(item.id)}
|
||||
onChange={() => !readonly && handleLibraryToggle(item.id)}
|
||||
checked={selectedContent.map(c => c.id).includes(item.id)}
|
||||
onChange={() => !readonly && handleLibraryToggle(item)}
|
||||
disabled={readonly}
|
||||
className={style.checkboxWrapper}
|
||||
/>
|
||||
@@ -5,11 +5,11 @@ import NavCommon from "@/components/NavCommon";
|
||||
import DeviceSelection from "@/components/DeviceSelection";
|
||||
import FriendSelection from "@/components/FriendSelection";
|
||||
import GroupSelection from "@/components/GroupSelection";
|
||||
import ContentLibrarySelection from "@/components/ContentLibrarySelection";
|
||||
import ContentSelection from "@/components/ContentSelection";
|
||||
import AccountSelection from "@/components/AccountSelection";
|
||||
import { isDevelopment } from "@/utils/env";
|
||||
import { GroupSelectionItem } from "@/components/GroupSelection/data";
|
||||
|
||||
import { ContentItem } from "@/components/ContentSelection/data";
|
||||
const ComponentTest: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState("libraries");
|
||||
|
||||
@@ -25,7 +25,7 @@ const ComponentTest: React.FC = () => {
|
||||
);
|
||||
|
||||
// 内容库选择状态
|
||||
const [selectedLibraries, setSelectedLibraries] = useState<string[]>([]);
|
||||
const [selectedContent, setSelectedContent] = useState<ContentItem[]>([]);
|
||||
|
||||
const [selectedAccounts, setSelectedAccounts] = useState<number[]>([]);
|
||||
|
||||
@@ -43,12 +43,10 @@ const ComponentTest: React.FC = () => {
|
||||
<Tabs activeKey={activeTab} onChange={setActiveTab}>
|
||||
<Tabs.Tab title="内容库选择" key="libraries">
|
||||
<div style={{ padding: "16px 0" }}>
|
||||
<h3 style={{ marginBottom: 16 }}>
|
||||
ContentLibrarySelection 组件测试
|
||||
</h3>
|
||||
<ContentLibrarySelection
|
||||
selectedLibraries={selectedLibraries}
|
||||
onSelect={setSelectedLibraries}
|
||||
<h3 style={{ marginBottom: 16 }}>ContentSelection 组件测试</h3>
|
||||
<ContentSelection
|
||||
selectedContent={selectedContent}
|
||||
onSelect={setSelectedContent}
|
||||
placeholder="请选择内容库"
|
||||
showSelectedList={true}
|
||||
selectedListMaxHeight={300}
|
||||
@@ -61,10 +59,10 @@ const ComponentTest: React.FC = () => {
|
||||
borderRadius: 8,
|
||||
}}
|
||||
>
|
||||
<strong>已选内容库:</strong> {selectedLibraries.length} 个
|
||||
<strong>已选内容库:</strong> {selectedContent.length} 个
|
||||
<br />
|
||||
<strong>内容库ID:</strong>{" "}
|
||||
{selectedLibraries.join(", ") || "无"}
|
||||
{selectedContent.map(c => c.id).join(", ") || "无"}
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Tab>
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
import React, { useImperativeHandle, forwardRef } from "react";
|
||||
import { Form, Card } from "antd";
|
||||
import ContentLibrarySelection from "@/components/ContentLibrarySelection";
|
||||
|
||||
interface ContentLibrary {
|
||||
id: string;
|
||||
name: string;
|
||||
targets: Array<{
|
||||
id: string;
|
||||
avatar: string;
|
||||
}>;
|
||||
}
|
||||
import ContentSelection from "@/components/ContentSelection";
|
||||
import { ContentItem } from "@/components/ContentSelection/data";
|
||||
|
||||
interface ContentSelectorProps {
|
||||
selectedLibraries: ContentLibrary[];
|
||||
onLibrariesChange: (libraries: ContentLibrary[]) => void;
|
||||
selectedContent: ContentItem[];
|
||||
onPrevious: () => void;
|
||||
onNext: () => void;
|
||||
onSave: () => void;
|
||||
loading?: boolean;
|
||||
onNext: (data: {
|
||||
contentGroups: string[];
|
||||
contentGroupsOptions: ContentItem[];
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export interface ContentSelectorRef {
|
||||
@@ -26,17 +18,7 @@ export interface ContentSelectorRef {
|
||||
}
|
||||
|
||||
const ContentSelector = forwardRef<ContentSelectorRef, ContentSelectorProps>(
|
||||
(
|
||||
{
|
||||
selectedLibraries,
|
||||
onLibrariesChange,
|
||||
onPrevious,
|
||||
onNext,
|
||||
onSave,
|
||||
loading = false,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
({ selectedContent, onNext }, ref) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
// 暴露方法给父组件
|
||||
@@ -55,20 +37,17 @@ const ContentSelector = forwardRef<ContentSelectorRef, ContentSelectorProps>(
|
||||
},
|
||||
}));
|
||||
|
||||
// 将 ContentLibrary[] 转换为 string[] 用于 ContentLibrarySelection
|
||||
const selectedLibraryIds = selectedLibraries.map(lib => lib.id);
|
||||
|
||||
// 处理选择变化
|
||||
const handleLibrariesChange = (libraryIds: string[]) => {
|
||||
// 这里需要根据选中的ID重新构建ContentLibrary对象
|
||||
// 由于ContentLibrarySelection只返回ID,我们需要从原始数据中获取完整信息
|
||||
// 暂时使用简化的处理方式
|
||||
const newSelectedLibraries = libraryIds.map(id => ({
|
||||
const handleLibrariesChange = (contentGroups: string[]) => {
|
||||
const newSelectedLibraries = contentGroups.map(id => ({
|
||||
id,
|
||||
name: `内容库 ${id}`, // 这里应该从API获取完整信息
|
||||
targets: [], // 这里应该从API获取完整信息
|
||||
}));
|
||||
onLibrariesChange(newSelectedLibraries);
|
||||
onNext({
|
||||
contentGroups: libraryIds,
|
||||
contentGroupsOptions: newSelectedLibraries,
|
||||
});
|
||||
form.setFieldValue("contentLibraries", libraryIds);
|
||||
};
|
||||
|
||||
@@ -80,7 +59,7 @@ const ContentSelector = forwardRef<ContentSelectorRef, ContentSelectorProps>(
|
||||
name: lib.name,
|
||||
targets: [], // 这里需要根据实际情况获取targets数据
|
||||
}));
|
||||
onLibrariesChange(convertedLibraries);
|
||||
onNext(convertedLibraries);
|
||||
form.setFieldValue(
|
||||
"contentLibraries",
|
||||
libraries.map(lib => lib.id),
|
||||
@@ -112,8 +91,8 @@ const ContentSelector = forwardRef<ContentSelectorRef, ContentSelectorProps>(
|
||||
{ type: "array", max: 20, message: "最多只能选择20个内容库" },
|
||||
]}
|
||||
>
|
||||
<ContentLibrarySelection
|
||||
selectedLibraries={selectedLibraryIds}
|
||||
<ContentSelection
|
||||
selectedLibraries={selectedContent}
|
||||
onSelect={handleLibrariesChange}
|
||||
onSelectDetail={handleSelectDetail}
|
||||
placeholder="选择内容库"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ContentItem } from "@/components/ContentSelection/data";
|
||||
export interface WechatGroup {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -27,7 +28,7 @@ export interface FormData {
|
||||
isLoopPush: boolean;
|
||||
isImmediatePush: boolean;
|
||||
isEnabled: boolean;
|
||||
contentLibraries: ContentLibrary[];
|
||||
contentGroups: string[];
|
||||
wechatGroups: string[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import ContentSelector, {
|
||||
import type { ContentLibrary, FormData } from "./index.data";
|
||||
import NavCommon from "@/components/NavCommon";
|
||||
import { GroupSelectionItem } from "@/components/GroupSelection/data";
|
||||
import { ContentItem } from "@/components/ContentSelection/data";
|
||||
const steps = [
|
||||
{ id: 1, title: "步骤 1", subtitle: "基础设置" },
|
||||
{ id: 2, title: "步骤 2", subtitle: "选择社群" },
|
||||
@@ -27,6 +28,10 @@ const NewGroupPush: React.FC = () => {
|
||||
const [wechatGroupsOptions, setWechatGroupsOptions] = useState<
|
||||
GroupSelectionItem[]
|
||||
>([]);
|
||||
const [contentGroupsOptions, setContentGroupsOptions] = useState<
|
||||
ContentItem[]
|
||||
>([]);
|
||||
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
name: "",
|
||||
pushTimeStart: "06:00",
|
||||
@@ -37,7 +42,7 @@ const NewGroupPush: React.FC = () => {
|
||||
isImmediatePush: false,
|
||||
isEnabled: false,
|
||||
wechatGroups: [],
|
||||
contentLibraries: [],
|
||||
contentGroups: [],
|
||||
});
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
|
||||
@@ -66,9 +71,13 @@ const NewGroupPush: React.FC = () => {
|
||||
}));
|
||||
setWechatGroupsOptions(data.wechatGroupsOptions);
|
||||
};
|
||||
|
||||
const handleLibrariesChange = (contentLibraries: ContentLibrary[]) => {
|
||||
setFormData(prev => ({ ...prev, contentLibraries }));
|
||||
//内容库选择
|
||||
const handleLibrariesChange = (data: {
|
||||
contentGroups: string[];
|
||||
contentGroupsOptions: ContentItem[];
|
||||
}) => {
|
||||
setFormData(prev => ({ ...prev, contentGroups: data.contentGroups }));
|
||||
setContentGroupsOptions(data.contentGroupsOptions);
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
@@ -230,12 +239,9 @@ const NewGroupPush: React.FC = () => {
|
||||
{currentStep === 3 && (
|
||||
<ContentSelector
|
||||
ref={contentSelectorRef}
|
||||
selectedLibraries={formData.contentLibraries}
|
||||
onLibrariesChange={handleLibrariesChange}
|
||||
selectedContent={contentGroupsOptions}
|
||||
onPrevious={() => setCurrentStep(2)}
|
||||
onNext={() => setCurrentStep(4)}
|
||||
onSave={handleSave}
|
||||
loading={loading}
|
||||
onNext={handleLibrariesChange}
|
||||
/>
|
||||
)}
|
||||
{currentStep === 4 && (
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
getMomentsSyncDetail,
|
||||
} from "./api";
|
||||
import DeviceSelection from "@/components/DeviceSelection";
|
||||
import ContentLibrarySelection from "@/components/ContentLibrarySelection";
|
||||
import ContentLibrarySelection from "@/components/ContentSelection";
|
||||
import NavCommon from "@/components/NavCommon";
|
||||
|
||||
const steps = [
|
||||
|
||||
Reference in New Issue
Block a user