鸿蒙版本:harmony AI大模型WebSocket内容渲染【GPT、豆包、kimi】,支持markdown。

程序入口

ai问答效果视频

import { AppRouter, DynamicsRouter } from '@brainmed/router';
import { AppStorageModel } from '@brainmed/utils';
import { AiTopBar } from '../components/ai/AiTopBar';
import { AIContentList } from '../components/ai/AIContentList';
import { WebSocketManager } from '../util/AIWebSocket';
import { promptAction } from '@kit.ArkUI';
import { JSON, util } from '@kit.ArkTS';
import { AIChatBean, AIHistoryBean, AISendMessage } from '../types/KnowledgeResultType';
import { KnowledgeApi } from '../api/KnowledgeApi';
import { NetworkAddress } from '@brainmed/common';
import { KnowledgeAiController } from '../controller/KnowledgeAiController';

/**
 * AI问答
 */
@AppRouter()
@Component
export struct KnowledgeAI {
  @State isOnblur: boolean = false
  @State chatStatus: number = 1 // 0不可发送,1可发送
  @State areaCount: number = 0 //是否存在发送内容
  @State isIng: boolean = false //是否正在输出内容
  @State areaContent: string = "" //待发送内容
  @Provide sessionId: string = ""
  @State aiChatBeanList: AIChatBean[] = []
  @State fullAnswer: string = ""
  @State isFirst: boolean = true
  @State aiChatBean: AIChatBean = {
    queryData: '',
    answerFlag: '',
    answer: '',
    chatId: '',
    sessionId: '',
    keywords: [],
    question: '',
    collect: 'F',
    feedback: 'F',
    interrupt: 'F',
    saveStatus: false,
    isCollect: false,
    knowledgeInfo: [],
    relatedQuestions: [],
  }
  controller: TextAreaController = new TextAreaController()
  // 使用示例
  wsManager = new WebSocketManager(NetworkAddress.BASE_URL_AI_WS);

  aboutToAppear(): void {
    this.initWebSocket()
  }

  aboutToDisappear(): void {
    this.wsManager.close()
  }

  /**
   * 创建新会话
   */
  createNewSession(): void {

    if (this.aiChatBeanList.length == 0) {
      promptAction.showToast({
        message: "当前已是最新会话",
        duration: 2000,
        alignment: Alignment.Center
      })
      return
    }
    if (this.isIng) { //正在输出内容,结束输出
      promptAction.showToast({
        message: "当前问题正在输出",
        duration: 2000,
        alignment: Alignment.Center
      })
      return
    }
    this.sessionId = util.generateRandomUUID()
    this.aiChatBeanList = []
  }

  initWebSocket(): void {
    this.sessionId = util.generateRandomUUID()
    this.wsManager.connect(
      () => {
        this.chatStatus = 1
        if (this.isFirst) {
          this.isFirst = false
          const params = DynamicsRouter.getParamByName<AIChatBean>('knowledge/KnowledgeAI');
          if (params) {
            if (params.question) {
              this.createNewMessage(params.question)
            }
          }
        }
      },
      () => {
        this.chatStatus = 0
      }
    );
    this.wsManager.onMessage((message) => {
      let aiBean = this.jsonToBean(message.toString())
      console.log("AI_WEB_SOCKET输出内容" + message);

      if (this.sessionId === aiBean.sessionId) {
        // 查找 aiChatBeanList 中是否已有相同 chatId 的项
        let existingIndex = this.aiChatBeanList.findIndex(bean => bean.chatId === aiBean.chatId);
        // 如果列表中没有找到相同的 chatId
        if (existingIndex === -1) {
          if (this.aiChatBean.interrupt === "F") {
            this.aiChatBean.sessionId = aiBean.sessionId
            this.aiChatBean.queryData = aiBean.queryData
            this.aiChatBean.chatId = aiBean.chatId
            this.aiChatBean.answer = aiBean.answer
            this.aiChatBean.answerFlag = aiBean.answerFlag
            this.aiChatBean.question = aiBean.question
            if (aiBean.knowledgeInfo.length > 0) {
              this.aiChatBean.knowledgeInfo = []
              this.aiChatBean.knowledgeInfo = aiBean.knowledgeInfo
            }
            if (aiBean.keywords.length > 0) {
              this.aiChatBean.keywords = []
              this.aiChatBean.keywords = aiBean.keywords
            }
            //检查当前列表中是否存在该数据。不存在则保存
            this.isIng = true
            // 将当前接收到的answer追加到fullAnswer
            if (this.aiChatBean.answer != null) {
              this.fullAnswer += this.aiChatBean.answer;
            }
            this.aiChatBean.answer = this.fullAnswer
          }
        }
      }
    });
    this.wsManager.onError(() => {
    });

  }

  jsonToBean(message: string): AIChatBean {
    return JSON.parse(message.toString()) as AIChatBean
  }

  createNewMessage(question: string): void {
    this.areaContent = question
    this.sendMessage()
  }

  /**
   * 发送内容
   */
  sendMessage(): void {
    if (this.chatStatus == 0) { //当前websocket未连接不可发送内容
      return
    }
    if (this.isIng) { //正在输出内容,结束输出
      this.stopMessage()
      return
    }

    if (this.areaContent.length <= 0) {
      promptAction.showToast({
        message: "请输入您的问题",
        duration: 2000,
        alignment: Alignment.Center
      })
      return
    }
    //组装数据发送
    let aiSendMessage: AISendMessage = {
      question: this.areaContent,
      model: "doubao",
      sessionId: this.sessionId,
      history: []
    }
    let jsonString = JSON.stringify(aiSendMessage);
    console.log("AI_WEB_SOCKET_Message 发送内容:" + jsonString);
    this.wsManager.send(jsonString, () => {

    });
    this.areaContent = ""
  }

  /**
   * 结束发送内容
   */
  stopMessage(): void {
    this.aiChatBean.interrupt = "T"
    this.clearData([])
    this.showImage()
  }

  /**
   * 控制底部输入区域内图片根据状态展示
   * @returns
   */
  showImage(): Resource {
    if (this.isIng) {
      return $r('app.media.ai_chat_send_stop')
    } else {
      if (this.chatStatus == 0) {
        return $r('app.media.ai_chat_send_off')
      } else {
        if (this.areaCount > 0) {
          return $r('app.media.ai_chat_send_on')
        } else {
          return $r('app.media.ai_chat_send_off')
        }
      }
    }
  }

