9999 </div >
100100 </div >
101101 </div >
102+
103+ <!-- AI 解释区域 -->
104+ <div v-if =" result || loadingAi || aiError" class =" card result-card" >
105+ <div style =" display : flex ; justify-content : space-between ; align-items : center ; margin-bottom : 15px ;" >
106+ <h3 style =" margin-bottom : 0 ;" >✨ AI 深度解析与例句 (Qwen2.5)</h3 >
107+ <button v-if =" !aiExplanation && !loadingAi && result" @click =" fetchAiExplanation" class =" btn-secondary" >
108+ 获取解析
109+ </button >
110+ </div >
111+
112+ <div v-if =" loadingAi" class =" ai-loading" >
113+ <div class =" spinner" ></div >
114+ <p >Ollama 正在思考中,请稍候...</p >
115+ </div >
116+
117+ <div v-else-if =" aiError" class =" error-message" >
118+ {{ aiError }}
119+ <button @click =" fetchAiExplanation" style =" margin-left : 10px ; background : none ; border : underline ; color : inherit ; cursor : pointer ;" >重试</button >
120+ </div >
121+
122+ <div v-else-if =" aiExplanation" class =" ai-content markdown-body" v-html =" aiExplanation" ></div >
123+ </div >
102124 </section >
103125
104126 <!-- 右侧:文档区 -->
182204<script setup>
183205import { ref , watch } from ' vue' ;
184206import axios from ' axios' ;
207+ import { marked } from ' marked' ;
185208
186209const form = ref ({
187210 verb: ' '
188211});
189212
190213const result = ref (null );
214+ const aiExplanation = ref (null );
191215const loading = ref (false );
216+ const loadingAi = ref (false );
192217const error = ref (' ' );
218+ const aiError = ref (' ' );
193219const showSuggestions = ref (false );
194220const suggestions = ref ([]);
195221let suggestTimeout = null ;
@@ -239,6 +265,8 @@ const hideSuggestionsWithDelay = () => {
239265const conjugate = async () => {
240266 error .value = ' ' ;
241267 result .value = null ;
268+ aiExplanation .value = null ;
269+ aiError .value = ' ' ;
242270
243271 if (! form .value .verb ) {
244272 error .value = ' 请输入动词' ;
@@ -253,12 +281,33 @@ const conjugate = async () => {
253281 }
254282 });
255283 result .value = response .data ;
284+
285+ // 自动触发 AI 解析
286+ fetchAiExplanation ();
256287 } catch (err) {
257288 error .value = err .response ? .data ? .error || ' 请求失败,请检查输入' ;
258289 } finally {
259290 loading .value = false ;
260291 }
261292};
293+
294+ const fetchAiExplanation = async () => {
295+ if (! result .value ? .dictionaryForm ) return ;
296+
297+ loadingAi .value = true ;
298+ aiError .value = ' ' ;
299+
300+ try {
301+ const response = await axios .get (' /api/ai-explain' , {
302+ params: { verb: result .value .dictionaryForm }
303+ });
304+ aiExplanation .value = marked (response .data .explanation );
305+ } catch (err) {
306+ aiError .value = err .response ? .data ? .error || ' AI 解析请求失败' ;
307+ } finally {
308+ loadingAi .value = false ;
309+ }
310+ };
262311< / script>
263312
264313< style scoped>
@@ -509,4 +558,65 @@ const conjugate = async () => {
509558.guide - item strong {
510559 color: #333 ;
511560}
561+
562+ /* AI 解释区域样式 */
563+ .ai - loading {
564+ display: flex;
565+ align- items: center;
566+ justify- content: center;
567+ gap: 15px ;
568+ padding: 30px ;
569+ color: #666 ;
570+ }
571+
572+ .spinner {
573+ width: 24px ;
574+ height: 24px ;
575+ border: 3px solid #e0e0e0;
576+ border- top- color: #667eea ;
577+ border- radius: 50 % ;
578+ animation: spin 1s linear infinite;
579+ }
580+
581+ @keyframes spin {
582+ to { transform: rotate (360deg ); }
583+ }
584+
585+ .ai - content {
586+ background: #fdfdfd;
587+ padding: 20px ;
588+ border- radius: 8px ;
589+ border: 1px solid #eee;
590+ line- height: 1.6 ;
591+ color: #333 ;
592+ }
593+
594+ .btn - secondary {
595+ padding: 6px 12px ;
596+ background: #f0f0f0;
597+ color: #333 ;
598+ border: 1px solid #ddd;
599+ border- radius: 6px ;
600+ font- size: 0 .9em ;
601+ cursor: pointer;
602+ transition: all 0 .2s ;
603+ }
604+
605+ .btn - secondary: hover {
606+ background: #e4e4e4;
607+ }
608+
609+ /* 简单的 markdown 样式补充 */
610+ .markdown - body h1, .markdown - body h2, .markdown - body h3, .markdown - body h4 {
611+ margin- top: 10px ;
612+ margin- bottom: 10px ;
613+ color: #2c3e50 ;
614+ }
615+ .markdown - body p {
616+ margin- bottom: 10px ;
617+ }
618+ .markdown - body ul, .markdown - body ol {
619+ padding- left: 20px ;
620+ margin- bottom: 10px ;
621+ }
512622< / style>
0 commit comments