From e295922209fb87c6dcd68ea1560fd16c3e6d808c Mon Sep 17 00:00:00 2001
From: dongyukun <1208714201@qq.com>
Date: 星期五, 27 六月 2025 09:36:51 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/feature/ai'

---
 src/views/ai/dashboard/components/conversation/CommonConversationUpdateForm.vue |    2 
 src/assets/ai/zhuanlu/history_title.png                                         |    0 
 src/views/ai/utils/utils.ts                                                     |   17 
 src/views/ai/dashboard/components/conversation/ConversationUpdateForm.vue       |    2 
 src/assets/ai/zhuanlu/suggest_title.png                                         |    0 
 src/views/ai/suggest/index.vue                                                  |  223 ++++++++
 src/views/ai/model/template/templateForm.vue                                    |    3 
 src/components/Dialog/src/DialogSuggest.vue                                     |   51 +
 src/views/ai/dashboard/components/conversation/CommonConversation.vue           |   23 
 src/views/ai/suggest/ScheduleSuggestForm.vue                                    |  117 ++++
 src/views/ai/dashboard/components/suggest/ScheduleSuggestDialog.vue             |  417 +++++++++++++++
 src/views/ai/model/template/index.vue                                           |    3 
 src/views/ai/dashboard/components/conversation/CommonConversationList.vue       |    4 
 src/views/ai/dashboard/components/message/MessageList.vue                       |    2 
 src/views/ai/dashboard/components/message/ModelMessageList.vue                  |   22 
 src/api/ai/schedulesuggest/index.ts                                             |   55 ++
 src/views/ai/dashboard/components/message/HistoryMessageDialog.vue              |    4 
 src/views/ai/utils/constants.ts                                                 |   12 
 src/api/ai/model/model/index.ts                                                 |    2 
 src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue      |    2 
 src/components/Dialog/src/DialogAi.vue                                          |    4 
 src/views/ai/dashboard/components/suggest/ScheduleSuggestList.vue               |  307 +++++++++++
 src/views/ai/dashboard/zhuanlu/index.vue                                        |  338 ++++++++++--
 23 files changed, 1,477 insertions(+), 133 deletions(-)

diff --git a/src/api/ai/model/model/index.ts b/src/api/ai/model/model/index.ts
index 7c485a0..44c898a 100644
--- a/src/api/ai/model/model/index.ts
+++ b/src/api/ai/model/model/index.ts
@@ -23,7 +23,7 @@
   },
 
   // 获得模型列表
-  getModelSimpleList: async (type?: number) => {
+  getModelSimpleList: async (type?: string) => {
     return await request.get({
       url: `/ai/model/simple-list`,
       params: {
diff --git a/src/api/ai/schedulesuggest/index.ts b/src/api/ai/schedulesuggest/index.ts
new file mode 100644
index 0000000..19c5d1e
--- /dev/null
+++ b/src/api/ai/schedulesuggest/index.ts
@@ -0,0 +1,55 @@
+import request from '@/config/axios'
+
+// 大模型调度建议 VO
+export interface ScheduleSuggestVO {
+  id: number // id
+  modelId: number // 模型id
+  conversationId: number // 会话id
+  messageId: number // 消息id
+  content: string // 调度建议
+  status: number // 状态(0-未处理 1-已采纳 2-已忽略)
+  createTime: Date // 创建时间
+}
+
+// 大模型调度建议 API
+export const ScheduleSuggestApi = {
+  // 查询大模型调度建议分页
+  getScheduleSuggestPage: async (params: any) => {
+    return await request.get({ url: `/ai/schedule-suggest/page`, params })
+  },
+
+  // 查询大模型调度建议详情
+  getScheduleSuggest: async (id: number) => {
+    return await request.get({ url: `/ai/schedule-suggest/get?id=` + id })
+  },
+
+  // 查询大模型调度建议详情
+  getTopScheduleSuggests: async (top: number) => {
+    return await request.get({ url: `/ai/schedule-suggest/simple-list?top=` + top })
+  },
+
+  // 新增大模型调度建议
+  createScheduleSuggest: async (data: ScheduleSuggestVO) => {
+    return await request.post({ url: `/ai/schedule-suggest/create`, data })
+  },
+
+  // 修改大模型调度建议
+  updateScheduleSuggest: async (data: ScheduleSuggestVO) => {
+    return await request.put({ url: `/ai/schedule-suggest/update`, data })
+  },
+
+  // 采纳忽略取消采纳
+  operateScheduleSuggest: async (data: ScheduleSuggestVO) => {
+    return await request.put({ url: `/ai/schedule-suggest/operate-suggest`, data})
+  },
+
+  // 删除大模型调度建议
+  deleteScheduleSuggest: async (id: number) => {
+    return await request.delete({ url: `/ai/schedule-suggest/delete?id=` + id })
+  },
+
+  // 导出大模型调度建议 Excel
+  exportScheduleSuggest: async (params) => {
+    return await request.download({ url: `/ai/schedule-suggest/export-excel`, params })
+  },
+}
diff --git a/src/assets/ai/zhuanlu/history_title.png b/src/assets/ai/zhuanlu/history_title.png
new file mode 100644
index 0000000..c0350b6
--- /dev/null
+++ b/src/assets/ai/zhuanlu/history_title.png
Binary files differ
diff --git a/src/assets/ai/zhuanlu/suggest_title.png b/src/assets/ai/zhuanlu/suggest_title.png
new file mode 100644
index 0000000..16c716e
--- /dev/null
+++ b/src/assets/ai/zhuanlu/suggest_title.png
Binary files differ
diff --git a/src/components/Dialog/src/DialogHistory.vue b/src/components/Dialog/src/DialogAi.vue
similarity index 96%
rename from src/components/Dialog/src/DialogHistory.vue
rename to src/components/Dialog/src/DialogAi.vue
index 02dc867..07abfcf 100644
--- a/src/components/Dialog/src/DialogHistory.vue
+++ b/src/components/Dialog/src/DialogAi.vue
@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import { propTypes } from '@/utils/propTypes'
 import { isNumber } from '@/utils/is'
-defineOptions({ name: 'DialogHistory' })
+defineOptions({ name: 'DialogAi' })
 
 const slots = useSlots()
 
@@ -111,7 +111,7 @@
       padding: 0;
       margin-right: 0 !important;
       background:
-        url("@/assets/ai/zhuanlu/common_title.png") left no-repeat,
+        url("@/assets/ai/zhuanlu/history_title.png") left no-repeat,
         linear-gradient(to bottom, #0a1633dd, #0a1633dd); /* 叠加深色遮罩 */
       div {
         color: #73C4FF;
diff --git a/src/components/Dialog/src/DialogHistory.vue b/src/components/Dialog/src/DialogSuggest.vue
similarity index 71%
copy from src/components/Dialog/src/DialogHistory.vue
copy to src/components/Dialog/src/DialogSuggest.vue
index 02dc867..6d1723d 100644
--- a/src/components/Dialog/src/DialogHistory.vue
+++ b/src/components/Dialog/src/DialogSuggest.vue
@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import { propTypes } from '@/utils/propTypes'
 import { isNumber } from '@/utils/is'
-defineOptions({ name: 'DialogHistory' })
+defineOptions({ name: 'Dialog' })
 
 const slots = useSlots()
 
@@ -9,7 +9,7 @@
   modelValue: propTypes.bool.def(false),
   title: propTypes.string.def('Dialog'),
   fullscreen: propTypes.bool.def(true),
-  width: propTypes.oneOfType([String, Number]).def('30%'),
+  width: propTypes.oneOfType([String, Number]).def('40%'),
   scroll: propTypes.bool.def(false), // 是否开启滚动条。如果是的话,按照 maxHeight 设置最大高度
   maxHeight: propTypes.oneOfType([String, Number]).def('400px')
 })
@@ -50,40 +50,56 @@
   }
 )
 
+const dialogStyle = computed(() => {
+  return {
+    height: unref(dialogHeight)
+  }
+})
 </script>
 
 <template>
   <ElDialog
     v-bind="getBindValue"
-    :fullscreen="isFullscreen"
     :close-on-click-modal="true"
+    :fullscreen="isFullscreen"
     :width="width"
     destroy-on-close
     lock-scroll
     draggable
-    class="history-dialog"
+    class="com-dialog"
     :show-close="false"
   >
     <template #header="{ close }">
-      <div class="relative h-30px flex items-center justify-between pl-15px pr-15px">
+      <div class="relative h-54px flex items-center justify-between pl-15px pr-15px">
         <slot name="title">
           {{ title }}
         </slot>
         <div
-          class="absolute right-15px top-[50%] h-40px flex translate-y-[-50%] items-center justify-between"
+          class="absolute right-15px top-[50%] h-54px flex translate-y-[-50%] items-center justify-between"
         >
+          <Icon
+            v-if="fullscreen"
+            class="is-hover mr-10px cursor-pointer"
+            :icon="isFullscreen ? 'radix-icons:exit-full-screen' : 'radix-icons:enter-full-screen'"
+            color="var(--el-color-info)"
+            hover-color="var(--el-color-primary)"
+            @click="toggleFull"
+          />
           <Icon
             class="is-hover cursor-pointer"
             icon="ep:close"
             hover-color="var(--el-color-primary)"
-            color="#73C4FF"
+            color="var(--el-color-info)"
             @click="close"
           />
         </div>
       </div>
     </template>
 
-    <slot></slot>
+    <ElScrollbar v-if="scroll" :style="dialogStyle">
+      <slot></slot>
+    </ElScrollbar>
+    <slot v-else></slot>
     <template v-if="slots.footer" #footer>
       <slot name="footer"></slot>
     </template>
@@ -91,10 +107,9 @@
 </template>
 
 <style lang="scss">
-.history-dialog {
-  height: 90vh;
+.com-dialog {
+  height: 62vh;
   color: #73C4FF;
-  margin-top: 30px;
   background: rgba(3,29,76,0.79);
   border-radius: 4px 4px 4px 4px;
   border: 1px solid;
@@ -111,7 +126,7 @@
       padding: 0;
       margin-right: 0 !important;
       background:
-        url("@/assets/ai/zhuanlu/common_title.png") left no-repeat,
+        url("@/assets/ai/zhuanlu/suggest_title.png") left no-repeat,
         linear-gradient(to bottom, #0a1633dd, #0a1633dd); /* 叠加深色遮罩 */
       div {
         color: #73C4FF;
@@ -123,6 +138,18 @@
       color: #73C4FF;
       top: 0;
     }
+
+    &__body {
+      padding: 15px !important;
+    }
+
+    &__footer {
+      border-top: 1px solid var(--el-border-color);
+    }
+
+    &__headerbtn {
+      top: 0;
+    }
   }
 }
 </style>
diff --git a/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue b/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue
index 90f68c6..bba2a10 100644
--- a/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue
+++ b/src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue
@@ -110,7 +110,7 @@
     }
   }
   // 获得下拉数据
-  models.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT)
+  models.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT + "," + AiModelTypeEnum.LLM)
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
diff --git a/src/views/ai/dashboard/components/conversation/CommonConversation.vue b/src/views/ai/dashboard/components/conversation/CommonConversation.vue
index 04137e7..5d41a42 100644
--- a/src/views/ai/dashboard/components/conversation/CommonConversation.vue
+++ b/src/views/ai/dashboard/components/conversation/CommonConversation.vue
@@ -147,7 +147,7 @@
 import * as authUtil from "@/utils/auth";
 import {refreshToken} from "@/api/login";
 import {formatToDateTime} from "@/utils/dateUtil";
