2025-02-28 19:58:41 +08:00
|
|
|
|
|
2025-02-28 19:53:40 +08:00
|
|
|
|
// import React, { useState } from 'react';
|
|
|
|
|
// import { Form, Select, Input } from 'antd';
|
|
|
|
|
// import axios from 'axios';
|
|
|
|
|
|
|
|
|
|
// const { Option } = Select;
|
|
|
|
|
|
|
|
|
|
// // 假数据
|
|
|
|
|
// const fakePostsData = Array.from({ length: 15 }, (_, index) => ({
|
|
|
|
|
// id: index + 1,
|
|
|
|
|
// type: 'Lecture',
|
|
|
|
|
// name: `Lecture ${index + 1}`,
|
|
|
|
|
// description: `This is lecture number ${index + 1}`,
|
|
|
|
|
// }));
|
|
|
|
|
|
|
|
|
|
// // 模拟获取数据的函数
|
|
|
|
|
// async function fetchPosts(query = '') {
|
|
|
|
|
// // 在实际应用中,这里应该是一个真实的API调用
|
|
|
|
|
// return fakePostsData.filter(post =>
|
|
|
|
|
// post.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
|
|
|
// post.description.toLowerCase().includes(query.toLowerCase())
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const PostSelector = ({ value, onChange }) => {
|
|
|
|
|
// const [posts, setPosts] = useState([]);
|
|
|
|
|
// const [searchValue, setSearchValue] = useState('');
|
|
|
|
|
|
|
|
|
|
// const handleSearch = async (query) => {
|
|
|
|
|
// setSearchValue(query);
|
|
|
|
|
// const result = await fetchPosts(query);
|
|
|
|
|
// setPosts(result);
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const handlePostChange = (selectedIds) => {
|
|
|
|
|
// onChange(selectedIds); // 更新父组件的状态
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const renderOption = (post) => (
|
|
|
|
|
// <Option key={post.id} value={post.id.toString()}>
|
|
|
|
|
// {post.name} - {post.description}
|
|
|
|
|
// </Option>
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// return (
|
|
|
|
|
// <Select
|
|
|
|
|
// mode="multiple" // 支持多选
|
|
|
|
|
// showSearch
|
|
|
|
|
// placeholder="请选择或搜索讲座"
|
|
|
|
|
// optionFilterProp="children"
|
|
|
|
|
// onSearch={handleSearch}
|
|
|
|
|
// filterOption={false} // 禁用默认过滤,因为我们已经在 onSearch 中实现了自定义过滤
|
|
|
|
|
// notFoundContent={''}
|
|
|
|
|
// style={{ width: '100%' }}
|
|
|
|
|
// value={value || []}
|
|
|
|
|
// onChange={handlePostChange}
|
|
|
|
|
// >
|
|
|
|
|
// {posts.map(renderOption)}
|
|
|
|
|
// </Select>
|
|
|
|
|
// );
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const PostForm = () => {
|
|
|
|
|
// const [form] = Form.useForm();
|
|
|
|
|
|
|
|
|
|
// const onFinish = (values) => {
|
|
|
|
|
// console.log('Received values of form: ', values);
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// return (
|
|
|
|
|
// <Form
|
|
|
|
|
// form={form}
|
|
|
|
|
// name="postForm"
|
|
|
|
|
// onFinish={onFinish}
|
|
|
|
|
// initialValues={{
|
|
|
|
|
// postIds: [], // 初始值为空数组
|
|
|
|
|
// }}
|
|
|
|
|
// >
|
|
|
|
|
// <Form.Item
|
|
|
|
|
// name="postIds"
|
|
|
|
|
// label="选择讲座"
|
|
|
|
|
// rules={[{ required: true, message: '请选择至少一个讲座!' }]}
|
|
|
|
|
// >
|
|
|
|
|
// <PostSelector
|
|
|
|
|
// value={form.getFieldValue('postIds')}
|
|
|
|
|
// onChange={(selectedIds) => form.setFieldsValue({ postIds: selectedIds })}
|
|
|
|
|
// />
|
|
|
|
|
// </Form.Item>
|
|
|
|
|
|
|
|
|
|
// <Form.Item>
|
|
|
|
|
// <button type="submit">提交</button>
|
|
|
|
|
// </Form.Item>
|
|
|
|
|
// </Form>
|
|
|
|
|
// );
|
|
|
|
|
// };
|
|
|
|
|
|
2025-02-28 19:58:41 +08:00
|
|
|
|
// export default PostForm;
|
2025-02-28 15:17:56 +08:00
|
|
|
|
import { api } from "@nice/client";
|
2025-03-02 11:49:46 +08:00
|
|
|
|
import { Button, Select } from "antd";
|
|
|
|
|
import {
|
|
|
|
|
Lecture,
|
|
|
|
|
lectureDetailSelect,
|
|
|
|
|
postDetailSelect,
|
|
|
|
|
postUnDetailSelect,
|
|
|
|
|
Prisma,
|
|
|
|
|
} from "@nice/common";
|
|
|
|
|
import { useMemo, useState } from "react";
|
|
|
|
|
import PostSelectOption from "./PostSelectOption";
|
|
|
|
|
import { DefaultArgs } from "@prisma/client/runtime/library";
|
|
|
|
|
import { safeOR } from "@nice/utils";
|
2025-02-28 15:17:56 +08:00
|
|
|
|
|
2025-03-02 11:49:46 +08:00
|
|
|
|
export default function PostSelect({
|
|
|
|
|
value,
|
|
|
|
|
onChange,
|
|
|
|
|
placeholder = "请选择课时",
|
|
|
|
|
params = { where: {}, select: {} },
|
|
|
|
|
className,
|
|
|
|
|
}: {
|
|
|
|
|
value?: string | string[];
|
|
|
|
|
onChange?: (value: string | string[]) => void;
|
|
|
|
|
placeholder?: string;
|
|
|
|
|
params?: {
|
|
|
|
|
where?: Prisma.PostWhereInput;
|
|
|
|
|
select?: Prisma.PostSelect<DefaultArgs>;
|
|
|
|
|
};
|
|
|
|
|
className?: string;
|
|
|
|
|
}) {
|
|
|
|
|
const [searchValue, setSearch] = useState("");
|
|
|
|
|
const searchCondition: Prisma.PostWhereInput = useMemo(() => {
|
|
|
|
|
const containTextCondition: Prisma.StringNullableFilter = {
|
|
|
|
|
contains: searchValue,
|
|
|
|
|
mode: "insensitive" as Prisma.QueryMode, // 使用类型断言
|
|
|
|
|
};
|
|
|
|
|
return searchValue
|
|
|
|
|
? {
|
|
|
|
|
OR: [
|
|
|
|
|
{ title: containTextCondition },
|
|
|
|
|
|
|
|
|
|
{ content: containTextCondition },
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
: {};
|
|
|
|
|
}, [searchValue]);
|
|
|
|
|
// 核心条件生成逻辑
|
|
|
|
|
const idCondition: Prisma.PostWhereInput = useMemo(() => {
|
|
|
|
|
if (value === undefined) return {}; // 无值时返回空对象
|
|
|
|
|
// 字符串类型增强判断
|
|
|
|
|
if (typeof value === "string") {
|
|
|
|
|
// 如果明确需要支持逗号分隔字符串
|
|
|
|
|
|
|
|
|
|
return { id: value };
|
|
|
|
|
}
|
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
|
return value.length > 0 ? { id: { in: value } } : {}; // 空数组不注入条件
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}, [value]);
|
|
|
|
|
const {
|
|
|
|
|
data: lectures,
|
|
|
|
|
isLoading,
|
|
|
|
|
}: { data: Lecture[]; isLoading: boolean } = api.post.findMany.useQuery({
|
|
|
|
|
where: safeOR([
|
|
|
|
|
{ ...idCondition },
|
|
|
|
|
|
|
|
|
|
{ ...searchCondition, ...(params?.where || {}) },
|
|
|
|
|
]),
|
|
|
|
|
select: { ...postDetailSelect, ...(params?.select || {}) },
|
|
|
|
|
take: 15,
|
|
|
|
|
});
|
|
|
|
|
const options = useMemo(() => {
|
|
|
|
|
return (lectures || []).map((lecture, index) => {
|
|
|
|
|
return {
|
|
|
|
|
value: lecture.id,
|
|
|
|
|
label: <PostSelectOption post={lecture}></PostSelectOption>,
|
|
|
|
|
tag: lecture?.title,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}, [lectures, isLoading]);
|
|
|
|
|
const tagRender = (props) => {
|
|
|
|
|
// 根据 value 找到对应的 option
|
|
|
|
|
const option = options.find((opt) => opt.value === props.value);
|
|
|
|
|
// 使用自定义的展示内容(这里假设你的 option 中有 customDisplay 字段)
|
|
|
|
|
return <span style={{ marginRight: 3 }}>{option?.tag}</span>;
|
|
|
|
|
};
|
2025-02-28 15:17:56 +08:00
|
|
|
|
return (
|
2025-03-02 11:49:46 +08:00
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
width: 200,
|
|
|
|
|
}}>
|
2025-02-28 15:17:56 +08:00
|
|
|
|
<Select
|
2025-03-02 11:49:46 +08:00
|
|
|
|
showSearch
|
|
|
|
|
value={value}
|
|
|
|
|
dropdownStyle={{
|
|
|
|
|
minWidth: 200, // 设置合适的最小宽度
|
|
|
|
|
}}
|
|
|
|
|
placeholder={placeholder}
|
|
|
|
|
onChange={onChange}
|
|
|
|
|
filterOption={false}
|
|
|
|
|
loading={isLoading}
|
|
|
|
|
className={`flex-1 w-full ${className}`}
|
|
|
|
|
options={options}
|
|
|
|
|
tagRender={tagRender}
|
|
|
|
|
optionLabelProp="tag" // 新增这个属性 ✅
|
2025-02-28 15:17:56 +08:00
|
|
|
|
onSearch={(inputValue) => setSearch(inputValue)}></Select>
|
2025-03-02 11:49:46 +08:00
|
|
|
|
</div>
|
2025-02-28 15:17:56 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
2025-02-28 19:58:41 +08:00
|
|
|
|
|