  async saveAI(chatId: string) {
    console.log("MZQ_AI---执行保存" + chatId);
    const index = this.aiChatBeanList.findIndex(bean => bean.chatId === chatId);
    if (index !== -1) {
      const foundBean = this.aiChatBeanList[index];
      KnowledgeApi.saveAi(foundBean).then(() => {
        console.log("MZQ_AI---存储成功:" + chatId);
        this.aiChatBeanList[index].saveStatus = true
        if (foundBean.relatedQuestions.length > 0) {
          console.log("MZQ_AI---开始存储相关问题:" + chatId);
          this.saveOtherQuestionList(foundBean)
        }
      })
    } else {
      console.log("MZQ_AI---存储失败,未查询到数据 AI——ID" + chatId + "====列表数据:" + this.aiChatBeanList);
    }
  }

  async saveOtherQuestionList(foundBean: AIChatBean) {
    KnowledgeApi.saveOtherQuestionList(foundBean).then(() => {
      console.log("MZQ_AI---相关问题存储成功:" + foundBean.chatId);
    })
  }

  clearData(otherList: string[]): void {
    this.fullAnswer = ""
    this.isIng = false
    this.aiChatBean.relatedQuestions = otherList
    //结束后插入数据
    let existingIndexTwo = this.aiChatBeanList.findIndex(bean => bean.chatId === this.aiChatBean.chatId);
    if (existingIndexTwo !== -1) {
      // 更新 aiChatBeanList 中的对象
      this.aiChatBeanList[existingIndexTwo] = this.aiChatBean;
    } else {
      this.aiChatBeanList.push(this.aiChatBean)
    }
    console.log("MZQ_AI---存储状态:" + this.aiChatBean.saveStatus + "相关问题列表:" + otherList.length);
    if (this.aiChatBean.saveStatus === false) {
      //调用存储方法
      this.saveAI(this.aiChatBean.chatId).then(() => {
        console.log("MZQ_AI---执行保存saveAI返回");
      })
    }
    this.aiChatBean = {
      queryData: '',
      answerFlag: '',
      answer: '',
      chatId: '',
      sessionId: '',
      keywords: [],
      knowledgeInfo: [],
      question: '',
      collect: 'F',
      feedback: 'F',
      interrupt: 'F',
      saveStatus: false,
      isCollect: false,
      relatedQuestions: []
    }
    // console.log("MZQ_AI---结束:" + this.aiChatBeanList.length);
  }

  /**
   * 选中当前数据
   * @param item
   */
  selectAiHistory(item: AIHistoryBean): void {
    console.log("MZQ_AI---选中当前指定的数据:" + item.name);
    //清空本地数据,
    if (this.isIng) {
      promptAction.showToast({
        message: '当前会话无法删除',
        alignment: Alignment.Center,
        duration: 1500
      });
    } else {
      //根据历史ID获取AIHistory列表
      this.getAiHistoryBySessionId(item.sessionId!)
    }
  }

  /**
   * 根据会话ID获取会话列表
   * @param sessionId
   */
  async getAiHistoryBySessionId(sessionId: string) {
    this.sessionId = sessionId
    KnowledgeApi.getAiHistoryBySessionId(sessionId).then((data) => {
      this.aiChatBeanList = []
      data.list?.map((item) => {
        this.aiChatBeanList.push(item)
      })
      this.knowledgeAiController.scrollBottom()
    })
  }

  /**
   * 删除当前会话列表
   * @param item
   */
  deleteAiHistory(item: AIHistoryBean): void {
    console.log("MZQ_AI---删除当前指定的数据:" + item.name);
    //检查会话ID是否与当前ID相同
    if (item.sessionId === this.sessionId) {
      //不允许删除
      promptAction.showToast({
        message: '当前会话无法删除',
        alignment: Alignment.Center,
        duration: 1500
      });
    } else {
      //执行删除
      this.deleteSession(item.sessionId!!).then(() => {

      })
    }
  }

  private knowledgeAiController = new KnowledgeAiController()

  //删除当前会话
  async deleteSession(sessionId: string) {
    KnowledgeApi.deleteSession(sessionId).then(() => {
      promptAction.showToast({
        message: '删除成功',
        alignment: Alignment.Center,
        duration: 1500
      });
      this.knowledgeAiController.refHistoryList()
    })
  }

  build() {
    NavDestination() {
      Column() {
        AiTopBar({
          knowledgeAiController: this.knowledgeAiController,
          selectAiHistory: (item: AIHistoryBean) => this.selectAiHistory(item),
          deleteAiHistory: (item: AIHistoryBean) => this.deleteAiHistory(item),
          createNewSession: () => this.createNewSession()
        })
        AIContentList({
          knowledgeAiController: this.knowledgeAiController,
          aiChatBeanList: this.aiChatBeanList,
          status: this.fullAnswer,
          aIChatBeanBottom: this.aiChatBean,
          clear: (otherList: string[]) => this.clearData(otherList),
          createMessage: (question: string) => this.createNewMessage(question)
        }).layoutWeight(1)
        Stack() {
          TextArea({ text: this.areaContent, placeholder: "请输入您的问题", controller: this.controller })
            .width('90%')
            .placeholderColor($r('app.color.tipText'))
            .padding(12)
            .backgroundColor(Color.White)
            .borderWidth(this.isOnblur ? 1 : 0)
            .borderColor($r('app.color.text_area_border'))
            .margin({ bottom: 12, top: 12 })
            .padding({ right: 34 })
            .onChange((value: string) => {
              this.areaContent = value
              this.areaCount = value.length
            })
            .onBlur(() => {
              this.isOnblur = false;
            })
            .onFocus(() => {
              this.isOnblur = true;
            })
            .constraintSize({
              maxHeight: 70
            })
          Image(this.showImage())
            .width(28)
            .aspectRatio(1)
            .position({ right: 8, bottom: 15 }).onClick(() => {
            this.sendMessage()
          })
        }
      }.height('100%').width('100%')
    }
    .width('100%')
    .hideTitleBar(true)
    .padding({ top: AppStorageModel.statusBarHeight() })
    .backgroundImage($r('app.media.knowledge_ai_top_bg'))
    .backgroundImageSize({
      width: '100%',
    })
    .backgroundColor($r('app.color.knowledge_bg'))
  }
}

侧边栏:

import { DynamicsRouter } from '@brainmed/router';
import { SilkPopup } from 'silk_ui';
import { AppStorageModel, UserModel } from '@brainmed/utils';
import { KnowledgeApi } from '../../api/KnowledgeApi';
import { AIHistoryBean, AIHistoryBeanGroup, AIHistoryBeanRequest } from '../../types/KnowledgeResultType';
import { BarImage, Pull2refresh2 } from '@brainmed/uicomponents';
import { KnowledgeAiController } from '../../controller/KnowledgeAiController';
import { inputMethod } from '@kit.IMEKit';
import { Page } from '@brainmed/network';