-import {ElLoading} from "element-plus";
+import { formatReasoningContent } from '@/views/ai/utils/utils'
 
 /** AI 聊天对话 列表 */
 defineOptions({ name: 'NormalConversation' })
@@ -347,23 +347,6 @@
   return []
 })
 
-// //处理调度推理结论(deepSeek)
-// const dealResult = (conversations: any) => {
-//   const regex = /<think>(\n*)([\s\S]*?)(\n*)<\/think>(\n*)([\s\S]*)/;
-//   conversations.forEach((conversation) => {
-//     if(conversation.content.includes('<\/think>')) {
-//       conversation.thinkingFlag = false
-//     } else {
-//       conversation.thinkingFlag = true
-//     }
-//     const match = conversation.content.match(regex);
-//     if(match) {
-//       conversation.thinking = match[2];
-//       conversation.conclusion = match[5]
-//     }
-//   })
-// }
-
 //处理调度推理结论(微调大模型)
 const dealResult = (messages: any) => {
   messages.forEach((message) => {
@@ -378,6 +361,8 @@
       } else {
         message.thinking = message.content
       }
+      // 处理推理思路内容
+      message.thinking = formatReasoningContent(message.thinking);
     }
   })
 }
@@ -691,7 +676,7 @@
   position: absolute;
   left: 320px;  // 初始展开位置
   top: 40%;
-  z-index: 1000;
+  z-index: 1;
   width: 20px;
   height: 80px;
   background: rgba(115, 196, 255, 0.5);
diff --git a/src/views/ai/dashboard/components/conversation/CommonConversationList.vue b/src/views/ai/dashboard/components/conversation/CommonConversationList.vue
index 590e88c..fc32a5a 100644
--- a/src/views/ai/dashboard/components/conversation/CommonConversationList.vue
+++ b/src/views/ai/dashboard/components/conversation/CommonConversationList.vue
@@ -128,7 +128,9 @@
     type: Boolean || null,
     required: true
   },
-  defaultMessage: {}
+  defaultMessage: {
+    type: Object as PropType<ChatMessageVO>
+  }
 })
 
 // 定义钩子
diff --git a/src/views/ai/dashboard/components/conversation/CommonConversationUpdateForm.vue b/src/views/ai/dashboard/components/conversation/CommonConversationUpdateForm.vue
index afa5279..5882bce 100644
--- a/src/views/ai/dashboard/components/conversation/CommonConversationUpdateForm.vue
+++ b/src/views/ai/dashboard/components/conversation/CommonConversationUpdateForm.vue
@@ -102,7 +102,7 @@
     }
   }
   // 获得下拉数据
-  models.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT)
+  models.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.LLM)
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
diff --git a/src/views/ai/dashboard/components/conversation/ConversationUpdateForm.vue b/src/views/ai/dashboard/components/conversation/ConversationUpdateForm.vue
index 90f68c6..af25f2f 100644
--- a/src/views/ai/dashboard/components/conversation/ConversationUpdateForm.vue
+++ b/src/views/ai/dashboard/components/conversation/ConversationUpdateForm.vue
@@ -110,7 +110,7 @@
     }
   }
   // 获得下拉数据
-  models.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT)
+  models.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.LLM)
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
diff --git a/src/views/ai/dashboard/components/message/HistoryMessageDialog.vue b/src/views/ai/dashboard/components/message/HistoryMessageDialog.vue
index 51999c2..2d58542 100644
--- a/src/views/ai/dashboard/components/message/HistoryMessageDialog.vue
+++ b/src/views/ai/dashboard/components/message/HistoryMessageDialog.vue
@@ -1,5 +1,5 @@
 <template>
-  <DialogHistory title="历史建议" v-model="dialogVisible" width="1200" custom-class="transparent-dialog">
+  <DialogAi title="" v-model="dialogVisible" width="1200" custom-class="transparent-dialog">
     <!-- 搜索工作栏 -->
     <el-form
       class="-mb-15px query-area"
@@ -79,7 +79,7 @@
       v-model:limit="queryParams.pageSize"
       @pagination="handleQuery"
     />
-  </DialogHistory>
+  </DialogAi>
 </template>
 
 <script setup lang="ts">
