Files
MaliangAINovalWriter/AINoval/lib/widgets/setting/setting_relations_tab.dart
2025-09-10 00:07:52 +08:00

1035 lines
32 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:ainoval/models/novel_setting_item.dart';
import 'package:ainoval/models/setting_relationship_type.dart';
import 'package:ainoval/blocs/setting/setting_bloc.dart';
import 'package:ainoval/utils/web_theme.dart';
import 'package:ainoval/widgets/common/top_toast.dart';
/// 设定关系管理标签页
class SettingRelationsTab extends StatefulWidget {
final NovelSettingItem settingItem;
final String novelId;
final List<NovelSettingItem> availableItems;
final Function(NovelSettingItem)? onItemUpdated;
const SettingRelationsTab({
Key? key,
required this.settingItem,
required this.novelId,
required this.availableItems,
this.onItemUpdated,
}) : super(key: key);
@override
State<SettingRelationsTab> createState() => _SettingRelationsTabState();
}
class _SettingRelationsTabState extends State<SettingRelationsTab> {
bool _isAddingRelation = false;
late NovelSettingItem _currentSettingItem;
late List<NovelSettingItem> _currentAvailableItems;
@override
void initState() {
super.initState();
_currentSettingItem = widget.settingItem;
_currentAvailableItems = List.from(widget.availableItems);
}
@override
void didUpdateWidget(SettingRelationsTab oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.settingItem != widget.settingItem) {
_currentSettingItem = widget.settingItem;
}
if (oldWidget.availableItems != widget.availableItems) {
_currentAvailableItems = List.from(widget.availableItems);
}
}
@override
Widget build(BuildContext context) {
final isDark = WebTheme.isDarkMode(context);
return SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 父子关系区域
_buildHierarchySection(isDark),
const SizedBox(height: 16),
// 其他关系区域
_buildOtherRelationsSection(isDark),
const SizedBox(height: 16),
// 添加关系按钮
_buildAddRelationButton(isDark),
],
),
);
}
/// 构建层级关系区域(父子关系)
Widget _buildHierarchySection(bool isDark) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'层级关系',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: WebTheme.getTextColor(context),
),
),
const SizedBox(height: 12),
// 父设定
_buildParentSection(isDark),
const SizedBox(height: 16),
// 子设定
_buildChildrenSection(isDark),
],
);
}
/// 构建父设定区域
Widget _buildParentSection(bool isDark) {
// 从 relationships 中查找父关系
String? parentId;
if (_currentSettingItem.relationships != null) {
final parentRelation = _currentSettingItem.relationships!
.where((rel) => rel.type.value == 'parent')
.firstOrNull;
parentId = parentRelation?.targetItemId;
}
// 如果 relationships 中没有找到,再检查 parentId 字段
parentId ??= _currentSettingItem.parentId;
final hasParent = parentId != null;
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isDark ? WebTheme.darkGrey100 : WebTheme.grey50,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isDark ? WebTheme.darkGrey700 : WebTheme.grey200,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.arrow_upward,
size: 16,
color: Colors.blue,
),
const SizedBox(width: 8),
Text(
'父设定',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: WebTheme.getTextColor(context),
),
),
],
),
const SizedBox(height: 8),
if (hasParent) ...[
// 显示父设定
_buildParentItem(isDark),
] else ...[
// 无父设定时的占位
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12),
child: Column(
children: [
Icon(
Icons.account_tree_outlined,
size: 24,
color: WebTheme.getSecondaryTextColor(context).withOpacity(0.5),
),
const SizedBox(height: 8),
Text(
'没有父设定',
style: TextStyle(
fontSize: 12,
color: WebTheme.getSecondaryTextColor(context).withOpacity(0.7),
),
),
],
),
),
// 添加父设定按钮
_buildSetParentButton(isDark),
],
],
),
);
}
/// 构建父设定项目
Widget _buildParentItem(bool isDark) {
// 从 relationships 中查找父关系
String? parentId;
if (_currentSettingItem.relationships != null) {
final parentRelation = _currentSettingItem.relationships!
.where((rel) => rel.type.value == 'parent')
.firstOrNull;
parentId = parentRelation?.targetItemId;
}
// 如果 relationships 中没有找到,再检查 parentId 字段
parentId ??= _currentSettingItem.parentId;
final parentItem = _currentAvailableItems.firstWhere(
(item) => item.id == parentId,
orElse: () => NovelSettingItem(name: '未知父设定', type: 'unknown'),
);
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: WebTheme.getSurfaceColor(context),
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: isDark ? WebTheme.darkGrey600 : WebTheme.grey300,
),
),
child: Row(
children: [
// 图标
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
Icons.person,
size: 18,
color: Colors.blue,
),
),
const SizedBox(width: 12),
// 名称和类型
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
parentItem.name,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: WebTheme.getTextColor(context),
),
),
if (parentItem.type != null) ...[
const SizedBox(height: 2),
Text(
parentItem.type!,
style: TextStyle(
fontSize: 12,
color: WebTheme.getSecondaryTextColor(context),
),
),
],
],
),
),
// 移除按钮
IconButton(
icon: Icon(
Icons.close,
size: 16,
color: WebTheme.getSecondaryTextColor(context),
),
onPressed: () => _removeParent(),
tooltip: '移除父子关系',
),
],
),
);
}
/// 构建设置父设定按钮
Widget _buildSetParentButton(bool isDark) {
return SizedBox(
width: double.infinity,
child: TextButton.icon(
icon: Icon(
Icons.add,
size: 16,
color: WebTheme.getTextColor(context),
),
label: Text(
'设置父设定',
style: TextStyle(
fontSize: 13,
color: WebTheme.getTextColor(context),
),
),
onPressed: _showSetParentDialog,
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
side: BorderSide(
color: isDark ? WebTheme.darkGrey600 : WebTheme.grey300,
),
),
),
),
);
}
/// 构建子设定区域
Widget _buildChildrenSection(bool isDark) {
// 从两个地方查找子设定:
// 1. 其他设定的 parentId 字段指向当前设定
// 2. 其他设定的 relationships 中有指向当前设定的 parent 关系
final children = _currentAvailableItems.where((item) {
// 方法1检查 parentId 字段
if (item.parentId == _currentSettingItem.id) {
return true;
}
// 方法2检查 relationships 中的 parent 关系
if (item.relationships != null) {
return item.relationships!.any((rel) =>
rel.type.value == 'parent' && rel.targetItemId == _currentSettingItem.id);
}
return false;
}).toList();
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isDark ? WebTheme.darkGrey100 : WebTheme.grey50,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isDark ? WebTheme.darkGrey700 : WebTheme.grey200,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.arrow_downward,
size: 16,
color: Colors.green,
),
const SizedBox(width: 8),
Text(
'子设定 (${children.length})',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: WebTheme.getTextColor(context),
),
),
],
),
const SizedBox(height: 12),
if (children.isNotEmpty) ...[
// 子设定列表
...children.map((child) => _buildChildItem(child, isDark)).toList(),
] else ...[
// 无子设定时的占位
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12),
child: Column(
children: [
Icon(
Icons.account_tree_outlined,
size: 24,
color: WebTheme.getSecondaryTextColor(context).withOpacity(0.5),
),
const SizedBox(height: 8),
Text(
'没有子设定',
style: TextStyle(
fontSize: 12,
color: WebTheme.getSecondaryTextColor(context).withOpacity(0.7),
),
),
],
),
),
],
],
),
);
}
/// 构建子设定项目
Widget _buildChildItem(NovelSettingItem child, bool isDark) {
return Container(
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: WebTheme.getSurfaceColor(context),
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: isDark ? WebTheme.darkGrey600 : WebTheme.grey300,
),
),
child: Row(
children: [
// 图标
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
Icons.person,
size: 18,
color: Colors.green,
),
),
const SizedBox(width: 12),
// 名称和类型
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
child.name,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: WebTheme.getTextColor(context),
),
),
if (child.type != null) ...[
const SizedBox(height: 2),
Text(
child.type!,
style: TextStyle(
fontSize: 12,
color: WebTheme.getSecondaryTextColor(context),
),
),
],
],
),
),
// 移除按钮
IconButton(
icon: Icon(
Icons.close,
size: 16,
color: WebTheme.getSecondaryTextColor(context),
),
onPressed: () => _removeChild(child.id!),
tooltip: '移除父子关系',
),
],
),
);
}
/// 构建其他关系区域
Widget _buildOtherRelationsSection(bool isDark) {
final relationships = _currentSettingItem.relationships ?? [];
final nonHierarchicalRels = relationships.where(
(rel) => !rel.type.isHierarchical,
).toList();
// 按关系类型分组
final groupedRelations = <String, List<SettingRelationship>>{};
for (final rel in nonHierarchicalRels) {
final groupName = _getRelationGroupName(rel.type);
groupedRelations.putIfAbsent(groupName, () => []).add(rel);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'其他关系',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: WebTheme.getTextColor(context),
),
),
const SizedBox(height: 12),
if (groupedRelations.isEmpty) ...[
// 无关系时的占位
Container(
width: double.infinity,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: isDark ? WebTheme.darkGrey100 : WebTheme.grey50,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isDark ? WebTheme.darkGrey700 : WebTheme.grey200,
),
),
child: Column(
children: [
Icon(
Icons.link_off,
size: 24,
color: WebTheme.getSecondaryTextColor(context).withOpacity(0.5),
),
const SizedBox(height: 8),
Text(
'没有其他关系',
style: TextStyle(
fontSize: 12,
color: WebTheme.getSecondaryTextColor(context).withOpacity(0.7),
),
),
],
),
),
] else ...[
// 按分组显示关系
...groupedRelations.entries.map((entry) {
return _buildRelationGroup(entry.key, entry.value, isDark);
}).toList(),
],
],
);
}
/// 构建关系分组
Widget _buildRelationGroup(String groupName, List<SettingRelationship> relations, bool isDark) {
return Container(
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isDark ? WebTheme.darkGrey100 : WebTheme.grey50,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isDark ? WebTheme.darkGrey700 : WebTheme.grey200,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$groupName (${relations.length})',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: WebTheme.getTextColor(context),
),
),
const SizedBox(height: 12),
...relations.map((rel) => _buildRelationItem(rel, isDark)).toList(),
],
),
);
}
/// 构建关系项目
Widget _buildRelationItem(SettingRelationship relationship, bool isDark) {
final targetItem = _currentAvailableItems.firstWhere(
(item) => item.id == relationship.targetItemId,
orElse: () => NovelSettingItem(name: '未知设定', type: 'unknown'),
);
return Container(
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: WebTheme.getSurfaceColor(context),
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: isDark ? WebTheme.darkGrey600 : WebTheme.grey300,
),
),
child: Row(
children: [
// 关系类型图标
Container(
width: 28,
height: 28,
decoration: BoxDecoration(
color: _getRelationColor(relationship.type).withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
_getRelationIcon(relationship.type),
size: 18,
color: _getRelationColor(relationship.type),
),
),
const SizedBox(width: 12),
// 关系信息
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
relationship.type.displayName,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: _getRelationColor(relationship.type),
),
),
const SizedBox(width: 8),
Icon(
Icons.arrow_forward,
size: 12,
color: WebTheme.getSecondaryTextColor(context),
),
const SizedBox(width: 8),
Expanded(
child: Text(
targetItem.name,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: WebTheme.getTextColor(context),
),
),
),
],
),
if (relationship.description != null) ...[
const SizedBox(height: 4),
Text(
relationship.description!,
style: TextStyle(
fontSize: 12,
color: WebTheme.getSecondaryTextColor(context),
),
),
],
],
),
),
// 操作按钮
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(
Icons.edit,
size: 16,
color: WebTheme.getSecondaryTextColor(context),
),
onPressed: () => _editRelation(relationship),
tooltip: '编辑关系',
),
IconButton(
icon: Icon(
Icons.delete,
size: 16,
color: Colors.red,
),
onPressed: () => _removeRelation(relationship),
tooltip: '删除关系',
),
],
),
],
),
);
}
/// 构建添加关系按钮
Widget _buildAddRelationButton(bool isDark) {
return SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
icon: Icon(
Icons.add,
size: 16,
),
label: Text('添加关系'),
onPressed: _isAddingRelation ? null : _showAddRelationDialog,
style: ElevatedButton.styleFrom(
backgroundColor: WebTheme.getTextColor(context),
foregroundColor: WebTheme.getBackgroundColor(context),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
);
}
/// 获取关系分组名称
String _getRelationGroupName(SettingRelationshipType type) {
final groups = SettingRelationshipType.groupedTypes;
for (final entry in groups.entries) {
if (entry.value.contains(type)) {
return entry.key;
}
}
return '其他';
}
/// 获取关系图标
IconData _getRelationIcon(SettingRelationshipType type) {
switch (type) {
case SettingRelationshipType.friend:
return Icons.favorite;
case SettingRelationshipType.enemy:
return Icons.bolt;
case SettingRelationshipType.ally:
return Icons.handshake;
case SettingRelationshipType.rival:
return Icons.sports_martial_arts;
case SettingRelationshipType.owns:
return Icons.inventory;
case SettingRelationshipType.ownedBy:
return Icons.person;
case SettingRelationshipType.memberOf:
return Icons.group;
case SettingRelationshipType.contains:
return Icons.folder;
case SettingRelationshipType.containedBy:
return Icons.folder_open;
case SettingRelationshipType.adjacent:
return Icons.place;
case SettingRelationshipType.uses:
return Icons.build;
case SettingRelationshipType.usedBy:
return Icons.engineering;
case SettingRelationshipType.related:
return Icons.link;
default:
return Icons.more_horiz;
}
}
/// 获取关系颜色
Color _getRelationColor(SettingRelationshipType type) {
switch (type) {
case SettingRelationshipType.friend:
return Colors.green;
case SettingRelationshipType.enemy:
return Colors.red;
case SettingRelationshipType.ally:
return Colors.blue;
case SettingRelationshipType.rival:
return Colors.orange;
case SettingRelationshipType.owns:
case SettingRelationshipType.ownedBy:
return Colors.purple;
case SettingRelationshipType.memberOf:
return Colors.indigo;
case SettingRelationshipType.contains:
case SettingRelationshipType.containedBy:
return Colors.teal;
case SettingRelationshipType.adjacent:
return Colors.lime;
case SettingRelationshipType.uses:
case SettingRelationshipType.usedBy:
return Colors.amber;
case SettingRelationshipType.related:
return Colors.grey;
default:
return Colors.grey;
}
}
/// 显示设置父设定对话框
void _showSetParentDialog() {
final availableParents = _currentAvailableItems.where(
(item) => item.id != _currentSettingItem.id && item.parentId != _currentSettingItem.id,
).toList();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('设置父设定'),
content: Container(
width: 300,
child: Column(
mainAxisSize: MainAxisSize.min,
children: availableParents.map((item) {
return ListTile(
leading: Icon(Icons.person),
title: Text(item.name),
subtitle: item.type != null ? Text(item.type!) : null,
onTap: () {
Navigator.of(context).pop();
_setParent(item.id!);
},
);
}).toList(),
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('取消'),
),
],
),
);
}
/// 显示添加关系对话框
void _showAddRelationDialog() {
// TODO: 实现添加关系对话框
TopToast.info(context, '添加关系功能开发中...');
}
/// 编辑关系
void _editRelation(SettingRelationship relationship) {
// TODO: 实现编辑关系功能
TopToast.info(context, '编辑关系功能开发中...');
}
/// 设置父设定
void _setParent(String parentId) {
if (_currentSettingItem.id == null) return;
// 移除现有的父关系,然后添加新的父关系
final updatedRelationships = List<SettingRelationship>.from(_currentSettingItem.relationships ?? []);
updatedRelationships.removeWhere((rel) => rel.type.value == 'parent');
// 添加新的父关系
updatedRelationships.add(SettingRelationship(
targetItemId: parentId,
type: SettingRelationshipType.parent,
));
// 先更新本地状态
setState(() {
_currentSettingItem = _currentSettingItem.copyWith(
parentId: parentId,
relationships: updatedRelationships,
);
});
// 立即通知父组件更新
if (widget.onItemUpdated != null) {
widget.onItemUpdated!(_currentSettingItem);
}
// 显示成功提示
TopToast.success(context, '已设置父设定');
// 异步保存到后端 - 使用专门的父子关系设置 API
_saveRelationshipAsync(() {
context.read<SettingBloc>().add(SetParentChildRelationship(
novelId: widget.novelId,
childId: _currentSettingItem.id!,
parentId: parentId,
));
});
}
/// 移除父设定
void _removeParent() {
if (_currentSettingItem.id == null) return;
// 从 relationships 中查找父关系
String? parentId;
if (_currentSettingItem.relationships != null) {
final parentRelation = _currentSettingItem.relationships!
.where((rel) => rel.type.value == 'parent')
.firstOrNull;
parentId = parentRelation?.targetItemId;
}
// 如果 relationships 中没有找到,再检查 parentId 字段
parentId ??= _currentSettingItem.parentId;
if (parentId == null) return;
final originalParentId = parentId;
// 移除所有父关系
final updatedRelationships = _currentSettingItem.relationships?.where((rel) => rel.type.value != 'parent').toList();
// 创建一个新的NovelSettingItem移除父关系
final updatedItem = NovelSettingItem(
id: _currentSettingItem.id,
novelId: _currentSettingItem.novelId,
userId: _currentSettingItem.userId,
name: _currentSettingItem.name,
type: _currentSettingItem.type,
content: _currentSettingItem.content,
description: _currentSettingItem.description,
attributes: _currentSettingItem.attributes,
imageUrl: _currentSettingItem.imageUrl,
relationships: updatedRelationships,
sceneIds: _currentSettingItem.sceneIds,
priority: _currentSettingItem.priority,
generatedBy: _currentSettingItem.generatedBy,
tags: _currentSettingItem.tags,
status: _currentSettingItem.status,
vector: _currentSettingItem.vector,
createdAt: _currentSettingItem.createdAt,
updatedAt: _currentSettingItem.updatedAt,
isAiSuggestion: _currentSettingItem.isAiSuggestion,
metadata: _currentSettingItem.metadata,
parentId: null, // 显式设置为null
childrenIds: _currentSettingItem.childrenIds,
nameAliasTracking: _currentSettingItem.nameAliasTracking,
aiContextTracking: _currentSettingItem.aiContextTracking,
referenceUpdatePolicy: _currentSettingItem.referenceUpdatePolicy,
);
// 先更新本地状态
setState(() {
_currentSettingItem = updatedItem;
});
// 立即通知父组件更新
if (widget.onItemUpdated != null) {
widget.onItemUpdated!(_currentSettingItem);
}
// 显示成功提示
TopToast.success(context, '已移除父子关系');
// 异步保存到后端 - 使用专门的父子关系移除 API
_saveRelationshipAsync(() {
context.read<SettingBloc>().add(RemoveParentChildRelationship(
novelId: widget.novelId,
childId: _currentSettingItem.id!,
));
});
}
/// 移除子设定
void _removeChild(String childId) {
if (_currentSettingItem.id == null) return;
// 先更新本地可用项目列表中的子项目
setState(() {
_currentAvailableItems = _currentAvailableItems.map((item) {
if (item.id == childId) {
// 创建新的NovelSettingItem显式设置parentId为null
return NovelSettingItem(
id: item.id,
novelId: item.novelId,
userId: item.userId,
name: item.name,
type: item.type,
content: item.content,
description: item.description,
attributes: item.attributes,
imageUrl: item.imageUrl,
relationships: item.relationships,
sceneIds: item.sceneIds,
priority: item.priority,
generatedBy: item.generatedBy,
tags: item.tags,
status: item.status,
vector: item.vector,
createdAt: item.createdAt,
updatedAt: item.updatedAt,
isAiSuggestion: item.isAiSuggestion,
metadata: item.metadata,
parentId: null, // 显式设置为null
childrenIds: item.childrenIds,
nameAliasTracking: item.nameAliasTracking,
aiContextTracking: item.aiContextTracking,
referenceUpdatePolicy: item.referenceUpdatePolicy,
);
}
return item;
}).toList();
});
// 显示成功提示
TopToast.success(context, '已移除父子关系');
// 异步保存到后端 - 使用专门的父子关系移除 API
_saveRelationshipAsync(() {
context.read<SettingBloc>().add(RemoveParentChildRelationship(
novelId: widget.novelId,
childId: childId,
));
});
}
/// 移除关系
void _removeRelation(SettingRelationship relationship) {
if (_currentSettingItem.id == null) return;
// 先更新本地状态,移除关系
setState(() {
final relationships = List<SettingRelationship>.from(_currentSettingItem.relationships ?? []);
relationships.removeWhere((rel) =>
rel.targetItemId == relationship.targetItemId &&
rel.type == relationship.type);
_currentSettingItem = _currentSettingItem.copyWith(relationships: relationships);
});
// 立即通知父组件更新
if (widget.onItemUpdated != null) {
widget.onItemUpdated!(_currentSettingItem);
}
// 显示成功提示
TopToast.success(context, '已删除关系');
// 异步保存到后端
_saveRelationshipAsync(() {
context.read<SettingBloc>().add(RemoveSettingRelationship(
novelId: widget.novelId,
itemId: _currentSettingItem.id!,
targetItemId: relationship.targetItemId,
relationshipType: relationship.type.value,
));
});
}
/// 异步保存关系变更到后端
Future<void> _saveRelationshipAsync(VoidCallback action) async {
try {
action();
} catch (e) {
// 静默处理错误,不干扰用户体验
}
}
}