@Component
export struct AiTopBar {
  @State showPopup: boolean = false
  selectAiHistory: (item: AIHistoryBean) => void = (item) => {
  }
  deleteAiHistory: (item: AIHistoryBean) => void = (item) => {
  }
  createNewSession: () => void = () => {
  }
  @Consume sessionId: string

  closePopup():
    void {
    this.showPopup = false
  }

  private knowledgeAiController = new KnowledgeAiController()
  @State timer: number | null = null // 存储定时器ID

  build() {
    Row() {
      BarImage({
        click: () => {
          DynamicsRouter.popAppRouter();
        }
      }).margin({ left: 12 })
      Text('AI问答')
        .padding(12)
        .fontSize(16)
        .fontColor(Color.Black)
        .align(Alignment.Center)
        .alignSelf(ItemAlign.Center)
      Row() {
        BarImage({
          icon: $r('app.media.ai_icon_new_chat'),
          click: () => {
            this.createNewSession()
          }
        }).margin({ right: 12 })
        BarImage({
          icon: $r('app.media.ai_icon_more'),
          click: () => {
            let inputMethodController = inputMethod.getController();
            inputMethodController.stopInputSession()
            this.timer = setInterval(() => {
              this.showPopup = true
              clearInterval(this.timer!);
            }, 50);
          }
        }).margin({ right: 12 })
      }.align(Alignment.End).alignSelf(ItemAlign.Center)

      SilkPopup({
        show: this.showPopup,
        showPosition: 'right',
        safe_bottom: true,
        showClose: true,
        round: 0
      }) {
        AiHistoryList({
          knowledgeAiController: this.knowledgeAiController,
          selectAiHistory: (item: AIHistoryBean) => this.selectAiHistory(item)
        ,
          deleteAiHistory: (item: AIHistoryBean) => this.deleteAiHistory(item),
          closePopup: () => this.closePopup()
        }).width('100%')
      }
    }.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({ top: 8 })
  }
}

@Component
export struct AiHistoryList {
  @State isEdit: boolean = false
  @State aIHistoryBeanList: AIHistoryBean[] = []
  @State pageIndex: number = 1
  scroller: Scroller = new Scroller();
  @State nullData: boolean = false;
  @State loading: boolean = false;
  @State useList: AIHistoryBeanGroup[] = []
  @State isRequest: boolean = false
  selectAiHistory: (item: AIHistoryBean) => void = (item) => {
  }
  deleteAiHistory: (item: AIHistoryBean) => void = (item) => {
  }
  closePopup: () => void = () => {
  }
  @Consume sessionId: string
  @State aIHistoryBeanListUse: AIHistoryBean[] = []
  private knowledgeAiController = new KnowledgeAiController()

  aboutToAppear(): void {
    if (this.isRequest === false) {
      // 将testFunc方法用子组件方法进行覆盖
      if (this.knowledgeAiController) {
        this.knowledgeAiController.refHistoryList = () => this.onRefresh()
      }
      this.isRequest = true
      this.loading = true;
      this.onRefresh();
    }
  }

  /**
   * 获取知识工具常用工具列表
   */
  async getConversationHistory() {
    let param: AIHistoryBeanRequest;
    param = {
      userId: UserModel.getUserInfo()?.id.toString(),
      pageNum: this.pageIndex,
      pageSize: 20,
    };

    let res = await KnowledgeApi.getConversationHistory(param)
    this.aIHistoryBeanList = []
    res.list?.map((v) => {
      this.aIHistoryBeanList.push(v)
    })
    this.resetData()
    if (this.aIHistoryBeanListUse.length === 0) {
      this.nullData = true;
    }
    this.loading = false;
    return res.page!;
  }

  @State index: number = 0
  @State indexChild: number = 0

  /**
   * 重新组装数据,将数据分组
   */
  resetData() {
    // 遍历 aIHistoryBeanList,将数据按 dateType 分组
    this.aIHistoryBeanList.forEach((v) => {
      //判断是否已经存在存在则增加数据
      if (this.useList.length > 0) {
        // 检查是否存在
        let isIn = false;
        for (let i = 0; i < this.useList.length; i++) {
          let u = this.useList[i];
          if (u.dateType === v.dateType) {
            // 存在
            isIn = true;
            break;
          }
        }
        if (isIn == false) {
          let aiHistoryBeanGroup: AIHistoryBeanGroup = {
            dateType: v.dateType,
          }
          this.useList.push(aiHistoryBeanGroup);
        }
      } else {
        let aiHistoryBeanGroup: AIHistoryBeanGroup = {
          dateType: v.dateType,
        }
        this.useList.push(aiHistoryBeanGroup);
      }
    });

    this.useList.forEach((v) => {
      if (!v.list) {
        v.list = []
        v.id = this.index++
      }
      for (let i = 0; i < this.aIHistoryBeanList.length; i++) {
        let u = this.aIHistoryBeanList[i];
        if (u.dateType === v.dateType) {
          u.id = this.indexChild++
          v.list.push(u)
        }
      }
    });
    this.aIHistoryBeanListUse = []
    this.useList.forEach((item) => {
      if (Array.isArray(item.list)) {
        item.list[0].isGroup = true
        item.list.forEach((itemChild) => {
          this.aIHistoryBeanListUse.push(itemChild)
        })
      }
      console.log("MZQ_AI : " + item.dateType + ",list :" + item?.list?.length);
    });
  }

  async onRefresh(): Promise<Page | undefined> {
    this.pageIndex = 1
    this.aIHistoryBeanList = []
    this.useList = []
    this.index = 0
    this.indexChild = 0
    let page = await this.getConversationHistory();
    return page;
  }

  async onLoadMore() {
    console.log('123123', '翻页了' + this.pageIndex)
    this.pageIndex++;
    console.log('123123', '翻页了2' + this.pageIndex)
    let page = await this.getConversationHistory()
    return page;
  }

  build() {
    // 侧边抽屉
    Column() {
      Row() {
        Text('历史提问').fontSize(16).fontColor($r('app.color.black')).padding(12)
        Blank()
        Text(this.isEdit ? '完成' : "编辑")
          .fontSize(16)
          .fontColor(this.isEdit ? $r('app.color.theme_color') : $r('app.color.black'))
          .padding(12).onClick(() => {
          this.isEdit = !this.isEdit
        })
      }.width('100%')

      Pull2refresh2({
        listData: this.aIHistoryBeanList,
        scroller: this.scroller,
        loading: this.loading,
        nullData: this.nullData,
        onRefresh: (): Promise<Page | undefined> => this.onRefresh(),
        onLoadMore: (): Promise<Page | undefined> => this.onLoadMore(),
        listView: (): void => this.contentView(),
      })

    }
    .align(Alignment.Top)
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .height('100%')
    .padding({ top: AppStorageModel.statusBarHeight() })
  }

