123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- <script setup>
- import { computed, unref } from 'vue';
- import { useMessage } from 'naive-ui';
- import { useClipboard } from '@vueuse/core'
- import MarkdownIt from 'markdown-it';
- import hljs from 'highlight.js';
- import mila from 'markdown-it-link-attributes';
- // import markdownItLatex from 'markdown-it-latex'
- import mdKatex from '@traptitech/markdown-it-katex';
- import { SvgIcon } from '@/components';
- import { chatApi } from "@/api/chat"
- // import 'markdown-it-latex/dist/index.css'
- const props = defineProps({
- id: {
- type: String || Number,
- default: ''
- },
- content: {
- type: String,
- default: ''
- },
- loading: {
- type: Boolean,
- default: false
- },
- delayLoading: {
- type: Boolean,
- default: false
- },
- isSatisfied: {
- type: Number,
- default: 2
- }
- })
- const emit = defineEmits(['on-click-icon']);
- const { copy } = useClipboard();
- const message = useMessage();
- function highlightBlock(str, lang) {
- return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__copy"></span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`
- }
- const mdi = new MarkdownIt({
- html: true,
- linkify: true,
- // breaks: true,
- typographer: true,
- highlight(code, language) {
- const validLang = !!(language && hljs.getLanguage(language))
- if (validLang) {
- const lang = language ?? ''
- return highlightBlock(hljs.highlight(code, { language: lang }).value, lang)
- }
- return highlightBlock(hljs.highlightAuto(code).value, '')
- },
- })
- mdi.use(mila, { attrs: { target: '_blank', rel: 'noopener' } })
- mdi.use(mdKatex, { blockClass: 'katexmath-block rounded-md p-[10px]', errorColor: ' #cc0000' })
- // mdi.use(markdownItLatex)
- const text = computed(() => {
- const value = props.content ?? ""
- if (!props.asRawText)
- return mdi.render(value)
- return value
- })
- const handlLeToggleLike = async (state) => {
- const { id } = unref(props);
- const isSatisfied = props.isSatisfied === state ? 2 : state;
- const params = { id, isSatisfied };
-
- await chatApi.putIsSatisfiedAnswer(params);
- isSatisfied < 2 ? message.success('感谢您的反馈') : message.success('已取消反馈');
- emit('on-click-icon', params)
- }
- const handleCopy = () => {
- copy(props.content).then(() => {
- message.success('复制成功');
- })
- }
- </script>
- <template>
- <div class="answer-inner">
- <div :class="[ 'answer-card', 'px-[20px]', 'py-[20px]']">
- <div class="chat-answer_icon relative flex-shrink-0">
- <SvgIcon name="common-logo" class="chat-logo " size="30" :style="{ scale: loading ? 0 : 1 }" />
- <div style="color: #2454FF" class="la-ball-circus la-dark la-sm flex-shrink-0" v-show="loading">
- <div v-for="item in 5" :key="item"></div>
- </div>
- </div>
- <div class="flex-1 pt-[4px] ml-[16px] text-[15px]">
- <template v-if="loading && delayLoading">
- <p class="font-bold text-[#1A2029] leading-[24px]">内容生成中...</p>
- </template>
- <div class="markdown-body text-[15px]" v-if="content">
- <div v-html="text"></div>
- </div>
- <template>
- <slot></slot>
- </template>
- </div>
- </div>
- <ul class="answer-btn-group" v-if="!loading">
- <li class="btn" @click="handleCopy">
- <SvgIcon name="chat-icon-copy" size="16" />
- </li>
- <li class="line"></li>
- <li :class="['btn', { btn_active: isSatisfied == 1 }]">
- <SvgIcon name="chat-icon-yes" size="16" @click="handlLeToggleLike(1)" />
- </li>
- <li class="line"></li>
- <li :class="['btn', { btn_active: isSatisfied == 0 }]">
- <SvgIcon name="chat-icon-no" size="16" @click="handlLeToggleLike(0)" />
- </li>
- </ul>
- </div>
- </template>
- <style lang="scss">
- .markdown-body p:last-child {
- margin-bottom: 0;
- }
- .markdown-body {
- p:last-child {
- margin-bottom: 0;
- }
- img {
- margin-top: 20px;
- }
- }
- .chat-logo {
- position: absolute;
- transition: all 1s;
- }
- .answer-inner {
- margin-bottom: 20px;
- .answer-card {
- @include flex(x, start, start);
- // padding: 20px 20px 4px 20px;
- border-radius: 8px;
- background: #fff;
- }
- .answer-btn-group {
- @include flex(x, center, end);
- padding-top: 6px;
- .btn {
- @include flex(x, center, center);
- @include layout(28px, 28px, 4px);
- color: #89909B;
- cursor: pointer;
- &:hover, &_active {
- background: #DBEFFF;
- color: #2454FF;
- }
- }
- .line {
- @include layout(1px, 12px, 0);
- margin: 0 5px;
- background: #D3D0E1;
- }
- }
- }
- </style>
|