diff --git a/src/views/ai/dashboard/components/message/MessageList.vue b/src/views/ai/dashboard/components/message/MessageList.vue
index 5ecf1bc..7635873 100644
--- a/src/views/ai/dashboard/components/message/MessageList.vue
+++ b/src/views/ai/dashboard/components/message/MessageList.vue
@@ -134,14 +134,12 @@
 /** 回到底部 */
 const handleGoBottom = async () => {
   const scrollContainer = messageContainer.value
-  console.log(scrollContainer.scrollHeight)
   scrollContainer.scrollTop = scrollContainer.scrollHeight
 }
 
 /** 回到顶部 */
 const handlerGoTop = async () => {
   const scrollContainer = messageContainer.value
-  console.log(scrollContainer.scrollHeight)
   scrollContainer.scrollTop = 0
 }
 
diff --git a/src/views/ai/dashboard/components/message/ModelMessageList.vue b/src/views/ai/dashboard/components/message/ModelMessageList.vue
index f46b93e..4728658 100644
--- a/src/views/ai/dashboard/components/message/ModelMessageList.vue
+++ b/src/views/ai/dashboard/components/message/ModelMessageList.vue
@@ -1,5 +1,5 @@
 <template>
-  <div ref="messageContainer" class="h-100%">
+  <div ref="messageContainer" class="h-100% relative">
     <div class="chat-list" v-for="(item, index) in list" :key="index">
       <!-- 靠左 message:system、assistant 类型 -->
       <div class="left-message message-item" v-if="item.type !== 'user'">
@@ -21,10 +21,9 @@
 import MarkdownView from '@/components/MarkdownView/index.vue'
 import { useClipboard } from '@vueuse/core'
 import { ArrowDownBold} from '@element-plus/icons-vue'
-import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message'
+import { ChatMessageVO } from '@/api/ai/chat/message'
 import { ChatConversationVO } from '@/api/ai/chat/conversation'
 import { useUserStore } from '@/store/modules/user'
-import {formatDate} from "@/utils/formatTime";
 
 const message = useMessage() // 消息弹窗
 const { copy } = useClipboard() // 初始化 copy 到粘贴板
@@ -88,24 +87,9 @@
   scrollContainer.scrollTop = 0
 }
 
-defineExpose({ scrollToBottom, handlerGoTop }) // 提供方法给 parent 调用
+defineExpose({ scrollToBottom, handlerGoTop, handleGoBottom }) // 提供方法给 parent 调用
 
 // ============ 处理消息操作 ==============