  getTypeName(dateType?: number): string {
    let name = '';
    switch (dateType) {
      case 1:
        name = '今天';
        break;
      case 2:
        name = '本周';
        break;
      case 3:
        name = '本月';
        break;
      default:
        name = '更早';
    }
    return name
  }

  @Builder
  contentView() {
    List({ space: 8, initialIndex: 0, scroller: this.scroller }) {
      ForEach(this.aIHistoryBeanListUse, (item: AIHistoryBean) => {
        if (item.isGroup) {
          ListItem() {
            Text(this.getTypeName(item?.dateType))
              .padding({ left: 12, top: 12 })
              .fontSize(14)
              .fontColor($r('app.color.ai_other_info'))
              .width('100%')
              .backgroundColor(Color.White)
          }
        }
        ListItem() {
          Row() {
            Row() {
              Text(item.name)
                .fontSize(14)
                .fontColor($r('app.color.black'))
                .padding(12)
                .textOverflow({ overflow: TextOverflow.Ellipsis })
                .maxLines(1)
                .layoutWeight(1)
              Text(item.dateValue)
                .fontSize(12)
                .fontColor($r('app.color.ai_history_time'))
                .padding({ top: 12, bottom: 12, right: 12 })
            }
            .backgroundColor($r('app.color.ai_history_item'))
            .borderRadius(4)
            .borderWidth(item.sessionId === this.sessionId ? 1 : 0)
            .borderColor(item.sessionId === this.sessionId ? $r('app.color.theme_color') : Color.Transparent)
            .margin({ left: 12, right: 12, top: 12 })
            .layoutWeight(1)

            Image($r('app.media.ai_delete'))
              .visibility(this.isEdit ? Visibility.Visible : Visibility.None)
              .width(18)
              .aspectRatio(1)
              .alignSelf(ItemAlign.Center)
              .margin({ right: 12, top: 12 })
              .onClick(() => {
                this.deleteAiHistory(item)
              })
          }.width('100%').justifyContent(FlexAlign.Center)
        }.width('100%').onClick(() => {
          this.closePopup()
          this.selectAiHistory(item)
        })
      })
    }
    .onReachEnd(() => this.onLoadMore())
    .margin({ right: 12, bottom: 40 })
    .listDirection(Axis.Vertical)
    .scrollBar(BarState.Off)
    .nestedScroll({
      scrollForward: NestedScrollMode.PARENT_FIRST,
      scrollBackward: NestedScrollMode.SELF_FIRST
    })
    .sticky(StickyStyle.Header) // 设置吸顶,实现粘性标题效果
    .edgeEffect(EdgeEffect.None)
    .width('100%')
    .constraintSize({ maxHeight: '100%' })
  }
}

具体内容渲染:

import { DynamicsRouter } from '@brainmed/router';
import { LengthMetrics, promptAction } from '@kit.ArkUI';
import { Markdown } from '@lidary/markdown';
import { KnowledgeApi } from '../../api/KnowledgeApi';
import { KnowledgeAiController } from '../../controller/KnowledgeAiController';
import { AIChatBean, AIFeedBackBean, AIKnowledgeInfo, AIOtherQuestion } from '../../types/KnowledgeResultType';

/**
 * ai记录 列表
 */
@Component
export struct AIContentList {
  private listScroller: Scroller = new Scroller();
  @Prop aiChatBeanList: AIChatBean[]
  @Provide feedBackTypeList: AIFeedBackBean[] = []
  @Link @Watch('scrollBottom') status: string
  @Link @Watch('updateBottom') aIChatBeanBottom: AIChatBean
  private knowledgeAiController = new KnowledgeAiController()
  clear: (otherList: string[]) => void = (otherList) => {
  }
  createMessage: (question: string) => void = (question) => {
  }

  aboutToAppear(): void {
    // 将testFunc方法用子组件方法进行覆盖
    if (this.knowledgeAiController) {
      this.knowledgeAiController.scrollBottom = () => this.scrollBottom()
    }
    this.getFeedbackTypes()
  }

  scrollBottom(): void {
    this.listScroller.scrollEdge(Edge.End)
  }

  updateBottom(): AIChatBean {
    this.scrollBottom()
    return this.aIChatBeanBottom
  }

  async getFeedbackTypes() {
    KnowledgeApi.getFeedbackTypes().then((result) => {
      this.feedBackTypeList = []
      result.list?.map((item) => {
        this.feedBackTypeList.push(item)
      })
    })
  }

  build() {
    List({ scroller: this.listScroller }) {
      defaultAi()
      ForEach(this.aiChatBeanList, (aiBean: AIChatBean) => {
        ListItem() {
          AiContent({
            aiBean: aiBean,
            isOld: true,
            clear: (otherList: string[]) => this.clear(otherList),
            createMessage: (question: string) => this.createMessage(question)
          })
        }
      })
      bottomAi({
        aiBean: this.updateBottom(),
        clear: (otherList: string[]) => this.clear(otherList),
        createMessage: (question: string) => this.createMessage(question)
      })
        .visibility(!this.updateBottom().question ? Visibility.None : Visibility.Visible)
    }.scrollBar(BarState.Auto)
  }
}

/**
 * 最底部需要输出得正文item
 */
@Component
export struct bottomAi {
  @Prop aiBean: AIChatBean
  clear: (otherList: string[]) => void = (otherList) => {
  }
  createMessage: (question: string) => void = (question) => {
  }

  build() {
    AiContent({
      aiBean: this.aiBean,
      isOld: false,
      clear: (otherList: string[]) => this.clear(otherList),
      createMessage: (question: string) => this.createMessage(question)
    })
  }
}

/**
 * 历史数据正文item
 */
@Component
export struct AiContent {
  @Prop isOld: boolean = true
  @Prop aiBean: AIChatBean
  clear: (otherList: string[]) => void = (otherList) => {
  }
  createMessage: (question: string) => void = (question) => {
  }

  build() {
    Column() {
      AiContentTop({ question: this.aiBean.question })
      if (this.isOld) {
        AiContentOld({
          aiBean: this.aiBean,
          createMessage: (question: string) => this.createMessage(question)
        })
      } else {
        AiContentIn({
          aiBean: this.aiBean,
          clear: (otherList: string[]) => this.clear(otherList)
        })
      }
    }
  }
}

