Răsfoiți Sursa

Add 增加离线模式的字典维护

Yue 4 zile în urmă
părinte
comite
f62e4c29fa

+ 117 - 0
UI/CF.APP/chicken_farm/lib/core/config/default_dicts.dart

@@ -0,0 +1,117 @@
+import 'package:chicken_farm/modes/system/dict.dart';
+
+/// 默认字典配置
+class DefaultDicts {
+  /// 获取系统预设的字典类型和数据
+  static Map<String, List<DictDataModel>> getDefaultDicts() {
+    return {
+      'chicken_cull_reason': [
+        DictDataModel(
+          dictCode: 1,
+          dictSort: 1,
+          dictLabel: '腿病',
+          dictValue: '1',
+          dictType: 'culling_reason',
+        ),
+        DictDataModel(
+          dictCode: 2,
+          dictSort: 2,
+          dictLabel: '腹水',
+          dictValue: '2',
+          dictType: 'culling_reason',
+        ),
+        DictDataModel(
+          dictCode: 3,
+          dictSort: 3,
+          dictLabel: '细菌感染',
+          dictValue: '3',
+          dictType: 'culling_reason',
+        ),
+        DictDataModel(
+          dictCode: 4,
+          dictSort: 4,
+          dictLabel: '外伤',
+          dictValue: '4',
+          dictType: 'culling_reason',
+        ),
+        DictDataModel(
+          dictCode: 5,
+          dictSort: 5,
+          dictLabel: '其他',
+          dictValue: '5',
+          dictType: 'culling_reason',
+        ),
+        DictDataModel(
+          dictCode: 6,
+          dictSort: 6,
+          dictLabel: '转群',
+          dictValue: '9',
+          dictType: 'culling_reason',
+        ),
+      ],
+      'chicken_disposal_method': [
+        DictDataModel(
+          dictCode: 1,
+          dictSort: 1,
+          dictLabel: '无害化',
+          dictValue: '1',
+          dictType: 'chicken_disposal_method',
+        ),
+        DictDataModel(
+          dictCode: 2,
+          dictSort: 2,
+          dictLabel: '食堂',
+          dictValue: '2',
+          dictType: 'chicken_disposal_method',
+        ),
+        DictDataModel(
+          dictCode: 3,
+          dictSort: 3,
+          dictLabel: '屠宰场',
+          dictValue: '3',
+          dictType: 'chicken_disposal_method',
+        ),
+        DictDataModel(
+          dictCode: 4,
+          dictSort: 4,
+          dictLabel: '转群',
+          dictValue: '9',
+          dictType: 'chicken_disposal_method',
+        ),
+      ],
+    };
+  }
+
+  static String getDictName(String type) {
+    switch (type) {
+      case 'chicken_cull_reason':
+        return '淘汰原因';
+      case 'chicken_disposal_method':
+        return '淘汰处置方式';
+      default:
+        return '';
+    }
+  }
+
+  static List<String> getAllDictTypes() {
+    return ['chicken_cull_reason', 'chicken_disposal_method'];
+  }
+
+  /// 根据字典类型获取字典项列表
+  static List<DictDataModel>? getDictByType(String type) {
+    final dicts = getDefaultDicts();
+    return dicts[type];
+  }
+
+  /// 根据字典类型和值查找字典项
+  static DictDataModel? getDictByTypeAndValue(String type, String value) {
+    final dicts = getDictByType(type);
+    if (dicts == null) return null;
+
+    try {
+      return dicts.firstWhere((dict) => dict.dictValue == value);
+    } catch (e) {
+      return null;
+    }
+  }
+}

+ 136 - 0
UI/CF.APP/chicken_farm/lib/core/services/offline_dict_service.dart

