Right.vue 2.6 KB

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