/**
 * 正在输出得数据item
 */
@Component
export struct AiContentIn {
  @Prop @Watch('onReady') aiBean: AIChatBean
  @State answer: string = ""
  @State remainingTime: number = 0 // 倒计时剩余时间
  @State timerIdTitle: number | null = null // 存储定时器ID
  @State displayText: string = "" // 用于显示的文本
  @State currentIndex: number = 0 // 当前显示到文本的哪个索引
  @State timerId: number | null = null // 存储定时器ID
  clear: (otherList: string[]) => void = (otherList) => {
  }

  // 初始化倒计时
  onReady() {
    if (!this.aiBean.answerFlag && this.remainingTime <= 0) {
      if (this.aiBean.saveStatus == false && this.aiBean.chatId) {
        this.displayText = ""
        this.startCountdown(20);
        this.requestOtherQuestionList(this.aiBean).then(() => {

        })
      }
    } else {
      if (this.aiBean.answerFlag === "ing") {
        if (this.displayText === '') {
          this.startTextOutput(this.aiBean.answer)
        }
      }
    }
  }

  // 启动倒计时
  startCountdown(seconds: number) {
    this.remainingTime = seconds;
    console.log("MZQ_AI---重置计时参数:" + this.remainingTime);
    this.timerIdTitle = setInterval(() => {
      if (this.remainingTime > 0) {
        this.remainingTime--;
      } else {
        clearInterval(this.timerIdTitle!);
      }
    }, 1000);
  }

  // 启动逐字输出
  startTextOutput(text: string) {
    // 清理当前定时器
    if (this.timerId) {
      clearInterval(this.timerId);
    }
    this.displayText = ""; // 清空当前显示的文本
    this.currentIndex = 0; // 从头开始
    this.timerId = setInterval(() => {
      if (this.currentIndex < this.aiBean.answer.length && this.aiBean.interrupt == "F") {
        this.displayText += this.aiBean.answer[this.currentIndex];
        this.currentIndex++;
      } else {
        if (this.aiBean.answerFlag === "end" || this.aiBean.interrupt === "T") {
          // console.log("AI_WEB_SOCKET_" + this.aiBean.answerFlag + "===" + this.aiBean.interrupt);
          if (this.timerId) {
            this.clear(this.relatedQuestions)
            clearInterval(this.timerId);
          }
        }
      }
    }, 20); // 每 20 毫秒输出一个字符
  }

  @State relatedQuestions: string [] = []

  async requestOtherQuestionList(aiBean: AIChatBean) {
    console.log("MZQ_AI---准备执行" + aiBean.saveStatus + "==" + aiBean.chatId);
    let params: AIOtherQuestion = {
      question: aiBean.question,
      chatId: aiBean.chatId
    }
    KnowledgeApi.getQueryList(params).then((res) => {
      if (typeof res === 'string') {
        this.relatedQuestions = [res];
      } else if (Array.isArray(res)) {
        this.relatedQuestions = res as string[];
      }
      console.log("MZQ_AI---请求相关问题列表集合:" + this.relatedQuestions.length + "===会话ID:" + aiBean.chatId);
    })
  }

  build() {
    Row() {
      if (!this.aiBean.answerFlag) {
        Text() {
          //倒计时
          if (this.remainingTime > 0) {
            Span('正在获取资料,答案预计在 ')
              .fontSize(14)
              .fontColor($r('app.color.black'))
            Span(`${this.remainingTime} 秒`)
              .fontSize(14)
              .fontColor($r('app.color.theme_color')) // 设置秒数的颜色
            Span('内生成…')
              .fontSize(14)
              .fontColor($r('app.color.black'))
          } else {
            Span('答案生成中…')
              .fontSize(14)
              .fontColor($r('app.color.black'))
          }
        }
        .lineSpacing(LengthMetrics.vp(6))
        .fontSize(14)
        .padding(12)
        .backgroundColor(Color.White)
        .borderRadius({
          topLeft: 0,
          topRight: 8,
          bottomLeft: 8,
          bottomRight: 8
        })
        .margin({ left: 12, right: 12 })
      } else {
        Column() {
          Stack() {
            Markdown({
              content: this.displayText + " ●",
              lineSpace: 8,
              textLineSpace: 8,
              fontStyle: {
                fontColor: $r('app.color.txt_color'),
                fontSize: 14,
              }
            }).padding(12)
          }
        }
        .backgroundColor(Color.White)
        .borderRadius({
          topLeft: 0,
          topRight: 8,
          bottomLeft: 8,
          bottomRight: 8
        })
        .margin({ left: 12, right: 12 })
      }
    }.justifyContent(FlexAlign.Start).width('100%')
  }
}

/**
 * 历史数据
 */
@Component
export struct AiContentOld {
  @Prop aiBean: AIChatBean
  createMessage: (question: string) => void = (question) => {
  }

  build() {
    Column() {
      Column() {
        AIContent({ aiBean: this.aiBean })
        if (this.aiBean.answer.indexOf("您好,我是脑医汇") < 0) {
          Text('内容由AI结合脑医汇知识库生成')
            .fontSize(12)
            .borderRadius(25)
            .backgroundColor($r('app.color.page_bg'))
            .padding({
              left: 12,
              right: 12,
              top: 8,
              bottom: 8
            })
            .fontColor($r('app.color.txt_tips_color'))
            .margin({ top: 12, bottom: 12 })
          AIPause({ aiBean: this.aiBean })
          AIKnowledge({ aiBean: this.aiBean })
          AIBottomMenu({ aiBean: this.aiBean, createMessage: (question: string) => this.createMessage(question) })
          AISendCommunity({ aiBean: this.aiBean })
          AIKeyWords({ aiBean: this.aiBean })
          AIKnowledgeOtherQuestion({
            aiBean: this.aiBean,
            createMessage: (question: string) => this.createMessage(question)
          })
        }
      }
      .padding(12)
      .alignItems(HorizontalAlign.Start)
      .backgroundColor(Color.White)
      .borderRadius({
        topLeft: 0,
        topRight: 8,
        bottomLeft: 8,
        bottomRight: 8
      })
      .margin({ left: 12, right: 12 })

      if (this.aiBean.answer.indexOf("您好,我是脑医汇") < 0) {
        LineNew({ aiBean: this.aiBean })
      }
    }.justifyContent(FlexAlign.Start).width('100%')
  }
}

/**
 * question默认
 */
@Component
export struct AiContentTop {
  @Prop question: string

