fix
This commit is contained in:
parent
dcae1469bf
commit
426bfff6cd
|
|
@ -151,16 +151,18 @@ class ResourceCategoryManager:
|
||||||
return asdict(new_category)
|
return asdict(new_category)
|
||||||
|
|
||||||
def update_category(self, category_id: str, title: str = None,
|
def update_category(self, category_id: str, title: str = None,
|
||||||
ai_prompt: str = None, color: str = None) -> Optional[Dict]:
|
ai_prompt: str = None, color: str = None, is_active: bool = None) -> Optional[Dict]:
|
||||||
"""更新分类"""
|
"""更新分类"""
|
||||||
for i, category in enumerate(self.categories):
|
for i, category in enumerate(self.categories):
|
||||||
if category.id == category_id and category.is_active:
|
if category.id == category_id:
|
||||||
if title is not None:
|
if title is not None:
|
||||||
category.title = title
|
category.title = title
|
||||||
if ai_prompt is not None:
|
if ai_prompt is not None:
|
||||||
category.ai_prompt = ai_prompt
|
category.ai_prompt = ai_prompt
|
||||||
if color is not None:
|
if color is not None:
|
||||||
category.color = color
|
category.color = color
|
||||||
|
if is_active is not None:
|
||||||
|
category.is_active = is_active
|
||||||
category.updated_at = datetime.now().isoformat()
|
category.updated_at = datetime.now().isoformat()
|
||||||
|
|
||||||
self.categories[i] = category
|
self.categories[i] = category
|
||||||
|
|
@ -250,7 +252,8 @@ def main():
|
||||||
category_id,
|
category_id,
|
||||||
update_data.get('title'),
|
update_data.get('title'),
|
||||||
update_data.get('ai_prompt'),
|
update_data.get('ai_prompt'),
|
||||||
update_data.get('color')
|
update_data.get('color'),
|
||||||
|
update_data.get('is_active')
|
||||||
)
|
)
|
||||||
if result:
|
if result:
|
||||||
rpc.success(result)
|
rpc.success(result)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ pub struct UpdateCategoryRequest {
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
pub ai_prompt: Option<String>,
|
pub ai_prompt: Option<String>,
|
||||||
pub color: Option<String>,
|
pub color: Option<String>,
|
||||||
|
pub is_active: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 获取所有资源分类
|
/// 获取所有资源分类
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const ResourceCategoryPage: React.FC = () => {
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const [editingCategory, setEditingCategory] = useState<ResourceCategory | null>(null)
|
const [editingCategory, setEditingCategory] = useState<ResourceCategory | null>(null)
|
||||||
const [showCreateForm, setShowCreateForm] = useState(false)
|
const [showCreateForm, setShowCreateForm] = useState(false)
|
||||||
|
const [showDisabled, setShowDisabled] = useState(true) // 在管理页面默认显示所有分类
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
title: '',
|
title: '',
|
||||||
ai_prompt: '',
|
ai_prompt: '',
|
||||||
|
|
@ -93,6 +94,24 @@ const ResourceCategoryPage: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleToggleCategory = async (categoryId: string, isActive: boolean) => {
|
||||||
|
try {
|
||||||
|
const response = await ResourceCategoryService.updateCategory(categoryId, {
|
||||||
|
is_active: isActive
|
||||||
|
})
|
||||||
|
if (response.status && response.data) {
|
||||||
|
const updatedCategories = categories.map(cat =>
|
||||||
|
cat.id === categoryId ? response.data! : cat
|
||||||
|
)
|
||||||
|
setCategories(updatedCategories)
|
||||||
|
} else {
|
||||||
|
console.error('切换状态失败:', response.msg || '未知错误')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to toggle category:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const startEdit = (category: ResourceCategory) => {
|
const startEdit = (category: ResourceCategory) => {
|
||||||
setEditingCategory(category)
|
setEditingCategory(category)
|
||||||
setFormData({
|
setFormData({
|
||||||
|
|
@ -109,10 +128,16 @@ const ResourceCategoryPage: React.FC = () => {
|
||||||
setFormData({ title: '', ai_prompt: '', color: '#FF6B6B' })
|
setFormData({ title: '', ai_prompt: '', color: '#FF6B6B' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredCategories = categories.filter(category =>
|
const filteredCategories = categories.filter(category => {
|
||||||
category.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
// 搜索过滤
|
||||||
category.ai_prompt.toLowerCase().includes(searchTerm.toLowerCase())
|
const matchesSearch = category.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
)
|
category.ai_prompt.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
|
||||||
|
// 状态过滤:在管理页面显示所有分类,其他地方只显示启用的
|
||||||
|
const matchesStatus = showDisabled || category.is_active
|
||||||
|
|
||||||
|
return matchesSearch && matchesStatus
|
||||||
|
})
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -143,23 +168,40 @@ const ResourceCategoryPage: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<div className="flex items-center space-x-3 ml-4">
|
||||||
onClick={() => {
|
{/* 显示禁用分类开关 */}
|
||||||
setShowCreateForm(true)
|
<label className="flex items-center text-sm text-gray-600">
|
||||||
setEditingCategory(null)
|
<input
|
||||||
setFormData({ title: '', ai_prompt: '', color: '#FF6B6B' })
|
type="checkbox"
|
||||||
}}
|
checked={showDisabled}
|
||||||
className="ml-4 flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
onChange={(e) => setShowDisabled(e.target.checked)}
|
||||||
>
|
className="mr-2"
|
||||||
<Plus size={20} className="mr-2" />
|
/>
|
||||||
新建分类
|
显示禁用分类
|
||||||
</button>
|
</label>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setShowCreateForm(true)
|
||||||
|
setEditingCategory(null)
|
||||||
|
setFormData({ title: '', ai_prompt: '', color: '#FF6B6B' })
|
||||||
|
}}
|
||||||
|
className="flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||||
|
>
|
||||||
|
<Plus size={20} className="mr-2" />
|
||||||
|
新建分类
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 分类列表 */}
|
{/* 分类列表 */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
{filteredCategories.map((category) => (
|
{filteredCategories.map((category) => (
|
||||||
<div key={category.id} className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
<div key={category.id} className={`bg-white rounded-lg shadow-sm border p-6 transition-all ${
|
||||||
|
category.is_active
|
||||||
|
? 'border-gray-200'
|
||||||
|
: 'border-gray-300 bg-gray-50 opacity-75'
|
||||||
|
}`}>
|
||||||
{/* 分类标题和颜色 */}
|
{/* 分类标题和颜色 */}
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
|
|
@ -167,10 +209,28 @@ const ResourceCategoryPage: React.FC = () => {
|
||||||
className="w-4 h-4 rounded-full mr-3"
|
className="w-4 h-4 rounded-full mr-3"
|
||||||
style={{ backgroundColor: category.color }}
|
style={{ backgroundColor: category.color }}
|
||||||
/>
|
/>
|
||||||
<h3 className="text-lg font-semibold text-gray-900">{category.title}</h3>
|
<h3 className={`text-lg font-semibold ${category.is_active ? 'text-gray-900' : 'text-gray-400'}`}>
|
||||||
|
{category.title}
|
||||||
|
</h3>
|
||||||
|
{!category.is_active && (
|
||||||
|
<span className="ml-2 px-2 py-1 text-xs bg-gray-100 text-gray-500 rounded">
|
||||||
|
已禁用
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
{/* 启用/禁用开关 */}
|
||||||
|
<label className="relative inline-flex items-center cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={category.is_active}
|
||||||
|
onChange={(e) => handleToggleCategory(category.id, e.target.checked)}
|
||||||
|
className="sr-only peer"
|
||||||
|
/>
|
||||||
|
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||||
|
</label>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => startEdit(category)}
|
onClick={() => startEdit(category)}
|
||||||
className="p-2 text-gray-400 hover:text-blue-600 transition-colors"
|
className="p-2 text-gray-400 hover:text-blue-600 transition-colors"
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ export interface UpdateCategoryRequest {
|
||||||
title?: string
|
title?: string
|
||||||
ai_prompt?: string
|
ai_prompt?: string
|
||||||
color?: string
|
color?: string
|
||||||
|
is_active?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiResponse<T> {
|
export interface ApiResponse<T> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue