Prechádzať zdrojové kódy

[new]增加新增模板&模板列表功能

zk 1 rok pred
rodič
commit
c92b831a10

BIN
assets/images/icon_template_add_title.webp


BIN
assets/images/icon_template_more_operation.webp


+ 12 - 0
assets/string/base/string.xml

@@ -154,4 +154,16 @@
     <string name="template_to_manage">去管理</string>
     <string name="mind_map_export">正在导出...</string>
     <string name="template_manage_title">总结模板列表</string>
+    <string name="template_detail_name">模板名称</string>
+    <string name="template_detail_name_hint">请输入模板名称</string>
+    <string name="template_detail_title">模板标题</string>
+    <string name="template_detail_title_hint">小听将按照您设置的标题做总结哦</string>
+    <string name="template_detail_title_txt">添加标题</string>
+    <string name="template_detail_save">保存模板</string>
+    <string name="template_dialog_add_title">添加模板标题</string>
+    <string name="template_dialog_add_title_hint">请输入模板标题</string>
+    <string name="template_dialog_update_title">编辑模板标题</string>
+    <string name="template_add_success">新建成功,即将返回上一页</string>
+    <string name="template_update_success">保存成功,即将返回上一页</string>
+    <string name="template_title_not_fail">添加模板标题</string>
 </resources>

+ 14 - 0
lib/data/api/atmob_api.dart

@@ -19,6 +19,7 @@ import 'package:electronic_assistant/data/api/request/talk_query_request.dart';
 import 'package:electronic_assistant/data/api/request/talk_rename_request.dart';
 import 'package:electronic_assistant/data/api/request/talk_request.dart';
 import 'package:electronic_assistant/data/api/request/talk_translate_request.dart';
+import 'package:electronic_assistant/data/api/request/template_update_request.dart';
 import 'package:electronic_assistant/data/api/request/user_info_update_request.dart';
 import 'package:electronic_assistant/data/api/request/verification_code_request.dart';
 import 'package:electronic_assistant/data/api/response/agenda_list_all_response.dart';
@@ -39,8 +40,10 @@ import 'package:electronic_assistant/data/api/response/talk_paginate_response.da
 import 'package:electronic_assistant/data/api/response/talk_query_response.dart';
 import 'package:electronic_assistant/data/api/response/talk_translate_response.dart';
 import 'package:electronic_assistant/data/api/response/tasks_running_response.dart';
+import 'package:electronic_assistant/data/api/response/template_list_response.dart';
 import 'package:electronic_assistant/data/api/response/user_info_response.dart';
 import 'package:electronic_assistant/data/bean/talks.dart';
+import 'package:electronic_assistant/data/bean/template_bean.dart';
 import 'package:electronic_assistant/data/consts/constants.dart';
 import 'package:retrofit/http.dart';
 
@@ -161,6 +164,17 @@ abstract class AtmobApi {
   @POST("/project/secretary/v1/talk/translate")
   Future<BaseResponse<TalkTranslateResponse>> talkTranslate(
       @Body() TalkTranslateRequest request);
+
+  @POST("/project/secretary/v1/template/list")
+  Future<BaseResponse<TemplateListResponse>> templateList(
+      @Body() AppBaseRequest request);
+
+  @POST("/project/secretary/v1/template/default/info")
+  Future<BaseResponse<TemplateBean>> defaultInfo(
+      @Body() AppBaseRequest request);
+
+  @POST("/project/secretary/v1/template/update")
+  Future<BaseResponse> templateUpdate(@Body() TemplateUpdateRequest request);
 }
 
 final atmobApi = AtmobApi(defaultDio, baseUrl: Constants.baseUrl);

+ 21 - 0
lib/data/api/request/template_update_request.dart

@@ -0,0 +1,21 @@
+import 'package:electronic_assistant/base/app_base_request.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'template_update_request.g.dart';
+
+@JsonSerializable()
+class TemplateUpdateRequest extends AppBaseRequest {
+  @JsonKey(name: 'id')
+  int? id;
+
+  @JsonKey(name: 'name')
+  String name;
+
+  @JsonKey(name: 'titles')
+  List<String>? titles;
+
+  TemplateUpdateRequest(this.id, this.name, this.titles);
+
+  @override
+  Map<String, dynamic> toJson() => _$TemplateUpdateRequestToJson(this);
+}

+ 22 - 0
lib/data/api/response/template_list_response.dart