  build() {
    Column() {
      Column() {
        Row() {
          Image($r('app.media.ai_default_user')).width(24).aspectRatio(1)
          Text('你').fontSize(14).fontColor($r('app.color.ai_user_color')).padding({ left: 12 })
        }
        .padding(12)
        .justifyContent(FlexAlign.End).width('100%')

        Row() {
          Text(this.question)
            .fontColor($r('app.color.black'))
            .fontSize(14)
            .padding(12)
            .backgroundColor($r('app.color.ai_user_content'))
            .borderRadius({
              topLeft: 8,
              topRight: 0,
              bottomLeft: 8,
              bottomRight: 8
            })
        }.justifyContent(FlexAlign.End).width('100%').padding({ right: 12 })
      }.margin({ right: 12 }).width('100%')

      Row() {
        Image($r('app.media.ai_icon_top_logo')).width(24).aspectRatio(1)
        Text('脑医汇AI问答助手').fontSize(14).fontColor($r('app.color.ai_user_color')).padding({ left: 12 })
      }
      .padding(12)
      .justifyContent(FlexAlign.Start).width('100%')

    }
  }
}


/**
 * 默认数据
 */
@Component
export struct defaultAi {
  build() {
    ListItem() {
      Stack() {
        Column() {
          Row() {
            Image($r('app.media.ai_icon_top_logo')).width(24).aspectRatio(1).margin({ left: 12 })
            Text('脑医汇AI问答助手')
              .padding({
                left: 6,
                top: 16,
                right: 12,
                bottom: 12
              }).fontSize(14).fontColor($r('app.color.ai_user_name'))
          }.width('100%').justifyContent(FlexAlign.Start)

          Text('您好!欢迎使用脑医汇AI问答服务。我是您的智能医学助手。请随时向我提出您的问题,我将努力为您提供专业的回答。让我们开始吧!')
            .padding({ left: 12, right: 12, bottom: 16 })
            .fontSize(16)
            .fontColor($r('app.color.black'))
            .lineSpacing(LengthMetrics.vp(8))
        }.margin({ left: 15, right: 15, top: 55 }).borderRadius(8).backgroundColor(Color.White)

        Image($r('app.media.ai_chat')).width(80).aspectRatio(1).position({ right: 15, top: 15 })
      }
    }
  }
}

/**
 * 参考资料
 */
@Component
export struct AIKnowledge {
  @Prop aiBean: AIChatBean
  @State isOpenMore: boolean = false

  build() {
    if (this.aiBean.knowledgeInfo.length > 0 && this.aiBean.answerFlag === "end") {
      Column() {
        Text('参考资料:').fontColor($r('app.color.txt_color')).fontSize(14).padding(12).alignSelf(ItemAlign.Start)
        List() {
          ForEach(this.aiBean.knowledgeInfo, (item: AIKnowledgeInfo, index) => {
            if (this.isOpenMore) {
              knowledgeItem({ index: index, item: item })
            } else {
              if (index < 3) {
                knowledgeItem({ index: index, item: item })
              }
            }
          })
          if (this.isOpenMore) {
            ListItem() {
              Text() {
                Span('收起')
                ImageSpan($r('app.media.ai_more_off')).width(16).aspectRatio(1).margin({ left: 6 })
              }.fontColor($r('app.color.ai_info_more')).fontSize(14).padding(12).align(Alignment.Center)
            }.width('100%').onClick(() => {
              this.isOpenMore = false
            })
          } else {
            ListItem() {
              Text() {
                Span('展开全部')
                ImageSpan($r('app.media.ai_more')).width(16).aspectRatio(1).margin({ left: 6 })
              }.fontColor($r('app.color.ai_info_more')).fontSize(14).padding(12).align(Alignment.Center)
            }.width('100%').onClick(() => {
              this.isOpenMore = true
            })
          }

        }
      }.margin({ top: 12, bottom: 12 }).borderRadius(4).backgroundColor($r('app.color.ai_info_bg'))
    }
  }
}

/**
 * 参考资料Item
 */
@Component
export struct knowledgeItem {
  @Prop index: number
  @Prop item: AIKnowledgeInfo

  goPageByType() {
    if (this.item.type === "literature") {
      promptAction.showToast({
        message: '敬请期待',
        alignment: Alignment.Center,
        duration: 1500
      });
    } else if (this.item.type === "community_qa") {
      promptAction.showToast({
        message: '敬请期待',
        alignment: Alignment.Center,
        duration: 1500
      });
    } else if (this.item.type === "user") {
      DynamicsRouter.pushUri('mine/UserCenter', {
        id: this.item.userId
      })
    } else {
      const match = this.item.url?.match(/\/info\/(\d+)\.jspx/);
      if (match) {
        const param = match[1]; // 截取到的参数
        DynamicsRouter.pushUri('article/WebInfo', {
          id: param,
          url: this.item.url
        })
      }
    }
  }

  build() {
    ListItem() {
      Text((this.index + 1) + "." + this.item.title)
        .fontColor($r('app.color.txt_color'))
        .fontSize(14)
        .lineSpacing(LengthMetrics.vp(6))
        .padding({
          left: 12,
          right: 12,
          top: 7,
          bottom: 7
        })
        .decoration({ type: TextDecorationType.Underline })
    }.onClick(() => {
      this.goPageByType()
    })
  }
}

/**
 * 暂停
 */
@Component
export struct AIPause {
  @Prop aiBean: AIChatBean

  build() {
    if (this.aiBean.interrupt == "T" || this.aiBean.interrupt == "S") {
      Text(this.aiBean.interrupt == "T" ? "(用户暂停)" : "(连接已断开)")
        .fontColor($r('app.color.txt_tips_color'))
        .fontSize(14)
    }
  }
}

/**
 * 正文渲染
 */
@Component
export struct AIContent {
  @Prop aiBean: AIChatBean

  build() {
    if (this.aiBean.answerFlag) {
      if (this.aiBean.answerFlag === "ing") {
        Markdown({
          content: this.aiBean.answer,
          lineSpace: 8,
          textLineSpace: 8,
          fontStyle: {
            fontColor: $r('app.color.txt_color'),
            fontSize: 14,
          }
        }).padding(12)
          .backgroundColor(Color.White)
          .borderRadius({
            topLeft: 0,
            topRight: 8,
            bottomLeft: 8,
            bottomRight: 8
          })
          .margin({ left: 12, right: 12 })
      } else if (this.aiBean.answerFlag === "end") {
        Markdown({
          content: this.aiBean.answer,
          lineSpace: 8,
          textLineSpace: 8,
          fontStyle: {
            fontColor: $r('app.color.txt_color'),
            fontSize: 14,
          }
        })
        //展示其他内容
      }
    }
  }
}