-
-/** 复制 */
-const copyContent = async (content) => {
-  await copy(content)
-  message.success('复制成功!')
-}
-
-/** 删除 */
-const onDelete = async (id) => {
-  // 删除 message
-  await ChatMessageApi.deleteChatMessage(id)
-  message.success('删除成功!')
-  // 回调
-  emits('onDeleteSuccess')
-}
 
 /** 刷新 */
 const onRefresh = async (message: ChatMessageVO) => {
diff --git a/src/views/ai/dashboard/components/suggest/ScheduleSuggestDialog.vue b/src/views/ai/dashboard/components/suggest/ScheduleSuggestDialog.vue
new file mode 100644
index 0000000..48224a0
--- /dev/null
+++ b/src/views/ai/dashboard/components/suggest/ScheduleSuggestDialog.vue
@@ -0,0 +1,417 @@
+<template>
+  <DialogSuggest title="" v-model="dialogVisible" width="1300">
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px query-area"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="采纳状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择"
+          size="large"
+          class="!w-200px"
+          clearable
+          @change="getList"
+        >
+          <el-option
+            v-for="item in suggestStatus"
+            :key="item.key"
+            :label="item.name"
+            :value="item.key"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="调度时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="datetimerange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-360px transparent-date-picker-popper"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery">
+          <Icon icon="ep:search" class="mr-5px"/>
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon icon="ep:refresh" class="mr-5px"/>
+          重置
+        </el-button>
+      </el-form-item>
+    </el-form>
+    <!-- 对话详情 -->
+    <el-container class="detail-container">
+      <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+        <el-table-column
+          label="调度时间"
+          align="center"
+          prop="createTime"
+          :formatter="dateFormatter"
+          width="180px"
+        />
+        <el-table-column label="调度建议" align="center" prop="content" width="750"/>
+        <el-table-column label="采纳状态" align="center" prop="status" width="90">
+          <template #default="scope">
+            <template v-if="scope.row.status === 0">
+              未处理
+            </template>
+            <template v-else-if="scope.row.status === 1">
+              <span style="color: var(--el-color-success)">已采纳</span>
+            </template>
+            <template v-else>
+              <span style="color: var(--el-color-danger)">已忽略</span>
+            </template>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center">
+          <template #default="scope">
+            <template v-if="scope.row.status === 0">
+              <el-button
+                link
+                type="success"
+                @click="operateSuggest(scope.row.id, 1)"
+              >
+                采纳建议
+              </el-button>
+              <el-button
+                link
+                type="primary"
+                @click="operateSuggest(scope.row.id, 2)"
+              >
+                忽略建议
+              </el-button>
+            </template>
+            <template v-else-if="scope.row.status === 1">
+              <el-button
+                link
+                type="primary"
+                @click="operateSuggest(scope.row.id, 2)"
+              >
+                取消采纳
+              </el-button>
+            </template>
+            <template v-else>
+              <el-button
+                link
+                type="primary"
+              >
+                已忽略
+              </el-button>
+            </template>
+            <el-button
+              link
+              type="danger"
+              @click="handleDelete(scope.row.id)"
+              v-hasPermi="['ai:schedule-suggest:delete']"
+            >
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-container>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="handleQuery"
+    />
+  </DialogSuggest>
+</template>
+
+<script setup lang="ts">
+import {ChatMessageVO} from '@/api/ai/chat/message'
+import {ref} from "vue";
+import {dateFormatter} from "@/utils/formatTime";
+import {ScheduleSuggestApi, ScheduleSuggestVO} from "@/api/ai/schedulesuggest";
+import {OtherPlatformEnum} from "@/views/ai/utils/constants";
+
+/** AI 聊天对话 列表 */
+defineOptions({ name: 'HistoryMessageDialog' })
+
+// 接收父组件传递的方法
+// const props = defineProps({
+//   parentMethod: Function,
+//   gotoManualMethod: Function
+// });
+
+// 定义发射事件
+// const emit = defineEmits(['gotoManualMethod'])
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const loading = ref(true) // 列表的加载中
+const list = ref<ScheduleSuggestVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  modelId: undefined,
+  conversationId: undefined,
+  messageId: undefined,
+  content: undefined,
+  status: undefined,
+  createTime: [],
+})
+const operateData = ref({
+  id: undefined,
+  status: undefined,
+})
+const queryFormRef = ref() // 搜索的表单
+
+const suggestStatus = ref([
+  {
+    key: 0,
+    name: '未处理'
+  },
+  {
+    key: 1,
+    name: '已采纳'
+  },
+  {
+    key: 2,
+    name: '已忽略'
+  }
+])
+
+/** 打开弹窗 */
+const open = async () => {
+  dialogVisible.value = true
+  await nextTick() // 等待弹窗DOM挂载
+  await getList()
+}
+
+defineExpose({ open }) // 提供方法给 parent 调用
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await ScheduleSuggestApi.getScheduleSuggestPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 采纳与取消采纳建议 */
+const operateSuggest = async (id: number, status: number) => {
+  const data = operateData.value as unknown as ScheduleSuggestVO
+  data.id = id
+  data.status = status
+  await ScheduleSuggestApi.operateScheduleSuggest(data)
+  message.success(t('common.updateSuccess'))
+  // 刷新列表
+  await getList()
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await ScheduleSuggestApi.deleteScheduleSuggest(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  queryParams.status = undefined
+  handleQuery()
+}
+
+// const gotoManual = async (item: ChatMessageVO) => {
+//   emit('gotoManualMethod', item) // 发送数据给父组件
+// }
+
+
+/** 初始化 **/
+onMounted(async () => {})
+</script>
+
+<style lang="scss" scoped>
+
+.query-area {
+  margin-top: 2px;
+  margin-bottom: 2px;
+  float: left;
+  :deep(.el-select__wrapper) {
+    background: rgba(255,255,255,0.1) !important; /* 保留浅色背景 */
+    min-height: 30px;
+    box-shadow: none !important;
+  }
+  :deep(.el-select__placeholder) {
+    color: #DBEEFF;
+  }
+  :deep(.el-form-item__label) {
+    color: #73C4FF;
+  }
+  :deep(.el-date-editor .el-icon) {
+    color: #DBEEFF;
+  }
+  :deep(.el-date-editor .el-range-input) {
+    color: rgba(219, 238, 255, 0.5);
+  }
+  /* 移除所有输入框边框 */
+  :deep(.el-form-item .el-input__wrapper) {
+    border: none !important;
+    box-shadow: none !important;
+    background: rgba(255,255,255,0.1) !important; /* 保留浅色背景 */
+  }
+  /* 所有状态通用透明背景 */
+  :deep(.el-button) {
+    background: transparent !important;
+    border-color: currentColor; /* 保持与文字同色 */
+    color: #409EFF; /* 蓝色文字 */
+  }
+
+  /* 悬停状态 */
+  :deep(.el-button:hover) {
+    background: rgba(0, 0, 0, 0.5) !important; /* 轻微悬停反馈 */
+  }
+
+  /* 点击状态 */
+  :deep(.el-button:active) {
+    background: rgba(0, 0, 0, 0.8) !important;
+  }
+}
+
+// 头部
+.detail-container {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  height: 42vh;
+  background-color: rgba(0, 0, 0, 0); /* 透明背景 */
+  /* 表格透明背景 */
+  :deep(.el-table) {
+    background-color: transparent !important;
+    border: 1px solid rgba(255, 255, 255, 0.3) !important;
+    border-radius: 4px;
+  }
+
+  :deep(.el-table tr) {
+    color: #00b4ff; /* 蓝色文字 */
+    background: transparent !important;
+  }
+
+  /* 表头单元格边框 */
+  :deep(.el-table th.el-table__cell) {
+    border-bottom: 1px solid rgba(115,196,255,0.14) !important;
+    border-right: 1px solid rgba(115,196,255,0.14) !important;
+  }
+
+  /* 表格内容单元格边框 */
+  :deep(.el-table td.el-table__cell) {
+    border-bottom: 1px solid rgba(115,196,255,0.14) !important;
+    border-right: 1px solid rgba(115,196,255,0.14) !important;
+  }
+
+  /* 表头 */
+  :deep(.el-table__header thead tr th) {
+    background-color: rgba(0, 194, 255, 0.2);
+    border-bottom: none;
+  }
+
+  /* 行头样式 */
+  :deep(.el-table .el-table__body td:first-child) {
+    color: #8FD6FE;
+    font-weight: 500;
+  }
+
+  :deep(.el-table .el-table__body tr:nth-child(even) td) {
+    background-color: rgba(0, 194, 255, 0.1);
+  }
+
+  :deep(.el-table .el-table__body tr:nth-child(odd) td) {
+    background-color: rgba(0, 194, 255, 0.1);
+  }
+
+  /* 移除表格内部边框线 */
+  :deep(.el-table td, .el-table th.is-leaf) {
+    border-bottom: none;
+  }
+
+  :deep(.el-table .el-table__inner-wrapper:before) {
+    background-color: transparent !important;
+  }
+
+}
+
+// main 容器
+.main-container {
+  padding: 0;
+  position: relative;
+  overflow: hidden;          /* 隐藏外层滚动条 */
+  width: 100%;
+
+  .message-container {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    overflow-y: hidden;
+    /* Firefox */
+    scrollbar-width: thin;
+    scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
+
+    /* WebKit */
+    &::-webkit-scrollbar {
+      width: 6px;
+      background: transparent;
+    }
+    &::-webkit-scrollbar-thumb {
+      border-radius: 4px;
+      background: rgba(0, 0, 0, 0.15);
+      transition: background 0.3s;
+      &:hover { background: rgba(0, 0, 0, 0.25); }
+    }
+  }
+}
+
+.el-pagination {
+  //--el-pagination-button-bg-color: transparent;
+  opacity: 0.6;
+  :deep(.el-pagination__total) {
+    color: white;
+  }
+  :deep(.el-pager) {
+    color: rgba(3,27,21);
+    font-weight: bold;
+  }
+  :deep(.el-pagination__jump) {
+    color: white;
+  }
+  :deep(.el-select__popper) {
+    background-color: transparent;
+  }
+  :deep(.el-scrollbar) {
+    --el-scrollbar-opacity: 0.8;
+    --el-scrollbar-bg-color: transparent;
+  }
+}
+
+</style>
diff --git a/src/views/ai/dashboard/components/suggest/ScheduleSuggestList.vue b/src/views/ai/dashboard/components/suggest/ScheduleSuggestList.vue
new file mode 100644
index 0000000..b4ebf44
--- /dev/null
+++ b/src/views/ai/dashboard/components/suggest/ScheduleSuggestList.vue
@@ -0,0 +1,307 @@
+<template>
+  <div ref="messageContainer" class="h-100% overflow-y-auto relative">
+    <div class="chat-list" v-for="(item, index) in list" :key="index">
+      <!-- 靠左 message:system、assistant 类型 -->
+      <div class="left-message message-item" v-if="item.type !== 'user'">
+        <div class="avatar">
+          <el-avatar :src="roleAvatar" />
+        </div>
+        <div class="message">
+          <div>
+            <el-text class="time">{{ formatDate(item.createTime) }}</el-text>
+          </div>
+          <div v-if="item.thinkingFlag" class="left-text-container-thinking" ref="markdownViewRef">
+            <MarkdownView v-if="item.thinking" class="left-text thinking" :content="item.thinking" />
+            <MarkdownView v-else class="left-text thinking" :content="item.content" />
+          </div>
+          <div v-else-if="item.thinking" class="left-text-container-thinking" ref="markdownViewRef">
+            <MarkdownView class="left-text thinking" :content="item.thinking" />
+          </div>
+          <div v-else class="left-text-container-conclusion" ref="markdownViewRef">
+            <MarkdownView class="left-text" :content="item.content" />
+          </div>
+          <div class="left-text-container-conclusion" ref="markdownViewRef">
+            <MarkdownView class="left-text" :content="item.conclusion" />
+          </div>
+          <div class="right-btns">
+            <el-button class="btn-cus" link @click="copyContent(item.content)">
+              <img class="btn-image" src="@/assets/ai/zhuanlu/copy.png" />
+            </el-button>
+            <!-- 暂时不能删除,随意删除会影响首页echarts图表展示 -->
+<!--            <el-button v-if="item.id > 0" class="btn-cus" link @click="onDelete(item.id)">-->
+<!--              <img class="btn-image h-17px" src="@/assets/ai/zhuanlu/delete.png" />-->
+<!--            </el-button>-->
+          </div>
+        </div>
+      </div>
+      <!-- 靠右 message:user 类型 -->
+      <div class="left-message message-item" v-if="item.type === 'user'">
+        <div class="avatar">
+          <el-avatar :src="userAvatar" />
+        </div>
+        <div class="message">
+          <div>
+            <el-text class="time">{{ formatDate(item.createTime) }}</el-text>
+          </div>
+          <div class="right-text-container question" @click="gotoManual(item)">
+            <div class="right-text">{{ item.content }}</div>
+          </div>
+          <div class="right-btns">
+            <el-button class="btn-cus" link @click="copyContent(item.content)">
+              <img class="btn-image" src="@/assets/ai/zhuanlu/copy.png" />
+            </el-button>
+            <el-button class="btn-cus" link @click="onDelete(item.id)">
+              <img class="btn-image h-17px mr-12px" src="@/assets/ai/zhuanlu/delete.png" />
+            </el-button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <!-- 回到底部 -->
+  <div v-if="isScrolling" class="to-bottom" @click="handleGoBottom">
+    <el-button :icon="ArrowDownBold" circle />
+  </div>
+</template>
+<script setup lang="ts">
+import { PropType } from 'vue'
+import { formatDate } from '@/utils/formatTime'
+import MarkdownView from '@/components/MarkdownView/index.vue'
+import { useClipboard } from '@vueuse/core'
+import { ArrowDownBold } from '@element-plus/icons-vue'
+import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message'
+import { ChatConversationVO } from '@/api/ai/chat/conversation'
+import userAvatarDefaultImg from '@/assets/ai/zhuanlu/user.png'
+import roleAvatarDefaultImg from '@/assets/ai/zhuanlu/assistant.png'
+
+
+const message = useMessage() // 消息弹窗
+const { copy } = useClipboard() // 初始化 copy 到粘贴板
+
+// 判断“消息列表”滚动的位置(用于判断是否需要滚动到消息最下方)
+const messageContainer: any = ref(null)
+const isScrolling = ref(false) //用于判断用户是否在滚动
+
+const userAvatar = computed(() => userAvatarDefaultImg)
+const roleAvatar = computed(() => props.conversation.roleAvatar ?? roleAvatarDefaultImg)
+
+
+// 定义 props
+const props = defineProps({
+  conversation: {
+    type: Object as PropType<ChatConversationVO>,
+    required: true
+  },
+  list: {
+    type: Array as PropType<ChatMessageVO[]>,
+    required: true
+  },
+
+  gotoManualMethod: Function
+})
+
+const { list } = toRefs(props) // 消息列表
+
+const emits = defineEmits(['onDeleteSuccess']) // 定义 emits
+
+// ============ 处理对话滚动 ==============
+
+/** 滚动到底部 */
+const scrollToBottom = async (isIgnore?: boolean) => {
+  // 注意要使用 nextTick 以免获取不到 dom
+  await nextTick()
+  if (isIgnore || !isScrolling.value) {
+    messageContainer.value.scrollTop =
+      messageContainer.value.scrollHeight - messageContainer.value.offsetHeight
+  }
+}
+
+function handleScroll() {
+  const scrollContainer = messageContainer.value
+  const scrollTop = scrollContainer.scrollTop
+  const scrollHeight = scrollContainer.scrollHeight
+  const offsetHeight = scrollContainer.offsetHeight
+  if (scrollTop + offsetHeight < scrollHeight - 100) {
+    // 用户开始滚动并在最底部之上,取消保持在最底部的效果
+    isScrolling.value = true
+  } else {
+    // 用户停止滚动并滚动到最底部,开启保持到最底部的效果
+    isScrolling.value = false
+  }
+}
+
+/** 回到底部 */
+const handleGoBottom = async () => {
+  const scrollContainer = messageContainer.value
+  scrollContainer.scrollTop = scrollContainer.scrollHeight
+}
+
+/** 回到顶部 */
+const handlerGoTop = async () => {
+  const scrollContainer = messageContainer.value
+  scrollContainer.scrollTop = 0
+}
+
+defineExpose({ scrollToBottom, handlerGoTop, handleGoBottom }) // 提供方法给 parent 调用
+
+// ============ 处理消息操作 ==============
+
+const gotoManual = async (item: ChatMessageVO) => {
+  if(props.gotoManualMethod) {
+    props.gotoManualMethod(item)
+  }
+}
+
+/** 复制 */
+const copyContent = async (content) => {
+  await copy(content)
+  message.success('复制成功!')
+}
+
+/** 删除 */
+const onDelete = async (id) => {
+  // 删除 message
+  await ChatMessageApi.deleteChatMessage(id)
+  message.success('删除成功!')
+  // 回调
+  emits('onDeleteSuccess')
+}
+
+/** 初始化 */
+onMounted(async () => {
+  messageContainer.value.addEventListener('scroll', handleScroll)
+})
+</script>
+
+<style scoped lang="scss">
+/* 添加或修改以下样式 */
+div[ref="messageContainer"] {
+  height: 100%;          /* 继承父容器高度 */
+  overflow-y: auto;      /* 启用垂直滚动 */
+  max-height: 720px;     /* 或根据实际需求调整 */
+  padding-bottom: 20px; /* 避免底部内容被截断 */
+}
+// 中间
+.chat-list {
+  display: flex;
+  flex-direction: column;
+  height: auto;
+  padding: 0 20px;
+
+  .left-message {
+    display: flex;
+    flex-direction: row;
+  }
+
+  .message {
+    display: flex;
+    flex-direction: column;
+    text-align: left;
+    margin: 0 15px;
+
+    .question:hover {
+      cursor: pointer;
+      background: rgba(40, 139, 255, 0.3);
+    }
+
+    .time {
+      text-align: left;
+      line-height: 30px;
+    }
+
+    .left-text-container-thinking {
+      position: relative;
+      display: flex;
+      flex-direction: column;
+      overflow-wrap: break-word;
+      background: rgba(115,196,255,0.05);
+      border-radius: 4px 4px 4px 4px;
+      border-left: 1px solid #73C4FF;
+      padding: 10px 10px 5px 10px;
+      .left-text {
+        color: rgba(219,238,255,0.5);
+        font-size: 0.85rem;
+      }
+    }
+
+    .left-text-container-conclusion {
+      position: relative;
+      display: flex;
+      flex-direction: column;
+      overflow-wrap: break-word;
+      background: rgba(115,196,255,0);
+      border-radius: 4px 4px 4px 4px;
+      padding: 0 10px 5px 0;
+      .left-text {
+        color: rgba(219,238,255,0.8);
+        font-size: 1rem;
+      }
+    }
+
+    .right-text-container {
+      display: flex;
+      flex-direction: row-reverse;
+
+      .right-text {
+        font-size: 0.95rem;
+        color: #DBEEFF;
+        display: inline;
+        background: rgba(40,139,255,0.1);
+        box-shadow: 0 0 0 0 rgba(40,139,255,0.3);
+        border-radius: 10px;
+        padding: 10px;
+        width: auto;
+        overflow-wrap: break-word;
+        white-space: pre-wrap;
+      }
+    }
+
+    .left-btns {
+      display: flex;
+      flex-direction: row;
+      margin-top: 8px;
+    }
+
+    .right-btns {
+      display: flex;
+      flex-direction: row-reverse;
+      margin-top: 8px;
+    }
+  }
+
+  // 复制、删除按钮
+  .btn-cus {
+    display: flex;
+    background-color: transparent;
+    align-items: center;
+
+    .btn-image {
+      height: 20px;
+    }
+  }
+
+  .btn-cus:hover {
+    cursor: pointer;
+    background-color: #f6f6f6;
+  }
+}
+
+// 回到底部
+.to-bottom {
+  position: absolute;
+  z-index: 1000;
+  bottom: 0;
+  right: 50%;
+  .el-button {
+    background: rgba(255,255,255,0.1);
+    border: solid 1px rgba(255,215,0,0.6);
+    color: rgba(255,215,0,0.5);
+  }
+  .el-button:hover {
+    cursor: pointer;
+    background-color: rgba(255,255,255,0.4);
+    border: solid 2px rgba(255,215,0);
+    color: rgba(255,215,0);
+  }
+}
+</style>
diff --git a/src/views/ai/dashboard/zhuanlu/index.vue b/src/views/ai/dashboard/zhuanlu/index.vue
index 9feb5d0..16e7643 100644
--- a/src/views/ai/dashboard/zhuanlu/index.vue
+++ b/src/views/ai/dashboard/zhuanlu/index.vue
@@ -26,9 +26,15 @@
       <div id="tsxx">
         <div class="title"></div>
         <div class="data1-item" v-for="(item, index) in tsxxList" :key="`dynamics-${index}`">
-          <div class="content">
-            <div class="value">
-              <span>{{item.value}}</span> <span>{{item.unit}}</span>
+          <div class="content1">
+            <div class="value" v-if="item.type == 1">
+              <div class="item" v-for="(list, i) in item.lists" :key="`dynamics-${i}`">
+                <span>{{list.no}}</span><span>{{list.value}}</span>
+              </div>
+            </div>
+            <div class="value" v-else>
+              <span v-if="item.value == '进行'" style="color: #49FFD3; font-size: 14px; font-weight: bold;">{{item.value}}</span>
+              <span v-else style="color: #FFAE81; font-size: 14px; font-weight: bold;">{{item.value}}</span>
             </div>
             <div class="name">
               {{item.name}}
@@ -179,11 +185,11 @@
     <div class="gas-scheduling-right">
       <div id="ldghslyc">
         <div class="title"></div>
-        <div ref="LDGHSLYCEhartContainer" style="width: 100%; height: 180px"></div>
+        <div ref="LDGHSLYCEhartContainer" style="width: 100%; height: 140px"></div>
       </div>
       <div id="ldggrqsyc">
         <div class="title"></div>
-        <div ref="LDGGRYCEhartContainer" style="width: 100%; height: 180px"></div>
+        <div ref="LDGGRYCEhartContainer" style="width: 100%; height: 140px"></div>
       </div>
       <div id="mqhsjhxx">
         <div class="title"></div>
@@ -248,6 +254,31 @@
           <div class="item right-label"></div>
         </div>
       </div>
+      <div class="schedule-suggest">
+        <div class="result-title">
+          <span>推理结论</span><el-button @click="openSuggest" size="small" class="result-button" :icon="ArrowRight">查看更多</el-button>
+        </div>
+        <div class="result-content">
+          <div class="content-item" v-for="(item, index) in topSuggests" :key="`dynamics-${index}`">
+            <div class="time">
+              <span>{{formatDate(item.createTime, 'MM-DD HH:mm')}}</span>
+            </div>
+            <el-tooltip
+              effect="dark"
+              :content="item.content"
+              placement="top"
+              :disabled="!isOverflow"
+            >
+              <div class="content" ref="contentRef">
+                {{ item.content }}
+              </div>
+            </el-tooltip>
+          </div>
+        </div>
+        <!-- 推理结论 -->
+        <ScheduleSuggestDialog
+          ref="scheduleSuggestRef" />
+      </div>
     </div>
   </div>
 </template>
@@ -262,13 +293,16 @@
 import MessageLoading from '../components/message/MessageLoading.vue'
 import ConversationList from "../components/conversation/ConversationList.vue";
 import HistoryMessageDialog from "../components/message/HistoryMessageDialog.vue"
+import ScheduleSuggestDialog from "../components/suggest/ScheduleSuggestDialog.vue"
 import * as echarts from "echarts";
 import {formatToDateTime} from "@/utils/dateUtil";
+import { formatReasoningContent } from '@/views/ai/utils/utils'
 import {refreshToken} from "@/api/login";
 import {round} from "lodash-es";
-import {ArrowUpBold} from "@element-plus/icons-vue";
+import {ArrowRight, ArrowUpBold} from "@element-plus/icons-vue";
 import * as authUtil from "@/utils/auth";
-import HistoryMessageList from "@/views/ai/dashboard/components/message/HistoryMessageList.vue";
+import {ScheduleSuggestApi, ScheduleSuggestVO} from "@/api/ai/schedulesuggest";
+import {formatDate} from "@/utils/formatTime";
 
 const mqhsList = ref([
   {
@@ -278,7 +312,7 @@
   },
   {
     name: '转炉煤气 O 含量',
-    value: 618,
+    value: 10,
     unit: '%'
   },
   {
@@ -306,33 +340,60 @@
 const tsxxList = ref([
   {
     name: '各高炉出铁水信号',
-    value: '进行',
-    unit: ''
+    type: 1,
+    lists: [
+      {
+        no: '1#',
+        value: '不进行',
+      },
+      {
+        no: '2#',
+        value: '不进行',
+      }
+    ]
   },
   {
     name: '各高炉出铁量',
-    value: 5000,
-    unit: '吨'
+    type: 1,
+    lists: [
+      {
+        no: '1#',
+        value: '500t',
+      },
+      {
+        no: '2#',
+        value: '600t',
+      }
+    ]
   },
   {
     name: '各高炉铁水装入鱼雷罐车信号',
-    value: '进行',
-    unit: 'm³/h'
+    type: 1,
+    lists: [
+      {
+        no: '1#',
+        value: '不进行',
+      },
+      {
+        no: '2#',
+        value: '不进行',
+      }
+    ]
   },
   {
     name: '鱼雷罐车等待信号',
-    value: '进行',
-    unit: 'm³/h'
+    type: 2,
+    value: '进行'
   },
   {
     name: '铁水倒入铁水包信号',
-    value: '不进行',
-    unit: 'm³/h'
+    type: 2,
+    value: '不进行'
   },
   {
     name: '铁产量计划',
-    value: 6000,
-    unit: '吨'
+    type: 3,
+    value: '6000t',
   },
 ])
 
@@ -440,36 +501,24 @@
 
 const mqhsjhxxList = ref([
   {
-    name: '转炉总炉数\n' +
-      '日计划',
-    value: 567,
+    name: '转炉总炉数日计划',
+    value: 123,
     unit: '炉'
   },
   {
-    name: '转炉入炉铁水量\n' +
-      '日计划',
-    value: 200,
-    unit: '吨'
-  },
-  {
     name: '转炉检修计划',
-    value: '未进行',
+    value: '0',
     unit: ''
   },
   {
     name: '钢产量日计划',
-    value: 300,
-    unit: '吨'
-  },
-  {
-    name: '转炉加入废钢总量',
-    value: 500,
-    unit: '吨'
+    value: 20000,
+    unit: 't'
   },
   {
     name: '转炉实绩钢产量',
-    value: 100,
-    unit: '吨'
+    value: 20929,
+    unit: 't'
   }
 ])
 
@@ -495,20 +544,20 @@
   {
     id: 1,
     name: '1#转炉',
-    current: 20,
-    total: 30
+    current: 4,
+    total: 29
   },
   {
     id: 2,
     name: '2#转炉',
-    current: 25,
-    total: 100
+    current: 5,
+    total: 42
   },
   {
     id: 3,
     name: '3#转炉',
-    current: 4,
-    total: 29
+    current: 6,
+    total: 42
   }
 ])
 
@@ -536,6 +585,11 @@
   }
 
 ])