@@ -0,0 +1,22 @@
+import 'package:electronic_assistant/data/bean/template_bean.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'template_list_response.g.dart';
+
+@JsonSerializable()
+class TemplateListResponse {
+  @JsonKey(name: 'templates')
+  List<TemplateBean>? templateList;
+
+  @JsonKey(name: 'defaultTemplate')
+  TemplateBean? defaultTemplate;
+
+  @JsonKey(name: 'maxTemplateCount')
+  int maxTemplateCount;
+
+  TemplateListResponse(
+      this.templateList, this.defaultTemplate, this.maxTemplateCount);
+
+  factory TemplateListResponse.fromJson(Map<String, dynamic> json) =>
+      _$TemplateListResponseFromJson(json);
+}

+ 15 - 2
lib/data/bean/template_bean.dart

@@ -5,12 +5,25 @@ part 'template_bean.g.dart';
 @JsonSerializable()
 class TemplateBean {
   @JsonKey(name: 'id')
-  int id;
+  int? id;
 
   @JsonKey(name: 'name')
   String? name;
 
-  TemplateBean(this.id, {this.name});
+  @JsonKey(name: 'titles')
+  List<String>? titles;
+
+  @JsonKey(name: 'defaultTitle')
+  String? defaultTitle;
+
+  @JsonKey(ignore: true)
+  bool isDefaultTemp = false;
+
+  TemplateBean({this.id, this.name, this.titles, this.defaultTitle});
+
+  setDefaultTemp(bool isDefault) {
+    isDefaultTemp = isDefault;
+  }
 
   factory TemplateBean.fromJson(Map<String, dynamic> json) =>
       _$TemplateBeanFromJson(json);

+ 31 - 0
lib/data/repositories/template_repository.dart

@@ -0,0 +1,31 @@
+import 'package:electronic_assistant/base/app_base_request.dart';
+
+import '../../utils/http_handler.dart';
+import '../api/atmob_api.dart';
+import '../api/request/template_update_request.dart';
+import '../api/response/template_list_response.dart';
+
+class TemplateRepository {
+  TemplateRepository._();
+
+  Future<TemplateListResponse> getTemplateList() {
+    return atmobApi
+        .templateList(AppBaseRequest())
+        .then(HttpHandler.handle(false));
+  }
+
+  Future<String?> defaultInfo() {
+    return atmobApi
+        .defaultInfo(AppBaseRequest())
+        .then(HttpHandler.handle(true))
+        .then((value) => value.defaultTitle);
+  }
+
+  Future<void> templateUpdate(int? id, String name, List<String>? titles) {
+    return atmobApi
+        .templateUpdate(TemplateUpdateRequest(id, name, titles))
+        .then(HttpHandler.handle(true));
+  }
+}
+
+final templateRepository = TemplateRepository._();

+ 3 - 3
lib/dialog/rename_dialog.dart

@@ -9,13 +9,13 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
 import 'package:get/get.dart';
 
-typedef RenameBuilder = void Function(String? content);
+typedef RenameBuilder = void Function(String content);
 
 void reNameDialog(String title, String? content,
     {String? hintTxt, int? maxLength, RenameBuilder? returnBuilder}) {
   final controller = TextEditingController();
   controller.text = content ?? "";
-  final contentObs = content.obs;
+  final contentObs = controller.text.obs;
   controller.addListener(() {
     contentObs.value = controller.text;
   });
@@ -130,7 +130,7 @@ void reNameDialog(String title, String? content,
                     Expanded(
                         child: GestureDetector(
                       onTap: () {
-                        if (contentObs.value!.isEmpty) {
+                        if (contentObs.value.isEmpty) {
                           ToastUtil.showToast(hintTxt);
                           return;
                         }

+ 4 - 0
lib/main.dart

@@ -133,6 +133,10 @@ class MyApp extends StatelessWidget {
         initialBinding: AppBinding(),
         theme: ThemeData(
           useMaterial3: true,
+          textSelectionTheme: const TextSelectionThemeData(
+            cursorColor: ColorName.colorPrimary, // 设置默认光标颜色
+            selectionHandleColor: ColorName.colorPrimary, // 设置光标下面水滴的颜色
+          ),
         ),
         navigatorObservers: [FlutterSmartDialog.observer],
         builder: FlutterSmartDialog.init(),

+ 4 - 4
lib/module/chat/start/view.dart

@@ -283,10 +283,10 @@ class ChatStartPage extends BasePage<ChatStartController> {
               decoration: InputDecoration(
                 hintText: '如:房地产、金融、电子设备出口、教培',
                 hintStyle: TextStyle(fontSize: 14, color: "#AFAFAF".toColor()),
-                labelStyle:
-                    TextStyle(fontSize: 14, color: ColorName.primaryTextColor),
-                contentPadding: EdgeInsets.only(left: 12),
-                border: OutlineInputBorder(borderSide: BorderSide.none),
+                labelStyle: const TextStyle(
+                    fontSize: 14, color: ColorName.primaryTextColor),
+                contentPadding: const EdgeInsets.only(left: 12),
+                border: const OutlineInputBorder(borderSide: BorderSide.none),
                 enabled: true,
               ),
               style: TextStyle(fontSize: 14.sp),

+ 8 - 5
lib/module/main/drawer/view.dart

@@ -4,6 +4,7 @@ import 'package:electronic_assistant/data/consts/event_report_id.dart';
 import 'package:electronic_assistant/handler/event_handler.dart';
 import 'package:electronic_assistant/module/browser/view.dart';
 import 'package:electronic_assistant/module/store/view.dart';
+import 'package:electronic_assistant/module/template/templatelist/view.dart';
 import 'package:electronic_assistant/router/app_pages.dart';
 import 'package:electronic_assistant/utils/expand.dart';
 import 'package:electronic_assistant/utils/toast_util.dart';
@@ -222,11 +223,13 @@ class MainDrawerView extends BasePage<MainDrawerController> {
       ),
       child: Column(
         children: [
-          // buildOperationItem(
-          //   Assets.images.iconTempManagement.image(),
-          //   StringName.mainDrawerTemplateManagement.tr,
-          //       () {},
-          // ),
+          buildOperationItem(
+            Assets.images.iconTempManagement.image(),
+            StringName.mainDrawerTemplateManagement.tr,
+            () {
+              TemplateListPage.start();
+            },
+          ),
           buildOperationItem(
             Assets.images.iconIndustryChange.image(),
             StringName.mainDrawerIndustryPositionChange.tr,

+ 2 - 1
lib/module/talk/common_view.dart

@@ -371,7 +371,7 @@ List<Widget> getTalkAgendaNormalList(List<Agenda>? list) {
 Widget buildTemplateView(List<TemplateBean>? templateList, int? id,
     {bool? isShowAdd, VoidCallback? addCallback}) {
   return SizedBox(
-    height: 28.h,
+    height: 32.h,
     child: ListView(
       scrollDirection: Axis.horizontal,
       shrinkWrap: true,
@@ -414,6 +414,7 @@ Widget _buildAddTemplateView(VoidCallback? addCallback) {
   return GestureDetector(
     onTap: addCallback,
     child: Container(
+      margin: EdgeInsets.only(right: 8.w),
       height: double.infinity,
       decoration: BoxDecoration(
         color: "#FAF9FB".toColor(),

+ 10 - 10
lib/module/talk/mindmap/view.dart

@@ -61,16 +61,16 @@ class MindMapView extends BasePage<MindMapController> {
     return Stack(
       children: [
         DWebViewWidget(controller: controller.talkController.webViewController),
-        // Obx(() {
-        //   return Visibility(
-        //     visible: !controller.isShowMindFullScreen.value,
-        //     child: Container(
-        //       margin: EdgeInsets.only(top: 14.h),
-        //       child: buildTemplateView(
-        //           controller.templateList, controller.templateSelectId),
-        //     ),
-        //   );
-        // }),
+        Obx(() {
+          return Visibility(
+            visible: !controller.isShowMindFullScreen.value,
+            child: Container(
+              margin: EdgeInsets.only(top: 14.h),
+              child: buildTemplateView(
+                  controller.templateList, controller.templateSelectId),
+            ),
+          );
+        }),
         GestureDetector(
           onTap: () {
             controller.fullScreenClick();

+ 4 - 3
lib/module/talk/summary/controller.dart

@@ -3,7 +3,7 @@ import 'package:electronic_assistant/base/base_controller.dart';
 import 'package:electronic_assistant/data/bean/agenda.dart';
 import 'package:electronic_assistant/dialog/alert_dialog.dart';
 import 'package:electronic_assistant/module/talk/controller.dart';
-import 'package:electronic_assistant/module/template/templatemanage/view.dart';
+import 'package:electronic_assistant/module/template/templatedetail/view.dart';
 import 'package:electronic_assistant/resource/colors.gen.dart';
 import 'package:electronic_assistant/resource/string.gen.dart';
 import 'package:flutter/cupertino.dart';
@@ -13,6 +13,7 @@ import '../../../data/bean/agenda_list_all_bean.dart';
 import '../../../data/bean/talks.dart';
 import '../../../data/bean/template_bean.dart';
 import '../../../data/consts/event_report_id.dart';
+import '../../template/templatelist/view.dart';
 
 class SummaryController extends BaseController {
   final String? talkId;
@@ -89,7 +90,7 @@ class SummaryController extends BaseController {
       _showMaxTemplateDialog();
       return;
     }
-    TemplateManagePage.start();
+    TemplateDetailPage.addStart();
   }
 
   void _showMaxTemplateDialog() {
@@ -111,7 +112,7 @@ class SummaryController extends BaseController {
         },
         confirmOnTap: () {
           EAAlertDialog.dismiss();
-          TemplateManagePage.start();
+          TemplateListPage.start();
         });
   }
 

+ 8 - 8
lib/module/talk/summary/view.dart

@@ -122,14 +122,14 @@ class SummaryView extends BasePage<SummaryController> {
       } else if (controller.summaryBean.value?.status.value ==
           TalkStatus.analysisSuccess) {
         return ListView(padding: EdgeInsets.only(bottom: 150.h), children: [
-          // SizedBox(height: 14.h),
-          // Obx(() {
-          //   return buildTemplateView(
-          //       controller.templateList, controller.templateSelectId,
-          //       isShowAdd: true, addCallback: () {
-          //     controller.addTemplateClick();
-          //   });
-          // }),
+          SizedBox(height: 14.h),
+          Obx(() {
+            return buildTemplateView(
+                controller.templateList, controller.templateSelectId,
+                isShowAdd: true, addCallback: () {
+              controller.addTemplateClick();
+            });
+          }),
           buildSummaryView(),
           Container(
             height: 6.h,

+ 0 - 9
lib/module/template/addtemplate/controller.dart

@@ -1,9 +0,0 @@
-import 'package:electronic_assistant/base/base_controller.dart';
-import 'package:get/get.dart';
-import 'package:get/get_core/src/get_main.dart';
-
-class AddTemplateController extends BaseController {
-  void onBack() {
-    Get.back();
-  }
-}

+ 0 - 35
lib/module/template/addtemplate/view.dart

@@ -1,35 +0,0 @@
-import 'package:electronic_assistant/base/base_page.dart';
-import 'package:electronic_assistant/resource/colors.gen.dart';
-import 'package:electronic_assistant/resource/string.gen.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/src/widgets/framework.dart';
-import 'package:flutter_screenutil/flutter_screenutil.dart';
-import 'package:get/get.dart';
-
-import '../../../resource/assets.gen.dart';
-import 'controller.dart';
-
-class AddTemplatePage extends BasePage<AddTemplateController> {
-  const AddTemplatePage({super.key});
-
-  @override
-  Widget buildBody(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        title: Text(
-          StringName.templateAddTitle.tr,
-          style: TextStyle(fontSize: 17.sp, color: ColorName.primaryTextColor),
-        ),
-        centerTitle: true,
-        leading: IconButton(
-            onPressed: () {
-              controller.onBack();
-            },
-            icon: SizedBox(
-                width: 24.w,
-                height: 24.w,
-                child: Assets.images.iconBack.image())),
-      ),
-    );
-  }
-}

+ 108 - 0
lib/module/template/templatedetail/controller.dart

@@ -0,0 +1,108 @@
+import 'package:electronic_assistant/base/base_controller.dart';
+import 'package:electronic_assistant/data/bean/template_bean.dart';
+import 'package:electronic_assistant/data/repositories/template_repository.dart';
+import 'package:electronic_assistant/resource/string.gen.dart';
+import 'package:electronic_assistant/utils/error_handler.dart';
+import 'package:electronic_assistant/utils/toast_util.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:get/get_core/src/get_main.dart';
+
+import '../../../dialog/rename_dialog.dart';
+
+class TemplateDetailController extends BaseController {
+  int? templateId;
+
+  final titleController = TextEditingController();
+  final focusNode = FocusNode();
+
+  final Rxn<String> _defaultTemplate = Rxn();
+
+  String? get defaultTemplate => _defaultTemplate.value;
+
+  final RxList<String> templateCustomTitle = RxList();
+
+  @override
+  void onInit() {
+    super.onInit();
+    var arguments = Get.arguments;
+    if (arguments is TemplateBean) {
+      templateId = arguments.id;
+      titleController.text = arguments.name ?? '';
+      templateCustomTitle.assignAll(arguments.titles ?? []);
+    }
+    if (templateId == null) {
+      _getDefaultTitle();
+    }
+  }
+
+  void _getDefaultTitle() {
+    templateRepository.defaultInfo().then((data) {
+      _defaultTemplate.value = data;
+    }).catchError((error) {
+      ErrorHandler.toastError(error);
+    });
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+  }
+
+  void onBack() {
+    Get.back();
+  }
+
+  void onCancel() {
+    Get.back();
+  }
+
+  void onSaveTemplate() {
+    if (titleController.text.isEmpty) {
+      ToastUtil.showToast(StringName.templateDetailNameHint.tr);
+      return;
+    }
+    if (templateCustomTitle.isEmpty) {
+      ToastUtil.showToast(StringName.templateTitleNotFail.tr);
+      return;
+    }
+    templateRepository
+        .templateUpdate(templateId, titleController.text, templateCustomTitle)
+        .then((data) async {
+      if (templateId == null) {
+        ToastUtil.showToast(StringName.templateAddSuccess.tr);
+      } else {
+        ToastUtil.showToast(StringName.templateUpdateSuccess.tr);
+      }
+      await Future.delayed(const Duration(milliseconds: 400));
+      Get.back(result: true);
+    }).catchError((error) {
+      ErrorHandler.toastError(error);
+    });
+  }
+
+  void clearTextFieldSelection() {
+    focusNode.unfocus();
+  }
+
+  void onAddTemplate() {
+    clearTextFieldSelection();
+    reNameDialog(StringName.templateDialogAddTitle.tr, null,
+        hintTxt: StringName.templateDialogAddTitleHint.tr,
+        maxLength: 30, returnBuilder: (newValue) {
+      templateCustomTitle.add(newValue);
+    });
+  }
+
+  void onDeleteTemplate(int index) {
+    templateCustomTitle.removeAt(index);
+  }
+
+  void onUpdateTemplate(int index, String txt) {
+    reNameDialog(StringName.templateDialogUpdateTitle.tr, txt,
+        hintTxt: StringName.templateDialogAddTitleHint.tr,
+        maxLength: 30, returnBuilder: (newValue) {
+      templateCustomTitle[index] = newValue;
+    });
+  }
+}

+ 240 - 0
lib/module/template/templatedetail/view.dart

@@ -0,0 +1,240 @@
+import 'package:electronic_assistant/base/base_page.dart';
+import 'package:electronic_assistant/data/bean/template_bean.dart';
+import 'package:electronic_assistant/resource/colors.gen.dart';
+import 'package:electronic_assistant/resource/string.gen.dart';
+import 'package:electronic_assistant/utils/expand.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import '../../../resource/assets.gen.dart';
+import '../../../router/app_pages.dart';
+import '../../../utils/common_style.dart';
+import 'controller.dart';
+
+class TemplateDetailPage extends BasePage<TemplateDetailController> {
+  const TemplateDetailPage({super.key});
+
+  static void addStart() {
+    Get.toNamed(RoutePath.templateDetail);
+  }
+
+  static void updateDetail(TemplateBean bean) {
+    Get.toNamed(RoutePath.templateDetail, arguments: bean);
+  }
+
+  @override
+  bool immersive() {
+    return true;
+  }
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Scaffold(
+      resizeToAvoidBottomInset: false,
+      backgroundColor: 'F6F6F6'.color,
+      appBar: _buildAppBar(),
+      body: Column(
+        children: [
+          Expanded(child: _buildTemplateContent()),
+          _buildTemplateBtn()
+        ],
+      ),
+    );
+  }
+
+  Widget _buildTemplateContent() {
+    return SingleChildScrollView(
+        padding: EdgeInsets.symmetric(horizontal: 12.w),
+        child: SizedBox(
+          width: double.infinity,
+          child:
+              Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
+            SizedBox(height: 12.h),
+            Text(StringName.templateDetailName.tr,
+                style: TextStyle(
+                    fontSize: 14.sp, color: ColorName.secondaryTextColor)),
+            SizedBox(height: 8.h),
+            _buildTemplateTitle(),
+            SizedBox(height: 20.h),
+            Text(StringName.templateDetailTitle.tr,
+                style: TextStyle(
+                    fontSize: 14.sp, color: ColorName.secondaryTextColor)),
+            Text(StringName.templateDetailTitleHint.tr,
+                style: TextStyle(
+                    fontSize: 12.sp, color: ColorName.tertiaryTextColor)),
+            SizedBox(height: 12.h),
+            _buildTemplateTitleList(),
+            _buildDefaultTemplate(),
+            _buildAddTemplate()
+          ]),
+        ));
+  }
+
+  Widget _buildAddTemplate() {
+    return GestureDetector(
+      onTap: () {
+        controller.onAddTemplate();
+      },
+      child: Container(
+        margin: EdgeInsets.only(bottom: 8.w),
+        decoration: BoxDecoration(
+            color: '#F0F0F0'.color, borderRadius: BorderRadius.circular(8.w)),
+        child: Row(
+          children: [
+            SizedBox(width: 15.w),
+            Assets.images.iconTemplateAddTitle.image(width: 28.w, height: 28.w),
+            SizedBox(width: 10.w),
+            Padding(
+              padding: EdgeInsets.symmetric(vertical: 17.w),
+              child: Text(StringName.templateDetailTitleTxt.tr,
+                  style: TextStyle(
+                      fontSize: 15.sp, color: ColorName.tertiaryTextColor)),
+            )
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget _buildDefaultTemplate() {
+    return Obx(() {
+      if (controller.defaultTemplate?.isNotEmpty == true) {
+        return _templateItem(controller.defaultTemplate!, hideDeleteIcon: true);
+      } else {
+        return Container();
+      }
+    });
+  }
+
+  Widget _buildTemplateTitleList() {
+    return Obx(() {
+      return ListView.builder(
+          physics: const NeverScrollableScrollPhysics(),
+          itemBuilder: (context, index) {
+            var item = controller.templateCustomTitle[index];
+            return _templateItem(item, itemClick: () {
+              controller.onUpdateTemplate(index, item);
+            }, deleteClick: () {
+              controller.onDeleteTemplate(index);
+            });
+          },
+          itemCount: controller.templateCustomTitle.length,
+          reverse: true,
+          shrinkWrap: true);
+    });
+  }
+
+  Widget _templateItem(String title,
+      {bool? hideDeleteIcon,
+      VoidCallback? itemClick,
+      VoidCallback? deleteClick}) {
+    return GestureDetector(
+      onTap: itemClick,
+      child: Container(
+          margin: EdgeInsets.only(bottom: 8.w),
+          decoration: BoxDecoration(
+              color: ColorName.white, borderRadius: BorderRadius.circular(8.w)),
+          padding: EdgeInsets.symmetric(horizontal: 14.w),
+          child: Row(
+            children: [
+              Padding(
+                padding: EdgeInsets.symmetric(vertical: 17.w),
+                child: Text(title,
+                    style: TextStyle(
+                        fontSize: 15.sp, color: ColorName.primaryTextColor)),
+              ),
+              SizedBox(width: 14.w),
+              const Spacer(),
+              GestureDetector(
+                onTap: deleteClick,
+                child: Visibility(
+                    visible: hideDeleteIcon != true,
+                    child: Assets.images.iconRenameClearTxt
+                        .image(width: 20.w, height: 20.w)),
+              )
+            ],
+          )),
+    );
+  }
+
+  Widget _buildTemplateTitle() {
+    return Container(
+      width: double.infinity,
+      decoration: BoxDecoration(
+          color: ColorName.white, borderRadius: BorderRadius.circular(8.w)),
+      child: TextField(
+          focusNode: controller.focusNode,
+          controller: controller.titleController,
+          maxLength: 6,
+          decoration: InputDecoration(
+            counterText: '',
+            contentPadding:
+                EdgeInsets.symmetric(horizontal: 14.w, vertical: 20.w),
+            border: const OutlineInputBorder(borderSide: BorderSide.none),
+            hintStyle: TextStyle(
+                height: 1, fontSize: 20.sp, color: ColorName.tertiaryTextColor),
+            hintText: StringName.templateDetailNameHint.tr,
+          ),
+          style: TextStyle(
+              height: 1, fontSize: 20.sp, color: ColorName.primaryTextColor)),
+    );
+  }
+
+  Widget _buildTemplateBtn() {
+    return GestureDetector(
+      onTap: () {
+        controller.onSaveTemplate();
+      },
+      child: Center(
+        child: Container(
+          margin: EdgeInsets.only(bottom: 16.w),
+          decoration: getCommonDecoration(8.w),
+          width: 328.w,
+          height: 48.w,
+          child: Center(
+            child: Text(
+              StringName.templateDetailSave.tr,
+              style: TextStyle(fontSize: 16.sp, color: ColorName.white),
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+
+  AppBar _buildAppBar() {
+    return AppBar(
+      scrolledUnderElevation: 0,
+      systemOverlayStyle: SystemUiOverlayStyle.dark,
+      backgroundColor: Colors.transparent,
+      title: Text(
+        StringName.templateAddTitle.tr,
+        style: TextStyle(fontSize: 17.sp, color: ColorName.primaryTextColor),
+      ),
+      actions: [
+        GestureDetector(
+          onTap: () {
+            controller.onCancel();
+          },
+          child: Text(
+            StringName.cancel.tr,
+            style:
+                TextStyle(fontSize: 15.sp, color: ColorName.secondaryTextColor),
+          ),
+        ),
+        SizedBox(width: 12.w)
+      ],
+      centerTitle: true,
+      leading: IconButton(
+          onPressed: () {
+            controller.onBack();
+          },
+          icon: SizedBox(
+              width: 24.w,
+              height: 24.w,
+              child: Assets.images.iconBack.image())),
+    );
+  }
+}

+ 48 - 0
lib/module/template/templatelist/controller.dart

@@ -0,0 +1,48 @@
+import 'package:electronic_assistant/base/base_controller.dart';
+import 'package:electronic_assistant/data/bean/template_bean.dart';
+import 'package:electronic_assistant/module/template/templatedetail/view.dart';
+import 'package:electronic_assistant/utils/error_handler.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:get/get_core/src/get_main.dart';
+
+import '../../../data/repositories/template_repository.dart';
+
+class TemplateListController extends BaseController {
+  final RxList<TemplateBean> templateList = RxList();
+
+  int? maxTemplateCount;
+
+  @override
+  void onInit() {
+    super.onInit();
+    refreshTemplateList();
+  }
+
+  void refreshTemplateList() {
+    templateRepository.getTemplateList().then((data) {
+      templateList.clear();
+      var defaultTemp = data.defaultTemplate;
+      if (defaultTemp != null) {
+        defaultTemp.setDefaultTemp(true);
+        templateList.add(defaultTemp);
+      }
+      var customTemp = data.templateList;
+      if (customTemp != null) {
+        templateList.addAll(customTemp);
+      }
+      maxTemplateCount = data.maxTemplateCount;
+    }).catchError((error) {
+      debugPrint('error: $error');
+      ErrorHandler.toastError(error);
+    });
+  }
+
+  void onBack() {
+    Get.back();
+  }
+
+  void onAddTemplate() {
+    TemplateDetailPage.addStart();
+  }
+}

+ 121 - 0
lib/module/template/templatelist/view.dart

@@ -0,0 +1,121 @@
+import 'package:electronic_assistant/base/base_page.dart';
+import 'package:electronic_assistant/router/app_pages.dart';
+import 'package:electronic_assistant/utils/expand.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:get/get_core/src/get_main.dart';
+import '../../../data/bean/template_bean.dart';
+import '../../../resource/assets.gen.dart';
+import '../../../resource/colors.gen.dart';
+import '../../../resource/string.gen.dart';
+import '../../../utils/common_style.dart';
+import 'controller.dart';
+
+class TemplateListPage extends BasePage<TemplateListController> {
+  const TemplateListPage({super.key});
+
+  static void start() {
+    Get.toNamed(RoutePath.templateList);
+  }
+
+  @override
+  bool immersive() {
+    return true;
+  }
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Scaffold(
+      backgroundColor: '#F6F6F6'.color,
+      appBar: _buildAppBar(),
+      body: Column(
+        children: [Expanded(child: _buildTemplateList()), _buildTemplateBtn()],
+      ),
+    );
+  }
+
+  Widget _buildTemplateBtn() {
+    return GestureDetector(
+      onTap: () {
+        controller.onAddTemplate();
+      },
+      child: Center(
+        child: Container(
+          margin: EdgeInsets.only(bottom: 16.w),
+          decoration: getCommonDecoration(8.w),
+          width: 328.w,
+          height: 48.w,
+          child: Center(
+            child: Text(
+              StringName.talkAddTemplate.tr,
+              style: TextStyle(fontSize: 16.sp, color: ColorName.white),
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+
+  AppBar _buildAppBar() {
+    return AppBar(
+      scrolledUnderElevation: 0,
+      systemOverlayStyle: SystemUiOverlayStyle.dark,
+      backgroundColor: Colors.transparent,
+      title: Text(
+        StringName.templateManageTitle.tr,
+        style: TextStyle(fontSize: 17.sp, color: ColorName.primaryTextColor),
+      ),
+      centerTitle: true,
+      leading: IconButton(
+          onPressed: () {
+            controller.onBack();
+          },
+          icon: SizedBox(
+              width: 24.w,
+              height: 24.w,
+              child: Assets.images.iconBack.image())),
+    );
+  }
+
+  Widget _buildTemplateList() {
+    return Obx(() {
+      return ListView.builder(
+        padding: EdgeInsets.only(top: 12.w),
+        itemCount: controller.templateList.length,
+        itemBuilder: (context, index) {
+          return _buildTemplateItem(controller.templateList[index]);
+        },
+      );
+    });
+  }
+
+  Widget _buildTemplateItem(TemplateBean templateBean) {
+    return Container(
+      decoration: BoxDecoration(
+          color: ColorName.white, borderRadius: BorderRadius.circular(8.w)),
+      padding: EdgeInsets.only(left: 16.w, right: 12.w),
+      margin: EdgeInsets.only(bottom: 8.h, left: 12.w, right: 12.w),
+      child: Row(
+        children: [
+          Padding(
+            padding: EdgeInsets.symmetric(vertical: 20.w),
+            child: Text(templateBean.name ?? '',
+                style: TextStyle(
+                    fontSize: 15.sp,
+                    color: ColorName.primaryTextColor,
+                    height: 1)),
+          ),
+          const Spacer(),
+          Visibility(
+              visible: !templateBean.isDefaultTemp,
+              child: Assets.images.iconTemplateMoreOperation
+                  .image(width: 24.w, height: 24.w)),
+        ],
+      ),
+    );
+  }
+}

+ 0 - 9
lib/module/template/templatemanage/controller.dart

@@ -1,9 +0,0 @@
-import 'package:electronic_assistant/base/base_controller.dart';
-import 'package:get/get.dart';
-import 'package:get/get_core/src/get_main.dart';
-
-class TemplateManageController extends BaseController {
-  void onBack() {
-    Get.back();
-  }
-}

+ 0 - 45
lib/module/template/templatemanage/view.dart

@@ -1,45 +0,0 @@
-import 'package:electronic_assistant/base/base_controller.dart';
-import 'package:electronic_assistant/base/base_page.dart';
-import 'package:electronic_assistant/router/app_pages.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
-import 'package:flutter/src/widgets/framework.dart';
-import 'package:flutter_screenutil/flutter_screenutil.dart';
-import 'package:get/get.dart';
-import 'package:get/get_core/src/get_main.dart';
-import '../../../resource/assets.gen.dart';
-import '../../../resource/colors.gen.dart';
-import '../../../resource/string.gen.dart';
-import 'controller.dart';
-
-class TemplateManagePage extends BasePage<TemplateManageController> {
-  const TemplateManagePage({super.key});
-
-  static void start() {
-    Get.toNamed(RoutePath.templateManage);
-  }
-
-  @override
-  Widget buildBody(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        systemOverlayStyle: SystemUiOverlayStyle.dark,
-        backgroundColor: Colors.transparent,
-        title: Text(
-          StringName.templateManageTitle.tr,
-          style: TextStyle(fontSize: 17.sp, color: ColorName.primaryTextColor),
-        ),
-        centerTitle: true,
-        leading: IconButton(
-            onPressed: () {
-              controller.onBack();
-            },
-            icon: SizedBox(
-                width: 24.w,
-                height: 24.w,
-                child: Assets.images.iconBack.image())),
-      ),
-    );
-  }
-}

+ 10 - 10
lib/router/app_pages.dart

@@ -15,10 +15,7 @@ import 'package:electronic_assistant/module/splash/controller.dart';
 import 'package:electronic_assistant/module/store/controller.dart';
 import 'package:electronic_assistant/module/store/view.dart';
 import 'package:electronic_assistant/module/talk/view.dart';
-import 'package:electronic_assistant/module/template/addtemplate/controller.dart';
-import 'package:electronic_assistant/module/template/addtemplate/view.dart';
-import 'package:electronic_assistant/module/template/templatemanage/controller.dart';
-import 'package:electronic_assistant/module/template/templatemanage/view.dart';
+import 'package:electronic_assistant/module/template/templatedetail/view.dart';
 import 'package:get/get.dart';
 
 import '../module/agenda/controller.dart';
@@ -38,6 +35,9 @@ import '../module/modelexplain/controller.dart';
 import '../module/record/view.dart';
 import '../module/splash/view.dart';
 import '../module/talk/controller.dart';
+import '../module/template/templatedetail/controller.dart';
+import '../module/template/templatelist/controller.dart';
+import '../module/template/templatelist/view.dart';
 
 abstract class AppPage {
   static final pages = <GetPage>[
@@ -78,9 +78,9 @@ abstract class RoutePath {
 
   static const modelExplain = '/modelExplain';
 
-  static const addTemplate = '/addTemplate';
+  static const templateDetail = '/templateDetail';
 
-  static const templateManage = '/templateManage';
+  static const templateList = '/templateList';
 }
 
 class AppBinding extends Bindings {
@@ -104,8 +104,8 @@ class AppBinding extends Bindings {
     lazyPut(() => AudioPickerController());
     lazyPut(() => ComplaintOpinionController());
     lazyPut(() => ModelExplainController());
-    lazyPut(() => AddTemplateController());
-    lazyPut(() => TemplateManageController());
+    lazyPut(() => TemplateDetailController());
+    lazyPut(() => TemplateListController());
   }
 
   void lazyPut<S>(InstanceBuilderCallback<S> builder) {
@@ -135,7 +135,7 @@ final generalPages = [
       name: RoutePath.complaintOpinion,
       page: () => const ComplaintOpinionPage()),
   GetPage(name: RoutePath.modelExplain, page: () => const ModelExplainPage()),
-  GetPage(name: RoutePath.addTemplate, page: () => const AddTemplatePage()),
   GetPage(
-      name: RoutePath.templateManage, page: () => const TemplateManagePage()),
+      name: RoutePath.templateDetail, page: () => const TemplateDetailPage()),
+  GetPage(name: RoutePath.templateList, page: () => const TemplateListPage()),
 ];

+ 1 - 1
lib/widget/shimmer_effect.dart

@@ -15,7 +15,7 @@ class ShimmerEffect extends StatefulWidget {
     this.duration = const Duration(seconds: 2),
     this.colors = const [
       Colors.transparent,
-      Colors.white60,
+      Colors.white38,
       Colors.transparent,
     ],
     this.begin = const Alignment(-1, -1),