/**
 * 底部按钮
 */
@Component
export struct AIBottomMenu {
  @Prop aiBean: AIChatBean
  createMessage: (question: string) => void = (question) => {
  }
  @State collectStatus: string = "F"
  @State feedBackStatus: string = "F"
  @Consume feedBackTypeList: AIFeedBackBean[]

  aboutToAppear(): void {
    this.collectStatus = this.aiBean.collect
    this.feedBackStatus = this.aiBean.feedback
  }

  /**
   * 收藏
   */
  async collect() {
    KnowledgeApi.collectAi(this.aiBean.chatId).then((result) => {
      if (result.data?.collectStatus === "F") {
        this.collectStatus = "F"
      } else {
        this.collectStatus = "T"
        promptAction.showToast({
          message: '收藏成功',
          alignment: Alignment.Center,
          duration: 1500
        });
      }
    })
  }

  dialogController: CustomDialogController | null = new CustomDialogController({
    builder: AiFeedbackDialog({
      aiBean: this.aiBean,
      feedBackTypeList: this.feedBackTypeList,
      updateFeedBack: () => {
        this.updateFeedBack()
      },
      cancel: () => {
        this.onCancel()
      }
    }),
    autoCancel: true,
    onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
      if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
        dismissDialogAction.dismiss()
      }
      if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
        dismissDialogAction.dismiss()
      }
    },
    alignment: DialogAlignment.Bottom,
    offset: { dx: 0, dy: 0 },
    customStyle: false,
    cornerRadius: {
      topLeft: 20,
      topRight: 20,
      bottomLeft: 0,
      bottomRight: 0
    },
    width: '100%',
    height: '60%',
    borderWidth: 0,
    borderStyle: BorderStyle.Dashed, //使用borderStyle属性,需要和borderWidth属性一起使用
    borderColor: Color.Blue, //使用borderColor属性,需要和borderWidth属性一起使用
    backgroundColor: Color.White,
  })

  /**
   * 反馈
   */
  async feedBack() {
    if (this.feedBackStatus === "F") {
      //弹出框
      if (this.dialogController != null) {
        this.dialogController.open()
      }
    } else {
      this.cancelFeedBack()
    }
  }

  /**
   * 取消意见反馈
   */
  async cancelFeedBack() {
    KnowledgeApi.cancelSaveFeedback(this.aiBean.chatId).then(() => {
      this.feedBackStatus = "F"
    })
  }

  updateFeedBack() {
    this.feedBackStatus = "T"
  }

  onCancel(): void {
    if (this.dialogController != null) {
      this.dialogController?.close()
    }
  }

  build() {
    Row({ space: 12 }) {
      if (this.aiBean.interrupt == "T" || this.aiBean.interrupt == "S") {
        //渲染暂停与点赞按钮
        Text() {
          ImageSpan($r('app.media.ai_re_try')).width(20).aspectRatio(1).verticalAlign(ImageSpanAlignment.CENTER)
          Span('重试').fontSize(12).fontColor($r('app.color.ai_info_more'))
        }.textAlign(TextAlign.Center).padding({
          left: 10,
          right: 10,
          top: 4,
          bottom: 4
        })
        .border({
          width: 1,
          color: $r('app.color.ai_info_more'),
          radius: 30
        }).onClick(() => {
          this.createMessage(this.aiBean.question)
        })
      } else {
        //渲染全部按钮
        if (this.aiBean.answerFlag == "end") {
          Text() {
            ImageSpan($r('app.media.ai_share')).width(20).aspectRatio(1).verticalAlign(ImageSpanAlignment.CENTER)
            Span('分享').fontSize(12).fontColor($r('app.color.ai_info_more'))
          }.textAlign(TextAlign.Center)
          .padding({
            left: 10,
            right: 10,
            top: 4,
            bottom: 4
          })
          .border({
            width: 1,
            color: $r('app.color.ai_info_more'),
            radius: 30
          })

          Text() {
            ImageSpan(this.collectStatus === "T" ? $r('app.media.ai_save_on') : $r('app.media.ai_save'))
              .width(20)
              .aspectRatio(1)
              .verticalAlign(ImageSpanAlignment.CENTER)
            Span('收藏').fontSize(12).fontColor($r('app.color.ai_info_more'))
          }.textAlign(TextAlign.Center)
          .padding({
            left: 10,
            right: 10,
            top: 4,
            bottom: 4
          })
          .border({
            width: 1,
            color: $r('app.color.ai_info_more'),
            radius: 30
          }).onClick(() => {
            this.collect()
          })
        }
      }
      Image(this.feedBackStatus === "T" ? $r('app.media.ai_zan_on') : $r('app.media.ai_zan'))
        .width(30)
        .aspectRatio(1)
        .padding(4)
        .border({
          width: 1,
          color: $r('app.color.ai_info_more'),
          radius: 30
        })
        .onClick(() => {
          this.feedBack()
        })
    }.justifyContent(FlexAlign.Start).width('100%').padding({ top: 12 })
  }
}

@CustomDialog
struct AiFeedbackDialog {
  @Prop aiBean: AIChatBean
  controller?: CustomDialogController
  @Prop feedBackTypeList: AIFeedBackBean[]
  cancel: () => void = () => {
  }
  updateFeedBack: () => void = () => {
  }
  @State text: string = ""
  @State isCommit: boolean = false
  @State selectType: AIFeedBackBean | null = null

  clickType(feedBackId?: string): void {
    this.feedBackTypeList.forEach((item) => {
      if (feedBackId) {
        if (item.id === feedBackId) {
          item.select = true
          this.selectType = item
        } else {
          item.select = false
        }
      } else {
        item.select = false
        this.selectType = null
      }
    })
    let listJson = JSON.stringify(this.feedBackTypeList)
    this.feedBackTypeList = []
    this.feedBackTypeList = JSON.parse(listJson)
    this.resetBtnStatus()
  }

  /**
   * 重置按钮状态
   */
  resetBtnStatus() {
    if (this.selectType) {
      this.isCommit = true
      if (this.selectType.name === "其他") {
        if (this.text) {
          this.isCommit = true
        } else {
          this.isCommit = false
        }
      } else {
        this.isCommit = true
      }
    } else {
      this.isCommit = false
    }
  }

  /**
   * 意见反馈
   */
  async feedBack() {
    if (this.isCommit === true) {
      KnowledgeApi.saveFeedBack(this.aiBean.chatId, this.selectType?.id?.toString()!, this.text).then(() => {
        promptAction.showToast({
          message: '反馈已提交',
          alignment: Alignment.Center,
          duration: 1500
        });
        this.cancel()
        //状态刷新
        this.updateFeedBack()
      })
    }
  }