+
+const topSuggests = ref<ScheduleSuggestVO[]>([])
+
+const contentRef = ref([]);
+const isOverflow = ref([]);
 
 const ddtlResult = ref('')
 
@@ -725,10 +779,14 @@
     message.thinking = match[2];
     message.conclusion = match[4]
   }
+  message.thinking = formatReasoningContent(message.thinking)
   return message
 }
-
-
+/** 调度建议 */
+const scheduleSuggestRef = ref()
+const openSuggest = async () => {
+  scheduleSuggestRef.value.open()
+}
 /**
  * 消息列表
  *
@@ -736,8 +794,22 @@
  */
 const messageList = computed(() => {
   if (activeMessageList.value.length > 0) {
-    activeMessageList.value[1].thinking = dealResultAndData(activeMessageList.value[1].content)
-    return activeMessageList.value
+    // 对AI返回的消息进行格式化处理
+    const formattedList = activeMessageList.value.map(msg => {
+      if (msg.type === 'assistant') {
+        // 复制消息对象以避免修改原始数据
+        const formattedMsg = {...msg};
+        // 处理推理思路内容
+        formattedMsg.content = formatReasoningContent(msg.content);
+        return formattedMsg;
+      }
+      return msg;
+    });
+
+    // 处理调度推理结论及数据
+    formattedList[1].thinking = dealResultAndData(formattedList[1].content);
+
+    return formattedList;
   }
   // 没有消息时,如果有 systemMessage 则展示它
   if (activeConversation.value?.systemMessage) {
@@ -773,6 +845,14 @@
   }
   initLDGGRQSYCChart()
   return content
+}
+
+const getScheduleResult = (content: string) => {
+  const spliceText = content.includes("总结:") ? "总结:" : "结论:";
+  const regex = new RegExp(`^([\\s\\S]*?)${spliceText}([\\s\\S]*)$`);
+  const match = content.match(regex);
+  const result = match ? match[2].trim() : '';
+  return result
 }
 
 const extractRecoveryDetails = (text, consume, gui, totalMinutes = 60) => {
@@ -945,6 +1025,10 @@
     conversationId: activeConversationId.value,
     content: content
   } as ChatMessageVO)