@@ -0,0 +1,136 @@
+import 'dart:convert';
+import 'package:chicken_farm/core/utils/storage.dart';
+import 'package:chicken_farm/modes/system/dict.dart';
+import 'package:chicken_farm/core/config/default_dicts.dart';
+
+/// 离线字典服务
+/// 处理本地字典数据的存储和检索
+class OfflineDictService {
+  static final OfflineDictService _instance = OfflineDictService._internal();
+  static const String _localStorageKey = 'cf_offline_dicts';
+  static bool _initialized = false;
+
+  factory OfflineDictService() => _instance;
+
+  OfflineDictService._internal();
+
+  /// 初始化默认字典数据
+  Future<void> _initDefaultDicts() async {
+    if (_initialized) return;
+
+    final jsonString = await StorageUtils.get(_localStorageKey);
+    if (jsonString == null || jsonString.isEmpty) {
+      // 如果本地没有数据,则初始化默认数据
+      final defaultDicts = DefaultDicts.getDefaultDicts();
+      await _saveAllDicts(defaultDicts);
+    }
+
+    _initialized = true;
+  }
+
+  /// 获取所有本地字典数据
+  Future<Map<String, List<DictDataModel>>> getAllDicts() async {
+    await _initDefaultDicts();
+
+    final jsonString = await StorageUtils.get(_localStorageKey);
+    if (jsonString != null && jsonString.isNotEmpty) {
+      try {
+        final Map<String, dynamic> jsonMap = json.decode(jsonString);
+        final Map<String, List<DictDataModel>> result = {};
+
+        jsonMap.forEach((key, value) {
+          if (value is List) {
+            result[key] = value
+                .map(
+                  (item) =>
+                      DictDataModel.fromJson(item as Map<String, dynamic>),
+                )
+                .toList();
+          }
+        });
+
+        return result;
+      } catch (e) {
+        // 解析失败,返回空字典
+        return {};
+      }
+    }
+    return {};
+  }
+
+  /// 根据字典类型获取字典数据列表
+  Future<List<DictDataModel>?> getDictByType(String dictType) async {
+    await _initDefaultDicts();
+
+    final allDicts = await getAllDicts();
+    return allDicts[dictType];
+  }
+
+  /// 保存字典数据
+  Future<void> saveDict(String dictType, List<DictDataModel> dictList) async {
+    await _initDefaultDicts();
+
+    final allDicts = await getAllDicts();
+    allDicts[dictType] = dictList;
+    await _saveAllDicts(allDicts);
+  }
+
+  /// 删除指定类型的字典
+  Future<void> removeDict(String dictType) async {
+    await _initDefaultDicts();
+
+    final allDicts = await getAllDicts();
+    allDicts.remove(dictType);
+    await _saveAllDicts(allDicts);
+  }
+
+  /// 保存所有字典数据
+  Future<void> _saveAllDicts(Map<String, List<DictDataModel>> dicts) async {
+    final Map<String, dynamic> jsonMap = {};
+    dicts.forEach((key, value) {
+      jsonMap[key] = value.map((item) => item.toJson()).toList();
+    });
+    final jsonString = json.encode(jsonMap);
+    await StorageUtils.set(_localStorageKey, jsonString);
+  }
+
+  /// 获取所有字典类型
+  Future<List<String>> getAllDictTypes() async {
+    return DefaultDicts.getAllDictTypes();
+  }
+
+  /// 添加或更新字典项
+  Future<void> addOrUpdateDictItem(
+    String dictType,
+    DictDataModel dictItem,
+  ) async {
+    await _initDefaultDicts();
+
+    final dictList = await getDictByType(dictType) ?? [];
+
+    // 查找是否存在相同的dictCode
+    final existingIndex = dictList.indexWhere(
+      (item) => item.dictCode == dictItem.dictCode,
+    );
+    if (existingIndex >= 0) {
+      // 更新现有项
+      dictList[existingIndex] = dictItem;
+    } else {
+      // 添加新项
+      dictList.add(dictItem);
+    }
+
+    await saveDict(dictType, dictList);
+  }
+
+  /// 删除字典项
+  Future<void> removeDictItem(String dictType, int dictCode) async {
+    await _initDefaultDicts();
+
+    final dictList = await getDictByType(dictType);
+    if (dictList != null) {
+      dictList.removeWhere((item) => item.dictCode == dictCode);
+      await saveDict(dictType, dictList);
+    }
+  }
+}

+ 295 - 0
UI/CF.APP/chicken_farm/lib/pages/dict/dict_manage_page.dart

