houzhongjian
2024-08-08 820397e43a0b64d35c6d31d2a55475061438593b
提交 | 用户 | 时间
820397 1 <template>
H 2   <el-card class="my-card h-full">
3     <template #header>
4       <h3 class="m-0 px-7 shrink-0 flex items-center justify-between">
5         <span>预览</span>
6         <!-- 展示在右上角 -->
7         <el-button color="#846af7" v-show="showCopy" @click="copyContent" size="small">
8           <template #icon>
9             <Icon icon="ph:copy-bold" />
10           </template>
11           复制
12         </el-button>
13       </h3>
14     </template>
15
16     <div ref="contentRef" class="hide-scroll-bar h-full box-border overflow-y-auto">
17       <div class="w-full min-h-full relative flex-grow bg-white box-border p-3 sm:p-7">
18         <!-- 终止生成内容的按钮 -->
19         <el-button
20           v-show="isWriting"
21           class="absolute bottom-2 sm:bottom-5 left-1/2 -translate-x-1/2 z-36"
22           @click="emits('stopStream')"
23           size="small"
24         >
25           <template #icon>
26             <Icon icon="material-symbols:stop" />
27           </template>
28           终止生成
29         </el-button>
30         <el-input
31           id="inputId"
32           type="textarea"
33           v-model="compContent"
34           autosize
35           :input-style="{ boxShadow: 'none' }"
36           resize="none"
37           placeholder="生成的内容……"
38         />
39       </div>
40     </div>
41   </el-card>
42 </template>
43
44 <script setup lang="ts">
45 import { useClipboard } from '@vueuse/core'
46
47 const message = useMessage() // 消息弹窗
48 const { copied, copy } = useClipboard() // 粘贴板
49
50 const props = defineProps({
51   content: {
52     // 生成的结果
53     type: String,
54     default: ''
55   },
56   isWriting: {
57     // 是否正在生成文章
58     type: Boolean,
59     default: false
60   }
61 })
62
63 const emits = defineEmits(['update:content', 'stopStream'])
64
65 /** 通过计算属性,双向绑定,更改生成的内容,考虑到用户想要更改生成文章的情况 */
66 const compContent = computed({
67   get() {
68     return props.content
69   },
70   set(val) {
71     emits('update:content', val)
72   }
73 })
74
75 /** 滚动 */
76 const contentRef = ref<HTMLDivElement>()
77 defineExpose({
78   scrollToBottom() {
79     contentRef.value?.scrollTo(0, contentRef.value?.scrollHeight)
80   }
81 })
82
83 /** 点击复制的时候复制内容 */
84 const showCopy = computed(() => props.content && !props.isWriting) // 是否展示复制按钮,在生成内容完成的时候展示
85 const copyContent = () => {
86   copy(props.content)
87 }
88
89 /** 复制成功的时候 copied.value 为 true */
90 watch(copied, (val) => {
91   if (val) {
92     message.success('复制成功')
93   }
94 })
95 </script>
96
97 <style lang="scss" scoped>
98 .hide-scroll-bar {
99   -ms-overflow-style: none;
100   scrollbar-width: none;
101
102   &::-webkit-scrollbar {
103     width: 0;
104     height: 0;
105   }
106 }
107
108 .my-card {
109   display: flex;
110   flex-direction: column;
111
112   :deep(.el-card__body) {
113     box-sizing: border-box;
114     flex-grow: 1;
115     overflow-y: auto;
116     padding: 0;
117     @extend .hide-scroll-bar;
118   }
119 }
120 </style>