  build() {
    Stack() {
      Column() {
        Text('反馈').fontSize(16).fontColor($r('app.color.black')).fontWeight(600).padding(12)
        Text('请选择对回答不满意的原因·')
          .fontSize(12)
          .fontColor($r('app.color.txt_tips_color'))
          .padding({ left: 12, bottom: 12 })

        List({ space: 12 }) {
          ForEach(this.feedBackTypeList, (item: AIFeedBackBean) => {
            ListItem() {
              feedBackType({
                item: item,
                clickType: (feedBackId?: string) => this.clickType(feedBackId)
              })
            }
          }

          )
        }.margin({ left: 12 })

        TextArea({
          text:
          this.text,
          placeholder:
          '你的反馈将帮助我们更好地改进...'
        })
          .placeholderColor($r('app.color.txt_tips_color'))
          .fontSize(14)
          .onChange((value: string) => {
            this.text = value
            this.resetBtnStatus()
          })
          .constraintSize({
            maxHeight: 100,
            minHeight: 100,
          })
          .borderRadius(8)
          .padding(12)
          .backgroundColor($r('app.color.bg_f5f5'))
          .margin(12)
        Button('提交', { type: ButtonType.Normal, stateEffect: true })
          .width('95%')
          .backgroundColor(this.isCommit ? $r('app.color.theme_color') : $r('app.color.bg_B4D9F0'))
          .borderRadius(8)
          .margin({ left: 12, right: 12 })
          .alignSelf(ItemAlign.Center)
          .onClick(() => {
            this.feedBack()
          })

      }.width('100%').alignItems(HorizontalAlign.Start)

      Image($r('app.media.ai_feedback_close'))
        .width(16)
        .aspectRatio(1)
        .position({ right: 1, top: 1 })
        .onClick(() => {
          this.cancel()
        })
        .margin({ right: 12 })
    }

    .width
    ('100%'
    ).padding({ top: 12 })
  }
}

@Component
export struct feedBackType {
  @Prop item: AIFeedBackBean
  clickType: (feedBackId?: string) => void = (feedBackId) => {
  }

  build() {
    Text(this.item.name)
      .fontSize(14)
      .fontColor(this.item.select ? $r('app.color.theme_color') : $r('app.color.black'))
      .padding(12)
      .constraintSize({ minWidth: 120 })
      .backgroundColor(this.item.select ? $r('app.color.bg_E6F2FA') : $r('app.color.bg_f5f5'))
      .borderWidth(1)
      .borderColor(this.item.select ? $r('app.color.theme_color') : $r('app.color.line_D0'))
      .borderRadius(8)
      .textAlign(TextAlign.Center)
      .onClick(() => {
        this.item.select = !this.item.select
        if (this.item.select) {
          this.clickType(this.item.id!)
        } else {
          this.clickType()
        }
      })
  }
}

/**
 * 应该是不开发
 */
@Component
export struct AISendCommunity {
  @Prop aiBean: AIChatBean

  build() {

  }
}

/**
 * 关键词
 */
@Component
export struct AIKeyWords {
  @Prop aiBean: AIChatBean

  build() {
    if (this.aiBean.answerFlag == "end") {
      Column() {
        Text() {
          ImageSpan($r('app.media.ai_keyword'))
            .width(25)
            .aspectRatio(1)
            .verticalAlign(ImageSpanAlignment.CENTER)
            .margin({ right: 12 })
          Span('关键词').fontSize(14).fontWeight(700).fontColor($r('app.color.ai_other_info'))
        }.padding({ top: 12, bottom: 12 })

        Flex({ space: { main: LengthMetrics.vp(10), cross: LengthMetrics.vp(10) }, wrap: FlexWrap.Wrap }) {
          ForEach(this.aiBean.keywords, (title: string) => {
            Text(title)
              .fontColor($r('app.color.ai_other_info'))
              .fontSize(14)
              .padding({
                left: 12,
                right: 12,
                top: 8,
                bottom: 8
              })
              .backgroundColor($r('app.color.ai_keyword_bg'))
              .borderRadius(30)
          })
        }
      }.width('100%').alignItems(HorizontalAlign.Start).padding({ top: 12 })
    }
  }
}

/**
 * 相关问题
 */
@Component
export struct AIKnowledgeOtherQuestion {
  @Prop aiBean: AIChatBean
  createMessage: (question: string) => void = (question) => {
  }

  build() {
    if (this.aiBean.answerFlag == "end") {
      Column() {
        Text() {
          ImageSpan($r('app.media.ai_question'))
            .width(25)
            .aspectRatio(1)
            .verticalAlign(ImageSpanAlignment.CENTER)
            .margin({ right: 12 })
          Span('相关问题').fontSize(14).fontWeight(700).fontColor($r('app.color.ai_other_info'))
        }.padding({ top: 12, bottom: 12 })

        List() {
          ForEach(this.aiBean.relatedQuestions, (item: string) => {
            ListItem() {
              Column() {
                Row() {
                  Text(item)
                    .padding(12)
                    .fontSize(14)
                    .maxLines(2)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
                    .fontColor($r('app.color.ai_other_info'))
                    .layoutWeight(1)
                  Image($r('app.media.ai_other')).width(24).aspectRatio(1)
                }.width('100%')

                Divider().vertical(false).strokeWidth(1).color('#F0ECE7').width('100%')
              }.width('100%').alignItems(HorizontalAlign.Start)
            }.onClick(() => {
              this.createMessage(item)
            })
          })
        }
      }.width('100%').alignItems(HorizontalAlign.Start).padding({ top: 12 })
    }
  }
}

/**
 * 开启新话题
 */
@Component
export struct LineNew {
  @Prop aiBean: AIChatBean

  build() {
    if (this.aiBean.answerFlag == "end") {
      Row() {
        Divider()
          .vertical(false)
          .strokeWidth(0.5)
          .color($r('app.color.ai_line'))
          .width("35%")
        Text("开启新话题")
          .padding(12)
          .fontSize(14)
          .textAlign(TextAlign.Center)
          .fontColor($r('app.color.ai_other_txt'))
          .width("30%")
        Divider()
          .vertical(false)
          .strokeWidth(0.5)
          .color($r('app.color.ai_line'))
          .width("35%")
      }
      .width('100%')
      .alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.SpaceAround)
      .margin({ top: 12 })
      .padding({ left: 12, right: 12 })
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无敌程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值