origin/apps/web/src/components/models/post/PostSelect/PostSelect.tsx

107 lines
2.9 KiB
TypeScript

import { api } from "@nice/client";
import { Input, Select } from "antd";
import { Lecture, postDetailSelect, 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";
import { LinkOutlined } from "@ant-design/icons";
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>;
};
return (
<div
style={{
width: "100%",
}}>
<Select
showSearch
value={value}
dropdownStyle={{
minWidth: 200, // 设置合适的最小宽度
}}
autoClearSearchValue
placeholder={placeholder}
onChange={onChange}
filterOption={false}
loading={isLoading}
className={`flex-1 w-full ${className}`}
options={options}
tagRender={tagRender}
optionLabelProp="tag" // 新增这个属性
onSearch={(inputValue) => setSearch(inputValue)}></Select>
</div>
);
}