+  // 保存调度建议
+  setTimeout(async () => {
+    await createSuggest()
+  }, 1000)
 }
 
 /** 真正执行【发送】消息操作 */
@@ -1108,6 +1192,31 @@
   } catch {}
 }
 
+const suggestData = ref({
+  id: undefined,
+  modelId: undefined,
+  conversationId: undefined,
+  messageId: undefined,
+  content: undefined,
+  status: undefined,
+})
+
+const createSuggest = async () => {
+  const suggestParam = suggestData.value as unknown as ScheduleSuggestVO
+  let assistantMessage = activeMessageList.value[1]
+  suggestParam.content = getScheduleResult(assistantMessage.content)
+  if(suggestParam.content != '') {
+    suggestParam.modelId = activeConversation.value.modelId
+    suggestParam.conversationId = activeConversation.value.id
+    suggestParam.messageId = assistantMessage.id
+    suggestParam.createTime = assistantMessage.createTime
+    suggestParam.status = 0
+    await ScheduleSuggestApi.createScheduleSuggest(suggestParam)
+    // 刷新首页推理结果列表
+    await getTopSuggest()
+  }
+}
+
 const LDGHSLYCEhartContainer = ref();
 
   // 生成未来60秒的时间标签(LDG回收量预测)
@@ -1148,7 +1257,7 @@
   const max = LDGMaxTotalValue()
   const schedule = modelData.value.schedule[type]
   // 返回对象格式数据,包含原始值和基准值