@@ -0,0 +1,295 @@
+import 'package:chicken_farm/components/vb_app_bar.dart';
+import 'package:chicken_farm/core/config/default_dicts.dart';
+import 'package:chicken_farm/modes/system/dict.dart';
+import 'package:chicken_farm/stores/dict_stroe.dart';
+import 'package:flutter/material.dart';
+
+class DictManagePage extends StatefulWidget {
+  const DictManagePage({super.key});
+
+  @override
+  State<DictManagePage> createState() => _DictManagePageState();
+}
+
+class _DictManagePageState extends State<DictManagePage> {
+  final DictStore _dictStore = DictStore();
+  late Future<Map<String, List<DictDataModel>>> _dictsFuture;
+  final Set<String> _expandedTypes = <String>{};
+
+  @override
+  void initState() {
+    super.initState();
+    _loadDicts();
+  }
+
+  void _loadDicts() {
+    setState(() {
+      _dictsFuture = _dictStore.getAllOfflineDicts();
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: VberAppBar(title: '字典维护'),
+      body: FutureBuilder<Map<String, List<DictDataModel>>>(
+        future: _dictsFuture,
+        builder: (context, snapshot) {
+          if (snapshot.connectionState == ConnectionState.waiting) {
+            return const Center(child: CircularProgressIndicator());
+          }
+
+          if (snapshot.hasError) {
+            return Center(child: Text('加载失败: ${snapshot.error}'));
+          }
+
+          final dicts = snapshot.data ?? {};
+
+          if (dicts.isEmpty) {
+            return const Center(
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  Icon(Icons.info, size: 48, color: Colors.grey),
+                  SizedBox(height: 16),
+                  Text('暂无字典数据', style: TextStyle(fontSize: 16)),
+                ],
+              ),
+            );
+          }
+
+          return ListView.builder(
+            itemCount: dicts.length,
+            itemBuilder: (context, index) {
+              final dictType = dicts.keys.elementAt(index);
+              final dictItems = dicts[dictType] ?? [];
+              final dictName = DefaultDicts.getDictName(dictType);
+              return Card(
+                margin: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
+                child: Theme(
+                  data: Theme.of(
+                    context,
+                  ).copyWith(dividerColor: Colors.transparent),
+                  child: ExpansionTile(
+                    key: Key(dictType),
+                    initiallyExpanded: _expandedTypes.contains(dictType),
+                    onExpansionChanged: (expanded) {
+                      setState(() {
+                        if (expanded) {
+                          _expandedTypes.add(dictType);
+                        } else {
+                          _expandedTypes.remove(dictType);
+                        }
+                      });
+                    },
+                    title: Text('$dictName (${dictItems.length})'),
+                    children: [
+                      if (dictItems.isEmpty)
+                        const ListTile(title: Text('该类型下暂无数据'))
+                      else
+                        ...dictItems.map(
+                          (item) => ListTile(
+                            title: Text(item.dictLabel),
+                            subtitle: Text('值: ${item.dictValue}'),
+                            trailing: Row(
+                              mainAxisSize: MainAxisSize.min,
+                              children: [
+                                IconButton(
+                                  icon: const Icon(Icons.edit, size: 18),
+                                  onPressed: () =>
+                                      _editDictItem(dictType, item),
+                                ),
+                                IconButton(
+                                  icon: const Icon(Icons.delete, size: 18),
+                                  onPressed: () =>
+                                      _deleteDictItem(dictType, item),
+                                ),
+                              ],
+                            ),
+                          ),
+                        ),
+                      ListTile(
+                        leading: const Icon(Icons.add, color: Colors.blue),
+                        title: const Text('添加新项目'),
+                        onTap: () => _addNewDictItem(dictType),
+                      ),
+                    ],
+                  ),
+                ),
+              );
+            },
+          );
+        },
+      ),
+    );
+  }
+
+  void _addNewDictItem(String dictType) async {
+    final labelController = TextEditingController();
+    final valueController = TextEditingController();
+    final sortController = TextEditingController(text: '0');
+
+    final result = await showDialog<bool>(
+      context: context,
+      builder: (context) => AlertDialog(
+        title: const Text('添加字典项'),
+        content: Column(
+          mainAxisSize: MainAxisSize.min,
+          children: [
+            TextField(
+              controller: labelController,
+              decoration: const InputDecoration(labelText: '标签'),
+            ),
+            TextField(
+              controller: valueController,
+              decoration: const InputDecoration(labelText: '值'),
+            ),
+            TextField(
+              controller: sortController,
+              decoration: const InputDecoration(labelText: '排序'),
+              keyboardType: TextInputType.number,
+            ),
+          ],
+        ),
+        actions: [
+          TextButton(
+            onPressed: () => Navigator.of(context).pop(false),
+            child: const Text('取消'),
+          ),
+          TextButton(
+            onPressed: () => Navigator.of(context).pop(true),
+            child: const Text('确定'),
+          ),
+        ],
+      ),
+    );
+
+    if (result == true) {
+      final dictItems = (await _dictStore.getDictByType(dictType)) ?? [];
+
+      // 生成唯一的dictCode
+      int maxCode = 0;
+      for (final item in dictItems) {
+        if (item.dictCode > maxCode) {
+          maxCode = item.dictCode;
+        }
+      }
+
+      final newItem = DictDataModel(
+        dictCode: maxCode + 1,
+        dictSort: int.tryParse(sortController.text) ?? 0,
+        dictLabel: labelController.text,
+        dictValue: valueController.text,
+        dictType: dictType,
+      );
+
+      try {
+        await _dictStore.addDictItem(dictType, newItem);
+        _loadDicts(); // 重新加载数据
+      } catch (e) {
+        if (mounted) {
+          ScaffoldMessenger.of(
+            context,
+          ).showSnackBar(SnackBar(content: Text('操作失败: $e')));
+        }
+      }
+    }
+  }
+
+  void _editDictItem(String dictType, DictDataModel item) async {
+    final labelController = TextEditingController(text: item.dictLabel);
+    final valueController = TextEditingController(text: item.dictValue);
+    final sortController = TextEditingController(
+      text: item.dictSort.toString(),
+    );
+
+    final result = await showDialog<bool>(
+      context: context,
+      builder: (context) => AlertDialog(
+        title: const Text('编辑字典项'),
+        content: Column(
+          mainAxisSize: MainAxisSize.min,
+          children: [
+            TextField(
+              controller: labelController,
+              decoration: const InputDecoration(labelText: '标签'),
+            ),
+            TextField(
+              controller: valueController,
+              decoration: const InputDecoration(labelText: '值'),
+            ),
+            TextField(
+              controller: sortController,
+              decoration: const InputDecoration(labelText: '排序'),
+              keyboardType: TextInputType.number,
+            ),
+          ],
+        ),
+        actions: [
+          TextButton(
+            onPressed: () => Navigator.of(context).pop(false),
+            child: const Text('取消'),
+          ),
+          TextButton(
+            onPressed: () => Navigator.of(context).pop(true),
+            child: const Text('确定'),
+          ),
+        ],
+      ),
+    );
+
+    if (result == true) {
+      final updatedItem = DictDataModel(
+        dictCode: item.dictCode,
+        dictSort: int.tryParse(sortController.text) ?? item.dictSort,
+        dictLabel: labelController.text,
+        dictValue: valueController.text,
+        dictType: dictType,
+      );
+
+      try {
+        await _dictStore.updateDictItem(dictType, updatedItem);
+        _loadDicts(); // 重新加载数据
+      } catch (e) {
+        if (mounted) {
+          ScaffoldMessenger.of(
+            context,
+          ).showSnackBar(SnackBar(content: Text('操作失败: $e')));
+        }
+      }
+    }
+  }
+
+  void _deleteDictItem(String dictType, DictDataModel item) async {
+    final confirm = await showDialog<bool>(
+      context: context,
+      builder: (context) => AlertDialog(
+        title: const Text('确认删除'),
+        content: Text('确定要删除 "${item.dictLabel}" 吗?'),
+        actions: [
+          TextButton(
+            onPressed: () => Navigator.of(context).pop(false),
+            child: const Text('取消'),
+          ),
+          TextButton(
+            onPressed: () => Navigator.of(context).pop(true),
+            child: const Text('确定'),
+          ),
+        ],
+      ),
+    );
+
+    if (confirm == true) {
+      try {
+        await _dictStore.removeDictItem(dictType, item.dictCode);
+        _loadDicts(); // 重新加载数据
+      } catch (e) {
+        if (mounted) {
+          ScaffoldMessenger.of(
+            context,
+          ).showSnackBar(SnackBar(content: Text('删除失败: $e')));
+        }
+      }
+    }
+  }
+}

