💄 麻烦的新闻来源过滤
This commit is contained in:
parent
b1efffc9fe
commit
9e274a8e46
@ -244,14 +244,59 @@
|
||||
|
||||
.timer-select-options {
|
||||
@apply rounded-xl py-1 overflow-hidden drop-shadow absolute inset-x-0 top-[30px];
|
||||
background: linear-gradient(180deg,rgb(244, 247, 252) 0%, rgb(217, 232, 255) 100%);
|
||||
background: linear-gradient(180deg, rgb(244, 247, 252) 0%, rgb(217, 232, 255) 100%);
|
||||
}
|
||||
|
||||
.timer-select-option-item {
|
||||
@apply py-1.5 px-4 cursor-pointer text-gray-800 hover:text-blue-500;
|
||||
&.selected{
|
||||
&.selected {
|
||||
@apply text-blue-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tag-select-container {
|
||||
.select-value {
|
||||
@apply text-blue-500 px-4 cursor-pointer h-[31px];
|
||||
}
|
||||
.options-list-container {
|
||||
@apply overflow-auto py-1 drop-shadow absolute top-[30px];
|
||||
border-radius: 0 0 0.75rem 0.75rem;
|
||||
background: linear-gradient(180deg, rgb(244, 247, 252) 0%, rgb(217, 232, 255) 100%);
|
||||
max-height: calc(100vh - var(--app-header-header) - 300px);
|
||||
}
|
||||
|
||||
.options-list {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.select-option-item {
|
||||
@apply py-1.5 px-4 cursor-pointer text-gray-800 hover:text-blue-500 hover:bg-[#d9eaff];
|
||||
&.selected {
|
||||
@apply text-blue-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tag-select-child-container {
|
||||
.ant-popover-inner {
|
||||
@apply p-0 overflow-hidden drop-shadow shadow-none; //
|
||||
background: linear-gradient(180deg, rgb(235, 242, 253) 0%, rgb(244, 247, 252) 100%);
|
||||
border-radius: 0 0.75rem 0.75rem 0;
|
||||
transform: translate(16px, -7px);
|
||||
//backdrop-filter: 0 3px 1px 5px rgb(0, 0, 0,0.1);
|
||||
}
|
||||
|
||||
.sub-options-list {
|
||||
@apply py-1.5 top-0;
|
||||
max-height: 150px;
|
||||
|
||||
.select-option-item {
|
||||
@apply py-1.5 px-4 cursor-pointer text-gray-800 hover:text-blue-500 hover:bg-[#d9eaff];
|
||||
&.selected {
|
||||
@apply text-blue-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
151
src/components/form/tag-select.tsx
Normal file
151
src/components/form/tag-select.tsx
Normal file
@ -0,0 +1,151 @@
|
||||
import React, {useMemo, useState} from "react";
|
||||
import {Checkbox, Popover} from "antd";
|
||||
import {useBoolean} from "ahooks";
|
||||
import {CaretUpOutlined} from "@ant-design/icons";
|
||||
|
||||
const TagSelect = (props: {
|
||||
options: OptionItem[];
|
||||
onChange: (values: Id[][]) => void;
|
||||
className?: string;
|
||||
}) => {
|
||||
const [selectValues, _setSelectValues] = React.useState<Id[][]>([])
|
||||
const [checkedAll, _setCheckedAll] = React.useState<boolean>(false)
|
||||
const [visible, {set}] = useBoolean(false);
|
||||
const allValues = useMemo(()=>{
|
||||
const values:Id[][] = []
|
||||
props.options.forEach(item=>{
|
||||
if(item && item.children?.length > 0){
|
||||
// eslint-disable-next-line no-unsafe-optional-chaining
|
||||
values.push(...(item.children?.map(c => [item.value, c.value])))
|
||||
}
|
||||
})
|
||||
return values
|
||||
},[props.options])
|
||||
const handleAllChanged = (checked: boolean) => {
|
||||
_setCheckedAll(checked)
|
||||
const values:Id[][] = []
|
||||
if (checked){
|
||||
// set(false)
|
||||
values.push(...allValues)
|
||||
}
|
||||
_setSelectValues(values)
|
||||
}
|
||||
const handleLevel1Change = (checked: boolean, item: OptionItem) => {
|
||||
console.log('handleLevel1Change', checked, item)
|
||||
if (checked) {
|
||||
const values = selectValues.filter(s => s[0] != item.value)
|
||||
const checkedIds: Id[][] = [];
|
||||
item.children?.forEach(c => {
|
||||
checkedIds.push([item.value, c.value])
|
||||
})
|
||||
const _values = [...values, ...checkedIds];
|
||||
_setCheckedAll(_values.length == allValues.length)
|
||||
_setSelectValues(_values)
|
||||
} else {
|
||||
_setCheckedAll(false)
|
||||
const values = selectValues.filter(s => s[0] != item.value)
|
||||
_setSelectValues([...values])
|
||||
}
|
||||
}
|
||||
const level1Checked = (item: OptionItem) => {
|
||||
// 完全没有选中
|
||||
if (selectValues.findIndex(s => s[0] == item.value) == -1) return -1
|
||||
const myList = selectValues.filter(s => s[0] == item.value)
|
||||
// 只有1个但是全选或者选中元素和子元素个数相等
|
||||
if (myList.length == item.children?.length) return 1;
|
||||
return 0;
|
||||
}
|
||||
const handleLevel2Change = (checked: boolean, item: OptionItem, parent: OptionItem) => {
|
||||
// 获取一级选项的选中状态
|
||||
const parentList = selectValues.filter(s => s[0] == parent.value)
|
||||
_setSelectValues((prev) => {
|
||||
let values = [...prev]
|
||||
if (checked) {
|
||||
values = [...prev,[parent.value, item.value]]
|
||||
} else {
|
||||
_setCheckedAll(false)
|
||||
if(parentList.length == 0){ // && parentList[0].length == 1
|
||||
return prev;
|
||||
}
|
||||
values = values.filter(s => s.length == 1 || s[1] != item.value)
|
||||
}
|
||||
_setCheckedAll(values.length == allValues.length)
|
||||
return values
|
||||
})
|
||||
}
|
||||
const level2Checked = (item: OptionItem, parent: OptionItem) => {
|
||||
// 获取一级选项的选中状态
|
||||
const parentList = selectValues.filter(s => s[0] == parent.value)
|
||||
// 没有找到父级
|
||||
if (parentList.length == 0) return false;
|
||||
if (parentList.length == 1) {
|
||||
// 只有一个 且长度为0 说明是全选
|
||||
if (parentList[0].length == 1) return true;
|
||||
return parentList[0][1] == item.value;
|
||||
}
|
||||
|
||||
return parentList.findIndex(s => s[1] == item.value) != -1;
|
||||
}
|
||||
|
||||
return (<div className={`tag-select-container z-10 select-none relative group ${props.className}`}>
|
||||
<div className="select-value w-[120px] flex justify-center items-center"
|
||||
onMouseEnter={() => set(!visible)}
|
||||
>
|
||||
<span>{checkedAll ? '全部来源' : '来源'}</span>
|
||||
<CaretUpOutlined className={`ml-2 arrow-icon ${visible ? 'rotate-0' : 'rotate-180'}`}/>
|
||||
</div>
|
||||
<div className={`options-list-container absolute ${visible ? 'block' : 'hidden'}`}>
|
||||
<ul className="options-list">
|
||||
<li className="select-option-item relative">
|
||||
<div className="option-value whitespace-nowrap flex justify-between">
|
||||
<span className="text-center flex-1"
|
||||
onClick={() => handleAllChanged(!checkedAll)}>全部来源</span>
|
||||
<Checkbox className="ml-6" checked={checkedAll}
|
||||
onChange={e => handleAllChanged(e.target.checked)}/>
|
||||
</div>
|
||||
</li>
|
||||
{props.options.filter(s => s.value != 999999).map((option) => {
|
||||
const checkStatus = level1Checked(option)
|
||||
return (<li key={option.value} className="select-option-item relative">
|
||||
{(option.children && option.children.length > 0) ?
|
||||
<Popover placement="rightTop" trigger={['hover']}
|
||||
rootClassName="tag-select-child-container" arrow={false}
|
||||
content={option.children && <ul className="sub-options-list">
|
||||
{option.children.map((subOption) => {
|
||||
const myCheckStatus = level2Checked(subOption, option)
|
||||
return (<li key={subOption.value}
|
||||
className="sub-option-item select-option-item whitespace-nowrap">
|
||||
<div
|
||||
className="option-value whitespace-nowrap flex justify-between">
|
||||
<span
|
||||
onClick={() => {
|
||||
handleLevel2Change(!myCheckStatus, subOption, option)
|
||||
}}>{subOption.label}</span>
|
||||
<Checkbox className="ml-6" checked={myCheckStatus}
|
||||
onChange={e => handleLevel2Change(e.target.checked, subOption, option)}/>
|
||||
</div>
|
||||
</li>)
|
||||
})}
|
||||
</ul>}>
|
||||
<div className="option-value whitespace-nowrap flex justify-between">
|
||||
<span className="text-center flex-1">{option.label}</span>
|
||||
<Checkbox className="ml-6"
|
||||
checked={checkStatus == 1}
|
||||
indeterminate={checkStatus == 0}
|
||||
onChange={e => {
|
||||
handleLevel1Change(e.target.checked, option)
|
||||
}}/>
|
||||
</div>
|
||||
</Popover> : <div className="option-value whitespace-nowrap flex justify-between">
|
||||
<span>{option.label}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
</li>)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default TagSelect
|
@ -1,5 +1,5 @@
|
||||
import {Cascader} from "antd";
|
||||
import React, {useEffect, useMemo} from "react";
|
||||
import React, {useEffect} from "react";
|
||||
|
||||
|
||||
const prevSelectValues: Id[][] = [];
|
||||
@ -71,9 +71,6 @@ export default function ArticleCascader(props: {
|
||||
// 清除上一次的选中值
|
||||
prevSelectValues.length = 0;
|
||||
}, [])
|
||||
// const allOptionValue = useMemo(() => {
|
||||
// return getAllValue(props.options)
|
||||
// }, [props.options])
|
||||
|
||||
const setSelectValues = (value: Id[][]) => {
|
||||
_setSelectValues(value)
|
||||
@ -81,33 +78,6 @@ export default function ArticleCascader(props: {
|
||||
props.onChange?.(value)
|
||||
}
|
||||
const handleChange = (values: Id[][]) => {
|
||||
// const fullValues = buildValues(props.options, values)
|
||||
// const diffValue = getValuesDiff(fullValues, prevSelectValues);
|
||||
// const isIncrease = fullValues.length > prevSelectValues.length;
|
||||
// prevSelectValues.length = 0;
|
||||
//
|
||||
// if(values.length == 0){
|
||||
// setSelectValues([])
|
||||
// return;
|
||||
// }
|
||||
// // 判断操作的是否是全部
|
||||
// if(diffValue?.length == 1 && diffValue[0] == -1){
|
||||
// if(isIncrease) prevSelectValues.push(...allOptionValue);
|
||||
// setSelectValues(isIncrease ? [...allOptionValue] : [])
|
||||
// return;
|
||||
// }
|
||||
// // if(fullValues.length != allOptionValue.length){
|
||||
// // setSelectValues(fullValues.filter(s=>s.length == 1 && s[0] != -1))
|
||||
// // }else{
|
||||
// //
|
||||
// // }
|
||||
//
|
||||
// if(fullValues.filter(s=>s.length > 1 || s[0] != -1).length == allOptionValue.length - 1){
|
||||
// prevSelectValues.push(...allOptionValue);
|
||||
// setSelectValues( [...allOptionValue])
|
||||
// return;
|
||||
// }
|
||||
// prevSelectValues.push(...fullValues);
|
||||
setSelectValues(values.filter(s=>s.length > 1 || s[0] != -1))
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import ArticleCascader from "@/pages/news/components/article-cascader.tsx";
|
||||
import React, {useState} from "react";
|
||||
import {useSetState} from "ahooks";
|
||||
import useArticleTags from "@/hooks/useArticleTags.ts";
|
||||
import TagSelect from "@/components/form/tag-select.tsx";
|
||||
|
||||
export default function EditSearchForm(props: {
|
||||
onSubmit: (values: ApiArticleSearchParams) => void;
|
||||
@ -35,6 +36,7 @@ export default function EditSearchForm(props: {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="search-form-input flex gap-2 items-center">
|
||||
<Input
|
||||
@ -42,16 +44,17 @@ export default function EditSearchForm(props: {
|
||||
setParams({title: e.target.value})
|
||||
}}
|
||||
allowClear
|
||||
type="text" className="rounded px-3 w-[250px]"
|
||||
suffix={<SearchOutlined/>}
|
||||
placeholder="请输入你先搜索的关键词"
|
||||
type="text" className="rounded-3xl px-3 w-[270px]"
|
||||
prefix={<SearchOutlined/>}
|
||||
placeholder="请输入新闻标题关键词进行搜索"
|
||||
onPressEnter={handleSubmit}
|
||||
/>
|
||||
<span className="ml-5 text-sm">来源</span>
|
||||
<ArticleCascader
|
||||
options={articleTags}
|
||||
onChange={setTags}
|
||||
/>
|
||||
<Button type="primary" onClick={handleSubmit}>搜索</Button>
|
||||
<TagSelect onChange={setTags} options={articleTags}/>
|
||||
</div>
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user