-  const baseline = round(max, 0) + (6 - 2 * type)
+  const baseline = round(max, 0) + (4.5 - 2 * type)
   return schedule.map(item => ({
     value: item + baseline, // 显示值 = 原始值 + 基准值
     original: item        // 原始值
@@ -1232,15 +1341,15 @@
     },
     grid: {
       left: 25,
-      right: 25,
+      right: 5,
       bottom: 10,
       top: 30,
       containLabel: true
     },
     legend: {
-      top: 10,
+      top: 5,
       right: 10,
-      data: ['1#转炉', '2#转炉', '3#转炉', '总回收量'],
+      data: ['1#转炉', '2#转炉', '3#转炉'],
       textStyle: {
         color: '#8FD6FE'
       },
@@ -1293,6 +1402,7 @@
           focus: 'series'
         },
         lineStyle: {
+          width: 1,
           color: '#FF7686' // 粉色
         }
       },
@@ -1306,6 +1416,7 @@
           focus: 'series'
         },
         lineStyle: {
+          width: 1,
           color: '#49FFD3' // 绿色
         }
       },
@@ -1320,6 +1431,7 @@
           focus: 'series'
         },
         lineStyle: {
+          width: 1,
           color: '#FFAE81' // 橙色
         },
       },
@@ -1333,6 +1445,7 @@
           focus: 'series'
         },
         lineStyle: {
+          width: 1,
           color: 'white'
         },
       }
@@ -1383,7 +1496,7 @@
       left: 0,
       right: 0,
       bottom: 10,