+ 31 - 0
UI/CF.APP/chicken_farm/lib/pages/home/_profile/dict_config_button.dart

@@ -0,0 +1,31 @@
+import 'package:chicken_farm/routes/app_routes.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+class DictConfigButton extends StatelessWidget {
+  const DictConfigButton({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return SizedBox(
+      width: double.infinity,
+      child: ElevatedButton.icon(
+        onPressed: () {
+          context.pushNamed(AppRouteNames.dictManage);
+        },
+        icon: const Icon(Icons.book),
+        label: const Text('字典配置'),
+        style: ElevatedButton.styleFrom(
+          padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15),
+          textStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
+          backgroundColor: Theme.of(context).colorScheme.primary,
+          foregroundColor: Colors.white,
+          elevation: 12,
+          shape: RoundedRectangleBorder(
+            borderRadius: BorderRadius.circular(25),
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 2 - 1
UI/CF.APP/chicken_farm/lib/pages/home/home_page.dart

@@ -1,4 +1,5 @@
 import 'package:chicken_farm/components/vb_app_bar.dart';
+import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/core/services/offline_storage_service.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/core/utils/service_checker.dart';
@@ -75,7 +76,7 @@ class _HomePageState extends ConsumerState<HomePage> {
 
   // 检查是否有待上传数据,如果有则导航到上传页面
   Future<void> _checkAndNavigateToUpload() async {
-    if (!_needCheck) {
+    if (!_needCheck || AppConfig.isOffline) {
       return;
     }
     _needCheck = false;

+ 44 - 2
UI/CF.APP/chicken_farm/lib/pages/home/profile.dart

@@ -6,16 +6,50 @@ import 'package:chicken_farm/pages/home/_profile/user_info_card.dart';
 import 'package:chicken_farm/pages/home/_profile/upload_data_button.dart';
 import 'package:chicken_farm/pages/home/_profile/clear_cache_button.dart';
 import 'package:chicken_farm/pages/home/_profile/config_button.dart';
+import 'package:chicken_farm/pages/home/_profile/dict_config_button.dart';
 // import 'package:chicken_farm/pages/home/_profile/rfid_config_button.dart';
 // import 'package:chicken_farm/pages/home/_profile/scanner_light_button.dart';
 import 'package:chicken_farm/pages/home/_profile/logout_button.dart';
 
+final tapCountProvider = StateProvider<int>((ref) => 0);
+final lastTapTimeProvider = StateProvider<DateTime>((ref) => DateTime.now());
+
 class ProfilePage extends ConsumerWidget {
   const ProfilePage({super.key});
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
     final authState = ref.watch(authStoreProvider);
+    final tapCount = ref.watch(tapCountProvider);
+
+    // 判断是否应该显示字典维护按钮 (连续点击5次后显示)
+    final showDictConfig = tapCount >= 5;
+
+    void handleUserCardTap() {
+      final now = DateTime.now();
+      final previousTapTime = ref.read(lastTapTimeProvider);
+      final tapCountNotifier = ref.read(tapCountProvider.notifier);
+      final lastTapTimeNotifier = ref.read(lastTapTimeProvider.notifier);
+
+      // 如果距离上次点击超过1秒,则重置计数
+      if (now.difference(previousTapTime).inMilliseconds > 1000) {
+        tapCountNotifier.state = 1;
+      } else {
+        tapCountNotifier.state = tapCount + 1;
+
+        // 如果达到5次点击,显示提示
+        if (tapCountNotifier.state == 5) {
+          ScaffoldMessenger.of(context).showSnackBar(
+            const SnackBar(
+              content: Text('已解锁字典维护功能'),
+              duration: Duration(seconds: 2),
+            ),
+          );
+        }
+      }
+
+      lastTapTimeNotifier.state = now;
+    }
 
     return Scaffold(
       body: Padding(
@@ -31,12 +65,20 @@ class ProfilePage extends ConsumerWidget {
                   child: Column(
                     crossAxisAlignment: CrossAxisAlignment.start,
                     children: [
-                      UserInfoCard(user: authState.user!),
-                      const SizedBox(height: 20),
                       if (AppConfig.isOffline) ...[
+                        GestureDetector(
+                          onTap: handleUserCardTap,
+                          child: UserInfoCard(user: authState.user!),
+                        ),
+                        const SizedBox(height: 20),
+                        if (showDictConfig) ...[
+                          const DictConfigButton(),
+                          const SizedBox(height: 20),
+                        ],
                         const ClearCacheButton(),
                         const SizedBox(height: 20),
                       ] else ...[
+                        UserInfoCard(user: authState.user!),
                         const UploadDataButton(),
                         const SizedBox(height: 20),
                         const ClearCacheButton(),

+ 9 - 3
UI/CF.APP/chicken_farm/lib/routes/app_routes.dart

@@ -1,3 +1,4 @@
+import 'package:chicken_farm/pages/dict/dict_manage_page.dart';
 import 'package:chicken_farm/stores/auth_store.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -24,7 +25,7 @@ class AppRouteNames {
   static const String home = '/home';
   static const String checkin = '/checkin';
   static const String checkinRecord = '/checkin_record';
-  static const String bindChicken = '/bind_wing_tag_num';
+  static const String bindChicken = '/bind_chicken';
   static const String bindwingTagNumWin =
       '/bind_wing_tag_num_win'; // Windows平台个体绑定
   static const String cageChange = '/cage_change';
@@ -35,7 +36,8 @@ class AppRouteNames {
   static const String sample = '/sample';
   static const String sampleDetail = '/sample/detail';
   static const String rfidConfig = '/rfid-config';
-  static const String upload = '/upload'; // 新增上传路由名称
+  static const String upload = '/upload';
+  static const String dictManage = '/dict_manage';
 }
 
 class AppRoutes {
@@ -120,12 +122,16 @@ class AppRoutes {
       name: AppRouteNames.rfidConfig,
       builder: (context, state) => const RfidConfigPage(),
     ),
-    // 新增上传路由
     GoRoute(
       path: AppRouteNames.upload,
       name: AppRouteNames.upload,
       builder: (context, state) => const UploadPage(),
     ),
+    GoRoute(
+      path: AppRouteNames.dictManage,
+      name: AppRouteNames.dictManage,
+      builder: (context, state) => const DictManagePage(),
+    ),
   ];
 }
 

+ 116 - 31
UI/CF.APP/chicken_farm/lib/stores/dict_stroe.dart

@@ -1,11 +1,14 @@
 import 'package:chicken_farm/apis/system/_dict.dart';
+import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/core/utils/storage.dart';
 import 'package:chicken_farm/modes/system/dict.dart';
+import 'package:chicken_farm/core/services/offline_dict_service.dart';
 
 class DictStore {
   static final DictStore _instance = DictStore._internal();
   static const String _localStorgeKey = 'vb_dict_';
   final Map<String, List<DictDataModel>> _cache = {};
+  final OfflineDictService _offlineDictService = OfflineDictService();
 
   factory DictStore() => _instance;
 
@@ -18,40 +21,44 @@ class DictStore {
     if (_cache.containsKey(dictType)) {
       return _cache[dictType];
     }
-
-    // 再从本地存储中查找
-    // final cachedDict = await StorageUtils.getObject<List<dynamic>>(
-    //   '$_localStorgeKey$dictType',
-    // );
-    // if (cachedDict != null) {
-    //   try {
-    //     final dictList = cachedDict
-    //         .map(
-    //           (item) => item is Map<String, dynamic>
-    //               ? DictDataModel.fromJson(item)
-    //               : null,
-    //         )
-    //         .where((item) => item != null)
-    //         .cast<DictDataModel>()
-    //         .toList();
-    //     _cache[dictType] = dictList;
-    //     return dictList;
-    //   } catch (e) {
-    //     // 解析失败,继续从网络获取
-    //   }
-    // }
-
-    // 如果本地都没有,则调用接口查询
-    final dictData = await DictApi().getDicts(dictType);
-    if (dictData != null) {
-      // 存入缓存
-      _cache[dictType] = dictData;
-      await StorageUtils.setObject(
+    if (AppConfig.isOffline) {
+      // 如果是离线模式,则从本地配置中查找
+      return await _offlineDictService.getDictByType(dictType);
+    } else {
+      // 再从本地存储中查找
+      final cachedDict = await StorageUtils.getObject<List<dynamic>>(
         '$_localStorgeKey$dictType',
-        dictData.map((e) => e.toJson()).toList(),
       );
+      if (cachedDict != null) {
+        try {
+          final dictList = cachedDict
+              .map(
+                (item) => item is Map<String, dynamic>
+                    ? DictDataModel.fromJson(item)
+                    : null,
+              )
+              .where((item) => item != null)
+              .cast<DictDataModel>()
+              .toList();
+          _cache[dictType] = dictList;
+          return dictList;
+        } catch (e) {
+          // 解析失败,继续从网络获取
+        }
+      }
 
-      return dictData;
+      // 如果本地都没有,则调用接口查询
+      final dictData = await DictApi().getDicts(dictType);
+      if (dictData != null) {
+        // 存入缓存
+        _cache[dictType] = dictData;
+        await StorageUtils.setObject(
+          '$_localStorgeKey$dictType',
+          dictData.map((e) => e.toJson()).toList(),
+        );
+
+        return dictData;
+      }
     }
 
     return null;
@@ -90,6 +97,25 @@ class DictStore {
     return null;
   }
 
+  /// 获取所有字典项(离线模式下)
+  Future<Map<String, List<DictDataModel>>> getAllOfflineDicts() async {
+    if (!AppConfig.isOffline) {
+      throw Exception('字典获取操作仅支持离线模式');
+    }
+    final Map<String, List<DictDataModel>> result = {};
+    // 获取所有字典类型
+    final dictTypes = await _offlineDictService.getAllDictTypes();
+
+    for (final dictType in dictTypes) {
+      final items = await getDictByType(dictType);
+      if (items != null && items.isNotEmpty) {
+        result[dictType] = items;
+      }
+    }
+
+    return result;
+  }
+
   /// 清除指定字典类型的缓存
   void clearDictCache(String dictType) {
     _cache.remove(dictType);
@@ -101,4 +127,63 @@ class DictStore {
     _cache.clear();
     //StorageUtils.removeWithPrefix(_localStorgeKey);
   }
+
+  /// 添加新的字典项
+  Future<void> addDictItem(String dictType, DictDataModel dictItem) async {
+    await _modifyDictList(dictType, (list) {
+      list.add(dictItem);
+      return list;
+    });
+  }
+
+  /// 更新字典项
+  Future<void> updateDictItem(String dictType, DictDataModel dictItem) async {
+    await _modifyDictList(dictType, (list) {
+      final index = list.indexWhere(
+        (item) => item.dictCode == dictItem.dictCode,
+      );
+      if (index >= 0) {
+        list[index] = dictItem;
+      } else {
+        list.add(dictItem);
+      }
+      return list;
+    });
+  }
+
+  /// 删除字典项
+  Future<void> removeDictItem(String dictType, int dictCode) async {
+    await _modifyDictList(dictType, (list) {
+      list.removeWhere((item) => item.dictCode == dictCode);
+      return list;
+    });
+  }
+
+  /// 修改字典列表的通用方法
+  Future<void> _modifyDictList(
+    String dictType,
+    List<DictDataModel> Function(List<DictDataModel> list) modifier,
+  ) async {
+    // 只支持离线模式
+    if (!AppConfig.isOffline) {
+      throw Exception('字典修改操作仅支持离线模式');
+    }
+
+    // 获取现有列表或创建一个新列表
+    List<DictDataModel>? dictList = _cache[dictType];
+
+    dictList ??= await _offlineDictService.getDictByType(dictType) ?? [];
+
+    // 应用修改
+    dictList = modifier(List<DictDataModel>.from(dictList));
+
+    // 按照dictSort排序
+    dictList.sort((a, b) => a.dictSort.compareTo(b.dictSort));
+
+    // 更新缓存
+    _cache[dictType] = dictList;
+
+    // 保存到本地存储
+    await _offlineDictService.saveDict(dictType, dictList);
+  }
 }