-      top: 20,
+      top: 10,
       containLabel: true
     },
     tooltip: {
@@ -1434,7 +1547,10 @@
         data: realData,
         smooth: true,
         symbol: 'none',
-        lineStyle: { color: '#95E6FF' },
+        lineStyle: {
+          color: '#95E6FF',
+          width: 1
+        },
         markLine: {
           symbol: ['none', 'none'],
           label: {
@@ -1459,6 +1575,7 @@
         lineStyle: {
           type: 'dashed',
           color: '#E76666',
+          width: 1,
           dashOffset: 5
         }
       },
@@ -1591,6 +1708,11 @@
   // 初始状态检测
   updateFullscreenStatus();
 }
+/** 查询列表 */
+const getTopSuggest = async () => {
+  const data = await ScheduleSuggestApi.getTopScheduleSuggests(5)
+  topSuggests.value = data
+}
 
 /** 初始化 **/
 onMounted(async () => {
@@ -1605,11 +1727,11 @@
   // 获取列表数据
   activeMessageListLoading.value = true
   await getMessageList()
+  await getTopSuggest()
 })
 
 // 清理监听
 onUnmounted(() => {
-  console.log('stopStream')
   const events = ['fullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'];
   events.forEach(event => {
     document.removeEventListener(event, handleFullscreenChange);
@@ -1682,6 +1804,35 @@
           font-weight: 400;
           font-size: 12px;
           color: #C7E7FF;
+        }
+      }
+      .name {
+        height: 16px;
+        font-weight: 400;
+        font-size: 12px;
+        color: #C7E7FF;
+      }
+    }
+    .content1 {
+      margin-left: 16px;
+      .value {
+        span:nth-child(1) {
+          height: 16px;
+          font-weight: 400;
+          font-size: 12px;
+          color: #C7E7FF;
+        }
+        span:nth-child(2){
+          padding-left: 3px;
+          height: 19px;
+          font-weight: bold;
+          font-size: 14px;
+          color: #FFAE81;
+          line-height: 19px;
+        }
+        .item {
+          display: inline-block;
+          width: 45%;
         }
       }
       .name {
@@ -2229,10 +2380,10 @@
         }
       }
       .data2-item {
-        height: 2.8rem;
-        width: 45%;
+        height: 1.4rem;
+        width: 46%;
         display: inline-block;
-        margin: 6px 8px;
+        margin: 8px 8px;
         background: url("@/assets/ai/zhuanlu/data_bg3.png") no-repeat;
       }
       .content {
@@ -2241,15 +2392,13 @@
         margin-left: 10px;
 
         .name {
-          width: 95px;
-          height: 18px;
+          width: 130px;
           font-weight: 400;
           font-size: 14px;
           color: #C7E7FF;
         }
 
         .value {
-          margin-top: 10px;
           margin-left: auto;
           margin-right: 5px;
           span:nth-child(1) {
@@ -2279,13 +2428,13 @@
       .little-title {
         font-size: 14px;
         color: #8FD6FE;
-        margin: 10px;
+        margin: 5px 10px 5px 10px;
       }
       .data3-item {
         height: 5.2rem;
         width: 30%;
         display: inline-block;
-        margin: 0 6px 6px 6px;
+        margin: 0 6px 0 6px;
         background: url("@/assets/ai/zhuanlu/data_bg4.png") center/cover no-repeat;
         .name {
           font-family: Alimama ShuHeiTi, Alimama ShuHeiTi;
@@ -2355,6 +2504,67 @@
         }
       }
     }
+    .schedule-suggest {
+      .result-title {
+        margin-top: 10px;
+        background: url("@/assets/ai/zhuanlu/ddtljl_result_title.png") no-repeat;
+        height: 1.8rem;
+        font-weight: 400;
+        font-size: 14px;
+        color: #8FD6FE;
+        text-align: left;
+        font-style: normal;
+        text-transform: none;
+        span {
+          margin-left: 30px;
+        }
+        .result-button {
+          color: rgba(143, 214, 254);
+          font-weight: bold;
+          float: right;
+          margin-right: 5px;
+          background-color: rgba(0, 255, 255, 0.1);
+          border-radius: 3px;
+          padding: 0 5px;
+          border: none;
+          cursor: pointer
+        }
+        .history-button:hover {
+          color: rgba(143, 214, 254, 0.5);
+        }
+      }
+      .result-content {
+        margin-top: 5px;
+        display: inline-block;
+        font-weight: 400;
+        font-size: 14px;
+        color: rgba(130,202,255,0.89);
+        text-align: left;
+        font-style: normal;
+        text-transform: none;
+        .content-item {
+          height: 28px;
+          background: rgba(69,133,255,0.2);
+          border-radius: 2px 2px 2px 2px;
+          padding-left: 3px;
+          margin: 3px 0;
+          display: flex;
+          align-items: center;
+          overflow: hidden;
+        }
+        .time {
+          flex-shrink: 0;
+          margin-right: 12px;
+        }
+        .content {
+          width: 350px;
+          flex: 1;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+      }
+    }
   }
 }
 
diff --git a/src/views/ai/model/template/index.vue b/src/views/ai/model/template/index.vue
index b6de43b..9d51204 100644
--- a/src/views/ai/model/template/index.vue
+++ b/src/views/ai/model/template/index.vue
@@ -113,6 +113,7 @@
   import * as AiQuestionTemplateApi from '@/api/ai/questiontemplate'
   import TemplateForm from './templateForm.vue'
   import * as AiModelApi from "@/api/ai/model/model";
+  import {AiModelTypeEnum} from "@/views/ai/utils/constants";
 
   defineOptions({name: 'AiTemplate'})
 
@@ -179,7 +180,7 @@
   /** 初始化 **/
   onMounted(async () => {
 
-    aiModelList.value = await AiModelApi.ModelApi.getModelSimpleList(1)
+    aiModelList.value = await AiModelApi.ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT + "," + AiModelTypeEnum.LLM)
     await getList()
   })
 </script>
diff --git a/src/views/ai/model/template/templateForm.vue b/src/views/ai/model/template/templateForm.vue
index fde0ed7..da11743 100644
--- a/src/views/ai/model/template/templateForm.vue
+++ b/src/views/ai/model/template/templateForm.vue
@@ -148,6 +148,7 @@
   import {CommonStatusEnum} from '@/utils/constants'
   import {ElMessage} from 'element-plus'
   import * as AiModelApi from "@/api/ai/model/model";
+  import {AiModelTypeEnum} from "@/views/ai/utils/constants";
 
   const aiModelList = ref([] as AiModelApi.ModelVO[])
   defineOptions({name: 'AiTemplateForm'})
@@ -203,7 +204,7 @@
     formType.value = type
     resetForm()
     // 加载调度模型列表
-    aiModelList.value = await AiModelApi.ModelApi.getModelSimpleList(1)
+    aiModelList.value = await AiModelApi.ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT + "," + AiModelTypeEnum.LLM)
     if (id) {
       formLoading.value = true
       try {
diff --git a/src/views/ai/suggest/ScheduleSuggestForm.vue b/src/views/ai/suggest/ScheduleSuggestForm.vue
new file mode 100644
index 0000000..1329936
--- /dev/null
+++ b/src/views/ai/suggest/ScheduleSuggestForm.vue
@@ -0,0 +1,117 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="模型id" prop="modelId">
+        <el-input v-model="formData.modelId" placeholder="请输入模型id" />
+      </el-form-item>
+      <el-form-item label="会话id" prop="conversationId">
+        <el-input v-model="formData.conversationId" placeholder="请输入会话id" />
+      </el-form-item>
+      <el-form-item label="消息id" prop="messageId">
+        <el-input v-model="formData.messageId" placeholder="请输入消息id" />
+      </el-form-item>
+      <el-form-item label="调度建议" prop="content">
+        <Editor v-model="formData.content" height="150px" />
+      </el-form-item>
+      <el-form-item label="状态(0-未处理 1-已采纳 2-已忽略)" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio label="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { ScheduleSuggestApi, ScheduleSuggestVO } from '@/api/ai/schedulesuggest'
+
+/** 大模型调度建议 表单 */
+defineOptions({ name: 'ScheduleSuggestForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  modelId: undefined,
+  conversationId: undefined,
+  messageId: undefined,
+  content: undefined,
+  status: undefined,
+})
+const formRules = reactive({
+  modelId: [{ required: true, message: '模型id不能为空', trigger: 'blur' }],
+  conversationId: [{ required: true, message: '会话id不能为空', trigger: 'blur' }],
+  messageId: [{ required: true, message: '消息id不能为空', trigger: 'blur' }],
+  status: [{ required: true, message: '状态(0-未处理 1-已采纳 2-已忽略)不能为空', trigger: 'blur' }],
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await ScheduleSuggestApi.getScheduleSuggest(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as ScheduleSuggestVO
+    if (formType.value === 'create') {
+      await ScheduleSuggestApi.createScheduleSuggest(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await ScheduleSuggestApi.updateScheduleSuggest(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    modelId: undefined,
+    conversationId: undefined,
+    messageId: undefined,
+    content: undefined,
+    status: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>
\ No newline at end of file
diff --git a/src/views/ai/suggest/index.vue b/src/views/ai/suggest/index.vue
new file mode 100644
index 0000000..b241a18
--- /dev/null
+++ b/src/views/ai/suggest/index.vue
@@ -0,0 +1,223 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="模型id" prop="modelId">
+        <el-input
+          v-model="queryParams.modelId"
+          placeholder="请输入模型id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="会话id" prop="conversationId">
+        <el-input
+          v-model="queryParams.conversationId"
+          placeholder="请输入会话id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="消息id" prop="messageId">
+        <el-input
+          v-model="queryParams.messageId"
+          placeholder="请输入消息id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="状态(0-未处理 1-已采纳 2-已忽略)" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态(0-未处理 1-已采纳 2-已忽略)"
+          clearable
+          class="!w-240px"
+        >
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['ai:schedule-suggest:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['ai:schedule-suggest:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="模型id" align="center" prop="modelId" />
+      <el-table-column label="会话id" align="center" prop="conversationId" />
+      <el-table-column label="消息id" align="center" prop="messageId" />
+      <el-table-column label="调度建议" align="center" prop="content" />
+      <el-table-column label="状态(0-未处理 1-已采纳 2-已忽略)" align="center" prop="status" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['ai:schedule-suggest:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['ai:schedule-suggest:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <ScheduleSuggestForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { ScheduleSuggestApi, ScheduleSuggestVO } from '@/api/ai/schedulesuggest'
+import ScheduleSuggestForm from './ScheduleSuggestForm.vue'
+
+/** 大模型调度建议 列表 */
+defineOptions({ name: 'ScheduleSuggest' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<ScheduleSuggestVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  modelId: undefined,
+  conversationId: undefined,
+  messageId: undefined,
+  content: undefined,
+  status: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await ScheduleSuggestApi.getScheduleSuggestPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await ScheduleSuggestApi.deleteScheduleSuggest(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await ScheduleSuggestApi.exportScheduleSuggest(queryParams)
+    download.excel(data, '大模型调度建议.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>
\ No newline at end of file
diff --git a/src/views/ai/utils/constants.ts b/src/views/ai/utils/constants.ts
index 580c676..713862a 100644
--- a/src/views/ai/utils/constants.ts
+++ b/src/views/ai/utils/constants.ts
@@ -25,12 +25,12 @@
 }
 
 export const AiModelTypeEnum = {
-  CHAT: 1, // 聊天
-  IMAGE: 2, // 图像
-  VOICE: 3, // 音频
-  VIDEO: 4, // 视频
-  EMBEDDING: 5, // 向量
-  RERANK: 6 // 重排
+  CHAT: '1', // 聊天
+  IMAGE: '2', // 图像
+  VOICE: '3', // 音频
+  VIDEO: '4', // 视频
+  EMBEDDING: '5', // 向量
+  LLM: '6' // 重排
 }
 
 export const OtherPlatformEnum: ImageModelVO[] = [
diff --git a/src/views/ai/utils/utils.ts b/src/views/ai/utils/utils.ts
index ef36350..2688533 100644
--- a/src/views/ai/utils/utils.ts
+++ b/src/views/ai/utils/utils.ts
@@ -11,3 +11,20 @@
 export const hasChinese = (str: string) => {
   return /[\u4e00-\u9fa5]/.test(str)
 }
+
+export const formatReasoningContent = (content: string) => {
+  // 匹配 "数字" + "." + ("中文"或"空格") + "其他内容" + ":"
+  const stepRegex = /(\d+\.(?:[\u4e00-\u9fa5]|\s)[^:]*:)(\s*)/g;
+
+  // 替换逻辑:
+  // - 如果标题后没有换行(即 `$2` 是空或只有空格),则添加 `<br>`
+  // - 如果标题后已有换行(如 `\n` 或 `<br>`),则不额外添加
+  return content.replace(
+    stepRegex,
+    (match, title, whitespace) => {
+      const hasNewline = whitespace.includes('\\n') || whitespace.includes('<br>');
+      const lineBreak = hasNewline ? '' : '<br>';
+      return `<strong style="font-size: 16px; line-height: 32px; color: #FFFFFF;">${title}</strong>${lineBreak}`;
+    }
+  );
+}

--
Gitblit v1.9.3